mise gestion

This commit is contained in:
Dede
2025-12-02 08:40:58 +00:00
parent 7d2cc98d2c
commit 65c5fd5c6e
18 changed files with 237 additions and 45 deletions

View File

@@ -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') {

View File

@@ -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();
}
}

View File

@@ -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<AuthResponse> login(@RequestBody AuthRequest request) {
return ResponseEntity.ok(authService.login(request));
public ResponseEntity<User> login(@RequestBody AuthRequest request) {
User loggedUser = authService.login(request);
return ResponseEntity.ok(loggedUser);
}
}

View File

@@ -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<List<Mise>> getAllMises() {
return ResponseEntity.ok(miseService.getAll());
}
@GetMapping("/{id}")
@Operation(summary = "Obtenir une Mise par ID")
public ResponseEntity<Mise> getMiseById(@PathVariable Long id) {
return ResponseEntity.ok(miseService.getById(id));
}
@PostMapping
@Operation(summary = "Créer une Mise")
public ResponseEntity<Mise> createMise(@RequestBody Mise mise) {
return new ResponseEntity<>(miseService.create(mise), HttpStatus.CREATED);
}
@PutMapping("/{id}")
@Operation(summary = "Modifier une Mise")
public ResponseEntity<Mise> updateMise(@PathVariable Long id, @RequestBody Mise mise) {
return ResponseEntity.ok(miseService.update(id, mise));
}
@DeleteMapping("/{id}")
@Operation(summary = "Supprimer une Mise")
public ResponseEntity<Void> deleteMise(@PathVariable Long id) {
miseService.delete(id);
return ResponseEntity.noContent().build();
}
}

View File

@@ -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")
@@ -58,9 +60,15 @@ public class ResultatController {
// GET BY COURSE
@GetMapping("/course/{courseId}")
public ResponseEntity<Resultat> getByCourse(@PathVariable Long 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<String, String> response = new HashMap<>();
response.put("message", "Aucun résultat disponible pour cette course");
return ResponseEntity.ok(response);
}
}
// UPDATE

View File

@@ -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<String> nonPartants;

View File

@@ -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;
}

View File

@@ -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")

View File

@@ -0,0 +1,7 @@
package com.pmu.betengine.model.statut;
public enum StatutUser {
ACTIF,
INACTIF,
SUSPENDU
}

View File

@@ -28,6 +28,4 @@ public enum TypeFormule {
CHAMP_TOTAL_1,
CHAMP_PARTIEL_1,
}

View File

@@ -10,9 +10,7 @@ public enum TypePaiement {
QUARTE_PLUS_ORDRE_INEXACT,
BONUS_3,
BONUS_3_BIS,
MULTI_4,
MULTI_5,
MULTI_6,
MULTI_7,

View File

@@ -1,5 +1,4 @@
package com.pmu.betengine.model.type;
public enum TypePari {
SIMPLE,
JUMELE_GAGNANT,

View File

@@ -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<Mise, Long> {
}

View File

@@ -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<User, Long> {
// Récupérer un utilisateur par identifiant (connexion)
Optional<User> 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);
}

View File

@@ -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);
}
}

View File

@@ -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<Mise> 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);
}
}

View File

@@ -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);

View File

@@ -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