From c080143d3e35c48b7fe1c91e4dc949a37e804648 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Sat, 20 Jun 2020 19:19:39 +0200 Subject: [PATCH] move API and AP object from number to string enum --- .../video-abuse-details.component.html | 2 +- .../video-abuse-details.component.ts | 20 ++++----- .../shared/video-abuse/video-abuse.service.ts | 13 +----- .../video/modals/video-report.component.ts | 10 ++--- client/src/sass/include/_mixins.scss | 11 ++++- server/controllers/api/videos/abuse.ts | 8 ++-- .../helpers/custom-validators/video-abuses.ts | 19 ++++++--- .../0515-video-abuse-reason-timestamps.ts | 5 +++ .../lib/activitypub/process/process-flag.ts | 9 +++- .../validators/videos/video-abuses.ts | 15 ++++--- server/models/video/video-abuse.ts | 31 ++++++++++---- server/tests/api/videos/video-abuse.ts | 41 +++++++++++++++---- shared/extra-utils/videos/video-abuses.ts | 15 +++++-- .../activitypub/objects/common-objects.ts | 4 +- .../videos/abuse/video-abuse-create.model.ts | 4 +- .../videos/abuse/video-abuse-reason.model.ts | 8 ++-- .../models/videos/abuse/video-abuse.model.ts | 3 +- 17 files changed, 147 insertions(+), 71 deletions(-) diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html index f8ef78c815d2..5512bb1dea80 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html @@ -60,7 +60,7 @@
- +
{{ reason.label }}
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts index b79580868a8e..13485124f210 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core' import { Actor } from '@app/shared/actor/actor.model' -import { VideoAbusePredefinedReasons } from '../../../../../../shared/models/videos/abuse/video-abuse-reason.model' +import { VideoAbusePredefinedReasonsString } from '../../../../../../shared/models/videos/abuse/video-abuse-reason.model' import { ProcessedVideoAbuse } from './video-abuse-list.component' import { I18n } from '@ngx-translate/i18n-polyfill' import { durationToString } from '@app/shared/misc/utils' @@ -13,20 +13,20 @@ import { durationToString } from '@app/shared/misc/utils' export class VideoAbuseDetailsComponent { @Input() videoAbuse: ProcessedVideoAbuse - private predefinedReasonsTranslations: { [key: number]: string } + private predefinedReasonsTranslations: { [key in VideoAbusePredefinedReasonsString]: string } constructor ( private i18n: I18n ) { this.predefinedReasonsTranslations = { - [VideoAbusePredefinedReasons.VIOLENT_OR_REPULSIVE]: this.i18n('Violent or Repulsive'), - [VideoAbusePredefinedReasons.HATEFUL_OR_ABUSIVE]: this.i18n('Hateful or Abusive'), - [VideoAbusePredefinedReasons.SPAM_OR_MISLEADING]: this.i18n('Spam or Misleading'), - [VideoAbusePredefinedReasons.PRIVACY]: this.i18n('Privacy'), - [VideoAbusePredefinedReasons.RIGHTS]: this.i18n('Rights'), - [VideoAbusePredefinedReasons.SERVER_RULES]: this.i18n('Server rules'), - [VideoAbusePredefinedReasons.THUMBNAILS]: this.i18n('Thumbnails'), - [VideoAbusePredefinedReasons.CAPTIONS]: this.i18n('Captions') + violentOrRepulsive: this.i18n('Violent or Repulsive'), + hatefulOrAbusive: this.i18n('Hateful or Abusive'), + spamOrMisleading: this.i18n('Spam or Misleading'), + privacy: this.i18n('Privacy'), + rights: this.i18n('Rights'), + serverRules: this.i18n('Server rules'), + thumbnails: this.i18n('Thumbnails'), + captions: this.i18n('Captions') } } diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts index 0b102a88d5fa..43f4674b14b7 100644 --- a/client/src/app/shared/video-abuse/video-abuse.service.ts +++ b/client/src/app/shared/video-abuse/video-abuse.service.ts @@ -53,18 +53,7 @@ export class VideoAbuseService { }, searchReporter: { prefix: 'reporter:' }, searchReportee: { prefix: 'reportee:' }, - predefinedReasonId: { - prefix: 'tag:', - handler: v => { - try { - const id = parseInt(v, 10) - return id - } catch (e) { - console.error('Cannot parse predefinedReasonId in search.', e) - return undefined - } - } - } + predefinedReason: { prefix: 'tag:' } }) params = this.restService.addObjectParams(params, filters) diff --git a/client/src/app/shared/video/modals/video-report.component.ts b/client/src/app/shared/video/modals/video-report.component.ts index 39085a069a7a..0a01a4a179a5 100644 --- a/client/src/app/shared/video/modals/video-report.component.ts +++ b/client/src/app/shared/video/modals/video-report.component.ts @@ -10,8 +10,8 @@ import { VideoAbuseService } from '@app/shared/video-abuse' import { Video } from '@app/shared/video/video.model' import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' import { DomSanitizer, SafeHtml } from '@angular/platform-browser' -import { VideoAbusePredefinedReasonsIn } from '@shared/models/videos/abuse/video-abuse-reason.model' -import { mapValues, pickBy, keys } from 'lodash-es' +import { VideoAbusePredefinedReasonsString, VideoAbusePredefinedReasonsMap } from '@shared/models/videos/abuse/video-abuse-reason.model' +import { mapValues, pickBy } from 'lodash-es' @Component({ selector: 'my-video-report', @@ -24,7 +24,7 @@ export class VideoReportComponent extends FormReactive implements OnInit { @ViewChild('modal', { static: true }) modal: NgbModal error: string = null - predefinedReasons: { id: VideoAbusePredefinedReasonsIn, label: string, description?: string, help?: string }[] = [] + predefinedReasons: { id: VideoAbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = [] embedHtml: SafeHtml private openedModal: NgbModalRef @@ -72,7 +72,7 @@ export class VideoReportComponent extends FormReactive implements OnInit { ngOnInit () { this.buildForm({ reason: this.videoAbuseValidatorsService.VIDEO_ABUSE_REASON, - predefinedReasons: mapValues(VideoAbusePredefinedReasonsIn, r => null), + predefinedReasons: mapValues(VideoAbusePredefinedReasonsMap, r => null), timestamp: { hasStart: null, startAt: null, @@ -138,7 +138,7 @@ export class VideoReportComponent extends FormReactive implements OnInit { report () { const reason = this.form.get('reason').value - const predefinedReasons = keys(pickBy(this.form.get('predefinedReasons').value)) as VideoAbusePredefinedReasonsIn[] + const predefinedReasons = Object.keys(pickBy(this.form.get('predefinedReasons').value)) as VideoAbusePredefinedReasonsString[] const { hasStart, startAt, hasEnd, endAt } = this.form.get('timestamp').value this.videoAbuseService.reportVideo({ diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index eb80ea0e32b6..6a1deac76772 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss @@ -804,10 +804,12 @@ } @mixin chip { + --chip-radius: 5rem; + --chip-padding: .2rem .4rem; $avatar-height: 1.2rem; align-items: center; - border-radius: 5rem; + border-radius: var(--chip-radius); display: inline-flex; font-size: 90%; color: pvar(--mainForegroundColor); @@ -816,12 +818,17 @@ margin: .1rem; max-width: 320px; overflow: hidden; - padding: .2rem .4rem; + padding: var(--chip-padding); text-decoration: none; text-overflow: ellipsis; vertical-align: middle; white-space: nowrap; + &.rectangular { + --chip-radius: .2rem; + --chip-padding: .2rem .3rem; + } + .avatar { margin-left: -.4rem; margin-right: .2rem; diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index ff34da9d6be7..90f0f16243b6 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts @@ -1,5 +1,5 @@ import * as express from 'express' -import { UserRight, VideoAbuseCreate, VideoAbuseState, VideoAbuse } from '../../../../shared' +import { UserRight, VideoAbuseCreate, VideoAbuseState, VideoAbuse, VideoAbusePredefinedReasonsMap } from '../../../../shared' import { logger } from '../../../helpers/logger' import { getFormattedObjects } from '../../../helpers/utils' import { sequelizeTypescript } from '../../../initializers/database' @@ -25,8 +25,6 @@ import { sendVideoAbuse } from '../../../lib/activitypub/send/send-flag' import { MVideoAbuseAccountVideo } from '../../../types/models/video' import { getServerActor } from '@server/models/application/application' import { MAccountDefault } from '@server/types/models' -import { keys, pickBy } from 'lodash' -import { VideoAbusePredefinedReasonsIn } from '@shared/models/videos/abuse/video-abuse-reason.model' const auditLogger = auditLoggerFactory('abuse') const abuseVideoRouter = express.Router() @@ -76,7 +74,7 @@ async function listVideoAbuses (req: express.Request, res: express.Response) { count: req.query.count, sort: req.query.sort, id: req.query.id, - predefinedReasonId: req.query.predefinedReasonId, + predefinedReason: req.query.predefinedReason, search: req.query.search, state: req.query.state, videoIs: req.query.videoIs, @@ -126,7 +124,7 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) { const videoAbuseInstance = await sequelizeTypescript.transaction(async t => { reporterAccount = await AccountModel.load(res.locals.oauth.token.User.Account.id, t) - const predefinedReasons = body.predefinedReasons.map(r => VideoAbusePredefinedReasonsIn[r]) + const predefinedReasons = body.predefinedReasons?.map(r => VideoAbusePredefinedReasonsMap[r]) const abuseToCreate = { reporterAccountId: reporterAccount.id, diff --git a/server/helpers/custom-validators/video-abuses.ts b/server/helpers/custom-validators/video-abuses.ts index d3a83e040ad7..061353b9ebd6 100644 --- a/server/helpers/custom-validators/video-abuses.ts +++ b/server/helpers/custom-validators/video-abuses.ts @@ -1,10 +1,9 @@ import validator from 'validator' -import { keys } from 'lodash' import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' -import { exists } from './misc' +import { exists, isArray } from './misc' import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' -import { VideoAbusePredefinedReasonsIn } from '@shared/models/videos/abuse/video-abuse-reason.model' +import { VideoAbusePredefinedReasonsString, VideoAbusePredefinedReasonsMap } from '@shared/models/videos/abuse/video-abuse-reason.model' const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES @@ -12,8 +11,16 @@ function isVideoAbuseReasonValid (value: string) { return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON) } -function isVideoAbusePredefinedReasonsValid (value: VideoAbusePredefinedReasonsIn[]) { - return exists(value) && value.every(element => keys(VideoAbusePredefinedReasonsIn).includes(element)) +function isVideoAbusePredefinedReasonValid (value: VideoAbusePredefinedReasonsString) { + return exists(value) && value in VideoAbusePredefinedReasonsMap +} + +function isVideoAbusePredefinedReasonsValid (value: VideoAbusePredefinedReasonsString[]) { + return exists(value) && isArray(value) && value.every(v => v in VideoAbusePredefinedReasonsMap) +} + +function isVideoAbuseTimestampValid (value: number) { + return value === null || (exists(value) && validator.isInt('' + value, { min: 0 })) } function isVideoAbuseModerationCommentValid (value: string) { @@ -35,7 +42,9 @@ function isAbuseVideoIsValid (value: VideoAbuseVideoIs) { export { isVideoAbuseReasonValid, + isVideoAbusePredefinedReasonValid, isVideoAbusePredefinedReasonsValid, + isVideoAbuseTimestampValid, isVideoAbuseModerationCommentValid, isVideoAbuseStateValid, isAbuseVideoIsValid diff --git a/server/initializers/migrations/0515-video-abuse-reason-timestamps.ts b/server/initializers/migrations/0515-video-abuse-reason-timestamps.ts index 964a5f588b74..c583356171dc 100644 --- a/server/initializers/migrations/0515-video-abuse-reason-timestamps.ts +++ b/server/initializers/migrations/0515-video-abuse-reason-timestamps.ts @@ -5,6 +5,11 @@ async function up (utils: { queryInterface: Sequelize.QueryInterface sequelize: Sequelize.Sequelize }): Promise { + await utils.queryInterface.addColumn('videoAbuse', 'predefinedReasons', { + type: Sequelize.ARRAY(Sequelize.INTEGER), + allowNull: true + }) + await utils.queryInterface.addColumn('videoAbuse', 'startAt', { type: Sequelize.INTEGER, allowNull: true diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index 7de75d7962a4..42a86c120dbd 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts @@ -1,4 +1,9 @@ -import { ActivityCreate, ActivityFlag, VideoAbuseState } from '../../../../shared' +import { + ActivityCreate, + ActivityFlag, + VideoAbuseState, + VideoAbusePredefinedReasonsMap +} from '../../../../shared' import { VideoAbuseObject } from '../../../../shared/models/activitypub/objects' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' @@ -39,7 +44,7 @@ async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: object }) const reporterAccount = await sequelizeTypescript.transaction(async t => AccountModel.load(account.id, t)) const tags = Array.isArray(flag.tag) ? flag.tag : [] - const predefinedReasons = tags.map(tag => parseInt(tag.name, 10)) + const predefinedReasons = tags.map(tag => VideoAbusePredefinedReasonsMap[tag.name]) .filter(v => !isNaN(v)) const startAt = flag.startAt const endAt = flag.endAt diff --git a/server/middlewares/validators/videos/video-abuses.ts b/server/middlewares/validators/videos/video-abuses.ts index d0b2f7f0336d..33bd4a912398 100644 --- a/server/middlewares/validators/videos/video-abuses.ts +++ b/server/middlewares/validators/videos/video-abuses.ts @@ -6,7 +6,9 @@ import { isVideoAbuseModerationCommentValid, isVideoAbuseReasonValid, isVideoAbuseStateValid, - isVideoAbusePredefinedReasonsValid + isVideoAbusePredefinedReasonsValid, + isVideoAbusePredefinedReasonValid, + isVideoAbuseTimestampValid } from '../../../helpers/custom-validators/video-abuses' import { logger } from '../../../helpers/logger' import { doesVideoAbuseExist, doesVideoExist } from '../../../helpers/middlewares' @@ -27,11 +29,13 @@ const videoAbuseReportValidator = [ .withMessage('Should have a valid list of predefined reasons'), body('startAt') .optional() - .custom(toIntOrNull) + .customSanitizer(toIntOrNull) + .custom(isVideoAbuseTimestampValid) .withMessage('Should have valid starting time value'), body('endAt') .optional() - .custom(toIntOrNull) + .customSanitizer(toIntOrNull) + .custom(isVideoAbuseTimestampValid) .withMessage('Should have valid ending time value'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { @@ -82,9 +86,10 @@ const videoAbuseListValidator = [ query('id') .optional() .custom(isIdValid).withMessage('Should have a valid id'), - query('predefinedReasonId') + query('predefinedReason') .optional() - .custom(isIdValid).withMessage('Should have a valid predefinedReasonId'), + .custom(isVideoAbusePredefinedReasonValid) + .withMessage('Should have a valid predefinedReason'), query('search') .optional() .custom(exists).withMessage('Should have a valid search'), diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index 7579b575a3b0..9c6e03175922 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts @@ -15,7 +15,13 @@ import { UpdatedAt } from 'sequelize-typescript' import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' -import { VideoAbuseState, VideoDetails } from '../../../shared' +import { + VideoAbuseState, + VideoDetails, + VideoAbusePredefinedReasons, + VideoAbusePredefinedReasonsString, + VideoAbusePredefinedReasonsMap +} from '../../../shared' import { VideoAbuseObject } from '../../../shared/models/activitypub/objects' import { VideoAbuse } from '../../../shared/models/videos' import { @@ -31,6 +37,7 @@ import { ThumbnailModel } from './thumbnail' import { VideoModel } from './video' import { VideoBlacklistModel } from './video-blacklist' import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' +import { invert } from 'lodash' export enum ScopeNames { FOR_API = 'FOR_API' @@ -270,7 +277,7 @@ export class VideoAbuseModel extends Model { @AllowNull(true) @Default(null) @Column(DataType.ARRAY(DataType.INTEGER)) - predefinedReasons: number[] + predefinedReasons: VideoAbusePredefinedReasons[] @AllowNull(true) @Default(null) @@ -335,7 +342,7 @@ export class VideoAbuseModel extends Model { user?: MUserAccountId id?: number - predefinedReasonId?: number + predefinedReason?: VideoAbusePredefinedReasonsString state?: VideoAbuseState videoIs?: VideoAbuseVideoIs @@ -354,7 +361,7 @@ export class VideoAbuseModel extends Model { serverAccountId, state, videoIs, - predefinedReasonId, + predefinedReason, searchReportee, searchVideo, searchVideoChannel, @@ -363,6 +370,7 @@ export class VideoAbuseModel extends Model { } = parameters const userAccountId = user ? user.Account.id : undefined + const predefinedReasonId = predefinedReason ? VideoAbusePredefinedReasonsMap[predefinedReason] : undefined const query = { offset: start, @@ -397,6 +405,7 @@ export class VideoAbuseModel extends Model { } toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse { + const predefinedReasons = VideoAbuseModel.getPredefinedReasonsStrings(this.predefinedReasons || []) const countReportsForVideo = this.get('countReportsForVideo') as number const nthReportForVideo = this.get('nthReportForVideo') as number const countReportsForReporterVideo = this.get('countReportsForReporter__video') as number @@ -411,7 +420,7 @@ export class VideoAbuseModel extends Model { return { id: this.id, reason: this.reason, - predefinedReasons: this.predefinedReasons, + predefinedReasons, reporterAccount: this.Account.toFormattedJSON(), state: { id: this.state, @@ -440,6 +449,8 @@ export class VideoAbuseModel extends Model { } toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject { + const predefinedReasons = VideoAbuseModel.getPredefinedReasonsStrings(this.predefinedReasons || []) + const startAt = this.startAt const endAt = this.endAt @@ -447,9 +458,9 @@ export class VideoAbuseModel extends Model { type: 'Flag' as 'Flag', content: this.reason, object: this.Video.url, - tag: this.predefinedReasons.map(r => ({ + tag: predefinedReasons.map(r => ({ type: 'Hashtag' as 'Hashtag', - name: r.toString() + name: r })), startAt, endAt @@ -459,4 +470,10 @@ export class VideoAbuseModel extends Model { private static getStateLabel (id: number) { return VIDEO_ABUSE_STATES[id] || 'Unknown' } + + private static getPredefinedReasonsStrings (predefinedReasons: VideoAbusePredefinedReasons[]): VideoAbusePredefinedReasonsString[] { + return predefinedReasons + .filter(r => r in VideoAbusePredefinedReasons) + .map(r => invert(VideoAbusePredefinedReasonsMap)[r] as VideoAbusePredefinedReasonsString) + } } diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts index a96be97f6362..f29075ef3dfa 100644 --- a/server/tests/api/videos/video-abuse.ts +++ b/server/tests/api/videos/video-abuse.ts @@ -2,7 +2,7 @@ import * as chai from 'chai' import 'mocha' -import { VideoAbuse, VideoAbuseState } from '../../../../shared/models/videos' +import { VideoAbuse, VideoAbuseState, VideoAbusePredefinedReasonsString } from '../../../../shared/models/videos' import { cleanupTests, deleteVideoAbuse, @@ -291,6 +291,33 @@ describe('Test video abuses', function () { } }) + it('Should list predefined reasons as well as timestamps for the reported video', async function () { + this.timeout(10000) + + const reason5 = 'my super bad reason 5' + const predefinedReasons5: VideoAbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ] + const createdAbuse = (await reportVideoAbuse( + servers[0].url, + servers[0].accessToken, + servers[0].video.id, + reason5, + predefinedReasons5, + 1, + 5 + )).body as VideoAbuse + + const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) + + for (const abuse of res.body.data as VideoAbuse[]) { + if (abuse.id === createdAbuse.id) { + expect(abuse.reason).to.equals(reason5) + expect(abuse.predefinedReasons).to.equals(predefinedReasons5, "predefined reasons do not match the one reported") + expect(abuse.startAt).to.equal(1, "starting timestamp doesn't match the one reported") + expect(abuse.endAt).to.equal(5, "ending timestamp doesn't match the one reported") + } + } + }) + it('Should delete the video abuse', async function () { this.timeout(10000) @@ -307,7 +334,7 @@ describe('Test video abuses', function () { { const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) - expect(res.body.total).to.equal(5) + expect(res.body.total).to.equal(6) } }) @@ -328,25 +355,25 @@ describe('Test video abuses', function () { expect(await list({ id: 56 })).to.have.lengthOf(0) expect(await list({ id: 1 })).to.have.lengthOf(1) - expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(3) + expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4) expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0) expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1) - expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(3) + expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4) expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0) expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1) - expect(await list({ searchReporter: 'root' })).to.have.lengthOf(4) + expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5) - expect(await list({ searchReportee: 'root' })).to.have.lengthOf(3) + expect(await list({ searchReportee: 'root' })).to.have.lengthOf(4) expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0) expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1) expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0) expect(await list({ state: VideoAbuseState.ACCEPTED })).to.have.lengthOf(0) - expect(await list({ state: VideoAbuseState.PENDING })).to.have.lengthOf(5) + expect(await list({ state: VideoAbuseState.PENDING })).to.have.lengthOf(6) }) after(async function () { diff --git a/shared/extra-utils/videos/video-abuses.ts b/shared/extra-utils/videos/video-abuses.ts index 81582bfc7fd2..88c599d52c93 100644 --- a/shared/extra-utils/videos/video-abuses.ts +++ b/shared/extra-utils/videos/video-abuses.ts @@ -1,17 +1,26 @@ import * as request from 'supertest' import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model' import { makeDeleteRequest, makePutBodyRequest, makeGetRequest } from '../requests/requests' -import { VideoAbuseState } from '@shared/models' +import { VideoAbuseState, VideoAbusePredefinedReasonsString } from '@shared/models' import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' -function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) { +function reportVideoAbuse ( + url: string, + token: string, + videoId: number | string, + reason: string, + predefinedReasons?: VideoAbusePredefinedReasonsString[], + startAt?: number, + endAt?: number, + specialStatus = 200 +) { const path = '/api/v1/videos/' + videoId + '/abuse' return request(url) .post(path) .set('Accept', 'application/json') .set('Authorization', 'Bearer ' + token) - .send({ reason }) + .send({ reason, predefinedReasons, startAt, endAt }) .expect(specialStatus) } diff --git a/shared/models/activitypub/objects/common-objects.ts b/shared/models/activitypub/objects/common-objects.ts index 704979e59400..096d422eab11 100644 --- a/shared/models/activitypub/objects/common-objects.ts +++ b/shared/models/activitypub/objects/common-objects.ts @@ -1,3 +1,5 @@ +import { VideoAbusePredefinedReasonsString } from '@shared/models/videos' + export interface ActivityIdentifierObject { identifier: string name: string @@ -83,7 +85,7 @@ export interface ActivityMentionObject { export interface ActivityFlagReasonObject { type: 'Hashtag' - name: string + name: VideoAbusePredefinedReasonsString } export type ActivityTagObject = diff --git a/shared/models/videos/abuse/video-abuse-create.model.ts b/shared/models/videos/abuse/video-abuse-create.model.ts index 54f3637b5851..c93cb8b2c42e 100644 --- a/shared/models/videos/abuse/video-abuse-create.model.ts +++ b/shared/models/videos/abuse/video-abuse-create.model.ts @@ -1,8 +1,8 @@ -import { VideoAbusePredefinedReasonsIn } from './video-abuse-reason.model' +import { VideoAbusePredefinedReasonsString } from './video-abuse-reason.model' export interface VideoAbuseCreate { reason: string - predefinedReasons?: VideoAbusePredefinedReasonsIn[] + predefinedReasons?: VideoAbusePredefinedReasonsString[] startAt?: number endAt?: number } diff --git a/shared/models/videos/abuse/video-abuse-reason.model.ts b/shared/models/videos/abuse/video-abuse-reason.model.ts index 8dd473227b19..e514471b9dce 100644 --- a/shared/models/videos/abuse/video-abuse-reason.model.ts +++ b/shared/models/videos/abuse/video-abuse-reason.model.ts @@ -1,5 +1,5 @@ export enum VideoAbusePredefinedReasons { - VIOLENT_OR_REPULSIVE, + VIOLENT_OR_REPULSIVE = 1, HATEFUL_OR_ABUSIVE, SPAM_OR_MISLEADING, PRIVACY, @@ -9,7 +9,7 @@ export enum VideoAbusePredefinedReasons { CAPTIONS } -export type VideoAbusePredefinedReasonsIn = +export type VideoAbusePredefinedReasonsString = 'violentOrRepulsive' | 'hatefulOrAbusive' | 'spamOrMisleading' | @@ -19,7 +19,9 @@ export type VideoAbusePredefinedReasonsIn = 'thumbnails' | 'captions' -export const VideoAbusePredefinedReasonsIn = { +export const VideoAbusePredefinedReasonsMap: { + [key in VideoAbusePredefinedReasonsString]: VideoAbusePredefinedReasons +} = { violentOrRepulsive: VideoAbusePredefinedReasons.VIOLENT_OR_REPULSIVE, hatefulOrAbusive: VideoAbusePredefinedReasons.HATEFUL_OR_ABUSIVE, spamOrMisleading: VideoAbusePredefinedReasons.SPAM_OR_MISLEADING, diff --git a/shared/models/videos/abuse/video-abuse.model.ts b/shared/models/videos/abuse/video-abuse.model.ts index e948859771e2..38605dcac051 100644 --- a/shared/models/videos/abuse/video-abuse.model.ts +++ b/shared/models/videos/abuse/video-abuse.model.ts @@ -2,11 +2,12 @@ import { Account } from '../../actors/index' import { VideoConstant } from '../video-constant.model' import { VideoAbuseState } from './video-abuse-state.model' import { VideoChannel } from '../channel/video-channel.model' +import { VideoAbusePredefinedReasonsString } from './video-abuse-reason.model' export interface VideoAbuse { id: number reason: string - predefinedReasons?: number[] + predefinedReasons?: VideoAbusePredefinedReasonsString[] reporterAccount: Account state: VideoConstant