Files
cardverse-be/internal/modules/user/service.go

233 lines
5.2 KiB
Go
Raw Normal View History

2026-07-30 09:51:25 +07:00
package user
import (
"errors"
"cardverse/internal/pkg/utils"
)
var ErrEmailTaken = errors.New("email sudah terdaftar")
var ErrUserNotFound = errors.New("user tidak ditemukan")
var ErrUserSuspended = errors.New("akun anda sedang disuspensi")
var ErrForbiddenRoleCreation = errors.New("hanya superadmin yang dapat membuat atau mengubah akun dengan role admin atau superadmin")
type Service interface {
Create(creatorID *uint, req CreateUserRequest) (*User, error)
GetAll() ([]User, error)
GetAllPaginated(query ListUserQuery) ([]User, int64, error)
GetByID(id uint) (*User, error)
Update(modifierID uint, id uint, req UpdateUserRequest) (*User, error)
UpdateProfile(userID uint, req UpdateProfileRequest) (*User, error)
UpdateAvatar(userID uint, avatarURL string) (*User, error)
SuspendUser(modifierID uint, id uint) (*User, error)
UnsuspendUser(modifierID uint, id uint) (*User, error)
Delete(id uint) error
}
type service struct {
repo Repository
}
func NewService(repo Repository) Service {
return &service{repo: repo}
}
func (s *service) Create(creatorID *uint, req CreateUserRequest) (*User, error) {
existing, _ := s.repo.FindByEmail(req.Email)
if existing != nil {
return nil, ErrEmailTaken
}
role := req.Role
if role == "" {
role = RoleUser
}
// Batasan role: Hanya Superadmin yang boleh membuat akun dengan role admin atau superadmin
if role == RoleAdmin || role == RoleSuperAdmin {
if creatorID == nil {
return nil, ErrForbiddenRoleCreation
}
creator, err := s.repo.FindByID(*creatorID)
if err != nil || creator.Role != RoleSuperAdmin {
return nil, ErrForbiddenRoleCreation
}
}
hashedPassword, err := utils.HashPassword(req.Password)
if err != nil {
return nil, err
}
newUser := &User{
Name: req.Name,
Email: req.Email,
Password: hashedPassword,
Role: role,
Status: StatusActive,
IsEmailVerified: true,
CreatedBy: creatorID,
}
if err := s.repo.Create(newUser); err != nil {
return nil, err
}
return newUser, nil
}
func (s *service) GetAll() ([]User, error) {
return s.repo.FindAll()
}
func (s *service) GetAllPaginated(query ListUserQuery) ([]User, int64, error) {
page := query.Page
if page < 1 {
page = 1
}
limit := query.Limit
if limit < 1 {
limit = 20
}
return s.repo.FindAllPaginated(page, limit, query)
}
func (s *service) GetByID(id uint) (*User, error) {
u, err := s.repo.FindByID(id)
if err != nil {
return nil, ErrUserNotFound
}
return u, nil
}
func (s *service) Update(modifierID uint, id uint, req UpdateUserRequest) (*User, error) {
u, err := s.repo.FindByID(id)
if err != nil {
return nil, ErrUserNotFound
}
if req.Name != "" {
u.Name = req.Name
}
if req.Email != "" && req.Email != u.Email {
existing, _ := s.repo.FindByEmail(req.Email)
if existing != nil {
return nil, ErrEmailTaken
}
u.Email = req.Email
}
if req.AvatarURL != "" {
if u.AvatarURL != nil && *u.AvatarURL != "" && *u.AvatarURL != req.AvatarURL {
utils.DeleteLocalFile(*u.AvatarURL)
}
u.AvatarURL = &req.AvatarURL
}
if req.Role != "" && req.Role != u.Role {
// Batasan role: Hanya Superadmin yang boleh mengubah role ke admin atau superadmin
if req.Role == RoleAdmin || req.Role == RoleSuperAdmin {
creator, err := s.repo.FindByID(modifierID)
if err != nil || creator.Role != RoleSuperAdmin {
return nil, ErrForbiddenRoleCreation
}
}
u.Role = req.Role
}
if req.Status != "" {
u.Status = req.Status
}
u.UpdatedBy = &modifierID
if err := s.repo.Update(u); err != nil {
return nil, err
}
return u, nil
}
func (s *service) UpdateProfile(userID uint, req UpdateProfileRequest) (*User, error) {
u, err := s.repo.FindByID(userID)
if err != nil {
return nil, ErrUserNotFound
}
if req.Name != "" {
u.Name = req.Name
}
if req.AvatarURL != "" {
if u.AvatarURL != nil && *u.AvatarURL != "" && *u.AvatarURL != req.AvatarURL {
utils.DeleteLocalFile(*u.AvatarURL)
}
u.AvatarURL = &req.AvatarURL
}
u.UpdatedBy = &userID
if err := s.repo.Update(u); err != nil {
return nil, err
}
return u, nil
}
func (s *service) UpdateAvatar(userID uint, avatarURL string) (*User, error) {
u, err := s.repo.FindByID(userID)
if err != nil {
return nil, ErrUserNotFound
}
// Hapus file avatar lama jika ada
if u.AvatarURL != nil && *u.AvatarURL != "" && *u.AvatarURL != avatarURL {
utils.DeleteLocalFile(*u.AvatarURL)
}
u.AvatarURL = &avatarURL
u.UpdatedBy = &userID
if err := s.repo.Update(u); err != nil {
return nil, err
}
return u, nil
}
func (s *service) SuspendUser(modifierID uint, id uint) (*User, error) {
u, err := s.repo.FindByID(id)
if err != nil {
return nil, ErrUserNotFound
}
u.Status = StatusSuspended
u.UpdatedBy = &modifierID
if err := s.repo.Update(u); err != nil {
return nil, err
}
return u, nil
}
func (s *service) UnsuspendUser(modifierID uint, id uint) (*User, error) {
u, err := s.repo.FindByID(id)
if err != nil {
return nil, ErrUserNotFound
}
u.Status = StatusActive
u.UpdatedBy = &modifierID
if err := s.repo.Update(u); err != nil {
return nil, err
}
return u, nil
}
func (s *service) Delete(id uint) error {
_, err := s.repo.FindByID(id)
if err != nil {
return ErrUserNotFound
}
return s.repo.Delete(id)
}