357 lines
8.4 KiB
Go
357 lines
8.4 KiB
Go
// veza-backend-api/internal/api/user/handler.go
|
|
package user
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"veza-backend-api/internal/common"
|
|
"veza-backend-api/internal/response"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid" // Added import
|
|
)
|
|
|
|
type Handler struct {
|
|
service *Service
|
|
}
|
|
|
|
func NewHandler(service *Service) *Handler {
|
|
return &Handler{service: service}
|
|
}
|
|
|
|
// GetMe récupère le profil de l'utilisateur connecté
|
|
func (h *Handler) GetMe(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
user, err := h.service.GetUserByID(userID)
|
|
if err != nil {
|
|
response.NotFound(c, "User not found")
|
|
return
|
|
}
|
|
|
|
response.Success(c, user)
|
|
}
|
|
|
|
// UpdateMe met à jour le profil de l'utilisateur connecté
|
|
func (h *Handler) UpdateMe(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
var req UpdateUserRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request data")
|
|
return
|
|
}
|
|
|
|
user, err := h.service.UpdateUser(userID, req)
|
|
if err != nil {
|
|
response.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, user)
|
|
}
|
|
|
|
// ChangePassword change le mot de passe de l'utilisateur
|
|
func (h *Handler) ChangePassword(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
CurrentPassword string `json:"current_password" binding:"required"`
|
|
NewPassword string `json:"new_password" binding:"required,min=8"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request data")
|
|
return
|
|
}
|
|
|
|
err := h.service.ChangePassword(userID, req.CurrentPassword, req.NewPassword)
|
|
if err != nil {
|
|
response.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
// GetUsers liste tous les utilisateurs
|
|
func (h *Handler) GetUsers(c *gin.Context) {
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
|
search := c.Query("search")
|
|
|
|
users, total, err := h.service.GetUsers(page, limit, search)
|
|
if err != nil {
|
|
response.InternalServerError(c, "Failed to retrieve users")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"data": users,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"limit": limit,
|
|
"total": total,
|
|
"total_pages": (total + limit - 1) / limit,
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetUsersExceptMe liste tous les utilisateurs sauf l'utilisateur connecté
|
|
func (h *Handler) GetUsersExceptMe(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
|
search := c.Query("search")
|
|
|
|
// Ajouter le filtre pour exclure l'utilisateur actuel
|
|
users, total, err := h.service.GetUsers(page, limit, search)
|
|
if err != nil {
|
|
response.InternalServerError(c, "Failed to retrieve users")
|
|
return
|
|
}
|
|
|
|
// Filtrer l'utilisateur connecté
|
|
filteredUsers := []UserResponse{}
|
|
for _, user := range users {
|
|
if user.ID != userID { // Direct comparison of uuid.UUID
|
|
filteredUsers = append(filteredUsers, user)
|
|
}
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"data": filteredUsers,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"limit": limit,
|
|
"total": total - 1, // -1 car on exclut l'utilisateur connecté
|
|
"total_pages": (total + limit - 2) / limit,
|
|
},
|
|
})
|
|
}
|
|
|
|
// SearchUsers recherche des utilisateurs
|
|
func (h *Handler) SearchUsers(c *gin.Context) {
|
|
query := c.Query("q")
|
|
if query == "" {
|
|
response.BadRequest(c, "Query parameter 'q' is required")
|
|
return
|
|
}
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
|
|
|
users, total, err := h.service.GetUsers(page, limit, query)
|
|
if err != nil {
|
|
response.InternalServerError(c, "Failed to search users")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"data": users,
|
|
"pagination": gin.H{
|
|
"page": page,
|
|
"limit": limit,
|
|
"total": total,
|
|
"total_pages": (total + limit - 1) / limit,
|
|
},
|
|
})
|
|
}
|
|
|
|
func (h *Handler) GetUserAvatar(c *gin.Context) {
|
|
idStr := c.Param("id")
|
|
userID, err := uuid.Parse(idStr)
|
|
if err != nil {
|
|
response.BadRequest(c, "Invalid user ID")
|
|
return
|
|
}
|
|
|
|
user, err := h.service.GetUserByID(userID)
|
|
if err != nil {
|
|
response.NotFound(c, "User not found")
|
|
return
|
|
}
|
|
|
|
// ✅ Correct way to handle sql.NullString
|
|
if !user.Avatar.Valid || user.Avatar.String == "" {
|
|
response.NotFound(c, "No avatar found")
|
|
return
|
|
}
|
|
|
|
// Rediriger vers l'URL de l'avatar ou servir le fichier
|
|
c.Redirect(http.StatusFound, user.Avatar.String)
|
|
}
|
|
|
|
// GetPreferences récupère les préférences de l'utilisateur connecté
|
|
func (h *Handler) GetPreferences(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
preferences, err := h.service.GetUserPreferences(userID)
|
|
if err != nil {
|
|
response.InternalServerError(c, "Failed to get preferences")
|
|
return
|
|
}
|
|
|
|
response.Success(c, preferences)
|
|
}
|
|
|
|
// UpdatePreferences met à jour les préférences de l'utilisateur connecté
|
|
func (h *Handler) UpdatePreferences(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
var req UserPreferencesRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request data")
|
|
return
|
|
}
|
|
|
|
preferences, err := h.service.UpdateUserPreferences(userID, req)
|
|
if err != nil {
|
|
response.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, preferences)
|
|
}
|
|
|
|
// DeleteAccount supprime le compte de l'utilisateur (soft delete)
|
|
func (h *Handler) DeleteAccount(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Password string `json:"password" binding:"required"`
|
|
Reason string `json:"reason"`
|
|
ConfirmText string `json:"confirm_text" binding:"required"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request data")
|
|
return
|
|
}
|
|
|
|
// Vérifier le texte de confirmation
|
|
if req.ConfirmText != "DELETE" {
|
|
response.BadRequest(c, "Confirmation text must be 'DELETE'")
|
|
return
|
|
}
|
|
|
|
err := h.service.DeleteAccount(userID, req.Password, req.Reason)
|
|
if err != nil {
|
|
response.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
// RecoverAccount récupère un compte supprimé
|
|
func (h *Handler) RecoverAccount(c *gin.Context) {
|
|
var req struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Password string `json:"password" binding:"required"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request data")
|
|
return
|
|
}
|
|
|
|
err := h.service.RecoverAccount(req.Email, req.Password)
|
|
if err != nil {
|
|
response.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
// ExportData exporte les données de l'utilisateur (RGPD)
|
|
func (h *Handler) ExportData(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
exportData, err := h.service.ExportUserData(userID)
|
|
if err != nil {
|
|
response.InternalServerError(c, "Failed to export user data")
|
|
return
|
|
}
|
|
|
|
response.Success(c, exportData)
|
|
}
|
|
|
|
// RequestDataDeletion demande la suppression définitive des données (RGPD)
|
|
func (h *Handler) RequestDataDeletion(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Password string `json:"password" binding:"required"`
|
|
Reason string `json:"reason"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.BadRequest(c, "Invalid request data")
|
|
return
|
|
}
|
|
|
|
err := h.service.RequestDataDeletion(userID, req.Password, req.Reason)
|
|
if err != nil {
|
|
response.BadRequest(c, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, nil)
|
|
}
|
|
|
|
// GetAccountStatus récupère le statut du compte
|
|
func (h *Handler) GetAccountStatus(c *gin.Context) {
|
|
userID, exists := common.GetUserIDFromContext(c)
|
|
if !exists {
|
|
response.Unauthorized(c, "User ID not found")
|
|
return
|
|
}
|
|
|
|
status, err := h.service.GetAccountStatus(userID)
|
|
if err != nil {
|
|
response.InternalServerError(c, "Failed to get account status")
|
|
return
|
|
}
|
|
|
|
response.Success(c, status)
|
|
}
|