aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/notifier/shared/abuse
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-07-30 16:51:27 +0200
committerChocobozzz <me@florianbigard.com>2021-08-02 10:39:51 +0200
commitd26836cd95e981d636006652927773c7943e77ce (patch)
tree934a4a835bfddbf1c2c7da98d84ebd7623d60d49 /server/lib/notifier/shared/abuse
parent2bee9db56ade2b3b1bb0efa8716840d87efdb93f (diff)
downloadPeerTube-d26836cd95e981d636006652927773c7943e77ce.tar.gz
PeerTube-d26836cd95e981d636006652927773c7943e77ce.tar.zst
PeerTube-d26836cd95e981d636006652927773c7943e77ce.zip
Refactor notifier
Diffstat (limited to 'server/lib/notifier/shared/abuse')
-rw-r--r--server/lib/notifier/shared/abuse/abstract-new-abuse-message.ts67
-rw-r--r--server/lib/notifier/shared/abuse/abuse-state-change-for-reporter.ts74
-rw-r--r--server/lib/notifier/shared/abuse/index.ts4
-rw-r--r--server/lib/notifier/shared/abuse/new-abuse-for-moderators.ts119
-rw-r--r--server/lib/notifier/shared/abuse/new-abuse-message-for-moderators.ts32
-rw-r--r--server/lib/notifier/shared/abuse/new-abuse-message-for-reporter.ts36
6 files changed, 332 insertions, 0 deletions
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 @@
1import { WEBSERVER } from '@server/initializers/constants'
2import { AccountModel } from '@server/models/account/account'
3import { UserNotificationModel } from '@server/models/user/user-notification'
4import { MAbuseFull, MAbuseMessage, MAccountDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models'
5import { UserNotificationType } from '@shared/models'
6import { AbstractNotification } from '../common/abstract-notification'
7
8export type NewAbuseMessagePayload = {
9 abuse: MAbuseFull
10 message: MAbuseMessage
11}
12
13export abstract class AbstractNewAbuseMessage extends AbstractNotification <NewAbuseMessagePayload> {
14 protected messageAccount: MAccountDefault
15
16 async loadMessageAccount () {
17 this.messageAccount = await AccountModel.load(this.message.accountId)
18 }
19
20 getSetting (user: MUserWithNotificationSetting) {
21 return user.NotificationSetting.abuseNewMessage
22 }
23
24 async createNotification (user: MUserWithNotificationSetting) {
25 const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
26 type: UserNotificationType.ABUSE_NEW_MESSAGE,
27 userId: user.id,
28 abuseId: this.abuse.id
29 })
30 notification.Abuse = this.abuse
31
32 return notification
33 }
34
35 protected createEmailFor (to: string, target: 'moderator' | 'reporter') {
36 const text = 'New message on report #' + this.abuse.id
37 const abuseUrl = target === 'moderator'
38 ? WEBSERVER.URL + '/admin/moderation/abuses/list?search=%23' + this.abuse.id
39 : WEBSERVER.URL + '/my-account/abuses?search=%23' + this.abuse.id
40
41 const action = {
42 text,
43 url: abuseUrl
44 }
45
46 return {
47 template: 'abuse-new-message',
48 to,
49 subject: text,
50 locals: {
51 abuseId: this.abuse.id,
52 abuseUrl: action.url,
53 messageAccountName: this.messageAccount.getDisplayName(),
54 messageText: this.message.message,
55 action
56 }
57 }
58 }
59
60 protected get abuse () {
61 return this.payload.abuse
62 }
63
64 protected get message () {
65 return this.payload.message
66 }
67}
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 @@
1import { logger } from '@server/helpers/logger'
2import { WEBSERVER } from '@server/initializers/constants'
3import { getAbuseTargetUrl } from '@server/lib/activitypub/url'
4import { UserModel } from '@server/models/user/user'
5import { UserNotificationModel } from '@server/models/user/user-notification'
6import { MAbuseFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models'
7import { AbuseState, UserNotificationType } from '@shared/models'
8import { AbstractNotification } from '../common/abstract-notification'
9
10export class AbuseStateChangeForReporter extends AbstractNotification <MAbuseFull> {
11
12 private user: MUserDefault
13
14 async prepare () {
15 const reporter = this.abuse.ReporterAccount
16 if (reporter.isOwned() !== true) return
17
18 this.user = await UserModel.loadByAccountActorId(this.abuse.ReporterAccount.actorId)
19 }
20
21 log () {
22 logger.info('Notifying reporter of abuse % of state change.', getAbuseTargetUrl(this.abuse))
23 }
24
25 getSetting (user: MUserWithNotificationSetting) {
26 return user.NotificationSetting.abuseStateChange
27 }
28
29 getTargetUsers () {
30 if (!this.user) return []
31
32 return [ this.user ]
33 }
34
35 async createNotification (user: MUserWithNotificationSetting) {
36 const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
37 type: UserNotificationType.ABUSE_STATE_CHANGE,
38 userId: user.id,
39 abuseId: this.abuse.id
40 })
41 notification.Abuse = this.abuse
42
43 return notification
44 }
45
46 createEmail (to: string) {
47 const text = this.abuse.state === AbuseState.ACCEPTED
48 ? 'Report #' + this.abuse.id + ' has been accepted'
49 : 'Report #' + this.abuse.id + ' has been rejected'
50
51 const abuseUrl = WEBSERVER.URL + '/my-account/abuses?search=%23' + this.abuse.id
52
53 const action = {
54 text,
55 url: abuseUrl
56 }
57
58 return {
59 template: 'abuse-state-change',
60 to,
61 subject: text,
62 locals: {
63 action,
64 abuseId: this.abuse.id,
65 abuseUrl,
66 isAccepted: this.abuse.state === AbuseState.ACCEPTED
67 }
68 }
69 }
70
71 private get abuse () {
72 return this.payload
73 }
74}
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 @@
1export * from './abuse-state-change-for-reporter'
2export * from './new-abuse-for-moderators'
3export * from './new-abuse-message-for-reporter'
4export * 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 @@
1import { logger } from '@server/helpers/logger'
2import { WEBSERVER } from '@server/initializers/constants'
3import { getAbuseTargetUrl } from '@server/lib/activitypub/url'
4import { UserModel } from '@server/models/user/user'
5import { UserNotificationModel } from '@server/models/user/user-notification'
6import { MAbuseFull, MUserDefault, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/types/models'
7import { UserAbuse, UserNotificationType, UserRight } from '@shared/models'
8import { AbstractNotification } from '../common/abstract-notification'
9
10export type NewAbusePayload = { abuse: UserAbuse, abuseInstance: MAbuseFull, reporter: string }
11
12export class NewAbuseForModerators extends AbstractNotification <NewAbusePayload> {
13 private moderators: MUserDefault[]
14
15 async prepare () {
16 this.moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
17 }
18
19 log () {
20 logger.info('Notifying %s user/moderators of new abuse %s.', this.moderators.length, getAbuseTargetUrl(this.payload.abuseInstance))
21 }
22
23 getSetting (user: MUserWithNotificationSetting) {
24 return user.NotificationSetting.abuseAsModerator
25 }
26
27 getTargetUsers () {
28 return this.moderators
29 }
30
31 async createNotification (user: MUserWithNotificationSetting) {
32 const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
33 type: UserNotificationType.NEW_ABUSE_FOR_MODERATORS,
34 userId: user.id,
35 abuseId: this.payload.abuseInstance.id
36 })
37 notification.Abuse = this.payload.abuseInstance
38
39 return notification
40 }
41
42 createEmail (to: string) {
43 const abuseInstance = this.payload.abuseInstance
44
45 if (abuseInstance.VideoAbuse) return this.createVideoAbuseEmail(to)
46 if (abuseInstance.VideoCommentAbuse) return this.createCommentAbuseEmail(to)
47
48 return this.createAccountAbuseEmail(to)
49 }
50
51 private createVideoAbuseEmail (to: string) {
52 const video = this.payload.abuseInstance.VideoAbuse.Video
53 const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
54
55 return {
56 template: 'video-abuse-new',
57 to,
58 subject: `New video abuse report from ${this.payload.reporter}`,
59 locals: {
60 videoUrl,
61 isLocal: video.remote === false,
62 videoCreatedAt: new Date(video.createdAt).toLocaleString(),
63 videoPublishedAt: new Date(video.publishedAt).toLocaleString(),
64 videoName: video.name,
65 reason: this.payload.abuse.reason,
66 videoChannel: this.payload.abuse.video.channel,
67 reporter: this.payload.reporter,
68 action: this.buildEmailAction()
69 }
70 }
71 }
72
73 private createCommentAbuseEmail (to: string) {
74 const comment = this.payload.abuseInstance.VideoCommentAbuse.VideoComment
75 const commentUrl = WEBSERVER.URL + comment.Video.getWatchStaticPath() + ';threadId=' + comment.getThreadId()
76
77 return {
78 template: 'video-comment-abuse-new',
79 to,
80 subject: `New comment abuse report from ${this.payload.reporter}`,
81 locals: {
82 commentUrl,
83 videoName: comment.Video.name,
84 isLocal: comment.isOwned(),
85 commentCreatedAt: new Date(comment.createdAt).toLocaleString(),
86 reason: this.payload.abuse.reason,
87 flaggedAccount: this.payload.abuseInstance.FlaggedAccount.getDisplayName(),
88 reporter: this.payload.reporter,
89 action: this.buildEmailAction()
90 }
91 }
92 }
93
94 private createAccountAbuseEmail (to: string) {
95 const account = this.payload.abuseInstance.FlaggedAccount
96 const accountUrl = account.getClientUrl()
97
98 return {
99 template: 'account-abuse-new',
100 to,
101 subject: `New account abuse report from ${this.payload.reporter}`,
102 locals: {
103 accountUrl,
104 accountDisplayName: account.getDisplayName(),
105 isLocal: account.isOwned(),
106 reason: this.payload.abuse.reason,
107 reporter: this.payload.reporter,
108 action: this.buildEmailAction()
109 }
110 }
111 }
112
113 private buildEmailAction () {
114 return {
115 text: 'View report #' + this.payload.abuseInstance.id,
116 url: WEBSERVER.URL + '/admin/moderation/abuses/list?search=%23' + this.payload.abuseInstance.id
117 }
118 }
119}
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 @@
1import { logger } from '@server/helpers/logger'
2import { getAbuseTargetUrl } from '@server/lib/activitypub/url'
3import { UserModel } from '@server/models/user/user'
4import { MUserDefault } from '@server/types/models'
5import { UserRight } from '@shared/models'
6import { AbstractNewAbuseMessage } from './abstract-new-abuse-message'
7
8export class NewAbuseMessageForModerators extends AbstractNewAbuseMessage {
9 private moderators: MUserDefault[]
10
11 async prepare () {
12 this.moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
13
14 // Don't notify my own message
15 this.moderators = this.moderators.filter(m => m.Account.id !== this.message.accountId)
16 if (this.moderators.length === 0) return
17
18 await this.loadMessageAccount()
19 }
20
21 log () {
22 logger.info('Notifying moderators of new abuse message on %s.', getAbuseTargetUrl(this.abuse))
23 }
24
25 getTargetUsers () {
26 return this.moderators
27 }
28
29 createEmail (to: string) {
30 return this.createEmailFor(to, 'moderator')
31 }
32}
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 @@
1import { logger } from '@server/helpers/logger'
2import { getAbuseTargetUrl } from '@server/lib/activitypub/url'
3import { UserModel } from '@server/models/user/user'
4import { MUserDefault } from '@server/types/models'
5import { AbstractNewAbuseMessage } from './abstract-new-abuse-message'
6
7export class NewAbuseMessageForReporter extends AbstractNewAbuseMessage {
8 private reporter: MUserDefault
9
10 async prepare () {
11 // Only notify our users
12 if (this.abuse.ReporterAccount.isOwned() !== true) return
13
14 await this.loadMessageAccount()
15
16 const reporter = await UserModel.loadByAccountActorId(this.abuse.ReporterAccount.actorId)
17 // Don't notify my own message
18 if (reporter.Account.id === this.message.accountId) return
19
20 this.reporter = reporter
21 }
22
23 log () {
24 logger.info('Notifying reporter of new abuse message on %s.', getAbuseTargetUrl(this.abuse))
25 }
26
27 getTargetUsers () {
28 if (!this.reporter) return []
29
30 return [ this.reporter ]
31 }
32
33 createEmail (to: string) {
34 return this.createEmailFor(to, 'reporter')
35 }
36}