From d26836cd95e981d636006652927773c7943e77ce Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 30 Jul 2021 16:51:27 +0200 Subject: Refactor notifier --- .../shared/abuse/abstract-new-abuse-message.ts | 67 ++++++++++++ .../abuse/abuse-state-change-for-reporter.ts | 74 +++++++++++++ server/lib/notifier/shared/abuse/index.ts | 4 + .../shared/abuse/new-abuse-for-moderators.ts | 119 +++++++++++++++++++++ .../abuse/new-abuse-message-for-moderators.ts | 32 ++++++ .../shared/abuse/new-abuse-message-for-reporter.ts | 36 +++++++ 6 files changed, 332 insertions(+) create mode 100644 server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts create mode 100644 server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts create mode 100644 server/lib/notifier/shared/abuse/index.ts create mode 100644 server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts create mode 100644 server/lib/notifier/shared/abuse/new-abuse-message-for-moderators.ts create mode 100644 server/lib/notifier/shared/abuse/new-abuse-message-for-reporter.ts (limited to 'server/lib/notifier/shared/abuse') diff --git a/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts b/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts new file mode 100644 index 000000000..1425c38ec --- /dev/null +++ b/server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts @@ -0,0 +1,67 @@ +import { WEBSERVER } from '@server/initializers/constants' +import { AccountModel } from '@server/models/account/account' +import { UserNotificationModel } from '@server/models/user/user-notification' +import { MAbuseFull, MAbuseMessage, MAccountDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models' +import { UserNotificationType } from '@shared/models' +import { AbstractNotification } from '../common/abstract-notification' + +export type NewAbuseMessagePayload = { + abuse: MAbuseFull + message: MAbuseMessage +} + +export abstract class AbstractNewAbuseMessage extends AbstractNotification { + protected messageAccount: MAccountDefault + + async loadMessageAccount () { + this.messageAccount = await AccountModel.load(this.message.accountId) + } + + getSetting (user: MUserWithNotificationSetting) { + return user.NotificationSetting.abuseNewMessage + } + + async createNotification (user: MUserWithNotificationSetting) { + const notification = await UserNotificationModel.create({ + type: UserNotificationType.ABUSE_NEW_MESSAGE, + userId: user.id, + abuseId: this.abuse.id + }) + notification.Abuse = this.abuse + + return notification + } + + protected createEmailFor (to: string, target: 'moderator' | 'reporter') { + const text = 'New message on report #' + this.abuse.id + const abuseUrl = target === 'moderator' + ? WEBSERVER.URL + '/admin/moderation/abuses/list?search=%23' + this.abuse.id + : WEBSERVER.URL + '/my-account/abuses?search=%23' + this.abuse.id + + const action = { + text, + url: abuseUrl + } + + return { + template: 'abuse-new-message', + to, + subject: text, + locals: { + abuseId: this.abuse.id, + abuseUrl: action.url, + messageAccountName: this.messageAccount.getDisplayName(), + messageText: this.message.message, + action + } + } + } + + protected get abuse () { + return this.payload.abuse + } + + protected get message () { + return this.payload.message + } +} 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 new file mode 100644 index 000000000..968b5bca9 --- /dev/null +++ b/server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts @@ -0,0 +1,74 @@ +import { logger } from '@server/helpers/logger' +import { WEBSERVER } from '@server/initializers/constants' +import { getAbuseTargetUrl } from '@server/lib/activitypub/url' +import { UserModel } from '@server/models/user/user' +import { UserNotificationModel } from '@server/models/user/user-notification' +import { MAbuseFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models' +import { AbuseState, UserNotificationType } from '@shared/models' +import { AbstractNotification } from '../common/abstract-notification' + +export class AbuseStateChangeForReporter extends AbstractNotification { + + private user: MUserDefault + + async prepare () { + const reporter = this.abuse.ReporterAccount + if (reporter.isOwned() !== true) return + + this.user = await UserModel.loadByAccountActorId(this.abuse.ReporterAccount.actorId) + } + + log () { + logger.info('Notifying reporter of abuse % of state change.', getAbuseTargetUrl(this.abuse)) + } + + getSetting (user: MUserWithNotificationSetting) { + return user.NotificationSetting.abuseStateChange + } + + getTargetUsers () { + if (!this.user) return [] + + return [ this.user ] + } + + async createNotification (user: MUserWithNotificationSetting) { + const notification = await UserNotificationModel.create({ + type: UserNotificationType.ABUSE_STATE_CHANGE, + userId: user.id, + abuseId: this.abuse.id + }) + notification.Abuse = this.abuse + + return notification + } + + createEmail (to: string) { + const text = this.abuse.state === AbuseState.ACCEPTED + ? 'Report #' + this.abuse.id + ' has been accepted' + : 'Report #' + this.abuse.id + ' has been rejected' + + const abuseUrl = WEBSERVER.URL + '/my-account/abuses?search=%23' + this.abuse.id + + const action = { + text, + url: abuseUrl + } + + return { + template: 'abuse-state-change', + to, + subject: text, + locals: { + action, + abuseId: this.abuse.id, + abuseUrl, + isAccepted: this.abuse.state === AbuseState.ACCEPTED + } + } + } + + private get abuse () { + return this.payload + } +} diff --git a/server/lib/notifier/shared/abuse/index.ts b/server/lib/notifier/shared/abuse/index.ts new file mode 100644 index 000000000..7b54c5591 --- /dev/null +++ b/server/lib/notifier/shared/abuse/index.ts @@ -0,0 +1,4 @@ +export * from './abuse-state-change-for-reporter' +export * from './new-abuse-for-moderators' +export * from './new-abuse-message-for-reporter' +export * from './new-abuse-message-for-moderators' diff --git a/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts b/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts new file mode 100644 index 000000000..c3c7c5515 --- /dev/null +++ b/server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts @@ -0,0 +1,119 @@ +import { logger } from '@server/helpers/logger' +import { WEBSERVER } from '@server/initializers/constants' +import { getAbuseTargetUrl } from '@server/lib/activitypub/url' +import { UserModel } from '@server/models/user/user' +import { UserNotificationModel } from '@server/models/user/user-notification' +import { MAbuseFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models' +import { UserAbuse, UserNotificationType, UserRight } from '@shared/models' +import { AbstractNotification } from '../common/abstract-notification' + +export type NewAbusePayload = { abuse: UserAbuse, abuseInstance: MAbuseFull, reporter: string } + +export class NewAbuseForModerators extends AbstractNotification { + private moderators: MUserDefault[] + + async prepare () { + this.moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES) + } + + log () { + logger.info('Notifying %s user/moderators of new abuse %s.', this.moderators.length, getAbuseTargetUrl(this.payload.abuseInstance)) + } + + getSetting (user: MUserWithNotificationSetting) { + return user.NotificationSetting.abuseAsModerator + } + + getTargetUsers () { + return this.moderators + } + + async createNotification (user: MUserWithNotificationSetting) { + const notification = await UserNotificationModel.create({ + type: UserNotificationType.NEW_ABUSE_FOR_MODERATORS, + userId: user.id, + abuseId: this.payload.abuseInstance.id + }) + notification.Abuse = this.payload.abuseInstance + + return notification + } + + createEmail (to: string) { + const abuseInstance = this.payload.abuseInstance + + if (abuseInstance.VideoAbuse) return this.createVideoAbuseEmail(to) + if (abuseInstance.VideoCommentAbuse) return this.createCommentAbuseEmail(to) + + return this.createAccountAbuseEmail(to) + } + + private createVideoAbuseEmail (to: string) { + const video = this.payload.abuseInstance.VideoAbuse.Video + const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() + + return { + template: 'video-abuse-new', + to, + subject: `New video abuse report from ${this.payload.reporter}`, + locals: { + videoUrl, + isLocal: video.remote === false, + videoCreatedAt: new Date(video.createdAt).toLocaleString(), + videoPublishedAt: new Date(video.publishedAt).toLocaleString(), + videoName: video.name, + reason: this.payload.abuse.reason, + videoChannel: this.payload.abuse.video.channel, + reporter: this.payload.reporter, + action: this.buildEmailAction() + } + } + } + + private createCommentAbuseEmail (to: string) { + const comment = this.payload.abuseInstance.VideoCommentAbuse.VideoComment + const commentUrl = WEBSERVER.URL + comment.Video.getWatchStaticPath() + ';threadId=' + comment.getThreadId() + + return { + template: 'video-comment-abuse-new', + to, + subject: `New comment abuse report from ${this.payload.reporter}`, + locals: { + commentUrl, + videoName: comment.Video.name, + isLocal: comment.isOwned(), + commentCreatedAt: new Date(comment.createdAt).toLocaleString(), + reason: this.payload.abuse.reason, + flaggedAccount: this.payload.abuseInstance.FlaggedAccount.getDisplayName(), + reporter: this.payload.reporter, + action: this.buildEmailAction() + } + } + } + + private createAccountAbuseEmail (to: string) { + const account = this.payload.abuseInstance.FlaggedAccount + const accountUrl = account.getClientUrl() + + return { + template: 'account-abuse-new', + to, + subject: `New account abuse report from ${this.payload.reporter}`, + locals: { + accountUrl, + accountDisplayName: account.getDisplayName(), + isLocal: account.isOwned(), + reason: this.payload.abuse.reason, + reporter: this.payload.reporter, + action: this.buildEmailAction() + } + } + } + + private buildEmailAction () { + return { + text: 'View report #' + this.payload.abuseInstance.id, + url: WEBSERVER.URL + '/admin/moderation/abuses/list?search=%23' + this.payload.abuseInstance.id + } + } +} diff --git a/server/lib/notifier/shared/abuse/new-abuse-message-for-moderators.ts b/server/lib/notifier/shared/abuse/new-abuse-message-for-moderators.ts new file mode 100644 index 000000000..9d0629690 --- /dev/null +++ b/server/lib/notifier/shared/abuse/new-abuse-message-for-moderators.ts @@ -0,0 +1,32 @@ +import { logger } from '@server/helpers/logger' +import { getAbuseTargetUrl } from '@server/lib/activitypub/url' +import { UserModel } from '@server/models/user/user' +import { MUserDefault } from '@server/types/models' +import { UserRight } from '@shared/models' +import { AbstractNewAbuseMessage } from './abstract-new-abuse-message' + +export class NewAbuseMessageForModerators extends AbstractNewAbuseMessage { + private moderators: MUserDefault[] + + async prepare () { + this.moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES) + + // Don't notify my own message + this.moderators = this.moderators.filter(m => m.Account.id !== this.message.accountId) + if (this.moderators.length === 0) return + + await this.loadMessageAccount() + } + + log () { + logger.info('Notifying moderators of new abuse message on %s.', getAbuseTargetUrl(this.abuse)) + } + + getTargetUsers () { + return this.moderators + } + + createEmail (to: string) { + return this.createEmailFor(to, 'moderator') + } +} diff --git a/server/lib/notifier/shared/abuse/new-abuse-message-for-reporter.ts b/server/lib/notifier/shared/abuse/new-abuse-message-for-reporter.ts new file mode 100644 index 000000000..c5bbb5447 --- /dev/null +++ b/server/lib/notifier/shared/abuse/new-abuse-message-for-reporter.ts @@ -0,0 +1,36 @@ +import { logger } from '@server/helpers/logger' +import { getAbuseTargetUrl } from '@server/lib/activitypub/url' +import { UserModel } from '@server/models/user/user' +import { MUserDefault } from '@server/types/models' +import { AbstractNewAbuseMessage } from './abstract-new-abuse-message' + +export class NewAbuseMessageForReporter extends AbstractNewAbuseMessage { + private reporter: MUserDefault + + async prepare () { + // Only notify our users + if (this.abuse.ReporterAccount.isOwned() !== true) return + + await this.loadMessageAccount() + + const reporter = await UserModel.loadByAccountActorId(this.abuse.ReporterAccount.actorId) + // Don't notify my own message + if (reporter.Account.id === this.message.accountId) return + + this.reporter = reporter + } + + log () { + logger.info('Notifying reporter of new abuse message on %s.', getAbuseTargetUrl(this.abuse)) + } + + getTargetUsers () { + if (!this.reporter) return [] + + return [ this.reporter ] + } + + createEmail (to: string) { + return this.createEmailFor(to, 'reporter') + } +} -- cgit v1.2.3