256 lines
7.0 KiB
Go
Raw Normal View History

2025-07-18 20:10:29 +07:00
package processor
import (
"context"
"fmt"
"golang.org/x/crypto/bcrypt"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/mappers"
"apskel-pos-be/internal/models"
"github.com/google/uuid"
)
type UserProcessorImpl struct {
userRepo UserRepository
organizationRepo OrganizationRepository
outletRepo OutletRepository
}
func NewUserProcessor(
userRepo UserRepository,
organizationRepo OrganizationRepository,
outletRepo OutletRepository,
) *UserProcessorImpl {
return &UserProcessorImpl{
userRepo: userRepo,
organizationRepo: organizationRepo,
outletRepo: outletRepo,
}
}
func (p *UserProcessorImpl) CreateUser(ctx context.Context, req *models.CreateUserRequest) (*models.UserResponse, error) {
_, err := p.organizationRepo.GetByID(ctx, req.OrganizationID)
if err != nil {
return nil, fmt.Errorf("organization not found: %w", err)
}
if req.OutletID != nil {
_, err := p.outletRepo.GetByID(ctx, *req.OutletID)
if err != nil {
return nil, fmt.Errorf("outlet not found: %w", err)
}
}
existingUser, err := p.userRepo.GetByEmail(ctx, req.Email)
if err == nil && existingUser != nil {
return nil, fmt.Errorf("user with email %s already exists", req.Email)
}
passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
return nil, fmt.Errorf("failed to hash password: %w", err)
}
userEntity := mappers.UserCreateRequestToEntity(req, string(passwordHash))
err = p.userRepo.Create(ctx, userEntity)
if err != nil {
return nil, fmt.Errorf("failed to create user: %w", err)
}
return mappers.UserEntityToResponse(userEntity), nil
}
func (p *UserProcessorImpl) UpdateUser(ctx context.Context, id uuid.UUID, req *models.UpdateUserRequest) (*models.UserResponse, error) {
existingUser, err := p.userRepo.GetByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
if req.Email != nil && *req.Email != existingUser.Email {
existingUserByEmail, err := p.userRepo.GetByEmail(ctx, *req.Email)
if err == nil && existingUserByEmail != nil && existingUserByEmail.ID != id {
return nil, fmt.Errorf("user with email %s already exists", *req.Email)
}
}
if req.Name != nil {
existingUser.Name = *req.Name
}
if req.Email != nil {
existingUser.Email = *req.Email
}
if req.Role != nil {
existingUser.Role = entities.UserRole(*req.Role)
}
if req.OutletID != nil {
existingUser.OutletID = req.OutletID
}
if req.IsActive != nil {
existingUser.IsActive = *req.IsActive
}
if req.Permissions != nil {
existingUser.Permissions = entities.Permissions(*req.Permissions)
}
err = p.userRepo.Update(ctx, existingUser)
if err != nil {
return nil, fmt.Errorf("failed to update user: %w", err)
}
return mappers.UserEntityToResponse(existingUser), nil
}
func (p *UserProcessorImpl) DeleteUser(ctx context.Context, id uuid.UUID) error {
_, err := p.userRepo.GetByID(ctx, id)
if err != nil {
return fmt.Errorf("user not found: %w", err)
}
err = p.userRepo.Delete(ctx, id)
if err != nil {
return fmt.Errorf("failed to delete user: %w", err)
}
return nil
}
func (p *UserProcessorImpl) GetUserByID(ctx context.Context, id uuid.UUID) (*models.UserResponse, error) {
user, err := p.userRepo.GetByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
return mappers.UserEntityToResponse(user), nil
}
func (p *UserProcessorImpl) GetUserByEmail(ctx context.Context, email string) (*models.UserResponse, error) {
user, err := p.userRepo.GetByEmail(ctx, email)
if err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
return mappers.UserEntityToResponse(user), nil
}
func (p *UserProcessorImpl) ListUsers(ctx context.Context, organizationID uuid.UUID, page, limit int) ([]models.UserResponse, int, error) {
_, err := p.organizationRepo.GetByID(ctx, organizationID)
if err != nil {
return nil, 0, fmt.Errorf("organization not found: %w", err)
}
offset := (page - 1) * limit
filters := map[string]interface{}{
"organization_id": organizationID,
}
users, totalCount, err := p.userRepo.List(ctx, filters, limit, offset)
if err != nil {
return nil, 0, fmt.Errorf("failed to get users: %w", err)
}
responses := make([]models.UserResponse, len(users))
for i, user := range users {
response := mappers.UserEntityToResponse(user)
if response != nil {
responses[i] = *response
}
}
return responses, int(totalCount), nil
}
func (p *UserProcessorImpl) GetUserEntityByEmail(ctx context.Context, email string) (*entities.User, error) {
user, err := p.userRepo.GetByEmail(ctx, email)
if err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
return user, nil
}
func (p *UserProcessorImpl) ChangePassword(ctx context.Context, userID uuid.UUID, req *models.ChangePasswordRequest) error {
user, err := p.userRepo.GetByID(ctx, userID)
if err != nil {
return fmt.Errorf("user not found: %w", err)
}
err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.CurrentPassword))
if err != nil {
return fmt.Errorf("current password is incorrect")
}
newPasswordHash, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
return fmt.Errorf("failed to hash new password: %w", err)
}
err = p.userRepo.UpdatePassword(ctx, userID, string(newPasswordHash))
if err != nil {
return fmt.Errorf("failed to update password: %w", err)
}
return nil
}
func (p *UserProcessorImpl) ActivateUser(ctx context.Context, userID uuid.UUID) error {
_, err := p.userRepo.GetByID(ctx, userID)
if err != nil {
return fmt.Errorf("user not found: %w", err)
}
err = p.userRepo.UpdateActiveStatus(ctx, userID, true)
if err != nil {
return fmt.Errorf("failed to activate user: %w", err)
}
return nil
}
func (p *UserProcessorImpl) DeactivateUser(ctx context.Context, userID uuid.UUID) error {
_, err := p.userRepo.GetByID(ctx, userID)
if err != nil {
return fmt.Errorf("user not found: %w", err)
}
err = p.userRepo.UpdateActiveStatus(ctx, userID, false)
if err != nil {
return fmt.Errorf("failed to deactivate user: %w", err)
}
return nil
}
2025-07-30 23:18:20 +07:00
func (p *UserProcessorImpl) UpdateUserOutlet(ctx context.Context, userID uuid.UUID, req *models.UpdateUserOutletRequest) (*models.UserResponse, error) {
// Get user first to validate existence and get organization_id
existingUser, err := p.userRepo.GetByID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("user not found: %w", err)
}
// Validate outlet exists
outlet, err := p.outletRepo.GetByID(ctx, req.OutletID)
if err != nil {
return nil, fmt.Errorf("outlet not found: %w", err)
}
// Validate outlet belongs to user's organization
if outlet.OrganizationID != existingUser.OrganizationID {
return nil, fmt.Errorf("outlet does not belong to user's organization")
}
// Update user's outlet_id
existingUser.OutletID = &req.OutletID
err = p.userRepo.Update(ctx, existingUser)
if err != nil {
return nil, fmt.Errorf("failed to update user outlet: %w", err)
}
return mappers.UserEntityToResponse(existingUser), nil
}