package usecase import ( "errors" "time" "users_management/m/model/dto" "users_management/m/model/entity" "users_management/m/repository" "users_management/m/utils" "github.com/go-playground/validator/v10" "github.com/google/uuid" ) type UsersUsecase interface { GetRoleByDepartment(departmentName string) (uuid.UUID, error) GetUserByUsername(username string) (entity.User, error) GetUserByNomorInduk(nomorInduk string) (entity.User, error) // Add this CreateUserFromExternal(nomorInduk, name, roleName string) error // Add this UpdateUserRole(nomorInduk, roleName string) error // Add this GetAllUsers() ([]entity.User, error) // Add this RegisterUser(registerDTO dto.UserRegisterDTO) error GetPendingUsers() ([]dto.PendingUserResponse, error) ApproveUser(userID uuid.UUID) error 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) } type usersUsecase struct { userRepo repository.UsersRepo validate *validator.Validate } func NewUsersUsecase(userRepo repository.UsersRepo) UsersUsecase { return &usersUsecase{ userRepo: userRepo, validate: validator.New(), } } 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 { return err } // Check if username already exists existingUser, err := u.userRepo.GetUserByUsernameWithStatus(registerDTO.Username) if err == nil && existingUser.ID != uuid.Nil { return errors.New("username already exists") } // Check if nomor_induk already exists if registerDTO.NomorInduk != "" { existingUser, err := u.userRepo.GetUserByNomorInduk(registerDTO.NomorInduk) if err == nil && existingUser.ID != uuid.Nil { return errors.New("nomor induk already exists") } } // Hash password hashedPassword, err := utils.HashPassword(registerDTO.Password) if err != nil { return err } teknisiRoleID, err := u.GetRoleByDepartment("Teknisi") if err != nil { return errors.New("failed to get Teknisi role: " + err.Error()) } // Create user with pending status user := entity.User{ ID: uuid.New(), Name: registerDTO.Name, Username: registerDTO.Username, Password: hashedPassword, NomorInduk: ®isterDTO.NomorInduk, RoleID: teknisiRoleID, Status: entity.UserStatusPending, // Set status to pending CreatedAt: time.Now(), UpdatedAt: time.Now(), } return u.userRepo.RegisterUser(user) } func (u *usersUsecase) GetPendingUsers() ([]dto.PendingUserResponse, error) { users, err := u.userRepo.GetPendingUsers() if err != nil { return nil, err } var responses []dto.PendingUserResponse for _, user := range users { response := dto.PendingUserResponse{ ID: user.ID, Name: user.Name, Username: user.Username, NomorInduk: user.NomorInduk, RoleName: user.Role.Name, Status: dto.UserStatus(user.Status), CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } responses = append(responses, response) } return responses, nil } func (u *usersUsecase) ApproveUser(userID uuid.UUID) error { // Check if user exists and is pending user, err := u.userRepo.GetUserByID(userID) if err != nil { return errors.New("user not found") } if user.Status != entity.UserStatusPending { return errors.New("user is not in pending status") } return u.userRepo.UpdateUserStatus(userID, entity.UserStatusApproved) } func (u *usersUsecase) RejectUser(userID uuid.UUID) error { // Check if user exists and is pending user, err := u.userRepo.GetUserByID(userID) if err != nil { return errors.New("user not found") } if user.Status != entity.UserStatusPending { return errors.New("user is not in pending status") } return u.userRepo.UpdateUserStatus(userID, entity.UserStatusRejected) } func (u *usersUsecase) GetUserByUsernameWithStatus(username string) (entity.User, error) { return u.userRepo.GetUserByUsernameWithStatus(username) } func (u *usersUsecase) GetRoleByDepartment(departmentName string) (uuid.UUID, error) { role, err := u.userRepo.GetRoleByDepartment(departmentName) if err != nil { return uuid.Nil, err } return role.Id, nil } func (u *usersUsecase) GetUserByUsername(username string) (entity.User, error) { users, err := u.userRepo.GetUserByUsername(username) if err != nil { return users, err } return users, nil } // New methods for RBAC func (u *usersUsecase) GetUserByNomorInduk(nomorInduk string) (entity.User, error) { return u.userRepo.GetUserByNomorInduk(nomorInduk) } func (u *usersUsecase) CreateUserFromExternal(nomorInduk, name, roleName string) error { // Get role ID roleID, err := u.GetRoleByDepartment(roleName) if err != nil { return err } // Create user user := entity.User{ ID: uuid.New(), NomorInduk: &nomorInduk, RoleID: roleID, Name: name, Username: nomorInduk, // Use nomor_induk as username Password: "", // External auth, no local password needed CreatedAt: time.Now(), UpdatedAt: time.Now(), } return u.userRepo.CreateUserFromExternal(user) } func (u *usersUsecase) UpdateUserRole(nomorInduk, roleName string) error { roleID, err := u.GetRoleByDepartment(roleName) if err != nil { return err } return u.userRepo.UpdateUserRole(nomorInduk, roleID) } func (u *usersUsecase) GetAllUsers() ([]entity.User, error) { return u.userRepo.GetAllUsers() }