Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
les
gancio
Commits
4fe78aa3
Commit
4fe78aa3
authored
Oct 02, 2019
by
les
Browse files
[feat] add actions to notifications (add/del/update)
parent
d3febcdc
Changes
9
Hide whitespace changes
Inline
Side-by-side
server/api/controller/event.js
View file @
4fe78aa3
...
...
@@ -2,17 +2,16 @@ const crypto = require('crypto')
const
moment
=
require
(
'
moment
'
)
const
{
Op
}
=
require
(
'
sequelize
'
)
const
lodash
=
require
(
'
lodash
'
)
const
{
event
:
Event
,
comment
:
Comment
,
tag
:
Tag
,
place
:
Place
,
user
:
User
,
notification
:
Notification
}
=
require
(
'
../models
'
)
const
{
event
:
Event
,
comment
:
Comment
,
tag
:
Tag
,
place
:
Place
,
user
:
User
,
notification
:
Notification
,
event_notification
:
EventNotification
}
=
require
(
'
../models
'
)
const
Sequelize
=
require
(
'
sequelize
'
)
const
notifier
=
require
(
'
../../notifier
'
)
const
federation
=
require
(
'
../../federation/helpers
'
)
const
debug
=
require
(
'
debug
'
)(
'
controller:event
'
)
const
eventController
=
{
// NOT USED ANYWHERE, comments are added from fediverse
// NOT USED ANYWHERE, comments are added from fediverse
, should we remove this?
async
addComment
(
req
,
res
)
{
// comment could be added to an event or to another comment
// comment
s
could be added to an event or to another comment
let
event
=
await
Event
.
findOne
({
where
:
{
activitypub_id
:
{
[
Op
.
eq
]:
req
.
body
.
id
}
}
})
if
(
!
event
)
{
const
comment
=
await
Comment
.
findOne
({
where
:
{
activitypub_id
:
{
[
Op
.
eq
]:
req
.
body
.
id
}
},
include
:
Event
})
...
...
@@ -44,7 +43,8 @@ const eventController = {
res
.
json
({
tags
,
places
})
},
async
getNotifications
(
event
)
{
async
getNotifications
(
event
,
action
)
{
debug
(
'
getNotifications "%s" (%s)
'
,
event
.
title
,
action
)
function
match
(
event
,
filters
)
{
// matches if no filter specified
if
(
!
filters
)
{
return
true
}
...
...
@@ -64,10 +64,12 @@ const eventController = {
}
}
}
const
notifications
=
await
Notification
.
findAll
()
const
notifications
=
await
Notification
.
findAll
({
where
:
{
action
},
include
:
[
Event
]
})
// get notification that matches with selected event
return
notifications
.
filter
(
notification
=>
match
(
event
,
notification
.
filters
))
const
ret
=
notifications
.
filter
(
notification
=>
match
(
event
,
notification
.
filters
))
return
ret
},
async
updateTag
(
req
,
res
)
{
...
...
@@ -123,8 +125,8 @@ const eventController = {
res
.
sendStatus
(
200
)
// send notification
//
notifier
.notifyEvent(event.id
)
// federation.sendEvent(event, req.user
)
const
notifier
=
require
(
'
../../notifier
'
)
notifier
.
notifyEvent
(
'
Create
'
,
event
.
id
)
}
catch
(
e
)
{
res
.
sendStatus
(
404
)
}
...
...
server/api/controller/export.js
View file @
4fe78aa3
...
...
@@ -32,7 +32,7 @@ const exportController = {
},
include
:
[
{
model
:
Tag
,
...
where_tags
},
{
model
:
Place
,
attributes
:
[
'
name
'
,
'
id
'
,
'
address
'
]
}]
})
switch
(
type
)
{
case
'
rss
'
:
case
'
feed
'
:
...
...
server/api/controller/user.js
View file @
4fe78aa3
...
...
@@ -8,9 +8,6 @@ const config = require('config')
const
mail
=
require
(
'
../mail
'
)
const
{
user
:
User
,
event
:
Event
,
tag
:
Tag
,
place
:
Place
,
fed_users
:
FedUsers
}
=
require
(
'
../models
'
)
const
settingsController
=
require
(
'
./settings
'
)
const
federation
=
require
(
'
../../federation/helpers
'
)
const
util
=
require
(
'
util
'
)
const
generateKeyPair
=
util
.
promisify
(
crypto
.
generateKeyPair
)
const
debug
=
require
(
'
debug
'
)(
'
user:controller
'
)
const
userController
=
{
...
...
@@ -56,12 +53,14 @@ const userController = {
try
{
console
.
error
(
'
media files not removed
'
)
// TOFIX
//
await fs.unlink(old_path)
//
await fs.unlink(old_
thumb_
path)
await
fs
.
unlink
(
old_
thumb_
path
)
await
fs
.
unlink
(
old_path
)
}
catch
(
e
)
{
console
.
error
(
e
)
debug
(
e
)
}
}
const
notifier
=
require
(
'
../../notifier
'
)
await
notifier
.
notifyEvent
(
'
Delete
'
,
event
.
id
)
await
event
.
destroy
()
res
.
sendStatus
(
200
)
}
else
{
...
...
@@ -75,12 +74,11 @@ const userController = {
const
eventDetails
=
{
title
:
body
.
title
,
// remove html tag
// remove html tag
s
description
:
body
.
description
?
body
.
description
.
replace
(
/
(
<
([^
>
]
+
)
>
)
/ig
,
''
)
:
''
,
multidate
:
body
.
multidate
,
start_datetime
:
body
.
start_datetime
,
end_datetime
:
body
.
end_datetime
,
recurrent
:
body
.
recurrent
,
// publish this event only if authenticated
is_visible
:
!!
req
.
user
...
...
@@ -101,8 +99,9 @@ const userController = {
await
event
.
setPlace
(
place
)
event
.
place
=
place
}
catch
(
e
)
{
console
.
error
(
e
)
debug
(
e
)
}
// create/assign tags
if
(
body
.
tags
)
{
await
Tag
.
bulkCreate
(
body
.
tags
.
map
(
t
=>
({
tag
:
t
})),
{
ignoreDuplicates
:
true
})
...
...
@@ -112,21 +111,18 @@ const userController = {
event
.
tags
=
tags
}
// associate user to event and reverse
if
(
req
.
user
)
{
await
req
.
user
.
addEvent
(
event
)
await
event
.
setUser
(
req
.
user
)
}
//
send response to
client
//
return created event to the
client
res
.
json
(
event
)
const
user
=
await
User
.
findByPk
(
req
.
user
.
id
,
{
include
:
{
model
:
FedUsers
,
as
:
'
followers
'
}})
if
(
user
)
{
federation
.
sendEvent
(
event
,
user
)
}
// res.sendStatus(200)
// send notification (mastodon/email/confirmation)
// notifier.notifyEvent(event.id)
// send notification (mastodon/email)
const
notifier
=
require
(
'
../../notifier
'
)
notifier
.
notifyEvent
(
'
Create
'
,
event
.
id
)
},
async
updateEvent
(
req
,
res
)
{
...
...
@@ -167,6 +163,8 @@ const userController = {
}
const
newEvent
=
await
Event
.
findByPk
(
event
.
id
,
{
include
:
[
Tag
,
Place
]
})
res
.
json
(
newEvent
)
const
notifier
=
require
(
'
../../notifier
'
)
notifier
.
notifyEvent
(
'
Update
'
,
event
.
id
)
},
async
forgotPassword
(
req
,
res
)
{
...
...
server/api/mail.js
View file @
4fe78aa3
...
...
@@ -22,7 +22,7 @@ const mail = {
}
},
message
:
{
from
:
`
${
config
.
title
}
<
${
config
.
admin_email
}
>`
from
:
`
📅
${
config
.
title
}
<
${
config
.
admin_email
}
>`
},
send
:
true
,
i18n
:
{
...
...
@@ -32,7 +32,7 @@ const mail = {
updateFiles
:
false
,
defaultLocale
:
settings
.
locale
,
locale
:
settings
.
locale
,
locales
:
[
'
it
'
,
'
es
'
]
locales
:
[
'
it
'
,
'
es
'
]
// TOFIX
},
transport
:
config
.
smtp
})
...
...
@@ -44,9 +44,9 @@ const mail = {
},
locals
:
{
...
locals
,
locale
:
'
it
'
,
locale
:
'
it
'
,
// TOFIX
config
:
{
title
:
config
.
title
,
baseurl
:
config
.
baseurl
,
description
:
config
.
description
},
datetime
:
datetime
=>
moment
(
datetime
).
format
(
'
ddd, D MMMM HH:mm
'
)
datetime
:
datetime
=>
moment
.
unix
(
datetime
).
utc
(
false
).
format
(
'
ddd, D MMMM HH:mm
'
)
}
}
return
email
.
send
(
msg
)
...
...
server/api/models/eventnotification.js
View file @
4fe78aa3
...
...
@@ -10,5 +10,5 @@ module.exports = (sequelize, DataTypes) => {
}
},
{})
return
event_notification
return
event_notification
}
server/api/models/notification.js
View file @
4fe78aa3
...
...
@@ -4,13 +4,23 @@ module.exports = (sequelize, DataTypes) => {
filters
:
DataTypes
.
JSON
,
email
:
DataTypes
.
STRING
,
remove_code
:
DataTypes
.
STRING
,
action
:
{
type
:
DataTypes
.
ENUM
,
values
:
[
'
Create
'
,
'
Update
'
,
'
Delete
'
]
},
type
:
{
type
:
DataTypes
.
ENUM
,
values
:
[
'
mail
'
,
'
admin_email
'
,
'
mastodon
'
]
values
:
[
'
mail
'
,
'
admin_email
'
,
'
ap
'
]
}
},
{})
},
{
indexes
:
[{
unique
:
true
,
fields
:
[
'
action
'
,
'
type
'
]
}]
})
notification
.
associate
=
function
(
models
)
{
notification
.
belongsToMany
(
models
.
event
,
{
through
:
models
.
event_notification
})
notification
.
belongsToMany
(
models
.
event
,
{
through
:
'
event_notification
'
})
// associations can be defined here
}
return
notification
...
...
server/federation/helpers.js
View file @
4fe78aa3
...
...
@@ -52,7 +52,7 @@ const Helpers = {
debug
(
'
sign %s => %s
'
,
ret
.
status
,
await
ret
.
text
())
},
async
sendEvent
(
event
,
user
)
{
async
sendEvent
(
event
,
user
,
type
=
'
Create
'
)
{
if
(
!
settingsController
.
settings
.
enable_federation
)
{
debug
(
'
event not send, federation disabled
'
)
return
...
...
@@ -77,7 +77,7 @@ const Helpers = {
debug
(
'
Notify %s with event %s (from admin %s) cc => %d
'
,
sharedInbox
,
event
.
title
,
instanceAdmin
.
username
,
recipients
[
sharedInbox
].
length
)
const
body
=
{
id
:
`
${
config
.
baseurl
}
/federation/m/
${
event
.
id
}
#create`
,
type
:
'
Create
'
,
type
,
to
:
[
'
https://www.w3.org/ns/activitystreams#Public
'
],
cc
:
[
`
${
config
.
baseurl
}
/federation/u/
${
instanceAdmin
.
username
}
/followers`
,
...
recipients
[
sharedInbox
]],
//cc: recipients[sharedInbox],
...
...
server/migrations/20190927160148-new_notification.js
0 → 100644
View file @
4fe78aa3
'
use strict
'
;
const
{
notification
:
Notification
}
=
require
(
'
../api/models
'
)
module
.
exports
=
{
up
:
async
(
queryInterface
,
Sequelize
)
=>
{
// remove all notifications
await
Notification
.
destroy
({
where
:
[]})
// add `action` field to notification
try
{
await
queryInterface
.
addColumn
(
'
notifications
'
,
'
action
'
,
{
type
:
Sequelize
.
ENUM
,
values
:
[
'
Create
'
,
'
Update
'
,
'
Delete
'
]
})
}
catch
{}
// modify values of `type` field
try
{
await
queryInterface
.
removeColumn
(
'
notifications
'
,
'
type
'
)
}
catch
{}
try
{
await
queryInterface
.
addColumn
(
'
notifications
'
,
'
type
'
,
{
type
:
Sequelize
.
ENUM
,
values
:
[
'
mail
'
,
'
admin_email
'
,
'
ap
'
]
})
}
catch
{}
await
queryInterface
.
addIndex
(
'
notifications
'
,
{
unique
:
true
,
fields
:
[
'
action
'
,
'
type
'
]
})
// add AP notifications
await
Notification
.
create
({
action
:
'
Create
'
,
type
:
'
ap
'
,
filters
:
{
is_visible
:
true
}
})
await
Notification
.
create
({
action
:
'
Update
'
,
type
:
'
ap
'
,
filters
:
{
is_visible
:
true
}
})
await
Notification
.
create
({
action
:
'
Delete
'
,
type
:
'
ap
'
,
filters
:
{
is_visible
:
true
}
})
// send anon events via email to admin
await
Notification
.
create
({
action
:
'
Create
'
,
type
:
'
admin_email
'
,
filters
:
{
is_visible
:
false
}
})
return
true
},
down
:
(
queryInterface
,
Sequelize
)
=>
{
return
Promise
.
resolve
()
/*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.dropTable('users');
*/
}
};
server/notifier.js
View file @
4fe78aa3
const
mail
=
require
(
'
./api/mail
'
)
// const bot = require('./api/controller/fediverse')
const
settingsController
=
require
(
'
./api/controller/settings
'
)
const
config
=
require
(
'
config
'
)
const
eventController
=
require
(
'
./api/controller/event
'
)
const
get
=
require
(
'
lodash/get
'
)
const
debug
=
require
(
'
debug
'
)(
'
notifier
'
)
const
fediverseHelpers
=
require
(
'
./federation/helpers
'
)
const
{
event
:
Event
,
notification
:
Notification
,
event_notification
:
EventNotification
,
user
:
User
,
place
:
Place
,
tag
:
Tag
}
=
require
(
'
./api/models
'
)
user
:
User
,
place
:
Place
,
tag
:
Tag
,
fed_users
:
FedUsers
}
=
require
(
'
./api/models
'
)
const
eventController
=
require
(
'
./api/controller/event
'
)
const
notifier
=
{
async
sendNotification
(
notification
,
event
)
{
return
const
promises
=
[]
debug
(
'
Send %s notification %s
'
,
notification
.
type
,
notification
.
action
)
let
p
switch
(
notification
.
type
)
{
case
'
mail
'
:
return
mail
.
send
(
notification
.
email
,
'
event
'
,
{
event
,
config
,
notification
})
case
'
admin_email
'
:
return
mail
.
send
([
config
.
smtp
.
auth
.
user
,
config
.
admin_email
],
'
event
'
,
{
event
,
to_confirm
:
!
event
.
is_visible
,
config
,
notification
})
// case 'mastodon':
// // instance publish
// if (bot.bot) {
// const b = bot.post(event).then(b => {
// event.activitypub_id = String(b.data.id)
// return event.save()
// }).catch(e => {
// console.error("ERROR !! ", e)
// })
// promises.push(b)
// }
p
=
mail
.
send
([
config
.
smtp
.
auth
.
user
,
config
.
admin_email
],
'
event
'
,
{
event
,
to_confirm
:
!
event
.
is_visible
,
config
,
notification
})
promises
.
push
(
p
)
case
'
ap
'
:
p
=
fediverseHelpers
.
sendEvent
(
event
,
event
.
user
,
notification
.
action
)
promises
.
push
(
p
)
}
return
Promise
.
all
(
promises
)
},
async
notifyEvent
(
eventId
)
{
const
event
=
await
Event
.
findByPk
(
eventId
,
{
include
:
[
Tag
,
Place
,
User
]
async
notifyEvent
(
action
,
eventId
)
{
let
event
=
await
Event
.
findByPk
(
eventId
,
{
include
:
[
Tag
,
Place
,
Notification
,
{
model
:
User
,
include
:
{
model
:
FedUsers
,
as
:
'
followers
'
}}
]
})
debug
(
'
%s -> %s
'
,
action
,
event
.
title
)
// insert notifications
const
notifications
=
await
eventController
.
getNotifications
(
event
)
const
a
=
await
event
.
setNotifications
(
notifications
)
const
eventNotifications
=
await
EventNotification
.
findAll
({
where
:
{
notificationId
:
notifications
.
map
(
n
=>
n
.
id
),
status
:
'
new
'
}
})
const
notifications
=
await
eventController
.
getNotifications
(
event
,
action
)
await
event
.
addNotifications
(
notifications
)
const
event_notifications
=
await
event
.
getNotifications
()
const
promises
=
eventNotifications
.
map
(
async
e
=>
{
const
notification
=
await
Notification
.
findByPk
(
e
.
notificationId
)
const
promises
=
event_notifications
.
map
(
async
notification
=>
{
try
{
// await notification.event_notification.update({ status: 'sending' })
await
notifier
.
sendNotification
(
notification
,
event
)
e
.
status
=
'
sent
'
notification
.
event_notification
.
status
=
'
sent
'
}
catch
(
err
)
{
e
.
status
=
'
error
'
debug
(
err
)
notification
.
event_notification
.
status
=
'
error
'
}
return
e
.
save
()
return
notification
.
event_notification
.
save
()
})
return
Promise
.
all
(
promises
)
},
async
notify
()
{
...
...
@@ -68,7 +59,7 @@ const notifier = {
if
(
!
event
.
place
)
{
return
}
const
notification
=
await
Notification
.
findByPk
(
e
.
notificationId
)
try
{
await
sendNotification
(
notification
,
event
,
e
)
await
sendNotification
(
type
,
notification
,
event
)
e
.
status
=
'
sent
'
return
e
.
save
()
}
catch
(
err
)
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment