base con autenticacion, registro, modulo encuestas
This commit is contained in:
61
apps/api/src/features/auth/auth.controller.ts
Normal file
61
apps/api/src/features/auth/auth.controller.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Public } from '@/common/decorators';
|
||||
import { JwtRefreshGuard } from '@/common/guards/jwt-refresh.guard';
|
||||
import { RefreshTokenDto } from '@/features/auth/dto/refresh-token.dto';
|
||||
import { SignInUserDto } from '@/features/auth/dto/signIn-user.dto';
|
||||
import { SingUpUserDto } from '@/features/auth/dto/signUp-user.dto';
|
||||
import { SignOutUserDto } from '@/features/auth/dto/signOut-user.dto';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
HttpCode,
|
||||
Patch,
|
||||
Post,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Public()
|
||||
@HttpCode(200)
|
||||
@Post('sing-up')
|
||||
// @ApiOperation({ summary: 'Create a new user' })
|
||||
// @ApiResponse({ status: 201, description: 'User created successfully.' })
|
||||
async singUp(@Body() payload: SingUpUserDto) {
|
||||
const data = await this.authService.singUp(payload)
|
||||
return { message: 'User created successfully', data};
|
||||
// return { message: 'User created successfully', data };
|
||||
}
|
||||
|
||||
@Public()
|
||||
@HttpCode(200)
|
||||
@Post('sign-in')
|
||||
async signIn(@Body() signInUserDto: SignInUserDto) {
|
||||
return await this.authService.signIn(signInUserDto);
|
||||
}
|
||||
|
||||
@Post('sign-out')
|
||||
//@RequirePermissions('auth:sign-out')
|
||||
async signOut(@Body() signOutUserDto: SignOutUserDto) {
|
||||
await this.authService.signOut(signOutUserDto);
|
||||
return { message: 'User signed out successfully' };
|
||||
}
|
||||
|
||||
// @Post('forgot-password')
|
||||
// async forgotPassword(@Body() forgotPasswordDto: ForgotPasswordDto) {
|
||||
// await this.authService.forgotPassword(forgotPasswordDto);
|
||||
// return { message: 'Password reset link sent to your email' };
|
||||
// }
|
||||
|
||||
@UseGuards(JwtRefreshGuard)
|
||||
@Patch('refresh-token')
|
||||
//@RequirePermissions('auth:refresh-token')
|
||||
async refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
|
||||
return await this.authService.refreshToken(refreshTokenDto);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
12
apps/api/src/features/auth/auth.module.ts
Normal file
12
apps/api/src/features/auth/auth.module.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { MailModule } from '@/features/mail/mail.module';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './auth.service';
|
||||
import { DrizzleModule } from '@/database/drizzle.module';
|
||||
|
||||
@Module({
|
||||
imports: [DrizzleModule, MailModule],
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService],
|
||||
})
|
||||
export class AuthModule {}
|
||||
368
apps/api/src/features/auth/auth.service.ts
Normal file
368
apps/api/src/features/auth/auth.service.ts
Normal file
@@ -0,0 +1,368 @@
|
||||
import { envs } from '@/common/config/envs';
|
||||
import { Env, validateString } from '@/common/utils';
|
||||
import { DRIZZLE_PROVIDER } from '@/database/drizzle-provider';
|
||||
import { RefreshTokenDto } from '@/features/auth/dto/refresh-token.dto';
|
||||
import { SignInUserDto } from '@/features/auth/dto/signIn-user.dto';
|
||||
import { SingUpUserDto } from '@/features/auth/dto/signUp-user.dto';
|
||||
import { SignOutUserDto } from '@/features/auth/dto/signOut-user.dto';
|
||||
import { ValidateUserDto } from '@/features/auth/dto/validate-user.dto';
|
||||
import AuthTokensInterface from '@/features/auth/interfaces/auth-tokens.interface';
|
||||
import {
|
||||
LoginUserInterface,
|
||||
Roles,
|
||||
} from '@/features/auth/interfaces/login-user.interface';
|
||||
import RefreshTokenInterface from '@/features/auth/interfaces/refresh-token.interface';
|
||||
import { MailService } from '@/features/mail/mail.service';
|
||||
import { User } from '@/features/users/entities/user.entity';
|
||||
import {
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Inject,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import crypto from 'crypto';
|
||||
import { and, eq, or } from 'drizzle-orm';
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from 'src/database/index';
|
||||
import { sessions, users, roles, usersRole } from 'src/database/index';
|
||||
import { Session } from './interfaces/session.interface';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly config: ConfigService<Env>,
|
||||
@Inject(DRIZZLE_PROVIDER) private drizzle: NodePgDatabase<typeof schema>,
|
||||
private readonly mailService: MailService,
|
||||
) {}
|
||||
|
||||
//Decode Tokens
|
||||
// Método para decodificar el token y obtener los datos completos
|
||||
private decodeToken(token: string): {
|
||||
sub: number;
|
||||
username?: string;
|
||||
iat: number;
|
||||
exp: number;
|
||||
} {
|
||||
try {
|
||||
const decoded = this.jwtService.decode(token) as {
|
||||
sub: number;
|
||||
username?: string;
|
||||
iat: number;
|
||||
exp: number;
|
||||
};
|
||||
|
||||
// Validar que contiene los datos esenciales
|
||||
if (!decoded || !decoded.exp || !decoded.iat) {
|
||||
throw new Error('Token lacks required fields');
|
||||
}
|
||||
|
||||
return decoded;
|
||||
} catch (error) {
|
||||
// Manejo seguro del tipo unknown
|
||||
let errorMessage = 'Failed to decode token';
|
||||
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message;
|
||||
console.error('Error decoding token:', errorMessage);
|
||||
} else {
|
||||
console.error('Unknown error type:', error);
|
||||
}
|
||||
|
||||
throw new HttpException(errorMessage, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
//Generate Tokens
|
||||
async generateTokens(user: User): Promise<AuthTokensInterface> {
|
||||
const [access_token, refresh_token] = await Promise.all([
|
||||
this.jwtService.signAsync(
|
||||
{
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
},
|
||||
{
|
||||
secret: envs.access_token_secret,
|
||||
expiresIn: envs.access_token_expiration,
|
||||
},
|
||||
),
|
||||
this.jwtService.signAsync(
|
||||
{
|
||||
sub: user.id,
|
||||
username: user.username,
|
||||
},
|
||||
{
|
||||
secret: envs.refresh_token_secret,
|
||||
expiresIn: envs.refresh_token_expiration,
|
||||
},
|
||||
),
|
||||
]);
|
||||
|
||||
return {
|
||||
access_token,
|
||||
refresh_token,
|
||||
};
|
||||
}
|
||||
|
||||
//Generate OTP Code For Email Confirmation
|
||||
async generateOTP(length = 6): Promise<string> {
|
||||
return crypto
|
||||
.randomInt(0, 10 ** length)
|
||||
.toString()
|
||||
.padStart(length, '0');
|
||||
}
|
||||
|
||||
// metodo para crear una session
|
||||
private async createSession(sessionInput: Session): Promise<string> {
|
||||
const { userId } = sessionInput;
|
||||
const activeSessionsCount = await this.drizzle
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.userId, parseInt(userId)));
|
||||
|
||||
if (activeSessionsCount.length !== 0) {
|
||||
// Elimina sessiones viejsas
|
||||
await this.drizzle
|
||||
.delete(sessions)
|
||||
.where(eq(sessions.userId, parseInt(userId)));
|
||||
}
|
||||
|
||||
const session = await this.drizzle.insert(sessions).values({
|
||||
sessionToken: sessionInput.sessionToken,
|
||||
userId: parseInt(userId),
|
||||
expiresAt: sessionInput.expiresAt,
|
||||
});
|
||||
if (session.rowCount === 0) throw new HttpException('Failed to create session', HttpStatus.NOT_FOUND);
|
||||
|
||||
return 'Session created successfully';
|
||||
}
|
||||
|
||||
//Find User
|
||||
async findUser(username: string): Promise<User | null> {
|
||||
const user = await this.drizzle
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.username, username));
|
||||
return user[0];
|
||||
}
|
||||
|
||||
//Find User
|
||||
async findUserById(id: number): Promise<User | null> {
|
||||
const user = await this.drizzle
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, id));
|
||||
return user[0];
|
||||
}
|
||||
|
||||
//Check User Is Already Exists
|
||||
async validateUser(dto: ValidateUserDto): Promise<User> {
|
||||
const user = await this.findUser(dto.username);
|
||||
if (!user) throw new NotFoundException('User not found');
|
||||
const isValid = await validateString(
|
||||
dto.password,
|
||||
user?.password as string,
|
||||
);
|
||||
if (!isValid) throw new UnauthorizedException('Invalid credentials');
|
||||
return user;
|
||||
}
|
||||
|
||||
//Find rol user
|
||||
async findUserRol(id: number): Promise<Roles[]> {
|
||||
const roles = await this.drizzle
|
||||
.select({
|
||||
id: schema.roles.id,
|
||||
role: schema.roles.name,
|
||||
})
|
||||
.from(schema.usersRole)
|
||||
.leftJoin(schema.roles, eq(schema.roles.id, schema.usersRole.roleId))
|
||||
.where(eq(schema.usersRole.userId, id));
|
||||
|
||||
if (roles.length === 0) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
|
||||
// Aseguramos que no haya valores nulos
|
||||
return roles.map((role) => ({
|
||||
id: role.id ?? 0, // Asignamos un valor por defecto (0) si es null
|
||||
rol: role.role ?? '', // Asignamos un valor por defecto (cadena vacía) si es null
|
||||
}));
|
||||
}
|
||||
|
||||
//Sign In User Account
|
||||
async signIn(dto: SignInUserDto): Promise<LoginUserInterface> {
|
||||
|
||||
const user = await this.validateUser(dto);
|
||||
const tokens = await this.generateTokens(user);
|
||||
const decodeAccess = this.decodeToken(tokens.access_token);
|
||||
const decodeRefresh = this.decodeToken(tokens.refresh_token);
|
||||
const rol = await this.findUserRol(user?.id as number);
|
||||
|
||||
await this.createSession({
|
||||
userId: String(user?.id), // Convert number to string
|
||||
sessionToken: tokens.refresh_token,
|
||||
expiresAt: decodeRefresh.exp,
|
||||
});
|
||||
|
||||
return {
|
||||
message: 'User signed in successfully',
|
||||
user: {
|
||||
id: user?.id as number,
|
||||
username: user?.username,
|
||||
fullname: user?.fullname,
|
||||
email: user?.email,
|
||||
rol: rol,
|
||||
},
|
||||
tokens: {
|
||||
access_token: tokens.access_token,
|
||||
access_expire_in: decodeAccess.exp,
|
||||
refresh_token: tokens.refresh_token,
|
||||
refresh_expire_in: decodeRefresh.exp,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// //Forgot Password
|
||||
// async forgotPassword(dto: ForgotPasswordDto): Promise<void> {
|
||||
// const user = await this.findUser(dto.username);
|
||||
// if (!user) throw new NotFoundException('User not found');
|
||||
// const passwordResetToken = await this.generateOTP();
|
||||
// user.passwordResetToken = passwordResetToken;
|
||||
// user.passwordResetTokenExpires = new Date(
|
||||
// Date.now() + 1000 * 60 * 60 * 24, // 1 day
|
||||
// );
|
||||
// await this.UserRepository.save(user);
|
||||
// await this.mailService.sendEmail({
|
||||
// to: [user.email],
|
||||
// subject: 'Reset Password',
|
||||
// html: ForgotPasswordMail({
|
||||
// name: user.name,
|
||||
// code: passwordResetToken,
|
||||
// }),
|
||||
// });
|
||||
// }
|
||||
|
||||
//Sign Out User Account
|
||||
async signOut(dto: SignOutUserDto): Promise<void> {
|
||||
const { user_id } = dto;
|
||||
const user = await this.drizzle
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, parseInt(user_id)));
|
||||
if (!user) throw new NotFoundException('User not found');
|
||||
await this.drizzle
|
||||
.delete(sessions)
|
||||
.where(eq(sessions.userId, parseInt(user_id)));
|
||||
}
|
||||
|
||||
//Refresh User Access Token
|
||||
async refreshToken(dto: RefreshTokenDto): Promise<RefreshTokenInterface> {
|
||||
const { user_id } = dto;
|
||||
|
||||
const session = await this.drizzle
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(
|
||||
and(
|
||||
eq(sessions.userId, user_id) &&
|
||||
eq(sessions.sessionToken, dto.refresh_token),
|
||||
),
|
||||
);
|
||||
|
||||
if (session.length === 0) throw new NotFoundException('session not found');
|
||||
const user = await this.findUserById(dto.user_id);
|
||||
if (!user) throw new NotFoundException('User not found');
|
||||
const tokens = await this.generateTokens(user);
|
||||
const decodeAccess = this.decodeToken(tokens.access_token);
|
||||
const decodeRefresh = this.decodeToken(tokens.refresh_token);
|
||||
await this.drizzle
|
||||
.update(sessions)
|
||||
.set({ sessionToken: tokens.refresh_token, expiresAt: decodeRefresh.exp })
|
||||
.where(eq(sessions.userId, dto.user_id));
|
||||
|
||||
return {
|
||||
access_token: tokens.access_token,
|
||||
access_expire_in: decodeAccess.exp,
|
||||
refresh_token: tokens.refresh_token,
|
||||
refresh_expire_in: decodeRefresh.exp,
|
||||
};
|
||||
}
|
||||
|
||||
async singUp(createUserDto: SingUpUserDto): Promise<User> {
|
||||
// Check if username or email exists
|
||||
const data = await this.drizzle
|
||||
.select({
|
||||
id: users.id,
|
||||
username: users.username,
|
||||
email: users.email
|
||||
})
|
||||
.from(users)
|
||||
.where(or(eq(users.username, createUserDto.username), eq(users.email, createUserDto.email)));
|
||||
|
||||
if (data.length > 0) {
|
||||
if (data[0].username === createUserDto.username) {
|
||||
throw new HttpException('Username already exists', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
if (data[0].email === createUserDto.email) {
|
||||
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
|
||||
|
||||
// Start a transaction
|
||||
return await this.drizzle.transaction(async (tx) => {
|
||||
// Create the user
|
||||
const [newUser] = await tx
|
||||
.insert(users)
|
||||
.values({
|
||||
username: createUserDto.username,
|
||||
email: createUserDto.email,
|
||||
password: hashedPassword,
|
||||
fullname: createUserDto.fullname,
|
||||
isActive: true,
|
||||
state: createUserDto.state,
|
||||
municipality: createUserDto.municipality,
|
||||
parish: createUserDto.parish,
|
||||
phone: createUserDto.phone,
|
||||
isEmailVerified: false,
|
||||
isTwoFactorEnabled: false,
|
||||
})
|
||||
.returning();
|
||||
|
||||
// check if user role is admin
|
||||
const role = createUserDto.role <= 2 ? 5 : createUserDto.role;
|
||||
|
||||
// Assign role to user
|
||||
await tx.insert(usersRole).values({
|
||||
userId: newUser.id,
|
||||
roleId: role,
|
||||
});
|
||||
|
||||
// Return the created user with role
|
||||
const [userWithRole] = await tx
|
||||
.select({
|
||||
id: users.id,
|
||||
username: users.username,
|
||||
email: users.email,
|
||||
fullname: users.fullname,
|
||||
phone: users.phone,
|
||||
isActive: users.isActive,
|
||||
role: roles.name,
|
||||
})
|
||||
.from(users)
|
||||
.leftJoin(usersRole, eq(usersRole.userId, users.id))
|
||||
.leftJoin(roles, eq(roles.id, usersRole.roleId))
|
||||
.where(eq(users.id, newUser.id));
|
||||
|
||||
return userWithRole;
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
22
apps/api/src/features/auth/dto/change-password.dto.ts
Normal file
22
apps/api/src/features/auth/dto/change-password.dto.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class ChangePasswordDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Identifier must be a string',
|
||||
})
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Password must be a string',
|
||||
})
|
||||
password: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'New password must be a string',
|
||||
})
|
||||
newPassword: string;
|
||||
}
|
||||
14
apps/api/src/features/auth/dto/confirm-email.dto.ts
Normal file
14
apps/api/src/features/auth/dto/confirm-email.dto.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsString, MaxLength, MinLength } from 'class-validator';
|
||||
|
||||
export class ConfirmEmailDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@MaxLength(6)
|
||||
@MinLength(6)
|
||||
code: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
}
|
||||
29
apps/api/src/features/auth/dto/create-user.dto.ts
Normal file
29
apps/api/src/features/auth/dto/create-user.dto.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class CreateUserDto {
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
fullname: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Phone must be a string',
|
||||
})
|
||||
@IsOptional()
|
||||
phone: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Password must be a string',
|
||||
})
|
||||
password: string;
|
||||
}
|
||||
10
apps/api/src/features/auth/dto/forgot-password.dto.ts
Normal file
10
apps/api/src/features/auth/dto/forgot-password.dto.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class ForgotPasswordDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Identifier must be a string',
|
||||
})
|
||||
username: string;
|
||||
}
|
||||
14
apps/api/src/features/auth/dto/refresh-token.dto.ts
Normal file
14
apps/api/src/features/auth/dto/refresh-token.dto.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNumber, IsString } from 'class-validator';
|
||||
|
||||
export class RefreshTokenDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Refresh token must be a string',
|
||||
})
|
||||
refresh_token: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
user_id: number;
|
||||
}
|
||||
22
apps/api/src/features/auth/dto/reset-password.dto.ts
Normal file
22
apps/api/src/features/auth/dto/reset-password.dto.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class ResetPasswordDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Identifier must be a string',
|
||||
})
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Reset Token must be a string',
|
||||
})
|
||||
resetToken: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'New password must be a string',
|
||||
})
|
||||
newPassword: string;
|
||||
}
|
||||
16
apps/api/src/features/auth/dto/signIn-user.dto.ts
Normal file
16
apps/api/src/features/auth/dto/signIn-user.dto.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class SignInUserDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Identifier must be a string',
|
||||
})
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Password must be a string',
|
||||
})
|
||||
password: string;
|
||||
}
|
||||
10
apps/api/src/features/auth/dto/signOut-user.dto.ts
Normal file
10
apps/api/src/features/auth/dto/signOut-user.dto.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class SignOutUserDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'User Id must be a string',
|
||||
})
|
||||
user_id: string;
|
||||
}
|
||||
45
apps/api/src/features/auth/dto/signUp-user.dto.ts
Normal file
45
apps/api/src/features/auth/dto/signUp-user.dto.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsInt, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class SingUpUserDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
fullname: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Phone must be a string',
|
||||
})
|
||||
@IsOptional()
|
||||
phone: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Password must be a string',
|
||||
})
|
||||
password: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
state: number;
|
||||
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
municipality: number;
|
||||
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
parish: number;
|
||||
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
role: number;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { User } from '@/features/users/entities/user.entity';
|
||||
|
||||
export class UpdateRefreshTokenDto {
|
||||
user: User;
|
||||
refresh_token: string;
|
||||
}
|
||||
16
apps/api/src/features/auth/dto/validate-user.dto.ts
Normal file
16
apps/api/src/features/auth/dto/validate-user.dto.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString } from 'class-validator';
|
||||
|
||||
export class ValidateUserDto {
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'First name must be a string',
|
||||
})
|
||||
username: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString({
|
||||
message: 'Password must be a string',
|
||||
})
|
||||
password: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
interface AuthTokensInterface {
|
||||
access_token: string;
|
||||
refresh_token: string;
|
||||
}
|
||||
|
||||
export default AuthTokensInterface;
|
||||
@@ -0,0 +1,25 @@
|
||||
export interface LoginUserInterface {
|
||||
message: string;
|
||||
user: User;
|
||||
tokens: Tokens;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
username: string;
|
||||
fullname: string;
|
||||
email?: string;
|
||||
rol: Roles[];
|
||||
}
|
||||
|
||||
export interface Roles {
|
||||
id: number;
|
||||
rol: string;
|
||||
}
|
||||
|
||||
interface Tokens {
|
||||
access_token: string;
|
||||
access_expire_in: number;
|
||||
refresh_token: string;
|
||||
refresh_expire_in: number;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
interface RefreshTokenInterface {
|
||||
access_token: string;
|
||||
access_expire_in: number;
|
||||
refresh_token: string;
|
||||
refresh_expire_in: number;
|
||||
}
|
||||
|
||||
export default RefreshTokenInterface;
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface Session {
|
||||
userId: string;
|
||||
sessionToken: string;
|
||||
expiresAt: number;
|
||||
}
|
||||
Reference in New Issue
Block a user