From 785f1897a42984ece9c6f65829d195d67e331d95 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 3 Aug 2022 11:33:43 +0200 Subject: [PATCH] Add notification plugin hook --- server/lib/notifier/notifier.ts | 15 +++++++++++---- .../shared/abuse/abstract-new-abuse-message.ts | 4 ++-- .../abuse/abuse-state-change-for-reporter.ts | 4 ++-- .../shared/abuse/new-abuse-for-moderators.ts | 4 ++-- .../new-auto-blacklist-for-moderators.ts | 4 ++-- .../shared/blacklist/new-blacklist-for-owner.ts | 4 ++-- .../shared/blacklist/unblacklist-for-owner.ts | 4 ++-- .../notifier/shared/comment/comment-mention.ts | 4 ++-- .../shared/comment/new-comment-for-video-owner.ts | 4 ++-- .../shared/common/abstract-notification.ts | 2 +- .../shared/follow/auto-follow-for-instance.ts | 4 ++-- .../notifier/shared/follow/follow-for-instance.ts | 4 ++-- .../lib/notifier/shared/follow/follow-for-user.ts | 4 ++-- .../instance/new-peertube-version-for-admins.ts | 4 ++-- .../instance/new-plugin-version-for-admins.ts | 4 ++-- .../instance/registration-for-moderators.ts | 4 ++-- .../abstract-owned-video-publication.ts | 4 ++-- .../import-finished-for-owner.ts | 4 ++-- .../new-video-for-subscribers.ts | 4 ++-- .../studio-edition-finished-for-owner.ts | 4 ++-- .../tests/fixtures/peertube-plugin-test/main.js | 1 + server/tests/plugins/action-hooks.ts | 11 +++++++++-- shared/models/plugins/server/server-hook.model.ts | 3 +++ 23 files changed, 61 insertions(+), 43 deletions(-) diff --git a/server/lib/notifier/notifier.ts b/server/lib/notifier/notifier.ts index a6f13780b..d1c4c0215 100644 --- a/server/lib/notifier/notifier.ts +++ b/server/lib/notifier/notifier.ts @@ -7,12 +7,12 @@ import { MAbuseFull, MAbuseMessage, MActorFollowFull, MApplication, MPlugin } fr import { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../../types/models/video' import { JobQueue } from '../job-queue' import { PeerTubeSocket } from '../peertube-socket' +import { Hooks } from '../plugins/hooks' import { AbstractNotification, AbuseStateChangeForReporter, AutoFollowForInstance, CommentMention, - StudioEditionFinishedForOwner, FollowForInstance, FollowForUser, ImportFinishedForOwner, @@ -31,6 +31,7 @@ import { OwnedPublicationAfterScheduleUpdate, OwnedPublicationAfterTranscoding, RegistrationForModerators, + StudioEditionFinishedForOwner, UnblacklistForOwner } from './shared' @@ -222,15 +223,21 @@ class Notifier { for (const user of users) { const setting = object.getSetting(user) - if (this.isWebNotificationEnabled(setting)) { - const notification = await object.createNotification(user) + const webNotificationEnabled = this.isWebNotificationEnabled(setting) + const emailNotificationEnabled = this.isEmailEnabled(user, setting) + const notification = object.createNotification(user) + + if (webNotificationEnabled) { + await notification.save() PeerTubeSocket.Instance.sendNotification(user.id, notification) } - if (this.isEmailEnabled(user, setting)) { + if (emailNotificationEnabled) { toEmails.push(user.email) } + + Hooks.runAction('action:notifier.notification.created', { webNotificationEnabled, emailNotificationEnabled, user, notification }) } for (const to of toEmails) { diff --git a/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts b/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts index a7292de69..1dc1ccfc2 100644 --- a/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts +++ b/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts @@ -21,8 +21,8 @@ export abstract class AbstractNewAbuseMessage extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.ABUSE_NEW_MESSAGE, userId: user.id, abuseId: this.abuse.id diff --git a/server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts b/server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts index d92f7a13b..97e896c6a 100644 --- a/server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts +++ b/server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts @@ -32,8 +32,8 @@ export class AbuseStateChangeForReporter extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.ABUSE_STATE_CHANGE, userId: user.id, abuseId: this.abuse.id diff --git a/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts b/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts index c3c7c5515..7d86fb55f 100644 --- a/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts +++ b/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts @@ -28,8 +28,8 @@ export class NewAbuseForModerators extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_ABUSE_FOR_MODERATORS, userId: user.id, abuseId: this.payload.abuseInstance.id diff --git a/server/lib/notifier/shared/blacklist/new-auto-blacklist-for-moderators.ts b/server/lib/notifier/shared/blacklist/new-auto-blacklist-for-moderators.ts index a92a49a0c..ad2cc00ea 100644 --- a/server/lib/notifier/shared/blacklist/new-auto-blacklist-for-moderators.ts +++ b/server/lib/notifier/shared/blacklist/new-auto-blacklist-for-moderators.ts @@ -26,8 +26,8 @@ export class NewAutoBlacklistForModerators extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS, userId: user.id, videoBlacklistId: this.payload.id diff --git a/server/lib/notifier/shared/blacklist/new-blacklist-for-owner.ts b/server/lib/notifier/shared/blacklist/new-blacklist-for-owner.ts index 45bc30eb2..342b69ec7 100644 --- a/server/lib/notifier/shared/blacklist/new-blacklist-for-owner.ts +++ b/server/lib/notifier/shared/blacklist/new-blacklist-for-owner.ts @@ -28,8 +28,8 @@ export class NewBlacklistForOwner extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.BLACKLIST_ON_MY_VIDEO, userId: user.id, videoBlacklistId: this.payload.id diff --git a/server/lib/notifier/shared/blacklist/unblacklist-for-owner.ts b/server/lib/notifier/shared/blacklist/unblacklist-for-owner.ts index 21f5a1c2d..e6f90e23c 100644 --- a/server/lib/notifier/shared/blacklist/unblacklist-for-owner.ts +++ b/server/lib/notifier/shared/blacklist/unblacklist-for-owner.ts @@ -28,8 +28,8 @@ export class UnblacklistForOwner extends AbstractNotification return [ this.user ] } - async createNotification (user: MUserWithNotificationSetting) { - const notification = await UserNotificationModel.create({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.UNBLACKLIST_ON_MY_VIDEO, userId: user.id, videoId: this.payload.id diff --git a/server/lib/notifier/shared/comment/comment-mention.ts b/server/lib/notifier/shared/comment/comment-mention.ts index ecd1687b4..3074e97db 100644 --- a/server/lib/notifier/shared/comment/comment-mention.ts +++ b/server/lib/notifier/shared/comment/comment-mention.ts @@ -71,8 +71,8 @@ export class CommentMention extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.COMMENT_MENTION, userId: user.id, commentId: this.payload.id diff --git a/server/lib/notifier/shared/comment/new-comment-for-video-owner.ts b/server/lib/notifier/shared/comment/new-comment-for-video-owner.ts index 757502703..4f96439a3 100644 --- a/server/lib/notifier/shared/comment/new-comment-for-video-owner.ts +++ b/server/lib/notifier/shared/comment/new-comment-for-video-owner.ts @@ -38,8 +38,8 @@ export class NewCommentForVideoOwner extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, userId: user.id, commentId: this.payload.id diff --git a/server/lib/notifier/shared/common/abstract-notification.ts b/server/lib/notifier/shared/common/abstract-notification.ts index 53e2e02d5..79403611e 100644 --- a/server/lib/notifier/shared/common/abstract-notification.ts +++ b/server/lib/notifier/shared/common/abstract-notification.ts @@ -13,7 +13,7 @@ export abstract class AbstractNotification abstract getSetting (user: U): UserNotificationSettingValue abstract getTargetUsers (): U[] - abstract createNotification (user: U): Promise + abstract createNotification (user: U): UserNotificationModelForApi abstract createEmail (to: string): EmailPayload | Promise isDisabled (): boolean | Promise { diff --git a/server/lib/notifier/shared/follow/auto-follow-for-instance.ts b/server/lib/notifier/shared/follow/auto-follow-for-instance.ts index 01d2b3563..ab9747ba8 100644 --- a/server/lib/notifier/shared/follow/auto-follow-for-instance.ts +++ b/server/lib/notifier/shared/follow/auto-follow-for-instance.ts @@ -24,8 +24,8 @@ export class AutoFollowForInstance extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.AUTO_INSTANCE_FOLLOWING, userId: user.id, actorFollowId: this.actorFollow.id diff --git a/server/lib/notifier/shared/follow/follow-for-instance.ts b/server/lib/notifier/shared/follow/follow-for-instance.ts index a4a2fbf53..777a12ef4 100644 --- a/server/lib/notifier/shared/follow/follow-for-instance.ts +++ b/server/lib/notifier/shared/follow/follow-for-instance.ts @@ -32,8 +32,8 @@ export class FollowForInstance extends AbstractNotification { return this.admins } - async createNotification (user: MUserWithNotificationSetting) { - const notification = await UserNotificationModel.create({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_INSTANCE_FOLLOWER, userId: user.id, actorFollowId: this.actorFollow.id diff --git a/server/lib/notifier/shared/follow/follow-for-user.ts b/server/lib/notifier/shared/follow/follow-for-user.ts index e579d4487..697c82cdd 100644 --- a/server/lib/notifier/shared/follow/follow-for-user.ts +++ b/server/lib/notifier/shared/follow/follow-for-user.ts @@ -45,8 +45,8 @@ export class FollowForUser extends AbstractNotification { return [ this.user ] } - async createNotification (user: MUserWithNotificationSetting) { - const notification = await UserNotificationModel.create({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_FOLLOW, userId: user.id, actorFollowId: this.actorFollow.id diff --git a/server/lib/notifier/shared/instance/new-peertube-version-for-admins.ts b/server/lib/notifier/shared/instance/new-peertube-version-for-admins.ts index 6b5ac808a..f5646c666 100644 --- a/server/lib/notifier/shared/instance/new-peertube-version-for-admins.ts +++ b/server/lib/notifier/shared/instance/new-peertube-version-for-admins.ts @@ -30,8 +30,8 @@ export class NewPeerTubeVersionForAdmins extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_PEERTUBE_VERSION, userId: user.id, applicationId: this.payload.application.id diff --git a/server/lib/notifier/shared/instance/new-plugin-version-for-admins.ts b/server/lib/notifier/shared/instance/new-plugin-version-for-admins.ts index 874b10a3d..547c6726c 100644 --- a/server/lib/notifier/shared/instance/new-plugin-version-for-admins.ts +++ b/server/lib/notifier/shared/instance/new-plugin-version-for-admins.ts @@ -26,8 +26,8 @@ export class NewPluginVersionForAdmins extends AbstractNotification { return this.admins } - async createNotification (user: MUserWithNotificationSetting) { - const notification = await UserNotificationModel.create({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_PLUGIN_VERSION, userId: user.id, pluginId: this.plugin.id diff --git a/server/lib/notifier/shared/instance/registration-for-moderators.ts b/server/lib/notifier/shared/instance/registration-for-moderators.ts index 2a48ef2fa..e92467424 100644 --- a/server/lib/notifier/shared/instance/registration-for-moderators.ts +++ b/server/lib/notifier/shared/instance/registration-for-moderators.ts @@ -25,8 +25,8 @@ export class RegistrationForModerators extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_USER_REGISTRATION, userId: user.id, accountId: this.payload.Account.id diff --git a/server/lib/notifier/shared/video-publication/abstract-owned-video-publication.ts b/server/lib/notifier/shared/video-publication/abstract-owned-video-publication.ts index 37435f898..a940cde69 100644 --- a/server/lib/notifier/shared/video-publication/abstract-owned-video-publication.ts +++ b/server/lib/notifier/shared/video-publication/abstract-owned-video-publication.ts @@ -27,8 +27,8 @@ export abstract class AbstractOwnedVideoPublication extends AbstractNotification return [ this.user ] } - async createNotification (user: MUserWithNotificationSetting) { - const notification = await UserNotificationModel.create({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.MY_VIDEO_PUBLISHED, userId: user.id, videoId: this.payload.id diff --git a/server/lib/notifier/shared/video-publication/import-finished-for-owner.ts b/server/lib/notifier/shared/video-publication/import-finished-for-owner.ts index 9f374b6f9..3bd64692f 100644 --- a/server/lib/notifier/shared/video-publication/import-finished-for-owner.ts +++ b/server/lib/notifier/shared/video-publication/import-finished-for-owner.ts @@ -32,8 +32,8 @@ export class ImportFinishedForOwner extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: this.payload.success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR, diff --git a/server/lib/notifier/shared/video-publication/new-video-for-subscribers.ts b/server/lib/notifier/shared/video-publication/new-video-for-subscribers.ts index 4253a0930..df7a5561d 100644 --- a/server/lib/notifier/shared/video-publication/new-video-for-subscribers.ts +++ b/server/lib/notifier/shared/video-publication/new-video-for-subscribers.ts @@ -30,8 +30,8 @@ export class NewVideoForSubscribers extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION, userId: user.id, videoId: this.payload.id diff --git a/server/lib/notifier/shared/video-publication/studio-edition-finished-for-owner.ts b/server/lib/notifier/shared/video-publication/studio-edition-finished-for-owner.ts index ee3027245..f36399f05 100644 --- a/server/lib/notifier/shared/video-publication/studio-edition-finished-for-owner.ts +++ b/server/lib/notifier/shared/video-publication/studio-edition-finished-for-owner.ts @@ -27,8 +27,8 @@ export class StudioEditionFinishedForOwner extends AbstractNotification ({ + createNotification (user: MUserWithNotificationSetting) { + const notification = UserNotificationModel.build({ type: UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED, userId: user.id, videoId: this.payload.id diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index 8d7584eba..b3febfa12 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js @@ -1,6 +1,7 @@ async function register ({ registerHook, registerSetting, settingsManager, storageManager, peertubeHelpers }) { const actionHooks = [ 'action:application.listening', + 'action:notifier.notification.created', 'action:api.video.updated', 'action:api.video.deleted', diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index 209db95a4..405f81d7c 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts @@ -17,8 +17,8 @@ describe('Test plugin action hooks', function () { let videoUUID: string let threadId: number - function checkHook (hook: ServerHookName) { - return servers[0].servers.waitUntilLog('Run hook ' + hook) + function checkHook (hook: ServerHookName, strictCount = true) { + return servers[0].servers.waitUntilLog('Run hook ' + hook, 1, strictCount) } before(async function () { @@ -225,6 +225,13 @@ describe('Test plugin action hooks', function () { }) }) + describe('Notification hook', function () { + + it('Should run action:notifier.notification.created', async function () { + await checkHook('action:notifier.notification.created', false) + }) + }) + after(async function () { await cleanupTests(servers) }) diff --git a/shared/models/plugins/server/server-hook.model.ts b/shared/models/plugins/server/server-hook.model.ts index 5f3a5be10..c8e879323 100644 --- a/shared/models/plugins/server/server-hook.model.ts +++ b/shared/models/plugins/server/server-hook.model.ts @@ -112,6 +112,9 @@ export const serverActionHookObject = { // Fired when the application has been loaded and is listening HTTP requests 'action:application.listening': true, + // Fired when a new notification is created + 'action:notifier.notification.created': true, + // API actions hooks give access to the original express `req` and `res` parameters // Fired when a local video is updated