diff options
author | Chocobozzz <me@florianbigard.com> | 2020-07-08 15:51:46 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2020-07-10 14:02:41 +0200 |
commit | 310b5219b38427f0c2c7ba57225afdd8f3064380 (patch) | |
tree | 853ff7e4e66425ca47b0999384eeb08ed14b28ff | |
parent | 811cef146c841ef8530bc812c05dfee77e0f2998 (diff) | |
download | PeerTube-310b5219b38427f0c2c7ba57225afdd8f3064380.tar.gz PeerTube-310b5219b38427f0c2c7ba57225afdd8f3064380.tar.zst PeerTube-310b5219b38427f0c2c7ba57225afdd8f3064380.zip |
Add new abuses tests
29 files changed, 858 insertions, 375 deletions
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html index 167f32fe6..333438269 100644 --- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html +++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html | |||
@@ -138,8 +138,8 @@ | |||
138 | <tr> | 138 | <tr> |
139 | <td colspan="6"> | 139 | <td colspan="6"> |
140 | <div class="no-results"> | 140 | <div class="no-results"> |
141 | <ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container> | 141 | <ng-container *ngIf="search" i18n>No abuses found matching current filters.</ng-container> |
142 | <ng-container *ngIf="!search" i18n>No video abuses found.</ng-container> | 142 | <ng-container *ngIf="!search" i18n>No abuses found.</ng-container> |
143 | </div> | 143 | </div> |
144 | </td> | 144 | </td> |
145 | </tr> | 145 | </tr> |
diff --git a/client/src/app/shared/shared-main/users/user-notification.model.ts b/client/src/app/shared/shared-main/users/user-notification.model.ts index 389a242fd..a137f8c62 100644 --- a/client/src/app/shared/shared-main/users/user-notification.model.ts +++ b/client/src/app/shared/shared-main/users/user-notification.model.ts | |||
@@ -118,7 +118,7 @@ export class UserNotification implements UserNotificationServer { | |||
118 | this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ] | 118 | this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ] |
119 | break | 119 | break |
120 | 120 | ||
121 | case UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS: | 121 | case UserNotificationType.NEW_ABUSE_FOR_MODERATORS: |
122 | this.abuseUrl = '/admin/moderation/abuses/list' | 122 | this.abuseUrl = '/admin/moderation/abuses/list' |
123 | 123 | ||
124 | if (this.abuse.video) this.videoUrl = this.buildVideoUrl(this.abuse.video) | 124 | if (this.abuse.video) this.videoUrl = this.buildVideoUrl(this.abuse.video) |
diff --git a/client/src/app/shared/shared-main/users/user-notifications.component.html b/client/src/app/shared/shared-main/users/user-notifications.component.html index 8d31eab0d..2b341af2c 100644 --- a/client/src/app/shared/shared-main/users/user-notifications.component.html +++ b/client/src/app/shared/shared-main/users/user-notifications.component.html | |||
@@ -42,7 +42,7 @@ | |||
42 | </div> | 42 | </div> |
43 | </ng-container> | 43 | </ng-container> |
44 | 44 | ||
45 | <ng-container *ngSwitchCase="UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS"> | 45 | <ng-container *ngSwitchCase="UserNotificationType.NEW_ABUSE_FOR_MODERATORS"> |
46 | <my-global-icon iconName="flag" aria-hidden="true"></my-global-icon> | 46 | <my-global-icon iconName="flag" aria-hidden="true"></my-global-icon> |
47 | 47 | ||
48 | <div class="message" i18n> | 48 | <div class="message" i18n> |
diff --git a/client/src/app/shared/shared-moderation/video-report.component.ts b/client/src/app/shared/shared-moderation/video-report.component.ts index b8d9f8d27..7977e4cca 100644 --- a/client/src/app/shared/shared-moderation/video-report.component.ts +++ b/client/src/app/shared/shared-moderation/video-report.component.ts | |||
@@ -140,7 +140,6 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
140 | const { hasStart, startAt, hasEnd, endAt } = this.form.get('timestamp').value | 140 | const { hasStart, startAt, hasEnd, endAt } = this.form.get('timestamp').value |
141 | 141 | ||
142 | this.abuseService.reportVideo({ | 142 | this.abuseService.reportVideo({ |
143 | accountId: this.video.account.id, | ||
144 | reason, | 143 | reason, |
145 | predefinedReasons, | 144 | predefinedReasons, |
146 | video: { | 145 | video: { |
diff --git a/server/controllers/api/abuse.ts b/server/controllers/api/abuse.ts index 38808021d..04a0c06e3 100644 --- a/server/controllers/api/abuse.ts +++ b/server/controllers/api/abuse.ts | |||
@@ -100,7 +100,7 @@ async function updateAbuse (req: express.Request, res: express.Response) { | |||
100 | return abuse.save({ transaction: t }) | 100 | return abuse.save({ transaction: t }) |
101 | }) | 101 | }) |
102 | 102 | ||
103 | // Do not send the delete to other instances, we updated OUR copy of this video abuse | 103 | // Do not send the delete to other instances, we updated OUR copy of this abuse |
104 | 104 | ||
105 | return res.type('json').status(204).end() | 105 | return res.type('json').status(204).end() |
106 | } | 106 | } |
@@ -112,7 +112,7 @@ async function deleteAbuse (req: express.Request, res: express.Response) { | |||
112 | return abuse.destroy({ transaction: t }) | 112 | return abuse.destroy({ transaction: t }) |
113 | }) | 113 | }) |
114 | 114 | ||
115 | // Do not send the delete to other instances, we delete OUR copy of this video abuse | 115 | // Do not send the delete to other instances, we delete OUR copy of this abuse |
116 | 116 | ||
117 | return res.type('json').status(204).end() | 117 | return res.type('json').status(204).end() |
118 | } | 118 | } |
diff --git a/server/controllers/api/users/my-history.ts b/server/controllers/api/users/my-history.ts index 77a15e5fc..dc915977f 100644 --- a/server/controllers/api/users/my-history.ts +++ b/server/controllers/api/users/my-history.ts | |||
@@ -50,7 +50,5 @@ async function removeUserHistory (req: express.Request, res: express.Response) { | |||
50 | return UserVideoHistoryModel.removeUserHistoryBefore(user, beforeDate, t) | 50 | return UserVideoHistoryModel.removeUserHistoryBefore(user, beforeDate, t) |
51 | }) | 51 | }) |
52 | 52 | ||
53 | // Do not send the delete to other instances, we delete OUR copy of this video abuse | ||
54 | |||
55 | return res.type('json').status(204).end() | 53 | return res.type('json').status(204).end() |
56 | } | 54 | } |
diff --git a/server/helpers/custom-validators/abuses.ts b/server/helpers/custom-validators/abuses.ts index c21468caa..0ca06a252 100644 --- a/server/helpers/custom-validators/abuses.ts +++ b/server/helpers/custom-validators/abuses.ts | |||
@@ -3,10 +3,10 @@ import { AbuseFilter, abusePredefinedReasonsMap, AbusePredefinedReasonsString, A | |||
3 | import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' | 3 | import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' |
4 | import { exists, isArray } from './misc' | 4 | import { exists, isArray } from './misc' |
5 | 5 | ||
6 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.ABUSES | 6 | const ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.ABUSES |
7 | 7 | ||
8 | function isAbuseReasonValid (value: string) { | 8 | function isAbuseReasonValid (value: string) { |
9 | return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON) | 9 | return exists(value) && validator.isLength(value, ABUSES_CONSTRAINTS_FIELDS.REASON) |
10 | } | 10 | } |
11 | 11 | ||
12 | function isAbusePredefinedReasonValid (value: AbusePredefinedReasonsString) { | 12 | function isAbusePredefinedReasonValid (value: AbusePredefinedReasonsString) { |
@@ -32,7 +32,7 @@ function isAbuseTimestampCoherent (endAt: number, { req }) { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | function isAbuseModerationCommentValid (value: string) { | 34 | function isAbuseModerationCommentValid (value: string) { |
35 | return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.MODERATION_COMMENT) | 35 | return exists(value) && validator.isLength(value, ABUSES_CONSTRAINTS_FIELDS.MODERATION_COMMENT) |
36 | } | 36 | } |
37 | 37 | ||
38 | function isAbuseStateValid (value: string) { | 38 | function isAbuseStateValid (value: string) { |
diff --git a/server/helpers/custom-validators/video-comments.ts b/server/helpers/custom-validators/video-comments.ts index a01680cbe..455ff4241 100644 --- a/server/helpers/custom-validators/video-comments.ts +++ b/server/helpers/custom-validators/video-comments.ts | |||
@@ -68,7 +68,7 @@ async function doesVideoCommentExist (idArg: number | string, video: MVideoId, r | |||
68 | 68 | ||
69 | async function doesCommentIdExist (idArg: number | string, res: express.Response) { | 69 | async function doesCommentIdExist (idArg: number | string, res: express.Response) { |
70 | const id = parseInt(idArg + '', 10) | 70 | const id = parseInt(idArg + '', 10) |
71 | const videoComment = await VideoCommentModel.loadById(id) | 71 | const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id) |
72 | 72 | ||
73 | if (!videoComment) { | 73 | if (!videoComment) { |
74 | res.status(404) | 74 | res.status(404) |
@@ -77,7 +77,7 @@ async function doesCommentIdExist (idArg: number | string, res: express.Response | |||
77 | return false | 77 | return false |
78 | } | 78 | } |
79 | 79 | ||
80 | res.locals.videoComment = videoComment | 80 | res.locals.videoCommentFull = videoComment |
81 | 81 | ||
82 | return true | 82 | return true |
83 | } | 83 | } |
diff --git a/server/helpers/middlewares/abuses.ts b/server/helpers/middlewares/abuses.ts index b102273a2..be8c8b449 100644 --- a/server/helpers/middlewares/abuses.ts +++ b/server/helpers/middlewares/abuses.ts | |||
@@ -30,7 +30,7 @@ async function doesAbuseExist (abuseId: number | string, res: Response) { | |||
30 | 30 | ||
31 | if (!abuse) { | 31 | if (!abuse) { |
32 | res.status(404) | 32 | res.status(404) |
33 | .json({ error: 'Video abuse not found' }) | 33 | .json({ error: 'Abuse not found' }) |
34 | 34 | ||
35 | return false | 35 | return false |
36 | } | 36 | } |
diff --git a/server/initializers/migrations/0520-abuses-split.ts b/server/initializers/migrations/0520-abuses-split.ts index 5898d501f..b02a21989 100644 --- a/server/initializers/migrations/0520-abuses-split.ts +++ b/server/initializers/migrations/0520-abuses-split.ts | |||
@@ -43,12 +43,10 @@ async function up (utils: { | |||
43 | await utils.sequelize.query(` | 43 | await utils.sequelize.query(` |
44 | CREATE TABLE IF NOT EXISTS "commentAbuse" ( | 44 | CREATE TABLE IF NOT EXISTS "commentAbuse" ( |
45 | "id" serial, | 45 | "id" serial, |
46 | "deletedComment" jsonb DEFAULT NULL, | ||
47 | "abuseId" integer NOT NULL REFERENCES "abuse" ("id") ON DELETE CASCADE ON UPDATE CASCADE, | 46 | "abuseId" integer NOT NULL REFERENCES "abuse" ("id") ON DELETE CASCADE ON UPDATE CASCADE, |
48 | "videoCommentId" integer REFERENCES "videoComment" ("id") ON DELETE SET NULL ON UPDATE CASCADE, | 47 | "videoCommentId" integer REFERENCES "videoComment" ("id") ON DELETE SET NULL ON UPDATE CASCADE, |
49 | "createdAt" timestamp WITH time zone NOT NULL, | 48 | "createdAt" timestamp WITH time zone NOT NULL, |
50 | "updatedAt" timestamp WITH time zone NOT NULL, | 49 | "updatedAt" timestamp WITH time zone NOT NULL, |
51 | "commentId" integer REFERENCES "videoComment" ("id") ON DELETE SET NULL ON UPDATE CASCADE, | ||
52 | PRIMARY KEY ("id") | 50 | PRIMARY KEY ("id") |
53 | ); | 51 | ); |
54 | `) | 52 | `) |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index a5664408d..5a6f37bb9 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -325,6 +325,7 @@ class Emailer { | |||
325 | subject: `New comment abuse report from ${reporter}`, | 325 | subject: `New comment abuse report from ${reporter}`, |
326 | locals: { | 326 | locals: { |
327 | commentUrl, | 327 | commentUrl, |
328 | videoName: comment.Video.name, | ||
328 | isLocal: comment.isOwned(), | 329 | isLocal: comment.isOwned(), |
329 | commentCreatedAt: new Date(comment.createdAt).toLocaleString(), | 330 | commentCreatedAt: new Date(comment.createdAt).toLocaleString(), |
330 | reason: abuse.reason, | 331 | reason: abuse.reason, |
diff --git a/server/lib/emails/video-comment-abuse-new/html.pug b/server/lib/emails/video-comment-abuse-new/html.pug index 170b79576..fc1c3e4e7 100644 --- a/server/lib/emails/video-comment-abuse-new/html.pug +++ b/server/lib/emails/video-comment-abuse-new/html.pug | |||
@@ -7,7 +7,8 @@ block title | |||
7 | block content | 7 | block content |
8 | p | 8 | p |
9 | | #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}comment " | 9 | | #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}comment " |
10 | a(href=commentUrl) of #{flaggedAccount} | 10 | a(href=commentUrl) on video #{videoName} |
11 | | of #{flaggedAccount} | ||
11 | | created on #{commentCreatedAt} | 12 | | created on #{commentCreatedAt} |
12 | 13 | ||
13 | p The reporter, #{reporter}, cited the following reason(s): | 14 | p The reporter, #{reporter}, cited the following reason(s): |
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index 969e393fa..c567e1c20 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts | |||
@@ -371,7 +371,7 @@ class Notifier { | |||
371 | 371 | ||
372 | async function notificationCreator (user: MUserWithNotificationSetting) { | 372 | async function notificationCreator (user: MUserWithNotificationSetting) { |
373 | const notification = await UserNotificationModel.create<UserNotificationModelForApi>({ | 373 | const notification = await UserNotificationModel.create<UserNotificationModelForApi>({ |
374 | type: UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS, | 374 | type: UserNotificationType.NEW_ABUSE_FOR_MODERATORS, |
375 | userId: user.id, | 375 | userId: user.id, |
376 | abuseId: abuse.id | 376 | abuseId: abuse.id |
377 | }) | 377 | }) |
diff --git a/server/middlewares/validators/abuse.ts b/server/middlewares/validators/abuse.ts index 048dbead0..966d1f7fb 100644 --- a/server/middlewares/validators/abuse.ts +++ b/server/middlewares/validators/abuse.ts | |||
@@ -128,7 +128,7 @@ const abuseListValidator = [ | |||
128 | .custom(exists).withMessage('Should have a valid search'), | 128 | .custom(exists).withMessage('Should have a valid search'), |
129 | query('state') | 129 | query('state') |
130 | .optional() | 130 | .optional() |
131 | .custom(isAbuseStateValid).withMessage('Should have a valid video abuse state'), | 131 | .custom(isAbuseStateValid).withMessage('Should have a valid abuse state'), |
132 | query('videoIs') | 132 | query('videoIs') |
133 | .optional() | 133 | .optional() |
134 | .custom(isAbuseVideoIsValid).withMessage('Should have a valid "video is" attribute'), | 134 | .custom(isAbuseVideoIsValid).withMessage('Should have a valid "video is" attribute'), |
diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts index 28ecf8253..dffd503b3 100644 --- a/server/models/abuse/abuse.ts +++ b/server/models/abuse/abuse.ts | |||
@@ -362,8 +362,8 @@ export class AbuseModel extends Model<AbuseModel> { | |||
362 | const countReportsForReporter = this.get('countReportsForReporter') as number | 362 | const countReportsForReporter = this.get('countReportsForReporter') as number |
363 | const countReportsForReportee = this.get('countReportsForReportee') as number | 363 | const countReportsForReportee = this.get('countReportsForReportee') as number |
364 | 364 | ||
365 | let video: VideoAbuse | 365 | let video: VideoAbuse = null |
366 | let comment: VideoCommentAbuse | 366 | let comment: VideoCommentAbuse = null |
367 | 367 | ||
368 | if (this.VideoAbuse) { | 368 | if (this.VideoAbuse) { |
369 | const abuseModel = this.VideoAbuse | 369 | const abuseModel = this.VideoAbuse |
@@ -391,13 +391,13 @@ export class AbuseModel extends Model<AbuseModel> { | |||
391 | 391 | ||
392 | if (this.VideoCommentAbuse) { | 392 | if (this.VideoCommentAbuse) { |
393 | const abuseModel = this.VideoCommentAbuse | 393 | const abuseModel = this.VideoCommentAbuse |
394 | const entity = abuseModel.VideoComment || abuseModel.deletedComment | 394 | const entity = abuseModel.VideoComment |
395 | 395 | ||
396 | comment = { | 396 | comment = { |
397 | id: entity.id, | 397 | id: entity.id, |
398 | text: entity.text, | 398 | text: entity.text ?? '', |
399 | 399 | ||
400 | deleted: !abuseModel.VideoComment, | 400 | deleted: entity.isDeleted(), |
401 | 401 | ||
402 | video: { | 402 | video: { |
403 | id: entity.Video.id, | 403 | id: entity.Video.id, |
diff --git a/server/models/abuse/video-comment-abuse.ts b/server/models/abuse/video-comment-abuse.ts index de9f4d5fd..8b34009b4 100644 --- a/server/models/abuse/video-comment-abuse.ts +++ b/server/models/abuse/video-comment-abuse.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { VideoComment } from '@shared/models' | ||
3 | import { VideoCommentModel } from '../video/video-comment' | 2 | import { VideoCommentModel } from '../video/video-comment' |
4 | import { AbuseModel } from './abuse' | 3 | import { AbuseModel } from './abuse' |
5 | 4 | ||
@@ -22,11 +21,6 @@ export class VideoCommentAbuseModel extends Model<VideoCommentAbuseModel> { | |||
22 | @UpdatedAt | 21 | @UpdatedAt |
23 | updatedAt: Date | 22 | updatedAt: Date |
24 | 23 | ||
25 | @AllowNull(true) | ||
26 | @Default(null) | ||
27 | @Column(DataType.JSONB) | ||
28 | deletedComment: VideoComment & { Video: { name: string, id: number, uuid: string }} | ||
29 | |||
30 | @ForeignKey(() => AbuseModel) | 24 | @ForeignKey(() => AbuseModel) |
31 | @Column | 25 | @Column |
32 | abuseId: number | 26 | abuseId: number |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index 07db5a2db..2945bf709 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -109,7 +109,7 @@ function buildAccountInclude (required: boolean, withActor = false) { | |||
109 | required: true, | 109 | required: true, |
110 | include: [ | 110 | include: [ |
111 | { | 111 | { |
112 | attributes: [ 'uuid' ], | 112 | attributes: [ 'id', 'name', 'uuid' ], |
113 | model: VideoModel.unscoped(), | 113 | model: VideoModel.unscoped(), |
114 | required: true | 114 | required: true |
115 | } | 115 | } |
@@ -492,6 +492,8 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
492 | threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(), | 492 | threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(), |
493 | 493 | ||
494 | video: { | 494 | video: { |
495 | id: abuse.VideoCommentAbuse.VideoComment.Video.id, | ||
496 | name: abuse.VideoCommentAbuse.VideoComment.Video.name, | ||
495 | uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid | 497 | uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid |
496 | } | 498 | } |
497 | } : undefined | 499 | } : undefined |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index fb6078ed8..fa4d13c3b 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -3,7 +3,6 @@ import { uniq } from 'lodash' | |||
3 | import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' | 3 | import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' |
4 | import { | 4 | import { |
5 | AllowNull, | 5 | AllowNull, |
6 | BeforeDestroy, | ||
7 | BelongsTo, | 6 | BelongsTo, |
8 | Column, | 7 | Column, |
9 | CreatedAt, | 8 | CreatedAt, |
@@ -16,7 +15,6 @@ import { | |||
16 | Table, | 15 | Table, |
17 | UpdatedAt | 16 | UpdatedAt |
18 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
19 | import { logger } from '@server/helpers/logger' | ||
20 | import { getServerActor } from '@server/models/application/application' | 18 | import { getServerActor } from '@server/models/application/application' |
21 | import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' | 19 | import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' |
22 | import { VideoPrivacy } from '@shared/models' | 20 | import { VideoPrivacy } from '@shared/models' |
@@ -242,51 +240,13 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
242 | 240 | ||
243 | @HasMany(() => VideoCommentAbuseModel, { | 241 | @HasMany(() => VideoCommentAbuseModel, { |
244 | foreignKey: { | 242 | foreignKey: { |
245 | name: 'commentId', | 243 | name: 'videoCommentId', |
246 | allowNull: true | 244 | allowNull: true |
247 | }, | 245 | }, |
248 | onDelete: 'set null' | 246 | onDelete: 'set null' |
249 | }) | 247 | }) |
250 | CommentAbuses: VideoCommentAbuseModel[] | 248 | CommentAbuses: VideoCommentAbuseModel[] |
251 | 249 | ||
252 | @BeforeDestroy | ||
253 | static async saveEssentialDataToAbuses (instance: VideoCommentModel, options) { | ||
254 | const tasks: Promise<any>[] = [] | ||
255 | |||
256 | if (!Array.isArray(instance.CommentAbuses)) { | ||
257 | instance.CommentAbuses = await instance.$get('CommentAbuses') | ||
258 | |||
259 | if (instance.CommentAbuses.length === 0) return undefined | ||
260 | } | ||
261 | |||
262 | if (!instance.Video) { | ||
263 | instance.Video = await instance.$get('Video') | ||
264 | } | ||
265 | |||
266 | logger.info('Saving video comment %s for abuse.', instance.url) | ||
267 | |||
268 | const details = Object.assign(instance.toFormattedJSON(), { | ||
269 | Video: { | ||
270 | id: instance.Video.id, | ||
271 | name: instance.Video.name, | ||
272 | uuid: instance.Video.uuid | ||
273 | } | ||
274 | }) | ||
275 | |||
276 | for (const abuse of instance.CommentAbuses) { | ||
277 | abuse.deletedComment = details | ||
278 | |||
279 | tasks.push(abuse.save({ transaction: options.transaction })) | ||
280 | } | ||
281 | |||
282 | Promise.all(tasks) | ||
283 | .catch(err => { | ||
284 | logger.error('Some errors when saving details of comment %s in its abuses before destroy hook.', instance.url, { err }) | ||
285 | }) | ||
286 | |||
287 | return undefined | ||
288 | } | ||
289 | |||
290 | static loadById (id: number, t?: Transaction): Bluebird<MComment> { | 250 | static loadById (id: number, t?: Transaction): Bluebird<MComment> { |
291 | const query: FindOptions = { | 251 | const query: FindOptions = { |
292 | where: { | 252 | where: { |
diff --git a/server/tests/api/check-params/abuses.ts b/server/tests/api/check-params/abuses.ts index ba7c0833f..8964c0ab2 100644 --- a/server/tests/api/check-params/abuses.ts +++ b/server/tests/api/check-params/abuses.ts | |||
@@ -21,9 +21,7 @@ import { | |||
21 | checkBadStartPagination | 21 | checkBadStartPagination |
22 | } from '../../../../shared/extra-utils/requests/check-api-params' | 22 | } from '../../../../shared/extra-utils/requests/check-api-params' |
23 | 23 | ||
24 | // FIXME: deprecated in 2.3. Remove this controller | 24 | describe('Test abuses API validators', function () { |
25 | |||
26 | describe('Test video abuses API validators', function () { | ||
27 | const basePath = '/api/v1/abuses/' | 25 | const basePath = '/api/v1/abuses/' |
28 | 26 | ||
29 | let server: ServerInfo | 27 | let server: ServerInfo |
diff --git a/server/tests/api/moderation/abuses.ts b/server/tests/api/moderation/abuses.ts index 28c5a5531..f186f7ea0 100644 --- a/server/tests/api/moderation/abuses.ts +++ b/server/tests/api/moderation/abuses.ts | |||
@@ -2,21 +2,30 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { Abuse, AbusePredefinedReasonsString, AbuseState } from '@shared/models' | 5 | import { Abuse, AbuseFilter, AbusePredefinedReasonsString, AbuseState, VideoComment, Account } from '@shared/models' |
6 | import { | 6 | import { |
7 | addVideoCommentThread, | ||
7 | cleanupTests, | 8 | cleanupTests, |
8 | createUser, | 9 | createUser, |
9 | deleteVideoAbuse, | 10 | deleteAbuse, |
11 | deleteVideoComment, | ||
10 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
11 | getVideoAbusesList, | 13 | getAbusesList, |
14 | getVideoCommentThreads, | ||
15 | getVideoIdFromUUID, | ||
12 | getVideosList, | 16 | getVideosList, |
17 | immutableAssign, | ||
13 | removeVideo, | 18 | removeVideo, |
14 | reportVideoAbuse, | 19 | reportAbuse, |
15 | ServerInfo, | 20 | ServerInfo, |
16 | setAccessTokensToServers, | 21 | setAccessTokensToServers, |
17 | updateVideoAbuse, | 22 | updateAbuse, |
18 | uploadVideo, | 23 | uploadVideo, |
19 | userLogin | 24 | uploadVideoAndGetId, |
25 | userLogin, | ||
26 | getAccount, | ||
27 | removeUser, | ||
28 | generateUserAccessToken | ||
20 | } from '../../../../shared/extra-utils/index' | 29 | } from '../../../../shared/extra-utils/index' |
21 | import { doubleFollow } from '../../../../shared/extra-utils/server/follows' | 30 | import { doubleFollow } from '../../../../shared/extra-utils/server/follows' |
22 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 31 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
@@ -31,6 +40,7 @@ const expect = chai.expect | |||
31 | 40 | ||
32 | describe('Test abuses', function () { | 41 | describe('Test abuses', function () { |
33 | let servers: ServerInfo[] = [] | 42 | let servers: ServerInfo[] = [] |
43 | let abuseServer1: Abuse | ||
34 | let abuseServer2: Abuse | 44 | let abuseServer2: Abuse |
35 | 45 | ||
36 | before(async function () { | 46 | before(async function () { |
@@ -44,338 +54,721 @@ describe('Test abuses', function () { | |||
44 | 54 | ||
45 | // Server 1 and server 2 follow each other | 55 | // Server 1 and server 2 follow each other |
46 | await doubleFollow(servers[0], servers[1]) | 56 | await doubleFollow(servers[0], servers[1]) |
57 | }) | ||
47 | 58 | ||
48 | // Upload some videos on each servers | 59 | describe('Video abuses', function () { |
49 | const video1Attributes = { | ||
50 | name: 'my super name for server 1', | ||
51 | description: 'my super description for server 1' | ||
52 | } | ||
53 | await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes) | ||
54 | 60 | ||
55 | const video2Attributes = { | 61 | before(async function () { |
56 | name: 'my super name for server 2', | 62 | this.timeout(50000) |
57 | description: 'my super description for server 2' | ||
58 | } | ||
59 | await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes) | ||
60 | 63 | ||
61 | // Wait videos propagation, server 2 has transcoding enabled | 64 | // Upload some videos on each servers |
62 | await waitJobs(servers) | 65 | const video1Attributes = { |
66 | name: 'my super name for server 1', | ||
67 | description: 'my super description for server 1' | ||
68 | } | ||
69 | await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes) | ||
63 | 70 | ||
64 | const res = await getVideosList(servers[0].url) | 71 | const video2Attributes = { |
65 | const videos = res.body.data | 72 | name: 'my super name for server 2', |
73 | description: 'my super description for server 2' | ||
74 | } | ||
75 | await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes) | ||
66 | 76 | ||
67 | expect(videos.length).to.equal(2) | 77 | // Wait videos propagation, server 2 has transcoding enabled |
78 | await waitJobs(servers) | ||
68 | 79 | ||
69 | servers[0].video = videos.find(video => video.name === 'my super name for server 1') | 80 | const res = await getVideosList(servers[0].url) |
70 | servers[1].video = videos.find(video => video.name === 'my super name for server 2') | 81 | const videos = res.body.data |
71 | }) | ||
72 | 82 | ||
73 | it('Should not have video abuses', async function () { | 83 | expect(videos.length).to.equal(2) |
74 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | ||
75 | 84 | ||
76 | expect(res.body.total).to.equal(0) | 85 | servers[0].video = videos.find(video => video.name === 'my super name for server 1') |
77 | expect(res.body.data).to.be.an('array') | 86 | servers[1].video = videos.find(video => video.name === 'my super name for server 2') |
78 | expect(res.body.data.length).to.equal(0) | 87 | }) |
79 | }) | ||
80 | 88 | ||
81 | it('Should report abuse on a local video', async function () { | 89 | it('Should not have abuses', async function () { |
82 | this.timeout(15000) | 90 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
83 | 91 | ||
84 | const reason = 'my super bad reason' | 92 | expect(res.body.total).to.equal(0) |
85 | await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason) | 93 | expect(res.body.data).to.be.an('array') |
94 | expect(res.body.data.length).to.equal(0) | ||
95 | }) | ||
86 | 96 | ||
87 | // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2 | 97 | it('Should report abuse on a local video', async function () { |
88 | await waitJobs(servers) | 98 | this.timeout(15000) |
89 | }) | ||
90 | 99 | ||
91 | it('Should have 1 video abuses on server 1 and 0 on server 2', async function () { | 100 | const reason = 'my super bad reason' |
92 | const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 101 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: servers[0].video.id, reason }) |
93 | |||
94 | expect(res1.body.total).to.equal(1) | ||
95 | expect(res1.body.data).to.be.an('array') | ||
96 | expect(res1.body.data.length).to.equal(1) | ||
97 | |||
98 | const abuse: Abuse = res1.body.data[0] | ||
99 | expect(abuse.reason).to.equal('my super bad reason') | ||
100 | expect(abuse.reporterAccount.name).to.equal('root') | ||
101 | expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port) | ||
102 | expect(abuse.video.id).to.equal(servers[0].video.id) | ||
103 | expect(abuse.video.channel).to.exist | ||
104 | expect(abuse.count).to.equal(1) | ||
105 | expect(abuse.nth).to.equal(1) | ||
106 | expect(abuse.countReportsForReporter).to.equal(1) | ||
107 | expect(abuse.countReportsForReportee).to.equal(1) | ||
108 | |||
109 | const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | ||
110 | expect(res2.body.total).to.equal(0) | ||
111 | expect(res2.body.data).to.be.an('array') | ||
112 | expect(res2.body.data.length).to.equal(0) | ||
113 | }) | ||
114 | 102 | ||
115 | it('Should report abuse on a remote video', async function () { | 103 | // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2 |
116 | this.timeout(10000) | 104 | await waitJobs(servers) |
105 | }) | ||
117 | 106 | ||
118 | const reason = 'my super bad reason 2' | 107 | it('Should have 1 video abuses on server 1 and 0 on server 2', async function () { |
119 | await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason) | 108 | const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
120 | 109 | ||
121 | // We wait requests propagation | 110 | expect(res1.body.total).to.equal(1) |
122 | await waitJobs(servers) | 111 | expect(res1.body.data).to.be.an('array') |
123 | }) | 112 | expect(res1.body.data.length).to.equal(1) |
124 | 113 | ||
125 | it('Should have 2 video abuses on server 1 and 1 on server 2', async function () { | 114 | const abuse: Abuse = res1.body.data[0] |
126 | const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 115 | expect(abuse.reason).to.equal('my super bad reason') |
127 | expect(res1.body.total).to.equal(2) | ||
128 | expect(res1.body.data).to.be.an('array') | ||
129 | expect(res1.body.data.length).to.equal(2) | ||
130 | |||
131 | const abuse1: Abuse = res1.body.data[0] | ||
132 | expect(abuse1.reason).to.equal('my super bad reason') | ||
133 | expect(abuse1.reporterAccount.name).to.equal('root') | ||
134 | expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port) | ||
135 | expect(abuse1.video.id).to.equal(servers[0].video.id) | ||
136 | expect(abuse1.state.id).to.equal(AbuseState.PENDING) | ||
137 | expect(abuse1.state.label).to.equal('Pending') | ||
138 | expect(abuse1.moderationComment).to.be.null | ||
139 | expect(abuse1.count).to.equal(1) | ||
140 | expect(abuse1.nth).to.equal(1) | ||
141 | |||
142 | const abuse2: Abuse = res1.body.data[1] | ||
143 | expect(abuse2.reason).to.equal('my super bad reason 2') | ||
144 | expect(abuse2.reporterAccount.name).to.equal('root') | ||
145 | expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port) | ||
146 | expect(abuse2.video.id).to.equal(servers[1].video.id) | ||
147 | expect(abuse2.state.id).to.equal(AbuseState.PENDING) | ||
148 | expect(abuse2.state.label).to.equal('Pending') | ||
149 | expect(abuse2.moderationComment).to.be.null | ||
150 | |||
151 | const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | ||
152 | expect(res2.body.total).to.equal(1) | ||
153 | expect(res2.body.data).to.be.an('array') | ||
154 | expect(res2.body.data.length).to.equal(1) | ||
155 | |||
156 | abuseServer2 = res2.body.data[0] | ||
157 | expect(abuseServer2.reason).to.equal('my super bad reason 2') | ||
158 | expect(abuseServer2.reporterAccount.name).to.equal('root') | ||
159 | expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port) | ||
160 | expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) | ||
161 | expect(abuseServer2.state.label).to.equal('Pending') | ||
162 | expect(abuseServer2.moderationComment).to.be.null | ||
163 | }) | ||
164 | 116 | ||
165 | it('Should update the state of a video abuse', async function () { | 117 | expect(abuse.reporterAccount.name).to.equal('root') |
166 | const body = { state: AbuseState.REJECTED } | 118 | expect(abuse.reporterAccount.host).to.equal(servers[0].host) |
167 | await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body) | ||
168 | 119 | ||
169 | const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | 120 | expect(abuse.video.id).to.equal(servers[0].video.id) |
170 | expect(res.body.data[0].state.id).to.equal(AbuseState.REJECTED) | 121 | expect(abuse.video.channel).to.exist |
171 | }) | ||
172 | 122 | ||
173 | it('Should add a moderation comment', async function () { | 123 | expect(abuse.comment).to.be.null |
174 | const body = { state: AbuseState.ACCEPTED, moderationComment: 'It is valid' } | ||
175 | await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body) | ||
176 | 124 | ||
177 | const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | 125 | expect(abuse.flaggedAccount.name).to.equal('root') |
178 | expect(res.body.data[0].state.id).to.equal(AbuseState.ACCEPTED) | 126 | expect(abuse.flaggedAccount.host).to.equal(servers[0].host) |
179 | expect(res.body.data[0].moderationComment).to.equal('It is valid') | 127 | |
180 | }) | 128 | expect(abuse.video.countReports).to.equal(1) |
129 | expect(abuse.video.nthReport).to.equal(1) | ||
130 | |||
131 | expect(abuse.countReportsForReporter).to.equal(1) | ||
132 | expect(abuse.countReportsForReportee).to.equal(1) | ||
181 | 133 | ||
182 | it('Should hide video abuses from blocked accounts', async function () { | 134 | const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken }) |
183 | this.timeout(10000) | 135 | expect(res2.body.total).to.equal(0) |
136 | expect(res2.body.data).to.be.an('array') | ||
137 | expect(res2.body.data.length).to.equal(0) | ||
138 | }) | ||
184 | 139 | ||
185 | { | 140 | it('Should report abuse on a remote video', async function () { |
186 | await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this') | 141 | this.timeout(10000) |
142 | |||
143 | const reason = 'my super bad reason 2' | ||
144 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: servers[1].video.id, reason }) | ||
145 | |||
146 | // We wait requests propagation | ||
187 | await waitJobs(servers) | 147 | await waitJobs(servers) |
148 | }) | ||
188 | 149 | ||
189 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 150 | it('Should have 2 video abuses on server 1 and 1 on server 2', async function () { |
190 | expect(res.body.total).to.equal(3) | 151 | const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
191 | } | ||
192 | 152 | ||
193 | const accountToBlock = 'root@localhost:' + servers[1].port | 153 | expect(res1.body.total).to.equal(2) |
154 | expect(res1.body.data.length).to.equal(2) | ||
194 | 155 | ||
195 | { | 156 | const abuse1: Abuse = res1.body.data[0] |
196 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) | 157 | expect(abuse1.reason).to.equal('my super bad reason') |
158 | expect(abuse1.reporterAccount.name).to.equal('root') | ||
159 | expect(abuse1.reporterAccount.host).to.equal(servers[0].host) | ||
197 | 160 | ||
198 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 161 | expect(abuse1.video.id).to.equal(servers[0].video.id) |
199 | expect(res.body.total).to.equal(2) | 162 | expect(abuse1.video.countReports).to.equal(1) |
163 | expect(abuse1.video.nthReport).to.equal(1) | ||
200 | 164 | ||
201 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 165 | expect(abuse1.comment).to.be.null |
202 | expect(abuse).to.be.undefined | ||
203 | } | ||
204 | 166 | ||
205 | { | 167 | expect(abuse1.flaggedAccount.name).to.equal('root') |
206 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) | 168 | expect(abuse1.flaggedAccount.host).to.equal(servers[0].host) |
207 | 169 | ||
208 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 170 | expect(abuse1.state.id).to.equal(AbuseState.PENDING) |
209 | expect(res.body.total).to.equal(3) | 171 | expect(abuse1.state.label).to.equal('Pending') |
210 | } | 172 | expect(abuse1.moderationComment).to.be.null |
211 | }) | ||
212 | 173 | ||
213 | it('Should hide video abuses from blocked servers', async function () { | 174 | const abuse2: Abuse = res1.body.data[1] |
214 | const serverToBlock = servers[1].host | 175 | expect(abuse2.reason).to.equal('my super bad reason 2') |
215 | 176 | ||
216 | { | 177 | expect(abuse2.reporterAccount.name).to.equal('root') |
217 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host) | 178 | expect(abuse2.reporterAccount.host).to.equal(servers[0].host) |
218 | 179 | ||
219 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 180 | expect(abuse2.video.id).to.equal(servers[1].video.id) |
220 | expect(res.body.total).to.equal(2) | ||
221 | 181 | ||
222 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 182 | expect(abuse2.comment).to.be.null |
223 | expect(abuse).to.be.undefined | ||
224 | } | ||
225 | 183 | ||
226 | { | 184 | expect(abuse2.flaggedAccount.name).to.equal('root') |
227 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock) | 185 | expect(abuse2.flaggedAccount.host).to.equal(servers[1].host) |
228 | 186 | ||
229 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 187 | expect(abuse2.state.id).to.equal(AbuseState.PENDING) |
230 | expect(res.body.total).to.equal(3) | 188 | expect(abuse2.state.label).to.equal('Pending') |
231 | } | 189 | expect(abuse2.moderationComment).to.be.null |
232 | }) | ||
233 | 190 | ||
234 | it('Should keep the video abuse when deleting the video', async function () { | 191 | const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken }) |
235 | this.timeout(10000) | 192 | expect(res2.body.total).to.equal(1) |
193 | expect(res2.body.data.length).to.equal(1) | ||
236 | 194 | ||
237 | await removeVideo(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid) | 195 | abuseServer2 = res2.body.data[0] |
196 | expect(abuseServer2.reason).to.equal('my super bad reason 2') | ||
197 | expect(abuseServer2.reporterAccount.name).to.equal('root') | ||
198 | expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host) | ||
238 | 199 | ||
239 | await waitJobs(servers) | 200 | expect(abuse2.flaggedAccount.name).to.equal('root') |
201 | expect(abuse2.flaggedAccount.host).to.equal(servers[1].host) | ||
240 | 202 | ||
241 | const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | 203 | expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) |
242 | expect(res.body.total).to.equal(2, "wrong number of videos returned") | 204 | expect(abuseServer2.state.label).to.equal('Pending') |
243 | expect(res.body.data.length).to.equal(2, "wrong number of videos returned") | 205 | expect(abuseServer2.moderationComment).to.be.null |
244 | expect(res.body.data[0].id).to.equal(abuseServer2.id, "wrong origin server id for first video") | 206 | }) |
245 | 207 | ||
246 | const abuse: Abuse = res.body.data[0] | 208 | it('Should hide video abuses from blocked accounts', async function () { |
247 | expect(abuse.video.id).to.equal(abuseServer2.video.id, "wrong video id") | 209 | this.timeout(10000) |
248 | expect(abuse.video.channel).to.exist | ||
249 | expect(abuse.video.deleted).to.be.true | ||
250 | }) | ||
251 | 210 | ||
252 | it('Should include counts of reports from reporter and reportee', async function () { | 211 | { |
253 | this.timeout(10000) | 212 | const videoId = await getVideoIdFromUUID(servers[1].url, servers[0].video.uuid) |
213 | await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId, reason: 'will mute this' }) | ||
214 | await waitJobs(servers) | ||
254 | 215 | ||
255 | // register a second user to have two reporters/reportees | 216 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
256 | const user = { username: 'user2', password: 'password' } | 217 | expect(res.body.total).to.equal(3) |
257 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, ...user }) | 218 | } |
258 | const userAccessToken = await userLogin(servers[0], user) | ||
259 | 219 | ||
260 | // upload a third video via this user | 220 | const accountToBlock = 'root@' + servers[1].host |
261 | const video3Attributes = { | 221 | |
262 | name: 'my second super name for server 1', | 222 | { |
263 | description: 'my second super description for server 1' | 223 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
264 | } | 224 | |
265 | await uploadVideo(servers[0].url, userAccessToken, video3Attributes) | 225 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
266 | 226 | expect(res.body.total).to.equal(2) | |
267 | const res1 = await getVideosList(servers[0].url) | 227 | |
268 | const videos = res1.body.data | 228 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
269 | const video3 = videos.find(video => video.name === 'my second super name for server 1') | 229 | expect(abuse).to.be.undefined |
270 | 230 | } | |
271 | // resume with the test | 231 | |
272 | const reason3 = 'my super bad reason 3' | 232 | { |
273 | await reportVideoAbuse(servers[0].url, servers[0].accessToken, video3.id, reason3) | 233 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
274 | const reason4 = 'my super bad reason 4' | 234 | |
275 | await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4) | 235 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
276 | 236 | expect(res.body.total).to.equal(3) | |
277 | const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 237 | } |
278 | 238 | }) | |
279 | { | 239 | |
280 | for (const abuse of res2.body.data as Abuse[]) { | 240 | it('Should hide video abuses from blocked servers', async function () { |
281 | if (abuse.video.id === video3.id) { | 241 | const serverToBlock = servers[1].host |
282 | expect(abuse.count).to.equal(1, "wrong reports count for video 3") | 242 | |
283 | expect(abuse.nth).to.equal(1, "wrong report position in report list for video 3") | 243 | { |
284 | expect(abuse.countReportsForReportee).to.equal(1, "wrong reports count for reporter on video 3 abuse") | 244 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host) |
285 | expect(abuse.countReportsForReporter).to.equal(3, "wrong reports count for reportee on video 3 abuse") | 245 | |
286 | } | 246 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
287 | if (abuse.video.id === servers[0].video.id) { | 247 | expect(res.body.total).to.equal(2) |
288 | expect(abuse.countReportsForReportee).to.equal(3, "wrong reports count for reporter on video 1 abuse") | 248 | |
249 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | ||
250 | expect(abuse).to.be.undefined | ||
251 | } | ||
252 | |||
253 | { | ||
254 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock) | ||
255 | |||
256 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | ||
257 | expect(res.body.total).to.equal(3) | ||
258 | } | ||
259 | }) | ||
260 | |||
261 | it('Should keep the video abuse when deleting the video', async function () { | ||
262 | this.timeout(10000) | ||
263 | |||
264 | await removeVideo(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid) | ||
265 | |||
266 | await waitJobs(servers) | ||
267 | |||
268 | const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | ||
269 | expect(res.body.total).to.equal(2, "wrong number of videos returned") | ||
270 | expect(res.body.data).to.have.lengthOf(2, "wrong number of videos returned") | ||
271 | |||
272 | const abuse: Abuse = res.body.data[0] | ||
273 | expect(abuse.id).to.equal(abuseServer2.id, "wrong origin server id for first video") | ||
274 | expect(abuse.video.id).to.equal(abuseServer2.video.id, "wrong video id") | ||
275 | expect(abuse.video.channel).to.exist | ||
276 | expect(abuse.video.deleted).to.be.true | ||
277 | }) | ||
278 | |||
279 | it('Should include counts of reports from reporter and reportee', async function () { | ||
280 | this.timeout(10000) | ||
281 | |||
282 | // register a second user to have two reporters/reportees | ||
283 | const user = { username: 'user2', password: 'password' } | ||
284 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, ...user }) | ||
285 | const userAccessToken = await userLogin(servers[0], user) | ||
286 | |||
287 | // upload a third video via this user | ||
288 | const video3Attributes = { | ||
289 | name: 'my second super name for server 1', | ||
290 | description: 'my second super description for server 1' | ||
291 | } | ||
292 | await uploadVideo(servers[0].url, userAccessToken, video3Attributes) | ||
293 | |||
294 | const res1 = await getVideosList(servers[0].url) | ||
295 | const videos = res1.body.data | ||
296 | const video3 = videos.find(video => video.name === 'my second super name for server 1') | ||
297 | |||
298 | // resume with the test | ||
299 | const reason3 = 'my super bad reason 3' | ||
300 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: video3.id, reason: reason3 }) | ||
301 | |||
302 | const reason4 = 'my super bad reason 4' | ||
303 | await reportAbuse({ url: servers[0].url, token: userAccessToken, videoId: servers[0].video.id, reason: reason4 }) | ||
304 | |||
305 | { | ||
306 | const res2 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | ||
307 | const abuses = res2.body.data as Abuse[] | ||
308 | |||
309 | const abuseVideo3 = res2.body.data.find(a => a.video.id === video3.id) | ||
310 | expect(abuseVideo3).to.not.be.undefined | ||
311 | expect(abuseVideo3.video.countReports).to.equal(1, "wrong reports count for video 3") | ||
312 | expect(abuseVideo3.video.nthReport).to.equal(1, "wrong report position in report list for video 3") | ||
313 | expect(abuseVideo3.countReportsForReportee).to.equal(1, "wrong reports count for reporter on video 3 abuse") | ||
314 | expect(abuseVideo3.countReportsForReporter).to.equal(3, "wrong reports count for reportee on video 3 abuse") | ||
315 | |||
316 | const abuseServer1 = abuses.find(a => a.video.id === servers[0].video.id) | ||
317 | expect(abuseServer1.countReportsForReportee).to.equal(3, "wrong reports count for reporter on video 1 abuse") | ||
318 | } | ||
319 | }) | ||
320 | |||
321 | it('Should list predefined reasons as well as timestamps for the reported video', async function () { | ||
322 | this.timeout(10000) | ||
323 | |||
324 | const reason5 = 'my super bad reason 5' | ||
325 | const predefinedReasons5: AbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ] | ||
326 | const createdAbuse = (await reportAbuse({ | ||
327 | url: servers[0].url, | ||
328 | token: servers[0].accessToken, | ||
329 | videoId: servers[0].video.id, | ||
330 | reason: reason5, | ||
331 | predefinedReasons: predefinedReasons5, | ||
332 | startAt: 1, | ||
333 | endAt: 5 | ||
334 | })).body.abuse | ||
335 | |||
336 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | ||
337 | |||
338 | { | ||
339 | const abuse = (res.body.data as Abuse[]).find(a => a.id === createdAbuse.id) | ||
340 | expect(abuse.reason).to.equals(reason5) | ||
341 | expect(abuse.predefinedReasons).to.deep.equals(predefinedReasons5, "predefined reasons do not match the one reported") | ||
342 | expect(abuse.video.startAt).to.equal(1, "starting timestamp doesn't match the one reported") | ||
343 | expect(abuse.video.endAt).to.equal(5, "ending timestamp doesn't match the one reported") | ||
344 | } | ||
345 | }) | ||
346 | |||
347 | it('Should delete the video abuse', async function () { | ||
348 | this.timeout(10000) | ||
349 | |||
350 | await deleteAbuse(servers[1].url, servers[1].accessToken, abuseServer2.id) | ||
351 | |||
352 | await waitJobs(servers) | ||
353 | |||
354 | { | ||
355 | const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | ||
356 | expect(res.body.total).to.equal(1) | ||
357 | expect(res.body.data.length).to.equal(1) | ||
358 | expect(res.body.data[0].id).to.not.equal(abuseServer2.id) | ||
359 | } | ||
360 | |||
361 | { | ||
362 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | ||
363 | expect(res.body.total).to.equal(6) | ||
364 | } | ||
365 | }) | ||
366 | |||
367 | it('Should list and filter video abuses', async function () { | ||
368 | this.timeout(10000) | ||
369 | |||
370 | async function list (query: Omit<Parameters<typeof getAbusesList>[0], 'url' | 'token'>) { | ||
371 | const options = { | ||
372 | url: servers[0].url, | ||
373 | token: servers[0].accessToken | ||
289 | } | 374 | } |
375 | |||
376 | Object.assign(options, query) | ||
377 | |||
378 | const res = await getAbusesList(options) | ||
379 | |||
380 | return res.body.data as Abuse[] | ||
290 | } | 381 | } |
291 | } | ||
292 | }) | ||
293 | 382 | ||
294 | it('Should list predefined reasons as well as timestamps for the reported video', async function () { | 383 | expect(await list({ id: 56 })).to.have.lengthOf(0) |
295 | this.timeout(10000) | 384 | expect(await list({ id: 1 })).to.have.lengthOf(1) |
296 | 385 | ||
297 | const reason5 = 'my super bad reason 5' | 386 | expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4) |
298 | const predefinedReasons5: AbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ] | 387 | expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0) |
299 | const createdAbuse = (await reportVideoAbuse( | 388 | |
300 | servers[0].url, | 389 | expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1) |
301 | servers[0].accessToken, | 390 | |
302 | servers[0].video.id, | 391 | expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4) |
303 | reason5, | 392 | expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0) |
304 | predefinedReasons5, | 393 | |
305 | 1, | 394 | expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1) |
306 | 5 | 395 | expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5) |
307 | )).body.abuse | 396 | |
308 | 397 | expect(await list({ searchReportee: 'root' })).to.have.lengthOf(5) | |
309 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 398 | expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0) |
310 | 399 | ||
311 | { | 400 | expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1) |
312 | const abuse = (res.body.data as Abuse[]).find(a => a.id === createdAbuse.id) | 401 | expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0) |
313 | expect(abuse.reason).to.equals(reason5) | 402 | |
314 | expect(abuse.predefinedReasons).to.deep.equals(predefinedReasons5, "predefined reasons do not match the one reported") | 403 | expect(await list({ state: AbuseState.ACCEPTED })).to.have.lengthOf(0) |
315 | expect(abuse.video.startAt).to.equal(1, "starting timestamp doesn't match the one reported") | 404 | expect(await list({ state: AbuseState.PENDING })).to.have.lengthOf(6) |
316 | expect(abuse.video.endAt).to.equal(5, "ending timestamp doesn't match the one reported") | 405 | |
317 | } | 406 | expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1) |
407 | expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0) | ||
408 | }) | ||
318 | }) | 409 | }) |
319 | 410 | ||
320 | it('Should delete the video abuse', async function () { | 411 | describe('Comment abuses', function () { |
321 | this.timeout(10000) | ||
322 | 412 | ||
323 | await deleteVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id) | 413 | async function getComment (url: string, videoIdArg: number | string) { |
414 | const videoId = typeof videoIdArg === 'string' | ||
415 | ? await getVideoIdFromUUID(url, videoIdArg) | ||
416 | : videoIdArg | ||
324 | 417 | ||
325 | await waitJobs(servers) | 418 | const res = await getVideoCommentThreads(url, videoId, 0, 5) |
326 | 419 | ||
327 | { | 420 | return res.body.data[0] as VideoComment |
328 | const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) | ||
329 | expect(res.body.total).to.equal(1) | ||
330 | expect(res.body.data.length).to.equal(1) | ||
331 | expect(res.body.data[0].id).to.not.equal(abuseServer2.id) | ||
332 | } | 421 | } |
333 | 422 | ||
334 | { | 423 | before(async function () { |
335 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) | 424 | this.timeout(50000) |
336 | expect(res.body.total).to.equal(6) | ||
337 | } | ||
338 | }) | ||
339 | 425 | ||
340 | it('Should list and filter video abuses', async function () { | 426 | servers[0].video = await uploadVideoAndGetId({ server: servers[0], videoName: 'server 1' }) |
341 | async function list (query: Omit<Parameters<typeof getVideoAbusesList>[0], 'url' | 'token'>) { | 427 | servers[1].video = await uploadVideoAndGetId({ server: servers[1], videoName: 'server 2' }) |
342 | const options = { | 428 | |
343 | url: servers[0].url, | 429 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, servers[0].video.id, 'comment server 1') |
344 | token: servers[0].accessToken | 430 | await addVideoCommentThread(servers[1].url, servers[1].accessToken, servers[1].video.id, 'comment server 2') |
431 | |||
432 | await waitJobs(servers) | ||
433 | }) | ||
434 | |||
435 | it('Should report abuse on a comment', async function () { | ||
436 | this.timeout(15000) | ||
437 | |||
438 | const comment = await getComment(servers[0].url, servers[0].video.id) | ||
439 | |||
440 | const reason = 'it is a bad comment' | ||
441 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, commentId: comment.id, reason }) | ||
442 | |||
443 | await waitJobs(servers) | ||
444 | }) | ||
445 | |||
446 | it('Should have 1 comment abuse on server 1 and 0 on server 2', async function () { | ||
447 | { | ||
448 | const comment = await getComment(servers[0].url, servers[0].video.id) | ||
449 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' }) | ||
450 | |||
451 | expect(res.body.total).to.equal(1) | ||
452 | expect(res.body.data).to.have.lengthOf(1) | ||
453 | |||
454 | const abuse: Abuse = res.body.data[0] | ||
455 | expect(abuse.reason).to.equal('it is a bad comment') | ||
456 | |||
457 | expect(abuse.reporterAccount.name).to.equal('root') | ||
458 | expect(abuse.reporterAccount.host).to.equal(servers[0].host) | ||
459 | |||
460 | expect(abuse.video).to.be.null | ||
461 | |||
462 | expect(abuse.comment.deleted).to.be.false | ||
463 | expect(abuse.comment.id).to.equal(comment.id) | ||
464 | expect(abuse.comment.text).to.equal(comment.text) | ||
465 | expect(abuse.comment.video.name).to.equal('server 1') | ||
466 | expect(abuse.comment.video.id).to.equal(servers[0].video.id) | ||
467 | expect(abuse.comment.video.uuid).to.equal(servers[0].video.uuid) | ||
468 | |||
469 | expect(abuse.countReportsForReporter).to.equal(5) | ||
470 | expect(abuse.countReportsForReportee).to.equal(5) | ||
471 | } | ||
472 | |||
473 | { | ||
474 | const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' }) | ||
475 | expect(res.body.total).to.equal(0) | ||
476 | expect(res.body.data.length).to.equal(0) | ||
477 | } | ||
478 | }) | ||
479 | |||
480 | it('Should report abuse on a remote comment', async function () { | ||
481 | this.timeout(10000) | ||
482 | |||
483 | const comment = await getComment(servers[0].url, servers[1].video.uuid) | ||
484 | |||
485 | const reason = 'it is a really bad comment' | ||
486 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, commentId: comment.id, reason }) | ||
487 | |||
488 | await waitJobs(servers) | ||
489 | }) | ||
490 | |||
491 | it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () { | ||
492 | const commentServer2 = await getComment(servers[0].url, servers[1].video.id) | ||
493 | |||
494 | const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' }) | ||
495 | expect(res1.body.total).to.equal(2) | ||
496 | expect(res1.body.data.length).to.equal(2) | ||
497 | |||
498 | const abuse: Abuse = res1.body.data[0] | ||
499 | expect(abuse.reason).to.equal('it is a bad comment') | ||
500 | expect(abuse.countReportsForReporter).to.equal(6) | ||
501 | expect(abuse.countReportsForReportee).to.equal(5) | ||
502 | |||
503 | const abuse2: Abuse = res1.body.data[1] | ||
504 | |||
505 | expect(abuse2.reason).to.equal('it is a really bad comment') | ||
506 | |||
507 | expect(abuse2.reporterAccount.name).to.equal('root') | ||
508 | expect(abuse2.reporterAccount.host).to.equal(servers[0].host) | ||
509 | |||
510 | expect(abuse2.video).to.be.null | ||
511 | |||
512 | expect(abuse2.comment.deleted).to.be.false | ||
513 | expect(abuse2.comment.id).to.equal(commentServer2.id) | ||
514 | expect(abuse2.comment.text).to.equal(commentServer2.text) | ||
515 | expect(abuse2.comment.video.name).to.equal('server 2') | ||
516 | expect(abuse2.comment.video.uuid).to.equal(servers[1].video.uuid) | ||
517 | |||
518 | expect(abuse2.state.id).to.equal(AbuseState.PENDING) | ||
519 | expect(abuse2.state.label).to.equal('Pending') | ||
520 | |||
521 | expect(abuse2.moderationComment).to.be.null | ||
522 | |||
523 | expect(abuse2.countReportsForReporter).to.equal(6) | ||
524 | expect(abuse2.countReportsForReportee).to.equal(2) | ||
525 | |||
526 | const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' }) | ||
527 | expect(res2.body.total).to.equal(1) | ||
528 | expect(res2.body.data.length).to.equal(1) | ||
529 | |||
530 | abuseServer2 = res2.body.data[0] | ||
531 | expect(abuseServer2.reason).to.equal('it is a really bad comment') | ||
532 | expect(abuseServer2.reporterAccount.name).to.equal('root') | ||
533 | expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host) | ||
534 | |||
535 | expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) | ||
536 | expect(abuseServer2.state.label).to.equal('Pending') | ||
537 | |||
538 | expect(abuseServer2.moderationComment).to.be.null | ||
539 | |||
540 | expect(abuseServer2.countReportsForReporter).to.equal(1) | ||
541 | expect(abuseServer2.countReportsForReportee).to.equal(1) | ||
542 | }) | ||
543 | |||
544 | it('Should keep the comment abuse when deleting the comment', async function () { | ||
545 | this.timeout(10000) | ||
546 | |||
547 | const commentServer2 = await getComment(servers[0].url, servers[1].video.id) | ||
548 | |||
549 | await deleteVideoComment(servers[0].url, servers[0].accessToken, servers[1].video.uuid, commentServer2.id) | ||
550 | |||
551 | await waitJobs(servers) | ||
552 | |||
553 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' }) | ||
554 | expect(res.body.total).to.equal(2) | ||
555 | expect(res.body.data).to.have.lengthOf(2) | ||
556 | |||
557 | const abuse = (res.body.data as Abuse[]).find(a => a.comment?.id === commentServer2.id) | ||
558 | expect(abuse).to.not.be.undefined | ||
559 | |||
560 | expect(abuse.comment.text).to.be.empty | ||
561 | expect(abuse.comment.video.name).to.equal('server 2') | ||
562 | expect(abuse.comment.deleted).to.be.true | ||
563 | }) | ||
564 | |||
565 | it('Should delete the comment abuse', async function () { | ||
566 | this.timeout(10000) | ||
567 | |||
568 | await deleteAbuse(servers[1].url, servers[1].accessToken, abuseServer2.id) | ||
569 | |||
570 | await waitJobs(servers) | ||
571 | |||
572 | { | ||
573 | const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' }) | ||
574 | expect(res.body.total).to.equal(0) | ||
575 | expect(res.body.data.length).to.equal(0) | ||
576 | } | ||
577 | |||
578 | { | ||
579 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' }) | ||
580 | expect(res.body.total).to.equal(2) | ||
581 | } | ||
582 | }) | ||
583 | |||
584 | it('Should list and filter video abuses', async function () { | ||
585 | { | ||
586 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment', searchReportee: 'foo' }) | ||
587 | expect(res.body.total).to.equal(0) | ||
588 | } | ||
589 | |||
590 | { | ||
591 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment', searchReportee: 'ot' }) | ||
592 | expect(res.body.total).to.equal(2) | ||
593 | } | ||
594 | |||
595 | { | ||
596 | const baseParams = { url: servers[0].url, token: servers[0].accessToken, filter: 'comment' as AbuseFilter, start: 1, count: 1 } | ||
597 | |||
598 | const res1 = await getAbusesList(immutableAssign(baseParams, { sort: 'createdAt' })) | ||
599 | expect(res1.body.data).to.have.lengthOf(1) | ||
600 | expect(res1.body.data[0].comment.text).to.be.empty | ||
601 | |||
602 | const res2 = await getAbusesList(immutableAssign(baseParams, { sort: '-createdAt' })) | ||
603 | expect(res2.body.data).to.have.lengthOf(1) | ||
604 | expect(res2.body.data[0].comment.text).to.equal('comment server 1') | ||
345 | } | 605 | } |
606 | }) | ||
607 | }) | ||
346 | 608 | ||
347 | Object.assign(options, query) | 609 | describe('Account abuses', function () { |
348 | 610 | ||
349 | const res = await getVideoAbusesList(options) | 611 | async function getAccountFromServer (url: string, name: string, server: ServerInfo) { |
612 | const res = await getAccount(url, name + '@' + server.host) | ||
350 | 613 | ||
351 | return res.body.data as Abuse[] | 614 | return res.body as Account |
352 | } | 615 | } |
353 | 616 | ||
354 | expect(await list({ id: 56 })).to.have.lengthOf(0) | 617 | before(async function () { |
355 | expect(await list({ id: 1 })).to.have.lengthOf(1) | 618 | this.timeout(50000) |
619 | |||
620 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'user_1', password: 'donald' }) | ||
621 | |||
622 | const token = await generateUserAccessToken(servers[1], 'user_2') | ||
623 | await uploadVideo(servers[1].url, token, { name: 'super video' }) | ||
624 | |||
625 | await waitJobs(servers) | ||
626 | }) | ||
627 | |||
628 | it('Should report abuse on an account', async function () { | ||
629 | this.timeout(15000) | ||
630 | |||
631 | const account = await getAccountFromServer(servers[0].url, 'user_1', servers[0]) | ||
632 | |||
633 | const reason = 'it is a bad account' | ||
634 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, accountId: account.id, reason }) | ||
635 | |||
636 | await waitJobs(servers) | ||
637 | }) | ||
638 | |||
639 | it('Should have 1 account abuse on server 1 and 0 on server 2', async function () { | ||
640 | { | ||
641 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' }) | ||
642 | |||
643 | expect(res.body.total).to.equal(1) | ||
644 | expect(res.body.data).to.have.lengthOf(1) | ||
645 | |||
646 | const abuse: Abuse = res.body.data[0] | ||
647 | expect(abuse.reason).to.equal('it is a bad account') | ||
648 | |||
649 | expect(abuse.reporterAccount.name).to.equal('root') | ||
650 | expect(abuse.reporterAccount.host).to.equal(servers[0].host) | ||
651 | |||
652 | expect(abuse.video).to.be.null | ||
653 | expect(abuse.comment).to.be.null | ||
654 | |||
655 | expect(abuse.flaggedAccount.name).to.equal('user_1') | ||
656 | expect(abuse.flaggedAccount.host).to.equal(servers[0].host) | ||
657 | } | ||
658 | |||
659 | { | ||
660 | const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' }) | ||
661 | expect(res.body.total).to.equal(0) | ||
662 | expect(res.body.data.length).to.equal(0) | ||
663 | } | ||
664 | }) | ||
665 | |||
666 | it('Should report abuse on a remote account', async function () { | ||
667 | this.timeout(10000) | ||
668 | |||
669 | const account = await getAccountFromServer(servers[0].url, 'user_2', servers[1]) | ||
670 | |||
671 | const reason = 'it is a really bad account' | ||
672 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, accountId: account.id, reason }) | ||
673 | |||
674 | await waitJobs(servers) | ||
675 | }) | ||
676 | |||
677 | it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () { | ||
678 | const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' }) | ||
679 | expect(res1.body.total).to.equal(2) | ||
680 | expect(res1.body.data.length).to.equal(2) | ||
681 | |||
682 | const abuse: Abuse = res1.body.data[0] | ||
683 | expect(abuse.reason).to.equal('it is a bad account') | ||
356 | 684 | ||
357 | expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4) | 685 | const abuse2: Abuse = res1.body.data[1] |
358 | expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0) | 686 | expect(abuse2.reason).to.equal('it is a really bad account') |
359 | 687 | ||
360 | expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1) | 688 | expect(abuse2.reporterAccount.name).to.equal('root') |
689 | expect(abuse2.reporterAccount.host).to.equal(servers[0].host) | ||
361 | 690 | ||
362 | expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4) | 691 | expect(abuse2.video).to.be.null |
363 | expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0) | 692 | expect(abuse2.comment).to.be.null |
693 | |||
694 | expect(abuse2.state.id).to.equal(AbuseState.PENDING) | ||
695 | expect(abuse2.state.label).to.equal('Pending') | ||
696 | |||
697 | expect(abuse2.moderationComment).to.be.null | ||
698 | |||
699 | const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'account' }) | ||
700 | expect(res2.body.total).to.equal(1) | ||
701 | expect(res2.body.data.length).to.equal(1) | ||
702 | |||
703 | abuseServer2 = res2.body.data[0] | ||
704 | |||
705 | expect(abuseServer2.reason).to.equal('it is a really bad account') | ||
706 | |||
707 | expect(abuseServer2.reporterAccount.name).to.equal('root') | ||
708 | expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host) | ||
709 | |||
710 | expect(abuseServer2.state.id).to.equal(AbuseState.PENDING) | ||
711 | expect(abuseServer2.state.label).to.equal('Pending') | ||
712 | |||
713 | expect(abuseServer2.moderationComment).to.be.null | ||
714 | }) | ||
715 | |||
716 | it('Should keep the account abuse when deleting the account', async function () { | ||
717 | this.timeout(10000) | ||
718 | |||
719 | const account = await getAccountFromServer(servers[1].url, 'user_2', servers[1]) | ||
720 | await removeUser(servers[1].url, account.userId, servers[1].accessToken) | ||
721 | |||
722 | await waitJobs(servers) | ||
723 | |||
724 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' }) | ||
725 | expect(res.body.total).to.equal(2) | ||
726 | expect(res.body.data).to.have.lengthOf(2) | ||
727 | |||
728 | const abuse = (res.body.data as Abuse[]).find(a => a.reason === 'it is a really bad account') | ||
729 | expect(abuse).to.not.be.undefined | ||
730 | }) | ||
731 | |||
732 | it('Should delete the account abuse', async function () { | ||
733 | this.timeout(10000) | ||
734 | |||
735 | await deleteAbuse(servers[1].url, servers[1].accessToken, abuseServer2.id) | ||
736 | |||
737 | await waitJobs(servers) | ||
738 | |||
739 | { | ||
740 | const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'account' }) | ||
741 | expect(res.body.total).to.equal(0) | ||
742 | expect(res.body.data.length).to.equal(0) | ||
743 | } | ||
744 | |||
745 | { | ||
746 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' }) | ||
747 | expect(res.body.total).to.equal(2) | ||
748 | |||
749 | abuseServer1 = res.body.data[0] | ||
750 | } | ||
751 | }) | ||
752 | }) | ||
364 | 753 | ||
365 | expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1) | 754 | describe('Common actions on abuses', function () { |
366 | expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5) | ||
367 | 755 | ||
368 | expect(await list({ searchReportee: 'root' })).to.have.lengthOf(5) | 756 | it('Should update the state of an abuse', async function () { |
369 | expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0) | 757 | const body = { state: AbuseState.REJECTED } |
758 | await updateAbuse(servers[0].url, servers[0].accessToken, abuseServer1.id, body) | ||
370 | 759 | ||
371 | expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1) | 760 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, id: abuseServer1.id }) |
372 | expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0) | 761 | expect(res.body.data[0].state.id).to.equal(AbuseState.REJECTED) |
762 | }) | ||
373 | 763 | ||
374 | expect(await list({ state: AbuseState.ACCEPTED })).to.have.lengthOf(0) | 764 | it('Should add a moderation comment', async function () { |
375 | expect(await list({ state: AbuseState.PENDING })).to.have.lengthOf(6) | 765 | const body = { state: AbuseState.ACCEPTED, moderationComment: 'It is valid' } |
766 | await updateAbuse(servers[0].url, servers[0].accessToken, abuseServer1.id, body) | ||
376 | 767 | ||
377 | expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1) | 768 | const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, id: abuseServer1.id }) |
378 | expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0) | 769 | expect(res.body.data[0].state.id).to.equal(AbuseState.ACCEPTED) |
770 | expect(res.body.data[0].moderationComment).to.equal('It is valid') | ||
771 | }) | ||
379 | }) | 772 | }) |
380 | 773 | ||
381 | after(async function () { | 774 | after(async function () { |
diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts index a27681603..a8517600a 100644 --- a/server/tests/api/notifications/moderation-notifications.ts +++ b/server/tests/api/notifications/moderation-notifications.ts | |||
@@ -3,10 +3,16 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { v4 as uuidv4 } from 'uuid' | 4 | import { v4 as uuidv4 } from 'uuid' |
5 | import { | 5 | import { |
6 | addVideoCommentThread, | ||
6 | addVideoToBlacklist, | 7 | addVideoToBlacklist, |
7 | cleanupTests, | 8 | cleanupTests, |
9 | createUser, | ||
8 | follow, | 10 | follow, |
11 | generateUserAccessToken, | ||
12 | getAccount, | ||
9 | getCustomConfig, | 13 | getCustomConfig, |
14 | getVideoCommentThreads, | ||
15 | getVideoIdFromUUID, | ||
10 | immutableAssign, | 16 | immutableAssign, |
11 | MockInstancesIndex, | 17 | MockInstancesIndex, |
12 | registerUser, | 18 | registerUser, |
@@ -23,7 +29,9 @@ import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | |||
23 | import { | 29 | import { |
24 | checkAutoInstanceFollowing, | 30 | checkAutoInstanceFollowing, |
25 | CheckerBaseParams, | 31 | CheckerBaseParams, |
32 | checkNewAccountAbuseForModerators, | ||
26 | checkNewBlacklistOnMyVideo, | 33 | checkNewBlacklistOnMyVideo, |
34 | checkNewCommentAbuseForModerators, | ||
27 | checkNewInstanceFollower, | 35 | checkNewInstanceFollower, |
28 | checkNewVideoAbuseForModerators, | 36 | checkNewVideoAbuseForModerators, |
29 | checkNewVideoFromSubscription, | 37 | checkNewVideoFromSubscription, |
@@ -91,11 +99,74 @@ describe('Test moderation notifications', function () { | |||
91 | 99 | ||
92 | await waitJobs(servers) | 100 | await waitJobs(servers) |
93 | 101 | ||
94 | await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId: video.id, reason: 'super reason' }) | 102 | const videoId = await getVideoIdFromUUID(servers[1].url, video.uuid) |
103 | await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId, reason: 'super reason' }) | ||
95 | 104 | ||
96 | await waitJobs(servers) | 105 | await waitJobs(servers) |
97 | await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence') | 106 | await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence') |
98 | }) | 107 | }) |
108 | |||
109 | it('Should send a notification to moderators on local comment abuse', async function () { | ||
110 | this.timeout(10000) | ||
111 | |||
112 | const name = 'video for abuse ' + uuidv4() | ||
113 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) | ||
114 | const video = resVideo.body.video | ||
115 | const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4()) | ||
116 | const comment = resComment.body.comment | ||
117 | |||
118 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, commentId: comment.id, reason: 'super reason' }) | ||
119 | |||
120 | await waitJobs(servers) | ||
121 | await checkNewCommentAbuseForModerators(baseParams, video.uuid, name, 'presence') | ||
122 | }) | ||
123 | |||
124 | it('Should send a notification to moderators on remote comment abuse', async function () { | ||
125 | this.timeout(10000) | ||
126 | |||
127 | const name = 'video for abuse ' + uuidv4() | ||
128 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) | ||
129 | const video = resVideo.body.video | ||
130 | await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4()) | ||
131 | |||
132 | await waitJobs(servers) | ||
133 | |||
134 | const resComments = await getVideoCommentThreads(servers[1].url, video.uuid, 0, 5) | ||
135 | const commentId = resComments.body.data[0].id | ||
136 | await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, commentId, reason: 'super reason' }) | ||
137 | |||
138 | await waitJobs(servers) | ||
139 | await checkNewCommentAbuseForModerators(baseParams, video.uuid, name, 'presence') | ||
140 | }) | ||
141 | |||
142 | it('Should send a notification to moderators on local account abuse', async function () { | ||
143 | this.timeout(10000) | ||
144 | |||
145 | const username = 'user' + new Date().getTime() | ||
146 | const resUser = await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username, password: 'donald' }) | ||
147 | const accountId = resUser.body.user.account.id | ||
148 | |||
149 | await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, accountId, reason: 'super reason' }) | ||
150 | |||
151 | await waitJobs(servers) | ||
152 | await checkNewAccountAbuseForModerators(baseParams, username, 'presence') | ||
153 | }) | ||
154 | |||
155 | it('Should send a notification to moderators on remote account abuse', async function () { | ||
156 | this.timeout(10000) | ||
157 | |||
158 | const username = 'user' + new Date().getTime() | ||
159 | const tmpToken = await generateUserAccessToken(servers[0], username) | ||
160 | await uploadVideo(servers[0].url, tmpToken, { name: 'super video' }) | ||
161 | |||
162 | await waitJobs(servers) | ||
163 | |||
164 | const resAccount = await getAccount(servers[1].url, username + '@' + servers[0].host) | ||
165 | await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, accountId: resAccount.body.id, reason: 'super reason' }) | ||
166 | |||
167 | await waitJobs(servers) | ||
168 | await checkNewAccountAbuseForModerators(baseParams, username, 'presence') | ||
169 | }) | ||
99 | }) | 170 | }) |
100 | 171 | ||
101 | describe('Video blacklist on my video', function () { | 172 | describe('Video blacklist on my video', function () { |
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index 9c3299618..b01a91d48 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts | |||
@@ -180,7 +180,7 @@ describe('Test emails', function () { | |||
180 | }) | 180 | }) |
181 | }) | 181 | }) |
182 | 182 | ||
183 | describe('When creating a video abuse', function () { | 183 | describe('When creating an abuse', function () { |
184 | it('Should send the notification email', async function () { | 184 | it('Should send the notification email', async function () { |
185 | this.timeout(10000) | 185 | this.timeout(10000) |
186 | 186 | ||
diff --git a/server/types/models/user/user-notification.ts b/server/types/models/user/user-notification.ts index 92ea16768..f59eb7260 100644 --- a/server/types/models/user/user-notification.ts +++ b/server/types/models/user/user-notification.ts | |||
@@ -53,7 +53,7 @@ export module UserNotificationIncludes { | |||
53 | Pick<VideoCommentAbuseModel, 'id'> & | 53 | Pick<VideoCommentAbuseModel, 'id'> & |
54 | PickWith<VideoCommentAbuseModel, 'VideoComment', | 54 | PickWith<VideoCommentAbuseModel, 'VideoComment', |
55 | Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & | 55 | Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & |
56 | PickWith<VideoCommentModel, 'Video', Pick<VideoModel, 'uuid'>>> | 56 | PickWith<VideoCommentModel, 'Video', Pick<VideoModel, 'id' | 'name' | 'uuid'>>> |
57 | 57 | ||
58 | export type AbuseInclude = | 58 | export type AbuseInclude = |
59 | Pick<AbuseModel, 'id'> & | 59 | Pick<AbuseModel, 'id'> & |
diff --git a/server/typings/express/index.d.ts b/server/typings/express/index.d.ts index b1afffcd4..7595e6d86 100644 --- a/server/typings/express/index.d.ts +++ b/server/typings/express/index.d.ts | |||
@@ -91,7 +91,6 @@ declare module 'express' { | |||
91 | 91 | ||
92 | accountVideoRate?: MAccountVideoRateAccountVideo | 92 | accountVideoRate?: MAccountVideoRateAccountVideo |
93 | 93 | ||
94 | videoComment?: MComment | ||
95 | videoCommentFull?: MCommentOwnerVideoReply | 94 | videoCommentFull?: MCommentOwnerVideoReply |
96 | videoCommentThread?: MComment | 95 | videoCommentThread?: MComment |
97 | 96 | ||
diff --git a/shared/extra-utils/moderation/abuses.ts b/shared/extra-utils/moderation/abuses.ts index 1af703f92..62af9556e 100644 --- a/shared/extra-utils/moderation/abuses.ts +++ b/shared/extra-utils/moderation/abuses.ts | |||
@@ -57,10 +57,15 @@ function reportAbuse (options: { | |||
57 | function getAbusesList (options: { | 57 | function getAbusesList (options: { |
58 | url: string | 58 | url: string |
59 | token: string | 59 | token: string |
60 | |||
61 | start?: number | ||
62 | count?: number | ||
63 | sort?: string | ||
64 | |||
60 | id?: number | 65 | id?: number |
61 | predefinedReason?: AbusePredefinedReasonsString | 66 | predefinedReason?: AbusePredefinedReasonsString |
62 | search?: string | 67 | search?: string |
63 | filter?: AbuseFilter, | 68 | filter?: AbuseFilter |
64 | state?: AbuseState | 69 | state?: AbuseState |
65 | videoIs?: AbuseVideoIs | 70 | videoIs?: AbuseVideoIs |
66 | searchReporter?: string | 71 | searchReporter?: string |
@@ -71,6 +76,9 @@ function getAbusesList (options: { | |||
71 | const { | 76 | const { |
72 | url, | 77 | url, |
73 | token, | 78 | token, |
79 | start, | ||
80 | count, | ||
81 | sort, | ||
74 | id, | 82 | id, |
75 | predefinedReason, | 83 | predefinedReason, |
76 | search, | 84 | search, |
@@ -85,13 +93,15 @@ function getAbusesList (options: { | |||
85 | const path = '/api/v1/abuses' | 93 | const path = '/api/v1/abuses' |
86 | 94 | ||
87 | const query = { | 95 | const query = { |
88 | sort: 'createdAt', | ||
89 | id, | 96 | id, |
90 | predefinedReason, | 97 | predefinedReason, |
91 | search, | 98 | search, |
92 | state, | 99 | state, |
93 | filter, | 100 | filter, |
94 | videoIs, | 101 | videoIs, |
102 | start, | ||
103 | count, | ||
104 | sort: sort || 'createdAt', | ||
95 | searchReporter, | 105 | searchReporter, |
96 | searchReportee, | 106 | searchReportee, |
97 | searchVideo, | 107 | searchVideo, |
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 0f883d839..994aac628 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts | |||
@@ -37,8 +37,8 @@ interface ServerInfo { | |||
37 | video?: { | 37 | video?: { |
38 | id: number | 38 | id: number |
39 | uuid: string | 39 | uuid: string |
40 | name: string | 40 | name?: string |
41 | account: { | 41 | account?: { |
42 | name: string | 42 | name: string |
43 | } | 43 | } |
44 | } | 44 | } |
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts index 4a5bc30fe..2061e3353 100644 --- a/shared/extra-utils/users/user-notifications.ts +++ b/shared/extra-utils/users/user-notifications.ts | |||
@@ -139,13 +139,17 @@ async function checkNotification ( | |||
139 | } | 139 | } |
140 | 140 | ||
141 | function checkVideo (video: any, videoName?: string, videoUUID?: string) { | 141 | function checkVideo (video: any, videoName?: string, videoUUID?: string) { |
142 | expect(video.name).to.be.a('string') | 142 | if (videoName) { |
143 | expect(video.name).to.not.be.empty | 143 | expect(video.name).to.be.a('string') |
144 | if (videoName) expect(video.name).to.equal(videoName) | 144 | expect(video.name).to.not.be.empty |
145 | expect(video.name).to.equal(videoName) | ||
146 | } | ||
145 | 147 | ||
146 | expect(video.uuid).to.be.a('string') | 148 | if (videoUUID) { |
147 | expect(video.uuid).to.not.be.empty | 149 | expect(video.uuid).to.be.a('string') |
148 | if (videoUUID) expect(video.uuid).to.equal(videoUUID) | 150 | expect(video.uuid).to.not.be.empty |
151 | expect(video.uuid).to.equal(videoUUID) | ||
152 | } | ||
149 | 153 | ||
150 | expect(video.id).to.be.a('number') | 154 | expect(video.id).to.be.a('number') |
151 | } | 155 | } |
@@ -436,7 +440,7 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, | |||
436 | } | 440 | } |
437 | 441 | ||
438 | async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | 442 | async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { |
439 | const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS | 443 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS |
440 | 444 | ||
441 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 445 | function notificationChecker (notification: UserNotification, type: CheckerType) { |
442 | if (type === 'presence') { | 446 | if (type === 'presence') { |
@@ -460,6 +464,56 @@ async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUU | |||
460 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 464 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) |
461 | } | 465 | } |
462 | 466 | ||
467 | async function checkNewCommentAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | ||
468 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | ||
469 | |||
470 | function notificationChecker (notification: UserNotification, type: CheckerType) { | ||
471 | if (type === 'presence') { | ||
472 | expect(notification).to.not.be.undefined | ||
473 | expect(notification.type).to.equal(notificationType) | ||
474 | |||
475 | expect(notification.abuse.id).to.be.a('number') | ||
476 | checkVideo(notification.abuse.comment.video, videoName, videoUUID) | ||
477 | } else { | ||
478 | expect(notification).to.satisfy((n: UserNotification) => { | ||
479 | return n === undefined || n.abuse === undefined || n.abuse.comment.video.uuid !== videoUUID | ||
480 | }) | ||
481 | } | ||
482 | } | ||
483 | |||
484 | function emailNotificationFinder (email: object) { | ||
485 | const text = email['text'] | ||
486 | return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 | ||
487 | } | ||
488 | |||
489 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | ||
490 | } | ||
491 | |||
492 | async function checkNewAccountAbuseForModerators (base: CheckerBaseParams, displayName: string, type: CheckerType) { | ||
493 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | ||
494 | |||
495 | function notificationChecker (notification: UserNotification, type: CheckerType) { | ||
496 | if (type === 'presence') { | ||
497 | expect(notification).to.not.be.undefined | ||
498 | expect(notification.type).to.equal(notificationType) | ||
499 | |||
500 | expect(notification.abuse.id).to.be.a('number') | ||
501 | expect(notification.abuse.account.displayName).to.equal(displayName) | ||
502 | } else { | ||
503 | expect(notification).to.satisfy((n: UserNotification) => { | ||
504 | return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName | ||
505 | }) | ||
506 | } | ||
507 | } | ||
508 | |||
509 | function emailNotificationFinder (email: object) { | ||
510 | const text = email['text'] | ||
511 | return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 | ||
512 | } | ||
513 | |||
514 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | ||
515 | } | ||
516 | |||
463 | async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | 517 | async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { |
464 | const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS | 518 | const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS |
465 | 519 | ||
@@ -541,6 +595,9 @@ async function prepareNotificationsTest (serversCount = 3) { | |||
541 | smtp: { | 595 | smtp: { |
542 | hostname: 'localhost', | 596 | hostname: 'localhost', |
543 | port | 597 | port |
598 | }, | ||
599 | signup: { | ||
600 | limit: 20 | ||
544 | } | 601 | } |
545 | } | 602 | } |
546 | const servers = await flushAndRunMultipleServers(serversCount, overrideConfig) | 603 | const servers = await flushAndRunMultipleServers(serversCount, overrideConfig) |
@@ -623,5 +680,7 @@ export { | |||
623 | markAsReadNotifications, | 680 | markAsReadNotifications, |
624 | getLastNotification, | 681 | getLastNotification, |
625 | checkNewInstanceFollower, | 682 | checkNewInstanceFollower, |
626 | prepareNotificationsTest | 683 | prepareNotificationsTest, |
684 | checkNewCommentAbuseForModerators, | ||
685 | checkNewAccountAbuseForModerators | ||
627 | } | 686 | } |
diff --git a/shared/models/users/user-notification.model.ts b/shared/models/users/user-notification.model.ts index 39090f5a1..11d96fd50 100644 --- a/shared/models/users/user-notification.model.ts +++ b/shared/models/users/user-notification.model.ts | |||
@@ -3,7 +3,7 @@ import { FollowState } from '../actors' | |||
3 | export enum UserNotificationType { | 3 | export enum UserNotificationType { |
4 | NEW_VIDEO_FROM_SUBSCRIPTION = 1, | 4 | NEW_VIDEO_FROM_SUBSCRIPTION = 1, |
5 | NEW_COMMENT_ON_MY_VIDEO = 2, | 5 | NEW_COMMENT_ON_MY_VIDEO = 2, |
6 | NEW_VIDEO_ABUSE_FOR_MODERATORS = 3, | 6 | NEW_ABUSE_FOR_MODERATORS = 3, |
7 | 7 | ||
8 | BLACKLIST_ON_MY_VIDEO = 4, | 8 | BLACKLIST_ON_MY_VIDEO = 4, |
9 | UNBLACKLIST_ON_MY_VIDEO = 5, | 9 | UNBLACKLIST_ON_MY_VIDEO = 5, |
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 03e60925b..3b381bbb5 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -106,9 +106,9 @@ tags: | |||
106 | Managing plugins installed from a local path or from NPM, or search for new ones. | 106 | Managing plugins installed from a local path or from NPM, or search for new ones. |
107 | externalDocs: | 107 | externalDocs: |
108 | url: https://docs.joinpeertube.org/#/api-plugins | 108 | url: https://docs.joinpeertube.org/#/api-plugins |
109 | - name: Video Abuses | 109 | - name: Abuses |
110 | description: | | 110 | description: | |
111 | Video abuses deal with reports of local or remote videos alike. | 111 | Abuses deal with reports of local or remote videos/comments/accounts alike. |
112 | - name: Video | 112 | - name: Video |
113 | description: | | 113 | description: | |
114 | Operations dealing with listing, uploading, fetching or modifying videos. | 114 | Operations dealing with listing, uploading, fetching or modifying videos. |
@@ -166,7 +166,7 @@ x-tagGroups: | |||
166 | - Search | 166 | - Search |
167 | - name: Moderation | 167 | - name: Moderation |
168 | tags: | 168 | tags: |
169 | - Video Abuses | 169 | - Abuses |
170 | - Video Blocks | 170 | - Video Blocks |
171 | - Account Blocks | 171 | - Account Blocks |
172 | - Server Blocks | 172 | - Server Blocks |
@@ -1474,13 +1474,13 @@ paths: | |||
1474 | /videos/abuse: | 1474 | /videos/abuse: |
1475 | get: | 1475 | get: |
1476 | deprecated: true | 1476 | deprecated: true |
1477 | summary: List video abuses | 1477 | summary: List abuses |
1478 | security: | 1478 | security: |
1479 | - OAuth2: | 1479 | - OAuth2: |
1480 | - admin | 1480 | - admin |
1481 | - moderator | 1481 | - moderator |
1482 | tags: | 1482 | tags: |
1483 | - Video Abuses | 1483 | - Abuses |
1484 | parameters: | 1484 | parameters: |
1485 | - name: id | 1485 | - name: id |
1486 | in: query | 1486 | in: query |
@@ -1508,7 +1508,7 @@ paths: | |||
1508 | type: string | 1508 | type: string |
1509 | - name: state | 1509 | - name: state |
1510 | in: query | 1510 | in: query |
1511 | description: 'The video playlist privacy (Pending = `1`, Rejected = `2`, Accepted = `3`)' | 1511 | description: 'The abuse state (Pending = `1`, Rejected = `2`, Accepted = `3`)' |
1512 | schema: | 1512 | schema: |
1513 | type: integer | 1513 | type: integer |
1514 | enum: | 1514 | enum: |
@@ -1554,7 +1554,7 @@ paths: | |||
1554 | security: | 1554 | security: |
1555 | - OAuth2: [] | 1555 | - OAuth2: [] |
1556 | tags: | 1556 | tags: |
1557 | - Video Abuses | 1557 | - Abuses |
1558 | - Videos | 1558 | - Videos |
1559 | parameters: | 1559 | parameters: |
1560 | - $ref: '#/components/parameters/idOrUUID' | 1560 | - $ref: '#/components/parameters/idOrUUID' |
@@ -1607,7 +1607,7 @@ paths: | |||
1607 | - admin | 1607 | - admin |
1608 | - moderator | 1608 | - moderator |
1609 | tags: | 1609 | tags: |
1610 | - Video Abuses | 1610 | - Abuses |
1611 | parameters: | 1611 | parameters: |
1612 | - $ref: '#/components/parameters/idOrUUID' | 1612 | - $ref: '#/components/parameters/idOrUUID' |
1613 | - $ref: '#/components/parameters/abuseId' | 1613 | - $ref: '#/components/parameters/abuseId' |
@@ -1626,11 +1626,11 @@ paths: | |||
1626 | '204': | 1626 | '204': |
1627 | description: successful operation | 1627 | description: successful operation |
1628 | '404': | 1628 | '404': |
1629 | description: video abuse not found | 1629 | description: abuse not found |
1630 | delete: | 1630 | delete: |
1631 | deprecated: true | 1631 | deprecated: true |
1632 | tags: | 1632 | tags: |
1633 | - Video Abuses | 1633 | - Abuses |
1634 | summary: Delete an abuse | 1634 | summary: Delete an abuse |
1635 | security: | 1635 | security: |
1636 | - OAuth2: | 1636 | - OAuth2: |
@@ -3320,7 +3320,7 @@ components: | |||
3320 | name: abuseId | 3320 | name: abuseId |
3321 | in: path | 3321 | in: path |
3322 | required: true | 3322 | required: true |
3323 | description: Video abuse id | 3323 | description: Abuse id |
3324 | schema: | 3324 | schema: |
3325 | type: integer | 3325 | type: integer |
3326 | captionLanguage: | 3326 | captionLanguage: |
@@ -5098,7 +5098,7 @@ components: | |||
5098 | 5098 | ||
5099 | - `2` NEW_COMMENT_ON_MY_VIDEO | 5099 | - `2` NEW_COMMENT_ON_MY_VIDEO |
5100 | 5100 | ||
5101 | - `3` NEW_VIDEO_ABUSE_FOR_MODERATORS | 5101 | - `3` NEW_ABUSE_FOR_MODERATORS |
5102 | 5102 | ||
5103 | - `4` BLACKLIST_ON_MY_VIDEO | 5103 | - `4` BLACKLIST_ON_MY_VIDEO |
5104 | 5104 | ||