This commit is contained in:
David Arranz 2022-02-17 13:12:13 +01:00
parent 0ebcd4abd7
commit 9623eb97e9
16 changed files with 445 additions and 18 deletions

View File

@ -78,7 +78,7 @@ const generateControllers = (service, extraControllers = {}, options = {}) => {
try {
//Asignamos el usuario que crea el elemento si viene
req.body.userId = (req.user)? req.user.id : null;
//Añadimos los paraqmetros que vienen por url
//Añadimos los parametros que vienen por url y en el body
let values = Object.assign({}, params.params, req.body);
//Quitamos el campo id si viniera, para que no de un conflicto con el id autoinc
if (values.id) delete values.id;

View File

@ -114,13 +114,14 @@ passport.use('jwt', new CustomStrategy(async (req, done) => {
if (result && result.id) {
//recuperamos el usuario de la petición
let user = await authService.extraMethods.findUser({ id: result.id });
if (user) {
if (user) {
user = user.toJSON();
const result = userService._updateLastLoginAndVersionUser(user.id, appVersion);
user.app_version = appVersion;
delete user.password;
console.log('Logged in Successfully');
console.log(user);
return done(null, user, { message: 'Logged in Successfully' });
}
else {

View File

@ -9,6 +9,7 @@ const securityHelper = require('../../helpers/security.helper');
const authService = require('./auth.service');
const userService = require('./user.service');
const eventInscriptionService = require('../events/events_inscriptions.service');
const { RequestContactImportNewList } = require('sib-api-v3-sdk');
moment.locale('es');
////////////////////////////////////////////////////////////////////////////////
@ -175,12 +176,15 @@ console.log('CREAMOS EL USUARIO EN NUESTRO SISTEMA', newUser);
}
async function regenerateToken(req, res, next) {
const refreshToken = req.body.refreshToken;
const refreshToken = req.body.token;
const phone = req.body.phone;
const email = req.body.email;
const user = await authService.extraMethods.findUserByRefreshToken(refreshToken);
if (user && user.phone === phone) {
const values = {
console.debug(user, req.body);
if (user && user.phone === phone && user.email === email) {
const tokenData = {
phone: user.phone,
fbuid: user.fbuid,
id: user.id,
@ -188,7 +192,7 @@ async function regenerateToken(req, res, next) {
};
try {
const tokens = securityHelper.generateToken(values);
const tokens = securityHelper.generateToken(tokenData);
await authService.extraMethods.updateUserRefreshToken(user.id, tokens.refreshToken);
const result = { token: tokens.token };
return controllerHelper.handleResultResponse(result, null, req.params, res, httpStatus.OK);
@ -254,9 +258,67 @@ async function singup(req, res, next) {
}
function verify(req, res, next) {
return controllerHelper.handleResultResponse('OK', null, req.params, res, httpStatus.OK);
const params = controllerHelper.extractParamsFromRequest(req, res, {});
const phone = params.query.phone;
const email = params.query.email;
const fbuid = params.query.fbuid;
const user = req.user;
if (user && user.phone === phone && user.email === email && user.fbuid === fbuid) {
return controllerHelper.handleResultResponse(user, null, req.params, res, httpStatus.OK);
} else {
return controllerHelper.handleResultResponse(null, null, req.params, res, httpStatus.UNAUTHORIZED);
}
}
async function getOrCreateUser(req, res, next) {
console.log('>>>>>>>>>>>>>>>>>>>> getOrCreateUser');
const params = controllerHelper.extractParamsFromRequest(req, res, {});
let dataInscription = res.locals.dataInscription;
if (!dataInscription)
return handleResultResponse("Error getOrCreateUser, prepareInscription, recuperateEvent, recuperateReservation requerida", null, params, res, httpStatus.NOT_FOUND);
//Iniciamos el usuario relacionadas con la inscripción.
let dataUser = {
id: (req.user) ? req.user.id : null,
phone: (req.user) ? req.user.phone : null, //((req.body.phone != '+34') ? req.body.phone : null), lo quitamos de momento por la de movistar
name: (req.user) ? req.user.name : req.body.name,
surname: (req.user) ? req.user.surname : req.body.surname,
email: (req.user) ? req.user.email : req.body.email,
entityId: null,
entityName: null,
entityLevel: null,
userResult: (req.user) ? req.user : null,
};
//Asignamos a los datos del usuario a crear, el id de la entidad a la que pertenece, este caso solo es necesario cuando viene la inscripción por web ya que hay que crear un usuario nuevo
if (dataInscription.reservation) {
dataUser.entityId = dataInscription.reservation.entityId;
};
//creamos o recuperamos el usuario teniendo en cuenta que pude venir por APP o WEB
//si viene por web se tendra en cuenta el email y si viene por APP el phone para buscar
try {
//CHAPUZA PARA PODER DAR DE ALTA USUARIOS CON EL MISMO CORREO ELECTRONICO, PERO DISTINTO NOMBRE Y APELLIDO.
if (req.user) //? 'app' : 'web', //En el caso de tener ya usuario viene por APP sino viene por web
dataUser.userResult = await userService._getOrCreateUser(dataUser)
else
dataUser.userResult = await userService._getOrCreateUserWEB(dataUser);
if (!dataUser.userResult) {
// No se ha encontrado
return handleResultResponse("No se ha podido crear o encontrar el usuario dado", null, params, res, httpStatus.NOT_FOUND);
};
} catch (error) {
return handleErrorResponse(MODULE_NAME, 'createInscription', error, res);
};
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', dataUser.userResult.user.Entity);
dataUser.entityId = (dataUser.userResult.user.Entity) ? dataUser.userResult.user.Entity.id : null;
dataUser.entityName = (dataUser.userResult.user.Entity) ? dataUser.userResult.user.Entity.name : 'DEFAULT';
dataUser.entityLevel = (dataUser.userResult.user.Entity) ? dataUser.userResult.user.Entity.level : null;
res.locals.dataUser = dataUser;
next();
}
module.exports = {
login,
@ -266,5 +328,6 @@ module.exports = {
rejectToken,
singup,
verify,
getOrCreateUser,
MODULE_NAME
}

View File

@ -52,8 +52,15 @@ routes.get('/test_jwt', AccessValidator.isLoggedUser,
}
);
routes.get('/verify',
SchemaValidator(authValidation.VerifyInputType, true),
AccessValidator.isLoggedUser,
authController.verify,
);
routes.post('/token',
routes.post('/token',
SchemaValidator(authValidation.RequestRefreshTokenInputType, true),
AccessValidator.isLoggedUser,
authController.regenerateToken,
);

View File

@ -7,6 +7,12 @@ const extraMethods = {
findUser: async (params, context) => {
return await models.User.findOne({
where: params,
include: [{
required: false,
model: models.Entity,
as: 'Entity',
}]
});
},
@ -27,7 +33,7 @@ const extraMethods = {
findUserByRefreshToken: async(refreshToken) => {
return await models.User.findOne({
where: {
token: refreshToken,
refresh_token: refreshToken,
state: 'active'
}
})
@ -35,14 +41,14 @@ const extraMethods = {
updateUserRefreshToken: async(userId, newRefreshToken) => {
return await models.User.update(
{ token: newRefreshToken },
{ refresh_token: newRefreshToken },
{ where: { id: userId }}
);
},
deleteRefreshToken: async (userId, refreshToken) => {
return await models.User.update(
{ token: null },
{ refresh_token: null },
{ where: { id: userId } }
);
}

View File

@ -30,10 +30,24 @@ const LoginOutputType = Joi.object().keys({
token: Joi.string().required()
});
const VerifyInputType = Joi.object().keys({
fbuid: Joi.string().required(),
phone: Joi.string().required(),
email: Joi.string().required(),
});
const RequestRefreshTokenInputType = Joi.object().keys({
token: Joi.string().required(),
phone: Joi.string().required(),
email: Joi.string().required(),
});
module.exports = {
LoginWithPhoneInputType,
LoginWithEmailInputType,
RegisterInputType,
LoginOutputType
LoginOutputType,
VerifyInputType,
RequestRefreshTokenInputType
};

View File

@ -66,6 +66,8 @@ module.exports = function (sequelize, DataTypes) {
tableName: 'users',
freezeTableName: true,
timestamps: true,
});
User.associate = function (models) {

View File

@ -21,6 +21,9 @@ module.exports = function (sequelize, DataTypes) {
},
contact_email: {
type: DataTypes.STRING,
},
level: {
type: DataTypes.STRING,
}
}, {
tableName: 'entities',

View File

@ -100,6 +100,57 @@ function generateBodyMail (member) {
const extraControllers = {
checkCapacity: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {});
let result = {
eventId: params.params.id,
group_size: (params.query.group_size) ? Number(params.query.group_size) : 1,
allow: false,
error: undefined,
};
if (!result.eventId) {
return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST);
}
if (!result.group_size) {
return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST);
}
const Event = await eventService._getEvent(result.eventId);
try {
if (!Event) {
result = {
...result,
error: "El evento solicitado no existe",
};
}
else{
let EventOverflow = null;
if (Event.overflow_eventId && Event.allow_overflow)
EventOverflow = await eventService._getEvent(Event.overflow_eventId);
result = {
...result,
allow: (Event.assistants - Event.confirmed) > result.group_size, // false
assistants: Event.assistants,
confirmed: Event.confirmed,
sold_out: Event.sold_out,
assistants_overflow: (EventOverflow)? EventOverflow.assistants : 0,
confirmed_overflow: (EventOverflow) ? EventOverflow.confirmed : 0,
sold_out_overflow: (EventOverflow) ? EventOverflow.sold_out : 1,
allow_overflow: (EventOverflow) ? (EventOverflow.assistants - EventOverflow.confirmed) > result.group_size : false,
};
};
return handleResultResponse(result, null, params, res, (result === null) ? httpStatus.NOT_FOUND : httpStatus.OK);
} catch (error){
return handleErrorResponse(MODULE_NAME, 'allowCapacity', error, res)
}
},
checkReservationCode: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {});
const appVersion = ((req && req.headers && req.headers['accept-version']) ? req.headers['accept-version'] : null);
@ -385,10 +436,41 @@ console.log('>>>>>>>>>>>>>> ', NewConfirmed);
},
recuperateEvent: async (req, res, next) => {
console.log('>>>>>>>>>>>>>>>>>>>> recuperateEvent');
const params = extractParamsFromRequest(req, res, {});
let dataInscription = res.locals.dataInscription;
if (!dataInscription)
return handleResultResponse("Error al recuperar evento, prepareInscription requerida", null, params, res, httpStatus.NOT_FOUND);
try {
dataInscription.event = await eventService._getEvent(dataInscription.eventId);
if (dataInscription.event) {
dataInscription.event = await dataInscription.event.toJSON();
} else {
// No se ha encontrado
return handleResultResponse("Evento no encontrado", null, params, res, httpStatus.NOT_FOUND);
}
} catch (error) {
return handleErrorResponse(MODULE_NAME, 'recuperateEvent', error, res)
};
// console.log('>>>>>>>>>>>>>>>>>>>>>>>esta es la reserva y el evento al que quiere inscribirse');
// console.log(req.dataInscription.event);
// return handleResultResponse(req.dataInscription, null, req.params, res, httpStatus.OK);
res.locals.dataInscription = dataInscription;
next();
},
//Esta función se puede llamar desde APP y desde WEB
createInscription: async(req, res, next) => {
console.log('CREATE INSCRIPTION********************************************>>>< ', req.body.type);
//Si la inscripcion en online o grupal saltamos la incripcion antigua y lo hacemos del nuevo modo
if ((req.body.group_size) && (req.body.group_size > 1)) {next(); return;}
if ((req.body.type) && (req.body.type === 'online')) { next(); return; }
const params = extractParamsFromRequest(req, res, {});
console.log('CREATE INSCRIPTION>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>< ', params);
console.log('CREATE INSCRIPTION>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>< ', req.body.code);
//Iniciamos entidades relacionadas con la inscripción.
let dataUser = {
id: (req.user) ? req.user.id : null,
@ -671,6 +753,30 @@ console.log('Mandamos mail con entrada>>>>>>>>>>>>>>>>>>>>>>>>>>>');
return handleResultResponse(await dataInscription.inscription.toJSON(), null, params, res, httpStatus.CREATED)
},
descontarAforo: async (req, res, next) => {
//_updateConfirmedEvent
console.log('>>>>>>>>>>>>>>>>>>>> descontarAforo');
const params = extractParamsFromRequest(req, res, {});
let dataInscription = res.locals.dataInscription;
if ((!dataInscription) || (!dataInscription.reservation) || (!dataInscription.event))
return handleResultResponse("Error createReservationToEntity, prepareInscription, recuperateEvent, ActiveReservationToEntity requerida", null, params, res, httpStatus.NOT_FOUND);
const newConfirmed = (dataInscription.event.confirmed + dataInscription.reservation.assistants);
if (dataInscription.event.assistants < newConfirmed)
return handleResultResponse({ message: "El aforo solicitado es superior a las plazas disponibles"}, null, params, res, httpStatus.OK);
//SE MODIFICA EL CONFIRMED DEL EVENTO, YA QUE SE DESCONTARA DEL AFORO DE LA RESERVA
if (!await eventService._updateConfirmedEvent(dataInscription.event.id, newConfirmed))
return handleResultResponse("No se ha podido actualizar el aforo del evento", null, params, res, httpStatus.NOT_FOUND);
//Si se ha llenado ponemos el evento en SOLD_OUT
if (dataInscription.event.assistants == newConfirmed)
await eventService._updateSoldOutEvent(dataInscription.event.id, true);
next();
},
getQRCodeInscription: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {});
const inscriptionId = params.params.id;

View File

@ -73,6 +73,29 @@ const getStateText = (event) => {
};
};
const getAssistanceType = (event) => {
if (event.virtual) {
if (event.assistants > 0) {
return 'onsite, online';
} else {
return 'online';
}
} else {
return 'onsite';
}
};
const getAssistanceTypeText = (event) => {
if (event.virtual) {
if (event.assistants > 0) {
return 'evento presencial y online';
} else {
return 'evento online';
}
} else {
return 'evento presencial';
}
};
module.exports = function (sequelize, DataTypes) {
@ -194,6 +217,18 @@ module.exports = function (sequelize, DataTypes) {
allow_questions: {
type: DataTypes.BOOLEAN,
defaultValue: true,
},
assistanceType: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['virtual', 'assistants']),
get: function () {
return getAssistanceType(this);
},
},
assistanceTypeText: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['virtual', 'assistants']),
get: function () {
return getAssistanceTypeText(this);
},
}
}, {

View File

@ -8,6 +8,7 @@ const PaginateMiddleware = require('../../middlewares/paginate');
const FieldMiddleware = require('../../middlewares/fields');
const SortMiddleware = require('../../middlewares/sort');
const authController = require('../auth/auth.controller');
const eventController = require('./event.controller');
const eventInscriptionController = require('./events_inscriptions.controller');
const eventReservationController = require('./events_reservations.controller');
@ -205,6 +206,13 @@ routes.get('/events/:id/multimedias',
eventController.find,
);
// Comprobar capacidad del grupo
routes.get('/events/:id/check_capacity',
isOptionalUser,
eventController.checkCapacity,
);
// Inscripciones
// Esto da las inscripciones de un usuario
routes.get('/events/:id/inscriptions',
@ -253,13 +261,30 @@ routes.get('/me/inscriptions/:id',
);
// Hacer una inscripción
// Hacer una inscripción ANTIGUA NO TOCAR
routes.post('/events/:id/inscriptions',
isLoggedUser,
SchemaValidator(eventValidation.InscriptionInputType, true),
eventController.createInscription
eventController.createInscription,
//Si la inscripcion en online o grupal la hacemos con el nuevo método
//Prepara los datos de la inscripción tipo ....
eventInscriptionController.prepareInscription,
//Recupera el evento
eventController.recuperateEvent,
//Recupera la reservation si viene
eventReservationController.recuperateReservation,
//Recupera a registra el usuario que se va a inscribir
authController.getOrCreateUser,
//Si es un usuario tutor y solicita un group_size se crea la reserva
eventReservationController.createReservationToEntity,
eventController.descontarAforo,
eventReservationController.activeReservationToEntity,
eventController.createInscription,
);
// Hacer una pregunta
routes.post('/events/:eventId/questions',
isLoggedUser,
@ -271,7 +296,7 @@ routes.post('/events/:eventId/questions',
routes.delete('/inscriptions/:id',
isLoggedUser,
//SchemaValidator(eventValidation.InscriptionInputType, true),
eventController.deleteInscription
eventController.deleteInscription,
);
// Imagen del código QR de una inscripción

View File

@ -1,8 +1,11 @@
const Joi = require('joi');
const { join } = require('lodash');
const InscriptionInputType = Joi.object().keys({
// id: Joi.string().required(),
code: Joi.string().optional()
code: Joi.string().optional(),
type: Joi.string().optional(),
group_size: Joi.number().optional(),
});
const webInscriptionInputType = Joi.object().keys({

View File

@ -3,12 +3,54 @@
const generateControllers = require('../../core/controllers');
const eventInscriptionService = require('./events_inscriptions.service');
const { extractParamsFromRequest } = require('../../helpers/controller.helper');
// Module Name
const MODULE_NAME = '[eventInscription.controller]';
const controllerOptions = { MODULE_NAME };
const extraControllers = {};
const extraControllers = {
prepareInscription: async (req, res, next) => {
console.log('>>>>>>>>>>>>>>>>>>>> prepareInscription');
const params = extractParamsFromRequest(req, res, {});
let typeInscription = 'presencial';
//online
if (req.body.type === 'online') {
if (req.body.code)
typeInscription = 'reservation online'
else if (req.body.group_size > 1)
typeInscription = 'reservation online'
else typeInscription = 'online'
}
//onsite
else {
if (req.body.code)
typeInscription = 'reservation presencial'
else if (req.body.group_size > 1)
typeInscription = 'reservation presencial'
};
let dataInscription = {
eventId: params.params.id,
reservationCode: (req.user) ? req.body.code : Buffer.from(req.body.code, 'base64').toString('ascii'),
type: typeInscription,
source: (req.user) ? 'app' : 'web', //En el caso de tener ya usuario viene por APP sino viene por web
validated: null, //si no esta validado la inscripción es a la lista de espera
inscriptionsWithoutReservationAndOverflowCount: null, //nº total de inscritos sin reserva y sin overflow asignada
inscriptionsWithReservationCount: null, //nº total de inscritos a la reserva asignada
event: null,
reservation: null,
inscription: null,
};
res.locals.dataInscription = dataInscription;
next();
},
};
module.exports = generateControllers(eventInscriptionService, extraControllers, controllerOptions);

View File

@ -7,6 +7,7 @@ const eventReservationService = require('./events_reservations.service');
const { extractParamsFromRequest, handleErrorResponse, handleResultResponse } = require('../../helpers/controller.helper');
const emailHelper = require('../../helpers/mail.helper');
const path = require("path");
const responseTime = require('response-time');
// Module Name
@ -128,6 +129,86 @@ const extraControllers = {
}
},
recuperateReservation: async (req, res, next) => {
console.log('>>>>>>>>>>>>>>>>>>>> recuperateReservation');
const params = extractParamsFromRequest(req, res, {});
let dataInscription = res.locals.dataInscription;
if (!dataInscription)
return handleResultResponse("Error recuperateReservation, prepareInscription, recuperateEvent requerida", null, params, res, httpStatus.NOT_FOUND);
//SI VIENE CODIGO DE RESERVA, RECUPERAMOS LA RESERVA Y EL EVENTO
if (dataInscription.reservationCode) {
try {
dataInscription.reservation = await eventReservationService._getReservaByCode(dataInscription.eventId, dataInscription.reservationCode);
if (dataInscription.reservation) {
dataInscription.reservation = await dataInscription.reservation.toJSON();
dataInscription.event = dataInscription.reservation.Event;
} else {
// No se ha encontrado
return handleResultResponse("Código de reserva no encontrado", null, params, res, httpStatus.NOT_FOUND);
}
} catch (error) {
return handleErrorResponse(MODULE_NAME, 'recuperateEventAndReservation', error, res)
}
}
res.locals.dataInscription = dataInscription;
next();
},
createReservationToEntity: async (req, res, next) => {
console.log('>>>>>>>>>>>>>>>>>>>> getOrCreateUser');
const params = extractParamsFromRequest(req, res, {});
let dataInscription = res.locals.dataInscription;
if ((!dataInscription) || (!dataInscription.event))
return handleResultResponse("Error createReservationToEntity, prepareInscription, recuperateEvent requerida", null, params, res, httpStatus.NOT_FOUND);
let dataUser = res.locals.dataUser;
if (!dataUser)
return handleResultResponse("Error createReservationToEntity, prepareInscription, recuperateEvent, getOrCreateUser requerida", null, params, res, httpStatus.NOT_FOUND);
//Si viene group_size crearemos un código de reserva
if (req.body.group_size > 1) {
const reservationData = {
reservation_code: eventReservationService._generateReservatioCode(dataInscription.event, dataUser.entityName),
state: 'draft', //borrador no estaría activa, publish es cuando se descuenta del aforo del evento
color: 'gray',
description: 'Reserva',
init_available_date: dataInscription.event.init_available_date,
end_available_date: dataInscription.event.end_available_date,
entityId: dataUser.entityId,
eventId: dataInscription.event.id,
gmt: dataInscription.event.gmt,
assistants: req.body.group_size,
confirmed: '0',
};
///Aqui podríamos validar si ya hay reserva y dar error ya que no pueden meter codigo de reserva y darnos un group_size superior a 1.
dataInscription.reservation = await eventReservationService.create(reservationData, generateControllers.buildContext(req, {}));
dataInscription.reservation = dataInscription.reservation.toJSON();
res.locals.dataInscription = dataInscription;
};
req.body.group_size = 1;
req.body.code = dataInscription.reservation.reservation_code;
next();
},
activeReservationToEntity: async (req, res, next) => {
console.log('>>>>>>>>>>>>>>>>>>>> ActiveReservationToEntity');
const params = extractParamsFromRequest(req, res, {});
let dataInscription = res.locals.dataInscription;
if ((!dataInscription) || (!dataInscription.reservation))
return handleResultResponse("Error activeReservationToEntity, prepareInscription, recuperateEvent requerida", null, params, res, httpStatus.NOT_FOUND);
///Aqui podríamos validar si ya hay reserva y dar error ya que no pueden meter codigo de reserva y darnos un group_size superior a 1.
if (!await eventReservationService._updatePublishReservation(dataInscription.reservation.id))
return handleResultResponse("No se ha podido publicar la reserva del evento", null, params, res, httpStatus.NOT_FOUND);
next();
},
};
module.exports = generateControllers(eventReservationService, extraControllers, controllerOptions);

View File

@ -122,6 +122,40 @@ const extraMethods = {
});
},
_updatePublishReservation: (id) => {
return new Promise(function (resolve, reject) {
models.EventReservation.update(
{
state: 'publish',
},
{
where: { id: id }
})
.then(function (result) {
resolve((result[0] === 1));
})
.catch(function (error) {
reject(error)
});
});
},
_generateReservatioCode: (event, entityName) => {
let result = 'default';
let entity = (entityName)? entityName : 'DEFAULT';
if (!event)
return result;
let xxx = event.location.city.replace(/\s+/g, '').substr(0, 3);
let yyy = moment(event.init_date).format('YY');
let zzz = entity.replace(/\s+/g, '').substr(0, 3);
let www = Math.floor((Math.random() * 999) + 1).toString().padStart(3, '0');
result = `${xxx}${yyy}-${zzz}${www}`;
return result.toUpperCase();
},
_getReservationsExcel: (user, eventId, partnerId, type, callback) => {
console.log('>>>>>>>>>>>>>>>>>>>><consulta con type:', type);

5
script.sql Normal file
View File

@ -0,0 +1,5 @@
ALTER TABLE `lqdvi_v2`.`entities`
ADD COLUMN `level` VARCHAR(45) NULL DEFAULT NULL AFTER `updatedAt`;
ALTER TABLE `lqdvi_v2`.`users`
ADD COLUMN `profile` VARCHAR(45) NULL DEFAULT NULL;