import { HttpException, Inject, Injectable, Logger, UnauthorizedException, } from '@nestjs/common'; import { UsersService } from '../users/users.service'; import { JwtService } from '@nestjs/jwt'; import { registerDto } from './dto/registerDto.dto'; import { User } from 'src/users/entities/user.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { hash } from 'bcrypt'; import { compare } from 'bcryptjs'; import { ConfigService } from '@nestjs/config'; @Injectable() export class AuthService { constructor( private usersService: UsersService, private jwtService: JwtService, private configService: ConfigService, @InjectRepository(User) private userRepository: Repository, ) {} //register users async register(data: registerDto) { const { usuario, contraseña } = data; if (await this.usersService.findOne(usuario)) { throw new HttpException('User already exist', 403); } const hashedpassword = await hash(contraseña, 10); data = { ...data, contraseña: hashedpassword }; return this.userRepository.save(this.userRepository.create(data)); } //singin async signIn(data: registerDto, rememberMe: boolean) { const { usuario, contraseña } = data; const user = await this.usersService.findOne(usuario); if (!user) { throw new UnauthorizedException('Invalid name'); } const checkPassword = await compare(contraseña, user.contraseña); if (!checkPassword) { throw new UnauthorizedException('Invalid password'); } const payload = { id_usuario: user.id_usuario, usuario: user.usuario, id_tipo_usuario: user.id_tipo_usuario, }; const token = this.jwtService.sign(payload, { expiresIn: rememberMe ? '31d' : '7h', }); const expirationTime = rememberMe ? 31 * 24 * 3600 * 1000 : 7 * 3600 * 1000; await this.usersService.updateTokenAndDates( user.id_usuario, token, new Date(), new Date(Date.now() + expirationTime), ); return { token }; } //update user async update( id_usuario: number, data: registerDto, token: string, ): Promise { const { contraseña, id_tipo_usuario } = data; const tokenUserId = this.getTokenUserId(token); if (tokenUserId == id_usuario && id_tipo_usuario !== undefined) { Logger.debug('Cannot modify id_tipo_usuario') delete data.id_tipo_usuario; } const user = await this.userRepository.findOne({ where: { id_usuario } }); if (!user) { throw new HttpException('User not found', 404); } if (contraseña) { const hashedpassword = await hash(contraseña, 10); data = { ...data, contraseña: hashedpassword }; } else { data = { ...data, contraseña: user.contraseña }; } return await this.userRepository.update(id_usuario, data); } async remove(id_usuario: number): Promise { await this.userRepository.delete(id_usuario); } //validate tojen of users async validateToken(token: string): Promise { try { const decoded = this.jwtService.verify(token, { secret: this.configService.get('JWT_SECRET'), }); //verify JWT's username with DB's username const user = await this.usersService.findOne(decoded.username); if (!user) { throw new UnauthorizedException('Invalid token'); } //verify JWT hasn't expired const currentTime = Math.floor(Date.now() / 1000); if (decoded.exp < currentTime) { throw new UnauthorizedException('Token has expired'); } return; } catch (error) { throw new UnauthorizedException('validation token failed'); } } async findAll(): Promise { return this.userRepository.find(); } async findAllPaginated( page: number, limit: number, filters: any, ): Promise<{ usuarios: User[]; total: number; totalPages: number }> { const query = this.userRepository.createQueryBuilder('usuario'); if (filters.nombre) { Logger.debug('fiter by name user'); query.andWhere('usuario.nombre LIKE :nombre', { nombre: `%${filters.nombre}%`, }); } if (filters.id_tipo_usuario) { Logger.debug('fiter by id user'); query.andWhere('usuario.id_tipo_usuario = :id_tipo_usuario', { id_tipo_usuario: filters.id_tipo_usuario, }); } const [usuarios, total] = await query .skip((page - 1) * limit) .take(limit) .orderBy('usuario.nombre', 'ASC') .getManyAndCount(); const totalPages = Math.ceil(total / limit); return { usuarios, total, totalPages }; } async profile(id_usuario: number) { const user = await this.userRepository.findOne({ where: { id_usuario }, }); if (!user) { Logger.debug('user not found'); throw new HttpException('user not found', 404); } return user; } getTokenUserId(token: string): number { try { const decoded = this.jwtService.verify(token); return decoded['id_usuario']; } catch (error) { throw new UnauthorizedException('Invalid token'); } } }