Ordenar los próximos eventos poniendo primero los del país del usuario o dispositivo

This commit is contained in:
David Arranz 2023-10-04 12:20:50 +02:00
parent d2e27c02af
commit abc9bb4dee
10 changed files with 725 additions and 582 deletions

View File

@ -155,3 +155,4 @@ const generateControllers = (service, extraControllers = {}, options = {}) => {
module.exports = generateControllers; module.exports = generateControllers;
module.exports.buildContext = buildContext; module.exports.buildContext = buildContext;
module.exports.defaultOptions = defaultOptions;

View File

@ -1,18 +1,20 @@
'use strict'; "use strict";
const express = require('express'); const express = require("express");
//const morgan = require('morgan'); //const morgan = require('morgan');
const bodyParser = require('body-parser'); const bodyParser = require("body-parser");
const compress = require('compression'); const compress = require("compression");
const responseTime = require('response-time'); const responseTime = require("response-time");
const methodOverride = require('method-override'); const methodOverride = require("method-override");
const cors = require('cors'); const cors = require("cors");
const helmet = require('helmet'); const helmet = require("helmet");
const passport = require('passport'); const passport = require("passport");
const config = require('../config'); const config = require("../config");
const router = require('./router'); const router = require("./router");
const error = require('../middlewares/error'); const error = require("../middlewares/error");
const deviceCountryMiddleware = require("../middlewares/deviceCountry");
/** /**
* Express instance * Express instance
@ -24,10 +26,13 @@ const app = express();
//app.use(morgan(logs)); //app.use(morgan(logs));
// parse body params and attache them to req.body // parse body params and attache them to req.body
app.use(bodyParser.json({ limit: '5mb' })); app.use(bodyParser.json({ limit: "5mb" }));
app.use(bodyParser.urlencoded({ app.use(
limit: '5mb', extended: true bodyParser.urlencoded({
})); limit: "5mb",
extended: true,
})
);
// set up the response-time middleware // set up the response-time middleware
app.use(responseTime()); app.use(responseTime());
@ -43,14 +48,23 @@ app.use(methodOverride());
app.use(helmet()); app.use(helmet());
// enable CORS - Cross Origin Resource Sharing // enable CORS - Cross Origin Resource Sharing
//var allowedOrigins = ['http://localhost:8080', 'http://127.0.0.1:8080', 'https://adminapp2.loquedeverdadimporta.org']; //var allowedOrigins = ['http://localhost:8080', 'http://127.0.0.1:8080', 'https://adminapp2.loquedeverdadimporta.org'];
// enable CORS - Cross Origin Resource Sharing // enable CORS - Cross Origin Resource Sharing
app.use(cors({ app.use(
exposedHeaders: ['Content-Disposition', 'Content-Type', 'Content-Length', cors({
'X-Total-Count', 'Pagination-Count', 'Pagination-Page', 'Pagination-Limit'], exposedHeaders: [
})); "X-Country",
"Content-Disposition",
"Content-Type",
"Content-Length",
"X-Total-Count",
"Pagination-Count",
"Pagination-Page",
"Pagination-Limit",
],
})
);
/*app.use(cors({ /*app.use(cors({
origin: function (origin, callback) { origin: function (origin, callback) {
@ -74,7 +88,6 @@ app.use(cors({
} }
}));*/ }));*/
/*app.use(cors({ /*app.use(cors({
origin: '*', origin: '*',
exposeHeaders: [ exposeHeaders: [
@ -113,14 +126,14 @@ app.use(cors({
], ],
}));*/ }));*/
app.use(deviceCountryMiddleware.middleware());
// Access validator // Access validator
app.use(passport.initialize()); app.use(passport.initialize());
require('./passport'); require("./passport");
// Set routes // Set routes
app.use('/api', router()); app.use("/api", router());
// if error is not an instanceOf APIError, convert it. // if error is not an instanceOf APIError, convert it.
app.use(error.converter); app.use(error.converter);
@ -131,4 +144,4 @@ app.use(error.notFound);
// error handler, send stacktrace only during development // error handler, send stacktrace only during development
app.use(error.handler); app.use(error.handler);
module.exports = app; module.exports = app;

View File

@ -0,0 +1,17 @@
const middleware = (config) => {
return function (req, res, next) {
const country = req.headers["x-country"];
if (country) {
req.deviceCountry = country;
} else {
req.deviceCountry = "ES";
}
next();
};
};
module.exports = {
middleware,
};

View File

@ -2,6 +2,7 @@
const moment = require("moment"); const moment = require("moment");
const httpStatus = require("http-status"); const httpStatus = require("http-status");
const generateControllers = require("../../core/controllers"); const generateControllers = require("../../core/controllers");
const { defaultOptions, buildContext } = require("../../core/controllers");
const QRHelper = require("../../helpers/qr.helper"); const QRHelper = require("../../helpers/qr.helper");
const emailHelper = require("../../helpers/mail.helper"); const emailHelper = require("../../helpers/mail.helper");
const notificationHelper = require("../../helpers/notification.helpers"); const notificationHelper = require("../../helpers/notification.helpers");
@ -31,7 +32,7 @@ const MODULE_NAME = "[event.controller]";
const controllerOptions = { const controllerOptions = {
MODULE_NAME, MODULE_NAME,
findOneCallback: eventInscriptionService._fillInscriptionsColor findOneCallback: eventInscriptionService._fillInscriptionsColor,
}; };
function generateMemberInscription(user, inscription, reservation) { function generateMemberInscription(user, inscription, reservation) {
@ -61,8 +62,6 @@ function generateMemberInscription(user, inscription, reservation) {
return memberInscription; return memberInscription;
} }
const extraControllers = { const extraControllers = {
checkCapacity: async (req, res, next) => { checkCapacity: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {}); const params = extractParamsFromRequest(req, res, {});
@ -72,7 +71,7 @@ const extraControllers = {
allow: false, allow: false,
error: undefined, error: undefined,
}; };
console.log('>>>>>>>>>>>>>>>>>>>>>>>checkCapacity', result); console.log(">>>>>>>>>>>>>>>>>>>>>>>checkCapacity", result);
if (!result.eventId) { if (!result.eventId) {
return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST); return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST);
@ -123,8 +122,6 @@ const extraControllers = {
const userId = req.user.id; const userId = req.user.id;
var result = null; var result = null;
console.log(params, req.user.level); console.log(params, req.user.level);
if (eventId) { if (eventId) {
try { try {
@ -138,7 +135,7 @@ const extraControllers = {
} else { } else {
try { try {
result = await eventInscriptionService._getInscriptionsUser(userId); result = await eventInscriptionService._getInscriptionsUser(userId);
result = result.map(row => row.toJSON()); result = result.map((row) => row.toJSON());
// Asigno colores a las entradas normales // Asigno colores a las entradas normales
result = eventInscriptionService._fillInscriptionsColor(result); result = eventInscriptionService._fillInscriptionsColor(result);
return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK); return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK);
@ -156,8 +153,7 @@ const extraControllers = {
const userId = req.user.id; const userId = req.user.id;
var result = null; var result = null;
if (!eventId) if (!eventId) return handleResultResponse("Es necesario el ID del evento", null, params, res, httpStatus.NOT_FOUND);
return handleResultResponse("Es necesario el ID del evento", null, params, res, httpStatus.NOT_FOUND);
try { try {
result = await eventInscriptionService._getInscriptionOnlineByEvent(eventId); result = await eventInscriptionService._getInscriptionOnlineByEvent(eventId);
@ -167,26 +163,53 @@ const extraControllers = {
} catch (error) { } catch (error) {
return handleErrorResponse(MODULE_NAME, "getInscriptionsOnline", error, res); return handleErrorResponse(MODULE_NAME, "getInscriptionsOnline", error, res);
} }
}, },
getInscriptionsOfNextEventsCount: async (req, res, next) => { getInscriptionsOfNextEventsCount: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {}); const params = extractParamsFromRequest(req, res, {});
const userId = req.user.id; const userId = req.user.id;
try { try {
const result = await eventInscriptionService._getInscriptionsOfNextEventsUser(userId); const result = await eventInscriptionService._getInscriptionsOfNextEventsUser(userId);
console.log("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
return handleResultResponse({ count: result }, null, params, res, httpStatus.OK); return handleResultResponse({ count: result }, null, params, res, httpStatus.OK);
} catch (error) { } catch (error) {
console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
return handleErrorResponse(MODULE_NAME, "getInscriptionsOfNextEventsCount", error, res); return handleErrorResponse(MODULE_NAME, "getInscriptionsOfNextEventsCount", error, res);
} }
}, },
findNextEventsByCountry: (config) => {
function placesCountrysEventsFirst(rows, countryCode) {
const countryEvents = [];
const restEvents = [];
for (const event of rows) {
if (event.location.country_code === countryCode) {
countryEvents.push(event);
} else {
restEvents.push(event);
}
}
return countryEvents.concat(restEvents);
}
return async (req, res, next) => {
config = config || {
scopes: [],
};
const params = extractParamsFromRequest(req, res, defaultOptions.params.find);
try {
const result = await eventService.fetchAll(params, buildContext(req, config));
const orderedRows = placesCountrysEventsFirst(result.rows, req.user ? req.user.country : req.deviceCountry);
console.log(orderedRows);
return handleResultResponse(orderedRows, result.count, params, res);
} catch (error) {
return handleErrorResponse(MODULE_NAME, "findNextEventsByCountry", error, res);
}
};
},
findPartners: async (req, res, next) => { findPartners: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {}); const params = extractParamsFromRequest(req, res, {});
@ -326,11 +349,15 @@ const extraControllers = {
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>><syncronizeMarketingList"); console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>><syncronizeMarketingList");
if (marketingListService.syncronizeEventWithMarketingList(eventId)) if (marketingListService.syncronizeEventWithMarketingList(eventId))
return handleResultResponse("La sincronización se ha realizado correctamente", null, params, res, httpStatus.DELETEOK); return handleResultResponse(
"La sincronización se ha realizado correctamente",
null,
params,
res,
httpStatus.DELETEOK
);
}, },
getQRCodeInscription: async (req, res, next) => { getQRCodeInscription: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {}); const params = extractParamsFromRequest(req, res, {});
const inscriptionId = params.params.id; const inscriptionId = params.params.id;
@ -381,7 +408,8 @@ const extraControllers = {
//console.log(headerMail, bodyMail); //console.log(headerMail, bodyMail);
try { try {
if (member.validated) emailHelper.sendTicket(mailService.generateHeaderMail(member), mailService.generateBodyMail(member)); if (member.validated)
emailHelper.sendTicket(mailService.generateHeaderMail(member), mailService.generateBodyMail(member));
else emailHelper.sendListaEspera(mailService.generateHeaderMail(member), mailService.generateBodyMail(member)); else emailHelper.sendListaEspera(mailService.generateHeaderMail(member), mailService.generateBodyMail(member));
} catch (error) { } catch (error) {
console.log("No se ha podido mandar email con entrada"); console.log("No se ha podido mandar email con entrada");

View File

@ -1,496 +1,544 @@
'use strict'; "use strict";
const moment = require('moment'); const moment = require("moment");
const Sequelize = require('sequelize'); const Sequelize = require("sequelize");
moment.locale('es'); moment.locale("es");
const getStateCode = (event) => { const getStateCode = (event) => {
var currentDate = moment(), var currentDate = moment(),
initDate = moment(event.init_date), initDate = moment(event.init_date),
endDate = moment(event.end_date), endDate = moment(event.end_date),
init_availableDate = moment(event.init_available_date), init_availableDate = moment(event.init_available_date),
end_availableDate = moment(event.end_available_date); end_availableDate = moment(event.end_available_date);
if (currentDate.isBetween(initDate, endDate)) { if (currentDate.isBetween(initDate, endDate)) {
return 'current_event'; return "current_event";
} else {
if (endDate.isBefore(currentDate)) {
return "closed_event";
} else { } else {
if (endDate.isBefore(currentDate)) { if (currentDate.isBefore(init_availableDate)) {
return 'closed_event'; return "future_registrations";
} else {
if (currentDate.isBetween(init_availableDate, end_availableDate)) {
if (event.url_registration) {
return "url_registrations_open";
} else {
return event.sold_out == 1 ? "waitinglist_open" : "registrations_open";
}
} else { } else {
if (currentDate.isBefore(init_availableDate)){ if (currentDate.isAfter(end_availableDate)) return "closed_registrations";
return 'future_registrations' else return "N/A";
} else {
if (currentDate.isBetween(init_availableDate, end_availableDate)) {
if (event.url_registration) {
return 'url_registrations_open';
} else {
return (event.sold_out == 1) ? 'waitinglist_open' : 'registrations_open';
}
}
else {
if (currentDate.isAfter(end_availableDate))
return 'closed_registrations'
else
return 'N/A';
}
}
} }
}; }
}
}
}; };
const getStateText = (event) => { const getStateText = (event) => {
var currentDate = moment(), var currentDate = moment(),
initDate = moment(event.init_date), initDate = moment(event.init_date),
endDate = moment(event.end_date), endDate = moment(event.end_date),
init_availableDate = moment(event.init_available_date), init_availableDate = moment(event.init_available_date),
end_availableDate = moment(event.end_available_date); end_availableDate = moment(event.end_available_date);
if (currentDate.isBetween(initDate, endDate)) { if (currentDate.isBetween(initDate, endDate)) {
return 'Congreso en curso'; return "Congreso en curso";
} else {
if (endDate.isBefore(currentDate)) {
return "Congreso finalizado";
} else { } else {
if (endDate.isBefore(currentDate)) { if (currentDate.isBefore(init_availableDate)) {
return 'Congreso finalizado'; return "Inscripciones a partir del " + init_availableDate.format("D [de] MMMM");
} else {
if (currentDate.isBetween(init_availableDate, end_availableDate)) {
if (event.url_registration) {
return "Inscripciones abiertas";
} else {
return event.sold_out == 1 ? "Inscripciones abiertas a lista de espera" : "Inscripciones abiertas";
}
} else { } else {
if (currentDate.isBefore(init_availableDate)) { if (currentDate.isAfter(end_availableDate)) return "Inscripciones cerradas";
return 'Inscripciones a partir del ' + init_availableDate.format('D [de] MMMM'); else return "N/A";
} else {
if (currentDate.isBetween(init_availableDate, end_availableDate)) {
if (event.url_registration) {
return 'Inscripciones abiertas';
} else {
return (event.sold_out == 1) ? 'Inscripciones abiertas a lista de espera' : 'Inscripciones abiertas';
}
}
else {
if (currentDate.isAfter(end_availableDate))
return 'Inscripciones cerradas'
else
return 'N/A';
}
}
} }
}; }
}
}
}; };
const getAssistanceType = (event) => { const getAssistanceType = (event) => {
if (event.virtual) { if (event.virtual) {
if (event.assistants > 0) { if (event.assistants > 0) {
return 'onsite, online'; return "onsite, online";
} else {
return 'online';
}
} else { } else {
return 'onsite'; return "online";
} }
} else {
return "onsite";
}
}; };
const getAssistanceTypeText = (event) => { const getAssistanceTypeText = (event) => {
if (event.virtual) { if (event.virtual) {
if (event.assistants > 0) { if (event.assistants > 0) {
return 'evento presencial y online'; return "evento presencial y online";
} else {
return 'evento online';
}
} else { } else {
return 'evento presencial'; return "evento online";
} }
} else {
return "evento presencial";
}
}; };
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const Event = sequelize.define(
"Event",
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.STRING,
},
campaign_text: {
type: DataTypes.TEXT,
allowNull: true,
},
init_date: {
type: DataTypes.DATE,
allowNull: false,
},
end_date: {
type: DataTypes.DATE,
},
init_available_date: {
type: DataTypes.DATE,
},
end_available_date: {
type: DataTypes.DATE,
},
gmt: {
type: DataTypes.INTEGER,
defaultValue: 1,
},
assistants: {
type: DataTypes.INTEGER,
},
confirmed: {
type: DataTypes.INTEGER,
},
sold_out: {
//Se han vendido todas y se ha abierto lista de espera si hay asignada
type: DataTypes.BOOLEAN,
defaultValue: false,
},
allow_multiple: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
multiple_limit: {
type: DataTypes.INTEGER,
},
allow_overflow: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
overflow_eventId: {
type: DataTypes.UUID,
foreignKey: true,
require: false,
},
state: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: "draft",
},
stateCode: {
type: Sequelize.VIRTUAL(Sequelize.STRING, [
"init_date",
"end_date",
"init_available_date",
"end_available_date",
"sold_out",
]),
get: function () {
return getStateCode(this);
},
},
stateText: {
type: Sequelize.VIRTUAL(Sequelize.STRING, [
"init_date",
"end_date",
"init_available_date",
"end_available_date",
"sold_out",
]),
get: function () {
return getStateText(this);
},
},
typeId: {
type: DataTypes.UUID,
foreignKey: true,
},
venueId: {
type: DataTypes.UUID,
foreignKey: true,
},
locationId: {
type: DataTypes.UUID,
foreignKey: true,
},
url_streaming: {
type: DataTypes.STRING,
},
url_poll: {
type: DataTypes.STRING,
},
url_registration: {
type: DataTypes.STRING,
},
marketing_list: {
type: DataTypes.STRING,
},
userId: {
type: DataTypes.UUID,
foreignKey: true,
},
featured: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
virtual: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
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);
},
},
},
{
tableName: "events",
freezeTableName: true,
timestamps: true,
const Event = sequelize.define('Event', { defaultScope: {
id: { where: {
type: DataTypes.UUID, state: "publish",
defaultValue: DataTypes.UUIDV4, typeId: { [Sequelize.Op.ne]: 2 },
primaryKey: true,
}, },
name: { include: [
type: DataTypes.STRING, {
allowNull: false, model: sequelize.models.EventType,
}, as: "type",
description: { attributes: ["name", "title"],
type: DataTypes.STRING, },
}, {
campaign_text: { association: "location",
type: DataTypes.TEXT, attributes: ["country", "city", "country_code"],
allowNull: true
},
init_date: {
type: DataTypes.DATE,
allowNull: false,
},
end_date: {
type: DataTypes.DATE,
},
init_available_date: {
type: DataTypes.DATE,
},
end_available_date: {
type: DataTypes.DATE,
},
gmt: {
type: DataTypes.INTEGER,
defaultValue: 1,
},
assistants: {
type: DataTypes.INTEGER,
},
confirmed: {
type: DataTypes.INTEGER,
},
sold_out: { //Se han vendido todas y se ha abierto lista de espera si hay asignada
type: DataTypes.BOOLEAN,
defaultValue: false,
},
allow_multiple: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
multiple_limit: {
type: DataTypes.INTEGER,
},
allow_overflow: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
overflow_eventId: {
type: DataTypes.UUID,
foreignKey: true,
require: false, require: false,
}, },
state: { ],
type: DataTypes.STRING, },
allowNull: false, }
defaultValue: 'draft' );
},
stateCode: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['init_date', 'end_date', 'init_available_date', 'end_available_date', 'sold_out']),
get: function () {
return getStateCode(this);
},
},
stateText: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['init_date', 'end_date', 'init_available_date', 'end_available_date', 'sold_out']),
get: function () {
return getStateText(this);
},
},
typeId: {
type: DataTypes.UUID,
foreignKey: true,
},
venueId: {
type: DataTypes.UUID,
foreignKey: true,
},
locationId:{
type: DataTypes.UUID,
foreignKey: true,
},
url_streaming: {
type: DataTypes.STRING,
},
url_poll: {
type: DataTypes.STRING,
},
url_registration: {
type: DataTypes.STRING,
},
marketing_list: {
type: DataTypes.STRING,
},
userId: {
type: DataTypes.UUID,
foreignKey: true,
},
featured: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
virtual: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
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);
},
}
}, { Event.associate = function (models) {
tableName: 'events', Event.OverflowEvent = Event.belongsTo(models.Event, {
freezeTableName: true, as: "overflowEvent",
timestamps: true, foreignKey: "overflow_eventId",
required: false,
defaultScope: {
where: {
state: 'publish',
typeId: { [Sequelize.Op.ne]: 2 },
},
include: [{
model: sequelize.models.EventType,
as: 'type',
attributes: ['name', 'title'],
},
{
association: 'location',
attributes: ['country', 'city'],
require:false,
}],
},
}); });
Event.associate = function (models) {
Event.OverflowEvent = Event.belongsTo(models.Event, { Event.Type = Event.belongsTo(models.EventType, { foreignKey: "typeId", as: "type" });
as: 'overflowEvent', Event.UserCreate = Event.belongsTo(models.User, { foreignKey: "userId", as: "user" });
foreignKey: 'overflow_eventId', Event.Venue = Event.belongsTo(models.Venue, { foreignKey: "venueId", as: "venue", required: false });
required: false }); Event.Details = Event.hasMany(models.EventDetail, { foreignKey: "eventId", as: "details" });
Event.Location = Event.belongsTo(models.Location, { foreignKey: "locationId", as: "location" });
Event.Type = Event.belongsTo(models.EventType, { foreignKey: 'typeId', as: "type" }); //OJO antes de force comentar
Event.UserCreate = Event.belongsTo(models.User, { foreignKey: 'userId', as: "user" }); // OJO GENERA UN FOREIGN KEY Con eventos y habrá ID de otras entidades que no exitan en la tabla eventos, porque son post o speakers
Event.Venue = Event.belongsTo(models.Venue, { foreignKey: 'venueId', as: "venue", required: false}); Event.Comments = Event.hasMany(models.Comment, {
Event.Details = Event.hasMany(models.EventDetail, { foreignKey: 'eventId', as: "details" }); foreignKey: "entityId",
Event.Location = Event.belongsTo(models.Location, { foreignKey: 'locationId', as: "location" }); scope: {
entityName: "event",
},
as: "comments",
required: false,
});
//OJO antes de force comentar Event.Multimedias = Event.hasMany(models.Multimedia, {
// OJO GENERA UN FOREIGN KEY Con eventos y habrá ID de otras entidades que no exitan en la tabla eventos, porque son post o speakers foreignKey: "entityId",
Event.Comments = Event.hasMany(models.Comment, { as: { singular: "multimedia", plural: "multimedias" },
foreignKey: 'entityId', required: false,
scope: { });
entityName: 'event'
},
as: "comments",
required: false,
});
Event.Multimedias = Event.hasMany(models.Multimedia, { Event.Reservations = Event.hasMany(models.EventReservation, {
foreignKey: 'entityId', foreignKey: "eventId",
as: { singular: 'multimedia', plural: 'multimedias' }, as: "reservations",
required: false, required: false,
}); });
Event.Inscriptions = Event.hasMany(models.EventInscription, {
foreignKey: "eventId",
as: "inscriptions",
required: false,
});
Event.Questions = Event.hasMany(models.EventQuestion, {
foreignKey: "eventId",
as: "questions",
required: false,
});
};
Event.Reservations = Event.hasMany(models.EventReservation, { Event.addScope("featured", {
foreignKey: 'eventId', as: "reservations", where: {
required: false, featured: true,
}); },
Event.Inscriptions = Event.hasMany(models.EventInscription, { });
foreignKey: 'eventId', as: "inscriptions",
required: false, Event.addScope("includeVenue", () => {
}); return {
Event.Questions = Event.hasMany(models.EventQuestion, { include: [{ model: sequelize.models.Venue, as: "venue" }],
foreignKey: 'eventId', as: "questions" ,
required: false,
});
}; };
});
Event.addScope('featured', {
where: { Event.addScope("includeMultimedias", () => {
featured: true return {
include: [
{
model: sequelize.models.Multimedia,
as: { singular: "multimedia", plural: "multimedias" },
required: false,
include: [
{
model: sequelize.models.MultimediaFile,
as: "multimediaFile",
},
],
order: [["type", "ASC"]], // <- esto no funciona por ahora en Sequelize
}, },
}); ],
};
});
Event.addScope('includeVenue', () => { Event.addScope("includeMultimediaAvatar", () => {
return { return {
include: [ include: [
{ model: sequelize.models.Venue, as: 'venue' } {
] model: sequelize.models.Multimedia,
} as: { singular: "multimedia", plural: "multimedias" },
}); where: { type: "avatar" },
required: false,
Event.addScope('includeMultimedias', () => { include: [
return { {
include: [{ model: sequelize.models.MultimediaFile,
model: sequelize.models.Multimedia, as: "multimediaFile",
as: { singular: 'multimedia', plural: 'multimedias' },
required: false,
include : [{
model: sequelize.models.MultimediaFile,
as: "multimediaFile"
}],
order: [["type", "ASC"]], // <- esto no funciona por ahora en Sequelize
}, },
] ],
} },
}); ],
};
});
Event.addScope('includeMultimediaAvatar', () => { Event.addScope("includeInscription", (userId) => {
return { return {
include: [{ include: [
model: sequelize.models.Multimedia, { model: sequelize.models.EventInscription, as: "inscriptions", required: false, where: { userId: userId } },
as: { singular: 'multimedia', plural: 'multimedias' }, ],
where: { type: 'avatar'}, };
required: false, });
include: [{
model: sequelize.models.MultimediaFile,
as: "multimediaFile"
}]
},
]
}
});
Event.addScope('includeInscription', (userId) => { Event.addScope("includeOverflowEvent", () => {
return { return {
include: [ include: [
{ model: sequelize.models.EventInscription, as: 'inscriptions', {
required: false, model: sequelize.models.Event,
where: { userId: userId } } as: "overflowEvent",
] required: false,
} where: { typeId: { [Sequelize.Op.ne]: null } },
}); // attributes: ['assistants', 'confirmed'],
},
],
};
});
Event.addScope('includeOverflowEvent', () => { Event.addScope("includeDetails", () => {
return { return {
include: [ include: [
{ model: sequelize.models.Event, {
as: 'overflowEvent', model: sequelize.models.EventDetail,
as: "details",
required: false,
include: [
{
model: sequelize.models.Speaker,
as: "speaker",
required: false,
include: [
{
model: sequelize.models.Multimedia,
as: { singular: "multimedia", plural: "multimedias" },
required: false, required: false,
where: { typeId: { [Sequelize.Op.ne]: null}}, include: [
// attributes: ['assistants', 'confirmed'], {
} model: sequelize.models.MultimediaFile,
] as: "multimediaFile",
} },
}); ],
},
Event.addScope('includeDetails', () => { ],
return { },
include: [{ ],
model: sequelize.models.EventDetail,
as: 'details',
required: false,
include: [{
model: sequelize.models.Speaker,
as: 'speaker',
required: false,
include : [{
model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' },
required: false,
include: [{
model: sequelize.models.MultimediaFile,
as: "multimediaFile"
}]
}]
}]
}]
}
});
Event.addScope('includeComments', () => {
return {
include: [{
model: sequelize.models.Comment,
as: 'comments',
required: false,
include: [{
model: sequelize.models.User,
as: 'user',
}]
}]
}
});
Event.addScope('next', {
where: {
init_date: {
[Sequelize.Op.gte]: moment().add(1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss')
}
}, },
}); ],
};
});
Event.addScope('today', { Event.addScope("includeComments", () => {
where: { return {
init_date: { include: [
[Sequelize.Op.gte]: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss'), {
[Sequelize.Op.lt]: moment().add(1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'), model: sequelize.models.Comment,
} as: "comments",
} required: false,
}); include: [
{
Event.addScope('current', { model: sequelize.models.User,
where: { as: "user",
init_date: {
[Sequelize.Op.lte]: moment().format('YYYY-MM-DD HH:mm:ss'),
}, },
end_date:{ ],
[Sequelize.Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss'),
},
}
});
Event.addScope('tomorrow', {
where: {
init_date: {
[Sequelize.Op.gte]: moment().add(1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
[Sequelize.Op.lt]: moment().add(2, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
}
}
});
Event.addScope('yesterday', {
where: {
init_date: {
[Sequelize.Op.gte]: moment().add(-1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
[Sequelize.Op.lt]: moment().add('day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
}
}
});
Event.addScope('past', {
where: {
init_date: {
[Sequelize.Op.lt]: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')
}
}
});
Event.addScope('withOpenInscriptions', {
where: {
init_available_date: {
[Sequelize.Op.lte]: moment().format('YYYY-MM-DD HH:mm:ss')
},
end_available_date: {
[Sequelize.Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss')
}
}, },
}); ],
};
});
Event.addScope('CitiesOfEvents', () => { Event.addScope("next", {
return { where: {
include: [{ init_date: {
model: sequelize.models.Location, as: 'location', required: false, [Sequelize.Op.gte]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
include: [{ },
model: sequelize.models.Multimedia, as: { singular: 'multimedia', plural: 'multimedias' }, required: false, attributes: ['type'], },
include: [{ model: sequelize.models.MultimediaFile, as: "multimediaFile", attributes: ['name', 'description', 'class', 'provider', 'url'] },] });
}]
},
{ model: sequelize.models.EventType, as: 'type', attributes: ['name', 'title'] }],
group: ['location.country', 'location.city', 'Event.typeId',],
attributes: ['location.country', 'location.city', 'type.name', 'type.title', [sequelize.fn('COUNT', sequelize.col('Event.typeId')), 'ediciones'], [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']]
}
});
Event.addScope('onlyOfLocation', (location) => { Event.addScope("today", {
return { where: {
where: { locationId: { [Sequelize.Op.eq]: location } }, init_date: {
} [Sequelize.Op.gte]: moment().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
}); [Sequelize.Op.lt]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
},
},
});
Event.addScope("current", {
where: {
init_date: {
[Sequelize.Op.lte]: moment().format("YYYY-MM-DD HH:mm:ss"),
},
end_date: {
[Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"),
},
},
});
return Event; Event.addScope("tomorrow", {
}; where: {
init_date: {
[Sequelize.Op.gte]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
[Sequelize.Op.lt]: moment().add(2, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
},
},
});
Event.addScope("yesterday", {
where: {
init_date: {
[Sequelize.Op.gte]: moment().add(-1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
[Sequelize.Op.lt]: moment().add("day").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
},
},
});
Event.addScope("past", {
where: {
init_date: {
[Sequelize.Op.lt]: moment().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
},
},
});
Event.addScope("withOpenInscriptions", {
where: {
init_available_date: {
[Sequelize.Op.lte]: moment().format("YYYY-MM-DD HH:mm:ss"),
},
end_available_date: {
[Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"),
},
},
});
Event.addScope("CitiesOfEvents", () => {
return {
include: [
{
model: sequelize.models.Location,
as: "location",
required: false,
include: [
{
model: sequelize.models.Multimedia,
as: { singular: "multimedia", plural: "multimedias" },
required: false,
attributes: ["type"],
include: [
{
model: sequelize.models.MultimediaFile,
as: "multimediaFile",
attributes: ["name", "description", "class", "provider", "url"],
},
],
},
],
},
{ model: sequelize.models.EventType, as: "type", attributes: ["name", "title"] },
],
group: ["location.country", "location.city", "Event.typeId"],
attributes: [
"location.country",
"location.city",
"type.name",
"type.title",
[sequelize.fn("COUNT", sequelize.col("Event.typeId")), "ediciones"],
[sequelize.fn("SUM", sequelize.col("Event.assistants")), "assistants"],
],
};
});
Event.addScope("onlyOfLocation", (location) => {
return {
where: { locationId: { [Sequelize.Op.eq]: location } },
};
});
return Event;
};

View File

@ -64,6 +64,7 @@ routes.get(
}) })
); );
// Esta ruta se dejará de usar a favor de "/events/next_by_country"
routes.get( routes.get(
"/events/next", "/events/next",
isOptionalUser, isOptionalUser,
@ -78,11 +79,29 @@ routes.get(
if (isLogged) { if (isLogged) {
scopes.push({ method: ["includeInscription", req.user.id] }); scopes.push({ method: ["includeInscription", req.user.id] });
} }
// console.log(moment().add(1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'));
return eventController.find({ scopes })(req, res, next); return eventController.find({ scopes })(req, res, next);
} }
); );
// Sustituye a "/events/next" a partir de la versión de la APP 1.4.4
routes.get(
"/events/next_by_country",
isOptionalUser,
FieldMiddleware.middleware({
invalidFields: generalInvalidFields,
}),
PaginateMiddleware.middleware(),
SortMiddleware.middleware({ default: "init_available_date" }),
(req, res, next) => {
const isLogged = req.user && req.user.id;
const scopes = ["defaultScope", "next", "includeVenue", "includeMultimedias"];
if (isLogged) {
scopes.push({ method: ["includeInscription", req.user.id] });
}
return eventController.findNextEventsByCountry({ scopes })(req, res, next);
}
);
routes.get( routes.get(
"/events/past", "/events/past",
isOptionalUser, isOptionalUser,
@ -274,7 +293,7 @@ routes.get(
eventInscriptionController.getInscription eventInscriptionController.getInscription
); );
// Hacer una inscripción // Hacer una inscripción
routes.post( routes.post(
"/events/:id/inscriptions", "/events/:id/inscriptions",
isLoggedUser, isLoggedUser,
@ -285,7 +304,7 @@ routes.post(
eventReservationController.recuperateReservationByCode, eventReservationController.recuperateReservationByCode,
//Recupera a registra el usuario que se va a inscribir //Recupera a registra el usuario que se va a inscribir
authController.getOrCreateUser, authController.getOrCreateUser,
//Comprobamos si tiene ya una incripción, en tal caso, comprobamos el código de reserva sea el de la inscripcion hecha, //Comprobamos si tiene ya una incripción, en tal caso, comprobamos el código de reserva sea el de la inscripcion hecha,
//si no es así es el caso de un usuario que se reinscribe con otro código de reserva //si no es así es el caso de un usuario que se reinscribe con otro código de reserva
eventInscriptionController.checkInscriptionByUser, eventInscriptionController.checkInscriptionByUser,
//Si es un usuario tutor y solicita un group_size se crea la reserva //Si es un usuario tutor y solicita un group_size se crea la reserva
@ -357,7 +376,7 @@ routes.post(
eventReservationController.recuperateReservationByCode, eventReservationController.recuperateReservationByCode,
//Recupera a registra el usuario que se va a inscribir //Recupera a registra el usuario que se va a inscribir
authController.getOrCreateUser, authController.getOrCreateUser,
//Comprobamos si tiene ya una incripción, en tal caso, comprobamos el código de reserva sea el de la inscripcion hecha, //Comprobamos si tiene ya una incripción, en tal caso, comprobamos el código de reserva sea el de la inscripcion hecha,
//si no es así es el caso de un usuario que se reinscribe con otro código de reserva //si no es así es el caso de un usuario que se reinscribe con otro código de reserva
eventInscriptionController.checkInscriptionByUser, eventInscriptionController.checkInscriptionByUser,
//Al ser via web siempre será inscripción con codigo de reserva //Al ser via web siempre será inscripción con codigo de reserva
@ -535,8 +554,8 @@ routes.put(
"/admin/reservations/:id", "/admin/reservations/:id",
isAdministratorUser, isAdministratorUser,
//SchemaValidator(eventValidation.ReservationInputType, true), //SchemaValidator(eventValidation.ReservationInputType, true),
eventReservationController.checkAssitantsUpdate, eventReservationController.checkAssitantsUpdate,
eventReservationController.update() eventReservationController.update()
); );
routes.put( routes.put(

View File

@ -46,9 +46,10 @@ async function activeReservation(reservation) {
} }
reservation.state = "publish"; reservation.state = "publish";
//Finalmente hay que validar la inscripción del tutor //Finalmente hay que validar la inscripción del tutor en el caso de aquellos centros que no son aliados
if ((await eventInscriptionService._validateInscriptionTutorOfReservation(reservation.id, reservation.userId)) <= 0) { if ((await eventInscriptionService._validateInscriptionTutorOfReservation(reservation.id, reservation.userId)) <= 0) {
console.log("No se ha podido validar la inscripción del tutor por ser de un centro aliado se hace a posteriori en este caso"); //En el caso de ser un centro aliado no se puede validar la inscripcion ya que se hace a posteriori por lo tanto no se hace nada
// console.log("No se ha podido validar la inscripción del tutor por ser de un centro aliado se hace a posteriori en este caso");
// return null; // return null;
} }

View File

@ -1,93 +1,109 @@
const Sequelize = require('sequelize'); const Sequelize = require("sequelize");
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const Location = sequelize.define('Location', { const Location = sequelize.define(
id: { "Location",
type: DataTypes.UUID, {
defaultValue: DataTypes.UUIDV4, id: {
primaryKey: true, type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
country: {
type: DataTypes.STRING(125),
allowNull: false,
},
city: {
type: DataTypes.STRING(125),
allowNull: false,
},
description: {
type: DataTypes.STRING,
},
country_code: {
type: DataTypes.STRING(2),
default: "ES",
},
},
{
tableName: "locations",
freezeTableName: true,
timestamps: true,
indexes: [
{
unique: true,
fields: ["country", "city"],
}, },
country: { {
type: DataTypes.STRING(125), unique: false,
allowNull: false, fields: ["country_code"],
}, },
city: { ],
type: DataTypes.STRING(125), }
allowNull: false, );
},
description: { Location.associate = function (models) {
type: DataTypes.STRING, Location.Events = Location.hasMany(models.Event, { as: "events", foreignKey: "locationId" });
},
}, { //OJO antes de force comentar
tableName: 'locations', // OJO GENERA UN FOREIGN KEY Con eventos y habrá ID de otras entidades que no exitan en la tabla eventos, porque son post o speakers
freezeTableName: true, Location.Multimedias = Location.hasMany(models.Multimedia, {
timestamps: true, foreignKey: "entityId",
indexes: [{ as: { singular: "multimedia", plural: "multimedias" },
unique: true,
fields: ['country', 'city']
}]
}); });
};
Location.associate = function (models) { Location.addScope("includeMultimedias", () => {
Location.Events = Location.hasMany(models.Event, {as: 'events', foreignKey: 'locationId'}); return {
include: [
//OJO antes de force comentar {
// OJO GENERA UN FOREIGN KEY Con eventos y habrá ID de otras entidades que no exitan en la tabla eventos, porque son post o speakers model: sequelize.models.Multimedia,
Location.Multimedias = Location.hasMany(models.Multimedia, { as: { singular: "multimedia", plural: "multimedias" },
foreignKey: 'entityId', required: false,
as: { singular: 'multimedia', plural: 'multimedias' }, include: [
}); {
model: sequelize.models.MultimediaFile,
as: "multimediaFile",
},
],
},
],
}; };
});
Location.addScope('includeMultimedias', () => { Location.addScope("includeEvents", () => {
return { return {
include: [{ include: [
model: sequelize.models.Multimedia, {
as: { singular: 'multimedia', plural: 'multimedias' }, model: sequelize.models.Event,
required: false, as: "events",
include: [{ required: false,
model: sequelize.models.MultimediaFile, // group: ['typeId'],
as: "multimediaFile" // attributes: ['name', 'type.title',] //[sequelize.fn('COUNT', sequelize.col('events.typeId')), 'ediciones'],] // [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']]
}] // attributes: [[sequelize.fn('COUNT', sequelize.col('typeId')), 'ediciones'],] // [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']]
}, // include: [{
] // model: sequelize.models.MultimediaFile,
} // as: "multimediaFile"
}); // }]
},
],
};
});
Location.addScope("includeGroupEvents", () => {
return {
include: [
{
as: "events",
required: false,
// include: [{
// model: sequelize.models.MultimediaFile,
// as: "multimediaFile"
// }]
},
],
};
});
Location.addScope('includeEvents', () => { return Location;
return { };
include: [{
model: sequelize.models.Event,
as: 'events',
required: false,
// group: ['typeId'],
// attributes: ['name', 'type.title',] //[sequelize.fn('COUNT', sequelize.col('events.typeId')), 'ediciones'],] // [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']]
// attributes: [[sequelize.fn('COUNT', sequelize.col('typeId')), 'ediciones'],] // [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']]
// include: [{
// model: sequelize.models.MultimediaFile,
// as: "multimediaFile"
// }]
},
]
}
});
Location.addScope('includeGroupEvents', () => {
return {
include: [{
as: 'events',
required: false,
// include: [{
// model: sequelize.models.MultimediaFile,
// as: "multimediaFile"
// }]
},
]
}
});
return Location;
};

View File

@ -118,7 +118,7 @@ const extraControllers = {
* "segment": "ALL" | "ALL_VALIDATED" | "ALL_NOT_VALIDATED" | * "segment": "ALL" | "ALL_VALIDATED" | "ALL_NOT_VALIDATED" |
* "PARTNERS_ALL" | "PARTNERS_VALIDATED" | "PARTNERS_NOT_VALIDATED" | * "PARTNERS_ALL" | "PARTNERS_VALIDATED" | "PARTNERS_NOT_VALIDATED" |
* "COLLEGE_ALL" | "COLLEGE_VALIDATED" | "COLLEGE_NOT_VALIDATED" * "COLLEGE_ALL" | "COLLEGE_VALIDATED" | "COLLEGE_NOT_VALIDATED"
* OPCION 3 - A todos los dispositivos activos * OPCION 3 - A todos los dispositivos activos de un país
* "deviceIds": ["*" | "ExponentPushToken[YbOS1AIZjQbchZbxNaVRqC]", ...] * "deviceIds": ["*" | "ExponentPushToken[YbOS1AIZjQbchZbxNaVRqC]", ...]
* "country": "*" | "ES" | "MX" * "country": "*" | "ES" | "MX"
* }, * },

View File

@ -1,6 +1,6 @@
{ {
"name": "lqdvi-api3", "name": "lqdvi-api3",
"version": "1.4.1", "version": "1.4.4",
"description": "", "description": "",
"author": "Rodax Software", "author": "Rodax Software",
"license": "ISC", "license": "ISC",