package controller import ( "errors" "net/http" "users_management/m/middleware" "users_management/m/usecase" "users_management/m/utils/common" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type UserRoleManagementController struct { userUC usecase.UsersUsecase rg *gin.RouterGroup } func NewUserRoleManagementController(userUC usecase.UsersUsecase, rg *gin.RouterGroup) *UserRoleManagementController { return &UserRoleManagementController{ userUC: userUC, rg: rg, } } func (c *UserRoleManagementController) Route() { userRole := c.rg.Group("/user-role-management") userRole.Use(middleware.RequireAdminRole()) // Only Admin and Super Admin can access { userRole.PUT("/update/:id", c.updateUserRoleByID) userRole.PUT("/update-by-username", c.updateUserRoleByUsername) userRole.GET("/users", c.getAllUsersWithRoles) userRole.GET("/available-roles", c.getAvailableRoles) } } type UpdateUserRoleByIDRequest struct { NewRole string `json:"new_role" binding:"required,oneof=Teknisi Admin"` } type UpdateUserRoleByUsernameRequest struct { Username string `json:"username" binding:"required"` NewRole string `json:"new_role" binding:"required,oneof=Teknisi Admin"` } func (c *UserRoleManagementController) updateUserRoleByID(ctx *gin.Context) { // Get user ID from URL parameter userIDStr := ctx.Param("id") userID, err := uuid.Parse(userIDStr) if err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid user ID format") return } var req UpdateUserRoleByIDRequest if err := ctx.ShouldBindJSON(&req); err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } // Get current user role to check permissions currentUserRole, exists := ctx.Get("userRole") if !exists { common.ErrorResponses(ctx, http.StatusUnauthorized, "User role not found") return } currentUserRoleStr, ok := currentUserRole.(string) if !ok { common.ErrorResponses(ctx, http.StatusUnauthorized, "Invalid user role format") return } // Get target user to check current role and prevent invalid operations targetUser, err := c.userUC.GetUserByID(userID) if err != nil { common.ErrorResponses(ctx, http.StatusNotFound, "User not found") return } // Validate role change permissions if err := c.validateRoleChange(currentUserRoleStr, targetUser.Role.Name, req.NewRole); err != nil { common.ErrorResponses(ctx, http.StatusForbidden, err.Error()) return } // Update user role err = c.userUC.UpdateUserRoleByID(userID, req.NewRole) if err != nil { common.ErrorResponses(ctx, http.StatusInternalServerError, "Failed to update user role: "+err.Error()) return } // Get updated user info updatedUser, err := c.userUC.GetUserByID(userID) if err != nil { // Role was updated but couldn't fetch updated info common.SingleResponses(ctx, "User role updated successfully", gin.H{ "user_id": userID, "new_role": req.NewRole, }) return } response := gin.H{ "user_id": updatedUser.ID, "username": updatedUser.Username, "name": updatedUser.Name, "previous_role": targetUser.Role.Name, "new_role": updatedUser.Role.Name, "updated_by": ctx.GetString("userName"), } common.SingleResponses(ctx, "User role updated successfully", response) } func (c *UserRoleManagementController) updateUserRoleByUsername(ctx *gin.Context) { var req UpdateUserRoleByUsernameRequest if err := ctx.ShouldBindJSON(&req); err != nil { common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) return } // Get current user role to check permissions currentUserRole, exists := ctx.Get("userRole") if !exists { common.ErrorResponses(ctx, http.StatusUnauthorized, "User role not found") return } currentUserRoleStr, ok := currentUserRole.(string) if !ok { common.ErrorResponses(ctx, http.StatusUnauthorized, "Invalid user role format") return } // Get target user targetUser, err := c.userUC.GetUserByUsernameWithStatus(req.Username) if err != nil { common.ErrorResponses(ctx, http.StatusNotFound, "User not found") return } // Validate role change permissions if err := c.validateRoleChange(currentUserRoleStr, targetUser.Role.Name, req.NewRole); err != nil { common.ErrorResponses(ctx, http.StatusForbidden, err.Error()) return } // Update user role by username err = c.userUC.UpdateUserRoleByUsername(req.Username, req.NewRole) if err != nil { common.ErrorResponses(ctx, http.StatusInternalServerError, "Failed to update user role: "+err.Error()) return } // Get updated user info updatedUser, err := c.userUC.GetUserByUsernameWithStatus(req.Username) if err != nil { // Role was updated but couldn't fetch updated info common.SingleResponses(ctx, "User role updated successfully", gin.H{ "username": req.Username, "new_role": req.NewRole, }) return } response := gin.H{ "user_id": updatedUser.ID, "username": updatedUser.Username, "name": updatedUser.Name, "previous_role": targetUser.Role.Name, "new_role": updatedUser.Role.Name, "updated_by": ctx.GetString("userName"), } common.SingleResponses(ctx, "User role updated successfully", response) } func (c *UserRoleManagementController) getAllUsersWithRoles(ctx *gin.Context) { users, err := c.userUC.GetAllUsers() if err != nil { common.ErrorResponses(ctx, http.StatusInternalServerError, "Failed to get users: "+err.Error()) return } // Filter and format response var userList []gin.H for _, user := range users { // Only show approved users if user.Status == "approved" { userInfo := gin.H{ "id": user.ID, "username": user.Username, "name": user.Name, "nomor_induk": user.NomorInduk, "role": user.Role.Name, "status": user.Status, "created_at": user.CreatedAt, "updated_at": user.UpdatedAt, } userList = append(userList, userInfo) } } response := gin.H{ "users": userList, "total": len(userList), } common.SingleResponses(ctx, "Users retrieved successfully", response) } func (c *UserRoleManagementController) getAvailableRoles(ctx *gin.Context) { roles := []gin.H{ { "name": "Teknisi", "description": "Technical user with limited administrative access", "can_be_assigned_by": []string{"Admin", "Super Admin"}, }, { "name": "Admin", "description": "Administrative user with full system access except user management", "can_be_assigned_by": []string{"Admin", "Super Admin"}, }, } currentUserRole := ctx.GetString("userRole") response := gin.H{ "available_roles": roles, "your_role": currentUserRole, "note": "You can update users between Teknisi and Admin roles only", } common.SingleResponses(ctx, "Available roles for assignment", response) } // Helper function to validate role change permissions func (c *UserRoleManagementController) validateRoleChange(currentUserRole, targetCurrentRole, newRole string) error { // Super Admin can change any role to Teknisi or Admin if currentUserRole == "Super Admin" { return nil } // Admin can change roles but with some restrictions if currentUserRole == "Admin" { // Admin cannot change Super Admin roles if targetCurrentRole == "Super Admin" { return errors.New("cannot modify Super Admin users") } // Admin cannot assign Super Admin role if newRole == "Super Admin" { return errors.New("cannot assign Super Admin role") } return nil } // Only Admin and Super Admin can change roles return errors.New("insufficient permissions to change user roles") }