[BE-API-007] be-api: Implement roles management endpoints
- Standardized API responses in RoleHandler (RespondSuccess, RespondWithAppError) - Added GET /api/v1/roles endpoint - Added GET /api/v1/roles/:id endpoint - Added POST /api/v1/users/:userId/roles endpoint - Added DELETE /api/v1/users/:userId/roles/:roleId endpoint - Created setupRoleRoutes function for role routes - Handlers support both :id and :userId parameters - All endpoints require authentication Phase: PHASE-2 Priority: P1 Progress: 16/267 (6.0%)
This commit is contained in:
parent
19275ff79e
commit
0e7a0351f3
3 changed files with 75 additions and 26 deletions
|
|
@ -1423,7 +1423,18 @@
|
|||
"description": "GET /api/v1/roles, GET /api/v1/roles/:id, POST /api/v1/users/:userId/roles, DELETE /api/v1/users/:userId/roles/:roleId",
|
||||
"owner": "backend",
|
||||
"estimated_hours": 6,
|
||||
"status": "todo",
|
||||
"status": "completed",
|
||||
"completion": {
|
||||
"completed_at": "2025-12-23T09:37:27Z",
|
||||
"actual_hours": 1.0,
|
||||
"commits": [],
|
||||
"files_changed": [
|
||||
"veza-backend-api/internal/handlers/role_handler.go",
|
||||
"veza-backend-api/internal/api/router.go"
|
||||
],
|
||||
"notes": "Standardized API responses in RoleHandler to use RespondSuccess and RespondWithAppError. Added setupRoleRoutes function with GET /roles and GET /roles/:id routes. Added POST /users/:userId/roles and DELETE /users/:userId/roles/:roleId routes in setupUserRoutes. Handlers support both :id and :userId parameters for flexibility. All endpoints require authentication.",
|
||||
"issues_encountered": []
|
||||
},
|
||||
"files_involved": [],
|
||||
"implementation_steps": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -170,6 +170,9 @@ func (r *APIRouter) Setup(router *gin.Engine) error {
|
|||
r.setupUserRoutes(v1)
|
||||
r.setupTrackRoutes(v1)
|
||||
|
||||
// BE-API-007: Roles management routes
|
||||
r.setupRoleRoutes(v1)
|
||||
|
||||
// Réactivation des routes Chat pour Phase 4
|
||||
r.setupChatRoutes(v1)
|
||||
// Réactivation des routes Playlists pour Phase 5
|
||||
|
|
@ -382,6 +385,33 @@ func (r *APIRouter) setupUserRoutes(router *gin.RouterGroup) {
|
|||
protected.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("user", userOwnerResolver), profileHandler.UpdateProfile)
|
||||
|
||||
protected.GET("/:id/completion", profileHandler.GetProfileCompletion)
|
||||
|
||||
// BE-API-007: User role assignment routes
|
||||
roleService := services.NewRoleService(r.db.GormDB)
|
||||
roleHandler := handlers.NewRoleHandler(roleService, r.logger)
|
||||
protected.POST("/:userId/roles", roleHandler.AssignRole) // POST /api/v1/users/:userId/roles
|
||||
protected.DELETE("/:userId/roles/:roleId", roleHandler.RevokeRole) // DELETE /api/v1/users/:userId/roles/:roleId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setupRoleRoutes configure les routes de gestion des rôles
|
||||
// BE-API-007: Implement roles management endpoints
|
||||
func (r *APIRouter) setupRoleRoutes(router *gin.RouterGroup) {
|
||||
roleService := services.NewRoleService(r.db.GormDB)
|
||||
roleHandler := handlers.NewRoleHandler(roleService, r.logger)
|
||||
|
||||
// Roles routes
|
||||
roles := router.Group("/roles")
|
||||
{
|
||||
// Protected routes
|
||||
if r.config.AuthMiddleware != nil {
|
||||
protected := roles.Group("")
|
||||
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||
{
|
||||
protected.GET("", roleHandler.GetRoles) // GET /api/v1/roles
|
||||
protected.GET("/:id", roleHandler.GetRole) // GET /api/v1/roles/:id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"go.uber.org/zap"
|
||||
apperrors "veza-backend-api/internal/errors"
|
||||
"veza-backend-api/internal/models"
|
||||
"veza-backend-api/internal/services"
|
||||
)
|
||||
|
|
@ -26,34 +27,36 @@ func NewRoleHandler(roleService *services.RoleService, logger *zap.Logger) *Role
|
|||
}
|
||||
|
||||
// GetRoles récupère tous les rôles
|
||||
// BE-API-007: Implement roles management endpoints
|
||||
func (h *RoleHandler) GetRoles(c *gin.Context) {
|
||||
roles, err := h.roleService.GetRoles(c.Request.Context())
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get roles", err))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"roles": roles})
|
||||
RespondSuccess(c, http.StatusOK, roles)
|
||||
}
|
||||
|
||||
// GetRole récupère un rôle par ID
|
||||
// BE-API-007: Implement roles management endpoints
|
||||
func (h *RoleHandler) GetRole(c *gin.Context) {
|
||||
roleIDStr := c.Param("id")
|
||||
roleID, err := uuid.Parse(roleIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid role id"})
|
||||
RespondWithAppError(c, apperrors.NewValidationError("invalid role id"))
|
||||
return
|
||||
}
|
||||
|
||||
role, err := h.roleService.GetRole(c.Request.Context(), roleID)
|
||||
if err != nil {
|
||||
if err.Error() == "role not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
RespondWithAppError(c, apperrors.NewNotFoundError("role"))
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get role", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"role": role})
|
||||
RespondSuccess(c, http.StatusOK, role)
|
||||
}
|
||||
|
||||
// CreateRole crée un nouveau rôle
|
||||
|
|
@ -118,11 +121,17 @@ func (h *RoleHandler) DeleteRole(c *gin.Context) {
|
|||
}
|
||||
|
||||
// AssignRole assigne un rôle à un utilisateur
|
||||
// BE-API-007: Implement roles management endpoints
|
||||
// Supports both :id and :userId parameters for flexibility
|
||||
func (h *RoleHandler) AssignRole(c *gin.Context) {
|
||||
userIDStr := c.Param("id")
|
||||
// Try :userId first (from /users/:userId/roles), fallback to :id
|
||||
userIDStr := c.Param("userId")
|
||||
if userIDStr == "" {
|
||||
userIDStr = c.Param("id")
|
||||
}
|
||||
userID, err := uuid.Parse(userIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
|
||||
RespondWithAppError(c, apperrors.NewValidationError("invalid user id"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -136,50 +145,49 @@ func (h *RoleHandler) AssignRole(c *gin.Context) {
|
|||
}
|
||||
|
||||
// Récupérer l'ID de l'utilisateur qui assigne depuis le contexte
|
||||
assignedByInterface, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
assignedBy, ok := assignedByInterface.(uuid.UUID)
|
||||
assignedBy, ok := GetUserIDUUID(c)
|
||||
if !ok {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id type"})
|
||||
return
|
||||
return // Erreur déjà envoyée par GetUserIDUUID
|
||||
}
|
||||
|
||||
if err := h.roleService.AssignRoleToUser(c.Request.Context(), userID, req.RoleID, assignedBy, req.ExpiresAt); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to assign role", err))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "role assigned"})
|
||||
RespondSuccess(c, http.StatusOK, gin.H{"message": "role assigned"})
|
||||
}
|
||||
|
||||
// RevokeRole révoque un rôle d'un utilisateur
|
||||
// BE-API-007: Implement roles management endpoints
|
||||
// Supports both :id and :userId parameters for flexibility
|
||||
func (h *RoleHandler) RevokeRole(c *gin.Context) {
|
||||
userIDStr := c.Param("id")
|
||||
// Try :userId first (from /users/:userId/roles/:roleId), fallback to :id
|
||||
userIDStr := c.Param("userId")
|
||||
if userIDStr == "" {
|
||||
userIDStr = c.Param("id")
|
||||
}
|
||||
userID, err := uuid.Parse(userIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
|
||||
RespondWithAppError(c, apperrors.NewValidationError("invalid user id"))
|
||||
return
|
||||
}
|
||||
|
||||
roleIDStr := c.Param("roleId")
|
||||
roleID, err := uuid.Parse(roleIDStr)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid role id"})
|
||||
RespondWithAppError(c, apperrors.NewValidationError("invalid role id"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.roleService.RevokeRoleFromUser(c.Request.Context(), userID, roleID); err != nil {
|
||||
if err.Error() == "role assignment not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
RespondWithAppError(c, apperrors.NewNotFoundError("role assignment"))
|
||||
} else {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to revoke role", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "role revoked"})
|
||||
RespondSuccess(c, http.StatusOK, gin.H{"message": "role revoked"})
|
||||
}
|
||||
|
||||
// GetUserRoles récupère tous les rôles d'un utilisateur
|
||||
|
|
|
|||
Loading…
Reference in a new issue