233 lines
5.2 KiB
Go
233 lines
5.2 KiB
Go
|
|
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)
|
||
|
|
}
|