mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
202 lines
5.5 KiB
Go
202 lines
5.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type UserService struct {
|
|
userRepo domain.UserRepository
|
|
}
|
|
|
|
func NewUserService(userRepo domain.UserRepository) *UserService {
|
|
return &UserService{
|
|
userRepo: userRepo,
|
|
}
|
|
}
|
|
|
|
type CreateUserRequest struct {
|
|
Email string
|
|
Name string
|
|
Password string
|
|
Role domain.UserRole
|
|
Permissions []string
|
|
}
|
|
|
|
type UpdateUserRequest struct {
|
|
Name *string
|
|
Email *string
|
|
Role *domain.UserRole
|
|
Permissions *[]string
|
|
IsActive *bool
|
|
}
|
|
|
|
// ListUsers retrieves users with filters and pagination
|
|
func (s *UserService) ListUsers(ctx context.Context, filters domain.UserListFilters, pagination domain.PaginationParams) (*domain.PaginatedResult[domain.User], error) {
|
|
return s.userRepo.List(ctx, filters, pagination)
|
|
}
|
|
|
|
// GetUser retrieves a user by ID
|
|
func (s *UserService) GetUser(ctx context.Context, userID string) (*domain.User, error) {
|
|
return s.userRepo.GetByID(ctx, userID)
|
|
}
|
|
|
|
// CreateUser creates a new user
|
|
func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) (*domain.User, error) {
|
|
// Check if email already exists
|
|
existing, err := s.userRepo.GetByEmail(ctx, req.Email)
|
|
if err == nil && existing != nil {
|
|
return nil, fmt.Errorf("user with email %s already exists", req.Email)
|
|
}
|
|
|
|
// Hash password
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to hash password: %w", err)
|
|
}
|
|
|
|
// Marshal permissions
|
|
permissionsJSON, err := json.Marshal(req.Permissions)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal permissions: %w", err)
|
|
}
|
|
|
|
user := &domain.User{
|
|
ID: uuid.New().String(),
|
|
Email: req.Email,
|
|
Name: req.Name,
|
|
Password: string(hashedPassword),
|
|
Role: req.Role,
|
|
Permissions: string(permissionsJSON),
|
|
IsActive: true,
|
|
}
|
|
|
|
if err := s.userRepo.Create(ctx, user); err != nil {
|
|
return nil, fmt.Errorf("failed to create user: %w", err)
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// UpdateUser updates a user
|
|
func (s *UserService) UpdateUser(ctx context.Context, userID string, req UpdateUserRequest) (*domain.User, error) {
|
|
user, err := s.userRepo.GetByID(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if req.Name != nil {
|
|
user.Name = *req.Name
|
|
}
|
|
if req.Email != nil {
|
|
// Check if email is already taken by another user
|
|
existing, err := s.userRepo.GetByEmail(ctx, *req.Email)
|
|
if err == nil && existing != nil && existing.ID != userID {
|
|
return nil, fmt.Errorf("email %s is already taken", *req.Email)
|
|
}
|
|
user.Email = *req.Email
|
|
}
|
|
if req.IsActive != nil {
|
|
user.IsActive = *req.IsActive
|
|
}
|
|
|
|
// Update role if provided
|
|
if req.Role != nil {
|
|
if err := s.userRepo.UpdateRole(ctx, userID, *req.Role); err != nil {
|
|
return nil, err
|
|
}
|
|
user.Role = *req.Role
|
|
}
|
|
|
|
// Update permissions if provided
|
|
if req.Permissions != nil {
|
|
if err := s.userRepo.UpdatePermissions(ctx, userID, *req.Permissions); err != nil {
|
|
return nil, err
|
|
}
|
|
permissionsJSON, err := json.Marshal(*req.Permissions)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal permissions: %w", err)
|
|
}
|
|
user.Permissions = string(permissionsJSON)
|
|
}
|
|
|
|
// Save updates (if any non-repository fields were updated)
|
|
if req.Name != nil || req.Email != nil || req.IsActive != nil {
|
|
if err := s.userRepo.Update(ctx, user); err != nil {
|
|
return nil, fmt.Errorf("failed to update user: %w", err)
|
|
}
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// UpdateRole updates a user's role
|
|
func (s *UserService) UpdateRole(ctx context.Context, userID string, role domain.UserRole) error {
|
|
return s.userRepo.UpdateRole(ctx, userID, role)
|
|
}
|
|
|
|
// UpdatePermissions updates a user's permissions
|
|
func (s *UserService) UpdatePermissions(ctx context.Context, userID string, permissions []string) error {
|
|
return s.userRepo.UpdatePermissions(ctx, userID, permissions)
|
|
}
|
|
|
|
// DeactivateUser deactivates a user
|
|
func (s *UserService) DeactivateUser(ctx context.Context, userID string) error {
|
|
return s.userRepo.Deactivate(ctx, userID)
|
|
}
|
|
|
|
// ActivateUser activates a user
|
|
func (s *UserService) ActivateUser(ctx context.Context, userID string) error {
|
|
return s.userRepo.Activate(ctx, userID)
|
|
}
|
|
|
|
// GetUserActivity retrieves activity log for a user
|
|
func (s *UserService) GetUserActivity(ctx context.Context, userID string, limit, offset int) ([]interface{}, int64, error) {
|
|
// TODO: Implement when activity logging is ready
|
|
return []interface{}{}, 0, nil
|
|
}
|
|
|
|
// GetUserStats retrieves user statistics
|
|
func (s *UserService) GetUserStats(ctx context.Context) (map[string]interface{}, error) {
|
|
// Get all users
|
|
allUsers, err := s.userRepo.List(ctx, domain.UserListFilters{}, domain.PaginationParams{Limit: 10000, Offset: 0})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
stats := map[string]interface{}{
|
|
"total": allUsers.Total,
|
|
"active": 0,
|
|
"inactive": 0,
|
|
"by_role": make(map[string]int64),
|
|
"new_this_month": 0,
|
|
}
|
|
|
|
now := time.Now()
|
|
monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
|
|
|
for _, user := range allUsers.Items {
|
|
if user.IsActive {
|
|
stats["active"] = stats["active"].(int) + 1
|
|
} else {
|
|
stats["inactive"] = stats["inactive"].(int) + 1
|
|
}
|
|
|
|
roleCount := stats["by_role"].(map[string]int64)
|
|
roleCount[string(user.Role)] = roleCount[string(user.Role)] + 1
|
|
|
|
if user.CreatedAt.After(monthStart) {
|
|
stats["new_this_month"] = stats["new_this_month"].(int) + 1
|
|
}
|
|
}
|
|
|
|
return stats, nil
|
|
}
|