Add new abuses tests
This commit is contained in:
parent
811cef146c
commit
310b5219b3
|
@ -138,8 +138,8 @@
|
|||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No video abuses found.</ng-container>
|
||||
<ng-container *ngIf="search" i18n>No abuses found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No abuses found.</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -118,7 +118,7 @@ export class UserNotification implements UserNotificationServer {
|
|||
this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ]
|
||||
break
|
||||
|
||||
case UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS:
|
||||
case UserNotificationType.NEW_ABUSE_FOR_MODERATORS:
|
||||
this.abuseUrl = '/admin/moderation/abuses/list'
|
||||
|
||||
if (this.abuse.video) this.videoUrl = this.buildVideoUrl(this.abuse.video)
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS">
|
||||
<ng-container *ngSwitchCase="UserNotificationType.NEW_ABUSE_FOR_MODERATORS">
|
||||
<my-global-icon iconName="flag" aria-hidden="true"></my-global-icon>
|
||||
|
||||
<div class="message" i18n>
|
||||
|
|
|
@ -140,7 +140,6 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
|||
const { hasStart, startAt, hasEnd, endAt } = this.form.get('timestamp').value
|
||||
|
||||
this.abuseService.reportVideo({
|
||||
accountId: this.video.account.id,
|
||||
reason,
|
||||
predefinedReasons,
|
||||
video: {
|
||||
|
|
|
@ -100,7 +100,7 @@ async function updateAbuse (req: express.Request, res: express.Response) {
|
|||
return abuse.save({ transaction: t })
|
||||
})
|
||||
|
||||
// Do not send the delete to other instances, we updated OUR copy of this video abuse
|
||||
// Do not send the delete to other instances, we updated OUR copy of this abuse
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ async function deleteAbuse (req: express.Request, res: express.Response) {
|
|||
return abuse.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
// Do not send the delete to other instances, we delete OUR copy of this video abuse
|
||||
// Do not send the delete to other instances, we delete OUR copy of this abuse
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
|
|
@ -50,7 +50,5 @@ async function removeUserHistory (req: express.Request, res: express.Response) {
|
|||
return UserVideoHistoryModel.removeUserHistoryBefore(user, beforeDate, t)
|
||||
})
|
||||
|
||||
// Do not send the delete to other instances, we delete OUR copy of this video abuse
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ import { AbuseFilter, abusePredefinedReasonsMap, AbusePredefinedReasonsString, A
|
|||
import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
||||
import { exists, isArray } from './misc'
|
||||
|
||||
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.ABUSES
|
||||
const ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.ABUSES
|
||||
|
||||
function isAbuseReasonValid (value: string) {
|
||||
return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
|
||||
return exists(value) && validator.isLength(value, ABUSES_CONSTRAINTS_FIELDS.REASON)
|
||||
}
|
||||
|
||||
function isAbusePredefinedReasonValid (value: AbusePredefinedReasonsString) {
|
||||
|
@ -32,7 +32,7 @@ function isAbuseTimestampCoherent (endAt: number, { req }) {
|
|||
}
|
||||
|
||||
function isAbuseModerationCommentValid (value: string) {
|
||||
return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.MODERATION_COMMENT)
|
||||
return exists(value) && validator.isLength(value, ABUSES_CONSTRAINTS_FIELDS.MODERATION_COMMENT)
|
||||
}
|
||||
|
||||
function isAbuseStateValid (value: string) {
|
||||
|
|
|
@ -68,7 +68,7 @@ async function doesVideoCommentExist (idArg: number | string, video: MVideoId, r
|
|||
|
||||
async function doesCommentIdExist (idArg: number | string, res: express.Response) {
|
||||
const id = parseInt(idArg + '', 10)
|
||||
const videoComment = await VideoCommentModel.loadById(id)
|
||||
const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id)
|
||||
|
||||
if (!videoComment) {
|
||||
res.status(404)
|
||||
|
@ -77,7 +77,7 @@ async function doesCommentIdExist (idArg: number | string, res: express.Response
|
|||
return false
|
||||
}
|
||||
|
||||
res.locals.videoComment = videoComment
|
||||
res.locals.videoCommentFull = videoComment
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ async function doesAbuseExist (abuseId: number | string, res: Response) {
|
|||
|
||||
if (!abuse) {
|
||||
res.status(404)
|
||||
.json({ error: 'Video abuse not found' })
|
||||
.json({ error: 'Abuse not found' })
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -43,12 +43,10 @@ async function up (utils: {
|
|||
await utils.sequelize.query(`
|
||||
CREATE TABLE IF NOT EXISTS "commentAbuse" (
|
||||
"id" serial,
|
||||
"deletedComment" jsonb DEFAULT NULL,
|
||||
"abuseId" integer NOT NULL REFERENCES "abuse" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
"videoCommentId" integer REFERENCES "videoComment" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
"createdAt" timestamp WITH time zone NOT NULL,
|
||||
"updatedAt" timestamp WITH time zone NOT NULL,
|
||||
"commentId" integer REFERENCES "videoComment" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
`)
|
||||
|
|
|
@ -325,6 +325,7 @@ class Emailer {
|
|||
subject: `New comment abuse report from ${reporter}`,
|
||||
locals: {
|
||||
commentUrl,
|
||||
videoName: comment.Video.name,
|
||||
isLocal: comment.isOwned(),
|
||||
commentCreatedAt: new Date(comment.createdAt).toLocaleString(),
|
||||
reason: abuse.reason,
|
||||
|
|
|
@ -7,7 +7,8 @@ block title
|
|||
block content
|
||||
p
|
||||
| #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}comment "
|
||||
a(href=commentUrl) of #{flaggedAccount}
|
||||
a(href=commentUrl) on video #{videoName}
|
||||
| of #{flaggedAccount}
|
||||
| created on #{commentCreatedAt}
|
||||
|
||||
p The reporter, #{reporter}, cited the following reason(s):
|
||||
|
|
|
@ -371,7 +371,7 @@ class Notifier {
|
|||
|
||||
async function notificationCreator (user: MUserWithNotificationSetting) {
|
||||
const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
|
||||
type: UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS,
|
||||
type: UserNotificationType.NEW_ABUSE_FOR_MODERATORS,
|
||||
userId: user.id,
|
||||
abuseId: abuse.id
|
||||
})
|
||||
|
|
|
@ -128,7 +128,7 @@ const abuseListValidator = [
|
|||
.custom(exists).withMessage('Should have a valid search'),
|
||||
query('state')
|
||||
.optional()
|
||||
.custom(isAbuseStateValid).withMessage('Should have a valid video abuse state'),
|
||||
.custom(isAbuseStateValid).withMessage('Should have a valid abuse state'),
|
||||
query('videoIs')
|
||||
.optional()
|
||||
.custom(isAbuseVideoIsValid).withMessage('Should have a valid "video is" attribute'),
|
||||
|
|
|
@ -362,8 +362,8 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
const countReportsForReporter = this.get('countReportsForReporter') as number
|
||||
const countReportsForReportee = this.get('countReportsForReportee') as number
|
||||
|
||||
let video: VideoAbuse
|
||||
let comment: VideoCommentAbuse
|
||||
let video: VideoAbuse = null
|
||||
let comment: VideoCommentAbuse = null
|
||||
|
||||
if (this.VideoAbuse) {
|
||||
const abuseModel = this.VideoAbuse
|
||||
|
@ -391,13 +391,13 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
|
||||
if (this.VideoCommentAbuse) {
|
||||
const abuseModel = this.VideoCommentAbuse
|
||||
const entity = abuseModel.VideoComment || abuseModel.deletedComment
|
||||
const entity = abuseModel.VideoComment
|
||||
|
||||
comment = {
|
||||
id: entity.id,
|
||||
text: entity.text,
|
||||
text: entity.text ?? '',
|
||||
|
||||
deleted: !abuseModel.VideoComment,
|
||||
deleted: entity.isDeleted(),
|
||||
|
||||
video: {
|
||||
id: entity.Video.id,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
|
||||
import { VideoComment } from '@shared/models'
|
||||
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
|
||||
import { VideoCommentModel } from '../video/video-comment'
|
||||
import { AbuseModel } from './abuse'
|
||||
|
||||
|
@ -22,11 +21,6 @@ export class VideoCommentAbuseModel extends Model<VideoCommentAbuseModel> {
|
|||
@UpdatedAt
|
||||
updatedAt: Date
|
||||
|
||||
@AllowNull(true)
|
||||
@Default(null)
|
||||
@Column(DataType.JSONB)
|
||||
deletedComment: VideoComment & { Video: { name: string, id: number, uuid: string }}
|
||||
|
||||
@ForeignKey(() => AbuseModel)
|
||||
@Column
|
||||
abuseId: number
|
||||
|
|
|
@ -109,7 +109,7 @@ function buildAccountInclude (required: boolean, withActor = false) {
|
|||
required: true,
|
||||
include: [
|
||||
{
|
||||
attributes: [ 'uuid' ],
|
||||
attributes: [ 'id', 'name', 'uuid' ],
|
||||
model: VideoModel.unscoped(),
|
||||
required: true
|
||||
}
|
||||
|
@ -492,6 +492,8 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
|
|||
threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(),
|
||||
|
||||
video: {
|
||||
id: abuse.VideoCommentAbuse.VideoComment.Video.id,
|
||||
name: abuse.VideoCommentAbuse.VideoComment.Video.name,
|
||||
uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid
|
||||
}
|
||||
} : undefined
|
||||
|
|
|
@ -3,7 +3,6 @@ import { uniq } from 'lodash'
|
|||
import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize'
|
||||
import {
|
||||
AllowNull,
|
||||
BeforeDestroy,
|
||||
BelongsTo,
|
||||
Column,
|
||||
CreatedAt,
|
||||
|
@ -16,7 +15,6 @@ import {
|
|||
Table,
|
||||
UpdatedAt
|
||||
} from 'sequelize-typescript'
|
||||
import { logger } from '@server/helpers/logger'
|
||||
import { getServerActor } from '@server/models/application/application'
|
||||
import { MAccount, MAccountId, MUserAccountId } from '@server/types/models'
|
||||
import { VideoPrivacy } from '@shared/models'
|
||||
|
@ -242,51 +240,13 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
|
|||
|
||||
@HasMany(() => VideoCommentAbuseModel, {
|
||||
foreignKey: {
|
||||
name: 'commentId',
|
||||
name: 'videoCommentId',
|
||||
allowNull: true
|
||||
},
|
||||
onDelete: 'set null'
|
||||
})
|
||||
CommentAbuses: VideoCommentAbuseModel[]
|
||||
|
||||
@BeforeDestroy
|
||||
static async saveEssentialDataToAbuses (instance: VideoCommentModel, options) {
|
||||
const tasks: Promise<any>[] = []
|
||||
|
||||
if (!Array.isArray(instance.CommentAbuses)) {
|
||||
instance.CommentAbuses = await instance.$get('CommentAbuses')
|
||||
|
||||
if (instance.CommentAbuses.length === 0) return undefined
|
||||
}
|
||||
|
||||
if (!instance.Video) {
|
||||
instance.Video = await instance.$get('Video')
|
||||
}
|
||||
|
||||
logger.info('Saving video comment %s for abuse.', instance.url)
|
||||
|
||||
const details = Object.assign(instance.toFormattedJSON(), {
|
||||
Video: {
|
||||
id: instance.Video.id,
|
||||
name: instance.Video.name,
|
||||
uuid: instance.Video.uuid
|
||||
}
|
||||
})
|
||||
|
||||
for (const abuse of instance.CommentAbuses) {
|
||||
abuse.deletedComment = details
|
||||
|
||||
tasks.push(abuse.save({ transaction: options.transaction }))
|
||||
}
|
||||
|
||||
Promise.all(tasks)
|
||||
.catch(err => {
|
||||
logger.error('Some errors when saving details of comment %s in its abuses before destroy hook.', instance.url, { err })
|
||||
})
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
static loadById (id: number, t?: Transaction): Bluebird<MComment> {
|
||||
const query: FindOptions = {
|
||||
where: {
|
||||
|
|
|
@ -21,9 +21,7 @@ import {
|
|||
checkBadStartPagination
|
||||
} from '../../../../shared/extra-utils/requests/check-api-params'
|
||||
|
||||
// FIXME: deprecated in 2.3. Remove this controller
|
||||
|
||||
describe('Test video abuses API validators', function () {
|
||||
describe('Test abuses API validators', function () {
|
||||
const basePath = '/api/v1/abuses/'
|
||||
|
||||
let server: ServerInfo
|
||||
|
|
|
@ -2,21 +2,30 @@
|
|||
|
||||
import 'mocha'
|
||||
import * as chai from 'chai'
|
||||
import { Abuse, AbusePredefinedReasonsString, AbuseState } from '@shared/models'
|
||||
import { Abuse, AbuseFilter, AbusePredefinedReasonsString, AbuseState, VideoComment, Account } from '@shared/models'
|
||||
import {
|
||||
addVideoCommentThread,
|
||||
cleanupTests,
|
||||
createUser,
|
||||
deleteVideoAbuse,
|
||||
deleteAbuse,
|
||||
deleteVideoComment,
|
||||
flushAndRunMultipleServers,
|
||||
getVideoAbusesList,
|
||||
getAbusesList,
|
||||
getVideoCommentThreads,
|
||||
getVideoIdFromUUID,
|
||||
getVideosList,
|
||||
immutableAssign,
|
||||
removeVideo,
|
||||
reportVideoAbuse,
|
||||
reportAbuse,
|
||||
ServerInfo,
|
||||
setAccessTokensToServers,
|
||||
updateVideoAbuse,
|
||||
updateAbuse,
|
||||
uploadVideo,
|
||||
userLogin
|
||||
uploadVideoAndGetId,
|
||||
userLogin,
|
||||
getAccount,
|
||||
removeUser,
|
||||
generateUserAccessToken
|
||||
} from '../../../../shared/extra-utils/index'
|
||||
import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
|
||||
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
|
||||
|
@ -31,6 +40,7 @@ const expect = chai.expect
|
|||
|
||||
describe('Test abuses', function () {
|
||||
let servers: ServerInfo[] = []
|
||||
let abuseServer1: Abuse
|
||||
let abuseServer2: Abuse
|
||||
|
||||
before(async function () {
|
||||
|
@ -44,6 +54,12 @@ describe('Test abuses', function () {
|
|||
|
||||
// Server 1 and server 2 follow each other
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
})
|
||||
|
||||
describe('Video abuses', function () {
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000)
|
||||
|
||||
// Upload some videos on each servers
|
||||
const video1Attributes = {
|
||||
|
@ -70,8 +86,8 @@ describe('Test abuses', function () {
|
|||
servers[1].video = videos.find(video => video.name === 'my super name for server 2')
|
||||
})
|
||||
|
||||
it('Should not have video abuses', async function () {
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
it('Should not have abuses', async function () {
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data).to.be.an('array')
|
||||
|
@ -82,14 +98,14 @@ describe('Test abuses', function () {
|
|||
this.timeout(15000)
|
||||
|
||||
const reason = 'my super bad reason'
|
||||
await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason)
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: servers[0].video.id, reason })
|
||||
|
||||
// We wait requests propagation, even if the server 1 is not supposed to make a request to server 2
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should have 1 video abuses on server 1 and 0 on server 2', async function () {
|
||||
const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
|
||||
expect(res1.body.total).to.equal(1)
|
||||
expect(res1.body.data).to.be.an('array')
|
||||
|
@ -97,16 +113,25 @@ describe('Test abuses', function () {
|
|||
|
||||
const abuse: Abuse = res1.body.data[0]
|
||||
expect(abuse.reason).to.equal('my super bad reason')
|
||||
|
||||
expect(abuse.reporterAccount.name).to.equal('root')
|
||||
expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
|
||||
expect(abuse.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse.video.id).to.equal(servers[0].video.id)
|
||||
expect(abuse.video.channel).to.exist
|
||||
expect(abuse.count).to.equal(1)
|
||||
expect(abuse.nth).to.equal(1)
|
||||
|
||||
expect(abuse.comment).to.be.null
|
||||
|
||||
expect(abuse.flaggedAccount.name).to.equal('root')
|
||||
expect(abuse.flaggedAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse.video.countReports).to.equal(1)
|
||||
expect(abuse.video.nthReport).to.equal(1)
|
||||
|
||||
expect(abuse.countReportsForReporter).to.equal(1)
|
||||
expect(abuse.countReportsForReportee).to.equal(1)
|
||||
|
||||
const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
expect(res2.body.total).to.equal(0)
|
||||
expect(res2.body.data).to.be.an('array')
|
||||
expect(res2.body.data.length).to.equal(0)
|
||||
|
@ -116,86 +141,88 @@ describe('Test abuses', function () {
|
|||
this.timeout(10000)
|
||||
|
||||
const reason = 'my super bad reason 2'
|
||||
await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason)
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: servers[1].video.id, reason })
|
||||
|
||||
// We wait requests propagation
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should have 2 video abuses on server 1 and 1 on server 2', async function () {
|
||||
const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
|
||||
expect(res1.body.total).to.equal(2)
|
||||
expect(res1.body.data).to.be.an('array')
|
||||
expect(res1.body.data.length).to.equal(2)
|
||||
|
||||
const abuse1: Abuse = res1.body.data[0]
|
||||
expect(abuse1.reason).to.equal('my super bad reason')
|
||||
expect(abuse1.reporterAccount.name).to.equal('root')
|
||||
expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port)
|
||||
expect(abuse1.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse1.video.id).to.equal(servers[0].video.id)
|
||||
expect(abuse1.video.countReports).to.equal(1)
|
||||
expect(abuse1.video.nthReport).to.equal(1)
|
||||
|
||||
expect(abuse1.comment).to.be.null
|
||||
|
||||
expect(abuse1.flaggedAccount.name).to.equal('root')
|
||||
expect(abuse1.flaggedAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse1.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuse1.state.label).to.equal('Pending')
|
||||
expect(abuse1.moderationComment).to.be.null
|
||||
expect(abuse1.count).to.equal(1)
|
||||
expect(abuse1.nth).to.equal(1)
|
||||
|
||||
const abuse2: Abuse = res1.body.data[1]
|
||||
expect(abuse2.reason).to.equal('my super bad reason 2')
|
||||
|
||||
expect(abuse2.reporterAccount.name).to.equal('root')
|
||||
expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
|
||||
expect(abuse2.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse2.video.id).to.equal(servers[1].video.id)
|
||||
|
||||
expect(abuse2.comment).to.be.null
|
||||
|
||||
expect(abuse2.flaggedAccount.name).to.equal('root')
|
||||
expect(abuse2.flaggedAccount.host).to.equal(servers[1].host)
|
||||
|
||||
expect(abuse2.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuse2.state.label).to.equal('Pending')
|
||||
expect(abuse2.moderationComment).to.be.null
|
||||
|
||||
const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
expect(res2.body.total).to.equal(1)
|
||||
expect(res2.body.data).to.be.an('array')
|
||||
expect(res2.body.data.length).to.equal(1)
|
||||
|
||||
abuseServer2 = res2.body.data[0]
|
||||
expect(abuseServer2.reason).to.equal('my super bad reason 2')
|
||||
expect(abuseServer2.reporterAccount.name).to.equal('root')
|
||||
expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
|
||||
expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse2.flaggedAccount.name).to.equal('root')
|
||||
expect(abuse2.flaggedAccount.host).to.equal(servers[1].host)
|
||||
|
||||
expect(abuseServer2.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuseServer2.state.label).to.equal('Pending')
|
||||
expect(abuseServer2.moderationComment).to.be.null
|
||||
})
|
||||
|
||||
it('Should update the state of a video abuse', async function () {
|
||||
const body = { state: AbuseState.REJECTED }
|
||||
await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
expect(res.body.data[0].state.id).to.equal(AbuseState.REJECTED)
|
||||
})
|
||||
|
||||
it('Should add a moderation comment', async function () {
|
||||
const body = { state: AbuseState.ACCEPTED, moderationComment: 'It is valid' }
|
||||
await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
expect(res.body.data[0].state.id).to.equal(AbuseState.ACCEPTED)
|
||||
expect(res.body.data[0].moderationComment).to.equal('It is valid')
|
||||
})
|
||||
|
||||
it('Should hide video abuses from blocked accounts', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
{
|
||||
await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this')
|
||||
const videoId = await getVideoIdFromUUID(servers[1].url, servers[0].video.uuid)
|
||||
await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId, reason: 'will mute this' })
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(3)
|
||||
}
|
||||
|
||||
const accountToBlock = 'root@localhost:' + servers[1].port
|
||||
const accountToBlock = 'root@' + servers[1].host
|
||||
|
||||
{
|
||||
await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(2)
|
||||
|
||||
const abuse = res.body.data.find(a => a.reason === 'will mute this')
|
||||
|
@ -205,7 +232,7 @@ describe('Test abuses', function () {
|
|||
{
|
||||
await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(3)
|
||||
}
|
||||
})
|
||||
|
@ -216,7 +243,7 @@ describe('Test abuses', function () {
|
|||
{
|
||||
await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(2)
|
||||
|
||||
const abuse = res.body.data.find(a => a.reason === 'will mute this')
|
||||
|
@ -226,7 +253,7 @@ describe('Test abuses', function () {
|
|||
{
|
||||
await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(3)
|
||||
}
|
||||
})
|
||||
|
@ -238,12 +265,12 @@ describe('Test abuses', function () {
|
|||
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
expect(res.body.total).to.equal(2, "wrong number of videos returned")
|
||||
expect(res.body.data.length).to.equal(2, "wrong number of videos returned")
|
||||
expect(res.body.data[0].id).to.equal(abuseServer2.id, "wrong origin server id for first video")
|
||||
expect(res.body.data).to.have.lengthOf(2, "wrong number of videos returned")
|
||||
|
||||
const abuse: Abuse = res.body.data[0]
|
||||
expect(abuse.id).to.equal(abuseServer2.id, "wrong origin server id for first video")
|
||||
expect(abuse.video.id).to.equal(abuseServer2.video.id, "wrong video id")
|
||||
expect(abuse.video.channel).to.exist
|
||||
expect(abuse.video.deleted).to.be.true
|
||||
|
@ -270,24 +297,24 @@ describe('Test abuses', function () {
|
|||
|
||||
// resume with the test
|
||||
const reason3 = 'my super bad reason 3'
|
||||
await reportVideoAbuse(servers[0].url, servers[0].accessToken, video3.id, reason3)
|
||||
const reason4 = 'my super bad reason 4'
|
||||
await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4)
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: video3.id, reason: reason3 })
|
||||
|
||||
const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const reason4 = 'my super bad reason 4'
|
||||
await reportAbuse({ url: servers[0].url, token: userAccessToken, videoId: servers[0].video.id, reason: reason4 })
|
||||
|
||||
{
|
||||
for (const abuse of res2.body.data as Abuse[]) {
|
||||
if (abuse.video.id === video3.id) {
|
||||
expect(abuse.count).to.equal(1, "wrong reports count for video 3")
|
||||
expect(abuse.nth).to.equal(1, "wrong report position in report list for video 3")
|
||||
expect(abuse.countReportsForReportee).to.equal(1, "wrong reports count for reporter on video 3 abuse")
|
||||
expect(abuse.countReportsForReporter).to.equal(3, "wrong reports count for reportee on video 3 abuse")
|
||||
}
|
||||
if (abuse.video.id === servers[0].video.id) {
|
||||
expect(abuse.countReportsForReportee).to.equal(3, "wrong reports count for reporter on video 1 abuse")
|
||||
}
|
||||
}
|
||||
const res2 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const abuses = res2.body.data as Abuse[]
|
||||
|
||||
const abuseVideo3 = res2.body.data.find(a => a.video.id === video3.id)
|
||||
expect(abuseVideo3).to.not.be.undefined
|
||||
expect(abuseVideo3.video.countReports).to.equal(1, "wrong reports count for video 3")
|
||||
expect(abuseVideo3.video.nthReport).to.equal(1, "wrong report position in report list for video 3")
|
||||
expect(abuseVideo3.countReportsForReportee).to.equal(1, "wrong reports count for reporter on video 3 abuse")
|
||||
expect(abuseVideo3.countReportsForReporter).to.equal(3, "wrong reports count for reportee on video 3 abuse")
|
||||
|
||||
const abuseServer1 = abuses.find(a => a.video.id === servers[0].video.id)
|
||||
expect(abuseServer1.countReportsForReportee).to.equal(3, "wrong reports count for reporter on video 1 abuse")
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -296,17 +323,17 @@ describe('Test abuses', function () {
|
|||
|
||||
const reason5 = 'my super bad reason 5'
|
||||
const predefinedReasons5: AbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ]
|
||||
const createdAbuse = (await reportVideoAbuse(
|
||||
servers[0].url,
|
||||
servers[0].accessToken,
|
||||
servers[0].video.id,
|
||||
reason5,
|
||||
predefinedReasons5,
|
||||
1,
|
||||
5
|
||||
)).body.abuse
|
||||
const createdAbuse = (await reportAbuse({
|
||||
url: servers[0].url,
|
||||
token: servers[0].accessToken,
|
||||
videoId: servers[0].video.id,
|
||||
reason: reason5,
|
||||
predefinedReasons: predefinedReasons5,
|
||||
startAt: 1,
|
||||
endAt: 5
|
||||
})).body.abuse
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
|
||||
{
|
||||
const abuse = (res.body.data as Abuse[]).find(a => a.id === createdAbuse.id)
|
||||
|
@ -320,25 +347,27 @@ describe('Test abuses', function () {
|
|||
it('Should delete the video abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
await deleteVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id)
|
||||
await deleteAbuse(servers[1].url, servers[1].accessToken, abuseServer2.id)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
{
|
||||
const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken })
|
||||
expect(res.body.total).to.equal(1)
|
||||
expect(res.body.data.length).to.equal(1)
|
||||
expect(res.body.data[0].id).to.not.equal(abuseServer2.id)
|
||||
}
|
||||
|
||||
{
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(6)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should list and filter video abuses', async function () {
|
||||
async function list (query: Omit<Parameters<typeof getVideoAbusesList>[0], 'url' | 'token'>) {
|
||||
this.timeout(10000)
|
||||
|
||||
async function list (query: Omit<Parameters<typeof getAbusesList>[0], 'url' | 'token'>) {
|
||||
const options = {
|
||||
url: servers[0].url,
|
||||
token: servers[0].accessToken
|
||||
|
@ -346,7 +375,7 @@ describe('Test abuses', function () {
|
|||
|
||||
Object.assign(options, query)
|
||||
|
||||
const res = await getVideoAbusesList(options)
|
||||
const res = await getAbusesList(options)
|
||||
|
||||
return res.body.data as Abuse[]
|
||||
}
|
||||
|
@ -377,6 +406,370 @@ describe('Test abuses', function () {
|
|||
expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1)
|
||||
expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Comment abuses', function () {
|
||||
|
||||
async function getComment (url: string, videoIdArg: number | string) {
|
||||
const videoId = typeof videoIdArg === 'string'
|
||||
? await getVideoIdFromUUID(url, videoIdArg)
|
||||
: videoIdArg
|
||||
|
||||
const res = await getVideoCommentThreads(url, videoId, 0, 5)
|
||||
|
||||
return res.body.data[0] as VideoComment
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000)
|
||||
|
||||
servers[0].video = await uploadVideoAndGetId({ server: servers[0], videoName: 'server 1' })
|
||||
servers[1].video = await uploadVideoAndGetId({ server: servers[1], videoName: 'server 2' })
|
||||
|
||||
await addVideoCommentThread(servers[0].url, servers[0].accessToken, servers[0].video.id, 'comment server 1')
|
||||
await addVideoCommentThread(servers[1].url, servers[1].accessToken, servers[1].video.id, 'comment server 2')
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should report abuse on a comment', async function () {
|
||||
this.timeout(15000)
|
||||
|
||||
const comment = await getComment(servers[0].url, servers[0].video.id)
|
||||
|
||||
const reason = 'it is a bad comment'
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, commentId: comment.id, reason })
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should have 1 comment abuse on server 1 and 0 on server 2', async function () {
|
||||
{
|
||||
const comment = await getComment(servers[0].url, servers[0].video.id)
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' })
|
||||
|
||||
expect(res.body.total).to.equal(1)
|
||||
expect(res.body.data).to.have.lengthOf(1)
|
||||
|
||||
const abuse: Abuse = res.body.data[0]
|
||||
expect(abuse.reason).to.equal('it is a bad comment')
|
||||
|
||||
expect(abuse.reporterAccount.name).to.equal('root')
|
||||
expect(abuse.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse.video).to.be.null
|
||||
|
||||
expect(abuse.comment.deleted).to.be.false
|
||||
expect(abuse.comment.id).to.equal(comment.id)
|
||||
expect(abuse.comment.text).to.equal(comment.text)
|
||||
expect(abuse.comment.video.name).to.equal('server 1')
|
||||
expect(abuse.comment.video.id).to.equal(servers[0].video.id)
|
||||
expect(abuse.comment.video.uuid).to.equal(servers[0].video.uuid)
|
||||
|
||||
expect(abuse.countReportsForReporter).to.equal(5)
|
||||
expect(abuse.countReportsForReportee).to.equal(5)
|
||||
}
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' })
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data.length).to.equal(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should report abuse on a remote comment', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const comment = await getComment(servers[0].url, servers[1].video.uuid)
|
||||
|
||||
const reason = 'it is a really bad comment'
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, commentId: comment.id, reason })
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () {
|
||||
const commentServer2 = await getComment(servers[0].url, servers[1].video.id)
|
||||
|
||||
const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' })
|
||||
expect(res1.body.total).to.equal(2)
|
||||
expect(res1.body.data.length).to.equal(2)
|
||||
|
||||
const abuse: Abuse = res1.body.data[0]
|
||||
expect(abuse.reason).to.equal('it is a bad comment')
|
||||
expect(abuse.countReportsForReporter).to.equal(6)
|
||||
expect(abuse.countReportsForReportee).to.equal(5)
|
||||
|
||||
const abuse2: Abuse = res1.body.data[1]
|
||||
|
||||
expect(abuse2.reason).to.equal('it is a really bad comment')
|
||||
|
||||
expect(abuse2.reporterAccount.name).to.equal('root')
|
||||
expect(abuse2.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse2.video).to.be.null
|
||||
|
||||
expect(abuse2.comment.deleted).to.be.false
|
||||
expect(abuse2.comment.id).to.equal(commentServer2.id)
|
||||
expect(abuse2.comment.text).to.equal(commentServer2.text)
|
||||
expect(abuse2.comment.video.name).to.equal('server 2')
|
||||
expect(abuse2.comment.video.uuid).to.equal(servers[1].video.uuid)
|
||||
|
||||
expect(abuse2.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuse2.state.label).to.equal('Pending')
|
||||
|
||||
expect(abuse2.moderationComment).to.be.null
|
||||
|
||||
expect(abuse2.countReportsForReporter).to.equal(6)
|
||||
expect(abuse2.countReportsForReportee).to.equal(2)
|
||||
|
||||
const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' })
|
||||
expect(res2.body.total).to.equal(1)
|
||||
expect(res2.body.data.length).to.equal(1)
|
||||
|
||||
abuseServer2 = res2.body.data[0]
|
||||
expect(abuseServer2.reason).to.equal('it is a really bad comment')
|
||||
expect(abuseServer2.reporterAccount.name).to.equal('root')
|
||||
expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuseServer2.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuseServer2.state.label).to.equal('Pending')
|
||||
|
||||
expect(abuseServer2.moderationComment).to.be.null
|
||||
|
||||
expect(abuseServer2.countReportsForReporter).to.equal(1)
|
||||
expect(abuseServer2.countReportsForReportee).to.equal(1)
|
||||
})
|
||||
|
||||
it('Should keep the comment abuse when deleting the comment', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const commentServer2 = await getComment(servers[0].url, servers[1].video.id)
|
||||
|
||||
await deleteVideoComment(servers[0].url, servers[0].accessToken, servers[1].video.uuid, commentServer2.id)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' })
|
||||
expect(res.body.total).to.equal(2)
|
||||
expect(res.body.data).to.have.lengthOf(2)
|
||||
|
||||
const abuse = (res.body.data as Abuse[]).find(a => a.comment?.id === commentServer2.id)
|
||||
expect(abuse).to.not.be.undefined
|
||||
|
||||
expect(abuse.comment.text).to.be.empty
|
||||
expect(abuse.comment.video.name).to.equal('server 2')
|
||||
expect(abuse.comment.deleted).to.be.true
|
||||
})
|
||||
|
||||
it('Should delete the comment abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
await deleteAbuse(servers[1].url, servers[1].accessToken, abuseServer2.id)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' })
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data.length).to.equal(0)
|
||||
}
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment' })
|
||||
expect(res.body.total).to.equal(2)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should list and filter video abuses', async function () {
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment', searchReportee: 'foo' })
|
||||
expect(res.body.total).to.equal(0)
|
||||
}
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'comment', searchReportee: 'ot' })
|
||||
expect(res.body.total).to.equal(2)
|
||||
}
|
||||
|
||||
{
|
||||
const baseParams = { url: servers[0].url, token: servers[0].accessToken, filter: 'comment' as AbuseFilter, start: 1, count: 1 }
|
||||
|
||||
const res1 = await getAbusesList(immutableAssign(baseParams, { sort: 'createdAt' }))
|
||||
expect(res1.body.data).to.have.lengthOf(1)
|
||||
expect(res1.body.data[0].comment.text).to.be.empty
|
||||
|
||||
const res2 = await getAbusesList(immutableAssign(baseParams, { sort: '-createdAt' }))
|
||||
expect(res2.body.data).to.have.lengthOf(1)
|
||||
expect(res2.body.data[0].comment.text).to.equal('comment server 1')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Account abuses', function () {
|
||||
|
||||
async function getAccountFromServer (url: string, name: string, server: ServerInfo) {
|
||||
const res = await getAccount(url, name + '@' + server.host)
|
||||
|
||||
return res.body as Account
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000)
|
||||
|
||||
await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'user_1', password: 'donald' })
|
||||
|
||||
const token = await generateUserAccessToken(servers[1], 'user_2')
|
||||
await uploadVideo(servers[1].url, token, { name: 'super video' })
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should report abuse on an account', async function () {
|
||||
this.timeout(15000)
|
||||
|
||||
const account = await getAccountFromServer(servers[0].url, 'user_1', servers[0])
|
||||
|
||||
const reason = 'it is a bad account'
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, accountId: account.id, reason })
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should have 1 account abuse on server 1 and 0 on server 2', async function () {
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' })
|
||||
|
||||
expect(res.body.total).to.equal(1)
|
||||
expect(res.body.data).to.have.lengthOf(1)
|
||||
|
||||
const abuse: Abuse = res.body.data[0]
|
||||
expect(abuse.reason).to.equal('it is a bad account')
|
||||
|
||||
expect(abuse.reporterAccount.name).to.equal('root')
|
||||
expect(abuse.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse.video).to.be.null
|
||||
expect(abuse.comment).to.be.null
|
||||
|
||||
expect(abuse.flaggedAccount.name).to.equal('user_1')
|
||||
expect(abuse.flaggedAccount.host).to.equal(servers[0].host)
|
||||
}
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'comment' })
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data.length).to.equal(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should report abuse on a remote account', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const account = await getAccountFromServer(servers[0].url, 'user_2', servers[1])
|
||||
|
||||
const reason = 'it is a really bad account'
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, accountId: account.id, reason })
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () {
|
||||
const res1 = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' })
|
||||
expect(res1.body.total).to.equal(2)
|
||||
expect(res1.body.data.length).to.equal(2)
|
||||
|
||||
const abuse: Abuse = res1.body.data[0]
|
||||
expect(abuse.reason).to.equal('it is a bad account')
|
||||
|
||||
const abuse2: Abuse = res1.body.data[1]
|
||||
expect(abuse2.reason).to.equal('it is a really bad account')
|
||||
|
||||
expect(abuse2.reporterAccount.name).to.equal('root')
|
||||
expect(abuse2.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuse2.video).to.be.null
|
||||
expect(abuse2.comment).to.be.null
|
||||
|
||||
expect(abuse2.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuse2.state.label).to.equal('Pending')
|
||||
|
||||
expect(abuse2.moderationComment).to.be.null
|
||||
|
||||
const res2 = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'account' })
|
||||
expect(res2.body.total).to.equal(1)
|
||||
expect(res2.body.data.length).to.equal(1)
|
||||
|
||||
abuseServer2 = res2.body.data[0]
|
||||
|
||||
expect(abuseServer2.reason).to.equal('it is a really bad account')
|
||||
|
||||
expect(abuseServer2.reporterAccount.name).to.equal('root')
|
||||
expect(abuseServer2.reporterAccount.host).to.equal(servers[0].host)
|
||||
|
||||
expect(abuseServer2.state.id).to.equal(AbuseState.PENDING)
|
||||
expect(abuseServer2.state.label).to.equal('Pending')
|
||||
|
||||
expect(abuseServer2.moderationComment).to.be.null
|
||||
})
|
||||
|
||||
it('Should keep the account abuse when deleting the account', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const account = await getAccountFromServer(servers[1].url, 'user_2', servers[1])
|
||||
await removeUser(servers[1].url, account.userId, servers[1].accessToken)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' })
|
||||
expect(res.body.total).to.equal(2)
|
||||
expect(res.body.data).to.have.lengthOf(2)
|
||||
|
||||
const abuse = (res.body.data as Abuse[]).find(a => a.reason === 'it is a really bad account')
|
||||
expect(abuse).to.not.be.undefined
|
||||
})
|
||||
|
||||
it('Should delete the account abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
await deleteAbuse(servers[1].url, servers[1].accessToken, abuseServer2.id)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[1].url, token: servers[1].accessToken, filter: 'account' })
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data.length).to.equal(0)
|
||||
}
|
||||
|
||||
{
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, filter: 'account' })
|
||||
expect(res.body.total).to.equal(2)
|
||||
|
||||
abuseServer1 = res.body.data[0]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Common actions on abuses', function () {
|
||||
|
||||
it('Should update the state of an abuse', async function () {
|
||||
const body = { state: AbuseState.REJECTED }
|
||||
await updateAbuse(servers[0].url, servers[0].accessToken, abuseServer1.id, body)
|
||||
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, id: abuseServer1.id })
|
||||
expect(res.body.data[0].state.id).to.equal(AbuseState.REJECTED)
|
||||
})
|
||||
|
||||
it('Should add a moderation comment', async function () {
|
||||
const body = { state: AbuseState.ACCEPTED, moderationComment: 'It is valid' }
|
||||
await updateAbuse(servers[0].url, servers[0].accessToken, abuseServer1.id, body)
|
||||
|
||||
const res = await getAbusesList({ url: servers[0].url, token: servers[0].accessToken, id: abuseServer1.id })
|
||||
expect(res.body.data[0].state.id).to.equal(AbuseState.ACCEPTED)
|
||||
expect(res.body.data[0].moderationComment).to.equal('It is valid')
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
|
|
|
@ -3,10 +3,16 @@
|
|||
import 'mocha'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {
|
||||
addVideoCommentThread,
|
||||
addVideoToBlacklist,
|
||||
cleanupTests,
|
||||
createUser,
|
||||
follow,
|
||||
generateUserAccessToken,
|
||||
getAccount,
|
||||
getCustomConfig,
|
||||
getVideoCommentThreads,
|
||||
getVideoIdFromUUID,
|
||||
immutableAssign,
|
||||
MockInstancesIndex,
|
||||
registerUser,
|
||||
|
@ -23,7 +29,9 @@ import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
|
|||
import {
|
||||
checkAutoInstanceFollowing,
|
||||
CheckerBaseParams,
|
||||
checkNewAccountAbuseForModerators,
|
||||
checkNewBlacklistOnMyVideo,
|
||||
checkNewCommentAbuseForModerators,
|
||||
checkNewInstanceFollower,
|
||||
checkNewVideoAbuseForModerators,
|
||||
checkNewVideoFromSubscription,
|
||||
|
@ -91,11 +99,74 @@ describe('Test moderation notifications', function () {
|
|||
|
||||
await waitJobs(servers)
|
||||
|
||||
await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId: video.id, reason: 'super reason' })
|
||||
const videoId = await getVideoIdFromUUID(servers[1].url, video.uuid)
|
||||
await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence')
|
||||
})
|
||||
|
||||
it('Should send a notification to moderators on local comment abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const name = 'video for abuse ' + uuidv4()
|
||||
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
||||
const video = resVideo.body.video
|
||||
const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4())
|
||||
const comment = resComment.body.comment
|
||||
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, commentId: comment.id, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewCommentAbuseForModerators(baseParams, video.uuid, name, 'presence')
|
||||
})
|
||||
|
||||
it('Should send a notification to moderators on remote comment abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const name = 'video for abuse ' + uuidv4()
|
||||
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
||||
const video = resVideo.body.video
|
||||
await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4())
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
const resComments = await getVideoCommentThreads(servers[1].url, video.uuid, 0, 5)
|
||||
const commentId = resComments.body.data[0].id
|
||||
await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, commentId, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewCommentAbuseForModerators(baseParams, video.uuid, name, 'presence')
|
||||
})
|
||||
|
||||
it('Should send a notification to moderators on local account abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const username = 'user' + new Date().getTime()
|
||||
const resUser = await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username, password: 'donald' })
|
||||
const accountId = resUser.body.user.account.id
|
||||
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, accountId, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewAccountAbuseForModerators(baseParams, username, 'presence')
|
||||
})
|
||||
|
||||
it('Should send a notification to moderators on remote account abuse', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const username = 'user' + new Date().getTime()
|
||||
const tmpToken = await generateUserAccessToken(servers[0], username)
|
||||
await uploadVideo(servers[0].url, tmpToken, { name: 'super video' })
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
const resAccount = await getAccount(servers[1].url, username + '@' + servers[0].host)
|
||||
await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, accountId: resAccount.body.id, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewAccountAbuseForModerators(baseParams, username, 'presence')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Video blacklist on my video', function () {
|
||||
|
|
|
@ -180,7 +180,7 @@ describe('Test emails', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('When creating a video abuse', function () {
|
||||
describe('When creating an abuse', function () {
|
||||
it('Should send the notification email', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ export module UserNotificationIncludes {
|
|||
Pick<VideoCommentAbuseModel, 'id'> &
|
||||
PickWith<VideoCommentAbuseModel, 'VideoComment',
|
||||
Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> &
|
||||
PickWith<VideoCommentModel, 'Video', Pick<VideoModel, 'uuid'>>>
|
||||
PickWith<VideoCommentModel, 'Video', Pick<VideoModel, 'id' | 'name' | 'uuid'>>>
|
||||
|
||||
export type AbuseInclude =
|
||||
Pick<AbuseModel, 'id'> &
|
||||
|
|
1
server/typings/express/index.d.ts
vendored
1
server/typings/express/index.d.ts
vendored
|
@ -91,7 +91,6 @@ declare module 'express' {
|
|||
|
||||
accountVideoRate?: MAccountVideoRateAccountVideo
|
||||
|
||||
videoComment?: MComment
|
||||
videoCommentFull?: MCommentOwnerVideoReply
|
||||
videoCommentThread?: MComment
|
||||
|
||||
|
|
|
@ -57,10 +57,15 @@ function reportAbuse (options: {
|
|||
function getAbusesList (options: {
|
||||
url: string
|
||||
token: string
|
||||
|
||||
start?: number
|
||||
count?: number
|
||||
sort?: string
|
||||
|
||||
id?: number
|
||||
predefinedReason?: AbusePredefinedReasonsString
|
||||
search?: string
|
||||
filter?: AbuseFilter,
|
||||
filter?: AbuseFilter
|
||||
state?: AbuseState
|
||||
videoIs?: AbuseVideoIs
|
||||
searchReporter?: string
|
||||
|
@ -71,6 +76,9 @@ function getAbusesList (options: {
|
|||
const {
|
||||
url,
|
||||
token,
|
||||
start,
|
||||
count,
|
||||
sort,
|
||||
id,
|
||||
predefinedReason,
|
||||
search,
|
||||
|
@ -85,13 +93,15 @@ function getAbusesList (options: {
|
|||
const path = '/api/v1/abuses'
|
||||
|
||||
const query = {
|
||||
sort: 'createdAt',
|
||||
id,
|
||||
predefinedReason,
|
||||
search,
|
||||
state,
|
||||
filter,
|
||||
videoIs,
|
||||
start,
|
||||
count,
|
||||
sort: sort || 'createdAt',
|
||||
searchReporter,
|
||||
searchReportee,
|
||||
searchVideo,
|
||||
|
|
|
@ -37,8 +37,8 @@ interface ServerInfo {
|
|||
video?: {
|
||||
id: number
|
||||
uuid: string
|
||||
name: string
|
||||
account: {
|
||||
name?: string
|
||||
account?: {
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,13 +139,17 @@ async function checkNotification (
|
|||
}
|
||||
|
||||
function checkVideo (video: any, videoName?: string, videoUUID?: string) {
|
||||
if (videoName) {
|
||||
expect(video.name).to.be.a('string')
|
||||
expect(video.name).to.not.be.empty
|
||||
if (videoName) expect(video.name).to.equal(videoName)
|
||||
expect(video.name).to.equal(videoName)
|
||||
}
|
||||
|
||||
if (videoUUID) {
|
||||
expect(video.uuid).to.be.a('string')
|
||||
expect(video.uuid).to.not.be.empty
|
||||
if (videoUUID) expect(video.uuid).to.equal(videoUUID)
|
||||
expect(video.uuid).to.equal(videoUUID)
|
||||
}
|
||||
|
||||
expect(video.id).to.be.a('number')
|
||||
}
|
||||
|
@ -436,7 +440,7 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string,
|
|||
}
|
||||
|
||||
async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
|
||||
const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS
|
||||
const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
|
||||
|
||||
function notificationChecker (notification: UserNotification, type: CheckerType) {
|
||||
if (type === 'presence') {
|
||||
|
@ -460,6 +464,56 @@ async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUU
|
|||
await checkNotification(base, notificationChecker, emailNotificationFinder, type)
|
||||
}
|
||||
|
||||
async function checkNewCommentAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
|
||||
const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
|
||||
|
||||
function notificationChecker (notification: UserNotification, type: CheckerType) {
|
||||
if (type === 'presence') {
|
||||
expect(notification).to.not.be.undefined
|
||||
expect(notification.type).to.equal(notificationType)
|
||||
|
||||
expect(notification.abuse.id).to.be.a('number')
|
||||
checkVideo(notification.abuse.comment.video, videoName, videoUUID)
|
||||
} else {
|
||||
expect(notification).to.satisfy((n: UserNotification) => {
|
||||
return n === undefined || n.abuse === undefined || n.abuse.comment.video.uuid !== videoUUID
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function emailNotificationFinder (email: object) {
|
||||
const text = email['text']
|
||||
return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
|
||||
}
|
||||
|
||||
await checkNotification(base, notificationChecker, emailNotificationFinder, type)
|
||||
}
|
||||
|
||||
async function checkNewAccountAbuseForModerators (base: CheckerBaseParams, displayName: string, type: CheckerType) {
|
||||
const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
|
||||
|
||||
function notificationChecker (notification: UserNotification, type: CheckerType) {
|
||||
if (type === 'presence') {
|
||||
expect(notification).to.not.be.undefined
|
||||
expect(notification.type).to.equal(notificationType)
|
||||
|
||||
expect(notification.abuse.id).to.be.a('number')
|
||||
expect(notification.abuse.account.displayName).to.equal(displayName)
|
||||
} else {
|
||||
expect(notification).to.satisfy((n: UserNotification) => {
|
||||
return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function emailNotificationFinder (email: object) {
|
||||
const text = email['text']
|
||||
return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1
|
||||
}
|
||||
|
||||
await checkNotification(base, notificationChecker, emailNotificationFinder, type)
|
||||
}
|
||||
|
||||
async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
|
||||
const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
|
||||
|
||||
|
@ -541,6 +595,9 @@ async function prepareNotificationsTest (serversCount = 3) {
|
|||
smtp: {
|
||||
hostname: 'localhost',
|
||||
port
|
||||
},
|
||||
signup: {
|
||||
limit: 20
|
||||
}
|
||||
}
|
||||
const servers = await flushAndRunMultipleServers(serversCount, overrideConfig)
|
||||
|
@ -623,5 +680,7 @@ export {
|
|||
markAsReadNotifications,
|
||||
getLastNotification,
|
||||
checkNewInstanceFollower,
|
||||
prepareNotificationsTest
|
||||
prepareNotificationsTest,
|
||||
checkNewCommentAbuseForModerators,
|
||||
checkNewAccountAbuseForModerators
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { FollowState } from '../actors'
|
|||
export enum UserNotificationType {
|
||||
NEW_VIDEO_FROM_SUBSCRIPTION = 1,
|
||||
NEW_COMMENT_ON_MY_VIDEO = 2,
|
||||
NEW_VIDEO_ABUSE_FOR_MODERATORS = 3,
|
||||
NEW_ABUSE_FOR_MODERATORS = 3,
|
||||
|
||||
BLACKLIST_ON_MY_VIDEO = 4,
|
||||
UNBLACKLIST_ON_MY_VIDEO = 5,
|
||||
|
|
|
@ -106,9 +106,9 @@ tags:
|
|||
Managing plugins installed from a local path or from NPM, or search for new ones.
|
||||
externalDocs:
|
||||
url: https://docs.joinpeertube.org/#/api-plugins
|
||||
- name: Video Abuses
|
||||
- name: Abuses
|
||||
description: |
|
||||
Video abuses deal with reports of local or remote videos alike.
|
||||
Abuses deal with reports of local or remote videos/comments/accounts alike.
|
||||
- name: Video
|
||||
description: |
|
||||
Operations dealing with listing, uploading, fetching or modifying videos.
|
||||
|
@ -166,7 +166,7 @@ x-tagGroups:
|
|||
- Search
|
||||
- name: Moderation
|
||||
tags:
|
||||
- Video Abuses
|
||||
- Abuses
|
||||
- Video Blocks
|
||||
- Account Blocks
|
||||
- Server Blocks
|
||||
|
@ -1474,13 +1474,13 @@ paths:
|
|||
/videos/abuse:
|
||||
get:
|
||||
deprecated: true
|
||||
summary: List video abuses
|
||||
summary: List abuses
|
||||
security:
|
||||
- OAuth2:
|
||||
- admin
|
||||
- moderator
|
||||
tags:
|
||||
- Video Abuses
|
||||
- Abuses
|
||||
parameters:
|
||||
- name: id
|
||||
in: query
|
||||
|
@ -1508,7 +1508,7 @@ paths:
|
|||
type: string
|
||||
- name: state
|
||||
in: query
|
||||
description: 'The video playlist privacy (Pending = `1`, Rejected = `2`, Accepted = `3`)'
|
||||
description: 'The abuse state (Pending = `1`, Rejected = `2`, Accepted = `3`)'
|
||||
schema:
|
||||
type: integer
|
||||
enum:
|
||||
|
@ -1554,7 +1554,7 @@ paths:
|
|||
security:
|
||||
- OAuth2: []
|
||||
tags:
|
||||
- Video Abuses
|
||||
- Abuses
|
||||
- Videos
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/idOrUUID'
|
||||
|
@ -1607,7 +1607,7 @@ paths:
|
|||
- admin
|
||||
- moderator
|
||||
tags:
|
||||
- Video Abuses
|
||||
- Abuses
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/idOrUUID'
|
||||
- $ref: '#/components/parameters/abuseId'
|
||||
|
@ -1626,11 +1626,11 @@ paths:
|
|||
'204':
|
||||
description: successful operation
|
||||
'404':
|
||||
description: video abuse not found
|
||||
description: abuse not found
|
||||
delete:
|
||||
deprecated: true
|
||||
tags:
|
||||
- Video Abuses
|
||||
- Abuses
|
||||
summary: Delete an abuse
|
||||
security:
|
||||
- OAuth2:
|
||||
|
@ -3320,7 +3320,7 @@ components:
|
|||
name: abuseId
|
||||
in: path
|
||||
required: true
|
||||
description: Video abuse id
|
||||
description: Abuse id
|
||||
schema:
|
||||
type: integer
|
||||
captionLanguage:
|
||||
|
@ -5098,7 +5098,7 @@ components:
|
|||
|
||||
- `2` NEW_COMMENT_ON_MY_VIDEO
|
||||
|
||||
- `3` NEW_VIDEO_ABUSE_FOR_MODERATORS
|
||||
- `3` NEW_ABUSE_FOR_MODERATORS
|
||||
|
||||
- `4` BLACKLIST_ON_MY_VIDEO
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user