Files
expense-control/api/src/services/auth.service.ts
T
2026-04-07 10:06:48 +02:00

63 lines
2.0 KiB
TypeScript

import bcrypt from 'bcryptjs';
import jwt, { type SignOptions } from 'jsonwebtoken';
import { AppDataSource } from '../config/data-source.js';
import { env } from '../config/env.js';
import { User, type UserRole } from '../entities/User.js';
const repo = () => AppDataSource.getRepository(User);
export const sanitizeUser = (user: User) => ({
id: user.id,
fullName: user.fullName,
email: user.email,
role: user.role,
isActive: user.isActive,
defaultCurrency: user.defaultCurrency,
integrationsEnabled: Boolean(user.integrationsEnabled),
reportPreferences: user.reportPreferences ?? {
enabled: false,
frequency: 'monthly',
thresholdAmount: 0,
sendToEmail: user.email,
categoryIds: []
},
createdAt: user.createdAt
});
export const hashPassword = async (password: string) => bcrypt.hash(password, 10);
export const comparePassword = async (password: string, hash: string) => bcrypt.compare(password, hash);
export const signToken = (payload: { id: string; email: string; role: UserRole }) =>
jwt.sign(payload, env.JWT_SECRET, { expiresIn: env.JWT_EXPIRES_IN as SignOptions['expiresIn'] });
export const findUserByEmail = (email: string) => repo().findOne({ where: { email: email.toLowerCase() } });
export const createUser = async (input: {
fullName: string;
email: string;
password: string;
role?: UserRole;
defaultCurrency?: string;
}) => {
const existing = await repo().findOne({ where: { email: input.email.toLowerCase() } });
if (existing) throw new Error('Email address is already in use');
const user = repo().create({
fullName: input.fullName,
email: input.email.toLowerCase(),
passwordHash: await hashPassword(input.password),
role: input.role ?? 'USER',
defaultCurrency: input.defaultCurrency ?? env.DEFAULT_CURRENCY,
integrationsEnabled: false,
reportPreferences: {
enabled: false,
frequency: 'monthly',
thresholdAmount: 0,
sendToEmail: input.email.toLowerCase(),
categoryIds: []
}
});
return repo().save(user);
};