mail notification
This commit is contained in:
parent
6ed639d94b
commit
9702f93cf9
17 changed files with 95 additions and 59 deletions
1
.env
1
.env
|
@ -1,3 +1,4 @@
|
||||||
|
NODE_ENV=production
|
||||||
BASE_URL=http://localhost:12300
|
BASE_URL=http://localhost:12300
|
||||||
|
|
||||||
TITLE=Gancio
|
TITLE=Gancio
|
||||||
|
|
|
@ -7,7 +7,7 @@ COPY package.json .
|
||||||
COPY pm2.json .
|
COPY pm2.json .
|
||||||
|
|
||||||
# install backend dependencies
|
# install backend dependencies
|
||||||
RUN yarn --prod
|
RUN yarn
|
||||||
|
|
||||||
# copy source
|
# copy source
|
||||||
COPY app app/
|
COPY app app/
|
||||||
|
|
|
@ -47,9 +47,9 @@ api.get('/event/meta', eventController.getMeta)
|
||||||
// get unconfirmed events
|
// get unconfirmed events
|
||||||
api.get('/event/unconfirmed', isAuth, isAdmin, eventController.getUnconfirmed)
|
api.get('/event/unconfirmed', isAuth, isAdmin, eventController.getUnconfirmed)
|
||||||
|
|
||||||
// add event reminder
|
// add event notification
|
||||||
api.post('/event/reminder', eventController.addReminder)
|
api.post('/event/notification', eventController.addNotification)
|
||||||
// api.del('/event/reminder/:id', eventController.delReminder)
|
api.delete('/event/del_notification/:code', eventController.delNotification)
|
||||||
|
|
||||||
// get event
|
// get event
|
||||||
api.get('/event/:event_id', eventController.get)
|
api.get('/event/:event_id', eventController.get)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
const { User, Event, Comment, Tag, Place, Reminder } = require('../model')
|
const { User, Event, Comment, Tag, Place, Notification } = require('../model')
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const { Op } = require('sequelize')
|
const { Op } = require('sequelize')
|
||||||
const lodash = require('lodash')
|
const lodash = require('lodash')
|
||||||
|
const crypto = require('crypto')
|
||||||
|
|
||||||
const eventController = {
|
const eventController = {
|
||||||
|
|
||||||
async addComment (req, res) {
|
async addComment (req, res) {
|
||||||
|
@ -23,7 +25,7 @@ const eventController = {
|
||||||
res.json({ tags, places })
|
res.json({ tags, places })
|
||||||
},
|
},
|
||||||
|
|
||||||
async getReminders (event) {
|
async getNotifications (event) {
|
||||||
function match (event, filters) {
|
function match (event, filters) {
|
||||||
// matches if no filter specified
|
// matches if no filter specified
|
||||||
if (!filters.tags.length && !filters.places.length) return true
|
if (!filters.tags.length && !filters.places.length) return true
|
||||||
|
@ -37,10 +39,10 @@ const eventController = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const reminders = await Reminder.findAll()
|
const notifications = await Notification.findAll()
|
||||||
|
|
||||||
// get reminder that matches with selected event
|
// get notification that matches with selected event
|
||||||
return reminders.filter(reminder => match(event, reminder.filters))
|
return notifications.filter(notification => match(event, notification.filters))
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateTag (req, res) {
|
async updateTag (req, res) {
|
||||||
|
@ -68,6 +70,11 @@ const eventController = {
|
||||||
async confirm (req, res) {
|
async confirm (req, res) {
|
||||||
const id = req.params.event_id
|
const id = req.params.event_id
|
||||||
const event = await Event.findByPk(id)
|
const event = await Event.findByPk(id)
|
||||||
|
|
||||||
|
// insert notification
|
||||||
|
const notifications = await eventController.getNotifications(event)
|
||||||
|
await event.setNotifications(notifications)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await event.update({ is_visible: true })
|
await event.update({ is_visible: true })
|
||||||
res.send(200)
|
res.send(200)
|
||||||
|
@ -87,14 +94,28 @@ const eventController = {
|
||||||
res.json(events)
|
res.json(events)
|
||||||
},
|
},
|
||||||
|
|
||||||
async addReminder (req, res) {
|
async addNotification (req, res) {
|
||||||
try {
|
try {
|
||||||
await Reminder.create(req.body)
|
const notification = req.body
|
||||||
|
notification.remove_code = crypto.randomBytes(16).toString('hex')
|
||||||
|
await Notification.create(req.body)
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.sendStatus(404)
|
res.sendStatus(404)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async delNotification (req, res) {
|
||||||
|
const remove_code = req.params.code
|
||||||
|
try {
|
||||||
|
const notification = await Notification.findOne({ where: { remove_code: { [Op.eq]: remove_code } } })
|
||||||
|
await notification.destroy()
|
||||||
|
} catch (e) {
|
||||||
|
return res.send('Error')
|
||||||
|
}
|
||||||
|
res.send('Ok, notification removed')
|
||||||
|
},
|
||||||
|
|
||||||
async getAll (req, res) {
|
async getAll (req, res) {
|
||||||
const start = moment().year(req.params.year).month(req.params.month).startOf('month').subtract(1, 'week')
|
const start = moment().year(req.params.year).month(req.params.month).startOf('month').subtract(1, 'week')
|
||||||
const end = moment().year(req.params.year).month(req.params.month).endOf('month').add(1, 'week')
|
const end = moment().year(req.params.year).month(req.params.month).endOf('month').add(1, 'week')
|
||||||
|
|
|
@ -2,7 +2,7 @@ const jwt = require('jsonwebtoken')
|
||||||
const Mastodon = require('mastodon-api')
|
const Mastodon = require('mastodon-api')
|
||||||
|
|
||||||
const User = require('../models/user')
|
const User = require('../models/user')
|
||||||
const { Event, Tag, Place } = require('../models/event')
|
const { Event, Tag, Place, Notification } = require('../models/event')
|
||||||
const eventController = require('./event')
|
const eventController = require('./event')
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const mail = require('../mail')
|
const mail = require('../mail')
|
||||||
|
@ -105,9 +105,14 @@ const userController = {
|
||||||
event.save()
|
event.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert reminder
|
if (req.user) {
|
||||||
const reminders = await eventController.getReminders(event)
|
// insert notifications
|
||||||
await event.setReminders(reminders)
|
const notifications = await eventController.getNotifications(event)
|
||||||
|
await event.setNotifications(notifications)
|
||||||
|
} else {
|
||||||
|
const notification = await Notification.create({ type: 'admin_email' })
|
||||||
|
await event.setNotification(notification)
|
||||||
|
}
|
||||||
|
|
||||||
return res.json(event)
|
return res.json(event)
|
||||||
},
|
},
|
||||||
|
|
23
app/cron.js
23
app/cron.js
|
@ -1,20 +1,23 @@
|
||||||
const mail = require('./mail')
|
const mail = require('./mail')
|
||||||
const { Event, Reminder, EventReminder, User, Place, Tag } = require('./model')
|
const { Event, Notification, EventNotification, User, Place, Tag } = require('./model')
|
||||||
|
|
||||||
async function loop () {
|
async function loop () {
|
||||||
console.log('nel loop')
|
// get all event notification in queue
|
||||||
// get all event reminder in queue
|
const eventNotifications = await EventNotification.findAll()
|
||||||
const eventReminders = await EventReminder.findAll()
|
const promises = eventNotifications.map(async e => {
|
||||||
const promises = eventReminders.map(async e => {
|
|
||||||
const event = await Event.findByPk(e.eventId, { include: [User, Place, Tag] })
|
const event = await Event.findByPk(e.eventId, { include: [User, Place, Tag] })
|
||||||
console.log('EVENT ')
|
|
||||||
console.log(event)
|
|
||||||
if (!event.place) return
|
if (!event.place) return
|
||||||
const reminder = await Reminder.findByPk(e.reminderId)
|
const notification = await Notification.findByPk(e.notificationId)
|
||||||
try {
|
try {
|
||||||
await mail.send(reminder.email, 'event', { event })
|
if (notification.type === 'mail') {
|
||||||
|
await mail.send(notification.email, 'event', { event })
|
||||||
|
} else if (notification.type === 'mail_admin') {
|
||||||
|
const admins = await User.findAll({ where: { is_admin: true } })
|
||||||
|
await Promise.all(admins.map(admin =>
|
||||||
|
mail.send(admin.email, 'event', { event, to_confirm: true, notification })))
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('DENTRO CATCH!', e)
|
console.log('CATCH!', e)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return e.destroy()
|
return e.destroy()
|
||||||
|
|
|
@ -6,5 +6,10 @@ br
|
||||||
p #{event.description}
|
p #{event.description}
|
||||||
|
|
||||||
<a href="#{config.baseurl}/event/#{event.id}">#{config.baseurl}/event/#{event.id}</a>
|
<a href="#{config.baseurl}/event/#{event.id}">#{config.baseurl}/event/#{event.id}</a>
|
||||||
|
p #{event.tags.join(', ')}
|
||||||
hr
|
hr
|
||||||
<a href="#{config.baseurl}">#{config.title} - #{config.description}</a>
|
if to_confirm
|
||||||
|
p Puoi confermare questo evento <a href="#{config.apiurl}/api/event/confirm/#{event.id}">#{config.apiurl}qui</a>
|
||||||
|
else
|
||||||
|
p Puoi eliminare queste notifiche <a href="#{confir.apiurl}/api/del_notification/#{notification.remove_code}">qui</a>
|
||||||
|
<a href="#{config.baseurl}">#{config.title} - #{config.description}</a>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const User = require('./models/user')
|
const User = require('./models/user')
|
||||||
const { Event, Comment, Tag, Place, Reminder, EventReminder } = require('./models/event')
|
const { Event, Comment, Tag, Place, Notification, EventNotification } = require('./models/event')
|
||||||
|
|
||||||
module.exports = { User, Event, Comment, Tag, Place, Reminder, EventReminder }
|
module.exports = { User, Event, Comment, Tag, Place, Notification, EventNotification }
|
||||||
|
|
|
@ -24,11 +24,14 @@ const Comment = db.define('comment', {
|
||||||
text: Sequelize.STRING
|
text: Sequelize.STRING
|
||||||
})
|
})
|
||||||
|
|
||||||
const Reminder = db.define('reminder', {
|
const Notification = db.define('notification', {
|
||||||
filters: Sequelize.JSON,
|
filters: Sequelize.JSON,
|
||||||
email: Sequelize.STRING,
|
email: Sequelize.STRING,
|
||||||
notify_on_add: Sequelize.BOOLEAN,
|
remove_code: Sequelize.STRING,
|
||||||
send_reminder: Sequelize.BOOLEAN
|
type: {
|
||||||
|
type: Sequelize.ENUM,
|
||||||
|
values: ['mail', 'admin_mail', 'activity_pub']
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const Place = db.define('place', {
|
const Place = db.define('place', {
|
||||||
|
@ -42,9 +45,9 @@ Event.hasMany(Comment)
|
||||||
Event.belongsToMany(Tag, { through: 'tagEvent' })
|
Event.belongsToMany(Tag, { through: 'tagEvent' })
|
||||||
Tag.belongsToMany(Event, { through: 'tagEvent' })
|
Tag.belongsToMany(Event, { through: 'tagEvent' })
|
||||||
|
|
||||||
const EventReminder = db.define('EventReminder')
|
const EventNotification = db.define('EventNotification')
|
||||||
Event.belongsToMany(Reminder, { through: EventReminder })
|
Event.belongsToMany(Notification, { through: EventNotification })
|
||||||
Reminder.belongsToMany(Event, { through: EventReminder })
|
Notification.belongsToMany(Event, { through: EventNotification })
|
||||||
|
|
||||||
Event.belongsTo(User)
|
Event.belongsTo(User)
|
||||||
Event.belongsTo(Place)
|
Event.belongsTo(Place)
|
||||||
|
@ -52,4 +55,4 @@ Event.belongsTo(Place)
|
||||||
User.hasMany(Event)
|
User.hasMany(Event)
|
||||||
Place.hasMany(Event)
|
Place.hasMany(Event)
|
||||||
|
|
||||||
module.exports = { Event, Comment, Tag, Place, Reminder, EventReminder }
|
module.exports = { Event, Comment, Tag, Place, Notification, EventNotification }
|
||||||
|
|
|
@ -4,6 +4,7 @@ const bodyParser = require('body-parser')
|
||||||
const api = require('./api')
|
const api = require('./api')
|
||||||
const cors = require('cors')
|
const cors = require('cors')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const config = require('./config')
|
||||||
const port = process.env.PORT || 9000
|
const port = process.env.PORT || 9000
|
||||||
|
|
||||||
app.set('views', path.join(__dirname, 'views'))
|
app.set('views', path.join(__dirname, 'views'))
|
||||||
|
@ -19,4 +20,4 @@ app.use('/js', express.static(path.join(__dirname, '..', 'client', 'dist', 'js')
|
||||||
app.use('*', express.static(path.join(__dirname, '..', 'client', 'dist', 'index.html')))
|
app.use('*', express.static(path.join(__dirname, '..', 'client', 'dist', 'index.html')))
|
||||||
|
|
||||||
app.listen(port)
|
app.listen(port)
|
||||||
console.log('Magic happens at http://localhost:' + port)
|
console.log(`[${config.title}] Started ${process.env.NODE_ENV} mode at ${config.baseurl} (api @ ${config.apiurl})`, config)
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default {
|
||||||
getAllEvents: (month, year) => get(`/event/${year}/${month}/`),
|
getAllEvents: (month, year) => get(`/event/${year}/${month}/`),
|
||||||
getUnconfirmedEvents: () => get('/event/unconfirmed'),
|
getUnconfirmedEvents: () => get('/event/unconfirmed'),
|
||||||
confirmEvent: id => get(`/event/confirm/${id}`),
|
confirmEvent: id => get(`/event/confirm/${id}`),
|
||||||
emailReminder: reminder => post('/event/reminder', reminder),
|
addNotification: notification => post('/event/notification', notification),
|
||||||
addEvent: event => post('/user/event', event),
|
addEvent: event => post('/user/event', event),
|
||||||
updateEvent: event => put('/user/event', event),
|
updateEvent: event => put('/user/event', event),
|
||||||
updatePlace: place => put('/place', place),
|
updatePlace: place => put('/place', place),
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
el-tab-pane.pt-1(label='email' name='email')
|
el-tab-pane.pt-1(label='email' name='email')
|
||||||
p(v-html='$t(`export_email_explanation`)')
|
p(v-html='$t(`export_email_explanation`)')
|
||||||
b-form
|
b-form
|
||||||
el-switch(v-model='reminder.notify_on_add' :active-text="$t('notify_on_insert')")
|
//- el-switch(v-model='notification.notify_on_add' :active-text="$t('notify_on_insert')")
|
||||||
br
|
//- br
|
||||||
//- el-switch.mt-2(v-model='reminder.send_reminder' :active-text="$t('send_reminder')")
|
//- el-switch.mt-2(v-model='notification.send_notification' :active-text="$t('send_notification')")
|
||||||
el-input.mt-2(v-model='reminder.email' :placeholder="$t('Insert your address')")
|
el-input.mt-2(v-model='notification.email' :placeholder="$t('Insert your address')")
|
||||||
el-button.mt-2.float-right(type='success' @click='add_reminder') {{$t('Send')}}
|
el-button.mt-2.float-right(type='success' @click='add_notification') {{$t('Send')}}
|
||||||
|
|
||||||
el-tab-pane.pt-1(label='feed rss' name='feed')
|
el-tab-pane.pt-1(label='feed rss' name='feed')
|
||||||
span(v-html='$t(`export_feed_explanation`)')
|
span(v-html='$t(`export_feed_explanation`)')
|
||||||
|
@ -67,9 +67,9 @@ export default {
|
||||||
return {
|
return {
|
||||||
type: 'email',
|
type: 'email',
|
||||||
link: '',
|
link: '',
|
||||||
reminder: { notify_on_add: true, send_reminder: false },
|
|
||||||
export_list: true,
|
export_list: true,
|
||||||
script: `<iframe>Ti piacerebbe</iframe>`,
|
script: `<iframe>Ti piacerebbe</iframe>`,
|
||||||
|
notification: { email: '' },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filters,
|
filters,
|
||||||
|
@ -82,8 +82,8 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async add_reminder () {
|
async add_notification () {
|
||||||
await api.emailReminder({ ...this.reminder, filters: this.filters})
|
await api.addNotification({ ...this.notification, filters: this.filters})
|
||||||
this.$refs.modal.hide()
|
this.$refs.modal.hide()
|
||||||
},
|
},
|
||||||
loadLink () {
|
loadLink () {
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
b-modal(hide-header hide-footer @hide='$router.go(-1)' :visible='true')
|
b-modal(:title="$t('Settings')" hide-footer @hide='$router.go(-1)' :visible='true')
|
||||||
h4.text-center {{$t('Settings')}}
|
el-form(inline)
|
||||||
b-form
|
el-input(v-model="mastodon_instance")
|
||||||
b-input-group.mt-1(prepend='Email')
|
span(slot='prepend') Mastodon instance
|
||||||
b-form-input(v-model="user.email")
|
el-button(slot='append' @click='associate' type='success') Associate
|
||||||
//- b-form-checkbox(v-model="tmpUser.user.autoboost") Autoboost
|
|
||||||
b-input-group.mt-1(prepend='Mastodon instance')
|
|
||||||
b-form-input(v-model="mastodon_instance")
|
|
||||||
b-input-group-append
|
|
||||||
b-button(@click='associate', variant='primary') Associate
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@ -35,6 +30,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async associate () {
|
async associate () {
|
||||||
|
if (!this.mastodon_instance) return
|
||||||
const url = await api.getAuthURL({instance: this.mastodon_instance})
|
const url = await api.getAuthURL({instance: this.mastodon_instance})
|
||||||
setTimeout( () => window.location.href=url, 100);
|
setTimeout( () => window.location.href=url, 100);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ export default {
|
||||||
id: null,
|
id: null,
|
||||||
activeTab: "0",
|
activeTab: "0",
|
||||||
date: null,
|
date: null,
|
||||||
time: { start: '00:00', end: null },
|
time: { start: '20:00', end: null },
|
||||||
edit: false,
|
edit: false,
|
||||||
sending: false,
|
sending: false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import moment from 'dayjs'
|
import moment from 'dayjs'
|
||||||
// moment.locale('it')
|
import 'dayjs/locale/it'
|
||||||
|
moment.locale('it')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
datetime (value) {
|
datetime (value) {
|
||||||
|
|
|
@ -67,7 +67,6 @@ const it = {
|
||||||
Admin: 'Amministra',
|
Admin: 'Amministra',
|
||||||
Today: 'Oggi',
|
Today: 'Oggi',
|
||||||
Export: 'Esporta',
|
Export: 'Esporta',
|
||||||
send_reminder: 'Ricordamelo il giorno prima',
|
|
||||||
event_confirmed: 'Evento confermato!',
|
event_confirmed: 'Evento confermato!',
|
||||||
notify_on_insert: `Notifica all'inserimento`,
|
notify_on_insert: `Notifica all'inserimento`,
|
||||||
'event_confirm_explanation': 'Puoi approvare gli eventi inseriti da utenti non registrati',
|
'event_confirm_explanation': 'Puoi approvare gli eventi inseriti da utenti non registrati',
|
||||||
|
|
|
@ -16,6 +16,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
transpileDependencies: [
|
transpileDependencies: [
|
||||||
/\bvue-awesome\b/,
|
/\bvue-awesome\b/,
|
||||||
'vuex-persist'
|
'vuex-persist',
|
||||||
|
'bootstrap-vue'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue