74 Commits

Author SHA1 Message Date
smoreno 95044f6426 Merge pull request 'Migrando xlsx a exceljs' (#19) from cidwa-ss/cedetec_api_nest:ActualizandoXlsx into update-dependencies
Reviewed-on: #19
2026-08-10 16:27:03 +00:00
smoreno dd0bc1550a Merge branch 'update-dependencies' into ActualizandoXlsx 2026-08-10 16:09:48 +00:00
SinR0str0 c34fb58b30 Corrigiendo email controller test 2026-08-09 22:00:01 -06:00
SinR0str0 ff23484331 Reparando referencias absolutas 2026-08-09 21:50:53 -06:00
SinR0str0 0cb847d057 Usando estilos lint 2026-08-09 21:35:44 -06:00
SinR0str0 8834d654d3 Migrando xlsx a exceljs 2026-08-09 21:28:42 -06:00
smoreno 90dad8f641 Merge pull request 'Actualizando NestJS a la versión 11' (#18) from cidwa-ss/cedetec_api_nest:ActualiandoA11 into update-dependencies
Reviewed-on: #18
2026-08-09 22:30:45 +00:00
SinR0str0 921d9a8970 Ultimas revisiones 2026-08-08 23:00:46 -06:00
SinR0str0 5077af6727 Actualizando grupos 2026-08-08 22:51:08 -06:00
SinR0str0 62f3d17e83 Actualizando a NestJS 11 2026-08-08 22:23:50 -06:00
SinR0str0 199034754e Migración a NestJS 10 2026-08-08 22:18:35 -06:00
SinR0str0 889ebec02b TS +5.7, reflect 0.2 y rxjs actualizados 2026-08-08 22:12:56 -06:00
Patriots01 7497790668 Se actualizaron las dependencias, asi como la funcion de ordenar los banner, se realizaron las pruebas con exito y no arrojaron ningun error, estan listas para mandar a produccion 2026-08-05 13:08:49 -06:00
Patriots01 9696a52072 Actualizacion de las dependencias, se realizaron pruebas de funcionamiento y no arrojaron ningun error 2026-08-04 17:46:11 -06:00
Patriots01 87f11ae968 Se termino de actualizar las dependencias faltantes que no suponen riesgo para el proyecto, a versiones estables, asi como dependencias de desarrollo, se hicieron pruebas de esta version y es estable y apta para migrar al sistema de pruebas, falta actualizar las dependencias criticas como lo son: nestjs, TypeScript, etc, estas versiones se recomienda hacer un plan de trabajo para que no causen conflicto al actualizar el sistema 2026-08-03 15:33:47 -06:00
Patriots01 becf48529d Se implemento la carga de banner con orden en automatico, asi como la funcion de poder actualizar el orden de los banner, ademas de algunas actualizaciones de dependencias, todo esto se probo y funciona correctamente, se mandan estos cambios por que es una version estable a la cual se puede actualizar antes de seguir actualizando las dependencias faltantes 2026-08-03 15:28:04 -06:00
Patriots01 028a8b277d Modificaciones del carrusel 2026-08-03 11:14:41 -06:00
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
santiago f02dd40d51 Se quito el orden para no causar conflicto 2026-02-09 12:22:33 -06:00
santiago b607cc2ccb Se quito el orden en los banners 2026-02-09 12:15:50 -06:00
santiago b5a832e179 Modificaciones 2026-02-09 12:13:50 -06: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
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
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 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 e29aacfc8f Actualizar '.env.example' 2023-03-14 21:38:33 +00: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
94 changed files with 7126 additions and 5084 deletions
-22
View File
@@ -1,22 +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=localhost
DB_USER=root
DB_PASSWORD=Dosmiluno2001
DB_NAME=cedetec_proyectos
DB_PORT=3306
DB_HOST_DSC = 132.248.180.82
DB_USER_DSC = sites_user
DB_PASS_DSC = F0rTest
DB_NAME_DSC = sat
NODEMAILER_SERVICE = gmail
NODEMAILER_USER = cidwa1@pcpuma.acatlan.unam.mx
NODEMAILER_PASWORD = cidwaxd1,
+15
View File
@@ -13,3 +13,18 @@ DB_NAME_DSC=
NODEMAILER_SERVICE= NODEMAILER_SERVICE=
NODEMAILER_USER= NODEMAILER_USER=
NODEMAILER_PASWORD= 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=
+5440 -4304
View File
File diff suppressed because it is too large Load Diff
+37 -32
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",
@@ -20,64 +20,64 @@
"test:e2e": "jest --config ./test/jest-e2e.json" "test:e2e": "jest --config ./test/jest-e2e.json"
}, },
"dependencies": { "dependencies": {
"@nestjs/common": "^9.0.0", "@nestjs/common": "^11.1.28",
"@nestjs/config": "^2.3.1", "@nestjs/config": "^4.0.4",
"@nestjs/core": "^9.0.0", "@nestjs/core": "^11.1.28",
"@nestjs/jwt": "^10.0.2", "@nestjs/jwt": "^11.0.2",
"@nestjs/passport": "^9.0.3", "@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^9.0.0", "@nestjs/platform-express": "^11.1.28",
"@nestjs/serve-static": "^3.0.1", "@nestjs/serve-static": "^5.0.5",
"@nestjs/swagger": "^6.2.1", "@nestjs/swagger": "^11.4.6",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^11.0.3",
"@types/multer": "^1.4.7",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"blob-stream": "^0.1.3", "blob-stream": "^0.1.3",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.15.1",
"exceljs": "^4.3.0", "date-fns": "^2.30.0",
"moment": "^2.29.4", "exceljs": "^4.4.0",
"multer": "^1.4.5-lts.1", "moment": "^2.30.1",
"mysql2": "^3.1.2", "multer": "^2.2.0",
"mysql2": "^3.23.2",
"nodemailer": "^6.9.1", "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", "pdf-lib": "^1.17.1",
"pdfkit": "^0.13.0", "pdfkit": "^0.13.0",
"pg": "^8.9.0", "pg": "^8.22.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.2.2",
"rxjs": "^7.2.0", "rxjs": "^7.8.2",
"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", "uuid": "^9.0.1"
"xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@jridgewell/sourcemap-codec": "^1.4.14", "@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": "^11.1.28",
"@types/express": "^4.17.13", "@types/express": "^5.0.6",
"@types/jest": "29.2.4", "@types/jest": "^29.5.14",
"@types/multer": "^2.2.0",
"@types/node": "18.11.18", "@types/node": "18.11.18",
"@types/passport-local": "^1.0.35", "@types/passport-local": "^1.0.38",
"@types/supertest": "^2.0.11", "@types/supertest": "^7.2.1",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1", "eslint": "^8.0.1",
"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.7.0",
"pdfmake": "^0.2.7", "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": "^7.2.2",
"ts-jest": "29.0.3", "ts-jest": "^29.4.12",
"ts-loader": "^9.2.3", "ts-loader": "^9.6.2",
"ts-node": "^10.0.0", "ts-node": "^10.9.2",
"tsconfig-paths": "4.1.1", "tsconfig-paths": "4.1.1",
"typescript": "^4.7.4" "typescript": "~5.7.0"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": [
@@ -95,5 +95,10 @@
], ],
"coverageDirectory": "../coverage", "coverageDirectory": "../coverage",
"testEnvironment": "node" "testEnvironment": "node"
},
"allowScripts": {
"bcrypt@5.1.0": true,
"es5-ext@0.10.64": true,
"@nestjs/core@10.4.22": true
} }
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

+1 -1
View File
@@ -4,6 +4,6 @@ import { ActividadService } from './actividad.service';
@Module({ @Module({
controllers: [ActividadController], controllers: [ActividadController],
providers: [ActividadService] providers: [ActividadService],
}) })
export class ActividadModule {} export class ActividadModule {}
@@ -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,35 @@
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,15 @@
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;
}
+19 -10
View File
@@ -46,10 +46,15 @@ import { EmailService } from './email/email.service';
import { EmailController } from './email/email.controller'; import { EmailController } from './email/email.controller';
import { EmailModule } from './email/email.module'; import { EmailModule } from './email/email.module';
import { MulterModule } from '@nestjs/platform-express'; import { MulterModule } from '@nestjs/platform-express';
import { CarouselController } from './carousel/carousel.controller';
import { CarouselService } from './carousel/carousel.service';
import { ServeStaticModule } from '@nestjs/serve-static'; import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path'; 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';
import { TylController } from './tyl/tyl.controller';
@Module({ @Module({
imports: [ imports: [
@@ -71,6 +76,7 @@ import { join } from 'path';
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,
@@ -93,8 +99,11 @@ import { join } from 'path';
Equipo, Equipo,
EquipoEvento, EquipoEvento,
EquipoMiembro, EquipoMiembro,
/* Agregado el 2 de junio */
Carrusel,
/* No recuerdo porque empece a ponerle fechas */
Comentarios,
], ],
synchronize: true,
}), }),
}), }),
EventosModule, EventosModule,
@@ -115,21 +124,21 @@ import { join } from 'path';
ProyectoActividadModule, ProyectoActividadModule,
ActividadModule, ActividadModule,
EmailModule, EmailModule,
ComentariosModule,
MulterModule.register({ MulterModule.register({
dest: './uploads', // directorio de destino para guardar los archivos cargados dest: './uploads', // directorio de destino para guardar los archivos cargados
}), }),
CarruselModule,
ComentariosModule,
AlmacenamientoModule,
], ],
controllers: [ controllers: [AppController, InscripcionStatusController, TylController],
AppController, providers: [AppService, InscripcionStatusService],
ParticipanteController,
InscripcionStatusController,
CarouselController,
],
providers: [AppService, InscripcionStatusService, CarouselService],
}) })
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');
} }
} }
+12 -4
View File
@@ -1,18 +1,21 @@
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 { Repository } from 'typeorm';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { LoginMiembroDto } from './dto/loginMiembro.dto'; import { LoginMiembroDto } from './dto/loginMiembro.dto';
import { RegistrarMiembroDto } from './dto/registrarMiembro.dto'; import { RegistrarMiembroDto } from './dto/registrarMiembro.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);
} }
@@ -21,4 +24,9 @@ export class AuthController {
login(@Body() LoginUsuario: LoginMiembroDto) { login(@Body() LoginUsuario: LoginMiembroDto) {
return this.authService.login(LoginUsuario); return this.authService.login(LoginUsuario);
} }
@Post('validate')
validar(@Param() token: any) {
return this.authValidar.validate;
}
} }
+76
View File
@@ -0,0 +1,76 @@
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.',
}),
);
}
+3 -3
View File
@@ -6,9 +6,9 @@ import { AuthController } from './auth.controller';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './jwt.constants'; import { jwtConstants } from './jwt.constants';
import { MiembroModule } from 'src/miembro/miembro.module'; import { MiembroModule } from '../miembro/miembro.module';
import { MiembroService } from 'src/miembro/miembro.service'; import { MiembroService } from '../miembro/miembro.service';
import { Miembro } from 'src/miembro/entity/miembro.entity'; import { Miembro } from '../miembro/entity/miembro.entity';
@Module({ @Module({
imports: [ imports: [
+3 -1
View File
@@ -7,7 +7,7 @@ import { Repository } from 'typeorm';
import { compare } from 'bcrypt'; import { compare } from 'bcrypt';
import { jwtConstants } from './jwt.constants'; import { jwtConstants } from './jwt.constants';
import { LoginMiembroDto } from './dto/loginMiembro.dto'; import { LoginMiembroDto } from './dto/loginMiembro.dto';
import { Miembro } from 'src/miembro/entity/miembro.entity'; import { Miembro } from '../miembro/entity/miembro.entity';
import { RegistrarMiembroDto } from './dto/registrarMiembro.dto'; import { RegistrarMiembroDto } from './dto/registrarMiembro.dto';
@Injectable() @Injectable()
@@ -54,9 +54,11 @@ export class AuthService {
/* console.log(token); */ /* console.log(token); */
const data = { const data = {
user: {
usuario: usuario.nombre, usuario: usuario.nombre,
id: usuario.id_miembro, id: usuario.id_miembro,
email: usuario.email, email: usuario.email,
},
token, token,
}; };
+3 -4
View File
@@ -1,11 +1,10 @@
import { IsEmail, MaxLength, MinLength } from "class-validator" import { IsEmail, MaxLength, MinLength } from 'class-validator';
export class LoginMiembroDto { export class LoginMiembroDto {
@IsEmail() @IsEmail()
email: string email: string;
@MinLength(5) @MinLength(5)
@MaxLength(15) @MaxLength(15)
password: string password: string;
} }
+4 -4
View File
@@ -19,14 +19,14 @@ export class RegistrarMiembroDto extends PartialType(LoginMiembroDto) {
@MaxLength(15) @MaxLength(15)
password: string; password: string;
descripcion: string descripcion: string;
id_carrera: number id_carrera: number;
semestre: string semestre: string;
@IsNotEmpty() @IsNotEmpty()
cuenta: number cuenta: number;
@IsEmail() @IsEmail()
email: string; email: string;
-1
View File
@@ -1,4 +1,3 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
+2 -2
View File
@@ -1,3 +1,3 @@
export const jwtConstants = { export const jwtConstants = {
secret: "SemillaSecreta" secret: 'SemillaSecreta',
} };
-92
View File
@@ -1,92 +0,0 @@
import {
BadRequestException,
Controller,
Delete,
Get,
HttpException,
HttpStatus,
Param,
Post,
Res,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { Response } from 'express';
import * as fs from 'fs';
import { diskStorage } from 'multer';
import * as path from 'path';
@Controller('carousel')
export class CarouselController {
private images: string[] = [];
@Post('/imagenes')
@UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: './public',
filename: function (req, file, cb) {
const directory = './public';
const filePath = `${directory}/${file.originalname}`;
if (fs.existsSync(filePath)) {
cb(
new BadRequestException(
`Ya existe un archivo con el nombre: '${file.originalname}'. Si está seguro de que no es el mismo, cambie el nombre del archivo.`,
),
null,
);
} else {
cb(null, file.originalname);
}
},
}),
fileFilter: function (req, file, cb) {
const filetypes = /jpeg|jpg|webp|png/;
const extname = filetypes.test(
path.extname(file.originalname).toLowerCase(),
);
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
}
cb(
new BadRequestException(
'Lo sentimos, para mejorar la calidad de las imagenes en el carousel solo se aceptan imagenes con terminación: .jpeg .jpg .png .webp',
),
false,
);
},
}),
)
async addImage(@UploadedFile() file) {
return { msg: 'Imagen guardada con exito :)' };
}
@Delete('/imagenes/:nombreArchivo')
async deleteImage(@Param('nombreArchivo') nombreArchivo: string) {
try {
await fs.promises.unlink(`./public/${nombreArchivo}`);
return { message: 'Imagen eliminada exitosamente' };
} catch (err) {
throw new Error('Error al eliminar la imagen');
}
}
@Get('/imagenes')
async getImages(@Res() res: Response) {
// Leer el directorio 'public' para obtener el nombre de todos los archivos
const fileNames = await fs.promises.readdir('./public');
// Generar la URL para cada archivo y agregarla a un arreglo
// Filtrar solo las imágenes con las terminaciones "jpg", "webp" y "png"
const imageNames = fileNames.filter((fileName) =>
['.jpg', '.webp', '.png'].includes(path.extname(fileName)),
);
const imageUrls = imageNames.map((imageName) => `public/${imageName}`);
// Devolver el arreglo de URLs como respuesta
return res.json(imageUrls);
}
}
-18
View File
@@ -1,18 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CarouselService } from './carousel.service';
describe('CarouselService', () => {
let service: CarouselService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CarouselService],
}).compile();
service = module.get<CarouselService>(CarouselService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
-9
View File
@@ -1,9 +0,0 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class CarouselService {
uploadImage(file){
/* console.log(file) */
}
}
+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 '../carrusel/entity/carrusel.entity';
@Module({
imports: [TypeOrmModule.forFeature([Carrusel])],
controllers: [CarruselController],
providers: [CarruselService],
})
export class CarruselModule {}
+207
View File
@@ -0,0 +1,207 @@
import {
BadRequestException,
Injectable,
InternalServerErrorException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Carrusel } from '../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}`;
// Obtener el banner con mayor orden
const ultimoCarrusel = await this.carruselRepository.find({
order: {
orden: 'DESC',
},
take: 1,
});
const ultimoOrden = ultimoCarrusel.length > 0 ? ultimoCarrusel[0].orden : 0;
// const siguienteOrden = ultimoCarrusel
// ? ultimoCarrusel.orden + 1
// : 1;
// const carruselCreate = this.carruselRepository.create(carruselDto);
const carruselCreate = this.carruselRepository.create({
...carruselDto,
orden: ultimoOrden + 1,
});
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 }[]) {
// Paso 1.- Mandar los banner a un orden extremo para que no causen conflicto al actualizar
for (const banner of banners) {
await this.carruselRepository.update(
{ id_imagen_carrusel: banner.id },
{ orden: banner.orden + 1000 },
);
}
// Paso 2.- Actualizamos al nuevo orden
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', unique: true })
orden: number;
}
+5
View File
@@ -0,0 +1,5 @@
export let contador = 0;
export const actualizarContador = () => {
contador++;
};
+12 -9
View File
@@ -1,17 +1,20 @@
import { InscripcionArea } from "src/inscripcion-area/entity/inscripcion_area.entity"; import { InscripcionArea } from '../inscripcion-area/entity/inscripcion_area.entity';
import { Column, Entity, OneToMany, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
OneToMany,
PrimaryColumn,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class Area { export class Area {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_area: number id_area: number;
@Column({ length: 20, nullable: false }) @Column({ length: 20, nullable: false })
area: string area: string;
@OneToMany(
() => InscripcionArea, (inscripcionArea) => inscripcionArea.area
)
inscripcionArea: InscripcionArea[]
@OneToMany(() => InscripcionArea, (inscripcionArea) => inscripcionArea.area)
inscripcionArea: InscripcionArea[];
} }
+6 -8
View File
@@ -1,16 +1,14 @@
import { Miembro } from "src/miembro/entity/miembro.entity"; import { Miembro } from '../miembro/entity/miembro.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity() @Entity()
export class Carrera { export class Carrera {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_carrera: number id_carrera: number;
@Column({ length: 40, nullable: false }) @Column({ length: 40, nullable: false })
carrera: string carrera: string;
@OneToMany( @OneToMany(() => Miembro, (miembro) => miembro.carrera)
() => Miembro, (miembro) => miembro.carrera miembro: Miembro;
)
miembro: Miembro
} }
+6 -8
View File
@@ -1,16 +1,14 @@
import { Miembro } from "src/miembro/entity/miembro.entity"; import { Miembro } from '../miembro/entity/miembro.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity() @Entity()
export class TipoMiembro { export class TipoMiembro {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_tipo_miembro: number id_tipo_miembro: number;
@Column({ length: 15, nullable: false }) @Column({ length: 15, nullable: false })
tipo_miembro: string tipo_miembro: string;
@OneToMany( @OneToMany(() => Miembro, (miembro) => miembro.tipoMiembro)
() => Miembro, (miembro) => miembro.tipoMiembro miembro: Miembro[];
)
miembro: Miembro[]
} }
+4
View File
@@ -0,0 +1,4 @@
export class ComentarioDto {
from: string;
comentario: string;
}
+47
View File
@@ -0,0 +1,47 @@
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 {}
+65
View File
@@ -0,0 +1,65 @@
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,21 @@
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;
}
+17 -11
View File
@@ -1,27 +1,33 @@
import { MiembroContacto } from "src/miembro-contacto/entity/miembro_contacto.entity"; import { MiembroContacto } from '../../miembro-contacto/entity/miembro_contacto.entity';
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class Contacto { export class Contacto {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_contacto: number id_contacto: number;
@Column({ nullable: false }) @Column({ nullable: false })
email: string email: string;
@Column({ length: 40 }) @Column({ length: 40 })
horario: string horario: string;
@Column({ length: 75, nullable: true }) @Column({ length: 75, nullable: true })
facebook: string facebook: string;
@Column({ length: 60, nullable: true }) @Column({ length: 60, nullable: true })
linkedin: string linkedin: string;
@ManyToOne( @ManyToOne(
() => MiembroContacto, (miembroContacto) => miembroContacto.contacto () => MiembroContacto,
(miembroContacto) => miembroContacto.contacto,
) )
@JoinColumn({name: "id_contacto"}) @JoinColumn({ name: 'id_contacto' })
miembroContacto: MiembroContacto miembroContacto: MiembroContacto;
} }
Binary file not shown.
+3 -4
View File
@@ -1,8 +1,7 @@
import { IsEmail } from "class-validator" import { IsEmail } from 'class-validator';
export class EmailDto { export class EmailDto {
subject: string;
subject:string text: string;
text:string
} }
+7 -7
View File
@@ -1,9 +1,9 @@
interface Row { interface Row {
Asistencia: number Asistencia: number;
Nombre: string Nombre: string;
'Apellido Paterno': string 'Apellido Paterno': string;
'Apellido Materno': string 'Apellido Materno': string;
Carrera: string Carrera: string;
'Institución Procedencia': string 'Institución Procedencia': string;
Email: string Email: string;
} }
+13
View File
@@ -1,12 +1,25 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { EmailController } from './email.controller'; import { EmailController } from './email.controller';
import { EmailService } from './email.service';
describe('EmailController', () => { describe('EmailController', () => {
let controller: EmailController; let controller: EmailController;
const mockEmailService = {
sendEmail: jest.fn(),
sendConstancias: jest.fn(),
getParticipantesExcel: jest.fn(),
};
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
controllers: [EmailController], controllers: [EmailController],
providers: [
{
provide: EmailService,
useValue: mockEmailService,
},
],
}).compile(); }).compile();
controller = module.get<EmailController>(EmailController); controller = module.get<EmailController>(EmailController);
+25 -8
View File
@@ -1,6 +1,7 @@
import { import {
Body, Body,
Controller, Controller,
Get,
HttpException, HttpException,
HttpStatus, HttpStatus,
Param, Param,
@@ -8,34 +9,50 @@ import {
Post, Post,
Res, Res,
UploadedFile, UploadedFile,
UseGuards,
UseInterceptors, UseInterceptors,
} from '@nestjs/common'; } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express'; import { FileInterceptor } from '@nestjs/platform-express';
import { EmailDto } from './dto/emailDto.dto'; import { EmailDto } from './dto/emailDto.dto';
import { EmailService } from './email.service'; import { EmailService } from './email.service';
import { Response } from 'express'; import { Response } from 'express';
import * as xlsx from 'xlsx'; import { AuthGuard } from '@nestjs/passport';
@Controller('email') @Controller('email')
export class EmailController { export class EmailController {
constructor(private readonly emailService: EmailService) {} constructor(private readonly emailService: EmailService) {}
@UseGuards(AuthGuard('jwt'))
@Post('/evento/:id') @Post('/evento/:id')
async sendEmail( async sendEmail(
@Param('id', ParseIntPipe) id: number, @Param('id', ParseIntPipe) id: number,
@Body() emailDto: EmailDto, @Body() emailDto: EmailDto,
@Res() res,
): Promise<any> { ): Promise<any> {
return this.emailService.sendEmail(id, emailDto); return this.emailService.sendEmail(id, emailDto, res);
} }
@Post('constancias') @UseGuards(AuthGuard('jwt'))
@Post('constancias/:id')
@UseInterceptors(FileInterceptor('file')) @UseInterceptors(FileInterceptor('file'))
async sendConstancias(@UploadedFile() file, @Body('nombreEvento') nombreEvento: string,) { async sendConstancias(
@UploadedFile() file,
@Param('id', ParseIntPipe) id: number,
@Res() res,
) {
if (!file) { if (!file) {
throw new HttpException("No se ha cargado ningun archivo", HttpStatus.BAD_REQUEST) throw new HttpException(
'No se ha cargado ningun archivo',
HttpStatus.BAD_REQUEST,
);
} }
/* console.log(file) */ return this.emailService.sendConstancias(file, id, res);
return this.emailService.sendConstancias(file, nombreEvento); }
//@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);
} }
} }
+9 -4
View File
@@ -1,13 +1,18 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { EventosModule } from 'src/eventos/eventos.module'; import { EventosModule } from '../eventos/eventos.module';
import { Participante } from 'src/participante/participante.entity'; import { Participante } from '../participante/participante.entity';
import { EmailController } from './email.controller'; import { EmailController } from './email.controller';
import { EmailService } from './email.service'; import { EmailService } from './email.service';
import { EventosService } from '../eventos/eventos.service';
import { EventoParticipante } from '../evento-participante/evento-participante/eventoParticipante.entity';
import { Evento } from '../eventos/evento.entity';
@Module({ @Module({
imports:[TypeOrmModule.forFeature([Participante])], imports: [
TypeOrmModule.forFeature([Participante, EventoParticipante, Evento]),
],
controllers: [EmailController], controllers: [EmailController],
providers:[EmailService] providers: [EmailService, EventosService],
}) })
export class EmailModule {} export class EmailModule {}
+184 -48
View File
@@ -1,18 +1,27 @@
import { HttpException, HttpStatus, Inject, Injectable, Res, UploadedFile } from '@nestjs/common'; import {
HttpException,
HttpStatus,
Inject,
Injectable,
Res,
UploadedFile,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import * as nodemailer from 'nodemailer'; import * as nodemailer from 'nodemailer';
import { EventosService } from 'src/eventos/eventos.service'; import { EventosService } from '../eventos/eventos.service';
import { Participante } from 'src/participante/participante.entity'; import { Participante } from '../participante/participante.entity';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { EmailDto } from './dto/emailDto.dto'; import { EmailDto } from './dto/emailDto.dto';
import * as xlsx from 'xlsx';
import * as pdfMake from 'pdfmake/build/pdfmake'; import * as pdfMake from 'pdfmake/build/pdfmake';
import * as pdfFonts from 'pdfmake/build/vfs_fonts'; import * as pdfFonts from 'pdfmake/build/vfs_fonts';
/* import * as PDFDocument from 'pdfkit'; */ /* import * as PDFDocument from 'pdfkit'; */
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'; import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
import { Response } from 'express';
import { format } from 'date-fns';
import * as ExcelJS from 'exceljs';
@Injectable() @Injectable()
export class EmailService { export class EmailService {
@@ -22,6 +31,7 @@ export class EmailService {
@InjectRepository(Participante) @InjectRepository(Participante)
private participanteRepository: Repository<Participante>, private participanteRepository: Repository<Participante>,
private configService: ConfigService, private configService: ConfigService,
private readonly eventoService: EventosService,
) { ) {
this.transporter = nodemailer.createTransport({ this.transporter = nodemailer.createTransport({
service: this.configService.get('NODEMAILER_SERVICE'), service: this.configService.get('NODEMAILER_SERVICE'),
@@ -32,7 +42,7 @@ export class EmailService {
}); });
} }
async sendEmail(id: number, message: EmailDto) { async sendEmail(id: number, message: EmailDto, res: Response) {
const participantes = await this.getEmailDeParticipantes(id); const participantes = await this.getEmailDeParticipantes(id);
participantes.map((res) => { participantes.map((res) => {
const emailDestinatario = res.email; const emailDestinatario = res.email;
@@ -41,8 +51,8 @@ export class EmailService {
subject: message.subject, subject: message.subject,
text: message.text, text: message.text,
}); });
/*console.log("Email enviado a: ", res)*/
}); });
return res.status(201).json({ message: 'Correos enviados con exito' });
} }
async getEmailDeParticipantes(idEvento: number) { async getEmailDeParticipantes(idEvento: number) {
@@ -57,63 +67,189 @@ export class EmailService {
return participantes; return participantes;
} }
async sendConstancias(file, nombreEvento) { async getParticipantesExcel(idEvento: number, res: Response) {
/* console.log(file) */ console.log('entro a la funcion');
const workbook = xlsx.read(file.buffer); const participantes = await this.participanteRepository
const worksheet = workbook.Sheets[workbook.SheetNames[0]]; .createQueryBuilder('participante')
const data = xlsx.utils.sheet_to_json(worksheet); .innerJoin('participante.eventosParticipante', 'eventoParticipante')
.innerJoin('eventoParticipante.evento', 'evento')
.where('evento.id_evento = :idEvento', { idEvento })
.select(['participante'])
.getMany();
for (const row of data as Row[]) { // 1. Crear workbook y worksheet
const pdfDoc = await PDFDocument.create(); const workbook = new ExcelJS.Workbook();
const page = pdfDoc.addPage(); const worksheet = workbook.addWorksheet('Participantes');
page.setSize(792, 612);
const font = await pdfDoc.embedFont(StandardFonts.HelveticaBold); // 2. Definir encabezados
const fontSize = 30; worksheet.columns = [
const text = 'Constancia de asistencia'; { header: 'ID', key: 'id', width: 10 },
const textWidth = font.widthOfTextAtSize(text, fontSize); { header: 'Nombre', key: 'nombre', width: 30 },
const textHeight = font.heightAtSize(fontSize); { 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 },
];
page.drawText(text, { console.log(participantes);
x: (page.getWidth() - textWidth) / 2,
y: (page.getHeight() - textHeight) / 2, // 3. Insertar datos
size: fontSize, participantes.forEach((p) => {
font: font, worksheet.addRow({
color: rgb(0/255, 0/255, 0/255), 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,
});
}); });
const { width, height } = page.getSize(); // 4. Preparar la respuesta HTTP para enviar el Excel
page.drawText( res.setHeader(
`Se le otorga la constancia por su asistencia al evento: ${nombreEvento}`, 'Content-Type',
{ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
x: 50,
y: height - 50,
size: 12,
font: await pdfDoc.embedFont('Helvetica'),
},
); );
page.drawText( res.setHeader(
`A ${row['Apellido Paterno']} ${row['Apellido Materno']} ${row.Nombre}`, 'Content-Disposition',
{ 'attachment; filename=participantes.xlsx',
x: 50,
y: height - 80,
size: 12,
font: await pdfDoc.embedFont('Helvetica'),
},
); );
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 = new ExcelJS.Workbook();
await workbook.xlsx.load(file.buffer);
const worksheet = workbook.worksheets[0];
const data: any[] = [];
const headers: string[] = [];
worksheet.eachRow((row, rowNumber) => {
const rowData: any = {};
row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
if (rowNumber === 1) {
headers[colNumber] = String(cell.value).trim();
} else {
rowData[headers[colNumber]] = cell.value;
}
});
if (rowNumber > 1) {
data.push(rowData);
}
});
// Carga el PDF pre-diseñado
const existingPdfBytes = fs.readFileSync('../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(); const pdfBytes = await pdfDoc.save();
// Crea el objeto de adjunto con el nombre y contenido del PDF
const attachment = { const attachment = {
filename: `Constancia ${nombreEvento} - ${row.Nombre}_${row['Apellido Paterno']}.pdf`, filename: `Constancia ${evento.nombre} - ${row.Nombre}_${row['Apellido Paterno']}.pdf`,
content: pdfBytes, content: pdfBytes,
}; };
/* const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const url = URL.createObjectURL(blob); */ // 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({ this.transporter.sendMail({
to: row.Email, to: row.Email,
subject: `Constancia de asistencia a "${nombreEvento}"`, subject: `Constancia de asistencia a "${evento.nombre}"`,
text: `¡Un saludo ${row.Nombre}! Aquí está tu constancia de asistencia por el evento "${nombreEvento}". Agradecemos tu asistencia y constancia, esperamos seguir viéndote en eventos futuros.`, 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], 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,27 +1,30 @@
import { Equipo } from "src/equipo/entity/equipo.entity"; import { Equipo } from '../../equipo/entity/equipo.entity';
import { Evento } from "src/eventos/evento.entity"; import { Evento } from '../../eventos/evento.entity';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class EquipoEvento { export class EquipoEvento {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_equipo_evento: number id_equipo_evento: number;
@Column() @Column()
id_equipo: number id_equipo: number;
@Column() @Column()
id_evento: number id_evento: number;
@ManyToOne( @ManyToOne(() => Equipo, (equipo) => equipo.equipoEvento)
() => Equipo, (equipo) => equipo.equipoEvento @JoinColumn({ name: 'id_equipo' })
) equipo: Equipo[];
@JoinColumn({name: "id_equipo"})
equipo: Equipo[]
@ManyToOne( @ManyToOne(() => Evento, (evento) => evento.equipoEvento)
() => Evento, (evento) => evento.equipoEvento @JoinColumn({ name: 'id_evento' })
) evento: Evento;
@JoinColumn({name: "id_evento"})
evento: Evento
} }
@@ -1,27 +1,30 @@
import { Equipo } from "src/equipo/entity/equipo.entity"; import { Equipo } from '../../equipo/entity/equipo.entity';
import { Miembro } from "src/miembro/entity/miembro.entity"; import { Miembro } from '../../miembro/entity/miembro.entity';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class EquipoMiembro { export class EquipoMiembro {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_equipo_miembro:number id_equipo_miembro: number;
@Column() @Column()
id_equipo:number id_equipo: number;
@Column() @Column()
id_miembro:number id_miembro: number;
@ManyToOne( @ManyToOne(() => Miembro, (miembro) => miembro.equipoMiembro)
() => Miembro, (miembro) => miembro.equipoMiembro @JoinColumn({ name: 'id_miembro' })
) miembro: Miembro[];
@JoinColumn({name:"id_miembro"})
miembro: Miembro[]
@ManyToOne( @ManyToOne(() => Equipo, (equipo) => equipo.equipoMiembro)
() => Equipo,(equipo) => equipo.equipoMiembro @JoinColumn({ name: 'id_equipo' })
) equipo: Equipo[];
@JoinColumn({name: "id_equipo"})
equipo: Equipo[]
} }
+17 -14
View File
@@ -1,25 +1,28 @@
import { EquipoEvento } from "src/equipo-evento/entity/equipo_evento.entity"; import { EquipoEvento } from '../../equipo-evento/entity/equipo_evento.entity';
import { EquipoMiembro } from "src/equipo-miembro/entity/equipo_miembro.entity"; import { EquipoMiembro } from '../../equipo-miembro/entity/equipo_miembro.entity';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class Equipo { export class Equipo {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_equipo: number id_equipo: number;
@Column({ length: 50, nullable: true }) @Column({ length: 50, nullable: true })
nombre: string nombre: string;
@Column({ length: 100 }) @Column({ length: 100 })
descripcion:string descripcion: string;
@OneToMany( @OneToMany(() => EquipoMiembro, (equipoMiembro) => equipoMiembro.miembro)
() => EquipoMiembro, (equipoMiembro) => equipoMiembro.miembro equipoMiembro: EquipoMiembro;
)
equipoMiembro: EquipoMiembro
@OneToMany( @OneToMany(() => EquipoEvento, (equipoEvento) => equipoEvento.evento)
() => EquipoEvento, (equipoEvento) => equipoEvento.evento equipoEvento: EquipoEvento;
)
equipoEvento: EquipoEvento
} }
@@ -1,15 +1,15 @@
import { IsNotEmpty, IsNumber } from "class-validator" import { IsNotEmpty, IsNumber } from 'class-validator';
export class registrarEnEvento { export class registrarEnEvento {
@IsNumber() @IsNumber()
@IsNotEmpty() @IsNotEmpty()
id_eventoParticipante: number id_eventoParticipante: number;
@IsNumber() @IsNumber()
@IsNotEmpty() @IsNotEmpty()
id_evento: number id_evento: number;
@IsNumber() @IsNumber()
@IsNotEmpty() @IsNotEmpty()
id_participante: number id_participante: number;
} }
@@ -21,7 +21,6 @@ export class RegistrarParticipanteDto {
@IsNotEmpty() @IsNotEmpty()
institucion_procedencia: string; institucion_procedencia: string;
@IsEmail() @IsEmail()
email: string; email: string;
} }
@@ -1,16 +1,31 @@
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';
@Controller('evento-participante') @Controller('evento-participante')
export class EventoParticipanteController { export class EventoParticipanteController {
constructor(private readonly eventoParticipanteService: EventoParticipanteService){} constructor(
private readonly eventoParticipanteService: EventoParticipanteService,
) {}
@Post(':id') @Post(':id')
regitrarParticipante(@Param("id", ParseIntPipe)id: number, @Body() datos: RegistrarParticipanteDto){ regitrarParticipante(
return this.eventoParticipanteService.registrarParticipante(id, datos) @Param('id', ParseIntPipe) id: number,
@Body() datos: RegistrarParticipanteDto,
) {
return this.eventoParticipanteService.registrarParticipante(id, datos);
} }
@Get()
getEventoParticipante(): Promise<EventoParticipante[]> {
return this.eventoParticipanteService.getEventoParticipantes();
}
} }
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { Participante } from 'src/participante/participante.entity'; import { Participante } from '../../participante/participante.entity';
import { EventoParticipanteController } from './evento-participante.controller'; import { EventoParticipanteController } from './evento-participante.controller';
import { EventoParticipanteService } from './evento-participante.service'; import { EventoParticipanteService } from './evento-participante.service';
import { EventoParticipante } from './eventoParticipante.entity'; import { EventoParticipante } from './eventoParticipante.entity';
@@ -8,6 +8,6 @@ import { EventoParticipante } from './eventoParticipante.entity';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([EventoParticipante, Participante])], imports: [TypeOrmModule.forFeature([EventoParticipante, Participante])],
controllers: [EventoParticipanteController], controllers: [EventoParticipanteController],
providers: [EventoParticipanteService] providers: [EventoParticipanteService],
}) })
export class EventoParticipanteModule {} export class EventoParticipanteModule {}
@@ -4,9 +4,9 @@ import { Repository } from 'typeorm';
import { RegistrarParticipanteDto } from './dto/registrarParticipanteDto.dto'; import { RegistrarParticipanteDto } from './dto/registrarParticipanteDto.dto';
import { Evento } from 'src/eventos/evento.entity'; import { Evento } from '../../eventos/evento.entity';
import { EventoParticipante } from './eventoParticipante.entity'; import { EventoParticipante } from './eventoParticipante.entity';
import { Participante } from 'src/participante/participante.entity'; import { Participante } from '../../participante/participante.entity';
import { info } from 'console'; import { info } from 'console';
import { registrarEnEvento } from './dto/registrarEnEvento.dto'; import { registrarEnEvento } from './dto/registrarEnEvento.dto';
@@ -49,7 +49,6 @@ export class EventoParticipanteService {
return this.participanteExiste(registrarParticipanteDto.email).then( return this.participanteExiste(registrarParticipanteDto.email).then(
(res) => { (res) => {
if (res) { if (res) {
res.nombre = registrarParticipanteDto.nombre; res.nombre = registrarParticipanteDto.nombre;
res.apellido_paterno = registrarParticipanteDto.apellido_paterno; res.apellido_paterno = registrarParticipanteDto.apellido_paterno;
res.apellido_materno = registrarParticipanteDto.apellido_materno; res.apellido_materno = registrarParticipanteDto.apellido_materno;
@@ -75,4 +74,8 @@ export class EventoParticipanteService {
}, },
); );
} }
getEventoParticipantes() {
return this.eventoParticipanteRepository.find();
}
} }
@@ -1,17 +1,24 @@
import { Evento } from 'src/eventos/evento.entity'; import { Evento } from '../../eventos/evento.entity';
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm'; import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryColumn,
PrimaryGeneratedColumn,
} from 'typeorm';
import { Participante } from '../../participante/participante.entity'; import { Participante } from '../../participante/participante.entity';
@Entity() @Entity()
export class EventoParticipante { export class EventoParticipante {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_eventoParticipante: number id_eventoParticipante: number;
@Column({ type: Number, nullable: false }) @Column({ type: Number, nullable: false })
id_evento: number id_evento: number;
@Column({ type: Number, nullable: false }) @Column({ type: Number, nullable: false })
id_participante: number id_participante: number;
@ManyToOne(() => Evento, (evento) => evento.eventoParticipantes) @ManyToOne(() => Evento, (evento) => evento.eventoParticipantes)
@JoinColumn({ name: 'id_evento' }) @JoinColumn({ name: 'id_evento' })
+1 -1
View File
@@ -5,7 +5,7 @@ export class actualizarEventoDto {
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;
+1 -1
View File
@@ -6,7 +6,7 @@ export class crearEventoDto {
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;
+11 -14
View File
@@ -1,5 +1,5 @@
import { EquipoEvento } from 'src/equipo-evento/entity/equipo_evento.entity'; import { EquipoEvento } from '../equipo-evento/entity/equipo_evento.entity';
import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity'; import { EventoParticipante } from '../evento-participante/evento-participante/eventoParticipante.entity';
import { import {
Column, Column,
Entity, Entity,
@@ -21,13 +21,13 @@ export class Evento {
tipo_evento: string; tipo_evento: string;
@Column({ length: 100, nullable: false }) @Column({ length: 100, nullable: false })
organizadores: string organizadores: string;
@Column({ length: 30, nullable: true }) @Column({ length: 30, nullable: true })
proyecto: string proyecto: string;
@Column({ length: 40, nullable: false }) @Column({ length: 40, nullable: false })
modalidad: string modalidad: string;
@Column({ length: 60, nullable: false }) @Column({ length: 60, nullable: false })
lugar: string; lugar: string;
@@ -35,8 +35,8 @@ export class Evento {
@Column({ nullable: false }) @Column({ nullable: false })
cupo: number; cupo: number;
@Column({length: 60, nullable: false }) @Column({ length: 500, nullable: false })
requisitos: string; observaciones: string;
@Column({ type: 'decimal', precision: 7, scale: 2, nullable: true }) @Column({ type: 'decimal', precision: 7, scale: 2, nullable: true })
cuota_inscripcion: number; cuota_inscripcion: number;
@@ -47,8 +47,8 @@ export class Evento {
@Column({ length: 40, nullable: true }) @Column({ length: 40, nullable: true })
tipo_acreditacion: string; tipo_acreditacion: string;
@Column({length: 200 ,nullable: false}) @Column({ length: 500, nullable: false })
objetivo: string objetivo: string;
@Column({ nullable: false, type: 'datetime' }) @Column({ nullable: false, type: 'datetime' })
fecha_inicio: Date; fecha_inicio: Date;
@@ -71,9 +71,6 @@ export class Evento {
) )
eventoParticipantes: EventoParticipante[]; eventoParticipantes: EventoParticipante[];
@OneToMany( @OneToMany(() => EquipoEvento, (equipoEvento) => equipoEvento.evento)
() => EquipoEvento, (equipoEvento) => equipoEvento.evento equipoEvento: EquipoEvento;
)
equipoEvento: EquipoEvento
} }
+41 -20
View File
@@ -1,66 +1,87 @@
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, Res } from '@nestjs/common'; import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Patch,
Post,
Res,
UseGuards,
} from '@nestjs/common';
import { Response } from 'express'; 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 '../evento-participante/evento-participante/eventoParticipante.entity';
import { Repository } from 'typeorm'; import { 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 { EventosService } from './eventos.service'; import { EventosService } from './eventos.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('eventos') @Controller('eventos')
export class EventosController { export class EventosController {
constructor(private readonly eventoService: EventosService) {} constructor(private readonly eventoService: EventosService) {}
@Get() @Get()
getEventos(): Promise<Evento[]> { getEventos(): Promise<Evento[]> {
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(
return this.eventoService.updateEvento(id,actualizacion) @Param('id', ParseIntPipe) id: number,
@Body() actualizacion: actualizarEventoDto,
) {
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/cupos') @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') @Get(':id/participante')
async getParticipnates(@Param('id', ParseIntPipe) id: number) { async getParticipnates(@Param('id', ParseIntPipe) id: number) {
return this.eventoService.getParticipantes(id) return this.eventoService.getParticipantes(id);
} }
@UseGuards(AuthGuard('jwt'))
@Get(':id/exportExcel') @Get(':id/exportExcel')
async exportarExcel (@Param('id', ParseIntPipe)id:number ,@Res() res: Response){ async exportarExcel(
this.eventoService.exportarParticipantes(id, res) @Param('id', ParseIntPipe) id: number,
} @Res() res: Response,
) {
@Post('disponibles') this.eventoService.exportarParticipantes(id, res);
getEventosDisponibles (){
return this.eventoService.getEventosDisponibles()
} }
@Post('disponibles/pendientesDconstancia') @Post('disponibles/pendientesDconstancia')
getEventosDisponiblesPendientes() { getEventosDisponiblesPendientes() {
return this.eventoService.geteventosDisponiblesMasDosDias() return this.eventoService.geteventosDisponiblesMasDosDias();
} }
} }
+4 -2
View File
@@ -7,8 +7,10 @@ import { EventosController } from './eventos.controller';
import { EventosService } from './eventos.service'; import { EventosService } from './eventos.service';
@Module({ @Module({
imports:[TypeOrmModule.forFeature([Evento, EventoParticipante, Participante])], imports: [
TypeOrmModule.forFeature([Evento, EventoParticipante, Participante]),
],
controllers: [EventosController], controllers: [EventosController],
providers:[EventosService] providers: [EventosService],
}) })
export class EventosModule {} export class EventosModule {}
+10 -5
View File
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'; 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 '../evento-participante/evento-participante/eventoParticipante.entity';
import { Participante } from 'src/participante/participante.entity'; import { Participante } from '../participante/participante.entity';
import { Between, MoreThanOrEqual, 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';
@@ -20,10 +20,14 @@ export class EventosService {
) {} ) {}
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,
@@ -189,7 +193,8 @@ export class EventosService {
geteventosDisponiblesMasDosDias() { geteventosDisponiblesMasDosDias() {
const hoy = new Date(); const hoy = new Date();
return this.eventoRepository.createQueryBuilder("evento") return this.eventoRepository
.createQueryBuilder('evento')
.where(`DATE_ADD(evento.fecha_fin, INTERVAL 3 DAY) >= :hoy`, { hoy }) .where(`DATE_ADD(evento.fecha_fin, INTERVAL 3 DAY) >= :hoy`, { hoy })
.andWhere('fecha_fin <= :hoy', { hoy }) .andWhere('fecha_fin <= :hoy', { hoy })
.getMany(); .getMany();
@@ -1,5 +1,5 @@
import { Area } from 'src/catalogos/area.entity'; import { Area } from '../../catalogos/area.entity';
import { InscripcionDSC } from 'src/inscripcion-dsc/entity/inscripcion_dsc.entity'; import { InscripcionDSC } from '../../inscripcion-dsc/entity/inscripcion_dsc.entity';
import { import {
Column, Column,
Entity, Entity,
@@ -24,8 +24,9 @@ export class InscripcionArea {
area: Area; area: Area;
@ManyToOne( @ManyToOne(
() => InscripcionDSC, (inscripcionDsc) => inscripcionDsc.inscripcionArea () => InscripcionDSC,
(inscripcionDsc) => inscripcionDsc.inscripcionArea,
) )
@JoinColumn({name:"id_inscripcion"}) @JoinColumn({ name: 'id_inscripcion' })
inscripcionDsc: InscripcionDSC inscripcionDsc: InscripcionDSC;
} }
@@ -4,6 +4,6 @@ import { InscripcionAreaService } from './inscripcion-area.service';
@Module({ @Module({
controllers: [InscripcionAreaController], controllers: [InscripcionAreaController],
providers: [InscripcionAreaService] providers: [InscripcionAreaService],
}) })
export class InscripcionAreaModule {} export class InscripcionAreaModule {}
@@ -1,8 +1,15 @@
import { InscripcionArea } from 'src/inscripcion-area/entity/inscripcion_area.entity'; import { InscripcionArea } from '../../inscripcion-area/entity/inscripcion_area.entity';
import { InscripcionStatus } from 'src/inscripcion-status/entity/inscripcion_status.entity'; import { InscripcionStatus } from '../../inscripcion-status/entity/inscripcion_status.entity';
import { InscripcionUsuario } from 'src/inscripcion-usuario/entity/inscripcion_usuario.entity'; import { InscripcionUsuario } from '../../inscripcion-usuario/entity/inscripcion_usuario.entity';
import { Periodo } from 'src/periodo/entity/periodo.entity'; import { Periodo } from '../../periodo/entity/periodo.entity';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class InscripcionDSC { export class InscripcionDSC {
@@ -49,20 +56,19 @@ export class InscripcionDSC {
inscripcionArea: InscripcionArea[]; inscripcionArea: InscripcionArea[];
@ManyToOne( @ManyToOne(
() => InscripcionStatus, (inscripcionStatus) => inscripcionStatus.inscripcionDsc () => InscripcionStatus,
(inscripcionStatus) => inscripcionStatus.inscripcionDsc,
) )
@JoinColumn({name: "id_status"}) @JoinColumn({ name: 'id_status' })
inscripcionStatus: InscripcionStatus inscripcionStatus: InscripcionStatus;
@ManyToOne( @ManyToOne(() => Periodo, (periodo) => periodo.inscripcionDsc)
() => Periodo, (periodo) => periodo.inscripcionDsc @JoinColumn({ name: 'id_periodo' })
) periodo: Periodo;
@JoinColumn({name: "id_periodo"})
periodo: Periodo
@OneToMany( @OneToMany(
() => InscripcionUsuario, (inscripcionUsuario) => inscripcionUsuario.inscripcionDsc () => InscripcionUsuario,
(inscripcionUsuario) => inscripcionUsuario.inscripcionDsc,
) )
inscripcionUsuario: InscripcionUsuario[] inscripcionUsuario: InscripcionUsuario[];
} }
@@ -1,9 +1,6 @@
import { import { Body, Controller, NotFoundException, Post } from '@nestjs/common';
Body,
Controller,
Post,
} 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 {
@@ -12,24 +9,32 @@ export class InscripcionDscController {
@Post('confirmacion') @Post('confirmacion')
async confirmacionDsc(@Body() body: any) { async confirmacionDsc(@Body() body: any) {
const { accountNumber } = body; const { accountNumber } = body;
console.log('Entro a la confirmacion');
const userVerification = await this.inscripcionService.userVerification(accountNumber); const userVerification = await this.inscripcionService.userVerification(
accountNumber,
);
/* console.log(userVerification) */ /* console.log(userVerification) */
console.log('Usuario verificacion', userVerification);
if (!userVerification) { if (!userVerification) {
return { throw new NotFoundException('El usuario no se encuentra inscrito');
error: true,
msj: 'El usuario no se encuentra inscrito', // return {
desc: '', // error: true,
}; // msj: 'El usuario no se encuentra inscrito',
// desc: '',
// };
} }
const userInformation = userVerification; const userInformation = userVerification;
/* console.log(userInformation[0].confirmacion) */ /* console.log(userInformation[0].confirmacion) */
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',
@@ -4,6 +4,6 @@ import { InscripcionDscService } from './inscripcion-dsc.service';
@Module({ @Module({
controllers: [InscripcionDscController], controllers: [InscripcionDscController],
providers: [InscripcionDscService] providers: [InscripcionDscService],
}) })
export class InscripcionDscModule {} export class InscripcionDscModule {}
+16 -2
View File
@@ -4,29 +4,43 @@ 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`;
console.log('despues de el select', userInformationQuery);
const qryEjemplo = `SELECT * FROM alumno WHERE id_cuenta="${accountNumber}";`; const qryEjemplo = `SELECT * FROM alumno WHERE id_cuenta="${accountNumber}";`;
const [results] = await connection.query(userInformationQuery); 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); */
console.log('The solution is: ', resultsArray);
console.log('Resultados', results);
return results; return results;
} catch (error) { } catch (error) {
console.log('Entro al error', error);
throw error; throw error;
} finally {
if (connection) {
await connection.end();
}
} }
} }
@@ -1,4 +1,4 @@
import { InscripcionDSC } from 'src/inscripcion-dsc/entity/inscripcion_dsc.entity'; import { InscripcionDSC } from '../../inscripcion-dsc/entity/inscripcion_dsc.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity() @Entity()
@@ -12,6 +12,9 @@ export class InscripcionStatus {
@Column({ nullable: false }) @Column({ nullable: false })
status: number; status: number;
@OneToMany(() => InscripcionDSC, (inscripcionDsc) => inscripcionDsc.inscripcionStatus) @OneToMany(
() => InscripcionDSC,
(inscripcionDsc) => inscripcionDsc.inscripcionStatus,
)
inscripcionDsc: InscripcionDSC[]; inscripcionDsc: InscripcionDSC[];
} }
@@ -1,29 +1,32 @@
import { InscripcionDSC } from "src/inscripcion-dsc/entity/inscripcion_dsc.entity"; import { InscripcionDSC } from '../../inscripcion-dsc/entity/inscripcion_dsc.entity';
import { Miembro } from "src/miembro/entity/miembro.entity"; import { Miembro } from '../../miembro/entity/miembro.entity';
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class InscripcionUsuario { export class InscripcionUsuario {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_inscripcion_usuario: number id_inscripcion_usuario: number;
@Column({ nullable: false }) @Column({ nullable: false })
id_miembro: number id_miembro: number;
@Column({ nullable: false }) @Column({ nullable: false })
id_inscripcion: number id_inscripcion: number;
@ManyToOne( @ManyToOne(
() => InscripcionDSC, (inscripcionDsc) => inscripcionDsc.inscripcionUsuario () => InscripcionDSC,
(inscripcionDsc) => inscripcionDsc.inscripcionUsuario,
) )
@JoinColumn({name: "id_inscripcion"}) @JoinColumn({ name: 'id_inscripcion' })
inscripcionDsc: InscripcionDSC inscripcionDsc: InscripcionDSC;
@ManyToOne(
() => Miembro, (miebro) => miebro.inscripcionUsuario
)
@JoinColumn({name: "id_miembro"})
miembro: Miembro[]
@ManyToOne(() => Miembro, (miebro) => miebro.inscripcionUsuario)
@JoinColumn({ name: 'id_miembro' })
miembro: Miembro[];
} }
@@ -4,6 +4,6 @@ import { InscripcionUsuarioService } from './inscripcion-usuario.service';
@Module({ @Module({
controllers: [InscripcionUsuarioController], controllers: [InscripcionUsuarioController],
providers: [InscripcionUsuarioService] providers: [InscripcionUsuarioService],
}) })
export class InscripcionUsuarioModule {} export class InscripcionUsuarioModule {}
+4
View File
@@ -22,5 +22,9 @@ async function bootstrap() {
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();
@@ -1,26 +1,30 @@
import { Contacto } from "src/contacto/entity/contacto.entity"; import { Contacto } from '../../contacto/entity/contacto.entity';
import { Miembro } from "src/miembro/entity/miembro.entity"; import { Miembro } from '../../miembro/entity/miembro.entity';
import { Column, Entity, JoinColumn, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class MiembroContacto { export class MiembroContacto {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_miembro_contacto: number id_miembro_contacto: number;
@Column() @Column()
id_miembro: number id_miembro: number;
@Column() @Column()
id_contacto: number id_contacto: number;
/* @OneToMany( /* @OneToMany(
() => Miembro, (miembro) => miembro.miembroContacto () => Miembro, (miembro) => miembro.miembroContacto
) )
miembro: Miembro[] */ miembro: Miembro[] */
@OneToMany( @OneToMany(() => Contacto, (contacto) => contacto.miembroContacto)
() => Contacto, (contacto) => contacto.miembroContacto @JoinColumn({ name: 'id_contacto' })
) contacto: Contacto;
@JoinColumn({name: "id_contacto"})
contacto: Contacto
} }
@@ -9,7 +9,9 @@ describe('MiembroContactoController', () => {
controllers: [MiembroContactoController], controllers: [MiembroContactoController],
}).compile(); }).compile();
controller = module.get<MiembroContactoController>(MiembroContactoController); controller = module.get<MiembroContactoController>(
MiembroContactoController,
);
}); });
it('should be defined', () => { it('should be defined', () => {
@@ -4,6 +4,6 @@ import { MiembroContactoService } from './miembro-contacto.service';
@Module({ @Module({
controllers: [MiembroContactoController], controllers: [MiembroContactoController],
providers: [MiembroContactoService] providers: [MiembroContactoService],
}) })
export class MiembroContactoModule {} export class MiembroContactoModule {}
@@ -1,26 +1,29 @@
import { Miembro } from "src/miembro/entity/miembro.entity"; import { Miembro } from '../../miembro/entity/miembro.entity';
import { Proyecto } from "src/proyecto/entity/proyecto.entity"; import { Proyecto } from '../../proyecto/entity/proyecto.entity';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class MiembroProyecto { export class MiembroProyecto {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_miembro_proyecto: number id_miembro_proyecto: number;
@Column() @Column()
id_proyecto: number id_proyecto: number;
@Column() @Column()
id_miembro: number id_miembro: number;
@ManyToOne( @ManyToOne(() => Miembro, (miembro) => miembro.miembroProyecto)
() => Miembro, (miembro) => miembro.miembroProyecto @JoinColumn({ name: 'id_miembro' })
) miembro: Miembro[];
@JoinColumn({name: "id_miembro"})
miembro: Miembro[]
@OneToMany( @OneToMany(() => Proyecto, (proyecto) => proyecto.miembroProyecto)
() => Proyecto, (proyecto) => proyecto.miembroProyecto proyecto: Proyecto[];
)
proyecto: Proyecto[]
} }
@@ -9,7 +9,9 @@ describe('MiembroProyectoController', () => {
controllers: [MiembroProyectoController], controllers: [MiembroProyectoController],
}).compile(); }).compile();
controller = module.get<MiembroProyectoController>(MiembroProyectoController); controller = module.get<MiembroProyectoController>(
MiembroProyectoController,
);
}); });
it('should be defined', () => { it('should be defined', () => {
@@ -4,6 +4,6 @@ import { MiembroProyectoService } from './miembro-proyecto.service';
@Module({ @Module({
controllers: [MiembroProyectoController], controllers: [MiembroProyectoController],
providers: [MiembroProyectoService] providers: [MiembroProyectoService],
}) })
export class MiembroProyectoModule {} export class MiembroProyectoModule {}
+11 -12
View File
@@ -1,10 +1,10 @@
import { IsEmail } from 'class-validator'; import { IsEmail } from 'class-validator';
import { Carrera } from 'src/catalogos/carrera.entity'; import { Carrera } from '../../catalogos/carrera.entity';
import { TipoMiembro } from 'src/catalogos/tipo-miembro.entity'; import { TipoMiembro } from '../../catalogos/tipo-miembro.entity';
import { EquipoMiembro } from 'src/equipo-miembro/entity/equipo_miembro.entity'; import { EquipoMiembro } from '../../equipo-miembro/entity/equipo_miembro.entity';
import { InscripcionUsuario } from 'src/inscripcion-usuario/entity/inscripcion_usuario.entity'; import { InscripcionUsuario } from '../../inscripcion-usuario/entity/inscripcion_usuario.entity';
import { MiembroContacto } from 'src/miembro-contacto/entity/miembro_contacto.entity'; import { MiembroContacto } from '../../miembro-contacto/entity/miembro_contacto.entity';
import { MiembroProyecto } from 'src/miembro-proyecto/entity/miembro_proyecto.entity'; import { MiembroProyecto } from '../../miembro-proyecto/entity/miembro_proyecto.entity';
import { import {
Column, Column,
Entity, Entity,
@@ -71,12 +71,11 @@ export class Miembro {
miembroContacto: MiembroContacto */ miembroContacto: MiembroContacto */
@OneToMany( @OneToMany(
() => MiembroProyecto, (miembroProyecto) => miembroProyecto.miembro () => MiembroProyecto,
(miembroProyecto) => miembroProyecto.miembro,
) )
miembroProyecto: MiembroProyecto miembroProyecto: MiembroProyecto;
@OneToMany( @OneToMany(() => EquipoMiembro, (equipoMiembro) => equipoMiembro.miembro)
() => EquipoMiembro, (equipoMiembro) => equipoMiembro.miembro equipoMiembro: EquipoMiembro;
)
equipoMiembro: EquipoMiembro
} }
+11 -5
View File
@@ -1,25 +1,31 @@
import { Controller, Delete, Get, Param, ParseIntPipe, 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';
@Controller('miembro') @Controller('miembro')
export class MiembroController { export class MiembroController {
constructor(private readonly miembroService: MiembroService) {} constructor(private readonly miembroService: MiembroService) {}
@Get() @Get()
getUsuarios(): Promise<Miembro[]> { getUsuarios(): Promise<Miembro[]> {
return this.miembroService.getUsuarios() return this.miembroService.getUsuarios();
} }
@Get(':tipo') @Get(':tipo')
getMiembros(@Param('tipo', ParseIntPipe) tipo: number): Promise<Miembro[]> { getMiembros(@Param('tipo', ParseIntPipe) tipo: number): Promise<Miembro[]> {
return this.miembroService.getMiembros(tipo) return this.miembroService.getMiembros(tipo);
} }
@Delete(':id') @Delete(':id')
deleteMiembro(@Param('id', ParseIntPipe) id: number) { deleteMiembro(@Param('id', ParseIntPipe) id: number) {
return this.miembroService.deleteMiembro(id) return this.miembroService.deleteMiembro(id);
} }
} }
+1 -1
View File
@@ -7,6 +7,6 @@ import { MiembroService } from './miembro.service';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([Miembro])], imports: [TypeOrmModule.forFeature([Miembro])],
controllers: [MiembroController], controllers: [MiembroController],
providers: [MiembroService] providers: [MiembroService],
}) })
export class MiembroModule {} export class MiembroModule {}
+5 -5
View File
@@ -10,7 +10,7 @@ export class MiembroService {
) {} ) {}
getUsuarios() { getUsuarios() {
return this.miembroRepository.find() return this.miembroRepository.find();
} }
getUsuario(email: string) { getUsuario(email: string) {
@@ -24,12 +24,12 @@ export class MiembroService {
getMiembros(tipo: number) { getMiembros(tipo: number) {
return this.miembroRepository.find({ return this.miembroRepository.find({
where: { where: {
id_tipo_miembro: tipo id_tipo_miembro: tipo,
} },
}) });
} }
deleteMiembro(id: number) { deleteMiembro(id: number) {
return this.miembroRepository.delete({id_miembro: id}) 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();
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { EventoParticipante } from 'src/evento-participante/evento-participante/eventoParticipante.entity'; import { EventoParticipante } from '../evento-participante/evento-participante/eventoParticipante.entity';
@Entity() @Entity()
export class Participante { export class Participante {
+1 -1
View File
@@ -7,6 +7,6 @@ import { ParticipanteService } from './participante.service';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([Participante])], imports: [TypeOrmModule.forFeature([Participante])],
controllers: [ParticipanteController], controllers: [ParticipanteController],
providers: [ParticipanteService] providers: [ParticipanteService],
}) })
export class ParticipanteModule {} export class ParticipanteModule {}
+7 -1
View File
@@ -19,7 +19,9 @@ export class ParticipanteService {
return this.participanteRepository.findOne({ where: { email } }); return this.participanteRepository.findOne({ where: { email } });
} }
async registrarParticipante(registrarParticipanteDto: RegistrarParticipanteDto) { async registrarParticipante(
registrarParticipanteDto: RegistrarParticipanteDto,
) {
return this.participanteExiste(registrarParticipanteDto.email).then( return this.participanteExiste(registrarParticipanteDto.email).then(
(participante) => { (participante) => {
if (participante) { if (participante) {
@@ -31,4 +33,8 @@ export class ParticipanteService {
}, },
); );
} }
getParticipantes() {
return this.participanteRepository.find();
}
} }
+6 -9
View File
@@ -1,17 +1,14 @@
import { InscripcionDSC } from "src/inscripcion-dsc/entity/inscripcion_dsc.entity"; import { InscripcionDSC } from '../../inscripcion-dsc/entity/inscripcion_dsc.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm"; import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
@Entity() @Entity()
export class Periodo { export class Periodo {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
id_periodo: number id_periodo: number;
@Column() @Column()
activo: number activo: number;
@OneToMany( @OneToMany(() => InscripcionDSC, (inscripcionDsc) => inscripcionDsc.periodo)
() => InscripcionDSC, (inscripcionDsc) => inscripcionDsc.periodo inscripcionDsc: InscripcionDSC[];
)
inscripcionDsc: InscripcionDSC[]
} }
+1 -1
View File
@@ -4,6 +4,6 @@ import { PeriodoService } from './periodo.service';
@Module({ @Module({
controllers: [PeriodoController], controllers: [PeriodoController],
providers: [PeriodoService] providers: [PeriodoService],
}) })
export class PeriodoModule {} export class PeriodoModule {}
@@ -9,7 +9,9 @@ describe('ProyectoActividadController', () => {
controllers: [ProyectoActividadController], controllers: [ProyectoActividadController],
}).compile(); }).compile();
controller = module.get<ProyectoActividadController>(ProyectoActividadController); controller = module.get<ProyectoActividadController>(
ProyectoActividadController,
);
}); });
it('should be defined', () => { it('should be defined', () => {
@@ -4,6 +4,6 @@ import { ProyectoActividadService } from './proyecto-actividad.service';
@Module({ @Module({
controllers: [ProyectoActividadController], controllers: [ProyectoActividadController],
providers: [ProyectoActividadService] providers: [ProyectoActividadService],
}) })
export class ProyectoActividadModule {} export class ProyectoActividadModule {}
+12 -5
View File
@@ -1,5 +1,11 @@
import { MiembroProyecto } from 'src/miembro-proyecto/entity/miembro_proyecto.entity'; import { MiembroProyecto } from '../../miembro-proyecto/entity/miembro_proyecto.entity';
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; import {
Column,
Entity,
JoinColumn,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity() @Entity()
export class Proyecto { export class Proyecto {
@@ -22,8 +28,9 @@ export class Proyecto {
descripcion: string; descripcion: string;
@ManyToOne( @ManyToOne(
() => MiembroProyecto, (miembroProyecto) => miembroProyecto.proyecto () => MiembroProyecto,
(miembroProyecto) => miembroProyecto.proyecto,
) )
@JoinColumn({name: "id_proyecto"}) @JoinColumn({ name: 'id_proyecto' })
miembroProyecto: MiembroProyecto miembroProyecto: MiembroProyecto;
} }
+1 -1
View File
@@ -4,6 +4,6 @@ import { ProyectoService } from './proyecto.service';
@Module({ @Module({
controllers: [ProyectoController], controllers: [ProyectoController],
providers: [ProyectoService] providers: [ProyectoService],
}) })
export class ProyectoModule {} export class ProyectoModule {}
@@ -1,15 +1,15 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { CarouselController } from './carousel.controller'; import { TylController } from './tyl.controller';
describe('CarouselController', () => { describe('TylController', () => {
let controller: CarouselController; let controller: TylController;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
controllers: [CarouselController], controllers: [TylController],
}).compile(); }).compile();
controller = module.get<CarouselController>(CarouselController); controller = module.get<TylController>(TylController);
}); });
it('should be defined', () => { it('should be defined', () => {
+45
View File
@@ -0,0 +1,45 @@
import {
Body,
Controller,
InternalServerErrorException,
Post,
} from '@nestjs/common';
@Controller('tyl')
export class TylController {
@Post('')
async enviarTyl(@Body() body: { email: string }) {
try {
const user = 'acatlan';
const api = 'LW2rtatYP8o2PhCkIqeJV94d6a60cSvTmJXPbRpP';
const params = new URLSearchParams();
params.append('user_name', user!);
params.append('email', body.email);
params.append('api_key', process.env.API_KEY!);
const response = await fetch(
'https://accede.estudio.app/ventas-acatlan',
{
method: 'POST',
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded',
// },
body: params,
redirect: 'manual',
},
);
console.log('respuesta', response);
const redirectUrl = response.headers.get('location');
console.log('redirect', redirectUrl);
return { redirectUrl };
} catch (error) {
throw new InternalServerErrorException(
'Error al conectar con API externa',
);
}
}
}