diff options
author | Chocobozzz <me@florianbigard.com> | 2019-04-08 17:26:01 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-04-08 17:30:48 +0200 |
commit | 883993c81ecc2388d4a4b37b29b81b6de73d264f (patch) | |
tree | f0f76995b6762b10a0c1a7ccc2b5d952f68014ea /server/lib | |
parent | 0dc647775881eb1378b213a530996cd096de24ea (diff) | |
download | PeerTube-883993c81ecc2388d4a4b37b29b81b6de73d264f.tar.gz PeerTube-883993c81ecc2388d4a4b37b29b81b6de73d264f.tar.zst PeerTube-883993c81ecc2388d4a4b37b29b81b6de73d264f.zip |
Add notification on new instance follower (server side)
Diffstat (limited to 'server/lib')
-rw-r--r-- | server/lib/activitypub/actor.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-follow.ts | 19 | ||||
-rw-r--r-- | server/lib/emailer.ts | 18 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/activitypub-follow.ts | 2 | ||||
-rw-r--r-- | server/lib/notifier.ts | 38 | ||||
-rw-r--r-- | server/lib/user.ts | 3 |
6 files changed, 71 insertions, 11 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 63e810642..c0ad07a52 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -342,6 +342,8 @@ function saveActorAndServerAndModelIfNotExist ( | |||
342 | actorCreated.VideoChannel.Account = ownerActor.Account | 342 | actorCreated.VideoChannel.Account = ownerActor.Account |
343 | } | 343 | } |
344 | 344 | ||
345 | actorCreated.Server = server | ||
346 | |||
345 | return actorCreated | 347 | return actorCreated |
346 | } | 348 | } |
347 | } | 349 | } |
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index 140bbe9f1..276a57e60 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts | |||
@@ -24,14 +24,16 @@ export { | |||
24 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
25 | 25 | ||
26 | async function processFollow (actor: ActorModel, targetActorURL: string) { | 26 | async function processFollow (actor: ActorModel, targetActorURL: string) { |
27 | const { actorFollow, created } = await sequelizeTypescript.transaction(async t => { | 27 | const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { |
28 | const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) | 28 | const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) |
29 | 29 | ||
30 | if (!targetActor) throw new Error('Unknown actor') | 30 | if (!targetActor) throw new Error('Unknown actor') |
31 | if (targetActor.isOwned() === false) throw new Error('This is not a local actor.') | 31 | if (targetActor.isOwned() === false) throw new Error('This is not a local actor.') |
32 | 32 | ||
33 | const serverActor = await getServerActor() | 33 | const serverActor = await getServerActor() |
34 | if (targetActor.id === serverActor.id && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { | 34 | const isFollowingInstance = targetActor.id === serverActor.id |
35 | |||
36 | if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { | ||
35 | logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) | 37 | logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) |
36 | 38 | ||
37 | return sendReject(actor, targetActor) | 39 | return sendReject(actor, targetActor) |
@@ -50,9 +52,6 @@ async function processFollow (actor: ActorModel, targetActorURL: string) { | |||
50 | transaction: t | 52 | transaction: t |
51 | }) | 53 | }) |
52 | 54 | ||
53 | actorFollow.ActorFollower = actor | ||
54 | actorFollow.ActorFollowing = targetActor | ||
55 | |||
56 | if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { | 55 | if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { |
57 | actorFollow.state = 'accepted' | 56 | actorFollow.state = 'accepted' |
58 | await actorFollow.save({ transaction: t }) | 57 | await actorFollow.save({ transaction: t }) |
@@ -64,10 +63,16 @@ async function processFollow (actor: ActorModel, targetActorURL: string) { | |||
64 | // Target sends to actor he accepted the follow request | 63 | // Target sends to actor he accepted the follow request |
65 | if (actorFollow.state === 'accepted') await sendAccept(actorFollow) | 64 | if (actorFollow.state === 'accepted') await sendAccept(actorFollow) |
66 | 65 | ||
67 | return { actorFollow, created } | 66 | return { actorFollow, created, isFollowingInstance } |
68 | }) | 67 | }) |
69 | 68 | ||
70 | if (created) Notifier.Instance.notifyOfNewFollow(actorFollow) | 69 | // Rejected |
70 | if (!actorFollow) return | ||
71 | |||
72 | if (created) { | ||
73 | if (isFollowingInstance) Notifier.Instance.notifyOfNewInstanceFollow(actorFollow) | ||
74 | else Notifier.Instance.notifyOfNewUserFollow(actorFollow) | ||
75 | } | ||
71 | 76 | ||
72 | logger.info('Actor %s is followed by actor %s.', targetActorURL, actor.url) | 77 | logger.info('Actor %s is followed by actor %s.', targetActorURL, actor.url) |
73 | } | 78 | } |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index eec97c27e..aa9083362 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -129,6 +129,24 @@ class Emailer { | |||
129 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 129 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
130 | } | 130 | } |
131 | 131 | ||
132 | addNewInstanceFollowerNotification (to: string[], actorFollow: ActorFollowModel) { | ||
133 | const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' | ||
134 | |||
135 | const text = `Hi dear admin,\n\n` + | ||
136 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + | ||
137 | `\n\n` + | ||
138 | `Cheers,\n` + | ||
139 | `PeerTube.` | ||
140 | |||
141 | const emailPayload: EmailPayload = { | ||
142 | to, | ||
143 | subject: 'New instance follower', | ||
144 | text | ||
145 | } | ||
146 | |||
147 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
148 | } | ||
149 | |||
132 | myVideoPublishedNotification (to: string[], video: VideoModel) { | 150 | myVideoPublishedNotification (to: string[], video: VideoModel) { |
133 | const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() | 151 | const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() |
134 | 152 | ||
diff --git a/server/lib/job-queue/handlers/activitypub-follow.ts b/server/lib/job-queue/handlers/activitypub-follow.ts index b4d381062..e7e5ff950 100644 --- a/server/lib/job-queue/handlers/activitypub-follow.ts +++ b/server/lib/job-queue/handlers/activitypub-follow.ts | |||
@@ -73,5 +73,5 @@ async function follow (fromActor: ActorModel, targetActor: ActorModel) { | |||
73 | return actorFollow | 73 | return actorFollow |
74 | }) | 74 | }) |
75 | 75 | ||
76 | if (actorFollow.state === 'accepted') Notifier.Instance.notifyOfNewFollow(actorFollow) | 76 | if (actorFollow.state === 'accepted') Notifier.Instance.notifyOfNewUserFollow(actorFollow) |
77 | } | 77 | } |
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index 9fe93ec0d..91b71cc64 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts | |||
@@ -92,18 +92,25 @@ class Notifier { | |||
92 | .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err })) | 92 | .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err })) |
93 | } | 93 | } |
94 | 94 | ||
95 | notifyOfNewFollow (actorFollow: ActorFollowModel): void { | 95 | notifyOfNewUserFollow (actorFollow: ActorFollowModel): void { |
96 | this.notifyUserOfNewActorFollow(actorFollow) | 96 | this.notifyUserOfNewActorFollow(actorFollow) |
97 | .catch(err => { | 97 | .catch(err => { |
98 | logger.error( | 98 | logger.error( |
99 | 'Cannot notify owner of channel %s of a new follow by %s.', | 99 | 'Cannot notify owner of channel %s of a new follow by %s.', |
100 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), | 100 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), |
101 | actorFollow.ActorFollower.Account.getDisplayName(), | 101 | actorFollow.ActorFollower.Account.getDisplayName(), |
102 | err | 102 | { err } |
103 | ) | 103 | ) |
104 | }) | 104 | }) |
105 | } | 105 | } |
106 | 106 | ||
107 | notifyOfNewInstanceFollow (actorFollow: ActorFollowModel): void { | ||
108 | this.notifyAdminsOfNewInstanceFollow(actorFollow) | ||
109 | .catch(err => { | ||
110 | logger.error('Cannot notify administrators of new follower %s.', actorFollow.ActorFollower.url, { err }) | ||
111 | }) | ||
112 | } | ||
113 | |||
107 | private async notifySubscribersOfNewVideo (video: VideoModel) { | 114 | private async notifySubscribersOfNewVideo (video: VideoModel) { |
108 | // List all followers that are users | 115 | // List all followers that are users |
109 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) | 116 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) |
@@ -261,6 +268,33 @@ class Notifier { | |||
261 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | 268 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) |
262 | } | 269 | } |
263 | 270 | ||
271 | private async notifyAdminsOfNewInstanceFollow (actorFollow: ActorFollowModel) { | ||
272 | const admins = await UserModel.listWithRight(UserRight.MANAGE_SERVER_FOLLOW) | ||
273 | |||
274 | logger.info('Notifying %d administrators of new instance follower: %s.', admins.length, actorFollow.ActorFollower.url) | ||
275 | |||
276 | function settingGetter (user: UserModel) { | ||
277 | return user.NotificationSetting.newInstanceFollower | ||
278 | } | ||
279 | |||
280 | async function notificationCreator (user: UserModel) { | ||
281 | const notification = await UserNotificationModel.create({ | ||
282 | type: UserNotificationType.NEW_INSTANCE_FOLLOWER, | ||
283 | userId: user.id, | ||
284 | actorFollowId: actorFollow.id | ||
285 | }) | ||
286 | notification.ActorFollow = actorFollow | ||
287 | |||
288 | return notification | ||
289 | } | ||
290 | |||
291 | function emailSender (emails: string[]) { | ||
292 | return Emailer.Instance.addNewInstanceFollowerNotification(emails, actorFollow) | ||
293 | } | ||
294 | |||
295 | return this.notify({ users: admins, settingGetter, notificationCreator, emailSender }) | ||
296 | } | ||
297 | |||
264 | private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { | 298 | private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { |
265 | const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) | 299 | const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) |
266 | if (moderators.length === 0) return | 300 | if (moderators.length === 0) return |
diff --git a/server/lib/user.ts b/server/lib/user.ts index 5588b0f76..6fbe3ed03 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -110,7 +110,8 @@ function createDefaultUserNotificationSettings (user: UserModel, t: Sequelize.Tr | |||
110 | blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | 110 | blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
111 | newUserRegistration: UserNotificationSettingValue.WEB, | 111 | newUserRegistration: UserNotificationSettingValue.WEB, |
112 | commentMention: UserNotificationSettingValue.WEB, | 112 | commentMention: UserNotificationSettingValue.WEB, |
113 | newFollow: UserNotificationSettingValue.WEB | 113 | newFollow: UserNotificationSettingValue.WEB, |
114 | newInstanceFollower: UserNotificationSettingValue.WEB | ||
114 | } | 115 | } |
115 | 116 | ||
116 | return UserNotificationSettingModel.create(values, { transaction: t }) | 117 | return UserNotificationSettingModel.create(values, { transaction: t }) |