Skip to content

Commit

Permalink
move API and AP object from number to string enum
Browse files Browse the repository at this point in the history
  • Loading branch information
rigelk committed Jun 20, 2020
1 parent 5ff6adf commit e1706e8
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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')
}
}

Expand Down
13 changes: 1 addition & 12 deletions client/src/app/shared/video-abuse/video-abuse.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions client/src/app/shared/video/modals/video-report.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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({
Expand Down
8 changes: 3 additions & 5 deletions server/controllers/api/videos/abuse.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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()
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
19 changes: 14 additions & 5 deletions server/helpers/custom-validators/video-abuses.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
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

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) {
Expand All @@ -35,7 +42,9 @@ function isAbuseVideoIsValid (value: VideoAbuseVideoIs) {

export {
isVideoAbuseReasonValid,
isVideoAbusePredefinedReasonValid,
isVideoAbusePredefinedReasonsValid,
isVideoAbuseTimestampValid,
isVideoAbuseModerationCommentValid,
isVideoAbuseStateValid,
isAbuseVideoIsValid
Expand Down
9 changes: 7 additions & 2 deletions server/lib/activitypub/process/process-flag.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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
Expand Down
15 changes: 10 additions & 5 deletions server/middlewares/validators/videos/video-abuses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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) => {
Expand Down Expand Up @@ -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'),
Expand Down
31 changes: 24 additions & 7 deletions server/models/video/video-abuse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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'
Expand Down Expand Up @@ -270,7 +277,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
@AllowNull(true)
@Default(null)
@Column(DataType.ARRAY(DataType.INTEGER))
predefinedReasons: number[]
predefinedReasons: VideoAbusePredefinedReasons[]

@AllowNull(true)
@Default(null)
Expand Down Expand Up @@ -335,7 +342,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
user?: MUserAccountId

id?: number
predefinedReasonId?: number
predefinedReason?: VideoAbusePredefinedReasonsString
state?: VideoAbuseState
videoIs?: VideoAbuseVideoIs

Expand All @@ -354,7 +361,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
serverAccountId,
state,
videoIs,
predefinedReasonId,
predefinedReason,
searchReportee,
searchVideo,
searchVideoChannel,
Expand All @@ -363,6 +370,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
} = parameters

const userAccountId = user ? user.Account.id : undefined
const predefinedReasonId = predefinedReason ? VideoAbusePredefinedReasonsMap[predefinedReason] : undefined

const query = {
offset: start,
Expand Down Expand Up @@ -397,6 +405,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
}

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
Expand All @@ -411,7 +420,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
return {
id: this.id,
reason: this.reason,
predefinedReasons: this.predefinedReasons,
predefinedReasons,
reporterAccount: this.Account.toFormattedJSON(),
state: {
id: this.state,
Expand Down Expand Up @@ -440,16 +449,18 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
}

toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject {
const predefinedReasons = VideoAbuseModel.getPredefinedReasonsStrings(this.predefinedReasons || [])

const startAt = this.startAt
const endAt = this.endAt

return {
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
Expand All @@ -459,4 +470,10 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
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)
}
}
5 changes: 3 additions & 2 deletions server/tests/api/videos/video-abuse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -272,7 +272,8 @@ describe('Test video abuses', function () {
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)
const predefinedReasons4: VideoAbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ]
await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4, predefinedReasons4, 1, 5)

const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })

Expand Down
15 changes: 12 additions & 3 deletions shared/extra-utils/videos/video-abuses.ts
Original file line number Diff line number Diff line change
@@ -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)
}

Expand Down
Loading

0 comments on commit e1706e8

Please sign in to comment.