NAM-APJATEL-BACKEND/usecase/users_usecase.go

264 lines
7.8 KiB
Go

package usecase
import (
"errors"
"time"
"users_management/m/model/dto"
"users_management/m/model/entity"
"users_management/m/repository"
"users_management/m/utils"
"users_management/m/utils/validation"
"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)
CreateUserFromExternal(nomorInduk, name, roleName string) error
UpdateUserRole(nomorInduk, roleName string) error
GetAllUsers() ([]entity.User, error)
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)
GetUserByName(name string) (entity.User, error)
}
type usersUsecase struct {
userRepo repository.UsersRepo
validate *validator.Validate
}
func NewUsersUsecase(userRepo repository.UsersRepo) UsersUsecase {
validate := validator.New()
validation.RegisterCustomValidators(validate)
return &usersUsecase{
userRepo: userRepo,
validate: validate,
}
}
func (u *usersUsecase) GetUserByName(name string) (entity.User, error) {
return u.userRepo.GetUserByName(name)
}
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")
}
}
existingUserByName, err := u.userRepo.GetUserByName(registerDTO.Name)
if err == nil && existingUserByName.ID != uuid.Nil {
return errors.New("name already exists, please use a different name")
}
// 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: &registerDTO.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()
}