feat: add TipoEvento entity and related functionality

- Introduced TipoEvento entity with enum for event types.
- Created DTOs for creating and updating TipoEvento.
- Implemented TipoEvento service with methods for CRUD operations and seeding initial data.
- Added TipoEvento controller for handling HTTP requests related to event types.
- Integrated TipoEvento into the main application module.
- Updated Evento entity to include a relationship with TipoEvento.
- Enhanced ParticipanteEvento service to register attendance using QR tokens.
- Implemented QR token generation and validation for event attendance.
- Updated API documentation for new endpoints and functionalities.
- Adjusted TypeOrm configuration to include new entities.
This commit is contained in:
miguel
2025-08-19 10:27:06 -06:00
parent 94002a3e50
commit bc5ddb29c7
39 changed files with 882 additions and 140 deletions
+23 -9
View File
@@ -15,9 +15,12 @@ import { CreateAdministradorDto } from './dto/create-administrador.dto';
import { UpdateAdministradorDto } from './dto/update.administrador.dto';
import { LoginAdministradorDto } from './dto/login-administrador.dto';
import { ChangePasswordDto } from './dto/change-password.dto';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { AdministradorApiDocumentation } from './administrador.documentation';
import { AdministradorApiDocumentation } from './docs/administrador.documentation';
import { JwtValidationGuard } from 'src/auth/guards/jwt-validation.guard';
import { Roles } from 'src/auth/decorators/roles.decorator';
import { RolesGuard } from 'src/auth/guards/roles.guard';
@AdministradorApiDocumentation.ApiController
@ApiBearerAuth()
@@ -26,20 +29,25 @@ export class AdministradorController {
constructor(private administradorService: AdministradorService) {}
@Get()
@UseGuards(JwtAuthGuard)
@UseGuards(RolesGuard)
@UseGuards(JwtValidationGuard)
@Roles('administrador')
@AdministradorApiDocumentation.ApiGetAll
getAdministradores(): Promise<Administrador[]> {
return this.administradorService.getAdministradores();
}
@Get(':id')
@UseGuards(JwtAuthGuard)
@UseGuards(RolesGuard)
@UseGuards(JwtValidationGuard)
@Roles('administrador')
@AdministradorApiDocumentation.ApiGetOne
getAdministrador(@Param('id', ParseIntPipe) id: number) {
return this.administradorService.getAdministrador(id);
return this.administradorService.getAdminByIdOrFail(id);
}
@Post()
@Roles('administrador')
@AdministradorApiDocumentation.ApiCreate
createAdministrador(@Body() newAdministrador: CreateAdministradorDto) {
return this.administradorService.createAdministrador(newAdministrador);
@@ -49,13 +57,15 @@ export class AdministradorController {
@AdministradorApiDocumentation.ApiLogin
login(@Body() loginData: LoginAdministradorDto) {
return this.administradorService.login(
loginData.correo,
loginData.nombre_usuario,
loginData.password,
);
}
@Patch(':id/change-password')
@UseGuards(JwtAuthGuard)
@UseGuards(RolesGuard)
@UseGuards(JwtValidationGuard)
@Roles('administrador')
@AdministradorApiDocumentation.ApiChangePassword
changePassword(
@Param('id', ParseIntPipe) id: number,
@@ -69,14 +79,18 @@ export class AdministradorController {
}
@Delete(':id')
@UseGuards(JwtAuthGuard)
@UseGuards(RolesGuard)
@UseGuards(JwtValidationGuard)
@Roles('administrador')
@AdministradorApiDocumentation.ApiRemove
deleteAdministrador(@Param('id', ParseIntPipe) id: number) {
return this.administradorService.deleteAdministrador(id);
}
@Patch(':id')
@UseGuards(JwtAuthGuard)
@UseGuards(RolesGuard)
@UseGuards(JwtValidationGuard)
@Roles('administrador')
@AdministradorApiDocumentation.ApiUpdate
updateAdministrador(
@Param('id', ParseIntPipe) id: number,
+28 -22
View File
@@ -35,9 +35,10 @@ export class AdministradorService {
// Crear y guardar el nuevo administrador
const newAdministrador = this.administradorRepository.create({
nombre_usuario: administrador.nombre_usuario,
correo: administrador.correo,
password: hashedPassword,
id_tipo_user: administrador.id_tipo_user,
tipoUser: { id_tipo_user: administrador.id_tipo_user }, // Asignar el tipo de usuario
});
const savedAdministrador =
@@ -48,10 +49,10 @@ export class AdministradorService {
return result;
}
async login(correo: string, password: string) {
// Buscar administrador por correo
async login(nombre_usuario: string, password: string) {
// Buscar administrador por nombre de usuario
const administrador = await this.administradorRepository.findOne({
where: { correo },
where: { nombre_usuario },
relations: ['tipoUser'],
});
@@ -76,24 +77,24 @@ export class AdministradorService {
// Generar token JWT
const payload = {
sub: administrador.id_admnistrador,
sub: administrador.id_administrador,
correo: administrador.correo,
id_tipo_user: administrador.id_tipo_user,
};
return {
token: this.jwtService.sign(payload),
tipo_usuario: administrador.tipoUser.tipo,
};
}
async changePassword(
id_admnistrador: number,
id_administrador: number,
currentPassword: string,
newPassword: string,
) {
// Buscar administrador
const administrador = await this.administradorRepository.findOne({
where: { id_admnistrador },
where: { id_administrador },
});
if (!administrador) {
@@ -131,23 +132,17 @@ export class AdministradorService {
return this.administradorRepository.find({
relations: ['tipoUser'],
select: {
id_admnistrador: true,
nombre_usuario: true,
id_administrador: true,
correo: true,
id_tipo_user: true,
},
});
}
async getAdministrador(id_admnistrador: number) {
async getAdminByIdOrFail(id_administrador: number) {
const administradorFound = await this.administradorRepository.findOne({
where: {
id_admnistrador,
},
relations: ['tipoUser'],
select: {
id_admnistrador: true,
correo: true,
id_tipo_user: true,
id_administrador,
},
});
@@ -161,9 +156,20 @@ export class AdministradorService {
return administradorFound;
}
async deleteAdministrador(id_admnistrador: number) {
async getAdminById(id_administrador: number) {
const administradorFound = await this.administradorRepository.findOne({
where: {
id_administrador,
},
relations: ['tipoUser'],
});
return administradorFound;
}
async deleteAdministrador(id_administrador: number) {
const result = await this.administradorRepository.delete({
id_admnistrador,
id_administrador,
});
if (result.affected === 0) {
@@ -177,12 +183,12 @@ export class AdministradorService {
}
async updateAdministrador(
id_admnistrador: number,
id_administrador: number,
administrador: UpdateAdministradorDto,
) {
const administradorFound = await this.administradorRepository.findOne({
where: {
id_admnistrador,
id_administrador,
},
});
@@ -10,9 +10,7 @@ import { applyDecorators } from '@nestjs/common';
export class AdministradorApiDocumentation {
// Decorador para toda la clase del controlador
static ApiController = applyDecorators(
ApiTags('Administrador'),
);
static ApiController = applyDecorators(ApiTags('Administrador'));
// Documentación para crear un administrador
static ApiCreate = applyDecorators(
ApiOperation({
@@ -26,6 +24,11 @@ export class AdministradorApiDocumentation {
type: 'object',
required: ['correo', 'password', 'id_tipo_user'],
properties: {
nombre_usuario: {
type: 'string',
example: 'mike',
description: 'Nombre de usuario del administrador',
},
correo: {
type: 'string',
format: 'email',
@@ -2,18 +2,31 @@ import { IsEmail, IsNotEmpty, IsNumber, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateAdministradorDto {
@ApiProperty({ example: 'admin@example.com', description: 'Correo del administrador' })
@IsEmail({}, { message: 'El correo no es válido' })
@IsNotEmpty({ message: 'El correo es requerido' })
correo: string;
@ApiProperty({
example: 'admin@example.com',
description: 'Correo del administrador',
})
@IsEmail({}, { message: 'El correo no es válido' })
@IsNotEmpty({ message: 'El correo es requerido' })
correo: string;
@ApiProperty({ example: 'Password123', description: 'Contraseña del administrador' })
@MinLength(6, { message: 'La contraseña debe tener al menos 6 caracteres' })
@IsNotEmpty({ message: 'La contraseña es requerida' })
password: string;
@ApiProperty({
example: 'mike',
description: 'Nombre de usuario del administrador',
})
@IsNotEmpty({ message: 'El nombre de usuario es requerido' })
nombre_usuario: string;
@ApiProperty({ example: 1, description: 'ID del tipo de usuario' })
@IsNumber({}, { message: 'El tipo de usuario debe ser un número' })
@IsNotEmpty({ message: 'El tipo de usuario es requerido' })
id_tipo_user: number;
}
@ApiProperty({
example: 'Password123',
description: 'Contraseña del administrador',
})
@MinLength(6, { message: 'La contraseña debe tener al menos 6 caracteres' })
@IsNotEmpty({ message: 'La contraseña es requerida' })
password: string;
@ApiProperty({ example: 1, description: 'ID del tipo de usuario' })
@IsNumber({}, { message: 'El tipo de usuario debe ser un número' })
@IsNotEmpty({ message: 'El tipo de usuario es requerido' })
id_tipo_user: number;
}
@@ -1,13 +1,18 @@
import { IsEmail, IsNotEmpty, MinLength } from 'class-validator';
import { IsEmail, IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class LoginAdministradorDto {
@ApiProperty({ example: 'admin@example.com', description: 'Correo del administrador' })
@IsEmail({}, { message: 'El correo no es válido' })
@IsNotEmpty({ message: 'El correo es requerido' })
correo: string;
@ApiProperty({
example: 'mike',
description: 'Nombre de usuario del administrador',
})
@IsNotEmpty({ message: 'El nombre de usuario es requerido' })
nombre_usuario: string;
@ApiProperty({ example: 'Password123', description: 'Contraseña del administrador' })
@IsNotEmpty({ message: 'La contraseña es requerida' })
password: string;
}
@ApiProperty({
example: 'Password123',
description: 'Contraseña del administrador',
})
@IsNotEmpty({ message: 'La contraseña es requerida' })
password: string;
}
@@ -1,10 +1,19 @@
import { TipoUser } from 'src/tipo_user/entities/tipo_user.entity';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity('administrador')
export class Administrador {
@PrimaryGeneratedColumn()
id_admnistrador: number;
id_administrador: number;
@Column({ unique: true })
nombre_usuario: string;
@Column({ unique: true })
correo: string;
@@ -12,9 +21,10 @@ export class Administrador {
@Column()
password: string;
@Column()
@Column({ type: 'int' })
id_tipo_user: number;
@ManyToOne(() => TipoUser, (tipoUser) => tipoUser.administrador)
tipoUser: TipoUser[];
@JoinColumn({ name: 'id_tipo_user' })
tipoUser: TipoUser;
}