import { prisma } from '../config/database'; import { Prisma } from '@prisma/client'; import { config } from '../config'; import { logger } from '../config/logger'; import jwt from 'jsonwebtoken'; import { ListUsersResponse, GetUserResponse, UpdateUser, UpdateRoleResponse, DeactivateAccountResponse, ActivateAccountResponse, } from '../types/usersmanagement.types'; import { UserResponse } from '../types/user.types'; import { UnauthorizedError, ValidationError, ForbiddenError } from '../middleware/errorHandler'; import { getPresignedUrl } from '../config/minio'; export class UserManagementService { async listUsers(): Promise { try { const users = await prisma.user.findMany({ where: { is_deactivated: false }, include: { profile: true, role: true, } }); return { code: 200, message: 'Users fetched successfully', total: users.length, data: await Promise.all(users.map(user => this.formatUserResponse(user))) }; } catch (error) { logger.error('Failed to fetch users', { error }); throw error; } } async getUserById(id: number): Promise { try { const user = await prisma.user.findUnique({ where: { id }, include: { role: true, profile: true } }); if (!user) throw new UnauthorizedError('User not found'); return { code: 200, message: 'User fetched successfully', data: await this.formatUserResponse(user) }; } catch (error) { logger.error('Failed to fetch user by ID', { error }); throw error; } } async updateUserRole(id: number, role_id: number): Promise { try { const user = await prisma.user.findUnique({ where: { id } }); if (!user) throw new UnauthorizedError('User not found'); const role = await prisma.role.findUnique({ where: { id: role_id } }); if (!role) throw new UnauthorizedError('Role not found'); await prisma.user.update({ where: { id }, data: { role_id } }); return { code: 200, message: 'User role updated successfully' }; } catch (error) { logger.error('Failed to update user role', { error }); throw error; } } async deleteUser(id: number): Promise { try { const user = await prisma.user.findUnique({ where: { id } }); if (!user) throw new UnauthorizedError('User not found'); await prisma.user.update({ where: { id }, data: { is_deactivated: true } }); return { code: 200, message: 'User deactivated successfully' }; } catch (error) { logger.error('Failed to deactivate user', { error }); throw error; } } async deactivateAccount(id: number): Promise { try { const user = await prisma.user.findUnique({ where: { id } }); if (!user) throw new UnauthorizedError('User not found'); if (user.is_deactivated) { logger.warn('Deactivate attempt with deactivated account', { userId: user.id }); throw new ForbiddenError('This account has already been deactivated'); } // Deactivate account await prisma.user.update({ where: { id: user.id }, data: { is_deactivated: true } }); logger.info('Account deactivated successfully', { userId: user.id }); return { code: 200, message: 'Account deactivated successfully' }; } catch (error) { if (error instanceof jwt.JsonWebTokenError) { logger.error('Invalid JWT token:', error); throw new UnauthorizedError('Invalid token'); } if (error instanceof jwt.TokenExpiredError) { logger.error('JWT token expired:', error); throw new UnauthorizedError('Token expired'); } logger.error('Failed to deactivate account', { error }); throw error; } } async activateAccount(id: number): Promise { try { const user = await prisma.user.findUnique({ where: { id } }); if (!user) throw new UnauthorizedError('User not found'); // Check if account is already activated if (!user.is_deactivated) { logger.warn('Activate attempt with activated account', { userId: user.id }); throw new ForbiddenError('This account has already been activated'); } // Activate account await prisma.user.update({ where: { id: user.id }, data: { is_deactivated: false } }); logger.info('Account activated successfully', { userId: user.id }); return { code: 200, message: 'Account activated successfully' }; } catch (error) { if (error instanceof jwt.JsonWebTokenError) { logger.error('Invalid JWT token:', error); throw new UnauthorizedError('Invalid token'); } if (error instanceof jwt.TokenExpiredError) { logger.error('JWT token expired:', error); throw new UnauthorizedError('Token expired'); } logger.error('Failed to activate account', { error }); throw error; } } /** * Format user response */ private async formatUserResponse(user: any): Promise { return { id: user.id, username: user.username, email: user.email, email_verified_at: user.email_verified_at, created_at: user.created_at, updated_at: user.updated_at, role: { code: user.role.code, name: user.role.name as { th: string; en: string } }, profile: user.profile ? { prefix: user.profile.prefix as { th?: string; en?: string } | undefined, first_name: user.profile.first_name, last_name: user.profile.last_name, avatar_url: user.profile.avatar_url ? await this.getAvatarPresignedUrl(user.profile.avatar_url) : null, birth_date: user.profile.birth_date, phone: user.profile.phone } : undefined }; } /** * Get presigned URL for avatar */ private async getAvatarPresignedUrl(avatarPath: string): Promise { try { return await getPresignedUrl(avatarPath, 3600); // 1 hour expiry } catch (error) { logger.warn(`Failed to generate presigned URL for avatar: ${error}`); throw error; } } }