UNPKG

@diagramers/api

Version:

Diagramers API - A comprehensive Node.js API template with TypeScript, Firebase Functions, and Socket.io

191 lines (168 loc) 5.48 kB
import { Result } from '../../../shared/types/result'; import { UserModel, IUserDocument } from '../schemas/user.schema'; import { IUser, IUserCreate, IUserUpdate } from '../entities/user.entity'; import * as bcrypt from 'bcryptjs'; export class UserService { /** * Get all active users */ async getAll(): Promise<Result<IUser[]>> { try { const users = await UserModel.find({ status: 1 }).select('-password').lean(); const convertedUsers = users.map(user => ({ ...user, _id: user._id?.toString() || '' })) as IUser[]; return Result.success(convertedUsers); } catch (error: any) { return Result.error('Failed to fetch users', error.message); } } /** * Get user by ID */ async getById(id: string): Promise<Result<IUser | null>> { try { const user = await UserModel.findOne({ _id: id, status: 1 }).select('-password'); if (!user) { return Result.error('User not found', 'User with the specified ID does not exist'); } const userObj = user.toObject(); const convertedUser = { ...userObj, _id: userObj._id?.toString() || '' } as IUser; return Result.success(convertedUser); } catch (error: any) { return Result.error('Failed to fetch user', error.message); } } /** * Get user by email */ async getByEmail(email: string): Promise<Result<IUser | null>> { try { const user = await UserModel.findOne({ email: email.toLowerCase(), status: 1 }); if (!user) { return Result.error('User not found', 'User with the specified email does not exist'); } const userObj = user.toObject(); const convertedUser = { ...userObj, _id: userObj._id?.toString() || '' } as IUser; return Result.success(convertedUser); } catch (error: any) { return Result.error('Failed to fetch user', error.message); } } /** * Create new user */ async create(userData: IUserCreate): Promise<Result<IUser>> { try { // Check if user already exists const existingUser = await UserModel.findOne({ $or: [ { email: userData.email.toLowerCase() }, { username: userData.username } ], status: 1 }); if (existingUser) { return Result.error('User already exists', 'A user with this email or username already exists'); } // Hash password const saltRounds = 10; const hashedPassword = await bcrypt.hash(userData.password, saltRounds); // Create user const user = new UserModel({ ...userData, email: userData.email.toLowerCase(), password: hashedPassword, role: userData.role || 'user', permissions: [] }); const savedUser = await user.save(); const userObj = savedUser.toObject(); delete userObj.password; const convertedUser = { ...userObj, _id: userObj._id?.toString() || '' } as IUser; return Result.success(convertedUser); } catch (error: any) { return Result.error('Failed to create user', error.message); } } /** * Update user */ async update(id: string, userData: IUserUpdate): Promise<Result<IUser | null>> { try { const user = await UserModel.findOne({ _id: id, status: 1 }); if (!user) { return Result.error('User not found', 'User with the specified ID does not exist'); } // Update user Object.assign(user, userData); const updatedUser = await user.save(); const userObj = updatedUser.toObject(); delete userObj.password; const convertedUser = { ...userObj, _id: userObj._id?.toString() || '' } as IUser; return Result.success(convertedUser); } catch (error: any) { return Result.error('Failed to update user', error.message); } } /** * Delete user (soft delete) */ async delete(id: string): Promise<Result<boolean>> { try { const user = await UserModel.findOne({ _id: id, status: 1 }); if (!user) { return Result.error('User not found', 'User with the specified ID does not exist'); } user.status = 0; await user.save(); return Result.success(true); } catch (error: any) { return Result.error('Failed to delete user', error.message); } } /** * Verify user password */ async verifyPassword(userId: string, password: string): Promise<Result<boolean>> { try { const user = await UserModel.findOne({ _id: userId, status: 1 }); if (!user) { return Result.error('User not found', 'User with the specified ID does not exist'); } const isValid = await bcrypt.compare(password, user.password); return Result.success(isValid); } catch (error: any) { return Result.error('Failed to verify password', error.message); } } /** * Update last login */ async updateLastLogin(id: string): Promise<Result<boolean>> { try { const user = await UserModel.findOne({ _id: id, status: 1 }); if (!user) { return Result.error('User not found', 'User with the specified ID does not exist'); } user.lastLoginAt = new Date(); await user.save(); return Result.success(true); } catch (error: any) { return Result.error('Failed to update last login', error.message); } } }