Add migrations
This commit is contained in:
parent
57f6896f67
commit
4f32032fed
|
@ -45,7 +45,7 @@ export class AdminComponent implements OnInit {
|
|||
children: []
|
||||
}
|
||||
|
||||
if (this.hasVideoAbusesRight()) {
|
||||
if (this.hasAbusesRight()) {
|
||||
moderationItems.children.push({
|
||||
label: this.i18n('Video reports'),
|
||||
routerLink: '/admin/moderation/video-abuses/list',
|
||||
|
@ -76,7 +76,7 @@ export class AdminComponent implements OnInit {
|
|||
|
||||
if (this.hasUsersRight()) this.menuEntries.push({ label: this.i18n('Users'), routerLink: '/admin/users' })
|
||||
if (this.hasServerFollowRight()) this.menuEntries.push(federationItems)
|
||||
if (this.hasVideoAbusesRight() || this.hasVideoBlocklistRight()) this.menuEntries.push(moderationItems)
|
||||
if (this.hasAbusesRight() || this.hasVideoBlocklistRight()) this.menuEntries.push(moderationItems)
|
||||
if (this.hasConfigRight()) this.menuEntries.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' })
|
||||
if (this.hasPluginsRight()) this.menuEntries.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' })
|
||||
if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) this.menuEntries.push({ label: this.i18n('System'), routerLink: '/admin/system' })
|
||||
|
@ -90,7 +90,7 @@ export class AdminComponent implements OnInit {
|
|||
return this.auth.getUser().hasRight(UserRight.MANAGE_SERVER_FOLLOW)
|
||||
}
|
||||
|
||||
hasVideoAbusesRight () {
|
||||
hasAbusesRight () {
|
||||
return this.auth.getUser().hasRight(UserRight.MANAGE_ABUSES)
|
||||
}
|
||||
|
||||
|
|
|
@ -37,14 +37,14 @@
|
|||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' + user?.account.displayName + '"' }">
|
||||
<div class="dashboard-num">{{ user.videoAbusesCount }}</div>
|
||||
<a [routerLink]="[ '/admin/moderation/abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' + user?.account.displayName + '"' }">
|
||||
<div class="dashboard-num">{{ user.abusesCount }}</div>
|
||||
<div class="dashboard-label" i18n>Incriminated in reports</div>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reporter:"' + user?.account.displayName + '" state:accepted' }">
|
||||
<div class="dashboard-num">{{ user.videoAbusesAcceptedCount }} / {{ user.videoAbusesCreatedCount }}</div>
|
||||
<a [routerLink]="[ '/admin/moderation/abuses/list' ]" [queryParams]="{ 'search': 'reporter:"' + user?.account.displayName + '" state:accepted' }">
|
||||
<div class="dashboard-num">{{ user.abusesAcceptedCount }} / {{ user.abusesCreatedCount }}</div>
|
||||
<div class="dashboard-label" i18n>Authored reports accepted</div>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -33,7 +33,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
|
|||
this.labelNotifications = {
|
||||
newVideoFromSubscription: this.i18n('New video from your subscriptions'),
|
||||
newCommentOnMyVideo: this.i18n('New comment on your video'),
|
||||
videoAbuseAsModerator: this.i18n('New video abuse'),
|
||||
abuseAsModerator: this.i18n('New abuse'),
|
||||
videoAutoBlacklistAsModerator: this.i18n('Video blocked automatically waiting review'),
|
||||
blacklistOnMyVideo: this.i18n('One of your video is blocked/unblocked'),
|
||||
myVideoPublished: this.i18n('Video published (after transcoding/scheduled update)'),
|
||||
|
@ -47,7 +47,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
|
|||
this.notificationSettingKeys = Object.keys(this.labelNotifications) as (keyof UserNotificationSetting)[]
|
||||
|
||||
this.rightNotifications = {
|
||||
videoAbuseAsModerator: UserRight.MANAGE_ABUSES,
|
||||
abuseAsModerator: UserRight.MANAGE_ABUSES,
|
||||
videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLACKLIST,
|
||||
newUserRegistration: UserRight.MANAGE_USERS,
|
||||
newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW,
|
||||
|
|
|
@ -51,12 +51,14 @@ export class User implements UserServerModel {
|
|||
videoQuotaDaily: number
|
||||
videoQuotaUsed?: number
|
||||
videoQuotaUsedDaily?: number
|
||||
|
||||
videosCount?: number
|
||||
videoAbusesCount?: number
|
||||
videoAbusesAcceptedCount?: number
|
||||
videoAbusesCreatedCount?: number
|
||||
videoCommentsCount?: number
|
||||
|
||||
abusesCount?: number
|
||||
abusesAcceptedCount?: number
|
||||
abusesCreatedCount?: number
|
||||
|
||||
theme: string
|
||||
|
||||
account: Account
|
||||
|
@ -89,9 +91,9 @@ export class User implements UserServerModel {
|
|||
this.videoQuotaUsed = hash.videoQuotaUsed
|
||||
this.videoQuotaUsedDaily = hash.videoQuotaUsedDaily
|
||||
this.videosCount = hash.videosCount
|
||||
this.videoAbusesCount = hash.videoAbusesCount
|
||||
this.videoAbusesAcceptedCount = hash.videoAbusesAcceptedCount
|
||||
this.videoAbusesCreatedCount = hash.videoAbusesCreatedCount
|
||||
this.abusesCount = hash.abusesCount
|
||||
this.abusesAcceptedCount = hash.abusesAcceptedCount
|
||||
this.abusesCreatedCount = hash.abusesCreatedCount
|
||||
this.videoCommentsCount = hash.videoCommentsCount
|
||||
|
||||
this.nsfwPolicy = hash.nsfwPolicy
|
||||
|
|
|
@ -68,7 +68,7 @@ async function updateNotificationSettings (req: express.Request, res: express.Re
|
|||
const values: UserNotificationSetting = {
|
||||
newVideoFromSubscription: body.newVideoFromSubscription,
|
||||
newCommentOnMyVideo: body.newCommentOnMyVideo,
|
||||
videoAbuseAsModerator: body.videoAbuseAsModerator,
|
||||
abuseAsModerator: body.abuseAsModerator,
|
||||
videoAutoBlacklistAsModerator: body.videoAutoBlacklistAsModerator,
|
||||
blacklistOnMyVideo: body.blacklistOnMyVideo,
|
||||
myVideoPublished: body.myVideoPublished,
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const LAST_MIGRATION_VERSION = 515
|
||||
const LAST_MIGRATION_VERSION = 520
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
import * as Sequelize from 'sequelize'
|
||||
|
||||
async function up (utils: {
|
||||
transaction: Sequelize.Transaction
|
||||
queryInterface: Sequelize.QueryInterface
|
||||
sequelize: Sequelize.Sequelize
|
||||
}): Promise<void> {
|
||||
await utils.queryInterface.renameTable('videoAbuse', 'abuse')
|
||||
|
||||
await utils.sequelize.query(`
|
||||
ALTER TABLE "abuse"
|
||||
ADD COLUMN "flaggedAccountId" INTEGER REFERENCES "account" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
`)
|
||||
|
||||
await utils.sequelize.query(`
|
||||
UPDATE "abuse" SET "videoId" = NULL
|
||||
WHERE "videoId" NOT IN (SELECT "id" FROM "video")
|
||||
`)
|
||||
|
||||
await utils.sequelize.query(`
|
||||
UPDATE "abuse" SET "flaggedAccountId" = "videoChannel"."accountId"
|
||||
FROM "video" INNER JOIN "videoChannel" ON "video"."channelId" = "videoChannel"."id"
|
||||
WHERE "abuse"."videoId" = "video"."id"
|
||||
`)
|
||||
|
||||
await utils.sequelize.query('DROP INDEX IF EXISTS video_abuse_video_id;')
|
||||
await utils.sequelize.query('DROP INDEX IF EXISTS video_abuse_reporter_account_id;')
|
||||
|
||||
await utils.sequelize.query(`
|
||||
CREATE TABLE IF NOT EXISTS "videoAbuse" (
|
||||
"id" serial,
|
||||
"startAt" integer DEFAULT NULL,
|
||||
"endAt" integer DEFAULT NULL,
|
||||
"deletedVideo" jsonb DEFAULT NULL,
|
||||
"abuseId" integer NOT NULL REFERENCES "abuse" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
"videoId" integer REFERENCES "video" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
"createdAt" TIMESTAMP WITH time zone NOT NULL,
|
||||
"updatedAt" timestamp WITH time zone NOT NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
`)
|
||||
|
||||
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")
|
||||
);
|
||||
`)
|
||||
|
||||
await utils.sequelize.query(`
|
||||
INSERT INTO "videoAbuse" ("startAt", "endAt", "deletedVideo", "abuseId", "videoId", "createdAt", "updatedAt")
|
||||
SELECT "abuse"."startAt", "abuse"."endAt", "abuse"."deletedVideo", "abuse"."id", "abuse"."videoId",
|
||||
"abuse"."createdAt", "abuse"."updatedAt"
|
||||
FROM "abuse"
|
||||
`)
|
||||
|
||||
await utils.queryInterface.removeColumn('abuse', 'startAt')
|
||||
await utils.queryInterface.removeColumn('abuse', 'endAt')
|
||||
await utils.queryInterface.removeColumn('abuse', 'deletedVideo')
|
||||
await utils.queryInterface.removeColumn('abuse', 'videoId')
|
||||
|
||||
await utils.sequelize.query('DROP INDEX IF EXISTS user_notification_video_abuse_id')
|
||||
await utils.queryInterface.renameColumn('userNotification', 'videoAbuseId', 'abuseId')
|
||||
await utils.sequelize.query(
|
||||
'ALTER TABLE "userNotification" RENAME CONSTRAINT "userNotification_videoAbuseId_fkey" TO "userNotification_abuseId_fkey"'
|
||||
)
|
||||
|
||||
await utils.sequelize.query(
|
||||
'ALTER TABLE "abuse" RENAME CONSTRAINT "videoAbuse_reporterAccountId_fkey" TO "abuse_reporterAccountId_fkey"'
|
||||
)
|
||||
|
||||
await utils.sequelize.query(
|
||||
'ALTER INDEX IF EXISTS "videoAbuse_pkey" RENAME TO "abuse_pkey"'
|
||||
)
|
||||
|
||||
await utils.queryInterface.renameColumn('userNotificationSetting', 'videoAbuseAsModerator', 'abuseAsModerator')
|
||||
}
|
||||
|
||||
function down (options) {
|
||||
throw new Error('Not implemented.')
|
||||
}
|
||||
|
||||
export {
|
||||
up,
|
||||
down
|
||||
}
|
|
@ -320,7 +320,7 @@ class Emailer {
|
|||
const commentUrl = WEBSERVER.URL + comment.Video.getWatchStaticPath() + ';threadId=' + comment.getThreadId()
|
||||
|
||||
emailPayload = {
|
||||
template: 'comment-abuse-new',
|
||||
template: 'video-comment-abuse-new',
|
||||
to,
|
||||
subject: `New comment abuse report from ${reporter}`,
|
||||
locals: {
|
||||
|
|
|
@ -18,7 +18,7 @@ import { CONFIG } from '../initializers/config'
|
|||
import { AccountBlocklistModel } from '../models/account/account-blocklist'
|
||||
import { UserModel } from '../models/account/user'
|
||||
import { UserNotificationModel } from '../models/account/user-notification'
|
||||
import { MAbuseFull, MAbuseVideo, MAccountServer, MActorFollowFull } from '../types/models'
|
||||
import { MAbuseFull, MAccountServer, MActorFollowFull } from '../types/models'
|
||||
import { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../types/models/video'
|
||||
import { isBlockedByServerOrAccount } from './blocklist'
|
||||
import { Emailer } from './emailer'
|
||||
|
@ -359,12 +359,14 @@ class Notifier {
|
|||
const moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
|
||||
if (moderators.length === 0) return
|
||||
|
||||
const url = abuseInstance.VideoAbuse?.Video?.url || abuseInstance.VideoCommentAbuse?.VideoComment?.url
|
||||
const url = abuseInstance.VideoAbuse?.Video?.url ||
|
||||
abuseInstance.VideoCommentAbuse?.VideoComment?.url ||
|
||||
abuseInstance.FlaggedAccount.Actor.url
|
||||
|
||||
logger.info('Notifying %s user/moderators of new abuse %s.', moderators.length, url)
|
||||
|
||||
function settingGetter (user: MUserWithNotificationSetting) {
|
||||
return user.NotificationSetting.videoAbuseAsModerator
|
||||
return user.NotificationSetting.abuseAsModerator
|
||||
}
|
||||
|
||||
async function notificationCreator (user: MUserWithNotificationSetting) {
|
||||
|
|
|
@ -133,7 +133,7 @@ function createDefaultUserNotificationSettings (user: MUserId, t: Transaction |
|
|||
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
||||
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
||||
myVideoPublished: UserNotificationSettingValue.WEB,
|
||||
videoAbuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
newUserRegistration: UserNotificationSettingValue.WEB,
|
||||
|
|
|
@ -25,8 +25,8 @@ const updateNotificationSettingsValidator = [
|
|||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'),
|
||||
body('newCommentOnMyVideo')
|
||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new comment on my video notification setting'),
|
||||
body('videoAbuseAsModerator')
|
||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new video abuse as moderator notification setting'),
|
||||
body('abuseAsModerator')
|
||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid abuse as moderator notification setting'),
|
||||
body('videoAutoBlacklistAsModerator')
|
||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid video auto blacklist notification setting'),
|
||||
body('blacklistOnMyVideo')
|
||||
|
|
|
@ -31,15 +31,15 @@ import {
|
|||
} from '@shared/models'
|
||||
import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
||||
import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models'
|
||||
import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account'
|
||||
import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account'
|
||||
import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils'
|
||||
import { ThumbnailModel } from '../video/thumbnail'
|
||||
import { VideoModel } from '../video/video'
|
||||
import { VideoBlacklistModel } from '../video/video-blacklist'
|
||||
import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel'
|
||||
import { ScopeNames as VideoChannelScopeNames, SummaryOptions as ChannelSummaryOptions, VideoChannelModel } from '../video/video-channel'
|
||||
import { VideoCommentModel } from '../video/video-comment'
|
||||
import { VideoAbuseModel } from './video-abuse'
|
||||
import { VideoCommentAbuseModel } from './video-comment-abuse'
|
||||
import { VideoCommentModel } from '../video/video-comment'
|
||||
|
||||
export enum ScopeNames {
|
||||
FOR_API = 'FOR_API'
|
||||
|
@ -149,7 +149,7 @@ export enum ScopeNames {
|
|||
'(' +
|
||||
'SELECT count(*) ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
'WHERE "videoId" = "VideoAbuse"."videoId" ' +
|
||||
'WHERE "videoId" = "VideoAbuse"."videoId" AND "videoId" IS NOT NULL' +
|
||||
')'
|
||||
),
|
||||
'countReportsForVideo'
|
||||
|
@ -164,7 +164,7 @@ export enum ScopeNames {
|
|||
'row_number() OVER (PARTITION BY "videoId" ORDER BY "createdAt") AS nth ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
') t ' +
|
||||
'WHERE t.id = "VideoAbuse".id' +
|
||||
'WHERE t.id = "VideoAbuse".id AND t.id IS NOT NULL' +
|
||||
')'
|
||||
),
|
||||
'nthReportForVideo'
|
||||
|
@ -172,51 +172,22 @@ export enum ScopeNames {
|
|||
[
|
||||
literal(
|
||||
'(' +
|
||||
'SELECT count("videoAbuse"."id") ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' +
|
||||
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
||||
'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
|
||||
'WHERE "account"."id" = "AbuseModel"."reporterAccountId" ' +
|
||||
'SELECT count("abuse"."id") ' +
|
||||
'FROM "abuse" ' +
|
||||
'WHERE "abuse"."reporterAccountId" = "AbuseModel"."reporterAccountId"' +
|
||||
')'
|
||||
),
|
||||
'countReportsForReporter__video'
|
||||
'countReportsForReporter'
|
||||
],
|
||||
[
|
||||
literal(
|
||||
'(' +
|
||||
'SELECT count(DISTINCT "videoAbuse"."id") ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
`WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "AbuseModel"."reporterAccountId" ` +
|
||||
'SELECT count("abuse"."id") ' +
|
||||
'FROM "abuse" ' +
|
||||
'WHERE "abuse"."flaggedAccountId" = "AbuseModel"."flaggedAccountId"' +
|
||||
')'
|
||||
),
|
||||
'countReportsForReporter__deletedVideo'
|
||||
],
|
||||
[
|
||||
literal(
|
||||
'(' +
|
||||
'SELECT count(DISTINCT "videoAbuse"."id") ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' +
|
||||
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
||||
'INNER JOIN "account" ON ' +
|
||||
'"videoChannel"."accountId" = "VideoAbuse->Video->VideoChannel"."accountId" ' +
|
||||
`OR "videoChannel"."accountId" = CAST("VideoAbuse"."deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) ` +
|
||||
')'
|
||||
),
|
||||
'countReportsForReportee__video'
|
||||
],
|
||||
[
|
||||
literal(
|
||||
'(' +
|
||||
'SELECT count(DISTINCT "videoAbuse"."id") ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
`WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "VideoAbuse->Video->VideoChannel"."accountId" ` +
|
||||
`OR CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = ` +
|
||||
`CAST("VideoAbuse"."deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) ` +
|
||||
')'
|
||||
),
|
||||
'countReportsForReportee__deletedVideo'
|
||||
'countReportsForReportee'
|
||||
]
|
||||
]
|
||||
},
|
||||
|
@ -224,13 +195,18 @@ export enum ScopeNames {
|
|||
{
|
||||
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
||||
as: 'ReporterAccount',
|
||||
required: true,
|
||||
required: !!options.searchReporter,
|
||||
where: searchAttribute(options.searchReporter, 'name')
|
||||
},
|
||||
{
|
||||
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
||||
model: AccountModel.scope({
|
||||
method: [
|
||||
AccountScopeNames.SUMMARY,
|
||||
{ actorRequired: false } as AccountSummaryOptions
|
||||
]
|
||||
}),
|
||||
as: 'FlaggedAccount',
|
||||
required: true,
|
||||
required: !!options.searchReportee,
|
||||
where: searchAttribute(options.searchReportee, 'name')
|
||||
},
|
||||
{
|
||||
|
@ -243,35 +219,36 @@ export enum ScopeNames {
|
|||
include: [
|
||||
{
|
||||
model: VideoModel.unscoped(),
|
||||
attributes: [ 'name', 'id', 'uuid' ],
|
||||
required: true
|
||||
attributes: [ 'name', 'id', 'uuid' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
model: VideoAbuseModel,
|
||||
model: VideoAbuseModel.unscoped(),
|
||||
required: options.filter === 'video' || !!options.videoIs || videoRequired,
|
||||
include: [
|
||||
{
|
||||
model: VideoModel,
|
||||
attributes: [ 'id', 'uuid', 'name', 'nsfw' ],
|
||||
model: VideoModel.unscoped(),
|
||||
required: videoRequired,
|
||||
where: searchAttribute(options.searchVideo, 'name'),
|
||||
include: [
|
||||
{
|
||||
attributes: [ 'filename', 'fileUrl' ],
|
||||
model: ThumbnailModel
|
||||
},
|
||||
{
|
||||
model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: false } as SummaryOptions ] }),
|
||||
model: VideoChannelModel.scope({
|
||||
method: [
|
||||
VideoChannelScopeNames.SUMMARY,
|
||||
{ withAccount: false, actorRequired: false } as ChannelSummaryOptions
|
||||
]
|
||||
}),
|
||||
|
||||
where: searchAttribute(options.searchVideoChannel, 'name'),
|
||||
required: true,
|
||||
include: [
|
||||
{
|
||||
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
||||
required: true
|
||||
}
|
||||
]
|
||||
required: !!options.searchVideoChannel
|
||||
},
|
||||
{
|
||||
attributes: [ 'id', 'reason', 'unfederated' ],
|
||||
|
@ -304,19 +281,19 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
|
||||
@AllowNull(false)
|
||||
@Default(null)
|
||||
@Is('VideoAbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason'))
|
||||
@Is('AbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason'))
|
||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.REASON.max))
|
||||
reason: string
|
||||
|
||||
@AllowNull(false)
|
||||
@Default(null)
|
||||
@Is('VideoAbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state'))
|
||||
@Is('AbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state'))
|
||||
@Column
|
||||
state: AbuseState
|
||||
|
||||
@AllowNull(true)
|
||||
@Default(null)
|
||||
@Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isAbuseModerationCommentValid, 'moderationComment', true))
|
||||
@Is('AbuseModerationComment', value => throwIfNotValid(value, isAbuseModerationCommentValid, 'moderationComment', true))
|
||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.MODERATION_COMMENT.max))
|
||||
moderationComment: string
|
||||
|
||||
|
@ -486,12 +463,12 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
|
||||
toFormattedJSON (this: MAbuseFormattable): Abuse {
|
||||
const predefinedReasons = AbuseModel.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
|
||||
const countReportsForReporterDeletedVideo = this.get('countReportsForReporter__deletedVideo') as number
|
||||
const countReportsForReporteeVideo = this.get('countReportsForReportee__video') as number
|
||||
const countReportsForReporteeDeletedVideo = this.get('countReportsForReportee__deletedVideo') as number
|
||||
|
||||
const countReportsForReporter = this.get('countReportsForReporter') as number
|
||||
const countReportsForReportee = this.get('countReportsForReportee') as number
|
||||
|
||||
let video: VideoAbuse
|
||||
let comment: VideoCommentAbuse
|
||||
|
@ -512,7 +489,11 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
deleted: !abuseModel.Video,
|
||||
blacklisted: abuseModel.Video?.isBlacklisted() || false,
|
||||
thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(),
|
||||
channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel
|
||||
|
||||
channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel,
|
||||
|
||||
countReports: countReportsForVideo,
|
||||
nthReport: nthReportForVideo
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -539,7 +520,13 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
reason: this.reason,
|
||||
predefinedReasons,
|
||||
|
||||
reporterAccount: this.ReporterAccount.toFormattedJSON(),
|
||||
reporterAccount: this.ReporterAccount
|
||||
? this.ReporterAccount.toFormattedJSON()
|
||||
: null,
|
||||
|
||||
flaggedAccount: this.FlaggedAccount
|
||||
? this.FlaggedAccount.toFormattedJSON()
|
||||
: null,
|
||||
|
||||
state: {
|
||||
id: this.state,
|
||||
|
@ -553,14 +540,15 @@ export class AbuseModel extends Model<AbuseModel> {
|
|||
|
||||
createdAt: this.createdAt,
|
||||
updatedAt: this.updatedAt,
|
||||
count: countReportsForVideo || 0,
|
||||
nth: nthReportForVideo || 0,
|
||||
countReportsForReporter: (countReportsForReporterVideo || 0) + (countReportsForReporterDeletedVideo || 0),
|
||||
countReportsForReportee: (countReportsForReporteeVideo || 0) + (countReportsForReporteeDeletedVideo || 0),
|
||||
|
||||
countReportsForReporter: (countReportsForReporter || 0),
|
||||
countReportsForReportee: (countReportsForReportee || 0),
|
||||
|
||||
// FIXME: deprecated in 2.3, remove this
|
||||
startAt: null,
|
||||
endAt: null
|
||||
endAt: null,
|
||||
count: countReportsForVideo || 0,
|
||||
nth: nthReportForVideo || 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ export enum ScopeNames {
|
|||
}
|
||||
|
||||
export type SummaryOptions = {
|
||||
actorRequired?: boolean // Default: true
|
||||
whereActor?: WhereOptions
|
||||
withAccountBlockerIds?: number[]
|
||||
}
|
||||
|
@ -65,12 +66,12 @@ export type SummaryOptions = {
|
|||
}
|
||||
|
||||
const query: FindOptions = {
|
||||
attributes: [ 'id', 'name' ],
|
||||
attributes: [ 'id', 'name', 'actorId' ],
|
||||
include: [
|
||||
{
|
||||
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
||||
model: ActorModel.unscoped(),
|
||||
required: true,
|
||||
required: options.actorRequired ?? true,
|
||||
where: whereActor,
|
||||
include: [
|
||||
serverInclude,
|
||||
|
|
|
@ -51,11 +51,11 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
|
|||
@AllowNull(false)
|
||||
@Default(null)
|
||||
@Is(
|
||||
'UserNotificationSettingVideoAbuseAsModerator',
|
||||
value => throwIfNotValid(value, isUserNotificationSettingValid, 'videoAbuseAsModerator')
|
||||
'UserNotificationSettingAbuseAsModerator',
|
||||
value => throwIfNotValid(value, isUserNotificationSettingValid, 'abuseAsModerator')
|
||||
)
|
||||
@Column
|
||||
videoAbuseAsModerator: UserNotificationSettingValue
|
||||
abuseAsModerator: UserNotificationSettingValue
|
||||
|
||||
@AllowNull(false)
|
||||
@Default(null)
|
||||
|
@ -166,7 +166,7 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
|
|||
return {
|
||||
newCommentOnMyVideo: this.newCommentOnMyVideo,
|
||||
newVideoFromSubscription: this.newVideoFromSubscription,
|
||||
videoAbuseAsModerator: this.videoAbuseAsModerator,
|
||||
abuseAsModerator: this.abuseAsModerator,
|
||||
videoAutoBlacklistAsModerator: this.videoAutoBlacklistAsModerator,
|
||||
blacklistOnMyVideo: this.blacklistOnMyVideo,
|
||||
myVideoPublished: this.myVideoPublished,
|
||||
|
|
|
@ -168,28 +168,26 @@ enum ScopeNames {
|
|||
'(' +
|
||||
`SELECT concat_ws(':', "abuses", "acceptedAbuses") ` +
|
||||
'FROM (' +
|
||||
'SELECT COUNT("videoAbuse"."id") AS "abuses", ' +
|
||||
`COUNT("videoAbuse"."id") FILTER (WHERE "videoAbuse"."state" = ${AbuseState.ACCEPTED}) AS "acceptedAbuses" ` +
|
||||
'FROM "videoAbuse" ' +
|
||||
'INNER JOIN "video" ON "videoAbuse"."videoId" = "video"."id" ' +
|
||||
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
||||
'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
|
||||
'SELECT COUNT("abuse"."id") AS "abuses", ' +
|
||||
`COUNT("abuse"."id") FILTER (WHERE "abuse"."state" = ${AbuseState.ACCEPTED}) AS "acceptedAbuses" ` +
|
||||
'FROM "abuse" ' +
|
||||
'INNER JOIN "account" ON "account"."id" = "abuse"."flaggedAccountId" ' +
|
||||
'WHERE "account"."userId" = "UserModel"."id"' +
|
||||
') t' +
|
||||
')'
|
||||
),
|
||||
'videoAbusesCount'
|
||||
'abusesCount'
|
||||
],
|
||||
[
|
||||
literal(
|
||||
'(' +
|
||||
'SELECT COUNT("videoAbuse"."id") ' +
|
||||
'FROM "videoAbuse" ' +
|
||||
'INNER JOIN "account" ON "account"."id" = "videoAbuse"."reporterAccountId" ' +
|
||||
'SELECT COUNT("abuse"."id") ' +
|
||||
'FROM "abuse" ' +
|
||||
'INNER JOIN "account" ON "account"."id" = "abuse"."reporterAccountId" ' +
|
||||
'WHERE "account"."userId" = "UserModel"."id"' +
|
||||
')'
|
||||
),
|
||||
'videoAbusesCreatedCount'
|
||||
'abusesCreatedCount'
|
||||
],
|
||||
[
|
||||
literal(
|
||||
|
@ -780,8 +778,8 @@ export class UserModel extends Model<UserModel> {
|
|||
const videoQuotaUsed = this.get('videoQuotaUsed')
|
||||
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
|
||||
const videosCount = this.get('videosCount')
|
||||
const [ videoAbusesCount, videoAbusesAcceptedCount ] = (this.get('videoAbusesCount') as string || ':').split(':')
|
||||
const videoAbusesCreatedCount = this.get('videoAbusesCreatedCount')
|
||||
const [ abusesCount, abusesAcceptedCount ] = (this.get('abusesCount') as string || ':').split(':')
|
||||
const abusesCreatedCount = this.get('abusesCreatedCount')
|
||||
const videoCommentsCount = this.get('videoCommentsCount')
|
||||
|
||||
const json: User = {
|
||||
|
@ -815,14 +813,14 @@ export class UserModel extends Model<UserModel> {
|
|||
videosCount: videosCount !== undefined
|
||||
? parseInt(videosCount + '', 10)
|
||||
: undefined,
|
||||
videoAbusesCount: videoAbusesCount
|
||||
? parseInt(videoAbusesCount, 10)
|
||||
abusesCount: abusesCount
|
||||
? parseInt(abusesCount, 10)
|
||||
: undefined,
|
||||
videoAbusesAcceptedCount: videoAbusesAcceptedCount
|
||||
? parseInt(videoAbusesAcceptedCount, 10)
|
||||
abusesAcceptedCount: abusesAcceptedCount
|
||||
? parseInt(abusesAcceptedCount, 10)
|
||||
: undefined,
|
||||
videoAbusesCreatedCount: videoAbusesCreatedCount !== undefined
|
||||
? parseInt(videoAbusesCreatedCount + '', 10)
|
||||
abusesCreatedCount: abusesCreatedCount !== undefined
|
||||
? parseInt(abusesCreatedCount + '', 10)
|
||||
: undefined,
|
||||
videoCommentsCount: videoCommentsCount !== undefined
|
||||
? parseInt(videoCommentsCount + '', 10)
|
||||
|
|
|
@ -61,6 +61,7 @@ type AvailableWithStatsOptions = {
|
|||
}
|
||||
|
||||
export type SummaryOptions = {
|
||||
actorRequired?: boolean // Default: true
|
||||
withAccount?: boolean // Default: false
|
||||
withAccountBlockerIds?: number[]
|
||||
}
|
||||
|
@ -121,7 +122,7 @@ export type SummaryOptions = {
|
|||
{
|
||||
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
||||
model: ActorModel.unscoped(),
|
||||
required: true,
|
||||
required: options.actorRequired ?? true,
|
||||
include: [
|
||||
{
|
||||
attributes: [ 'host' ],
|
||||
|
|
|
@ -164,7 +164,7 @@ describe('Test user notifications API validators', function () {
|
|||
const correctFields: UserNotificationSetting = {
|
||||
newVideoFromSubscription: UserNotificationSettingValue.WEB,
|
||||
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
||||
videoAbuseAsModerator: UserNotificationSettingValue.WEB,
|
||||
abuseAsModerator: UserNotificationSettingValue.WEB,
|
||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB,
|
||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB,
|
||||
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
set -eu
|
||||
|
||||
activitypubFiles=$(find server/tests/api/moderation -type f | grep -v index.ts | xargs echo)
|
||||
redundancyFiles=$(find server/tests/api/redundancy -type f | grep -v index.ts | xargs echo)
|
||||
activitypubFiles=$(find server/tests/api/activitypub -type f | grep -v index.ts | xargs echo)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Order of the tests we want to execute
|
||||
import './activitypub'
|
||||
import './check-params'
|
||||
import './moderation'
|
||||
import './notifications'
|
||||
import './redundancy'
|
||||
import './search'
|
||||
|
|
|
@ -0,0 +1,384 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import 'mocha'
|
||||
import * as chai from 'chai'
|
||||
import { Abuse, AbusePredefinedReasonsString, AbuseState } from '@shared/models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createUser,
|
||||
deleteVideoAbuse,
|
||||
flushAndRunMultipleServers,
|
||||
getVideoAbusesList,
|
||||
getVideosList,
|
||||
removeVideo,
|
||||
reportVideoAbuse,
|
||||
ServerInfo,
|
||||
setAccessTokensToServers,
|
||||
updateVideoAbuse,
|
||||
uploadVideo,
|
||||
userLogin
|
||||
} from '../../../../shared/extra-utils/index'
|
||||
import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
|
||||
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
|
||||
import {
|
||||
addAccountToServerBlocklist,
|
||||
addServerToServerBlocklist,
|
||||
removeAccountFromServerBlocklist,
|
||||
removeServerFromServerBlocklist
|
||||
} from '../../../../shared/extra-utils/users/blocklist'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
describe('Test abuses', function () {
|
||||
let servers: ServerInfo[] = []
|
||||
let abuseServer2: Abuse
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000)
|
||||
|
||||
// Run servers
|
||||
servers = await flushAndRunMultipleServers(2)
|
||||
|
||||
// Get the access tokens
|
||||
await setAccessTokensToServers(servers)
|
||||
|
||||
// Server 1 and server 2 follow each other
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
|
||||
// Upload some videos on each servers
|
||||
const video1Attributes = {
|
||||
name: 'my super name for server 1',
|
||||
description: 'my super description for server 1'
|
||||
}
|
||||
await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes)
|
||||
|
||||
const video2Attributes = {
|
||||
name: 'my super name for server 2',
|
||||
description: 'my super description for server 2'
|
||||
}
|
||||
await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes)
|
||||
|
||||
// Wait videos propagation, server 2 has transcoding enabled
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getVideosList(servers[0].url)
|
||||
const videos = res.body.data
|
||||
|
||||
expect(videos.length).to.equal(2)
|
||||
|
||||
servers[0].video = videos.find(video => video.name === 'my super name for server 1')
|
||||
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 })
|
||||
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data).to.be.an('array')
|
||||
expect(res.body.data.length).to.equal(0)
|
||||
})
|
||||
|
||||
it('Should report abuse on a local video', async function () {
|
||||
this.timeout(15000)
|
||||
|
||||
const reason = 'my super bad reason'
|
||||
await reportVideoAbuse(servers[0].url, servers[0].accessToken, 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 })
|
||||
|
||||
expect(res1.body.total).to.equal(1)
|
||||
expect(res1.body.data).to.be.an('array')
|
||||
expect(res1.body.data.length).to.equal(1)
|
||||
|
||||
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.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.countReportsForReporter).to.equal(1)
|
||||
expect(abuse.countReportsForReportee).to.equal(1)
|
||||
|
||||
const res2 = await getVideoAbusesList({ 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)
|
||||
})
|
||||
|
||||
it('Should report abuse on a remote video', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
const reason = 'my super bad reason 2'
|
||||
await reportVideoAbuse(servers[0].url, servers[0].accessToken, 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 })
|
||||
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.video.id).to.equal(servers[0].video.id)
|
||||
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.video.id).to.equal(servers[1].video.id)
|
||||
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 })
|
||||
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.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')
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(3)
|
||||
}
|
||||
|
||||
const accountToBlock = 'root@localhost:' + servers[1].port
|
||||
|
||||
{
|
||||
await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
|
||||
|
||||
const res = await getVideoAbusesList({ 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')
|
||||
expect(abuse).to.be.undefined
|
||||
}
|
||||
|
||||
{
|
||||
await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(3)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should hide video abuses from blocked servers', async function () {
|
||||
const serverToBlock = servers[1].host
|
||||
|
||||
{
|
||||
await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
|
||||
|
||||
const res = await getVideoAbusesList({ 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')
|
||||
expect(abuse).to.be.undefined
|
||||
}
|
||||
|
||||
{
|
||||
await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
expect(res.body.total).to.equal(3)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should keep the video abuse when deleting the video', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
await removeVideo(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
const res = await getVideoAbusesList({ 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")
|
||||
|
||||
const abuse: Abuse = res.body.data[0]
|
||||
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
|
||||
})
|
||||
|
||||
it('Should include counts of reports from reporter and reportee', async function () {
|
||||
this.timeout(10000)
|
||||
|
||||
// register a second user to have two reporters/reportees
|
||||
const user = { username: 'user2', password: 'password' }
|
||||
await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, ...user })
|
||||
const userAccessToken = await userLogin(servers[0], user)
|
||||
|
||||
// upload a third video via this user
|
||||
const video3Attributes = {
|
||||
name: 'my second super name for server 1',
|
||||
description: 'my second super description for server 1'
|
||||
}
|
||||
await uploadVideo(servers[0].url, userAccessToken, video3Attributes)
|
||||
|
||||
const res1 = await getVideosList(servers[0].url)
|
||||
const videos = res1.body.data
|
||||
const video3 = videos.find(video => video.name === 'my second super name for server 1')
|
||||
|
||||
// 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)
|
||||
|
||||
const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
|
||||
{
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
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: AbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ]
|
||||
const createdAbuse = (await reportVideoAbuse(
|
||||
servers[0].url,
|
||||
servers[0].accessToken,
|
||||
servers[0].video.id,
|
||||
reason5,
|
||||
predefinedReasons5,
|
||||
1,
|
||||
5
|
||||
)).body.abuse
|
||||
|
||||
const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
|
||||
|
||||
{
|
||||
const abuse = (res.body.data as Abuse[]).find(a => a.id === createdAbuse.id)
|
||||
expect(abuse.reason).to.equals(reason5)
|
||||
expect(abuse.predefinedReasons).to.deep.equals(predefinedReasons5, "predefined reasons do not match the one reported")
|
||||
expect(abuse.video.startAt).to.equal(1, "starting timestamp doesn't match the one reported")
|
||||
expect(abuse.video.endAt).to.equal(5, "ending timestamp doesn't match the one reported")
|
||||
}
|
||||
})
|
||||
|
||||
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 waitJobs(servers)
|
||||
|
||||
{
|
||||
const res = await getVideoAbusesList({ 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 })
|
||||
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'>) {
|
||||
const options = {
|
||||
url: servers[0].url,
|
||||
token: servers[0].accessToken
|
||||
}
|
||||
|
||||
Object.assign(options, query)
|
||||
|
||||
const res = await getVideoAbusesList(options)
|
||||
|
||||
return res.body.data as Abuse[]
|
||||
}
|
||||
|
||||
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(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(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(5)
|
||||
|
||||
expect(await list({ searchReportee: 'root' })).to.have.lengthOf(5)
|
||||
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: AbuseState.ACCEPTED })).to.have.lengthOf(0)
|
||||
expect(await list({ state: AbuseState.PENDING })).to.have.lengthOf(6)
|
||||
|
||||
expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1)
|
||||
expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0)
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,2 @@
|
|||
export * from './abuses'
|
||||
export * from './blocklist'
|
|
@ -11,7 +11,7 @@ import {
|
|||
MockInstancesIndex,
|
||||
registerUser,
|
||||
removeVideoFromBlacklist,
|
||||
reportVideoAbuse,
|
||||
reportAbuse,
|
||||
unfollow,
|
||||
updateCustomConfig,
|
||||
updateCustomSubConfig,
|
||||
|
@ -74,12 +74,12 @@ describe('Test moderation notifications', function () {
|
|||
|
||||
const name = 'video for abuse ' + uuidv4()
|
||||
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
||||
const uuid = resVideo.body.video.uuid
|
||||
const video = resVideo.body.video
|
||||
|
||||
await reportVideoAbuse(servers[0].url, servers[0].accessToken, uuid, 'super reason')
|
||||
await reportAbuse({ url: servers[0].url, token: servers[0].accessToken, videoId: video.id, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewVideoAbuseForModerators(baseParams, uuid, name, 'presence')
|
||||
await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence')
|
||||
})
|
||||
|
||||
it('Should send a notification to moderators on remote video abuse', async function () {
|
||||
|
@ -87,14 +87,14 @@ describe('Test moderation notifications', function () {
|
|||
|
||||
const name = 'video for abuse ' + uuidv4()
|
||||
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
||||
const uuid = resVideo.body.video.uuid
|
||||
const video = resVideo.body.video
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
await reportVideoAbuse(servers[1].url, servers[1].accessToken, uuid, 'super reason')
|
||||
await reportAbuse({ url: servers[1].url, token: servers[1].accessToken, videoId: video.id, reason: 'super reason' })
|
||||
|
||||
await waitJobs(servers)
|
||||
await checkNewVideoAbuseForModerators(baseParams, uuid, name, 'presence')
|
||||
await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import * as chai from 'chai'
|
||||
import 'mocha'
|
||||
import * as chai from 'chai'
|
||||
import {
|
||||
addVideoToBlacklist,
|
||||
askResetPassword,
|
||||
|
@ -11,7 +11,7 @@ import {
|
|||
createUser,
|
||||
flushAndRunServer,
|
||||
removeVideoFromBlacklist,
|
||||
reportVideoAbuse,
|
||||
reportAbuse,
|
||||
resetPassword,
|
||||
ServerInfo,
|
||||
setAccessTokensToServers,
|
||||
|
@ -30,10 +30,15 @@ describe('Test emails', function () {
|
|||
let userId: number
|
||||
let userId2: number
|
||||
let userAccessToken: string
|
||||
|
||||
let videoUUID: string
|
||||
let videoId: number
|
||||
|
||||
let videoUserUUID: string
|
||||
|
||||
let verificationString: string
|
||||
let verificationString2: string
|
||||
|
||||
const emails: object[] = []
|
||||
const user = {
|
||||
username: 'user_1',
|
||||
|
@ -76,6 +81,7 @@ describe('Test emails', function () {
|
|||
}
|
||||
const res = await uploadVideo(server.url, server.accessToken, attributes)
|
||||
videoUUID = res.body.video.uuid
|
||||
videoId = res.body.video.id
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -179,7 +185,7 @@ describe('Test emails', function () {
|
|||
this.timeout(10000)
|
||||
|
||||
const reason = 'my super bad reason'
|
||||
await reportVideoAbuse(server.url, server.accessToken, videoUUID, reason)
|
||||
await reportAbuse({ url: server.url, token: server.accessToken, videoId, reason })
|
||||
|
||||
await waitJobs(server)
|
||||
expect(emails).to.have.lengthOf(3)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import './users-verification'
|
||||
import './blocklist'
|
||||
import './user-subscriptions'
|
||||
import './users'
|
||||
import './users-multiple-servers'
|
||||
import './users-verification'
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import * as chai from 'chai'
|
||||
import 'mocha'
|
||||
import { MyUser, User, UserRole, Video, AbuseState, AbuseUpdate, VideoPlaylistType } from '@shared/models'
|
||||
import * as chai from 'chai'
|
||||
import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models'
|
||||
import { CustomConfig } from '@shared/models/server'
|
||||
import {
|
||||
addVideoCommentThread,
|
||||
blockUser,
|
||||
|
@ -10,6 +11,7 @@ import {
|
|||
createUser,
|
||||
deleteMe,
|
||||
flushAndRunServer,
|
||||
getAbusesList,
|
||||
getAccountRatings,
|
||||
getBlacklistedVideosList,
|
||||
getCustomConfig,
|
||||
|
@ -19,7 +21,6 @@ import {
|
|||
getUserInformation,
|
||||
getUsersList,
|
||||
getUsersListPaginationAndSort,
|
||||
getVideoAbusesList,
|
||||
getVideoChannel,
|
||||
getVideosList,
|
||||
installPlugin,
|
||||
|
@ -29,15 +30,15 @@ import {
|
|||
registerUserWithChannel,
|
||||
removeUser,
|
||||
removeVideo,
|
||||
reportVideoAbuse,
|
||||
reportAbuse,
|
||||
ServerInfo,
|
||||
testImage,
|
||||
unblockUser,
|
||||
updateAbuse,
|
||||
updateCustomSubConfig,
|
||||
updateMyAvatar,
|
||||
updateMyUser,
|
||||
updateUser,
|
||||
updateVideoAbuse,
|
||||
uploadVideo,
|
||||
userLogin,
|
||||
waitJobs
|
||||
|
@ -46,7 +47,6 @@ import { follow } from '../../../../shared/extra-utils/server/follows'
|
|||
import { logout, serverLogin, setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
|
||||
import { getMyVideos } from '../../../../shared/extra-utils/videos/videos'
|
||||
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
|
||||
import { CustomConfig } from '@shared/models/server'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
@ -302,10 +302,10 @@ describe('Test users', function () {
|
|||
expect(userGet.videosCount).to.equal(0)
|
||||
expect(userGet.videoCommentsCount).to.be.a('number')
|
||||
expect(userGet.videoCommentsCount).to.equal(0)
|
||||
expect(userGet.videoAbusesCount).to.be.a('number')
|
||||
expect(userGet.videoAbusesCount).to.equal(0)
|
||||
expect(userGet.videoAbusesAcceptedCount).to.be.a('number')
|
||||
expect(userGet.videoAbusesAcceptedCount).to.equal(0)
|
||||
expect(userGet.abusesCount).to.be.a('number')
|
||||
expect(userGet.abusesCount).to.equal(0)
|
||||
expect(userGet.abusesAcceptedCount).to.be.a('number')
|
||||
expect(userGet.abusesAcceptedCount).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -895,9 +895,9 @@ describe('Test users', function () {
|
|||
|
||||
expect(user.videosCount).to.equal(0)
|
||||
expect(user.videoCommentsCount).to.equal(0)
|
||||
expect(user.videoAbusesCount).to.equal(0)
|
||||
expect(user.videoAbusesCreatedCount).to.equal(0)
|
||||
expect(user.videoAbusesAcceptedCount).to.equal(0)
|
||||
expect(user.abusesCount).to.equal(0)
|
||||
expect(user.abusesCreatedCount).to.equal(0)
|
||||
expect(user.abusesAcceptedCount).to.equal(0)
|
||||
})
|
||||
|
||||
it('Should report correct videos count', async function () {
|
||||
|
@ -924,26 +924,26 @@ describe('Test users', function () {
|
|||
expect(user.videoCommentsCount).to.equal(1)
|
||||
})
|
||||
|
||||
it('Should report correct video abuses counts', async function () {
|
||||
it('Should report correct abuses counts', async function () {
|
||||
const reason = 'my super bad reason'
|
||||
await reportVideoAbuse(server.url, user17AccessToken, videoId, reason)
|
||||
await reportAbuse({ url: server.url, token: user17AccessToken, videoId, reason })
|
||||
|
||||
const res1 = await getVideoAbusesList({ url: server.url, token: server.accessToken })
|
||||
const res1 = await getAbusesList({ url: server.url, token: server.accessToken })
|
||||
const abuseId = res1.body.data[0].id
|
||||
|
||||
const res2 = await getUserInformation(server.url, server.accessToken, user17Id, true)
|
||||
const user2: User = res2.body
|
||||
|
||||
expect(user2.videoAbusesCount).to.equal(1) // number of incriminations
|
||||
expect(user2.videoAbusesCreatedCount).to.equal(1) // number of reports created
|
||||
expect(user2.abusesCount).to.equal(1) // number of incriminations
|
||||
expect(user2.abusesCreatedCount).to.equal(1) // number of reports created
|
||||
|
||||
const body: AbuseUpdate = { state: AbuseState.ACCEPTED }
|
||||
await updateVideoAbuse(server.url, server.accessToken, videoId, abuseId, body)
|
||||
await updateAbuse(server.url, server.accessToken, abuseId, body)
|
||||
|
||||
const res3 = await getUserInformation(server.url, server.accessToken, user17Id, true)
|
||||
const user3: User = res3.body
|
||||
|
||||
expect(user3.videoAbusesAcceptedCount).to.equal(1) // number of reports created accepted
|
||||
expect(user3.abusesAcceptedCount).to.equal(1) // number of reports created accepted
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -103,8 +103,8 @@ describe('Test video abuses', function () {
|
|||
expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
|
||||
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.video.countReports).to.equal(1)
|
||||
expect(abuse.video.nthReport).to.equal(1)
|
||||
expect(abuse.countReportsForReporter).to.equal(1)
|
||||
expect(abuse.countReportsForReportee).to.equal(1)
|
||||
|
||||
|
@ -138,8 +138,8 @@ describe('Test video abuses', function () {
|
|||
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)
|
||||
expect(abuse1.video.countReports).to.equal(1)
|
||||
expect(abuse1.video.nthReport).to.equal(1)
|
||||
|
||||
const abuse2: Abuse = res1.body.data[1]
|
||||
expect(abuse2.reason).to.equal('my super bad reason 2')
|
||||
|
@ -281,8 +281,8 @@ describe('Test video abuses', function () {
|
|||
{
|
||||
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.video.countReports).to.equal(1, "wrong reports count for video 3")
|
||||
expect(abuse.video.nthReport).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")
|
||||
}
|
||||
|
|
|
@ -98,5 +98,6 @@ export type MAbuseFull =
|
|||
export type MAbuseFormattable =
|
||||
MAbuse &
|
||||
Use<'ReporterAccount', MAccountFormattable> &
|
||||
Use<'FlaggedAccount', MAccountFormattable> &
|
||||
Use<'VideoAbuse', MVideoAbuseFormattable> &
|
||||
Use<'VideoCommentAbuse', MCommentAbuseFormattable>
|
||||
|
|
|
@ -516,7 +516,7 @@ function getAllNotificationsSettings () {
|
|||
return {
|
||||
newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
videoAbuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||
|
|
|
@ -18,6 +18,9 @@ export interface VideoAbuse {
|
|||
|
||||
thumbnailPath?: string
|
||||
channel?: VideoChannel
|
||||
|
||||
countReports: number
|
||||
nthReport: number
|
||||
}
|
||||
|
||||
export interface VideoCommentAbuse {
|
||||
|
@ -36,9 +39,12 @@ export interface VideoCommentAbuse {
|
|||
|
||||
export interface Abuse {
|
||||
id: number
|
||||
|
||||
reason: string
|
||||
predefinedReasons?: AbusePredefinedReasonsString[]
|
||||
|
||||
reporterAccount: Account
|
||||
flaggedAccount: Account
|
||||
|
||||
state: VideoConstant<AbuseState>
|
||||
moderationComment?: string
|
||||
|
@ -49,13 +55,18 @@ export interface Abuse {
|
|||
createdAt: Date
|
||||
updatedAt: Date
|
||||
|
||||
// FIXME: deprecated in 2.3, remove this
|
||||
startAt: null
|
||||
endAt: null
|
||||
|
||||
count?: number
|
||||
nth?: number
|
||||
|
||||
countReportsForReporter?: number
|
||||
countReportsForReportee?: number
|
||||
|
||||
// FIXME: deprecated in 2.3, remove the following properties
|
||||
|
||||
// // @deprecated
|
||||
// startAt: null
|
||||
// // @deprecated
|
||||
// endAt: null
|
||||
|
||||
// // @deprecated
|
||||
// count?: number
|
||||
// // @deprecated
|
||||
// nth?: number
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ export enum UserNotificationSettingValue {
|
|||
export interface UserNotificationSetting {
|
||||
newVideoFromSubscription: UserNotificationSettingValue
|
||||
newCommentOnMyVideo: UserNotificationSettingValue
|
||||
videoAbuseAsModerator: UserNotificationSettingValue
|
||||
abuseAsModerator: UserNotificationSettingValue
|
||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue
|
||||
blacklistOnMyVideo: UserNotificationSettingValue
|
||||
myVideoPublished: UserNotificationSettingValue
|
||||
|
|
|
@ -31,10 +31,13 @@ export interface User {
|
|||
videoQuotaDaily: number
|
||||
videoQuotaUsed?: number
|
||||
videoQuotaUsedDaily?: number
|
||||
|
||||
videosCount?: number
|
||||
videoAbusesCount?: number
|
||||
videoAbusesAcceptedCount?: number
|
||||
videoAbusesCreatedCount?: number
|
||||
|
||||
abusesCount?: number
|
||||
abusesAcceptedCount?: number
|
||||
abusesCreatedCount?: number
|
||||
|
||||
videoCommentsCount? : number
|
||||
|
||||
theme: string
|
||||
|
|
|
@ -893,7 +893,7 @@ paths:
|
|||
$ref: '#/components/schemas/NotificationSettingValue'
|
||||
newCommentOnMyVideo:
|
||||
$ref: '#/components/schemas/NotificationSettingValue'
|
||||
videoAbuseAsModerator:
|
||||
abuseAsModerator:
|
||||
$ref: '#/components/schemas/NotificationSettingValue'
|
||||
videoAutoBlacklistAsModerator:
|
||||
$ref: '#/components/schemas/NotificationSettingValue'
|
||||
|
@ -1618,7 +1618,7 @@ paths:
|
|||
type: object
|
||||
properties:
|
||||
state:
|
||||
$ref: '#/components/schemas/VideoAbuseStateSet'
|
||||
$ref: '#/components/schemas/AbuseStateSet'
|
||||
moderationComment:
|
||||
type: string
|
||||
description: Update the report comment visible only to the moderation team
|
||||
|
@ -3584,20 +3584,20 @@ components:
|
|||
label:
|
||||
type: string
|
||||
|
||||
VideoAbuseStateSet:
|
||||
AbuseStateSet:
|
||||
type: integer
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
description: 'The video playlist privacy (Pending = `1`, Rejected = `2`, Accepted = `3`)'
|
||||
VideoAbuseStateConstant:
|
||||
AbuseStateConstant:
|
||||
properties:
|
||||
id:
|
||||
$ref: '#/components/schemas/VideoAbuseStateSet'
|
||||
$ref: '#/components/schemas/AbuseStateSet'
|
||||
label:
|
||||
type: string
|
||||
VideoAbusePredefinedReasons:
|
||||
AbusePredefinedReasons:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
@ -3960,11 +3960,11 @@ components:
|
|||
type: string
|
||||
example: The video is a spam
|
||||
predefinedReasons:
|
||||
$ref: '#/components/schemas/VideoAbusePredefinedReasons'
|
||||
$ref: '#/components/schemas/AbusePredefinedReasons'
|
||||
reporterAccount:
|
||||
$ref: '#/components/schemas/Account'
|
||||
state:
|
||||
$ref: '#/components/schemas/VideoAbuseStateConstant'
|
||||
$ref: '#/components/schemas/AbuseStateConstant'
|
||||
moderationComment:
|
||||
type: string
|
||||
example: Decided to ban the server since it spams us regularly
|
||||
|
@ -4690,11 +4690,11 @@ components:
|
|||
description: The user daily video quota
|
||||
videosCount:
|
||||
type: integer
|
||||
videoAbusesCount:
|
||||
abusesCount:
|
||||
type: integer
|
||||
videoAbusesAcceptedCount:
|
||||
abusesAcceptedCount:
|
||||
type: integer
|
||||
videoAbusesCreatedCount:
|
||||
abusesCreatedCount:
|
||||
type: integer
|
||||
videoCommentsCount:
|
||||
type: integer
|
||||
|
|
Loading…
Reference in New Issue