NAM-APJATEL-BACKEND/delivery/controller/user_management_controller.go

263 lines
8.4 KiB
Go

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