Merge pull request 'generar y enviar qr por correo electronico despues de registrar un formulario' (#11) from eithan into develop
Reviewed-on: #11
This commit was merged in pull request #11.
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
PORT=4200
|
||||
|
||||
|
||||
|
||||
db_type=mysql
|
||||
db_host=mariadb # <-- uso del nombre del servicio, NO IP
|
||||
db_port=3306
|
||||
db_username=root # <-- te conectarás con root
|
||||
db_password=mypass # <-- la misma que MARIADB_ROOT_PASSWORD
|
||||
db_database=formularios_test
|
||||
|
||||
|
||||
|
||||
url_api_correos=http://host.docker.internal:4100 #http://localhost:4100
|
||||
@@ -12,6 +12,8 @@ import { RespuestaParticipanteAbierta } from '../respuesta_participante_abierta/
|
||||
import { RespuestaParticipanteCerrada } from '../respuesta_participante_cerrada/entities/respuesta_participante_cerrada.entity';
|
||||
import { PreguntaOpcion } from '../pregunta_opcion/entities/pregunta_opcion.entity';
|
||||
import { Opcion } from '../opcion/entities/opcion.entity';
|
||||
import axios from 'axios';
|
||||
import * as QRCode from 'qrcode';
|
||||
|
||||
@Injectable()
|
||||
export class CuestionarioRespondidoService {
|
||||
@@ -47,7 +49,8 @@ export class CuestionarioRespondidoService {
|
||||
try {
|
||||
// 1. Verificar que el cuestionario existe
|
||||
const cuestionario = await this.cuestionarioRepository.findOne({
|
||||
where: { id_cuestionario: submitDto.id_formulario }
|
||||
where: { id_cuestionario: submitDto.id_formulario },
|
||||
relations: ['evento']
|
||||
});
|
||||
|
||||
if (!cuestionario) {
|
||||
@@ -135,15 +138,110 @@ export class CuestionarioRespondidoService {
|
||||
}
|
||||
}
|
||||
|
||||
// Variables para el QR y correo electrónico
|
||||
let datosQR: {
|
||||
id_participante: number;
|
||||
id_evento: number;
|
||||
} | null = null;
|
||||
|
||||
// Capturamos los datos para el QR
|
||||
if (cuestionario.evento && cuestionario.evento.id_evento) {
|
||||
datosQR = {
|
||||
id_participante: participante.id_participante,
|
||||
id_evento: cuestionario.evento.id_evento
|
||||
};
|
||||
}
|
||||
|
||||
// Primero completamos la transacción principal
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return {
|
||||
// Después de la transacción principal, intentamos registrar la relación participante-evento
|
||||
// y enviar el correo como operaciones independientes
|
||||
if (cuestionario.evento && cuestionario.evento.id_evento) {
|
||||
try {
|
||||
// Registrar participante en evento
|
||||
try {
|
||||
// Verificar si ya existe una relación participante-evento
|
||||
const participanteEventoExistente = await this.dataSource.query(
|
||||
`SELECT * FROM participante_evento WHERE id_participante = ? AND id_evento = ?`,
|
||||
[participante.id_participante, cuestionario.evento.id_evento]
|
||||
);
|
||||
|
||||
// Si no existe, crear la relación
|
||||
if (!participanteEventoExistente || participanteEventoExistente.length === 0) {
|
||||
await this.dataSource.query(
|
||||
`INSERT INTO participante_evento (id_participante, id_evento, fecha_inscripcion, estatus) VALUES (?, ?, ?, ?)`,
|
||||
[participante.id_participante, cuestionario.evento.id_evento, new Date(), true]
|
||||
);
|
||||
}
|
||||
} catch (dbError) {
|
||||
console.error('Error al registrar participante en evento:', dbError.message);
|
||||
}
|
||||
|
||||
// Generar código QR
|
||||
const qrJsonData = JSON.stringify(datosQR);
|
||||
const qrBuffer = await QRCode.toBuffer(qrJsonData);
|
||||
const qrDataUrl = await QRCode.toDataURL(qrJsonData);
|
||||
|
||||
console.log('QR Data URL:', qrDataUrl);
|
||||
console.log("antes de enviar correo");
|
||||
|
||||
// Enviar correo con el QR
|
||||
const urlApiCorreos = process.env.url_api_correos || 'http://localhost:3000';
|
||||
|
||||
await axios.post(`${urlApiCorreos}/mail/send`, {
|
||||
to: participante.correo,
|
||||
subject: 'Asistencia QR',
|
||||
fecha_recibido: "2025-03-10T12:00:00Z",
|
||||
html: `
|
||||
<h1>¡Gracias por registrarte!</h1>
|
||||
<p>Has completado exitosamente el formulario: ${cuestionario.nombre_form}</p>
|
||||
<p>Este es tu QR para registrar asistencia:</p>
|
||||
<img src="cid:qrCode" alt="Código QR" />
|
||||
<p>Tus datos de registro:</p>
|
||||
<ul>
|
||||
<li>Evento: ${cuestionario.evento.nombre_evento || 'Evento'}</li>
|
||||
<li>Correo: ${participante.correo}</li>
|
||||
<li>Fecha de registro: ${new Date().toLocaleString()}</li>
|
||||
</ul>
|
||||
`,
|
||||
adjuntos: [
|
||||
{
|
||||
filename: 'qr.png',
|
||||
content: qrBuffer.toString('base64'),
|
||||
encoding: 'base64',
|
||||
cid: 'qrCode'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
console.log(`Correo enviado exitosamente a ${participante.correo}`);
|
||||
} catch (error) {
|
||||
console.error('Error después de la transacción principal:', error);
|
||||
// No lanzamos el error para que no afecte la respuesta al usuario
|
||||
}
|
||||
}
|
||||
|
||||
// Preparar respuesta
|
||||
const response: any = {
|
||||
success: true,
|
||||
message: 'Respuestas guardadas correctamente',
|
||||
cuestionarioRespondidoId: savedCuestionarioRespondido.idCuestionarioRespondido
|
||||
};
|
||||
|
||||
// Incluir IDs para generar QR si hay evento asociado
|
||||
if (datosQR) {
|
||||
response.datos_qr = datosQR;
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
// Solo hacemos rollback si no hemos hecho commit todavía
|
||||
try {
|
||||
await queryRunner.rollbackTransaction();
|
||||
} catch (rollbackError) {
|
||||
console.error('Error durante rollback:', rollbackError.message);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
|
||||
@@ -19,11 +19,27 @@ export class ParticipanteEventoController {
|
||||
return this.participanteEventoService.getParticipanteEvento(id)
|
||||
}
|
||||
|
||||
@Get(':idParticipante/:idEvento')
|
||||
getParticipanteEventoEspecifico(
|
||||
@Param('idParticipante', ParseIntPipe) idParticipante: number,
|
||||
@Param('idEvento', ParseIntPipe) idEvento: number
|
||||
) {
|
||||
return this.participanteEventoService.getParticipanteEventoEspecifico(idParticipante, idEvento)
|
||||
}
|
||||
|
||||
@Post()
|
||||
createParticipanteEvento(@Body() newParticipanteEvento: CreateParticipanteEventoDto) {
|
||||
return this.participanteEventoService.createParticipanteEvento(newParticipanteEvento)
|
||||
}
|
||||
|
||||
@Post('asistencia/:idParticipante/:idEvento')
|
||||
registrarAsistencia(
|
||||
@Param('idParticipante', ParseIntPipe) idParticipante: number,
|
||||
@Param('idEvento', ParseIntPipe) idEvento: number
|
||||
) {
|
||||
return this.participanteEventoService.registrarAsistencia(idParticipante, idEvento)
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
deleteParticipanteEvento(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.participanteEventoService.deleteParticipanteEvento(id)
|
||||
|
||||
@@ -15,6 +15,9 @@ export class ParticipanteEvento {
|
||||
@Column()
|
||||
estatus: boolean
|
||||
|
||||
@Column({ nullable: true, type: 'datetime' })
|
||||
fecha_asistencia: Date
|
||||
|
||||
/*
|
||||
@OneToOne(() => Qr, (qr) => qr.participanteEvento)
|
||||
qr: Qr;
|
||||
|
||||
@@ -53,6 +53,22 @@ export class ParticipanteEventoService {
|
||||
return participante_eventoFound
|
||||
}
|
||||
|
||||
async getParticipanteEventoEspecifico(id_participante: number, id_evento: number) {
|
||||
const participante_eventoFound = await this.participanteEventoRepository.findOne({
|
||||
where: {
|
||||
id_participante,
|
||||
id_evento
|
||||
},
|
||||
relations: ['evento', 'participante']
|
||||
})
|
||||
|
||||
if (!participante_eventoFound) {
|
||||
return new HttpException('Registro no encontrado', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
return participante_eventoFound
|
||||
}
|
||||
|
||||
async deleteParticipanteEvento(id_participante: number) {
|
||||
const result = await this.participanteEventoRepository.delete({ id_participante })
|
||||
|
||||
@@ -78,4 +94,19 @@ export class ParticipanteEventoService {
|
||||
return this.participanteEventoRepository.save(participante_evento)
|
||||
}
|
||||
|
||||
async registrarAsistencia(id_participante: number, id_evento: number) {
|
||||
const participante_eventoFound = await this.participanteEventoRepository.findOne({
|
||||
where: {
|
||||
id_participante,
|
||||
id_evento
|
||||
}
|
||||
});
|
||||
|
||||
if (!participante_eventoFound) {
|
||||
return new HttpException('Registro no encontrado', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
participante_eventoFound.fecha_asistencia = new Date();
|
||||
return this.participanteEventoRepository.save(participante_eventoFound);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -13,7 +13,7 @@ import { QrService } from './qr.service';
|
||||
import { Qr } from './qr.entity';
|
||||
import { CreateQrDto } from './dto/create-qr.dto';
|
||||
import { UpdateQrDto } from './dto/update.qr.dto';
|
||||
import { ApiOperation, ApiQuery } from '@nestjs/swagger';
|
||||
import { ApiOperation, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
|
||||
@Controller('qr')
|
||||
export class QrController {
|
||||
@@ -30,6 +30,17 @@ export class QrController {
|
||||
return this.qrService.generateQRCode(text);
|
||||
}
|
||||
|
||||
@Get('asistencia/:idParticipante/:idEvento')
|
||||
@ApiOperation({ summary: 'Genera un código QR para asistencia con IDs de participante y evento' })
|
||||
@ApiParam({ name: 'idParticipante', description: 'ID del participante' })
|
||||
@ApiParam({ name: 'idEvento', description: 'ID del evento' })
|
||||
async generateAsistenciaQR(
|
||||
@Param('idParticipante', ParseIntPipe) idParticipante: number,
|
||||
@Param('idEvento', ParseIntPipe) idEvento: number
|
||||
): Promise<string> {
|
||||
return this.qrService.generateAsistenciaQR(idParticipante, idEvento);
|
||||
}
|
||||
|
||||
@Get()
|
||||
getQrs(): Promise<Qr[]> {
|
||||
return this.qrService.getQrs();
|
||||
|
||||
@@ -15,6 +15,20 @@ export class QrService {
|
||||
return await QRCode.toDataURL(text);
|
||||
}
|
||||
|
||||
async generateAsistenciaQR(id_participante: number, id_evento: number): Promise<string> {
|
||||
// Crear un objeto JSON que contenga los IDs
|
||||
const qrData = {
|
||||
id_participante,
|
||||
id_evento
|
||||
};
|
||||
|
||||
// Convertir el objeto a una cadena JSON
|
||||
const jsonStr = JSON.stringify(qrData);
|
||||
|
||||
// Generar el código QR con la cadena JSON
|
||||
return await QRCode.toDataURL(jsonStr);
|
||||
}
|
||||
|
||||
async generateBuffer(text: string): Promise<Buffer> {
|
||||
return await QRCode.toBuffer(text); // Devuelve un buffer para adjuntar en email o stream
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user