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());
@ -46,11 +51,20 @@ app.use(helmet());
//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);

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,7 +1,7 @@
'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(),
@ -11,32 +11,28 @@ const getStateCode = (event) => {
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 { } else {
if (endDate.isBefore(currentDate)) { if (endDate.isBefore(currentDate)) {
return 'closed_event'; return "closed_event";
} else { } else {
if (currentDate.isBefore(init_availableDate)) { if (currentDate.isBefore(init_availableDate)) {
return 'future_registrations' return "future_registrations";
} else { } else {
if (currentDate.isBetween(init_availableDate, end_availableDate)) { if (currentDate.isBetween(init_availableDate, end_availableDate)) {
if (event.url_registration) { if (event.url_registration) {
return 'url_registrations_open'; return "url_registrations_open";
} else { } else {
return (event.sold_out == 1) ? 'waitinglist_open' : 'registrations_open'; return event.sold_out == 1 ? "waitinglist_open" : "registrations_open";
}
} else {
if (currentDate.isAfter(end_availableDate)) return "closed_registrations";
else return "N/A";
} }
} }
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(),
@ -46,60 +42,57 @@ const getStateText = (event) => {
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 { } else {
if (endDate.isBefore(currentDate)) { if (endDate.isBefore(currentDate)) {
return 'Congreso finalizado'; return "Congreso finalizado";
} else { } else {
if (currentDate.isBefore(init_availableDate)) { if (currentDate.isBefore(init_availableDate)) {
return 'Inscripciones a partir del ' + init_availableDate.format('D [de] MMMM'); return "Inscripciones a partir del " + init_availableDate.format("D [de] MMMM");
} else { } else {
if (currentDate.isBetween(init_availableDate, end_availableDate)) { if (currentDate.isBetween(init_availableDate, end_availableDate)) {
if (event.url_registration) { if (event.url_registration) {
return 'Inscripciones abiertas'; return "Inscripciones abiertas";
} else { } else {
return (event.sold_out == 1) ? 'Inscripciones abiertas a lista de espera' : 'Inscripciones abiertas'; 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";
} }
} }
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 { } else {
return 'online'; return "online";
} }
} else { } else {
return 'onsite'; 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 { } else {
return 'evento online'; return "evento online";
} }
} else { } else {
return 'evento presencial'; return "evento presencial";
} }
}; };
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const Event = sequelize.define(
const Event = sequelize.define('Event', { "Event",
{
id: { id: {
type: DataTypes.UUID, type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4, defaultValue: DataTypes.UUIDV4,
@ -114,7 +107,7 @@ module.exports = function (sequelize, DataTypes) {
}, },
campaign_text: { campaign_text: {
type: DataTypes.TEXT, type: DataTypes.TEXT,
allowNull: true allowNull: true,
}, },
init_date: { init_date: {
type: DataTypes.DATE, type: DataTypes.DATE,
@ -139,7 +132,8 @@ module.exports = function (sequelize, DataTypes) {
confirmed: { confirmed: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
}, },
sold_out: { //Se han vendido todas y se ha abierto lista de espera si hay asignada sold_out: {
//Se han vendido todas y se ha abierto lista de espera si hay asignada
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
defaultValue: false, defaultValue: false,
}, },
@ -164,16 +158,28 @@ module.exports = function (sequelize, DataTypes) {
state: { state: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: 'draft' defaultValue: "draft",
}, },
stateCode: { stateCode: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['init_date', 'end_date', 'init_available_date', 'end_available_date', 'sold_out']), type: Sequelize.VIRTUAL(Sequelize.STRING, [
"init_date",
"end_date",
"init_available_date",
"end_available_date",
"sold_out",
]),
get: function () { get: function () {
return getStateCode(this); return getStateCode(this);
}, },
}, },
stateText: { stateText: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['init_date', 'end_date', 'init_available_date', 'end_available_date', 'sold_out']), type: Sequelize.VIRTUAL(Sequelize.STRING, [
"init_date",
"end_date",
"init_available_date",
"end_available_date",
"sold_out",
]),
get: function () { get: function () {
return getStateText(this); return getStateText(this);
}, },
@ -219,278 +225,320 @@ module.exports = function (sequelize, DataTypes) {
defaultValue: true, defaultValue: true,
}, },
assistanceType: { assistanceType: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['virtual', 'assistants']), type: Sequelize.VIRTUAL(Sequelize.STRING, ["virtual", "assistants"]),
get: function () { get: function () {
return getAssistanceType(this); return getAssistanceType(this);
}, },
}, },
assistanceTypeText: { assistanceTypeText: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['virtual', 'assistants']), type: Sequelize.VIRTUAL(Sequelize.STRING, ["virtual", "assistants"]),
get: function () { get: function () {
return getAssistanceTypeText(this); return getAssistanceTypeText(this);
}, },
} },
},
}, { {
tableName: 'events', tableName: "events",
freezeTableName: true, freezeTableName: true,
timestamps: true, timestamps: true,
defaultScope: { defaultScope: {
where: { where: {
state: 'publish', state: "publish",
typeId: { [Sequelize.Op.ne]: 2 }, typeId: { [Sequelize.Op.ne]: 2 },
}, },
include: [{ include: [
{
model: sequelize.models.EventType, model: sequelize.models.EventType,
as: 'type', as: "type",
attributes: ['name', 'title'], attributes: ["name", "title"],
}, },
{ {
association: 'location', association: "location",
attributes: ['country', 'city'], attributes: ["country", "city", "country_code"],
require: false, require: false,
}],
}, },
}); ],
},
}
);
Event.associate = function (models) { Event.associate = function (models) {
Event.OverflowEvent = Event.belongsTo(models.Event, { Event.OverflowEvent = Event.belongsTo(models.Event, {
as: 'overflowEvent', as: "overflowEvent",
foreignKey: 'overflow_eventId', foreignKey: "overflow_eventId",
required: false }); required: false,
});
Event.Type = Event.belongsTo(models.EventType, { foreignKey: 'typeId', as: "type" }); Event.Type = Event.belongsTo(models.EventType, { foreignKey: "typeId", as: "type" });
Event.UserCreate = Event.belongsTo(models.User, { foreignKey: 'userId', as: "user" }); Event.UserCreate = Event.belongsTo(models.User, { foreignKey: "userId", as: "user" });
Event.Venue = Event.belongsTo(models.Venue, { foreignKey: 'venueId', as: "venue", required: false}); Event.Venue = Event.belongsTo(models.Venue, { foreignKey: "venueId", as: "venue", required: false });
Event.Details = Event.hasMany(models.EventDetail, { foreignKey: 'eventId', as: "details" }); Event.Details = Event.hasMany(models.EventDetail, { foreignKey: "eventId", as: "details" });
Event.Location = Event.belongsTo(models.Location, { foreignKey: 'locationId', as: "location" }); Event.Location = Event.belongsTo(models.Location, { foreignKey: "locationId", as: "location" });
//OJO antes de force comentar //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 // 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.Comments = Event.hasMany(models.Comment, { Event.Comments = Event.hasMany(models.Comment, {
foreignKey: 'entityId', foreignKey: "entityId",
scope: { scope: {
entityName: 'event' entityName: "event",
}, },
as: "comments", as: "comments",
required: false, required: false,
}); });
Event.Multimedias = Event.hasMany(models.Multimedia, { Event.Multimedias = Event.hasMany(models.Multimedia, {
foreignKey: 'entityId', foreignKey: "entityId",
as: { singular: 'multimedia', plural: 'multimedias' }, as: { singular: "multimedia", plural: "multimedias" },
required: false, required: false,
}); });
Event.Reservations = Event.hasMany(models.EventReservation, { Event.Reservations = Event.hasMany(models.EventReservation, {
foreignKey: 'eventId', as: "reservations", foreignKey: "eventId",
as: "reservations",
required: false, required: false,
}); });
Event.Inscriptions = Event.hasMany(models.EventInscription, { Event.Inscriptions = Event.hasMany(models.EventInscription, {
foreignKey: 'eventId', as: "inscriptions", foreignKey: "eventId",
as: "inscriptions",
required: false, required: false,
}); });
Event.Questions = Event.hasMany(models.EventQuestion, { Event.Questions = Event.hasMany(models.EventQuestion, {
foreignKey: 'eventId', as: "questions" , foreignKey: "eventId",
as: "questions",
required: false, required: false,
}); });
}; };
Event.addScope('featured', { Event.addScope("featured", {
where: { where: {
featured: true featured: true,
}, },
}); });
Event.addScope('includeVenue', () => { Event.addScope("includeVenue", () => {
return { return {
include: [ include: [{ model: sequelize.models.Venue, as: "venue" }],
{ model: sequelize.models.Venue, as: 'venue' } };
]
}
}); });
Event.addScope('includeMultimedias', () => { Event.addScope("includeMultimedias", () => {
return { return {
include: [{ include: [
{
model: sequelize.models.Multimedia, model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' }, as: { singular: "multimedia", plural: "multimedias" },
required: false, required: false,
include : [{ include: [
{
model: sequelize.models.MultimediaFile, model: sequelize.models.MultimediaFile,
as: "multimediaFile" as: "multimediaFile",
}], },
],
order: [["type", "ASC"]], // <- esto no funciona por ahora en Sequelize order: [["type", "ASC"]], // <- esto no funciona por ahora en Sequelize
}, },
] ],
} };
}); });
Event.addScope('includeMultimediaAvatar', () => { Event.addScope("includeMultimediaAvatar", () => {
return { return {
include: [{ include: [
{
model: sequelize.models.Multimedia, model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' }, as: { singular: "multimedia", plural: "multimedias" },
where: { type: 'avatar'}, where: { type: "avatar" },
required: false, required: false,
include: [{ include: [
{
model: sequelize.models.MultimediaFile, model: sequelize.models.MultimediaFile,
as: "multimediaFile" as: "multimediaFile",
}]
}, },
] ],
} },
],
};
}); });
Event.addScope('includeInscription', (userId) => { Event.addScope("includeInscription", (userId) => {
return { return {
include: [ include: [
{ model: sequelize.models.EventInscription, as: 'inscriptions', { model: sequelize.models.EventInscription, as: "inscriptions", required: false, where: { userId: userId } },
required: false, ],
where: { userId: userId } } };
]
}
}); });
Event.addScope('includeOverflowEvent', () => { Event.addScope("includeOverflowEvent", () => {
return { return {
include: [ include: [
{ model: sequelize.models.Event, {
as: 'overflowEvent', model: sequelize.models.Event,
as: "overflowEvent",
required: false, required: false,
where: { typeId: { [Sequelize.Op.ne]: null } }, where: { typeId: { [Sequelize.Op.ne]: null } },
// attributes: ['assistants', 'confirmed'], // attributes: ['assistants', 'confirmed'],
} },
] ],
} };
}); });
Event.addScope('includeDetails', () => { Event.addScope("includeDetails", () => {
return { return {
include: [{ include: [
{
model: sequelize.models.EventDetail, model: sequelize.models.EventDetail,
as: 'details', as: "details",
required: false, required: false,
include: [{ include: [
{
model: sequelize.models.Speaker, model: sequelize.models.Speaker,
as: 'speaker', as: "speaker",
required: false, required: false,
include : [{ include: [
{
model: sequelize.models.Multimedia, model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' }, as: { singular: "multimedia", plural: "multimedias" },
required: false, required: false,
include: [{ include: [
{
model: sequelize.models.MultimediaFile, model: sequelize.models.MultimediaFile,
as: "multimediaFile" as: "multimediaFile",
}] },
}] ],
}] },
}] ],
} },
],
},
],
};
}); });
Event.addScope('includeComments', () => { Event.addScope("includeComments", () => {
return { return {
include: [{ include: [
{
model: sequelize.models.Comment, model: sequelize.models.Comment,
as: 'comments', as: "comments",
required: false, required: false,
include: [{ include: [
{
model: sequelize.models.User, model: sequelize.models.User,
as: 'user', as: "user",
}] },
}] ],
} },
],
};
}); });
Event.addScope('next', { Event.addScope("next", {
where: { where: {
init_date: { init_date: {
[Sequelize.Op.gte]: moment().add(1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss') [Sequelize.Op.gte]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
} },
}, },
}); });
Event.addScope('today', { Event.addScope("today", {
where: { where: {
init_date: { init_date: {
[Sequelize.Op.gte]: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss'), [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'), [Sequelize.Op.lt]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
} },
} },
}); });
Event.addScope('current', { Event.addScope("current", {
where: { where: {
init_date: { init_date: {
[Sequelize.Op.lte]: moment().format('YYYY-MM-DD HH:mm:ss'), [Sequelize.Op.lte]: moment().format("YYYY-MM-DD HH:mm:ss"),
}, },
end_date: { end_date: {
[Sequelize.Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss'), [Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"),
},
}, },
}
}); });
Event.addScope('tomorrow', { Event.addScope("tomorrow", {
where: { where: {
init_date: { init_date: {
[Sequelize.Op.gte]: moment().add(1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'), [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'), [Sequelize.Op.lt]: moment().add(2, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
} },
} },
}); });
Event.addScope('yesterday', { Event.addScope("yesterday", {
where: { where: {
init_date: { init_date: {
[Sequelize.Op.gte]: moment().add(-1, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss'), [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'), [Sequelize.Op.lt]: moment().add("day").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
} },
} },
}); });
Event.addScope('past', { Event.addScope("past", {
where: { where: {
init_date: { init_date: {
[Sequelize.Op.lt]: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss') [Sequelize.Op.lt]: moment().startOf("day").format("YYYY-MM-DD HH:mm:ss"),
} },
} },
}); });
Event.addScope('withOpenInscriptions', { Event.addScope("withOpenInscriptions", {
where: { where: {
init_available_date: { init_available_date: {
[Sequelize.Op.lte]: moment().format('YYYY-MM-DD HH:mm:ss') [Sequelize.Op.lte]: moment().format("YYYY-MM-DD HH:mm:ss"),
}, },
end_available_date: { end_available_date: {
[Sequelize.Op.gt]: moment().format('YYYY-MM-DD HH:mm:ss') [Sequelize.Op.gt]: moment().format("YYYY-MM-DD HH:mm:ss"),
} },
}, },
}); });
Event.addScope('CitiesOfEvents', () => { Event.addScope("CitiesOfEvents", () => {
return { return {
include: [{ include: [
model: sequelize.models.Location, as: 'location', required: false, {
include: [{ model: sequelize.models.Location,
model: sequelize.models.Multimedia, as: { singular: 'multimedia', plural: 'multimedias' }, required: false, attributes: ['type'], as: "location",
include: [{ model: sequelize.models.MultimediaFile, as: "multimediaFile", attributes: ['name', 'description', 'class', 'provider', 'url'] },] 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']] ],
} },
{ 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("onlyOfLocation", (location) => {
return { return {
where: { locationId: { [Sequelize.Op.eq]: location } }, where: { locationId: { [Sequelize.Op.eq]: location } },
} };
}); });
return Event; 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,

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,7 +1,9 @@
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(
"Location",
{
id: { id: {
type: DataTypes.UUID, type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4, defaultValue: DataTypes.UUIDV4,
@ -18,48 +20,63 @@ module.exports = function (sequelize, DataTypes) {
description: { description: {
type: DataTypes.STRING, type: DataTypes.STRING,
}, },
}, { country_code: {
tableName: 'locations', type: DataTypes.STRING(2),
default: "ES",
},
},
{
tableName: "locations",
freezeTableName: true, freezeTableName: true,
timestamps: true, timestamps: true,
indexes: [{ indexes: [
{
unique: true, unique: true,
fields: ['country', 'city'] fields: ["country", "city"],
}] },
}); {
unique: false,
fields: ["country_code"],
},
],
}
);
Location.associate = function (models) { Location.associate = function (models) {
Location.Events = Location.hasMany(models.Event, {as: 'events', foreignKey: 'locationId'}); Location.Events = Location.hasMany(models.Event, { as: "events", foreignKey: "locationId" });
//OJO antes de force comentar //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 // 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
Location.Multimedias = Location.hasMany(models.Multimedia, { Location.Multimedias = Location.hasMany(models.Multimedia, {
foreignKey: 'entityId', foreignKey: "entityId",
as: { singular: 'multimedia', plural: 'multimedias' }, as: { singular: "multimedia", plural: "multimedias" },
}); });
}; };
Location.addScope('includeMultimedias', () => { Location.addScope("includeMultimedias", () => {
return { return {
include: [{ include: [
{
model: sequelize.models.Multimedia, model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' }, as: { singular: "multimedia", plural: "multimedias" },
required: false, required: false,
include: [{ include: [
{
model: sequelize.models.MultimediaFile, model: sequelize.models.MultimediaFile,
as: "multimediaFile" as: "multimediaFile",
}]
}, },
] ],
} },
],
};
}); });
Location.addScope("includeEvents", () => {
Location.addScope('includeEvents', () => {
return { return {
include: [{ include: [
{
model: sequelize.models.Event, model: sequelize.models.Event,
as: 'events', as: "events",
required: false, required: false,
// group: ['typeId'], // group: ['typeId'],
// attributes: ['name', 'type.title',] //[sequelize.fn('COUNT', sequelize.col('events.typeId')), 'ediciones'],] // [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']] // attributes: ['name', 'type.title',] //[sequelize.fn('COUNT', sequelize.col('events.typeId')), 'ediciones'],] // [sequelize.fn('SUM', sequelize.col('Event.assistants')), 'assistants']]
@ -69,25 +86,24 @@ module.exports = function (sequelize, DataTypes) {
// as: "multimediaFile" // as: "multimediaFile"
// }] // }]
}, },
] ],
} };
}); });
Location.addScope('includeGroupEvents', () => { Location.addScope("includeGroupEvents", () => {
return { return {
include: [{ include: [
{
as: 'events', as: "events",
required: false, required: false,
// include: [{ // include: [{
// model: sequelize.models.MultimediaFile, // model: sequelize.models.MultimediaFile,
// as: "multimediaFile" // as: "multimediaFile"
// }] // }]
}, },
] ],
} };
}); });
return Location; 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",