adding new feature for updating new roles

This commit is contained in:
areeqakbr 2025-06-19 19:35:02 +07:00
parent f84ec65fbb
commit e35edf3172
4 changed files with 277 additions and 50 deletions

View File

@ -1,89 +1,263 @@
package controller
import (
"net/http"
"users_management/m/middleware"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
"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 UserManagementController struct {
type UserRoleManagementController struct {
userUC usecase.UsersUsecase
rg *gin.RouterGroup
}
func NewUserManagementController(userUC usecase.UsersUsecase, rg *gin.RouterGroup) *UserManagementController {
return &UserManagementController{
func NewUserRoleManagementController(userUC usecase.UsersUsecase, rg *gin.RouterGroup) *UserRoleManagementController {
return &UserRoleManagementController{
userUC: userUC,
rg: rg,
}
}
func (c *UserManagementController) Route() {
users := c.rg.Group("/user-management")
func (c *UserRoleManagementController) Route() {
userRole := c.rg.Group("/user-role-management")
userRole.Use(middleware.RequireAdminRole()) // Only Admin and Super Admin can access
{
// Only superadmin can manage user roles
users.PUT("/role", middleware.RequireSuperAdminRole(), c.updateUserRole)
// Admins and superadmins can view all users
users.GET("/users", middleware.RequireAdminRole(), c.getAllUsers)
// Users can view their own profile
users.GET("/profile", c.getMyProfile)
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 UpdateRoleRequest struct {
NomorInduk string `json:"nomor_induk" binding:"required"`
RoleName string `json:"role_name" binding:"required"`
type UpdateUserRoleByIDRequest struct {
NewRole string `json:"new_role" binding:"required,oneof=Teknisi Admin"`
}
func (c *UserManagementController) updateUserRole(ctx *gin.Context) {
var req UpdateRoleRequest
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
}
err := c.userUC.UpdateUserRole(req.NomorInduk, req.RoleName)
if err != nil {
common.ErrorResponses(ctx, http.StatusInternalServerError, err.Error())
return
}
common.SingleResponses(ctx, "User role updated successfully", nil)
}
func (c *UserManagementController) getAllUsers(ctx *gin.Context) {
users, err := c.userUC.GetAllUsers()
if err != nil {
common.ErrorResponses(ctx, http.StatusInternalServerError, err.Error())
return
}
common.SingleResponses(ctx, "Users retrieved successfully", users)
}
func (c *UserManagementController) getMyProfile(ctx *gin.Context) {
userID, exists := ctx.Get("userID")
// Get current user role to check permissions
currentUserRole, exists := ctx.Get("userRole")
if !exists {
common.ErrorResponses(ctx, http.StatusUnauthorized, "User ID not found")
common.ErrorResponses(ctx, http.StatusUnauthorized, "User role not found")
return
}
nomorInduk, ok := userID.(string)
currentUserRoleStr, ok := currentUserRole.(string)
if !ok {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid user ID")
common.ErrorResponses(ctx, http.StatusUnauthorized, "Invalid user role format")
return
}
user, err := c.userUC.GetUserByNomorInduk(nomorInduk)
// 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
}
common.SingleResponses(ctx, "User profile retrieved successfully", user)
// 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")
}

View File

@ -78,6 +78,7 @@ func (s *Server) setupController() {
protectedRegistration.PUT("/approve/:id", middleware.RequireAdminRole(), controller.NewUserRegistrationController(s.ucManager.NewUserUsecase(), protected).ApproveUser)
protectedRegistration.PUT("/reject/:id", middleware.RequireAdminRole(), controller.NewUserRegistrationController(s.ucManager.NewUserUsecase(), protected).RejectUser)
}
controller.NewUserRoleManagementController(s.ucManager.NewUserUsecase(), protected).Route()
controller.NewUsersController(s.ucManager.NewUserUsecase(), s.ucManager.NewAuthUsecase(), protected).Route()
controller.NewCountAssetsController(s.ucManager.NewCountAssetsUsecase(), protected).Route()
controller.NewDeviceController(s.ucManager.NewDeviceUsecase(), protected, s.cfg).Route()

View File

@ -21,6 +21,8 @@ type UsersRepo interface {
GetUserByID(userID uuid.UUID) (entity.User, error)
GetUserByUsernameWithStatus(username string) (entity.User, error)
CreateSuperAdminBypass(user entity.User) error
UpdateUserRoleByID(userID uuid.UUID, roleID uuid.UUID) error
UpdateUserRoleByUsername(username string, roleID uuid.UUID) error
}
type usersRepo struct {
@ -33,6 +35,14 @@ func NewUsersRepo(db *gorm.DB) UsersRepo {
}
}
func (r *usersRepo) UpdateUserRoleByID(userID uuid.UUID, roleID uuid.UUID) error {
return r.db.Model(&entity.User{}).Where("id = ?", userID).Update("role_id", roleID).Error
}
func (r *usersRepo) UpdateUserRoleByUsername(username string, roleID uuid.UUID) error {
return r.db.Model(&entity.User{}).Where("username = ?", username).Update("role_id", roleID).Error
}
func (r *usersRepo) CreateSuperAdminBypass(user entity.User) error {
return r.db.Create(&user).Error
}

View File

@ -25,6 +25,9 @@ type UsersUsecase interface {
RejectUser(userID uuid.UUID) error
GetUserByUsernameWithStatus(username string) (entity.User, error)
CreateSuperAdminBypass(user entity.User) error
UpdateUserRoleByID(userID uuid.UUID, newRoleName string) error
UpdateUserRoleByUsername(username, newRoleName string) error
GetUserByID(userID uuid.UUID) (entity.User, error)
}
@ -45,6 +48,45 @@ func (u *usersUsecase) CreateSuperAdminBypass(user entity.User) error {
return u.userRepo.CreateSuperAdminBypass(user)
}
// Add these implementations to the usersUsecase struct
func (u *usersUsecase) UpdateUserRoleByID(userID uuid.UUID, newRoleName string) error {
// Get the new role ID
newRoleID, err := u.GetRoleByDepartment(newRoleName)
if err != nil {
return errors.New("invalid role name: " + err.Error())
}
// Check if user exists
_, err = u.userRepo.GetUserByID(userID)
if err != nil {
return errors.New("user not found")
}
// Update user role
return u.userRepo.UpdateUserRoleByID(userID, newRoleID)
}
func (u *usersUsecase) UpdateUserRoleByUsername(username, newRoleName string) error {
// Get the new role ID
newRoleID, err := u.GetRoleByDepartment(newRoleName)
if err != nil {
return errors.New("invalid role name: " + err.Error())
}
// Check if user exists
_, err = u.userRepo.GetUserByUsernameWithStatus(username)
if err != nil {
return errors.New("user not found")
}
// Update user role by username
return u.userRepo.UpdateUserRoleByUsername(username, newRoleID)
}
func (u *usersUsecase) GetUserByID(userID uuid.UUID) (entity.User, error) {
return u.userRepo.GetUserByID(userID)
}
func (u *usersUsecase) RegisterUser(registerDTO dto.UserRegisterDTO) error {
// Validate input
if err := u.validate.Struct(registerDTO); err != nil {