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.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 bodyParser = require('body-parser');
const compress = require('compression');
const responseTime = require('response-time');
const methodOverride = require('method-override');
const cors = require('cors');
const helmet = require('helmet');
const passport = require('passport');
const bodyParser = require("body-parser");
const compress = require("compression");
const responseTime = require("response-time");
const methodOverride = require("method-override");
const cors = require("cors");
const helmet = require("helmet");
const passport = require("passport");
const config = require('../config');
const router = require('./router');
const error = require('../middlewares/error');
const config = require("../config");
const router = require("./router");
const error = require("../middlewares/error");
const deviceCountryMiddleware = require("../middlewares/deviceCountry");
/**
* Express instance
@ -24,10 +26,13 @@ const app = express();
//app.use(morgan(logs));
// parse body params and attache them to req.body
app.use(bodyParser.json({ limit: '5mb' }));
app.use(bodyParser.urlencoded({
limit: '5mb', extended: true
}));
app.use(bodyParser.json({ limit: "5mb" }));
app.use(
bodyParser.urlencoded({
limit: "5mb",
extended: true,
})
);
// set up the response-time middleware
app.use(responseTime());
@ -43,14 +48,23 @@ app.use(methodOverride());
app.use(helmet());
// 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
app.use(cors({
exposedHeaders: ['Content-Disposition', 'Content-Type', 'Content-Length',
'X-Total-Count', 'Pagination-Count', 'Pagination-Page', 'Pagination-Limit'],
}));
app.use(
cors({
exposedHeaders: [
"X-Country",
"Content-Disposition",
"Content-Type",
"Content-Length",
"X-Total-Count",
"Pagination-Count",
"Pagination-Page",
"Pagination-Limit",
],
})
);
/*app.use(cors({
origin: function (origin, callback) {
@ -74,7 +88,6 @@ app.use(cors({
}
}));*/
/*app.use(cors({
origin: '*',
exposeHeaders: [
@ -113,14 +126,14 @@ app.use(cors({
],
}));*/
app.use(deviceCountryMiddleware.middleware());
// Access validator
app.use(passport.initialize());
require('./passport');
require("./passport");
// Set routes
app.use('/api', router());
app.use("/api", router());
// if error is not an instanceOf APIError, convert it.
app.use(error.converter);
@ -131,4 +144,4 @@ app.use(error.notFound);
// error handler, send stacktrace only during development
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 httpStatus = require("http-status");
const generateControllers = require("../../core/controllers");
const { defaultOptions, buildContext } = require("../../core/controllers");
const QRHelper = require("../../helpers/qr.helper");
const emailHelper = require("../../helpers/mail.helper");
const notificationHelper = require("../../helpers/notification.helpers");
@ -31,7 +32,7 @@ const MODULE_NAME = "[event.controller]";
const controllerOptions = {
MODULE_NAME,
findOneCallback: eventInscriptionService._fillInscriptionsColor
findOneCallback: eventInscriptionService._fillInscriptionsColor,
};
function generateMemberInscription(user, inscription, reservation) {
@ -61,8 +62,6 @@ function generateMemberInscription(user, inscription, reservation) {
return memberInscription;
}
const extraControllers = {
checkCapacity: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {});
@ -72,7 +71,7 @@ const extraControllers = {
allow: false,
error: undefined,
};
console.log('>>>>>>>>>>>>>>>>>>>>>>>checkCapacity', result);
console.log(">>>>>>>>>>>>>>>>>>>>>>>checkCapacity", result);
if (!result.eventId) {
return handleResultResponse(null, null, params, res, httpStatus.BAD_REQUEST);
@ -123,8 +122,6 @@ const extraControllers = {
const userId = req.user.id;
var result = null;
console.log(params, req.user.level);
if (eventId) {
try {
@ -138,7 +135,7 @@ const extraControllers = {
} else {
try {
result = await eventInscriptionService._getInscriptionsUser(userId);
result = result.map(row => row.toJSON());
result = result.map((row) => row.toJSON());
// Asigno colores a las entradas normales
result = eventInscriptionService._fillInscriptionsColor(result);
return handleResultResponse(result, null, params, res, result === null ? httpStatus.NOT_FOUND : httpStatus.OK);
@ -156,8 +153,7 @@ const extraControllers = {
const userId = req.user.id;
var result = null;
if (!eventId)
return handleResultResponse("Es necesario el ID del evento", null, params, res, httpStatus.NOT_FOUND);
if (!eventId) return handleResultResponse("Es necesario el ID del evento", null, params, res, httpStatus.NOT_FOUND);
try {
result = await eventInscriptionService._getInscriptionOnlineByEvent(eventId);
@ -167,26 +163,53 @@ const extraControllers = {
} catch (error) {
return handleErrorResponse(MODULE_NAME, "getInscriptionsOnline", error, res);
}
},
getInscriptionsOfNextEventsCount: async (req, res, next) => {
const params = extractParamsFromRequest(req, res, {});
const userId = req.user.id;
try {
const result = await eventInscriptionService._getInscriptionsOfNextEventsUser(userId);
console.log("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
return handleResultResponse({ count: result }, null, params, res, httpStatus.OK);
} catch (error) {
console.log("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
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) => {
const params = extractParamsFromRequest(req, res, {});
@ -326,11 +349,15 @@ const extraControllers = {
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>><syncronizeMarketingList");
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) => {
const params = extractParamsFromRequest(req, res, {});
const inscriptionId = params.params.id;
@ -381,7 +408,8 @@ const extraControllers = {
//console.log(headerMail, bodyMail);
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));
} catch (error) {
console.log("No se ha podido mandar email con entrada");

View File

@ -1,496 +1,544 @@
'use strict';
const moment = require('moment');
const Sequelize = require('sequelize');
moment.locale('es');
"use strict";
const moment = require("moment");
const Sequelize = require("sequelize");
moment.locale("es");
const getStateCode = (event) => {
var currentDate = moment(),
initDate = moment(event.init_date),
endDate = moment(event.end_date),
init_availableDate = moment(event.init_available_date),
end_availableDate = moment(event.end_available_date);
var currentDate = moment(),
initDate = moment(event.init_date),
endDate = moment(event.end_date),
init_availableDate = moment(event.init_available_date),
end_availableDate = moment(event.end_available_date);
if (currentDate.isBetween(initDate, endDate)) {
return 'current_event';
if (currentDate.isBetween(initDate, endDate)) {
return "current_event";
} else {
if (endDate.isBefore(currentDate)) {
return "closed_event";
} else {
if (endDate.isBefore(currentDate)) {
return 'closed_event';
if (currentDate.isBefore(init_availableDate)) {
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 {
if (currentDate.isBefore(init_availableDate)){
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 {
if (currentDate.isAfter(end_availableDate))
return 'closed_registrations'
else
return 'N/A';
}
}
if (currentDate.isAfter(end_availableDate)) return "closed_registrations";
else return "N/A";
}
};
}
}
}
};
const getStateText = (event) => {
var currentDate = moment(),
initDate = moment(event.init_date),
endDate = moment(event.end_date),
init_availableDate = moment(event.init_available_date),
end_availableDate = moment(event.end_available_date);
var currentDate = moment(),
initDate = moment(event.init_date),
endDate = moment(event.end_date),
init_availableDate = moment(event.init_available_date),
end_availableDate = moment(event.end_available_date);
if (currentDate.isBetween(initDate, endDate)) {
return 'Congreso en curso';
if (currentDate.isBetween(initDate, endDate)) {
return "Congreso en curso";
} else {
if (endDate.isBefore(currentDate)) {
return "Congreso finalizado";
} else {
if (endDate.isBefore(currentDate)) {
return 'Congreso finalizado';
if (currentDate.isBefore(init_availableDate)) {
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 {
if (currentDate.isBefore(init_availableDate)) {
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 {
if (currentDate.isAfter(end_availableDate))
return 'Inscripciones cerradas'
else
return 'N/A';
}
}
if (currentDate.isAfter(end_availableDate)) return "Inscripciones cerradas";
else return "N/A";
}
};
}
}
}
};
const getAssistanceType = (event) => {
if (event.virtual) {
if (event.assistants > 0) {
return 'onsite, online';
} else {
return 'online';
}
if (event.virtual) {
if (event.assistants > 0) {
return "onsite, online";
} else {
return 'onsite';
return "online";
}
} else {
return "onsite";
}
};
const getAssistanceTypeText = (event) => {
if (event.virtual) {
if (event.assistants > 0) {
return 'evento presencial y online';
} else {
return 'evento online';
}
if (event.virtual) {
if (event.assistants > 0) {
return "evento presencial y online";
} else {
return 'evento presencial';
return "evento online";
}
} else {
return "evento presencial";
}
};
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', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
defaultScope: {
where: {
state: "publish",
typeId: { [Sequelize.Op.ne]: 2 },
},
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,
include: [
{
model: sequelize.models.EventType,
as: "type",
attributes: ["name", "title"],
},
{
association: "location",
attributes: ["country", "city", "country_code"],
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,
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, {
as: "overflowEvent",
foreignKey: "overflow_eventId",
required: false,
});
Event.associate = function (models) {
Event.OverflowEvent = Event.belongsTo(models.Event, {
as: 'overflowEvent',
foreignKey: 'overflow_eventId',
required: false });
Event.Type = Event.belongsTo(models.EventType, { foreignKey: "typeId", as: "type" });
Event.UserCreate = Event.belongsTo(models.User, { foreignKey: "userId", as: "user" });
Event.Venue = Event.belongsTo(models.Venue, { foreignKey: "venueId", as: "venue", 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" });
Event.UserCreate = Event.belongsTo(models.User, { foreignKey: 'userId', as: "user" });
Event.Venue = Event.belongsTo(models.Venue, { foreignKey: 'venueId', as: "venue", required: false});
Event.Details = Event.hasMany(models.EventDetail, { foreignKey: 'eventId', as: "details" });
Event.Location = Event.belongsTo(models.Location, { foreignKey: 'locationId', as: "location" });
//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
Event.Comments = Event.hasMany(models.Comment, {
foreignKey: "entityId",
scope: {
entityName: "event",
},
as: "comments",
required: false,
});
//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
Event.Comments = Event.hasMany(models.Comment, {
foreignKey: 'entityId',
scope: {
entityName: 'event'
},
as: "comments",
required: false,
});
Event.Multimedias = Event.hasMany(models.Multimedia, {
foreignKey: "entityId",
as: { singular: "multimedia", plural: "multimedias" },
required: false,
});
Event.Multimedias = Event.hasMany(models.Multimedia, {
foreignKey: 'entityId',
as: { singular: 'multimedia', plural: 'multimedias' },
required: false,
});
Event.Reservations = Event.hasMany(models.EventReservation, {
foreignKey: "eventId",
as: "reservations",
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, {
foreignKey: 'eventId', as: "reservations",
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.addScope("featured", {
where: {
featured: true,
},
});
Event.addScope("includeVenue", () => {
return {
include: [{ model: sequelize.models.Venue, as: "venue" }],
};
Event.addScope('featured', {
where: {
featured: true
});
Event.addScope("includeMultimedias", () => {
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', () => {
return {
include: [
{ model: sequelize.models.Venue, as: 'venue' }
]
}
});
Event.addScope('includeMultimedias', () => {
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("includeMultimediaAvatar", () => {
return {
include: [
{
model: sequelize.models.Multimedia,
as: { singular: "multimedia", plural: "multimedias" },
where: { type: "avatar" },
required: false,
include: [
{
model: sequelize.models.MultimediaFile,
as: "multimediaFile",
},
]
}
});
],
},
],
};
});
Event.addScope('includeMultimediaAvatar', () => {
return {
include: [{
model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' },
where: { type: 'avatar'},
required: false,
include: [{
model: sequelize.models.MultimediaFile,
as: "multimediaFile"
}]
},
]
}
});
Event.addScope("includeInscription", (userId) => {
return {
include: [
{ model: sequelize.models.EventInscription, as: "inscriptions", required: false, where: { userId: userId } },
],
};
});
Event.addScope('includeInscription', (userId) => {
return {
include: [
{ model: sequelize.models.EventInscription, as: 'inscriptions',
required: false,
where: { userId: userId } }
]
}
});
Event.addScope("includeOverflowEvent", () => {
return {
include: [
{
model: sequelize.models.Event,
as: "overflowEvent",
required: false,
where: { typeId: { [Sequelize.Op.ne]: null } },
// attributes: ['assistants', 'confirmed'],
},
],
};
});
Event.addScope('includeOverflowEvent', () => {
return {
include: [
{ model: sequelize.models.Event,
as: 'overflowEvent',
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,
where: { typeId: { [Sequelize.Op.ne]: null}},
// attributes: ['assistants', 'confirmed'],
}
]
}
});
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')
}
include: [
{
model: sequelize.models.MultimediaFile,
as: "multimediaFile",
},
],
},
],
},
],
},
});
],
};
});
Event.addScope('today', {
where: {
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'),
Event.addScope("includeComments", () => {
return {
include: [
{
model: sequelize.models.Comment,
as: "comments",
required: false,
include: [
{
model: sequelize.models.User,
as: "user",
},
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', () => {
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("next", {
where: {
init_date: {
[Sequelize.Op.gte]: moment().add(1, "days").startOf("day").format("YYYY-MM-DD HH:mm:ss"),
},
},
});
Event.addScope('onlyOfLocation', (location) => {
return {
where: { locationId: { [Sequelize.Op.eq]: location } },
}
});
Event.addScope("today", {
where: {
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(
"/events/next",
isOptionalUser,
@ -78,11 +79,29 @@ routes.get(
if (isLogged) {
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);
}
);
// 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(
"/events/past",
isOptionalUser,
@ -274,7 +293,7 @@ routes.get(
eventInscriptionController.getInscription
);
// Hacer una inscripción
// Hacer una inscripción
routes.post(
"/events/:id/inscriptions",
isLoggedUser,
@ -285,7 +304,7 @@ routes.post(
eventReservationController.recuperateReservationByCode,
//Recupera a registra el usuario que se va a inscribir
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
eventInscriptionController.checkInscriptionByUser,
//Si es un usuario tutor y solicita un group_size se crea la reserva
@ -357,7 +376,7 @@ routes.post(
eventReservationController.recuperateReservationByCode,
//Recupera a registra el usuario que se va a inscribir
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
eventInscriptionController.checkInscriptionByUser,
//Al ser via web siempre será inscripción con codigo de reserva
@ -535,8 +554,8 @@ routes.put(
"/admin/reservations/:id",
isAdministratorUser,
//SchemaValidator(eventValidation.ReservationInputType, true),
eventReservationController.checkAssitantsUpdate,
eventReservationController.update()
eventReservationController.checkAssitantsUpdate,
eventReservationController.update()
);
routes.put(

View File

@ -46,9 +46,10 @@ async function activeReservation(reservation) {
}
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) {
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;
}

View File

@ -1,93 +1,109 @@
const Sequelize = require('sequelize');
const Sequelize = require("sequelize");
module.exports = function (sequelize, DataTypes) {
const Location = sequelize.define('Location', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
const Location = sequelize.define(
"Location",
{
id: {
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),
allowNull: false,
{
unique: false,
fields: ["country_code"],
},
city: {
type: DataTypes.STRING(125),
allowNull: false,
},
description: {
type: DataTypes.STRING,
},
}, {
tableName: 'locations',
freezeTableName: true,
timestamps: true,
indexes: [{
unique: true,
fields: ['country', 'city']
}]
],
}
);
Location.associate = function (models) {
Location.Events = Location.hasMany(models.Event, { as: "events", foreignKey: "locationId" });
//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
Location.Multimedias = Location.hasMany(models.Multimedia, {
foreignKey: "entityId",
as: { singular: "multimedia", plural: "multimedias" },
});
};
Location.associate = function (models) {
Location.Events = Location.hasMany(models.Event, {as: 'events', foreignKey: 'locationId'});
//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
Location.Multimedias = Location.hasMany(models.Multimedia, {
foreignKey: 'entityId',
as: { singular: 'multimedia', plural: 'multimedias' },
});
Location.addScope("includeMultimedias", () => {
return {
include: [
{
model: sequelize.models.Multimedia,
as: { singular: "multimedia", plural: "multimedias" },
required: false,
include: [
{
model: sequelize.models.MultimediaFile,
as: "multimediaFile",
},
],
},
],
};
});
Location.addScope('includeMultimedias', () => {
return {
include: [{
model: sequelize.models.Multimedia,
as: { singular: 'multimedia', plural: 'multimedias' },
required: false,
include: [{
model: sequelize.models.MultimediaFile,
as: "multimediaFile"
}]
},
]
}
});
Location.addScope("includeEvents", () => {
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"
// }]
},
],
};
});
Location.addScope('includeEvents', () => {
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;
};
return Location;
};

View File

@ -118,7 +118,7 @@ const extraControllers = {
* "segment": "ALL" | "ALL_VALIDATED" | "ALL_NOT_VALIDATED" |
* "PARTNERS_ALL" | "PARTNERS_VALIDATED" | "PARTNERS_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]", ...]
* "country": "*" | "ES" | "MX"
* },

View File

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