splitting the services
This commit is contained in:
@@ -47,11 +47,23 @@ public class AgentController {
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "Supprimer un Agent")
|
||||
@Operation(summary = "Désactiver un Agent")
|
||||
public ResponseEntity<String> deleteAgent(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(agentService.deleteAgent(id));
|
||||
}
|
||||
|
||||
@PutMapping("/toggle-status/{id}")
|
||||
@Operation(summary = "Activer ou désactiver un Agent")
|
||||
public ResponseEntity<Agent> toggleAgentStatus(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(agentService.toggleAgentStatus(id));
|
||||
}
|
||||
|
||||
@PutMapping("/restore/{id}")
|
||||
public ResponseEntity<Agent> restoreAgent(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(agentService.restoreAgent(id));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/code/{code}")
|
||||
@Operation(summary = "Obtenir un Agent par code")
|
||||
public ResponseEntity<Agent> getAgentByCode(@PathVariable String code) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.pmu.betengine.controller;
|
||||
|
||||
import com.pmu.betengine.model.Agent;
|
||||
import com.pmu.betengine.model.AuthRequest;
|
||||
import com.pmu.betengine.model.AuthRequestAgent;
|
||||
import com.pmu.betengine.model.AuthResponse;
|
||||
import com.pmu.betengine.model.User;
|
||||
import com.pmu.betengine.service.AuthService;
|
||||
@@ -24,4 +26,10 @@ public class AuthController {
|
||||
return ResponseEntity.ok(loggedUser);
|
||||
}
|
||||
|
||||
// AGENT LOGIN via TPE
|
||||
@PostMapping("/agent/login")
|
||||
public ResponseEntity<Agent> loginAgent(@RequestBody AuthRequestAgent request) {
|
||||
Agent loggedAgent = authService.loginAgentWithPin(request);
|
||||
return ResponseEntity.ok(loggedAgent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,4 +100,5 @@ public class CourseController {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -46,13 +46,28 @@ public class HippodromeController {
|
||||
return ResponseEntity.ok(hippodromeService.updateHippodrome(id, hippodrome));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@DeleteMapping("/delete/{id}")
|
||||
@Operation(summary = "Supprimer un Hippodrome")
|
||||
public ResponseEntity<Void> deleteHippodrome(@PathVariable Long id) {
|
||||
hippodromeService.deleteHippodrome(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@PutMapping("/restore/{id}")
|
||||
public ResponseEntity<Hippodrome> restoreHippodrome(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(hippodromeService.restoreHippodrome(id));
|
||||
}
|
||||
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "Desactiver un Hippodrome")
|
||||
public ResponseEntity<Void> deleteHippodrome2(@PathVariable Long id) {
|
||||
hippodromeService.deleteHippodrome2(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/ville/{ville}")
|
||||
@Operation(summary = "Lister les Hippodromes par ville")
|
||||
public ResponseEntity<List<Hippodrome>> getHippodromesByVille(@PathVariable String ville) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/ ")
|
||||
@RequestMapping("/api/v1")
|
||||
@CrossOrigin(origins = "*")
|
||||
@Tag(name = "Gestion des Mises", description = "Endpoints relatifs aux Mises")
|
||||
public class MiseController {
|
||||
|
||||
@@ -3,8 +3,12 @@ package com.pmu.betengine.controller;
|
||||
import com.pmu.betengine.model.Cheval;
|
||||
import com.pmu.betengine.model.Course;
|
||||
import com.pmu.betengine.model.Resultat;
|
||||
import com.pmu.betengine.model.SearchParam;
|
||||
import com.pmu.betengine.service.CourseService;
|
||||
import com.pmu.betengine.service.ResultatService;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -123,6 +127,13 @@ public ResponseEntity<Resultat> publishResultat(@RequestBody Resultat dto) {
|
||||
return ResponseEntity.ok(saved);
|
||||
}
|
||||
|
||||
@PostMapping("/searchByParams")
|
||||
@Operation(summary = "Rechercher des résultats avec critères")
|
||||
public ResponseEntity<List<Resultat>> searchResultats(@RequestBody SearchParam searchParam) {
|
||||
return ResponseEntity.ok(resultatService.search(searchParam));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -46,12 +46,25 @@ public class ReunionController {
|
||||
return ResponseEntity.ok(reunionService.updateReunion(id, reunion));
|
||||
}
|
||||
|
||||
// @DeleteMapping("/{id}")
|
||||
// @Operation(summary = "Supprimer une Réunion")
|
||||
// public ResponseEntity<String> deleteReunion(@PathVariable Long id) {
|
||||
// return ResponseEntity.ok(reunionService.deleteReunion(id));
|
||||
// }
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "Supprimer une Réunion")
|
||||
@Operation(summary = "Désactiver une Réunion")
|
||||
public ResponseEntity<String> deleteReunion(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(reunionService.deleteReunion(id));
|
||||
}
|
||||
|
||||
@PutMapping("/restore/{id}")
|
||||
@Operation(summary = "Restaurer une Réunion désactivée")
|
||||
public ResponseEntity<Reunion> restoreReunion(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(reunionService.restoreReunion(id));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/code/{code}")
|
||||
@Operation(summary = "Obtenir une Réunion par code")
|
||||
public ResponseEntity<Reunion> getReunionByCode(@PathVariable String code) {
|
||||
|
||||
@@ -33,7 +33,10 @@ public class Agent {
|
||||
private String profile;
|
||||
private String principalCode;
|
||||
private String caisseProfile;
|
||||
private String statut;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private StatutAgent statut = StatutAgent.ACTIF;
|
||||
|
||||
private String zone;
|
||||
private String kiosk;
|
||||
private String fonction;
|
||||
@@ -41,6 +44,10 @@ public class Agent {
|
||||
@Column(name = "date_embauche")
|
||||
private LocalDateTime dateEmbauche;
|
||||
|
||||
@Column(name = "derniere_connexion")
|
||||
private LocalDateTime derniereConnexion;
|
||||
|
||||
|
||||
private String nom;
|
||||
private String prenom;
|
||||
private String autresNoms;
|
||||
@@ -62,14 +69,11 @@ public class Agent {
|
||||
private Double limiteMaxAirtime;
|
||||
|
||||
private Integer maxPeripheriques;
|
||||
|
||||
@OneToMany(mappedBy = "agent")
|
||||
@JsonIgnore
|
||||
private List<TPE> tpes;
|
||||
|
||||
@Column(name = "limit_id")
|
||||
private Long limitId;
|
||||
|
||||
private String nationalite;
|
||||
private String cni;
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.pmu.betengine.model;
|
||||
|
||||
public class AuthRequestAgent {
|
||||
private String pin;
|
||||
|
||||
// Getter and Setter
|
||||
public String getPin() { return pin; }
|
||||
public void setPin(String pin) { this.pin = pin; }
|
||||
}
|
||||
@@ -33,11 +33,14 @@ public class Hippodrome {
|
||||
|
||||
private String description;
|
||||
|
||||
@Column(name = "created_at")
|
||||
@CreationTimestamp
|
||||
@Column(name = "created_at", updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@UpdateTimestamp
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
}
|
||||
|
||||
// @Table(name = "hippodrome")
|
||||
|
||||
@@ -33,7 +33,9 @@ public class Reunion {
|
||||
|
||||
private Integer numero;
|
||||
|
||||
private String statut;
|
||||
@Column(name = "statut", nullable = false)
|
||||
@Builder.Default
|
||||
private String statut = "ACTIF";
|
||||
|
||||
@Column(name = "hippodrome_id")
|
||||
private Long hippodromeId;
|
||||
|
||||
@@ -10,5 +10,11 @@ public enum TypePari {
|
||||
QUATRO,
|
||||
QUARTE_PLUS,
|
||||
MULTI,
|
||||
QUINTE_PLUS
|
||||
QUINTE_PLUS,
|
||||
|
||||
TIERCE,
|
||||
QUARTE,
|
||||
QUINTE,
|
||||
COUPLE_GAGNANT,
|
||||
COUPLE_PLACE
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ public interface AgentRepository extends JpaRepository<Agent, Long> {
|
||||
|
||||
Optional<Agent> findByCode(String code);
|
||||
|
||||
Optional<Agent> findByPin(String pin);
|
||||
|
||||
boolean existsByCode(String code);
|
||||
|
||||
List<Agent> findByStatut(String statut);
|
||||
|
||||
@@ -10,12 +10,14 @@ import java.util.List;
|
||||
public interface HippodromeRepository extends JpaRepository<Hippodrome, Long> {
|
||||
|
||||
boolean existsByNom(String nom);
|
||||
|
||||
List<Hippodrome> findByVille(String ville);
|
||||
|
||||
List<Hippodrome> findByPays(String pays);
|
||||
|
||||
List<Hippodrome> findByActif(boolean actif);
|
||||
|
||||
List<Hippodrome> findByNomContainingIgnoreCase(String nom);
|
||||
|
||||
|
||||
List<Hippodrome> findByActifTrue();
|
||||
List<Hippodrome> findByVilleAndActifTrue(String ville);
|
||||
List<Hippodrome> findByPaysAndActifTrue(String pays);
|
||||
List<Hippodrome> findByNomContainingIgnoreCaseAndActifTrue(String nom);
|
||||
}
|
||||
|
||||
@@ -8,24 +8,24 @@ import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface ResultatRepository extends JpaRepository<Resultat, Long> {
|
||||
|
||||
Optional<Resultat> findByCourseId(Long courseId);
|
||||
|
||||
@Query("SELECT r FROM Resultat r WHERE r.course.id = :courseId")
|
||||
Optional<Resultat> findByCourse(@Param("courseId") Long courseId);
|
||||
|
||||
boolean existsByCourseId(Long courseId);
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM Resultat r WHERE r.course.id = :courseId")
|
||||
void deleteByCourseId(@Param("courseId") Long courseId);
|
||||
}
|
||||
@Query("SELECT r FROM Resultat r WHERE r.course.dateDebutParis >= :start AND r.course.dateDebutParis < :end")
|
||||
List<Resultat> findByCourseDate(@Param("start") LocalDateTime start, @Param("end") LocalDateTime end);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// package com.pmu.betengine.repository;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.pmu.betengine.service;
|
||||
|
||||
import com.pmu.betengine.model.Agent;
|
||||
import com.pmu.betengine.model.statut.StatutAgent;
|
||||
import com.pmu.betengine.repository.AgentRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -27,7 +28,8 @@ public class AgentService {
|
||||
|
||||
// Get all
|
||||
public List<Agent> getAllAgents() {
|
||||
return agentRepository.findAll();
|
||||
// return agentRepository.findAll();
|
||||
return agentRepository.findByStatut(StatutAgent.ACTIF.name());
|
||||
}
|
||||
|
||||
// Get by ID
|
||||
@@ -82,13 +84,34 @@ public class AgentService {
|
||||
|
||||
// Delete
|
||||
public String deleteAgent(Long id) {
|
||||
if (!agentRepository.existsById(id)) {
|
||||
throw new RuntimeException("Agent non trouvé avec l'id: " + id);
|
||||
Agent agent = getAgentById(id);
|
||||
|
||||
if (agent.getStatut() == StatutAgent.INACTIF) {
|
||||
throw new RuntimeException("Cet agent est déjà désactivé.");
|
||||
}
|
||||
agentRepository.deleteById(id);
|
||||
return "Agent avec l'ID " + id + " supprimé avec succès.";
|
||||
|
||||
agent.setStatut(StatutAgent.INACTIF);
|
||||
agent.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
agentRepository.save(agent);
|
||||
|
||||
return "Agent désactivé avec succès (soft delete).";
|
||||
}
|
||||
|
||||
public Agent restoreAgent(Long id) {
|
||||
Agent agent = getAgentById(id);
|
||||
|
||||
if (agent.getStatut() == StatutAgent.ACTIF) {
|
||||
throw new RuntimeException("Cet agent est déjà actif.");
|
||||
}
|
||||
|
||||
agent.setStatut(StatutAgent.ACTIF);
|
||||
agent.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
return agentRepository.save(agent);
|
||||
}
|
||||
|
||||
|
||||
// Find by code
|
||||
public Agent getAgentByCode(String code) {
|
||||
return agentRepository.findByCode(code)
|
||||
@@ -100,6 +123,20 @@ public class AgentService {
|
||||
return agentRepository.findByStatut(statut);
|
||||
}
|
||||
|
||||
public Agent toggleAgentStatus(Long id) {
|
||||
Agent agent = getAgentById(id);
|
||||
|
||||
if (agent.getStatut() == StatutAgent.ACTIF) {
|
||||
agent.setStatut(StatutAgent.INACTIF);
|
||||
} else {
|
||||
agent.setStatut(StatutAgent.ACTIF);
|
||||
}
|
||||
|
||||
agent.setUpdatedAt(LocalDateTime.now());
|
||||
return agentRepository.save(agent);
|
||||
}
|
||||
|
||||
|
||||
// Find by ville
|
||||
public List<Agent> getAgentsByVille(String ville) {
|
||||
return agentRepository.findByVille(ville);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.pmu.betengine.service;
|
||||
|
||||
import com.pmu.betengine.model.AuthRequest;
|
||||
import com.pmu.betengine.model.AuthResponse;
|
||||
import com.pmu.betengine.model.AuthRequestAgent;
|
||||
import com.pmu.betengine.model.User;
|
||||
import com.pmu.betengine.model.Agent;
|
||||
import com.pmu.betengine.repository.UserRepository;
|
||||
import com.pmu.betengine.repository.AgentRepository;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
@@ -15,16 +17,17 @@ import java.time.LocalDateTime;
|
||||
public class AuthService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final AgentRepository agentRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
public AuthService(UserRepository userRepository) {
|
||||
public AuthService(UserRepository userRepository, AgentRepository agentRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.agentRepository = agentRepository;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// USER LOGIN
|
||||
public User login(AuthRequest request) {
|
||||
User user = userRepository.findByIdentifiant(request.getIdentifiant())
|
||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
||||
@@ -37,4 +40,15 @@ public class AuthService {
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
// AGENT ALR LOGIN
|
||||
public Agent loginAgentWithPin(AuthRequestAgent request) {
|
||||
Agent agent = agentRepository.findByPin(request.getPin())
|
||||
.orElseThrow(() -> new RuntimeException("Invalid PIN"));
|
||||
|
||||
agent.setDerniereConnexion(LocalDateTime.now());
|
||||
agentRepository.save(agent);
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,28 @@ public class HippodromeService {
|
||||
hippodromeRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public void deleteHippodrome2(Long id) {
|
||||
Hippodrome hippodrome = hippodromeRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("Hippodrome non trouvé"));
|
||||
|
||||
hippodrome.setActif(false);
|
||||
hippodromeRepository.save(hippodrome);
|
||||
}
|
||||
|
||||
public Hippodrome restoreHippodrome(Long id) {
|
||||
Hippodrome hippodrome = hippodromeRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("Hippodrome non trouvé"));
|
||||
|
||||
if (hippodrome.getActif()) {
|
||||
throw new RuntimeException("Hippodrome est déjà actif");
|
||||
}
|
||||
|
||||
hippodrome.setActif(true);
|
||||
return hippodromeRepository.save(hippodrome);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Search by ville
|
||||
public List<Hippodrome> getHippodromesByVille(String ville) {
|
||||
return hippodromeRepository.findByVille(ville);
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.pmu.betengine.service;
|
||||
|
||||
import com.pmu.betengine.model.Course;
|
||||
import com.pmu.betengine.model.Resultat;
|
||||
import com.pmu.betengine.model.SearchParam;
|
||||
import com.pmu.betengine.repository.ResultatRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@@ -12,7 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Map;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@@ -68,6 +70,41 @@ public class ResultatService {
|
||||
return savedResultat;
|
||||
}
|
||||
|
||||
public List<Resultat> search(SearchParam searchParam) {
|
||||
System.out.println("******************** SEARCH PARAM: " + searchParam);
|
||||
|
||||
if (searchParam.getCriteria() == null) {
|
||||
throw new IllegalArgumentException("Le paramètre 'criteria' est obligatoire et ne peut pas être null");
|
||||
}
|
||||
|
||||
try {
|
||||
String criteria = searchParam.getCriteria();
|
||||
|
||||
if ("1".equals(criteria)) {
|
||||
// Retourne tous les résultats
|
||||
return resultatRepository.findAll();
|
||||
} else if ("2".equals(criteria) && searchParam.getDate() != null) {
|
||||
LocalDate date = searchParam.getDate();
|
||||
LocalDateTime startOfDay = date.atStartOfDay();
|
||||
LocalDateTime endOfDay = startOfDay.plusDays(1);
|
||||
|
||||
return resultatRepository.findByCourseDate(startOfDay, endOfDay);
|
||||
} else if ("3".equals(criteria) && searchParam.getId() != null) {
|
||||
return resultatRepository.findByCourseId(searchParam.getId())
|
||||
.map(List::of)
|
||||
.orElse(List.of());
|
||||
}
|
||||
|
||||
// Cas par défaut
|
||||
return resultatRepository.findAll();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Erreur lors de la recherche des résultats");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -37,10 +37,46 @@ public class ReunionService {
|
||||
|
||||
|
||||
// Get all
|
||||
public List<Reunion> getAllReunions() {
|
||||
return reunionRepository.findAll();
|
||||
// public List<Reunion> getAllReunions() {
|
||||
// return reunionRepository.findAll();
|
||||
// }
|
||||
// Soft delete
|
||||
public String deleteReunion(Long id) {
|
||||
Reunion reunion = getReunionById(id);
|
||||
|
||||
if ("INACTIF".equals(reunion.getStatut())) {
|
||||
throw new RuntimeException("Cette réunion est déjà désactivée.");
|
||||
}
|
||||
|
||||
reunion.setStatut("INACTIF");
|
||||
reunion.setUpdatedAt(LocalDateTime.now());
|
||||
reunionRepository.save(reunion);
|
||||
|
||||
return "Réunion désactivée avec succès.";
|
||||
}
|
||||
|
||||
// Optional: restore
|
||||
public Reunion restoreReunion(Long id) {
|
||||
Reunion reunion = getReunionById(id);
|
||||
|
||||
if ("ACTIF".equals(reunion.getStatut())) {
|
||||
throw new RuntimeException("Cette réunion est déjà active.");
|
||||
}
|
||||
|
||||
reunion.setStatut("ACTIF");
|
||||
reunion.setUpdatedAt(LocalDateTime.now());
|
||||
return reunionRepository.save(reunion);
|
||||
}
|
||||
|
||||
// Override getAll to return only active reunions
|
||||
public List<Reunion> getAllReunions() {
|
||||
return reunionRepository.findAll()
|
||||
.stream()
|
||||
.filter(r -> "ACTIF".equals(r.getStatut()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
// Get by ID
|
||||
public Reunion getReunionById(Long id) {
|
||||
return reunionRepository.findById(id)
|
||||
@@ -62,13 +98,13 @@ public class ReunionService {
|
||||
}
|
||||
|
||||
// Delete
|
||||
public String deleteReunion(Long id) {
|
||||
if (!reunionRepository.existsById(id)) {
|
||||
throw new RuntimeException("Réunion non trouvée avec l'id: " + id);
|
||||
}
|
||||
reunionRepository.deleteById(id);
|
||||
return "Réunion avec l'ID " + id + " supprimée avec succès.";
|
||||
}
|
||||
// public String deleteReunion(Long id) {
|
||||
// if (!reunionRepository.existsById(id)) {
|
||||
// throw new RuntimeException("Réunion non trouvée avec l'id: " + id);
|
||||
// }
|
||||
// reunionRepository.deleteById(id);
|
||||
// return "Réunion avec l'ID " + id + " supprimée avec succès.";
|
||||
// }
|
||||
|
||||
// Find by code
|
||||
public Reunion getReunionByCode(String code) {
|
||||
|
||||
Reference in New Issue
Block a user