new events fetch methods

This commit is contained in:
les 2020-01-21 01:24:32 +01:00
parent e0b3dd8d4a
commit 3a698903f6
2 changed files with 197 additions and 151 deletions

View file

@ -1,7 +1,7 @@
const crypto = require('crypto')
const moment = require('moment-timezone')
const { Op } = require('sequelize')
const lodash = require('lodash')
const _ = require('lodash')
const { event: Event, resource: Resource, tag: Tag, place: Place, notification: Notification } = require('../models')
const Sequelize = require('sequelize')
const exportController = require('./export')
@ -30,7 +30,7 @@ const eventController = {
order: [[Sequelize.literal('weigth'), 'DESC']],
attributes: {
include: [[Sequelize.fn('count', Sequelize.col('events.placeId')), 'weigth']],
exclude: ['weigth', 'createdAt', 'updatedAt']
exclude: ['createdAt', 'updatedAt']
},
include: [{ model: Event, attributes: [] }],
group: ['place.id']
@ -40,11 +40,11 @@ const eventController = {
raw: true,
order: [['weigth', 'DESC']],
attributes: {
exclude: ['createdAt', 'updatedAt', 'weigth']
exclude: ['createdAt', 'updatedAt']
}
})
res.json({ tags: tags.map(t => t.tag), places })
res.json({ tags, places })
},
async getNotifications (event, action) {
@ -59,7 +59,7 @@ const eventController = {
if (!filters.tags && !filters.places) { return true }
if (!filters.tags.length && !filters.places.length) { return true }
if (filters.tags.length) {
const m = lodash.intersection(event.tags.map(t => t.tag), filters.tags)
const m = _.intersection(event.tags.map(t => t.tag), filters.tags)
if (m.length > 0) { return true }
}
if (filters.places.length) {
@ -69,7 +69,7 @@ const eventController = {
}
}
const notifications = await Notification.findAll({ where: { action }, include: [ Event ] })
const notifications = await Notification.findAll({ where: { action }, include: [Event] })
// get notification that matches with selected event
const ret = notifications.filter(notification => match(event, notification.filters))
@ -197,28 +197,121 @@ const eventController = {
res.sendStatus(200)
},
async addRecurrent (start, places, where_tags, limit) {
const where = {
is_visible: true,
recurrent: { [Op.ne]: null }
// placeId: places
}
const events = await Event.findAll({
where,
limit,
attributes: {
exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'description', 'createdAt', 'updatedAt', 'placeId']
},
order: ['start_datetime', [Tag, 'weigth', 'DESC']],
include: [
{ model: Resource, required: false, attributes: ['id'] },
{ model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] } },
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
]
})
debug(`Found ${events.length} recurrent events`)
let allEvents = []
_.forEach(events, e => {
allEvents = allEvents.concat(eventController.createEventsFromRecurrent(e.get(), start))
})
debug(`Created ${allEvents.length} events`)
return allEvents
},
// build singular events from a recurrent pattern
createEventsFromRecurrent (e, start, dueTo = null) {
const events = []
const recurrent = JSON.parse(e.recurrent)
if (!recurrent.frequency) { return false }
if (!dueTo) {
dueTo = moment.unix(start).add(2, 'month')
}
let cursor = moment.unix(start).startOf('week')
const start_date = moment.unix(e.start_datetime)
const duration = moment.unix(e.end_datetime).diff(start_date, 's')
const frequency = recurrent.frequency
const days = recurrent.days
const type = recurrent.type
// default frequency is '1d' => each day
const toAdd = { n: 1, unit: 'day' }
// each week or 2 (search for the first specified day)
if (frequency === '1w' || frequency === '2w') {
cursor.add(days[0] - 1, 'day')
if (frequency === '2w') {
const nWeeks = cursor.diff(e.start_datetime, 'w') % 2
if (!nWeeks) { cursor.add(1, 'week') }
}
toAdd.n = Number(frequency[0])
toAdd.unit = 'week'
// cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
}
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
// each month or 2
if (frequency === '1m' || frequency === '2m') {
// find first match
toAdd.n = 1
toAdd.unit = 'month'
if (type === 'weekday') {
} else if (type === 'ordinal') {
}
}
// add event at specified frequency
while (true) {
const first_event_of_week = cursor.clone()
days.forEach(d => {
if (type === 'ordinal') {
cursor.date(d)
} else {
cursor.day(d - 1)
}
if (cursor.isAfter(dueTo) || cursor.isBefore(start)) { return }
e.start_datetime = cursor.unix()
e.end_datetime = e.start_datetime + duration
events.push(Object.assign({}, e))
})
if (cursor.isAfter(dueTo)) { break }
cursor = first_event_of_week.add(toAdd.n, toAdd.unit)
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
}
return events
},
/**
* Select events based on params
*/
async select (req, res) {
const start = req.query.start || 0
const limit = req.query.limit
const show_recurrent = req.query.show_recurrent || false
const start = req.query.start || moment().unix()
const limit = req.query.limit || 100
const show_recurrent = req.query.show_recurrent || true
const filter_tags = req.query.tags || ''
const filter_places = req.query.places || ''
let where = {}
debug(`select limit:${limit} rec:${show_recurrent} tags:${filter_tags} places:${filter_places}`)
let where_tags = {}
if (show_recurrent) {
where = {
[Op.or]: [
{ recurrent: { [Op.ne]: null } },
{ start_datetime: { [Op.gt]: start }}
]
}
} else {
where = {
start_datetime: { [Op.gt]: start }
}
const where = {
// confirmed event only
is_visible: true,
start_datetime: { [Op.gt]: start },
recurrent: null
}
where.is_visible = true
if (filter_tags) {
where_tags = { where: { tag: filter_tags.split(',') } }
@ -232,139 +325,86 @@ const eventController = {
where,
limit,
attributes: {
exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'description', 'createdAt', 'updatedAt', 'placeId'],
exclude: ['slug', 'likes', 'boost', 'userId', 'is_visible', 'description', 'createdAt', 'updatedAt', 'placeId']
// include: [[Sequelize.fn('COUNT', Sequelize.col('activitypub_id')), 'ressources']]
},
order: ['start_datetime', [Tag, 'weigth', 'DESC']],
include: [
{ model: Resource, required: false, attributes: ['id'] },
{ model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] },},
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
],
})
events = events.map(e => e.get()).map(e => {
e.tags = e.tags.map(t => t.tag)
return e
})
res.json(events)
},
async getAll (req, res) {
// this is due how v-calendar shows dates
const start = moment()
.year(req.params.year)
.month(req.params.month)
.startOf('month')
.startOf('week')
let end = moment()
.year(req.params.year)
.month(req.params.month)
.endOf('month')
const shownDays = end.diff(start, 'days')
if (shownDays <= 35) { end = end.add(1, 'week') }
end = end.endOf('week')
let events = await Event.findAll({
where: {
// return only confirmed events
is_visible: true,
[Op.or]: [
// return all recurrent events regardless start_datetime
{ recurrent: { [Op.ne]: null } },
// and events in specified range
{ start_datetime: { [Op.between]: [start.unix(), end.unix()] } }
]
},
attributes: { exclude: [ 'createdAt', 'updatedAt', 'placeId' ] },
order: [[Tag, 'weigth', 'DESC']],
include: [
{ model: Resource, required: false, attributes: ['id'] },
{ model: Tag, required: false },
{ model: Tag, ...where_tags, attributes: ['tag'], through: { attributes: [] } },
{ model: Place, required: false, attributes: ['id', 'name', 'address'] }
]
})
events = events.map(e => e.get()).map(e => {
let recurrentEvents = []
events = _.map(events, e => e.get())
if (show_recurrent) {
recurrentEvents = await eventController.addRecurrent(start, where.placeId, where_tags, limit)
events = _.concat(events, recurrentEvents)
}
// flat tags
events = _(events).map(e => {
e.tags = e.tags.map(t => t.tag)
return e
})
// build singular events from a recurrent pattern
function createEventsFromRecurrent (e, dueTo = null) {
const events = []
const recurrent = JSON.parse(e.recurrent)
if (!recurrent.frequency) { return false }
let cursor = moment(start).startOf('week')
const start_date = moment.unix(e.start_datetime)
const duration = moment.unix(e.end_datetime).diff(start_date, 's')
const frequency = recurrent.frequency
const days = recurrent.days
const type = recurrent.type
// default frequency is '1d' => each day
const toAdd = { n: 1, unit: 'day' }
// each week or 2 (search for the first specified day)
if (frequency === '1w' || frequency === '2w') {
cursor.add(days[0] - 1, 'day')
if (frequency === '2w') {
const nWeeks = cursor.diff(e.start_datetime, 'w') % 2
if (!nWeeks) { cursor.add(1, 'week') }
}
toAdd.n = Number(frequency[0])
toAdd.unit = 'week'
// cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
}
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
// each month or 2
if (frequency === '1m' || frequency === '2m') {
// find first match
toAdd.n = 1
toAdd.unit = 'month'
if (type === 'weekday') {
} else if (type === 'ordinal') {
}
}
// add event at specified frequency
while (true) {
const first_event_of_week = cursor.clone()
days.forEach(d => {
if (type === 'ordinal') {
cursor.date(d)
} else {
cursor.day(d - 1)
}
if (cursor.isAfter(dueTo) || cursor.isBefore(start)) { return }
e.start_datetime = cursor.unix()
e.end_datetime = e.start_datetime + duration
events.push(Object.assign({}, e))
})
if (cursor.isAfter(dueTo)) { break }
cursor = first_event_of_week.add(toAdd.n, toAdd.unit)
cursor.set('hour', start_date.hour()).set('minute', start_date.minutes())
}
return events
}
let allEvents = events.filter(e => !e.recurrent || e.recurrent.length === 0)
events.filter(e => e.recurrent && e.recurrent.length).forEach(e => {
const events = createEventsFromRecurrent(e, end)
if (events) { allEvents = allEvents.concat(events) }
})
// allEvents.sort((a,b) => a.start_datetime-b.start_datetime)
res.json(allEvents.sort((a, b) => a.start_datetime - b.start_datetime))
res.json(events.sort((a, b) => a.start_datetime - b.start_datetime))
// res.json(recurrentEvents)
}
// async getAll (req, res) {
// // this is due how v-calendar shows dates
// const start = moment()
// .year(req.params.year)
// .month(req.params.month)
// .startOf('month')
// .startOf('week')
// let end = moment()
// .year(req.params.year)
// .month(req.params.month)
// .endOf('month')
// const shownDays = end.diff(start, 'days')
// if (shownDays <= 35) { end = end.add(1, 'week') }
// end = end.endOf('week')
// let events = await Event.findAll({
// where: {
// // return only confirmed events
// is_visible: true,
// [Op.or]: [
// // return all recurrent events regardless start_datetime
// { recurrent: { [Op.ne]: null } },
// // and events in specified range
// { start_datetime: { [Op.between]: [start.unix(), end.unix()] } }
// ]
// },
// attributes: { exclude: ['createdAt', 'updatedAt', 'placeId'] },
// order: [[Tag, 'weigth', 'DESC']],
// include: [
// { model: Resource, required: false, attributes: ['id'] },
// { model: Tag, required: false },
// { model: Place, required: false, attributes: ['id', 'name', 'address'] }
// ]
// })
// events = events.map(e => e.get()).map(e => {
// e.tags = e.tags.map(t => t.tag)
// return e
// })
// let allEvents = events.filter(e => !e.recurrent || e.recurrent.length === 0)
// events.filter(e => e.recurrent && e.recurrent.length).forEach(e => {
// const events = createEventsFromRecurrent(e, end)
// if (events) { allEvents = allEvents.concat(events) }
// })
// // allEvents.sort((a,b) => a.start_datetime-b.start_datetime)
// res.json(allEvents.sort((a, b) => a.start_datetime - b.start_datetime))
// }
}
module.exports = eventController

View file

@ -36,6 +36,9 @@ export const getters = {
const search_for_tags = !!state.filters.tags.length
const search_for_places = !!state.filters.places.length
const search_place_ids = state.filters.places.map(p => p.id)
const search_tags_tags = state.filters.tags.map(t => t.id)
return state.events.filter(e => {
// filter past events
if (!state.filters.show_past_events && e.past) { return false }
@ -44,13 +47,13 @@ export const getters = {
if (!state.filters.show_recurrent_events && e.recurrent) { return false }
if (search_for_places) {
if (find(state.filters.places, p => p.id === e.place.id)) {
if (search_place_ids.includes(e.place.id)) {
return true
}
}
if (search_for_tags) {
const common_tags = intersection(e.tags, state.filters.tags)
const common_tags = intersection(e.tags, search_tags_tags)
if (common_tags.length > 0) { return true }
}
@ -158,7 +161,11 @@ export const actions = {
commit('setSettings', settings)
const start_datetime = moment().startOf('month').startOf('week').unix()
const events = await this.$axios.$get(`/event?start=${start_datetime}`)
let query = `start=${start_datetime}`
if (settings.recurrent_event_visible) {
query += '&show_recurrent'
}
const events = await this.$axios.$get(`/event?${query}`)
commit('setEvents', events)
const { tags, places } = await this.$axios.$get('/event/meta')
@ -167,16 +174,15 @@ export const actions = {
// apply settings
commit('showRecurrentEvents', settings.allow_recurrent_event && settings.recurrent_event_visible)
},
async updateEvents ({ commit, state }, page) {
const month = moment().month()
const year = moment().year()
commit('setPast', page.year < year || (page.year === year && page.month <= month))
// const events = await this.$axios.$get(`/event/${page.month - 1}/${page.year}`)
const start_datetime = moment().year(page.year).month(page.month - 1).unix()
async updateEvents ({ commit }, page) {
const [month, year] = [moment().month(), moment().year()]
const in_past = page.year < year || (page.year === year && page.month <= month)
// commit('setPast', in_past)
const start_datetime = moment().year(page.year).month(page.month - 1).startOf('month').startOf('week').unix()
const query = `start=${start_datetime}`
const events = await this.$axios.$get(`/event?${query}`)
commit('setEvents', events)
commit('showPastEvents', in_past)
},
async updateMeta ({ commit }) {
const { tags, places } = await this.$axios.$get('/event/meta')