add bot wsp
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { Controller, Get, NotFoundException, Query, Res } from '@nestjs/common';
|
||||
import { Response } from 'express';
|
||||
import { AuthService } from './auth.service';
|
||||
import { Inject, forwardRef } from '@nestjs/common';
|
||||
import { WhatsappService } from '../whatsapp/whatsapp.service';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(
|
||||
private readonly authService: AuthService,
|
||||
@Inject(forwardRef(() => WhatsappService))
|
||||
private readonly whatsappService: WhatsappService,
|
||||
) { }
|
||||
|
||||
@Get('verify')
|
||||
verificar(@Query('t') token: string) {
|
||||
return this.authService.verificarToken(token);
|
||||
}
|
||||
|
||||
@Get('getToken')
|
||||
async getToken() {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return await this.authService.getTokenDev();
|
||||
}
|
||||
|
||||
@Get('init')
|
||||
async redirectDynamic(@Res() res: Response) {
|
||||
const whatsappStatus = await this.whatsappService.status().catch(() => null);
|
||||
return await this.authService.init(res, whatsappStatus?.status ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
//650030
|
||||
@@ -0,0 +1,33 @@
|
||||
import { forwardRef, Module } from '@nestjs/common';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { SystemConfigModule } from '../common/system-config.module';
|
||||
import { SystemConfigService } from '../common/system-config.service';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
import { WhatsappModule } from '../whatsapp/whatsapp.module';
|
||||
|
||||
@Module({
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService],
|
||||
imports: [
|
||||
JwtModule.registerAsync({
|
||||
imports: [SystemConfigModule],
|
||||
useFactory: async (systemConfig: SystemConfigService) => {
|
||||
// Esperar a que se cargue la configuración
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
const expirationMinutes = systemConfig.getTokenExpirationMinutes();
|
||||
return {
|
||||
secret: process.env.SECRET_JWT,
|
||||
signOptions: { expiresIn: `${expirationMinutes}m` },
|
||||
};
|
||||
},
|
||||
inject: [SystemConfigService],
|
||||
}),
|
||||
PrismaModule,
|
||||
SystemConfigModule,
|
||||
forwardRef(() => WhatsappModule),
|
||||
],
|
||||
exports: [AuthService],
|
||||
})
|
||||
export class AuthModule { }
|
||||
@@ -0,0 +1,142 @@
|
||||
import { forwardRef, Inject, Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
|
||||
import { User } from '@prisma/client';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { SystemConfigService } from '../common/system-config.service';
|
||||
import { Response } from 'express';
|
||||
|
||||
export enum TokenRedirectURL {
|
||||
FRONT = 'FRONT',
|
||||
SESSION = 'SESSION',
|
||||
USER = 'USER',
|
||||
WHATSAPP = 'WHATSAPP',
|
||||
CONFIG = 'CONFIG',
|
||||
}
|
||||
|
||||
const RedirectToUrlParams = {
|
||||
[TokenRedirectURL.FRONT]: '/',
|
||||
[TokenRedirectURL.SESSION]: 'clases',
|
||||
[TokenRedirectURL.USER]: 'usuarios',
|
||||
[TokenRedirectURL.WHATSAPP]: 'whatsapp',
|
||||
[TokenRedirectURL.CONFIG]: 'configuracion/sistema',
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
private readonly nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 10);
|
||||
|
||||
private readonly logger = new Logger(AuthService.name);
|
||||
|
||||
constructor(
|
||||
private prisma: PrismaService,
|
||||
@Inject(forwardRef(() => SystemConfigService))
|
||||
private systemConfig: SystemConfigService
|
||||
) { }
|
||||
|
||||
async getTokenDev() {
|
||||
try {
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: {
|
||||
role: 'ADMIN',
|
||||
phone: { not: null }
|
||||
}
|
||||
});
|
||||
return await this.generarToken(user?.id, TokenRedirectURL.SESSION);
|
||||
}
|
||||
catch (error: any) {
|
||||
|
||||
}
|
||||
}
|
||||
getLoginLink(user: User): Promise<string> {
|
||||
return this.generarToken(user.id).then(token => `${process.env.URL_FRONT}?t=${token}`);
|
||||
}
|
||||
|
||||
//NOTE duration opcional para el primer arranque , MINUTOS
|
||||
async generarToken(userId?: string, redirectUrl?: TokenRedirectURL, duration?: number): Promise<string> {
|
||||
try {
|
||||
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
// Buscar token activo existente
|
||||
const existing = userId ? await this.prisma.token.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
expiresAt: { gt: new Date(now) },
|
||||
isActive: { equals: true }
|
||||
},
|
||||
})
|
||||
: false
|
||||
|
||||
if (existing) {
|
||||
return existing.token;
|
||||
}
|
||||
|
||||
// Si no hay uno válido, crear uno nuevo
|
||||
const token = this.nanoid();
|
||||
const expirationMinutes = this.systemConfig.getTokenExpirationMinutes();
|
||||
const expiresAt = new Date(now + (duration ?? expirationMinutes) * 60 * 1000);
|
||||
|
||||
await this.prisma.token.create({
|
||||
data: {
|
||||
token,
|
||||
userId,
|
||||
expiresAt,
|
||||
...(redirectUrl
|
||||
? { redirectUrl: RedirectToUrlParams[redirectUrl] }
|
||||
: { redirectUrl: RedirectToUrlParams[TokenRedirectURL.FRONT] })
|
||||
},
|
||||
});
|
||||
|
||||
return token;
|
||||
}
|
||||
catch (error: any) {
|
||||
this.logger.error('Error generating token', error);
|
||||
throw new InternalServerErrorException('Error generating token');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async verificarToken(token: string): Promise<{ autorizado: boolean; user?: User, redirectUrl?: string }> {
|
||||
try {
|
||||
const found = await this.prisma.token.findUnique({
|
||||
where: { token, isActive: { equals: true } },
|
||||
include: { user: true },
|
||||
});
|
||||
|
||||
if (!found) return { autorizado: false };
|
||||
|
||||
const expired = new Date() > found.expiresAt;
|
||||
if (expired) return { autorizado: false };
|
||||
|
||||
await this.prisma.token.update({ where: { id: found.id }, data: { isActive: false } });
|
||||
return { autorizado: true, user: found?.user || undefined, redirectUrl: found.redirectUrl! };
|
||||
} catch {
|
||||
return { autorizado: false };
|
||||
}
|
||||
}
|
||||
|
||||
async init(res: Response, whatsappStatus?: 'Correcto' | 'Sin session' | null) {
|
||||
try {
|
||||
// Caso 1: primera vez que arranca el sistema (admin creado, token listo)
|
||||
const firstUrl = this.systemConfig.getFirstUrl();
|
||||
if (firstUrl) {
|
||||
return res.redirect(302, firstUrl);
|
||||
}
|
||||
|
||||
// Caso 2: WhatsApp sin sesión → redirigir al front en la sección de WhatsApp
|
||||
if (whatsappStatus === 'Sin session') {
|
||||
const admin = await this.prisma.user.findFirst({ where: { role: 'ADMIN' } });
|
||||
const token = await this.generarToken(admin?.id, TokenRedirectURL.WHATSAPP);
|
||||
return res.redirect(302, `${process.env.URL_FRONT}?t=${token}`);
|
||||
}
|
||||
|
||||
|
||||
// Caso 3: sistema normal no dar acceso
|
||||
return res.sendStatus(403);
|
||||
} catch (error: any) {
|
||||
this.logger.error('Error in init', error);
|
||||
return res.sendStatus(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user