64 Commits

Author SHA1 Message Date
Patriots01 535e030927 Modificaciones en los archivos de carrusel, entity, controller, servicio, se agrego un nuevo endpoint para actualizar los banner y se agrego un campo de orden en la entity 2026-02-18 21:16:38 +00:00
Patriots01 a53d9ddabe Se actualizo la infromacion de comentarios y participantes en el orden de enviar la infromacion y se documento el campo de orden en carrusel, para no causar conflicto falta arreglar esta parte 2026-02-17 22:32:20 +00:00
Patriots01 fb31589c78 Se implemento el cierre de la conexion en la base de datos 2026-02-07 00:40:01 +00:00
jalvarado 6238c82296 Merge pull request 'feat: ampliacion de campos' (#17) from develop into master
Reviewed-on: #17
2026-02-04 18:35:27 -06:00
miguel fa472fcbf1 feat: ampliacion de campos 2026-02-04 18:33:09 -06:00
Patriots01 da05d88923 Se modifico la confirmacion del alumno 2026-02-04 20:39:58 +00:00
santiago 20f7688f8b Modificaciones en produccion 2025-09-12 20:12:08 -06:00
santiago 05e4443c1b Mandar modificaciones a produccion 2025-09-12 20:09:28 -06:00
santiago a41b30b94a Modificacion y refactorizacion del codigo 2025-08-27 12:44:22 -06:00
santiago aa8efa74d9 Modificacion en la peticion para verificar si existe el correo 2025-08-27 12:30:46 -06:00
santiago 98ca9f7792 Modificacion para agegar la descarga de participantes de eventos 2025-08-23 09:57:16 -06:00
santiago 2c953b58da Subir cambios a develop 2025-08-22 12:48:25 -06:00
evenegas 0f986a2f7f Descarga de participantes 2025-08-22 12:14:54 -06:00
evenegas eaa5921c69 se agregó fecha de consulta a la api 2025-08-20 11:43:26 -06:00
evenegas b6f4084185 se agregó fecha de consulta a la api 2025-08-20 11:42:55 -06:00
evenegas 0aa0d514cb se agregó implementacion de Api para ampliación 2025-08-19 12:16:17 -06:00
jalvarado a88db620f3 Merge pull request 'develop' (#16) from develop into master
Reviewed-on: #16
2025-08-12 14:58:18 -06:00
miguel d6f28003b3 Implement deleteAllCarrusel method to remove all images and database records from the carrusel 2025-08-12 14:56:34 -06:00
santiago 5c68472a85 Agregar funcionalidad para agregar almacenamiento en la base de cedetec de T&L 2025-07-30 14:16:14 -06:00
miguel a5da262469 Add Almacenamiento module, controller, service, and entity for data management 2025-07-28 21:52:03 -06:00
miguel 562642648d Merge branch 'develop' 2025-07-28 10:56:37 -06:00
miguel 0b591d51bd Refactor eventos controller to remove duplicate getEventosDisponibles method 2025-07-28 10:49:25 -06:00
stern f628d2a3b4 Modificación a script start en package.json para uso de Node 22 2025-05-14 11:41:55 -06:00
stern 71866ffe86 Merge branch 'develop' of https://repositorio.acatlan.unam.mx/CIDWA/cedetec_api_nest into develop 2025-05-14 11:39:47 -06:00
stern 2a33f20681 Modificación a script start en package.json para uso de Node 22 2025-05-14 11:39:04 -06:00
jalvarado 0b48fde321 Increase maximum link length validation to 150 characters in CarruselService 2025-05-14 11:39:02 -06:00
jalvarado ef643019bb Merge pull request 'ampliacion link' (#14) from master into develop
Reviewed-on: #14
2025-05-14 11:35:03 -06:00
jalvarado 47747c3bed ampliacion link 2025-05-14 11:33:45 -06:00
jalvarado 0eebc186b2 Merge pull request 'master' (#12) from master into develop
Reviewed-on: #12
2025-05-13 20:54:12 -06:00
jorgemike 6fe658f668 Refactor authentication and carousel services; enhance error handling and validation 2025-05-13 19:42:36 -06:00
jalvarado d6a63dae13 Merge pull request 'Merge pull request 'master' (#10) from master into develop' (#11) from develop into master
Reviewed-on: #11
2024-07-24 19:34:50 -06:00
mike f5ae636a7f Seguridaad 2024-07-24 14:34:01 -06:00
jalvarado d6d54d17f0 Merge pull request 'master' (#10) from master into develop
Reviewed-on: #10
2024-07-23 19:56:34 -06:00
mike ff158b0d32 CRUD de comentarios 2024-07-23 19:00:51 -06:00
Jorge Miguel Alvarado Reyes f924401e7b Observaciones 2024-01-17 16:37:40 -06:00
Jorge Miguel Alvarado Reyes 73ef0d982b Requisitos -> Obervaciones, longitud 60 -> 300 2024-01-17 16:35:20 -06:00
jalvarado 95b287292f Merge pull request 'develop' (#9) from develop into master
Reviewed-on: #9
2023-08-04 09:42:53 -06:00
jalvarado e4a56184d5 Carrusel envia mensaje de error enlugar de detener el servicio 2023-06-26 12:51:29 -06:00
JorgeMike e2afc63e28 Muchos cambios 2023-06-26 08:33:18 -06:00
JorgeMike 0a70bf2af2 Se puede agregar links al carrusel 2023-06-06 14:07:49 -06:00
jalvarado c80590b838 Merge pull request 'email' (#8) from email into develop
Reviewed-on: #8
2023-05-03 20:19:14 +00:00
jalvarado d237c594ca Merge branch 'email' of https://repositorio.acatlan.unam.mx/CIDWA/cedetec_api_nest into email 2023-05-03 13:53:03 -06:00
jalvarado 42652f4fc1 ya se ejecuta el query correcto 2023-05-03 13:52:09 -06:00
JorgeMike 537ef3484f .env removed 2023-03-27 09:24:45 -06:00
JorgeMike d07c4b4a41 the banner edit is ready and name of participant its getting update in eache event 2023-03-27 09:24:11 -06:00
JorgeMike 7a712928bd the banner edit is ready and name of participant its getting update in eache event 2023-03-26 19:16:06 -06:00
jalvarado e098a52fd8 envio de constancias pdf, se añadio banner 2023-03-24 15:00:03 -06:00
jalvarado 291a2ff75e deleted .env 2023-03-21 14:38:54 -06:00
jalvarado 34ecc34fbe se agrego el crear excels con los participantes 2023-03-21 14:36:38 -06:00
jalvarado 6d6eb825d2 El excel ya no se guarda en el servidor 2023-03-21 14:23:35 -06:00
JorgeMike 357121500b eliminacion de excel 2023-03-20 20:01:29 -06:00
JorgeMike 4d6435ac8a se agrego controller para traer solo eventos disponibles y no todos 2023-03-20 20:00:10 -06:00
jalvarado 569dbca11f se modifico la base de datos y se agrego los excel 2023-03-17 13:38:37 -06:00
jalvarado 89066bc769 removed .env original and added new variables 2023-03-14 15:56:05 -06:00
jalvarado 9d910e247c Merge branch 'develop' of https://repositorio.acatlan.unam.mx/CIDWA/cedetec_api_nest into develop 2023-03-14 15:52:20 -06:00
jalvarado d4b6655880 Merge branch 'email' into develop 2023-03-14 15:51:53 -06:00
jalvarado 4a69baa07e Actualizar '.env.example' 2023-03-14 21:46:05 +00:00
jalvarado 0158b6af98 add new info in env 2023-03-14 15:41:02 -06:00
jalvarado e29aacfc8f Actualizar '.env.example' 2023-03-14 21:38:33 +00:00
jalvarado 498e70e589 sending email is already in the project 2023-03-14 15:26:00 -06:00
jalvarado b8daadd0e3 eliminar el env 2023-03-10 10:01:24 -06:00
jalvarado 01e7bfd580 Merge branch 'develop' of https://repositorio.acatlan.unam.mx/CIDWA/cedetec_api_nest into develop 2023-03-10 10:00:15 -06:00
jalvarado a46ba72fe4 env example 2023-03-10 09:58:48 -06:00
jalvarado d277503ff9 Merge pull request 'cupo_evento' (#3) from cupo_evento into develop
Reviewed-on: #3
2023-03-10 15:56:55 +00:00
66 changed files with 7456 additions and 2728 deletions
-12
View File
@@ -1,12 +0,0 @@
PORT=5089
DB_HOST=132.248.180.82
DB_USER=user_cedetec
DB_PASSWORD=c3t3d3c
DB_NAME=Betelgeuse_Cedetec_Prueba
DB_PORT=
DB_HOST_DSC = 132.248.180.82
DB_USER_DSC = sites_user
DB_PASS_DSC = F0rTest
DB_NAME_DSC = sat
+20 -1
View File
@@ -8,4 +8,23 @@ DB_NAME=
DB_HOST_DSC= DB_HOST_DSC=
DB_USER_DSC= DB_USER_DSC=
DB_PASS_DSC= DB_PASS_DSC=
DB_NAME_DSC= DB_NAME_DSC=
NODEMAILER_SERVICE=
NODEMAILER_USER=
NODEMAILER_PASWORD=
#132.248.180.82
#3306
#usr_tl
#A1m_p@$
#Betelgeuse_TL_test
HOST_TYL=132.248.180.82
PORT_TYL=3306
USUARIO_TYL=usr_tl
CONTRASENA_TYL=A1m_p@$
DATABASE_TYL=Betelgeuse_TL_test
#Funciones para la api
API_URL=
TOKEN=
+1 -1
View File
@@ -1,3 +1,4 @@
.env
# compiled output # compiled output
/dist /dist
/node_modules /node_modules
@@ -34,4 +35,3 @@ lerna-debug.log*
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
.env
+6045 -2495
View File
File diff suppressed because it is too large Load Diff
+16 -3
View File
@@ -8,7 +8,7 @@
"scripts": { "scripts": {
"build": "nest build", "build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start", "start": "source ~/.nvm/nvm.sh && nvm use 22.10.0 && npm install && nest start",
"start:dev": "nest start --watch", "start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch", "start:debug": "nest start --debug --watch",
"start:prod": "node dist/main", "start:prod": "node dist/main",
@@ -26,24 +26,36 @@
"@nestjs/jwt": "^10.0.2", "@nestjs/jwt": "^10.0.2",
"@nestjs/passport": "^9.0.3", "@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^9.0.0",
"@nestjs/serve-static": "^3.0.1",
"@nestjs/swagger": "^6.2.1", "@nestjs/swagger": "^6.2.1",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^9.0.1",
"@types/multer": "^1.4.7",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"blob-stream": "^0.1.3",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"date-fns": "^2.30.0",
"exceljs": "^4.4.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"mysql2": "^3.1.2", "multer": "^1.4.5-lts.1",
"mysql2": "^3.14.3",
"nodemailer": "^6.9.1",
"passport": "^0.6.0", "passport": "^0.6.0",
"passport-jwt": "^4.0.1", "passport-jwt": "^4.0.1",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"pdf-lib": "^1.17.1",
"pdfkit": "^0.13.0",
"pg": "^8.9.0", "pg": "^8.9.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rxjs": "^7.2.0", "rxjs": "^7.2.0",
"swagger-ui-express": "^4.6.1", "swagger-ui-express": "^4.6.1",
"sybase": "^1.2.3", "sybase": "^1.2.3",
"typeorm": "^0.3.12" "typeorm": "^0.3.12",
"uuid": "^9.0.0",
"xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@jridgewell/sourcemap-codec": "^1.4.14",
"@nestjs/cli": "^9.0.0", "@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0", "@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0", "@nestjs/testing": "^9.0.0",
@@ -58,6 +70,7 @@
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"jest": "29.3.1", "jest": "29.3.1",
"pdfmake": "^0.2.7",
"prettier": "^2.3.2", "prettier": "^2.3.2",
"source-map-support": "^0.5.20", "source-map-support": "^0.5.20",
"supertest": "^6.1.3", "supertest": "^6.1.3",
View File
+1 -1
View File
@@ -1,2 +1,2 @@
INSERT INTO tipo_miembro(tipo_miembro) VALUES("Admin"); INSERT INTO tipo_miembro(tipo_miembro) VALUES("Admin");
INSERT INTO tipo_miembro(tipo_miembro) VALUES("Alumno"); INSERT INTO tipo_miembro(tipo_miembro) VALUES("Miembro");
+1 -1
View File
@@ -1,2 +1,2 @@
INSERT INTO miembro (nombre, apellido_paterno, apellido_materno, id_tipo_miembro, email, password, descripcion, semestre, cuenta) INSERT INTO miembro (nombre, apellido_paterno, apellido_materno, id_tipo_miembro, email, password, descripcion, semestre, cuenta)
VALUES ('Jorge', 'Alvarado', 'Reyes', 1, 'Admin@unam.com', '$2b$10$1ExBjP1J1PET5N4m9Thv7O0l0nNjPsMYQW6.TZveaCFz0OkLh06Dy', 'Estudiante de Ingeniería en Sistemas', '4', 421010301); VALUES ('Jorge', 'Alvarado', 'Reyes', 1, 'Admin@unam.com', '$2b$10$1ExBjP1J1PET5N4m9Thv7O0l0nNjPsMYQW6.TZveaCFz0OkLh06Dy', 'Estudiante de Ingeniería en Sistemas', '4', 123456789);
@@ -0,0 +1,18 @@
import { Controller, Post, Get, Body } from '@nestjs/common';
import { AlmacenamientoService } from './almacenamiento.service';
@Controller('almacenamiento')
export class AlmacenamientoController {
constructor(private readonly almacenamientoService: AlmacenamientoService) {}
@Post()
async create(@Body() body: { correo: string; agree: boolean }) {
return this.almacenamientoService.create(body.correo);
}
@Get()
async findAll() {
const data = await this.almacenamientoService.findAll();
return { message: 'GET endpoint reached', data };
}
}
@@ -0,0 +1,32 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Almacenamiento } from './entity/almacenamiento.entity';
import { AlmacenamientoService } from './almacenamiento.service';
import { AlmacenamientoController } from './almacenamiento.controller';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
TypeOrmModule.forRootAsync({
name: 'almacenamiento',
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
name: 'almacenamiento',
type: 'mariadb',
host: configService.get('HOST_TYL'),
port: Number(configService.get('PORT_TYL')),
username: configService.get('USUARIO_TYL'),
password: configService.get('CONTRASENA_TYL'),
database: configService.get('DATABASE_TYL'),
entities: [Almacenamiento],
synchronize: true,
ssl: false, // <- importante
}),
}),
TypeOrmModule.forFeature([Almacenamiento], 'almacenamiento'),
],
providers: [AlmacenamientoService],
controllers: [AlmacenamientoController],
})
export class AlmacenamientoModule {}
@@ -0,0 +1,33 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Almacenamiento } from './entity/almacenamiento.entity';
@Injectable()
export class AlmacenamientoService {
constructor(
@InjectRepository(Almacenamiento, 'almacenamiento')
private readonly almacenamientoRepository: Repository<Almacenamiento>,
) {}
// Example method to create a new record
async create(correo: string): Promise<any> {
console.log(correo)
const existente = await this.almacenamientoRepository.findOne({ where:{correo} });
console.log(existente)
if (!existente) {
// Maneja el error aquí mismo
throw new HttpException(
{ error: 'Este usuario no tiene acceso' },
HttpStatus.NOT_FOUND
);
}
return { mensaje: 'Usuario verificado correctamente' };
}
// Example method to get all records
async findAll(): Promise<Almacenamiento[]> {
return this.almacenamientoRepository.find();
}
}
@@ -0,0 +1,16 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity('almacenamiento')
export class Almacenamiento {
@PrimaryGeneratedColumn({ type: 'int', name: 'id_almacenamiento' })
idAlmacenamiento: number;
@Column('varchar', { name: 'correo', length: 100 })
correo: string;
@Column('timestamp', {
name: 'fecha_ampliacion',
})
fechaConsulta: Date;
}
+30 -6
View File
@@ -7,14 +7,12 @@ import { EventosModule } from './eventos/eventos.module';
import { ParticipanteController } from './participante/participante.controller'; import { ParticipanteController } from './participante/participante.controller';
import { ParticipanteModule } from './participante/participante.module'; import { ParticipanteModule } from './participante/participante.module';
import { EventoParticipanteModule } from './evento-participante/evento-participante/evento-participante.module'; import { EventoParticipanteModule } from './evento-participante/evento-participante/evento-participante.module';
import { UsuarioModule } from './usuario/usuario.module';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { PassportModule } from '@nestjs/passport'; import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { Evento } from './eventos/evento.entity'; import { Evento } from './eventos/evento.entity';
import { Participante } from './participante/participante.entity'; import { Participante } from './participante/participante.entity';
import { EventoParticipante } from './evento-participante/evento-participante/eventoParticipante.entity'; import { EventoParticipante } from './evento-participante/evento-participante/eventoParticipante.entity';
import { Usuario } from './usuario/usuario.entity';
import { InscripcionDscModule } from './inscripcion-dsc/inscripcion-dsc.module'; import { InscripcionDscModule } from './inscripcion-dsc/inscripcion-dsc.module';
import { InscripcionAreaModule } from './inscripcion-area/inscripcion-area.module'; import { InscripcionAreaModule } from './inscripcion-area/inscripcion-area.module';
import { InscripcionStatusService } from './inscripcion-status/inscripcion-status.service'; import { InscripcionStatusService } from './inscripcion-status/inscripcion-status.service';
@@ -44,9 +42,25 @@ import { Contacto } from './contacto/entity/contacto.entity';
import { Equipo } from './equipo/entity/equipo.entity'; import { Equipo } from './equipo/entity/equipo.entity';
import { EquipoEvento } from './equipo-evento/entity/equipo_evento.entity'; import { EquipoEvento } from './equipo-evento/entity/equipo_evento.entity';
import { EquipoMiembro } from './equipo-miembro/entity/equipo_miembro.entity'; import { EquipoMiembro } from './equipo-miembro/entity/equipo_miembro.entity';
import { EmailService } from './email/email.service';
import { EmailController } from './email/email.controller';
import { EmailModule } from './email/email.module';
import { MulterModule } from '@nestjs/platform-express';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { CarruselModule } from './carrusel/carrusel.module';
import { Carrusel } from './carrusel/entity/carrusel.entity';
import { ComentariosModule } from './comentarios/comentarios.module';
import { Comentarios } from './comentarios/entity/comentarios.entity';
import { AlmacenamientoModule } from './almacenamiento/almacenamiento.module';
import { Almacenamiento } from './almacenamiento/entity/almacenamiento.entity';
@Module({ @Module({
imports: [ imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public'),
exclude: ['/api*'], // Excluir la ruta "/api" de servir archivos estáticos
}),
ConfigModule.forRoot({ ConfigModule.forRoot({
envFilePath: '.env', envFilePath: '.env',
isGlobal: true, isGlobal: true,
@@ -61,11 +75,11 @@ import { EquipoMiembro } from './equipo-miembro/entity/equipo_miembro.entity';
username: configService.get('DB_USER'), username: configService.get('DB_USER'),
password: configService.get('DB_PASSWORD'), password: configService.get('DB_PASSWORD'),
database: configService.get('DB_NAME'), database: configService.get('DB_NAME'),
synchronize: true,
entities: [ entities: [
Evento, Evento,
Participante, Participante,
EventoParticipante, EventoParticipante,
Usuario,
/* Agregadas el 29 de febrero */ /* Agregadas el 29 de febrero */
Miembro, Miembro,
InscripcionArea, InscripcionArea,
@@ -84,14 +98,16 @@ import { EquipoMiembro } from './equipo-miembro/entity/equipo_miembro.entity';
Equipo, Equipo,
EquipoEvento, EquipoEvento,
EquipoMiembro, EquipoMiembro,
/* Agregado el 2 de junio */
Carrusel,
/* No recuerdo porque empece a ponerle fechas */
Comentarios,
], ],
synchronize: true,
}), }),
}), }),
EventosModule, EventosModule,
ParticipanteModule, ParticipanteModule,
EventoParticipanteModule, EventoParticipanteModule,
UsuarioModule,
AuthModule, AuthModule,
PassportModule, PassportModule,
JwtModule.register({}), JwtModule.register({}),
@@ -106,10 +122,17 @@ import { EquipoMiembro } from './equipo-miembro/entity/equipo_miembro.entity';
ProyectoModule, ProyectoModule,
ProyectoActividadModule, ProyectoActividadModule,
ActividadModule, ActividadModule,
EmailModule,
ComentariosModule,
MulterModule.register({
dest: './uploads', // directorio de destino para guardar los archivos cargados
}),
CarruselModule,
ComentariosModule,
AlmacenamientoModule,
], ],
controllers: [ controllers: [
AppController, AppController,
ParticipanteController,
InscripcionStatusController, InscripcionStatusController,
], ],
providers: [AppService, InscripcionStatusService], providers: [AppService, InscripcionStatusService],
@@ -117,6 +140,7 @@ import { EquipoMiembro } from './equipo-miembro/entity/equipo_miembro.entity';
export class AppModule { export class AppModule {
static port: number; static port: number;
constructor(private readonly configService: ConfigService) { constructor(private readonly configService: ConfigService) {
console.log('PORT', this.configService.get('PORT'));
AppModule.port = this.configService.get('PORT'); AppModule.port = this.configService.get('PORT');
} }
} }
+14 -8
View File
@@ -1,26 +1,32 @@
import { Body, Controller, Post, Request, UseGuards } from '@nestjs/common'; import { Body, Controller, Param, Post } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { Usuario } from 'src/usuario/usuario.entity';
import { Repository } from 'typeorm';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { LoginUsuarioDto } from './dto/loginUsuario.dto'; import { LoginMiembroDto } from './dto/loginMiembro.dto';
import { RegistrarMiembroDto } from './dto/registrarMiembro.dto'; import { RegistrarMiembroDto } from './dto/registrarMiembro.dto';
import { RegistrarUsuarioDto } from './dto/registrarUsuario.dto'; import { ApiTags } from '@nestjs/swagger';
import { ApiPostRegistro } from './auth.docs';
import { jwtStrategy } from './jwt.strategy';
@Controller('auth') @Controller('auth')
@ApiTags('auth')
export class AuthController { export class AuthController {
constructor( constructor(
private authService: AuthService, private authService: AuthService,
private authValidar: jwtStrategy,
) /* @InjectRepository(Usuario) private usuarioRepository: Repository<Usuario> */ {} ) /* @InjectRepository(Usuario) private usuarioRepository: Repository<Usuario> */ {}
@Post('registro') @Post('registro')
@ApiPostRegistro()
registrarUsuario(@Body() registrarMiembro: RegistrarMiembroDto) { registrarUsuario(@Body() registrarMiembro: RegistrarMiembroDto) {
return this.authService.registrar(registrarMiembro); return this.authService.registrar(registrarMiembro);
} }
@Post('login') @Post('login')
login(@Body() LoginUsuario: LoginUsuarioDto) { login(@Body() LoginUsuario: LoginMiembroDto) {
return this.authService.login(LoginUsuario); return this.authService.login(LoginUsuario);
} }
@Post('validate')
validar(@Param() token: any) {
return this.authValidar.validate
}
} }
+78
View File
@@ -0,0 +1,78 @@
import { applyDecorators } from '@nestjs/common';
import {
ApiOperation,
ApiResponse,
ApiTags,
ApiBody,
} from '@nestjs/swagger';
import { RegistrarMiembroDto } from './dto/registrarMiembro.dto';
export function ApiPostRegistro() {
return applyDecorators(
ApiTags('Auth'),
ApiOperation({
summary: 'Registrar nuevo miembro',
description:
'Registra un nuevo usuario en la plataforma. No se permite duplicidad de correo electrónico.',
}),
ApiBody({
type: RegistrarMiembroDto,
examples: {
requeridos: {
summary: 'Solo datos obligatorios',
description: 'Ejemplo básico con los campos mínimos requeridos para registrar un usuario.',
value: {
nombre: 'Luis',
apellido_paterno: 'Martínez',
apellido_materno: 'Lopez',
id_tipo_miembro: 1,
password: 'contraseñaSegura123',
cuenta: 421010101,
email: 'luis@example.com',
},
},
completo: {
summary: 'Todos los campos llenos',
description: 'Ejemplo de un usuario con carrera, semestre y descripción.',
value: {
nombre: 'Ana',
apellido_paterno: 'Torres',
apellido_materno: 'Hernández',
id_tipo_miembro: 2,
password: 'AnaSegura456',
descripcion: 'Estudiante interesada en programación web',
id_carrera: 3,
semestre: '4°',
cuenta: 421020202,
email: 'ana.torres@example.com',
},
},
invalido: {
summary: 'Ejemplo con datos inválidos',
description: 'Muestra un correo mal formado y una contraseña demasiado corta.',
value: {
nombre: 'Mario',
apellido_paterno: 'Gómez',
apellido_materno: 'Ramírez',
id_tipo_miembro: 1,
password: '123',
cuenta: 421000000,
email: 'mario-sin-arroba.com',
},
},
},
}),
ApiResponse({
status: 201,
description: 'Usuario registrado exitosamente.',
}),
ApiResponse({
status: 403,
description: 'El usuario ya existe.',
}),
ApiResponse({
status: 400,
description: 'Datos inválidos o faltantes.',
}),
);
}
+5 -3
View File
@@ -54,9 +54,11 @@ export class AuthService {
/* console.log(token); */ /* console.log(token); */
const data = { const data = {
usuario: usuario.nombre, user: {
id: usuario.id_miembro, usuario: usuario.nombre,
email: usuario.email, id: usuario.id_miembro,
email: usuario.email,
},
token, token,
}; };
+1 -1
View File
@@ -5,7 +5,7 @@ export class LoginMiembroDto {
@IsEmail() @IsEmail()
email: string email: string
@MinLength(10) @MinLength(5)
@MaxLength(15) @MaxLength(15)
password: string password: string
} }
-10
View File
@@ -1,10 +0,0 @@
import { IsEmail, MaxLength, MinLength } from "class-validator";
export class LoginUsuarioDto {
@IsEmail()
email: string
@MinLength(10)
@MaxLength(15)
password: string
}
+2 -2
View File
@@ -1,8 +1,8 @@
import { PartialType } from '@nestjs/swagger'; import { PartialType } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator'; import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator';
import { LoginUsuarioDto } from './loginUsuario.dto'; import { LoginMiembroDto } from './loginMiembro.dto';
export class RegistrarMiembroDto extends PartialType(LoginUsuarioDto) { export class RegistrarMiembroDto extends PartialType(LoginMiembroDto) {
@IsNotEmpty() @IsNotEmpty()
nombre: string; nombre: string;
-18
View File
@@ -1,18 +0,0 @@
import { PartialType } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, MaxLength, MinLength } from 'class-validator';
import { LoginUsuarioDto } from './loginUsuario.dto';
export class RegistrarUsuarioDto extends PartialType(LoginUsuarioDto) {
@IsNotEmpty()
name: string;
@IsNotEmpty()
lastName: string;
@IsEmail()
email: string;
@MinLength(10)
@MaxLength(15)
password: string;
}
+80
View File
@@ -0,0 +1,80 @@
import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Patch,
Post,
Put,
Res,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { CarruselService } from './carrusel.service';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { actualizarContador, contador } from './utils';
import * as path from 'path';
import { carruselDto } from './dto/carruselDto.dto';
@Controller('carrusel')
export class CarruselController {
constructor(private carruselService: CarruselService) {}
@Post('addImage')
@UseInterceptors(
FileInterceptor('imagen', {
storage: diskStorage({
destination: './public/carrusel',
filename: function (req, file, cb) {
actualizarContador();
const { ext } = path.parse(file.originalname);
const filename = `carrusel${contador}${ext}`;
return cb(null, filename);
},
}),
fileFilter: function (req, file, cb) {
if (!file.originalname.match(/\.(jpg|jpeg|png|webp)$/)) {
return {
message:
'Lo sentimos los archivos permitidos para usar el carrusel son jpg jpeg png webp',
};
}
cb(null, true);
},
}),
)
addImagenToCarrusel(@Body() carruselDto: carruselDto, @UploadedFile() file) {
return this.carruselService.addImagenToCarrusel(carruselDto, file.filename);
}
@Patch('update/:id')
updateImagenCarrusel(
@Param('id', ParseIntPipe) id: number,
@Body() carruselDto: carruselDto,
) {
return this.carruselService.updateImagenCarrusel(id, carruselDto);
}
@Put('updateOrden')
async updateOrden(@Body() banners: { id: number; orden: number}[]) {
return this.carruselService.updateOrden(banners);
}
@Delete('delete/:id')
deleteImagenByRuta(@Param('id', ParseIntPipe) id: number) {
return this.carruselService.deleteImagenByRuta(id);
}
@Get('imagenes')
getAllImagenes() {
return this.carruselService.getAllImages();
}
@Delete('deleteAll')
deleteAllCarrusel() {
return this.carruselService.deleteAllCarrusel();
}
}
+12
View File
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { CarruselController } from './carrusel.controller';
import { CarruselService } from './carrusel.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Carrusel } from 'src/carrusel/entity/carrusel.entity';
@Module({
imports: [TypeOrmModule.forFeature([Carrusel])],
controllers: [CarruselController],
providers: [CarruselService],
})
export class CarruselModule {}
+179
View File
@@ -0,0 +1,179 @@
import {
BadRequestException,
Injectable,
InternalServerErrorException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Carrusel } from 'src/carrusel/entity/carrusel.entity';
import { Repository } from 'typeorm';
import { carruselDto } from './dto/carruselDto.dto';
import * as fs from 'fs';
import * as path from 'path';
@Injectable()
export class CarruselService {
constructor(
@InjectRepository(Carrusel)
private carruselRepository: Repository<Carrusel>,
) {}
async addImagenToCarrusel(
carruselDto: carruselDto,
filename: string,
): Promise<{ message: string; carrusel: Carrusel }> {
if (!filename) {
throw new BadRequestException({
message: 'No se ha subido la imagen',
});
}
if (!carruselDto.link) {
throw new BadRequestException({
message: 'El campo "link" es obligatorio',
});
}
if (carruselDto.link.length > 150) {
throw new BadRequestException({
message: 'El campo "link" no puede tener más de 100 caracteres',
});
}
carruselDto.ruta = `/public/carrusel/${filename}`;
const carruselCreate = this.carruselRepository.create(carruselDto);
try {
const carrusel = await this.carruselRepository.save(carruselCreate);
return {
message: 'Imagen agregada correctamente',
carrusel,
};
} catch (error) {
console.error('❌ Error al guardar carrusel en base de datos');
console.table({
code: error.code,
message: error.message,
});
throw new InternalServerErrorException({
message: 'Ocurrió un error inesperado al guardar la imagen',
error: error.message,
});
}
}
async updateImagenCarrusel(
id: number,
carruselDto: carruselDto,
): Promise<{ message: string; carrusel: Carrusel }> {
const carrusel = await this.carruselRepository.findOne({
where: { id_imagen_carrusel: id },
});
if (!carrusel) {
throw new BadRequestException({
message: `No se encontró una imagen de carrusel con el id ${id}`,
});
}
Object.assign(carrusel, carruselDto);
try {
const carruselUpdated = await this.carruselRepository.save(carrusel);
return {
message: 'Imagen de carrusel actualizada correctamente',
carrusel: carruselUpdated,
};
} catch (error) {
console.error('❌ Error al actualizar carrusel en base de datos');
console.table({
code: error.code,
message: error.message,
});
throw new InternalServerErrorException({
message: 'Ocurrió un error inesperado al actualizar la imagen',
error: error.message,
});
}
}
// Actualizar todas las imagenes por orden
async updateOrden(banners: { id: number; orden: number}[]) {
for (const banner of banners ) {
await this.carruselRepository.update(
{ id_imagen_carrusel: banner.id },
{ orden: banner.orden },
)
}
return {
message: 'Orden actualizado correctamente',
}
}
async deleteImagenByRuta(id: number) {
try {
const res = await this.carruselRepository.findOne({
where: { id_imagen_carrusel: id },
});
await fs.promises.unlink(`./${res.ruta}`);
return this.carruselRepository.delete({ id_imagen_carrusel: id });
} catch (error) {
console.error('Error:', error);
throw error;
}
}
getAllImages(): Promise<Carrusel[]> {
// return this.carruselRepository.find();
return this.carruselRepository.find({
order: {
orden: 'ASC',
},
});
// return this.carruselRepository.find();
}
async deleteAllCarrusel(): Promise<{ message: string }> {
try {
// Obtener todas las imágenes del carrusel
const images = await this.carruselRepository.find();
// Eliminar archivos físicos de la carpeta public/carrusel
const carruselDir = './public/carrusel';
if (fs.existsSync(carruselDir)) {
// Leer todos los archivos en el directorio
const files = await fs.promises.readdir(carruselDir);
// Eliminar cada archivo
for (const file of files) {
const filePath = path.join(carruselDir, file);
try {
await fs.promises.unlink(filePath);
console.log(`✅ Archivo eliminado: ${filePath}`);
} catch (fileError) {
console.warn(
`⚠️ No se pudo eliminar el archivo: ${filePath}`,
fileError.message,
);
}
}
}
// Eliminar todos los registros de la base de datos
await this.carruselRepository.delete({});
return {
message: `Carrusel limpiado exitosamente. Se eliminaron ${images.length} imágenes y registros.`,
};
} catch (error) {
console.error('❌ Error al limpiar el carrusel:', error);
throw new InternalServerErrorException({
message: 'Ocurrió un error inesperado al limpiar el carrusel',
error: error.message,
});
}
}
}
+13
View File
@@ -0,0 +1,13 @@
import { IsNotEmpty, IsOptional, IsNumber } from "class-validator";
export class carruselDto {
@IsNotEmpty()
ruta: string
@IsNotEmpty()
link: string
@IsOptional()
@IsNumber()
orden?: number
}
+18
View File
@@ -0,0 +1,18 @@
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class Carrusel {
@PrimaryGeneratedColumn()
id_imagen_carrusel: number
@Column({length: 40})
ruta: string
/* "/public/carrusel/carrusel1.jpg" */
@Column({length: 150})
link: string
/* "https://www.acatlan.unam.mx/" */
@Column({ type: 'int', default: 0 })
orden: number
}
+5
View File
@@ -0,0 +1,5 @@
export let contador = 0
export const actualizarContador = () => {
contador++
}
+1 -1
View File
@@ -6,7 +6,7 @@ export class Area {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_area: number id_area: number
@Column({length:60, nullable:false}) @Column({length:20, nullable:false})
area: string area: string
@OneToMany( @OneToMany(
+1 -1
View File
@@ -6,7 +6,7 @@ export class Carrera {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_carrera: number id_carrera: number
@Column({ length:70, nullable: false}) @Column({ length:40, nullable: false})
carrera: string carrera: string
@OneToMany( @OneToMany(
+1 -1
View File
@@ -6,7 +6,7 @@ export class TipoMiembro {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_tipo_miembro: number id_tipo_miembro: number
@Column({length:60, nullable:false}) @Column({length:15, nullable:false})
tipo_miembro: string tipo_miembro: string
@OneToMany( @OneToMany(
+4
View File
@@ -0,0 +1,4 @@
export class ComentarioDto {
from: string;
comentario: string;
}
+43
View File
@@ -0,0 +1,43 @@
import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Post,
Query,
} from '@nestjs/common';
import { ComentariosService } from './comentarios.service';
import { ComentarioDto } from './comentario.dto';
@Controller('comentarios')
export class ComentariosController {
constructor(private comentariosService: ComentariosService) {}
@Post()
postComentario(@Body() comentario: ComentarioDto) {
return this.comentariosService.postComentario(comentario);
}
@Get()
getComentarios() {
return this.comentariosService.getComentarios();
}
@Get('by-date')
getComentariosByDate(
@Query('before') before?: string,
@Query('after') after?: string,
@Query('from') from?: string,
@Query('to') to?: string,
) {
return this.comentariosService.getComentariosByDate(before, after, from, to);
}
@Delete(':id')
deleteComentario(@Param('id', ParseIntPipe) id: number) {
return this.comentariosService.deleteComentario(id);
}
}
+12
View File
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { ComentariosController } from './comentarios.controller';
import { ComentariosService } from './comentarios.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Comentarios } from './entity/comentarios.entity';
@Module({
imports: [TypeOrmModule.forFeature([Comentarios])],
controllers: [ComentariosController],
providers: [ComentariosService],
})
export class ComentariosModule {}
+66
View File
@@ -0,0 +1,66 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Comentarios } from './entity/comentarios.entity';
import { Repository } from 'typeorm';
import { ComentarioDto } from './comentario.dto';
@Injectable()
export class ComentariosService {
constructor(
@InjectRepository(Comentarios)
private comentariosRepository: Repository<Comentarios>,
) {}
postComentario(comentario: ComentarioDto) {
if (comentario.from !== 'CEDETEC' && comentario.from !== 'PCPUMA') {
throw new BadRequestException('Mensaje no autorizado');
}
const nuevoComentario = this.comentariosRepository.create(comentario);
return this.comentariosRepository.save(nuevoComentario);
}
getComentarios() {
return this.comentariosRepository.find();
}
async getComentariosByDate(
before?: string,
after?: string,
from?: string,
to?: string,
) {
const query = this.comentariosRepository.createQueryBuilder('comentarios');
if (before) {
query.andWhere('comentarios.fecha_registro < :before', {
before: new Date(before),
});
}
if (after) {
query.andWhere('comentarios.fecha_registro > :after', {
after: new Date(after),
});
}
if (from) {
query.andWhere('comentarios.fecha_registro >= :from', {
from: new Date(from),
});
}
if (to) {
query.andWhere('comentarios.fecha_registro <= :to', { to: new Date(to) });
}
query.orderBy('comentarios.fecha_registro', 'DESC');
return await query.getMany();
}
deleteComentario(id: number) {
return this.comentariosRepository.delete({ id_comentario: id });
}
}
@@ -0,0 +1,16 @@
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';
@Entity()
export class Comentarios {
@PrimaryGeneratedColumn()
id_comentario: number;
@Column()
from: string;
@Column()
comentario: string;
@CreateDateColumn({ type: 'timestamp' })
fecha_registro: Date;
}
+3 -3
View File
@@ -10,13 +10,13 @@ export class Contacto {
@Column({nullable:false}) @Column({nullable:false})
email: string email: string
@Column() @Column({length: 40})
horario: string horario: string
@Column({nullable:true}) @Column({length: 75, nullable:true})
facebook: string facebook: string
@Column({nullable: true}) @Column({length: 60, nullable: true})
linkedin: string linkedin: string
@ManyToOne( @ManyToOne(
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
import { IsEmail } from "class-validator"
export class EmailDto {
subject:string
text:string
}
+9
View File
@@ -0,0 +1,9 @@
interface Row {
Asistencia: number
Nombre: string
'Apellido Paterno': string
'Apellido Materno': string
Carrera: string
'Institución Procedencia': string
Email: string
}
+18
View File
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { EmailController } from './email.controller';
describe('EmailController', () => {
let controller: EmailController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [EmailController],
}).compile();
controller = module.get<EmailController>(EmailController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
+65
View File
@@ -0,0 +1,65 @@
import {
Body,
Controller,
Get,
HttpException,
HttpStatus,
Param,
ParseIntPipe,
Post,
Res,
UploadedFile,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { EmailDto } from './dto/emailDto.dto';
import { EmailService } from './email.service';
import { Response } from 'express';
import * as xlsx from 'xlsx';
import { AuthGuard } from '@nestjs/passport';
@Controller('email')
export class EmailController {
constructor(private readonly emailService: EmailService) { }
@UseGuards(AuthGuard('jwt'))
@Post('/evento/:id')
async sendEmail(
@Param('id', ParseIntPipe) id: number,
@Body() emailDto: EmailDto,
@Res() res,
): Promise<any> {
return this.emailService.sendEmail(id, emailDto, res);
}
@UseGuards(AuthGuard('jwt'))
@Post('constancias/:id')
@UseInterceptors(FileInterceptor('file'))
async sendConstancias(
@UploadedFile() file,
@Param('id', ParseIntPipe) id: number,
@Res() res,
) {
if (!file) {
throw new HttpException(
'No se ha cargado ningun archivo',
HttpStatus.BAD_REQUEST,
);
}
return this.emailService.sendConstancias(file, id, res);
}
//@UseGuards(AuthGuard('jwt'))
@Get(':id/participantes/xlsx')
async descargarExcel(
@Param('id') idEvento: number,
@Res() res: Response,
) {
console.log('entro en el controller')
return this.emailService.getParticipantesExcel(idEvento, res);
}
}
+16
View File
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { EventosModule } from 'src/eventos/eventos.module';
import { Participante } from 'src/participante/participante.entity';
import { EmailController } from './email.controller';
import { EmailService } from './email.service';
import { EventosService } from 'src/eventos/eventos.service';
import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity';
import { Evento } from 'src/eventos/evento.entity';
@Module({
imports:[TypeOrmModule.forFeature([Participante, EventoParticipante, Evento])],
controllers:[EmailController],
providers:[EmailService, EventosService]
})
export class EmailModule {}
+18
View File
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { EmailService } from './email.service';
describe('EmailService', () => {
let service: EmailService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [EmailService],
}).compile();
service = module.get<EmailService>(EmailService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
+239
View File
@@ -0,0 +1,239 @@
import {
HttpException,
HttpStatus,
Inject,
Injectable,
Res,
UploadedFile,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import * as nodemailer from 'nodemailer';
import { EventosService } from 'src/eventos/eventos.service';
import { Participante } from 'src/participante/participante.entity';
import { Repository } from 'typeorm';
import { EmailDto } from './dto/emailDto.dto';
import * as xlsx from 'xlsx';
import * as pdfMake from 'pdfmake/build/pdfmake';
import * as pdfFonts from 'pdfmake/build/vfs_fonts';
/* import * as PDFDocument from 'pdfkit'; */
import * as fs from 'fs';
import * as path from 'path';
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
import { Response } from 'express';
import { format } from 'date-fns';
import * as ExcelJS from 'exceljs';
@Injectable()
export class EmailService {
private transporter;
constructor(
@InjectRepository(Participante)
private participanteRepository: Repository<Participante>,
private configService: ConfigService,
private readonly eventoService: EventosService,
) {
this.transporter = nodemailer.createTransport({
service: this.configService.get('NODEMAILER_SERVICE'),
auth: {
user: this.configService.get<string>('NODEMAILER_USER'),
pass: this.configService.get<string>('NODEMAILER_PASWORD'),
},
});
}
async sendEmail(id: number, message: EmailDto, res: Response) {
const participantes = await this.getEmailDeParticipantes(id);
participantes.map((res) => {
const emailDestinatario = res.email;
this.transporter.sendMail({
to: emailDestinatario,
subject: message.subject,
text: message.text,
});
});
return res.status(201).json({ message: 'Correos enviados con exito' });
}
async getEmailDeParticipantes(idEvento: number) {
const participantes = await this.participanteRepository
.createQueryBuilder('participante')
.innerJoin('participante.eventosParticipante', 'eventoParticipante')
.innerJoin('eventoParticipante.evento', 'evento')
.where('evento.id_evento = :idEvento', { idEvento })
.select(['participante.email'])
.getMany();
return participantes;
}
async getParticipantesExcel(idEvento: number, res: Response) {
console.log('entro a la funcion')
const participantes = await this.participanteRepository
.createQueryBuilder('participante')
.innerJoin('participante.eventosParticipante', 'eventoParticipante')
.innerJoin('eventoParticipante.evento', 'evento')
.where('evento.id_evento = :idEvento', { idEvento })
.select(['participante'])
.getMany();
// 1. Crear workbook y worksheet
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Participantes');
// 2. Definir encabezados
worksheet.columns = [
{ header: 'ID', key: 'id', width: 10 },
{ header: 'Nombre', key: 'nombre', width: 30 },
{ header: 'Correo', key: 'correo', width: 30 },
{ header: 'Teléfono', key: 'telefono', width: 20 },
{ header: 'Carrera', key: 'carrera', width: 20 },
{ header: 'Institución', key: 'institucion_procedencia', width: 30 },
{ header: 'Apellido Paterno', key: 'apellido_paterno', width: 20 },
{ header: 'Apellido Materno', key: 'apellido_materno', width: 20 },
];
console.log(participantes);
// 3. Insertar datos
participantes.forEach((p) => {
worksheet.addRow({
nombre: p.nombre,
apellido_paterno: p.apellido_paterno,
apellido_materno: p.apellido_materno,
carrera: p.carrera,
institucion_procedencia: p.institucion_procedencia,
correo: p.email,
telefono: p.telefono,
});
});
// 4. Preparar la respuesta HTTP para enviar el Excel
res.setHeader(
'Content-Type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
);
res.setHeader(
'Content-Disposition',
'attachment; filename=participantes.xlsx',
);
await workbook.xlsx.write(res);
res.end();
}
async sendConstancias(file, id_evento, res: Response) {
//traemos la info del evento
const evento = await this.eventoService.getEventosPorId(id_evento);
const workbook = xlsx.read(file.buffer);
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const data = xlsx.utils.sheet_to_json(worksheet);
// Carga el PDF pre-diseñado
const existingPdfBytes = fs.readFileSync('src/email/DisenoConstancia.pdf');
for (let i = 0; i < data.length; i++) {
const row = data[i] as Row;
if(row.Email == undefined){
return res.status(400).json({ message: `El correo del renglon ${ i + 2} puede estar vacio o ser undefined`, solucion: `Seleccione el renglon donde ocurre el problema y borre todo lo de este renglon, Aunque parezca que el renglon esta vacio puede que haya un espacio en algun campo y esto genera que el sistema haga la lectura de este renglon`});
}
// Carga el PDF pre-diseñado en un documento PDF editable
const pdfDoc = await PDFDocument.load(existingPdfBytes);
const pagina = pdfDoc.getPages();
const primeraPagina = pagina[0];
// Obtén el ancho y alto de la página
const { width, height } = primeraPagina.getSize();
// Obtén la fuente del texto
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
// Configura el tamaño del texto
const fontSize = 26;
const nombreParticipante = `${row['Apellido Paterno']} ${row['Apellido Materno']} ${row.Nombre}`;
// Calcula la anchura del texto del nombre del participante
const textWidth = font.widthOfTextAtSize(nombreParticipante, fontSize);
const centerX = (width - textWidth) / 2;
const centerY = (height - fontSize) / 2;
// Dibuja el texto centrado en la página
primeraPagina.drawText(nombreParticipante, {
x: centerX,
y: centerY + 70,
size: fontSize,
color: rgb(0, 0, 0),
});
const nombreCurso = `${evento.nombre}`;
// Calcula la anchura del texto del nombre del evento
const nombreCursoWidth = font.widthOfTextAtSize(nombreCurso, fontSize);
const centerXNombreCurso = (width - nombreCursoWidth) / 2;
const centerYNombreCurso = (height - fontSize) / 2;
primeraPagina.drawText(nombreCurso, {
x: centerXNombreCurso,
y: centerYNombreCurso - 17,
size: fontSize,
color: rgb(0, 0, 0),
});
const fechaCurso = `del ${this.formatoFecha(
evento.fecha_inicio,
)} al ${this.formatoFecha(evento.fecha_fin)}`;
// Calcula la anchura del texto del nombre del participante
const fechaCursoWidth = font.widthOfTextAtSize(fechaCurso, 20);
const centerXFechaCurso = (width - fechaCursoWidth) / 2;
const centerYFechaCurso = (height - 20) / 2;
primeraPagina.drawText(fechaCurso, {
x: centerXFechaCurso,
y: centerYFechaCurso - 55,
size: 20,
color: rgb(0, 0, 0),
});
// Guarda el PDF modificado en forma de bytes
const pdfBytes = await pdfDoc.save();
// Crea el objeto de adjunto con el nombre y contenido del PDF
const attachment = {
filename: `Constancia ${evento.nombre} - ${row.Nombre}_${row['Apellido Paterno']}.pdf`,
content: pdfBytes,
};
// Crea el objeto Blob y la URL para el PDF
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
// Envía el correo electrónico con la constancia adjunta
this.transporter.sendMail({
to: row.Email,
subject: `Constancia de asistencia a "${evento.nombre}"`,
text: `¡Un saludo ${row.Nombre}! Aquí está tu constancia de asistencia por el evento "${evento.nombre}". Agradecemos tu asistencia y constancia, esperamos seguir viéndote en eventos futuros.`,
attachments: [attachment],
});
}
return res.status(200).json({ message: 'Constancias enviadas con éxito' });
}
formatoFecha(fecha: Date) {
const fechaLimpia = format(fecha, 'dd/MM/yyyy');
return fechaLimpia;
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ export class Equipo{
@Column({length:50, nullable:true}) @Column({length:50, nullable:true})
nombre: string nombre: string
@Column({length:250}) @Column({length:100})
descripcion:string descripcion:string
@OneToMany( @OneToMany(
@@ -17,6 +17,11 @@ export class RegistrarParticipanteDto {
@IsNotEmpty() @IsNotEmpty()
carrera: string; carrera: string;
@IsString()
@IsNotEmpty()
institucion_procedencia: string;
@IsEmail() @IsEmail()
email: string; email: string;
} }
@@ -1,4 +1,4 @@
import { Body, Controller, Param, ParseIntPipe, Post } from '@nestjs/common'; import { Body, Controller, Get, Param, ParseIntPipe, Post } from '@nestjs/common';
import { RegistrarParticipanteDto } from './dto/registrarParticipanteDto.dto'; import { RegistrarParticipanteDto } from './dto/registrarParticipanteDto.dto';
import { EventoParticipanteService } from './evento-participante.service'; import { EventoParticipanteService } from './evento-participante.service';
import { EventoParticipante } from './eventoParticipante.entity'; import { EventoParticipante } from './eventoParticipante.entity';
@@ -12,5 +12,8 @@ export class EventoParticipanteController {
return this.eventoParticipanteService.registrarParticipante(id, datos) return this.eventoParticipanteService.registrarParticipante(id, datos)
} }
@Get()
getEventoParticipante(): Promise<EventoParticipante[]> {
return this.eventoParticipanteService.getEventoParticipantes();
}
} }
@@ -46,12 +46,25 @@ export class EventoParticipanteService {
id_evento: number, id_evento: number,
registrarParticipanteDto: RegistrarParticipanteDto, registrarParticipanteDto: RegistrarParticipanteDto,
) { ) {
/* console.log(id_evento);
console.log(registrarParticipanteDto); */
return this.participanteExiste(registrarParticipanteDto.email).then( return this.participanteExiste(registrarParticipanteDto.email).then(
(res) => { (res) => {
if (res) { if (res) {
this.registrarEnEvento(id_evento, res);
res.nombre = registrarParticipanteDto.nombre;
res.apellido_paterno = registrarParticipanteDto.apellido_paterno;
res.apellido_materno = registrarParticipanteDto.apellido_materno;
res.carrera = registrarParticipanteDto.carrera;
res.institucion_procedencia =
registrarParticipanteDto.institucion_procedencia;
//si el correo ya existe en la base de datos solo se le cambia el nombre, apellidos, carrera e institucion
return this.participanteRepository
.save(res)
.then((participanteActualizado) => {
this.registrarEnEvento(id_evento, participanteActualizado);
return participanteActualizado;
});
} else { } else {
this.participanteRepository this.participanteRepository
.save(this.participanteRepository.create(registrarParticipanteDto)) .save(this.participanteRepository.create(registrarParticipanteDto))
@@ -62,4 +75,8 @@ export class EventoParticipanteService {
}, },
); );
} }
getEventoParticipantes() {
return this.eventoParticipanteRepository.find()
}
} }
+4 -4
View File
@@ -1,11 +1,11 @@
export class actualizarEventoDto { export class actualizarEventoDto {
nombre?: string; nombre?: string;
tipo_evento?: string; tipo_evento?: string;
organizadores?: string[]; organizadores?: string;
proyecto?: string[]; proyecto?: string;
modalidad?: string[]; modalidad?: string;
lugar?: string; lugar?: string;
requisitos?: string; observaciones?: string;
cuota_inscripcion?: number; cuota_inscripcion?: number;
patrocinador?: string; patrocinador?: string;
tipo_acreditacion?: string; tipo_acreditacion?: string;
+5 -5
View File
@@ -1,16 +1,16 @@
export class crearEventoDto { export class crearEventoDto {
nombre: string; nombre: string;
tipo_evento: string; tipo_evento: string;
organizadores: string[]; organizadores: string;
proyecto: string[]; proyecto: string;
modalidad: string[]; modalidad: string;
lugar: string; lugar: string;
cupo: number; cupo: number;
requisitos: string; observaciones: string;
cuota_inscripcion: number; cuota_inscripcion: number;
patrocinador: string; patrocinador: string;
tipo_acreditacion: string; tipo_acreditacion: string;
descripcion: string; objetivo: string;
fecha_inicio: Date; fecha_inicio: Date;
fecha_fin: Date; fecha_fin: Date;
fecha_limite_inscripcion: Date; fecha_limite_inscripcion: Date;
+25 -31
View File
@@ -14,55 +14,52 @@ export class Evento {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_evento: number; id_evento: number;
@Column({ nullable: false }) @Column({ length: 70, nullable: false })
nombre: string; nombre: string;
@Column({ nullable: false }) @Column({ length: 15, nullable: false })
tipo_evento: string; tipo_evento: string;
@Column("simple-array", {nullable: false}) @Column({ length: 100, nullable: false })
organizadores: string[] organizadores: string;
@Column("simple-array", {nullable: false}) @Column({ length: 30, nullable: true })
proyecto: string[] proyecto: string;
@Column("simple-array", {nullable: false}) @Column({ length: 40, nullable: false })
modalidad: string[] modalidad: string;
@Column({ nullable: false }) @Column({ length: 60, nullable: false })
lugar: string; lugar: string;
@Column({nullable: false}) @Column({ nullable: false })
cupo: number; cupo: number;
@Column({ nullable: false }) @Column({ length: 500, nullable: false })
requisitos: string; observaciones: string;
@Column({ nullable: true }) @Column({ type: 'decimal', precision: 7, scale: 2, nullable: true })
cuota_inscripcion: number; cuota_inscripcion: number;
@Column({ nullable: true }) @Column({ length: 50, nullable: true })
patrocinador: string; patrocinador: string;
@Column({ nullable: true }) @Column({ length: 40, nullable: true })
tipo_acreditacion: string; tipo_acreditacion: string;
@Column({nullable: false}) @Column({ length: 500, nullable: false })
descripcion: string objetivo: string;
@Column({ nullable: false, type: 'datetime' }) @Column({ nullable: false, type: 'datetime' })
fecha_inicio: Date; fecha_inicio: Date;
@Column({ nullable: false, type: 'datetime' }) @Column({ nullable: false, type: 'datetime' })
fecha_fin: Date; fecha_fin: Date;
@Column({ nullable: false, type: 'datetime' }) @Column({ nullable: false, type: 'datetime' })
fecha_limite_inscripcion: Date; fecha_limite_inscripcion: Date;
@Column({ nullable: true }) @Column({ length: 40, nullable: true })
evento_identificador: string;
@Column({ nullable: true })
horario: string; horario: string;
@Column({ nullable: true }) @Column({ nullable: true })
@@ -74,9 +71,6 @@ export class Evento {
) )
eventoParticipantes: EventoParticipante[]; eventoParticipantes: EventoParticipante[];
@OneToMany( @OneToMany(() => EquipoEvento, (equipoEvento) => equipoEvento.evento)
() => EquipoEvento, (equipoEvento) => equipoEvento.evento equipoEvento: EquipoEvento;
)
equipoEvento: EquipoEvento
} }
+33 -5
View File
@@ -1,4 +1,5 @@
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, Res, UseGuards } from '@nestjs/common';
import { Response } from 'express';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity'; import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
@@ -6,6 +7,7 @@ import { actualizarEventoDto } from './dto/actualizarEvento.dto';
import { crearEventoDto } from './dto/crearEvento.dto'; import { crearEventoDto } from './dto/crearEvento.dto';
import { Evento } from './evento.entity'; import { Evento } from './evento.entity';
import { EventosService } from './eventos.service'; import { EventosService } from './eventos.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('eventos') @Controller('eventos')
export class EventosController { export class EventosController {
@@ -17,28 +19,54 @@ export class EventosController {
return this.eventoService.getEventos() return this.eventoService.getEventos()
} }
@Get('disponibles')
getEventosDisponibles (){
return this.eventoService.getEventosDisponibles()
}
@Get(':id') @Get(':id')
getEventosPorId(@Param('id', ParseIntPipe)id: number):Promise<Evento>{ getEventosPorId(@Param('id', ParseIntPipe)id: number):Promise<Evento>{
return this.eventoService.getEventosPorId(id) return this.eventoService.getEventosPorId(id)
} }
@UseGuards(AuthGuard('jwt'))
@Post() @Post()
postEvento(@Body() nuevoEvento: crearEventoDto){ postEvento(@Body() nuevoEvento: crearEventoDto){
return this.eventoService.postEvento(nuevoEvento) return this.eventoService.postEvento(nuevoEvento)
} }
@UseGuards(AuthGuard('jwt'))
@Patch(':id') @Patch(':id')
patchEvento(@Param('id', ParseIntPipe)id:number, @Body() actualizacion: actualizarEventoDto){ patchEvento(@Param('id', ParseIntPipe)id:number, @Body() actualizacion: actualizarEventoDto){
return this.eventoService.updateEvento(id,actualizacion) return this.eventoService.updateEvento(id,actualizacion)
} }
@UseGuards(AuthGuard('jwt'))
@Delete(':id') @Delete(':id')
deleteEvento(@Param('id', ParseIntPipe)id: number){ deleteEvento(@Param('id', ParseIntPipe)id: number){
return this.eventoService.deleteEventoParticipante(id) return this.eventoService.deleteEventoParticipante(id)
} }
@Get(':id/participantes') @Get(':id/cupos')
async getCupos(@Param('id', ParseIntPipe)id: number){ async getCupos(@Param('id', ParseIntPipe)id: number){
return this.eventoService.getCupos(id) return this.eventoService.getCupos(id)
} }
@UseGuards(AuthGuard('jwt'))
@Get(':id/participante')
async getParticipnates(@Param('id', ParseIntPipe)id:number){
return this.eventoService.getParticipantes(id)
}
@UseGuards(AuthGuard('jwt'))
@Get(':id/exportExcel')
async exportarExcel (@Param('id', ParseIntPipe)id:number ,@Res() res: Response){
this.eventoService.exportarParticipantes(id, res)
}
@Post('disponibles/pendientesDconstancia')
getEventosDisponiblesPendientes(){
return this.eventoService.geteventosDisponiblesMasDosDias()
}
} }
+2 -1
View File
@@ -1,12 +1,13 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity'; import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity';
import { Participante } from 'src/participante/participante.entity';
import { Evento } from './evento.entity'; import { Evento } from './evento.entity';
import { EventosController } from './eventos.controller'; import { EventosController } from './eventos.controller';
import { EventosService } from './eventos.service'; import { EventosService } from './eventos.service';
@Module({ @Module({
imports:[TypeOrmModule.forFeature([Evento, EventoParticipante])], imports:[TypeOrmModule.forFeature([Evento, EventoParticipante, Participante])],
controllers:[EventosController], controllers:[EventosController],
providers:[EventosService] providers:[EventosService]
}) })
+137 -12
View File
@@ -2,10 +2,12 @@ import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity'; import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity';
import { Participante } from 'src/participante/participante.entity'; import { Participante } from 'src/participante/participante.entity';
import { Repository } from 'typeorm'; import { Between, MoreThanOrEqual, Repository } from 'typeorm';
import { actualizarEventoDto } from './dto/actualizarEvento.dto'; import { actualizarEventoDto } from './dto/actualizarEvento.dto';
import { crearEventoDto } from './dto/crearEvento.dto'; import { crearEventoDto } from './dto/crearEvento.dto';
import { Evento } from './evento.entity'; import { Evento } from './evento.entity';
import * as ExcelJS from 'exceljs';
import { Response } from 'express';
@Injectable() @Injectable()
export class EventosService { export class EventosService {
@@ -13,13 +15,19 @@ export class EventosService {
@InjectRepository(Evento) private eventoRepository: Repository<Evento>, @InjectRepository(Evento) private eventoRepository: Repository<Evento>,
@InjectRepository(EventoParticipante) @InjectRepository(EventoParticipante)
private eventoParticipanteRepository: Repository<EventoParticipante>, private eventoParticipanteRepository: Repository<EventoParticipante>,
@InjectRepository(Participante)
private participanteRepository: Repository<Participante>,
) {} ) {}
getEventos() { getEventos() {
return this.eventoRepository.find(); return this.eventoRepository.find({
order: {
fecha_inicio: 'DESC',
},
});
} }
getEventosPorId(id: number) { public getEventosPorId(id: number) {
return this.eventoRepository.findOne({ return this.eventoRepository.findOne({
where: { where: {
id_evento: id, id_evento: id,
@@ -61,16 +69,133 @@ export class EventosService {
} }
} }
async getCupos(id: number){ async getCupos(id: number) {
const evento = this.getEventosPorId(id) const evento = this.getEventosPorId(id);
if(!evento) throw new Error(`El evento con id:${id} no existe`) if (!evento) throw new Error(`El evento con id:${id} no existe`);
const registrados = await this.eventoParticipanteRepository const registrados = await this.eventoParticipanteRepository
.createQueryBuilder('ep') .createQueryBuilder('ep')
.select('COUNT(ep.id_evento)', 'count') .select('COUNT(ep.id_evento)', 'count')
.where('ep.id_evento = :eventoId', { eventoId: (await evento).id_evento }) .where('ep.id_evento = :eventoId', { eventoId: (await evento).id_evento })
.getRawOne(); .getRawOne();
const cupoOriginal = (await evento).cupo; const cupoOriginal = (await evento).cupo;
const cupoDisponible = cupoOriginal - registrados.count; const cupoDisponible = cupoOriginal - registrados.count;
return { registrados: registrados.count, cupoDisponible, cupoOriginal}; return { registrados: registrados.count, cupoDisponible, cupoOriginal };
}
async getParticipantes(idEvento: number) {
const participantes = await this.participanteRepository
.createQueryBuilder('participante')
.innerJoin('participante.eventosParticipante', 'eventoParticipante')
.innerJoin('eventoParticipante.evento', 'evento')
.where('evento.id_evento = :idEvento', { idEvento })
.select([
'participante.nombre',
'participante.apellido_paterno',
'participante.apellido_materno',
'participante.carrera',
'participante.email',
'participante.institucion_procedencia',
])
.getMany();
return participantes;
}
async exportarParticipantes(idEvento: number, res: Response): Promise<void> {
const participantes: Participante[] = await this.getParticipantes(idEvento);
/*console.log(participantes);*/
// Crear el workbook y la worksheet
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Participantes');
// Definir las columnas
worksheet.columns = [
{
header: 'Asistencia',
key: 'asistencia',
width: 10,
style: { alignment: { horizontal: 'center' } },
},
{
header: 'Nombre',
key: 'nombre',
width: 20,
style: { alignment: { horizontal: 'center' } },
},
{
header: 'Apellido Paterno',
key: 'apellido_paterno',
width: 20,
style: { alignment: { horizontal: 'center' } },
},
{
header: 'Apellido Materno',
key: 'apellido_materno',
width: 20,
style: { alignment: { horizontal: 'center' } },
},
{
header: 'Carrera',
key: 'carrera',
width: 20,
style: { alignment: { horizontal: 'center' } },
},
{
header: 'Email',
key: 'email',
width: 35,
style: { alignment: { horizontal: 'center' } },
},
{
header: 'Institución Procedencia',
key: 'institucion_procedencia',
width: 30,
style: { alignment: { horizontal: 'center' } },
},
];
// Agregar los datos a la worksheet
participantes.forEach((participante) => {
worksheet.addRow({
asistencia: '',
nombre: participante.nombre,
apellido_paterno: participante.apellido_paterno,
apellido_materno: participante.apellido_materno,
carrera: participante.carrera,
email: participante.email,
institucion_procedencia: participante.institucion_procedencia,
});
});
/* console.log(workbook.description); */
// Generar el archivo Excel y guardarlo en el servidor
const fileName = `participantes-${idEvento}.xlsx`;
// Configurar la respuesta HTTP para descargar el archivo
res.setHeader(
'Content-Type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
);
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);
// Escribir el archivo Excel en la respuesta HTTP
const buffer = await workbook.xlsx.writeBuffer();
res.send(buffer);
}
getEventosDisponibles() {
const hoy = new Date();
return this.eventoRepository.find({
where: {
fecha_fin: MoreThanOrEqual(hoy),
},
});
}
geteventosDisponiblesMasDosDias(){
const hoy = new Date();
return this.eventoRepository.createQueryBuilder("evento")
.where(`DATE_ADD(evento.fecha_fin, INTERVAL 3 DAY) >= :hoy`, { hoy })
.andWhere('fecha_fin <= :hoy', {hoy})
.getMany();
} }
} }
@@ -4,6 +4,7 @@ import {
Post, Post,
} from '@nestjs/common'; } from '@nestjs/common';
import { InscripcionDscService } from './inscripcion-dsc.service'; import { InscripcionDscService } from './inscripcion-dsc.service';
import { And } from 'typeorm';
@Controller('inscripcion-dsc') @Controller('inscripcion-dsc')
export class InscripcionDscController { export class InscripcionDscController {
@@ -29,7 +30,7 @@ export class InscripcionDscController {
try{ try{
/* console.log("verificando confirmacion:", userInformation); /* console.log("verificando confirmacion:", userInformation);
*/ if (userInformation[0].confirmacion) { */ if (userInformation[0].confirmacion && userInformation[1].confirmacion) {
return { return {
error: true, error: true,
msj: 'El usuario ya hizo la confirmación anteriormente', msj: 'El usuario ya hizo la confirmación anteriormente',
+13 -3
View File
@@ -4,16 +4,21 @@ import { createConnection } from 'mysql2/promise';
@Injectable() @Injectable()
export class InscripcionDscService { export class InscripcionDscService {
async userVerification(accountNumber: string) { async userVerification(accountNumber: string) {
let connection;
try { try {
const connection = await createConnection({ connection = await createConnection({
host: process.env.DB_HOST_DSC, host: process.env.DB_HOST_DSC,
user: process.env.DB_USER_DSC, user: process.env.DB_USER_DSC,
password: process.env.DB_PASS_DSC, password: process.env.DB_PASS_DSC,
database: process.env.DB_NAME_DSC, database: process.env.DB_NAME_DSC,
}); });
// const userInformationQuery = `SELECT A.id_cuenta, nombre, if(AI.platica=true,1,0) as confirmacion FROM alumno A
// JOIN alumno_inscrito AI ON (A.id_cuenta = AI.id_cuenta)
// JOIN periodo P ON (P.id_periodo = AI.id_periodo)
// WHERE A.id_cuenta = "${accountNumber}" and P.activo=true`;
const userInformationQuery = `SELECT A.id_cuenta, nombre, if(AI.platica=true,1,0) as confirmacion FROM alumno A const userInformationQuery = `SELECT A.id_cuenta, nombre, if(AI.platica=true,1,0) as confirmacion FROM alumno A
JOIN alumno_inscrito AI ON (A.id_cuenta = AI.id_cuenta) JOIN alumno_inscrito AI ON (A.id_cuenta = AI.id_cuenta) and (AI.id_plataforma = 1 || AI.id_plataforma = 2)
JOIN periodo P ON (P.id_periodo = AI.id_periodo) JOIN periodo P ON (P.id_periodo = AI.id_periodo)
WHERE A.id_cuenta = "${accountNumber}" and P.activo=true`; WHERE A.id_cuenta = "${accountNumber}" and P.activo=true`;
@@ -23,10 +28,15 @@ export class InscripcionDscService {
const resultsArray = JSON.parse(JSON.stringify(results)); const resultsArray = JSON.parse(JSON.stringify(results));
if (resultsArray.length === 0) return null; if (resultsArray.length === 0) return null;
/* console.log('The solution is: ', resultsArray); */ /* console.log('The solution is: ', resultsArray); */
console.log('The solution is: ', resultsArray);
return results; return results;
} catch (error) { } catch (error) {
throw error; throw error;
} finally {
if (connection) {
await connection.end();
}
} }
} }
@@ -44,7 +54,7 @@ export class InscripcionDscService {
const qryEjemplo = `select platica from alumno_inscrito WHERE id_cuenta="${accountNumber}"`; const qryEjemplo = `select platica from alumno_inscrito WHERE id_cuenta="${accountNumber}"`;
const [results] = await connection.query(qryEjemplo); const [results] = await connection.query(userInformationQuery);
const resultsArray = JSON.parse(JSON.stringify(results)); const resultsArray = JSON.parse(JSON.stringify(results));
if (resultsArray.length === 0) return null; if (resultsArray.length === 0) return null;
/* console.log('The solution is: ', resultsArray); */ /* console.log('The solution is: ', resultsArray); */
+12 -1
View File
@@ -1,9 +1,11 @@
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { join } from 'path';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create<NestExpressApplication>(AppModule);
const config = new DocumentBuilder() const config = new DocumentBuilder()
.addBearerAuth() .addBearerAuth()
@@ -14,7 +16,16 @@ async function bootstrap() {
const document = SwaggerModule.createDocument(app, config); const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document); SwaggerModule.setup('api', app, document);
app.useStaticAssets(join(__dirname, '..', 'public'), {
prefix: '/public/',
});
app.enableCors(); app.enableCors();
await app.listen(AppModule.port); await app.listen(AppModule.port);
const port = AppModule.port;
console.log(`Documentacion disponible en: http://localhost:${port}/api`);
console.log(`Servidor desplegado en: http://localhost:${port}`);
} }
bootstrap(); bootstrap();
+6 -6
View File
@@ -19,26 +19,26 @@ export class Miembro {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_miembro: number; id_miembro: number;
@Column({ nullable: false, length: 50 }) @Column({ nullable: false, length: 40 })
nombre: string; nombre: string;
@Column({ nullable: false, length: 50 }) @Column({ nullable: false, length: 30 })
apellido_paterno: string; apellido_paterno: string;
@Column({ nullable: false, length: 50 }) @Column({ nullable: false, length: 30 })
apellido_materno: string; apellido_materno: string;
@Column({ nullable: false }) @Column({ nullable: false })
id_tipo_miembro: number; id_tipo_miembro: number;
@Column({ nullable: false }) @Column({length: 40, nullable: false })
@IsEmail() @IsEmail()
email: string; email: string;
@Column({ nullable: false }) @Column({length: 180, nullable: false })
password: string; password: string;
@Column({ length: 260, nullable:true}) @Column({ length: 200, nullable:true})
descripcion: string; descripcion: string;
@Column({nullable: true}) @Column({nullable: true})
+11 -2
View File
@@ -1,4 +1,4 @@
import { Controller, Get, UseGuards } from '@nestjs/common'; import { Controller, Delete, Get, Param, ParseIntPipe, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
import { Miembro } from './entity/miembro.entity'; import { Miembro } from './entity/miembro.entity';
import { MiembroService } from './miembro.service'; import { MiembroService } from './miembro.service';
@@ -8,9 +8,18 @@ export class MiembroController {
constructor(private readonly miembroService: MiembroService){} constructor(private readonly miembroService: MiembroService){}
@UseGuards(JwtAuthGuard)
@Get() @Get()
getUsuarios(): Promise<Miembro[]>{ getUsuarios(): Promise<Miembro[]>{
return this.miembroService.getUsuarios() return this.miembroService.getUsuarios()
} }
@Get(':tipo')
getMiembros(@Param('tipo', ParseIntPipe)tipo: number): Promise<Miembro[]>{
return this.miembroService.getMiembros(tipo)
}
@Delete(':id')
deleteMiembro(@Param('id', ParseIntPipe)id: number){
return this.miembroService.deleteMiembro(id)
}
} }
+12
View File
@@ -20,4 +20,16 @@ export class MiembroService {
}, },
}); });
} }
getMiembros(tipo: number){
return this.miembroRepository.find({
where:{
id_tipo_miembro: tipo
}
})
}
deleteMiembro(id: number){
return this.miembroRepository.delete({id_miembro: id})
}
} }
+10 -2
View File
@@ -1,5 +1,13 @@
import { Controller, Post } from '@nestjs/common'; import { Controller, Get, Post } from '@nestjs/common';
import { ParticipanteService } from './participante.service'; import { ParticipanteService } from './participante.service';
import { Participante } from './participante.entity';
@Controller('participante') @Controller('participante')
export class ParticipanteController {} export class ParticipanteController {
constructor(private participanteService: ParticipanteService) {}
@Get()
getParticipantes(): Promise<Participante[]> {
return this.participanteService.getParticipantes();
}
}
+9 -12
View File
@@ -6,34 +6,31 @@ export class Participante {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_participante: number; id_participante: number;
@Column({ type: String, nullable: false, length: 100 }) @Column({ type: String, nullable: false, length: 40 })
nombre: string; nombre: string;
@Column({ nullable: false }) @Column({ nullable: false, length: 30 })
apellido_paterno: string; apellido_paterno: string;
@Column({ nullable: false }) @Column({ nullable: false, length: 30 })
apellido_materno: string; apellido_materno: string;
@Column({ nullable: true }) @Column({ nullable: true, length: 12 })
telefono: string; telefono: string;
@Column({ nullable: false }) @Column({ nullable: false, length: 40 })
email: string; email: string;
@Column({ nullable: true }) // @Column({ nullable: true, length: 180}) //
password: string; password: string;
@Column({ nullable: true }) // @Column({length:20, nullable: true }) //
tipo: string; tipo: string;
@Column({ nullable: true }) // @Column({ nullable: true, length: 50})
estado: string;
@Column({ nullable: true })
institucion_procedencia: string; institucion_procedencia: string;
@Column({ nullable: true }) @Column({ nullable: true, length:50})
carrera: string; carrera: string;
@OneToMany( @OneToMany(
+4
View File
@@ -31,4 +31,8 @@ export class ParticipanteService {
}, },
); );
} }
getParticipantes() {
return this.participanteRepository.find();
}
} }
-16
View File
@@ -1,16 +0,0 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Usuario {
@PrimaryGeneratedColumn()
id_usuario: number;
@Column({ nullable: false })
nombre: string;
@Column({ nullable: false })
password: string;
@Column({nullable:false})
email:string
}
-12
View File
@@ -1,12 +0,0 @@
import { Module } from '@nestjs/common';
import { UsuarioService } from './usuario.service';
import { UsuarioController } from './usuarios.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Usuario } from './usuario.entity';
@Module({
imports:[TypeOrmModule.forFeature([Usuario])],
providers: [UsuarioService],
controllers: [UsuarioController]
})
export class UsuarioModule {}
-23
View File
@@ -1,23 +0,0 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Usuario } from './usuario.entity';
@Injectable()
export class UsuarioService {
constructor(
@InjectRepository(Usuario) private usuarioRepository: Repository<Usuario>,
) {}
getUsuarios(){
return this.usuarioRepository.find()
}
getUsuario(email: string) {
return this.usuarioRepository.findOne({
where: {
email,
},
});
}
}
-18
View File
@@ -1,18 +0,0 @@
import { Controller, Get, UseGuards } from '@nestjs/common';
import { ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
import { Usuario } from './usuario.entity';
import { UsuarioService } from './usuario.service';
@ApiBearerAuth()
@Controller('usuarios')
export class UsuarioController {
constructor(private readonly usuarioService: UsuarioService){}
@UseGuards(JwtAuthGuard)
@Get()
getUsuarios(): Promise<Usuario[]>{
return this.usuarioService.getUsuarios()
}
}