@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
text/typescript
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);
}
}
}