mail notification

This commit is contained in:
lesion 2019-03-11 00:20:37 +01:00
parent 6ed639d94b
commit 9702f93cf9
17 changed files with 95 additions and 59 deletions

1
.env
View file

@ -1,3 +1,4 @@
NODE_ENV=production
BASE_URL=http://localhost:12300 BASE_URL=http://localhost:12300
TITLE=Gancio TITLE=Gancio

View file

@ -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/

View file

@ -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)

View file

@ -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')

View file

@ -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)
}, },

View file

@ -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()

View file

@ -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>

View file

@ -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 }

View file

@ -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 }

View file

@ -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)

View file

@ -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),

View file

@ -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 () {

View file

@ -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);
} }

View file

@ -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,
} }

View file

@ -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) {

View file

@ -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',

View file

@ -16,6 +16,7 @@ module.exports = {
}, },
transpileDependencies: [ transpileDependencies: [
/\bvue-awesome\b/, /\bvue-awesome\b/,
'vuex-persist' 'vuex-persist',
'bootstrap-vue'
] ]
} }