login de admin y endpoints de admin validados, falta validar lo de qr
This commit is contained in:
@@ -1,57 +1,72 @@
|
||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UseGuards } from '@nestjs/common';
|
||||
import { AdministradorService } from './administrador.service';
|
||||
import { Administrador } from './administrador.entity';
|
||||
import { CreateAdministradorDto } from './dto/create-administrador.dto';
|
||||
import { UpdateAdministradorDto } from './dto/update.administrador.dto';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody } from '@nestjs/swagger';
|
||||
import { LoginAdministradorDto } from './dto/login-administrador.dto';
|
||||
import { ChangePasswordDto } from './dto/change-password.dto';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||
import { AdministradorApiDocumentation } from './administrador.documentation';
|
||||
|
||||
@ApiTags('Administradores') // Agrupa los endpoints en Swagger
|
||||
@Controller('administrador')
|
||||
@ApiBearerAuth()
|
||||
@AdministradorApiDocumentation.ApiController
|
||||
export class AdministradorController {
|
||||
|
||||
constructor(private administradorService: AdministradorService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Obtener todos los administradores' })
|
||||
@ApiResponse({ status: 200, description: 'Lista de administradores obtenida correctamente.' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@AdministradorApiDocumentation.ApiGetAll
|
||||
getAdministradores(): Promise<Administrador[]> {
|
||||
return this.administradorService.getAdministradores();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Obtener un administrador por ID' })
|
||||
@ApiParam({ name: 'id', description: 'ID del administrador', example: 1 })
|
||||
@ApiResponse({ status: 200, description: 'Administrador obtenido correctamente.' })
|
||||
@ApiResponse({ status: 404, description: 'Administrador no encontrado.' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@AdministradorApiDocumentation.ApiGetOne
|
||||
getAdministrador(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.administradorService.getAdministrador(id)
|
||||
return this.administradorService.getAdministrador(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Registrar un nuevo administrador' })
|
||||
@ApiBody({
|
||||
description: 'Datos del administrador a registrar',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_tipo_user: { type: 'integer', example: 1 }
|
||||
}
|
||||
}
|
||||
})
|
||||
@ApiResponse({ status: 201, description: 'Administrador registrado exitosamente.' })
|
||||
@ApiResponse({ status: 400, description: 'Datos inválidos.' })
|
||||
@AdministradorApiDocumentation.ApiCreate
|
||||
createAdministrador(@Body() newAdministrador: CreateAdministradorDto) {
|
||||
return this.administradorService.createAdministrador(newAdministrador)
|
||||
return this.administradorService.createAdministrador(newAdministrador);
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
@AdministradorApiDocumentation.ApiLogin
|
||||
login(@Body() loginData: LoginAdministradorDto) {
|
||||
return this.administradorService.login(loginData.correo, loginData.password);
|
||||
}
|
||||
|
||||
@Patch(':id/change-password')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@AdministradorApiDocumentation.ApiChangePassword
|
||||
changePassword(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() changePasswordDto: ChangePasswordDto
|
||||
) {
|
||||
return this.administradorService.changePassword(
|
||||
id,
|
||||
changePasswordDto.currentPassword,
|
||||
changePasswordDto.newPassword
|
||||
);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@AdministradorApiDocumentation.ApiRemove
|
||||
deleteAdministrador(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.administradorService.deleteAdministrador(id)
|
||||
return this.administradorService.deleteAdministrador(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@AdministradorApiDocumentation.ApiUpdate
|
||||
updateAdministrador(@Param('id', ParseIntPipe) id: number, @Body() administrador: UpdateAdministradorDto) {
|
||||
return this.administradorService.updateAdministrador(id, administrador)
|
||||
return this.administradorService.updateAdministrador(id, administrador);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
import { ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
|
||||
export class AdministradorApiDocumentation {
|
||||
// Decorador para toda la clase del controlador
|
||||
static ApiController = ApiTags('Administradores');
|
||||
|
||||
// Documentación para crear un administrador
|
||||
static ApiCreate = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Registrar un nuevo administrador',
|
||||
description: 'Crea un nuevo administrador con correo, contraseña y tipo de administrador'
|
||||
}),
|
||||
ApiBody({
|
||||
description: 'Datos del administrador a registrar',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['correo', 'password', 'id_tipo_user'],
|
||||
properties: {
|
||||
correo: {
|
||||
type: 'string',
|
||||
format: 'email',
|
||||
example: 'admin@ejemplo.com',
|
||||
description: 'Correo electrónico del administrador'
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
format: 'password',
|
||||
example: 'Password123',
|
||||
description: 'Contraseña del administrador (mínimo 6 caracteres)'
|
||||
},
|
||||
id_tipo_user: {
|
||||
type: 'integer',
|
||||
example: 1,
|
||||
description: 'ID del tipo de usuario administrador'
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 201,
|
||||
description: 'Administrador registrado exitosamente',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_admnistrador: { type: 'number', example: 1 },
|
||||
correo: { type: 'string', example: 'admin@ejemplo.com' },
|
||||
id_tipo_user: { type: 'number', example: 1 }
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 400, description: 'Datos del administrador inválidos' }),
|
||||
ApiResponse({ status: 409, description: 'El correo ya está registrado' })
|
||||
);
|
||||
|
||||
// Documentación para iniciar sesión
|
||||
static ApiLogin = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Iniciar sesión como administrador',
|
||||
description: 'Autentica un administrador con correo y contraseña, y devuelve un token JWT'
|
||||
}),
|
||||
ApiBody({
|
||||
description: 'Credenciales de inicio de sesión',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['correo', 'password'],
|
||||
properties: {
|
||||
correo: {
|
||||
type: 'string',
|
||||
format: 'email',
|
||||
example: 'admin@ejemplo.com',
|
||||
description: 'Correo electrónico del administrador'
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
format: 'password',
|
||||
example: 'Password123',
|
||||
description: 'Contraseña del administrador'
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 200,
|
||||
description: 'Inicio de sesión exitoso',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
access_token: {
|
||||
type: 'string',
|
||||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
||||
description: 'Token JWT para autenticación'
|
||||
},
|
||||
id_administrador: {
|
||||
type: 'number',
|
||||
example: 1,
|
||||
description: 'ID del administrador autenticado'
|
||||
},
|
||||
correo: {
|
||||
type: 'string',
|
||||
example: 'admin@ejemplo.com',
|
||||
description: 'Correo del administrador autenticado'
|
||||
},
|
||||
tipo_user: {
|
||||
type: 'number',
|
||||
example: 1,
|
||||
description: 'Tipo de usuario del administrador'
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 401, description: 'Credenciales inválidas' })
|
||||
);
|
||||
|
||||
// Documentación para obtener todos los administradores
|
||||
static ApiGetAll = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Obtener todos los administradores',
|
||||
description: 'Retorna una lista de todos los administradores registrados (requiere autenticación)'
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de administradores obtenida correctamente',
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_admnistrador: { type: 'number', example: 1 },
|
||||
correo: { type: 'string', example: 'admin@ejemplo.com' },
|
||||
id_tipo_user: { type: 'number', example: 1 },
|
||||
tipoUser: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_tipo_user: { type: 'number', example: 1 },
|
||||
tipo_user: { type: 'string', example: 'Administrador General' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 401, description: 'No autorizado' })
|
||||
);
|
||||
|
||||
// Documentación para obtener un administrador por ID
|
||||
static ApiGetOne = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Obtener un administrador por ID',
|
||||
description: 'Retorna los datos de un administrador específico según su ID (requiere autenticación)'
|
||||
}),
|
||||
ApiParam({
|
||||
name: 'id',
|
||||
description: 'ID del administrador',
|
||||
type: 'number',
|
||||
example: 1
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 200,
|
||||
description: 'Administrador obtenido correctamente',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_admnistrador: { type: 'number', example: 1 },
|
||||
correo: { type: 'string', example: 'admin@ejemplo.com' },
|
||||
id_tipo_user: { type: 'number', example: 1 },
|
||||
tipoUser: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_tipo_user: { type: 'number', example: 1 },
|
||||
tipo_user: { type: 'string', example: 'Administrador General' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 404, description: 'Administrador no encontrado' }),
|
||||
ApiResponse({ status: 401, description: 'No autorizado' })
|
||||
);
|
||||
|
||||
// Documentación para actualizar un administrador
|
||||
static ApiUpdate = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Actualizar datos de un administrador',
|
||||
description: 'Actualiza la información de un administrador existente (requiere autenticación)'
|
||||
}),
|
||||
ApiParam({
|
||||
name: 'id',
|
||||
description: 'ID del administrador a actualizar',
|
||||
type: 'number',
|
||||
example: 1
|
||||
}),
|
||||
ApiBody({
|
||||
description: 'Datos a actualizar del administrador',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
correo: {
|
||||
type: 'string',
|
||||
format: 'email',
|
||||
example: 'nuevo_admin@ejemplo.com',
|
||||
description: 'Nuevo correo electrónico del administrador'
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
format: 'password',
|
||||
example: 'NuevaPassword123',
|
||||
description: 'Nueva contraseña del administrador (mínimo 6 caracteres)'
|
||||
},
|
||||
id_tipo_user: {
|
||||
type: 'integer',
|
||||
example: 2,
|
||||
description: 'Nuevo tipo de usuario administrador'
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 200,
|
||||
description: 'Administrador actualizado correctamente',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id_admnistrador: { type: 'number', example: 1 },
|
||||
correo: { type: 'string', example: 'nuevo_admin@ejemplo.com' },
|
||||
id_tipo_user: { type: 'number', example: 2 }
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 400, description: 'Datos de actualización inválidos' }),
|
||||
ApiResponse({ status: 404, description: 'Administrador no encontrado' }),
|
||||
ApiResponse({ status: 401, description: 'No autorizado' })
|
||||
);
|
||||
|
||||
// Documentación para cambiar contraseña
|
||||
static ApiChangePassword = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Cambiar contraseña de un administrador',
|
||||
description: 'Permite a un administrador cambiar su contraseña verificando primero la contraseña actual (requiere autenticación)'
|
||||
}),
|
||||
ApiParam({
|
||||
name: 'id',
|
||||
description: 'ID del administrador',
|
||||
type: 'number',
|
||||
example: 1
|
||||
}),
|
||||
ApiBody({
|
||||
description: 'Datos para cambio de contraseña',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['currentPassword', 'newPassword'],
|
||||
properties: {
|
||||
currentPassword: {
|
||||
type: 'string',
|
||||
format: 'password',
|
||||
example: 'Password123',
|
||||
description: 'Contraseña actual del administrador'
|
||||
},
|
||||
newPassword: {
|
||||
type: 'string',
|
||||
format: 'password',
|
||||
example: 'NuevaPassword123',
|
||||
description: 'Nueva contraseña del administrador (mínimo 6 caracteres)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 200,
|
||||
description: 'Contraseña actualizada correctamente',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
message: { type: 'string', example: 'Contraseña actualizada correctamente' }
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 400, description: 'Contraseña actual incorrecta' }),
|
||||
ApiResponse({ status: 404, description: 'Administrador no encontrado' }),
|
||||
ApiResponse({ status: 401, description: 'No autorizado' })
|
||||
);
|
||||
|
||||
// Documentación para eliminar un administrador
|
||||
static ApiRemove = applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Eliminar un administrador',
|
||||
description: 'Elimina permanentemente un administrador por su ID (requiere autenticación)'
|
||||
}),
|
||||
ApiParam({
|
||||
name: 'id',
|
||||
description: 'ID del administrador a eliminar',
|
||||
type: 'number',
|
||||
example: 1
|
||||
}),
|
||||
ApiResponse({
|
||||
status: 200,
|
||||
description: 'Administrador eliminado correctamente',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
affected: { type: 'number', example: 1 }
|
||||
}
|
||||
}
|
||||
}),
|
||||
ApiResponse({ status: 404, description: 'Administrador no encontrado' }),
|
||||
ApiResponse({ status: 401, description: 'No autorizado' })
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,12 @@ export class Administrador {
|
||||
@PrimaryGeneratedColumn()
|
||||
id_admnistrador: number
|
||||
|
||||
@Column({ unique: true })
|
||||
correo: string
|
||||
|
||||
@Column()
|
||||
password: string
|
||||
|
||||
/*
|
||||
@ManyToOne(() => TipoUser, (tipoUser) => tipoUser.administradores)
|
||||
@JoinColumn({ name: "id_tipo_user" })
|
||||
|
||||
@@ -3,9 +3,13 @@ import { AdministradorService } from './administrador.service';
|
||||
import { AdministradorController } from './administrador.controller';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Administrador } from './administrador.entity';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Administrador])],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Administrador]),
|
||||
AuthModule
|
||||
],
|
||||
controllers: [AdministradorController],
|
||||
providers: [AdministradorService],
|
||||
exports: [AdministradorService],
|
||||
|
||||
@@ -4,36 +4,115 @@ import { Administrador } from './administrador.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
import { CreateAdministradorDto } from './dto/create-administrador.dto';
|
||||
import { UpdateAdministradorDto } from './dto/update.administrador.dto';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
|
||||
@Injectable()
|
||||
export class AdministradorService {
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Administrador) private administradorRepository: Repository<Administrador>
|
||||
@InjectRepository(Administrador) private administradorRepository: Repository<Administrador>,
|
||||
private jwtService: JwtService
|
||||
) {}
|
||||
|
||||
async createAdministrador(administrador: CreateAdministradorDto) {
|
||||
|
||||
//revisar el where
|
||||
// Verificar si ya existe un administrador con el mismo correo
|
||||
const administradorFound = await this.administradorRepository.findOne({
|
||||
where: {
|
||||
id_admnistrador: administrador.id_tipo_user
|
||||
correo: administrador.correo
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (administradorFound) {
|
||||
return new HttpException('Administrador already exists', HttpStatus.CONFLICT)
|
||||
throw new HttpException('El correo ya está registrado', HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
// Encriptar la contraseña
|
||||
const hashedPassword = await this.hashPassword(administrador.password);
|
||||
|
||||
// Crear y guardar el nuevo administrador
|
||||
const newAdministrador = this.administradorRepository.create({
|
||||
correo: administrador.correo,
|
||||
password: hashedPassword,
|
||||
id_tipo_user: administrador.id_tipo_user
|
||||
});
|
||||
|
||||
//Falta regresar el return
|
||||
//return this.administradorRepository.save(administradorFound)
|
||||
const savedAdministrador = await this.administradorRepository.save(newAdministrador);
|
||||
|
||||
// Excluir la contraseña de la respuesta
|
||||
const { password, ...result } = savedAdministrador;
|
||||
return result;
|
||||
}
|
||||
|
||||
async login(correo: string, password: string) {
|
||||
// Buscar administrador por correo
|
||||
const administrador = await this.administradorRepository.findOne({
|
||||
where: { correo },
|
||||
relations: ['tipoUser']
|
||||
});
|
||||
|
||||
if (!administrador) {
|
||||
throw new HttpException('Credenciales inválidas', HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Verificar contraseña
|
||||
const isPasswordValid = await bcrypt.compare(password, administrador.password);
|
||||
if (!isPasswordValid) {
|
||||
throw new HttpException('Credenciales inválidas', HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Generar token JWT
|
||||
const payload = {
|
||||
sub: administrador.id_admnistrador,
|
||||
correo: administrador.correo,
|
||||
id_tipo_user: administrador.id_tipo_user
|
||||
};
|
||||
|
||||
return {
|
||||
access_token: this.jwtService.sign(payload),
|
||||
id_administrador: administrador.id_admnistrador,
|
||||
correo: administrador.correo,
|
||||
tipo_user: administrador.id_tipo_user
|
||||
};
|
||||
}
|
||||
|
||||
async changePassword(id_admnistrador: number, currentPassword: string, newPassword: string) {
|
||||
// Buscar administrador
|
||||
const administrador = await this.administradorRepository.findOne({
|
||||
where: { id_admnistrador }
|
||||
});
|
||||
|
||||
if (!administrador) {
|
||||
throw new HttpException('Administrador no encontrado', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Verificar contraseña actual
|
||||
const isPasswordValid = await bcrypt.compare(currentPassword, administrador.password);
|
||||
if (!isPasswordValid) {
|
||||
throw new HttpException('Contraseña actual incorrecta', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Hashear y actualizar nueva contraseña
|
||||
administrador.password = await this.hashPassword(newPassword);
|
||||
await this.administradorRepository.save(administrador);
|
||||
|
||||
return { message: 'Contraseña actualizada correctamente' };
|
||||
}
|
||||
|
||||
private async hashPassword(password: string): Promise<string> {
|
||||
const salt = await bcrypt.genSalt();
|
||||
return bcrypt.hash(password, salt);
|
||||
}
|
||||
|
||||
getAdministradores() {
|
||||
return this.administradorRepository.find({
|
||||
relations: ['tipoUser']
|
||||
})
|
||||
relations: ['tipoUser'],
|
||||
select: {
|
||||
id_admnistrador: true,
|
||||
correo: true,
|
||||
id_tipo_user: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async getAdministrador(id_admnistrador: number) {
|
||||
@@ -41,24 +120,29 @@ export class AdministradorService {
|
||||
where: {
|
||||
id_admnistrador
|
||||
},
|
||||
relations: ['tipoUser']
|
||||
})
|
||||
relations: ['tipoUser'],
|
||||
select: {
|
||||
id_admnistrador: true,
|
||||
correo: true,
|
||||
id_tipo_user: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!Administrador) {
|
||||
return new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
if (!administradorFound) {
|
||||
throw new HttpException('Administrador no encontrado', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
return administradorFound
|
||||
return administradorFound;
|
||||
}
|
||||
|
||||
async deleteAdministrador(id_admnistrador: number) {
|
||||
const result = await this.administradorRepository.delete({ id_admnistrador })
|
||||
const result = await this.administradorRepository.delete({ id_admnistrador });
|
||||
|
||||
if (result.affected === 0) {
|
||||
return new HttpException('User not found', HttpStatus.NOT_FOUND);
|
||||
throw new HttpException('Administrador no encontrado', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
|
||||
async updateAdministrador(id_admnistrador: number, administrador: UpdateAdministradorDto) {
|
||||
@@ -66,14 +150,22 @@ export class AdministradorService {
|
||||
where: {
|
||||
id_admnistrador
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (!administradorFound) {
|
||||
return new HttpException('User not found', HttpStatus.NOT_FOUND)
|
||||
throw new HttpException('Administrador no encontrado', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
const updateAdministrador = Object.assign(administradorFound, administrador)
|
||||
return this.administradorRepository.save(updateAdministrador)
|
||||
}
|
||||
// Si se incluye una nueva contraseña, hashearla
|
||||
if (administrador.password) {
|
||||
administrador.password = await this.hashPassword(administrador.password);
|
||||
}
|
||||
|
||||
const updateAdministrador = Object.assign(administradorFound, administrador);
|
||||
const savedAdministrador = await this.administradorRepository.save(updateAdministrador);
|
||||
|
||||
// Excluir la contraseña de la respuesta
|
||||
const { password, ...result } = savedAdministrador;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { IsNotEmpty, MinLength } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class ChangePasswordDto {
|
||||
@ApiProperty({ description: 'Contraseña actual del administrador' })
|
||||
@IsNotEmpty({ message: 'La contraseña actual es requerida' })
|
||||
currentPassword: string;
|
||||
|
||||
@ApiProperty({ description: 'Nueva contraseña del administrador' })
|
||||
@MinLength(6, { message: 'La nueva contraseña debe tener al menos 6 caracteres' })
|
||||
@IsNotEmpty({ message: 'La nueva contraseña es requerida' })
|
||||
newPassword: string;
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
import { IsEmail, IsNotEmpty, IsNumber, MinLength } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateAdministradorDto {
|
||||
id_tipo_user: number
|
||||
@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: 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;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { IsEmail, IsNotEmpty, MinLength } 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: 'Password123', description: 'Contraseña del administrador' })
|
||||
@IsNotEmpty({ message: 'La contraseña es requerida' })
|
||||
password: string;
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
import { IsEmail, IsNumber, IsOptional, MinLength } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class UpdateAdministradorDto {
|
||||
id_tipo_user?: number
|
||||
@ApiProperty({ example: 'admin@example.com', description: 'Correo del administrador', required: false })
|
||||
@IsEmail({}, { message: 'El correo no es válido' })
|
||||
@IsOptional()
|
||||
correo?: string;
|
||||
|
||||
@ApiProperty({ example: 'Password123', description: 'Contraseña del administrador', required: false })
|
||||
@MinLength(6, { message: 'La contraseña debe tener al menos 6 caracteres' })
|
||||
@IsOptional()
|
||||
password?: string;
|
||||
|
||||
@ApiProperty({ example: 1, description: 'ID del tipo de usuario', required: false })
|
||||
@IsNumber({}, { message: 'El tipo de usuario debe ser un número' })
|
||||
@IsOptional()
|
||||
id_tipo_user?: number;
|
||||
}
|
||||
+4
-2
@@ -25,6 +25,7 @@ import { AsistenciaModule } from './asistencia/asistencia.module';
|
||||
import { ParticipanteEventoModule } from './participante_evento/participante_evento.module';
|
||||
import { ValidacionesModule } from './validaciones/validaciones.module';
|
||||
import { AlumnosModule } from './alumnos/alumnos.module';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
|
||||
|
||||
@Module({
|
||||
@@ -42,8 +43,8 @@ import { AlumnosModule } from './alumnos/alumnos.module';
|
||||
port: Number(process.env.db_port),
|
||||
|
||||
|
||||
synchronize: false,
|
||||
dropSchema: false, // elimina la base de datos
|
||||
synchronize: true,
|
||||
dropSchema: true, // elimina la base de datos
|
||||
|
||||
// logging: true, // Habilita los logs para depuración
|
||||
autoLoadEntities: true, // Carga automáticamente las entidades
|
||||
@@ -66,6 +67,7 @@ import { AlumnosModule } from './alumnos/alumnos.module';
|
||||
retryAttempts: 10, // Intentos para reconectar
|
||||
retryDelay: 3000, // Tiempo entre reintentos
|
||||
}),
|
||||
AuthModule,
|
||||
CuestionarioModule,
|
||||
TipoCuestionarioModule,
|
||||
CuestionarioSeccionModule,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Administrador } from '../administrador/administrador.entity';
|
||||
import { JwtStrategy } from './jwt.strategy';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
PassportModule.register({ defaultStrategy: 'jwt' }),
|
||||
JwtModule.register({
|
||||
secret: process.env.JWT_SECRET || 'tu_clave_secreta',
|
||||
signOptions: {
|
||||
expiresIn: '24h', // Tokens expiran en 24 horas
|
||||
},
|
||||
}),
|
||||
TypeOrmModule.forFeature([Administrador]),
|
||||
],
|
||||
providers: [JwtStrategy],
|
||||
exports: [PassportModule, JwtModule],
|
||||
})
|
||||
export class AuthModule {}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { Repository } from 'typeorm';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Administrador } from '../administrador/administrador.entity';
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
constructor(
|
||||
@InjectRepository(Administrador)
|
||||
private administradorRepository: Repository<Administrador>,
|
||||
) {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: process.env.JWT_SECRET || 'tu_clave_secreta',
|
||||
});
|
||||
}
|
||||
|
||||
async validate(payload: any) {
|
||||
const { sub: id_admnistrador } = payload;
|
||||
|
||||
const administrador = await this.administradorRepository.findOne({
|
||||
where: { id_admnistrador },
|
||||
select: {
|
||||
id_admnistrador: true,
|
||||
correo: true,
|
||||
id_tipo_user: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!administrador) {
|
||||
throw new UnauthorizedException('Token inválido');
|
||||
}
|
||||
|
||||
return administrador;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user