diff --git a/build.gradle b/build.gradle index d2fb177..3e3b21d 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,7 @@ dependencies { implementation('io.jsonwebtoken:jjwt-jackson:0.11.5') implementation('org.modelmapper:modelmapper:3.2.0') + implementation 'org.springframework.boot:spring-boot-starter-security' } tasks.named('test') { diff --git a/src/main/java/com/pmu/betengine/config/SecurityConfig.java b/src/main/java/com/pmu/betengine/config/SecurityConfig.java index c96816a..899e98c 100644 --- a/src/main/java/com/pmu/betengine/config/SecurityConfig.java +++ b/src/main/java/com/pmu/betengine/config/SecurityConfig.java @@ -7,6 +7,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @@ -29,5 +31,10 @@ public class SecurityConfig { .addFilterBefore(apiKeyFilter, UsernamePasswordAuthenticationFilter.class) .build(); } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } } diff --git a/src/main/java/com/pmu/betengine/controller/AuthController.java b/src/main/java/com/pmu/betengine/controller/AuthController.java index 95c6550..904e897 100644 --- a/src/main/java/com/pmu/betengine/controller/AuthController.java +++ b/src/main/java/com/pmu/betengine/controller/AuthController.java @@ -2,6 +2,7 @@ package com.pmu.betengine.controller; import com.pmu.betengine.model.AuthRequest; import com.pmu.betengine.model.AuthResponse; +import com.pmu.betengine.model.User; import com.pmu.betengine.service.AuthService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -18,7 +19,9 @@ public class AuthController { } @PostMapping("/login") - public ResponseEntity login(@RequestBody AuthRequest request) { - return ResponseEntity.ok(authService.login(request)); + public ResponseEntity login(@RequestBody AuthRequest request) { + User loggedUser = authService.login(request); + return ResponseEntity.ok(loggedUser); } + } diff --git a/src/main/java/com/pmu/betengine/controller/MiseController.java b/src/main/java/com/pmu/betengine/controller/MiseController.java new file mode 100644 index 0000000..135aec4 --- /dev/null +++ b/src/main/java/com/pmu/betengine/controller/MiseController.java @@ -0,0 +1,55 @@ +package com.pmu.betengine.controller; + +import com.pmu.betengine.model.Mise; +import com.pmu.betengine.service.MiseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/mises") +@CrossOrigin(origins = "*") +@Tag(name = "Gestion des Mises", description = "Endpoints relatifs aux Mises") +public class MiseController { + + private final MiseService miseService; + + public MiseController(MiseService miseService) { + this.miseService = miseService; + } + + @GetMapping + @Operation(summary = "Lister toutes les Mises") + public ResponseEntity> getAllMises() { + return ResponseEntity.ok(miseService.getAll()); + } + + @GetMapping("/{id}") + @Operation(summary = "Obtenir une Mise par ID") + public ResponseEntity getMiseById(@PathVariable Long id) { + return ResponseEntity.ok(miseService.getById(id)); + } + + @PostMapping + @Operation(summary = "Créer une Mise") + public ResponseEntity createMise(@RequestBody Mise mise) { + return new ResponseEntity<>(miseService.create(mise), HttpStatus.CREATED); + } + + @PutMapping("/{id}") + @Operation(summary = "Modifier une Mise") + public ResponseEntity updateMise(@PathVariable Long id, @RequestBody Mise mise) { + return ResponseEntity.ok(miseService.update(id, mise)); + } + + @DeleteMapping("/{id}") + @Operation(summary = "Supprimer une Mise") + public ResponseEntity deleteMise(@PathVariable Long id) { + miseService.delete(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/pmu/betengine/controller/ResultatController.java b/src/main/java/com/pmu/betengine/controller/ResultatController.java index 5304a0e..cb2a10d 100644 --- a/src/main/java/com/pmu/betengine/controller/ResultatController.java +++ b/src/main/java/com/pmu/betengine/controller/ResultatController.java @@ -8,7 +8,9 @@ import com.pmu.betengine.service.ResultatService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RestController @RequestMapping("/api/v1/resultat") @@ -57,10 +59,16 @@ public class ResultatController { } // GET BY COURSE - @GetMapping("/course/{courseId}") - public ResponseEntity getByCourse(@PathVariable Long courseId) { + @GetMapping("/course/{courseId}") + public ResponseEntity getByCourse(@PathVariable Long courseId) { Resultat r = resultatService.getByCourseId(courseId); - return r != null ? ResponseEntity.ok(r) : ResponseEntity.notFound().build(); + if (r != null) { + return ResponseEntity.ok(r); + } else { + Map response = new HashMap<>(); + response.put("message", "Aucun résultat disponible pour cette course"); + return ResponseEntity.ok(response); + } } // UPDATE diff --git a/src/main/java/com/pmu/betengine/model/Course.java b/src/main/java/com/pmu/betengine/model/Course.java index eb06c47..7cda101 100644 --- a/src/main/java/com/pmu/betengine/model/Course.java +++ b/src/main/java/com/pmu/betengine/model/Course.java @@ -25,59 +25,38 @@ public class Course { @Id @GeneratedValue private Long id; - private String type; - private Integer numero; - private String nom; - @Column(name = "date_depart_course") private LocalDateTime dateDepartCourse; - @Column(name = "date_debut_paris") private LocalDateTime dateDebutParis; - @Column(name = "date_fin_paris") private LocalDateTime dateFinParis; - @Column(name = "reunion_id") private Long reunionId; - @Column(name = "reunion_course") private Integer reunionCourse; - private String particularite; - private Integer partants; - private Integer distance; - private String condition; - private boolean estTerminee; private boolean estAnnulee; private boolean aDeadHeat; - private String statut; - private int nombreChevauxInscrits; - @Column(name = "resultat_statut") private String resultatStatut; - @Column(name = "created_by") private String createdBy; - @Column(name = "validated_by") private String validatedBy; - @Column(name = "created_at") private LocalDateTime createdAt; - @Column(name = "updated_at") private LocalDateTime updatedAt; - @Column(name = "nom_partants") private List nonPartants; diff --git a/src/main/java/com/pmu/betengine/model/Mise.java b/src/main/java/com/pmu/betengine/model/Mise.java new file mode 100644 index 0000000..789c822 --- /dev/null +++ b/src/main/java/com/pmu/betengine/model/Mise.java @@ -0,0 +1,25 @@ +package com.pmu.betengine.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "mises") +public class Mise { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + String typePari; + Double montantMise; +} diff --git a/src/main/java/com/pmu/betengine/model/User.java b/src/main/java/com/pmu/betengine/model/User.java index e80b1c7..ce5b985 100644 --- a/src/main/java/com/pmu/betengine/model/User.java +++ b/src/main/java/com/pmu/betengine/model/User.java @@ -28,6 +28,7 @@ public class User { private String nom; private String prenom; private String identifiant; + private String password; private String matriculeAgent; @Column(name = "role_id") diff --git a/src/main/java/com/pmu/betengine/model/statut/StatutUser.java b/src/main/java/com/pmu/betengine/model/statut/StatutUser.java new file mode 100644 index 0000000..63e686e --- /dev/null +++ b/src/main/java/com/pmu/betengine/model/statut/StatutUser.java @@ -0,0 +1,7 @@ +package com.pmu.betengine.model.statut; + +public enum StatutUser { +ACTIF, +INACTIF, +SUSPENDU +} diff --git a/src/main/java/com/pmu/betengine/model/type/TypeFormule.java b/src/main/java/com/pmu/betengine/model/type/TypeFormule.java index 126a5d3..7501ebe 100644 --- a/src/main/java/com/pmu/betengine/model/type/TypeFormule.java +++ b/src/main/java/com/pmu/betengine/model/type/TypeFormule.java @@ -28,6 +28,4 @@ public enum TypeFormule { CHAMP_TOTAL_1, CHAMP_PARTIEL_1, - - } diff --git a/src/main/java/com/pmu/betengine/model/type/TypePaiement.java b/src/main/java/com/pmu/betengine/model/type/TypePaiement.java index 4d1f7a6..e7423d8 100644 --- a/src/main/java/com/pmu/betengine/model/type/TypePaiement.java +++ b/src/main/java/com/pmu/betengine/model/type/TypePaiement.java @@ -10,9 +10,7 @@ public enum TypePaiement { QUARTE_PLUS_ORDRE_INEXACT, BONUS_3, BONUS_3_BIS, - MULTI_4, - MULTI_5, MULTI_6, MULTI_7, diff --git a/src/main/java/com/pmu/betengine/model/type/TypePari.java b/src/main/java/com/pmu/betengine/model/type/TypePari.java index 661ad38..0ff1258 100644 --- a/src/main/java/com/pmu/betengine/model/type/TypePari.java +++ b/src/main/java/com/pmu/betengine/model/type/TypePari.java @@ -1,5 +1,4 @@ package com.pmu.betengine.model.type; - public enum TypePari { SIMPLE, JUMELE_GAGNANT, diff --git a/src/main/java/com/pmu/betengine/repository/MiseRepository.java b/src/main/java/com/pmu/betengine/repository/MiseRepository.java new file mode 100644 index 0000000..a7d15ba --- /dev/null +++ b/src/main/java/com/pmu/betengine/repository/MiseRepository.java @@ -0,0 +1,7 @@ +package com.pmu.betengine.repository; + +import com.pmu.betengine.model.Mise; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MiseRepository extends JpaRepository { +} diff --git a/src/main/java/com/pmu/betengine/repository/UserRepository.java b/src/main/java/com/pmu/betengine/repository/UserRepository.java index fa6c995..5df8636 100644 --- a/src/main/java/com/pmu/betengine/repository/UserRepository.java +++ b/src/main/java/com/pmu/betengine/repository/UserRepository.java @@ -2,7 +2,19 @@ package com.pmu.betengine.repository; import com.pmu.betengine.model.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.Optional; +@Repository public interface UserRepository extends JpaRepository { + + // Récupérer un utilisateur par identifiant (connexion) + Optional findByIdentifiant(String identifiant); + + // Vérifier si un identifiant existe déjà (création) + boolean existsByIdentifiant(String identifiant); + + // Vérifier si un matricule existe déjà (création) + boolean existsByMatriculeAgent(String matriculeAgent); } diff --git a/src/main/java/com/pmu/betengine/service/AuthService.java b/src/main/java/com/pmu/betengine/service/AuthService.java index 29c3b22..5f7ac2e 100644 --- a/src/main/java/com/pmu/betengine/service/AuthService.java +++ b/src/main/java/com/pmu/betengine/service/AuthService.java @@ -4,6 +4,9 @@ import com.pmu.betengine.model.AuthRequest; import com.pmu.betengine.model.AuthResponse; import com.pmu.betengine.model.User; import com.pmu.betengine.repository.UserRepository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.time.LocalDateTime; @@ -12,24 +15,26 @@ import java.time.LocalDateTime; public class AuthService { private final UserRepository userRepository; + @Autowired + private PasswordEncoder passwordEncoder; public AuthService(UserRepository userRepository) { this.userRepository = userRepository; } - public AuthResponse login(AuthRequest request) { - User user = userRepository.findAll().stream() - .filter(u -> u.getIdentifiant().equals(request.getIdentifiant())) - .findFirst() + + + + public User login(AuthRequest request) { + User user = userRepository.findByIdentifiant(request.getIdentifiant()) .orElseThrow(() -> new RuntimeException("User not found")); - - if (request.getPassword().equals("password123")) { - user.setDerniereConnexion(LocalDateTime.now()); - userRepository.save(user); - - return new AuthResponse("Login successful", user.getId(), user.getNom(), user.getPrenom()); - } else { + + if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { throw new RuntimeException("Invalid credentials"); } + + user.setDerniereConnexion(LocalDateTime.now()); + return userRepository.save(user); } + } diff --git a/src/main/java/com/pmu/betengine/service/MiseService.java b/src/main/java/com/pmu/betengine/service/MiseService.java new file mode 100644 index 0000000..53f5cab --- /dev/null +++ b/src/main/java/com/pmu/betengine/service/MiseService.java @@ -0,0 +1,41 @@ +package com.pmu.betengine.service; + +import com.pmu.betengine.model.Mise; +import com.pmu.betengine.repository.MiseRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class MiseService { + + private final MiseRepository repository; + + public MiseService(MiseRepository repository) { + this.repository = repository; + } + + public Mise create(Mise mise) { + return repository.save(mise); + } + + public Mise getById(Long id) { + return repository.findById(id) + .orElseThrow(() -> new RuntimeException("Mise not found")); + } + + public List getAll() { + return repository.findAll(); + } + + public Mise update(Long id, Mise mise) { + Mise existing = getById(id); + existing.setTypePari(mise.getTypePari()); + existing.setMontantMise(mise.getMontantMise()); + return repository.save(existing); + } + + public void delete(Long id) { + repository.deleteById(id); + } +} diff --git a/src/main/java/com/pmu/betengine/service/ResultatService.java b/src/main/java/com/pmu/betengine/service/ResultatService.java index 763f893..262d57a 100644 --- a/src/main/java/com/pmu/betengine/service/ResultatService.java +++ b/src/main/java/com/pmu/betengine/service/ResultatService.java @@ -4,8 +4,16 @@ import com.pmu.betengine.model.Course; import com.pmu.betengine.model.Resultat; import com.pmu.betengine.repository.ResultatRepository; import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.Optional; +import java.util.Map; + +import java.util.HashMap; import java.util.List; @Service @@ -35,6 +43,7 @@ public class ResultatService { return resultatRepository.findByCourseId(courseId).orElse(null); } + // DELETE BY ID public void delete(Long id) { resultatRepository.deleteById(id); diff --git a/src/main/java/com/pmu/betengine/service/UserService.java b/src/main/java/com/pmu/betengine/service/UserService.java index 29aabfd..54c7927 100644 --- a/src/main/java/com/pmu/betengine/service/UserService.java +++ b/src/main/java/com/pmu/betengine/service/UserService.java @@ -1,8 +1,13 @@ package com.pmu.betengine.service; import com.pmu.betengine.model.User; +import com.pmu.betengine.model.statut.StatutUser; import com.pmu.betengine.repository.UserRepository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import java.time.LocalDateTime; import java.util.List; @@ -12,15 +17,47 @@ public class UserService { private final UserRepository userRepository; + @Autowired + private PasswordEncoder passwordEncoder; + public UserService(UserRepository userRepository) { this.userRepository = userRepository; } // CREATE public User create(User user) { + // 1. Vérification des champs obligatoires + if (!StringUtils.hasText(user.getNom())) {throw new RuntimeException("Le nom est obligatoire");} + if (!StringUtils.hasText(user.getPrenom())) {throw new RuntimeException("Le prénom est obligatoire");} + if (!StringUtils.hasText(user.getIdentifiant())) {throw new RuntimeException("L'identifiant est obligatoire");} + if (!StringUtils.hasText(user.getPassword())) {throw new RuntimeException("Le mot de passe est obligatoire");} + if (user.getRoleId() == null) {throw new RuntimeException("L'ID du rôle est obligatoire");} + // 2. Vérification de l'unicité + if (userRepository.existsByIdentifiant(user.getIdentifiant())) {throw new RuntimeException("Cet identifiant existe déjà");} + if (user.getMatriculeAgent() != null && + userRepository.existsByMatriculeAgent(user.getMatriculeAgent())) {throw new RuntimeException("Ce matricule agent existe déjà");} + // 3. Validation du mot de passe + if (!user.getPassword().matches("^(?=.*[0-9])(?=.*[a-zA-Z]).{8,}$")) {throw new RuntimeException("Le mot de passe doit contenir au moins 8 caractères, incluant lettres et chiffres");} + // 4. Définition des valeurs par défaut et encodage du mot de passe user.setId(null); + user.setPassword(passwordEncoder.encode(user.getPassword())); + user.setStatut(StatutUser.ACTIF.name()); user.setCreatedAt(LocalDateTime.now()); user.setUpdatedAt(LocalDateTime.now()); + user.setDerniereConnexion(null); + // 5. Vérification des champs numériques + if (user.getNombreIpAutorise() == null || user.getNombreIpAutorise() < 0) { + user.setNombreIpAutorise(0); + } + if (user.getNombreIpAutoAutorise() == null || user.getNombreIpAutoAutorise() < 0) { + user.setNombreIpAutoAutorise(0); + } + // 6. Nettoyage des chaînes + user.setIdentifiant(user.getIdentifiant().trim().toLowerCase()); + if (user.getMatriculeAgent() != null) { + user.setMatriculeAgent(user.getMatriculeAgent().trim().toUpperCase()); + } + // 7. Enregistrement return userRepository.save(user); } @@ -44,13 +81,13 @@ public class UserService { return userRepository.save(user); - }).orElseThrow(() -> new RuntimeException("User not found")); + }).orElseThrow(() -> new RuntimeException("Utilisateur introuvable")); } // READ by ID public User getById(Long id) { return userRepository.findById(id) - .orElseThrow(() -> new RuntimeException("User not found")); + .orElseThrow(() -> new RuntimeException("Utilisateur introuvable")); } // READ all