Add migrations
This commit is contained in:
parent
57f6896f67
commit
4f32032fed
|
@ -45,7 +45,7 @@ export class AdminComponent implements OnInit {
|
||||||
children: []
|
children: []
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasVideoAbusesRight()) {
|
if (this.hasAbusesRight()) {
|
||||||
moderationItems.children.push({
|
moderationItems.children.push({
|
||||||
label: this.i18n('Video reports'),
|
label: this.i18n('Video reports'),
|
||||||
routerLink: '/admin/moderation/video-abuses/list',
|
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.hasUsersRight()) this.menuEntries.push({ label: this.i18n('Users'), routerLink: '/admin/users' })
|
||||||
if (this.hasServerFollowRight()) this.menuEntries.push(federationItems)
|
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.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.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' })
|
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)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_SERVER_FOLLOW)
|
||||||
}
|
}
|
||||||
|
|
||||||
hasVideoAbusesRight () {
|
hasAbusesRight () {
|
||||||
return this.auth.getUser().hasRight(UserRight.MANAGE_ABUSES)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_ABUSES)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,14 +37,14 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' + user?.account.displayName + '"' }">
|
<a [routerLink]="[ '/admin/moderation/abuses/list' ]" [queryParams]="{ 'search': 'reportee:"' + user?.account.displayName + '"' }">
|
||||||
<div class="dashboard-num">{{ user.videoAbusesCount }}</div>
|
<div class="dashboard-num">{{ user.abusesCount }}</div>
|
||||||
<div class="dashboard-label" i18n>Incriminated in reports</div>
|
<div class="dashboard-label" i18n>Incriminated in reports</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'reporter:"' + user?.account.displayName + '" state:accepted' }">
|
<a [routerLink]="[ '/admin/moderation/abuses/list' ]" [queryParams]="{ 'search': 'reporter:"' + user?.account.displayName + '" state:accepted' }">
|
||||||
<div class="dashboard-num">{{ user.videoAbusesAcceptedCount }} / {{ user.videoAbusesCreatedCount }}</div>
|
<div class="dashboard-num">{{ user.abusesAcceptedCount }} / {{ user.abusesCreatedCount }}</div>
|
||||||
<div class="dashboard-label" i18n>Authored reports accepted</div>
|
<div class="dashboard-label" i18n>Authored reports accepted</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -33,7 +33,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
|
||||||
this.labelNotifications = {
|
this.labelNotifications = {
|
||||||
newVideoFromSubscription: this.i18n('New video from your subscriptions'),
|
newVideoFromSubscription: this.i18n('New video from your subscriptions'),
|
||||||
newCommentOnMyVideo: this.i18n('New comment on your video'),
|
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'),
|
videoAutoBlacklistAsModerator: this.i18n('Video blocked automatically waiting review'),
|
||||||
blacklistOnMyVideo: this.i18n('One of your video is blocked/unblocked'),
|
blacklistOnMyVideo: this.i18n('One of your video is blocked/unblocked'),
|
||||||
myVideoPublished: this.i18n('Video published (after transcoding/scheduled update)'),
|
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.notificationSettingKeys = Object.keys(this.labelNotifications) as (keyof UserNotificationSetting)[]
|
||||||
|
|
||||||
this.rightNotifications = {
|
this.rightNotifications = {
|
||||||
videoAbuseAsModerator: UserRight.MANAGE_ABUSES,
|
abuseAsModerator: UserRight.MANAGE_ABUSES,
|
||||||
videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLACKLIST,
|
videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLACKLIST,
|
||||||
newUserRegistration: UserRight.MANAGE_USERS,
|
newUserRegistration: UserRight.MANAGE_USERS,
|
||||||
newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW,
|
newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW,
|
||||||
|
|
|
@ -51,12 +51,14 @@ export class User implements UserServerModel {
|
||||||
videoQuotaDaily: number
|
videoQuotaDaily: number
|
||||||
videoQuotaUsed?: number
|
videoQuotaUsed?: number
|
||||||
videoQuotaUsedDaily?: number
|
videoQuotaUsedDaily?: number
|
||||||
|
|
||||||
videosCount?: number
|
videosCount?: number
|
||||||
videoAbusesCount?: number
|
|
||||||
videoAbusesAcceptedCount?: number
|
|
||||||
videoAbusesCreatedCount?: number
|
|
||||||
videoCommentsCount?: number
|
videoCommentsCount?: number
|
||||||
|
|
||||||
|
abusesCount?: number
|
||||||
|
abusesAcceptedCount?: number
|
||||||
|
abusesCreatedCount?: number
|
||||||
|
|
||||||
theme: string
|
theme: string
|
||||||
|
|
||||||
account: Account
|
account: Account
|
||||||
|
@ -89,9 +91,9 @@ export class User implements UserServerModel {
|
||||||
this.videoQuotaUsed = hash.videoQuotaUsed
|
this.videoQuotaUsed = hash.videoQuotaUsed
|
||||||
this.videoQuotaUsedDaily = hash.videoQuotaUsedDaily
|
this.videoQuotaUsedDaily = hash.videoQuotaUsedDaily
|
||||||
this.videosCount = hash.videosCount
|
this.videosCount = hash.videosCount
|
||||||
this.videoAbusesCount = hash.videoAbusesCount
|
this.abusesCount = hash.abusesCount
|
||||||
this.videoAbusesAcceptedCount = hash.videoAbusesAcceptedCount
|
this.abusesAcceptedCount = hash.abusesAcceptedCount
|
||||||
this.videoAbusesCreatedCount = hash.videoAbusesCreatedCount
|
this.abusesCreatedCount = hash.abusesCreatedCount
|
||||||
this.videoCommentsCount = hash.videoCommentsCount
|
this.videoCommentsCount = hash.videoCommentsCount
|
||||||
|
|
||||||
this.nsfwPolicy = hash.nsfwPolicy
|
this.nsfwPolicy = hash.nsfwPolicy
|
||||||
|
|
|
@ -68,7 +68,7 @@ async function updateNotificationSettings (req: express.Request, res: express.Re
|
||||||
const values: UserNotificationSetting = {
|
const values: UserNotificationSetting = {
|
||||||
newVideoFromSubscription: body.newVideoFromSubscription,
|
newVideoFromSubscription: body.newVideoFromSubscription,
|
||||||
newCommentOnMyVideo: body.newCommentOnMyVideo,
|
newCommentOnMyVideo: body.newCommentOnMyVideo,
|
||||||
videoAbuseAsModerator: body.videoAbuseAsModerator,
|
abuseAsModerator: body.abuseAsModerator,
|
||||||
videoAutoBlacklistAsModerator: body.videoAutoBlacklistAsModerator,
|
videoAutoBlacklistAsModerator: body.videoAutoBlacklistAsModerator,
|
||||||
blacklistOnMyVideo: body.blacklistOnMyVideo,
|
blacklistOnMyVideo: body.blacklistOnMyVideo,
|
||||||
myVideoPublished: body.myVideoPublished,
|
myVideoPublished: body.myVideoPublished,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const LAST_MIGRATION_VERSION = 515
|
const LAST_MIGRATION_VERSION = 520
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
92
server/initializers/migrations/0520-abuses-split.ts
Normal file
92
server/initializers/migrations/0520-abuses-split.ts
Normal file
|
@ -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()
|
const commentUrl = WEBSERVER.URL + comment.Video.getWatchStaticPath() + ';threadId=' + comment.getThreadId()
|
||||||
|
|
||||||
emailPayload = {
|
emailPayload = {
|
||||||
template: 'comment-abuse-new',
|
template: 'video-comment-abuse-new',
|
||||||
to,
|
to,
|
||||||
subject: `New comment abuse report from ${reporter}`,
|
subject: `New comment abuse report from ${reporter}`,
|
||||||
locals: {
|
locals: {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { CONFIG } from '../initializers/config'
|
||||||
import { AccountBlocklistModel } from '../models/account/account-blocklist'
|
import { AccountBlocklistModel } from '../models/account/account-blocklist'
|
||||||
import { UserModel } from '../models/account/user'
|
import { UserModel } from '../models/account/user'
|
||||||
import { UserNotificationModel } from '../models/account/user-notification'
|
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 { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../types/models/video'
|
||||||
import { isBlockedByServerOrAccount } from './blocklist'
|
import { isBlockedByServerOrAccount } from './blocklist'
|
||||||
import { Emailer } from './emailer'
|
import { Emailer } from './emailer'
|
||||||
|
@ -359,12 +359,14 @@ class Notifier {
|
||||||
const moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
|
const moderators = await UserModel.listWithRight(UserRight.MANAGE_ABUSES)
|
||||||
if (moderators.length === 0) return
|
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)
|
logger.info('Notifying %s user/moderators of new abuse %s.', moderators.length, url)
|
||||||
|
|
||||||
function settingGetter (user: MUserWithNotificationSetting) {
|
function settingGetter (user: MUserWithNotificationSetting) {
|
||||||
return user.NotificationSetting.videoAbuseAsModerator
|
return user.NotificationSetting.abuseAsModerator
|
||||||
}
|
}
|
||||||
|
|
||||||
async function notificationCreator (user: MUserWithNotificationSetting) {
|
async function notificationCreator (user: MUserWithNotificationSetting) {
|
||||||
|
|
|
@ -133,7 +133,7 @@ function createDefaultUserNotificationSettings (user: MUserId, t: Transaction |
|
||||||
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
||||||
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
||||||
myVideoPublished: UserNotificationSettingValue.WEB,
|
myVideoPublished: UserNotificationSettingValue.WEB,
|
||||||
videoAbuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
newUserRegistration: UserNotificationSettingValue.WEB,
|
newUserRegistration: UserNotificationSettingValue.WEB,
|
||||||
|
|
|
@ -25,8 +25,8 @@ const updateNotificationSettingsValidator = [
|
||||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'),
|
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new video from subscription notification setting'),
|
||||||
body('newCommentOnMyVideo')
|
body('newCommentOnMyVideo')
|
||||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new comment on my video notification setting'),
|
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new comment on my video notification setting'),
|
||||||
body('videoAbuseAsModerator')
|
body('abuseAsModerator')
|
||||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid new video abuse as moderator notification setting'),
|
.custom(isUserNotificationSettingValid).withMessage('Should have a valid abuse as moderator notification setting'),
|
||||||
body('videoAutoBlacklistAsModerator')
|
body('videoAutoBlacklistAsModerator')
|
||||||
.custom(isUserNotificationSettingValid).withMessage('Should have a valid video auto blacklist notification setting'),
|
.custom(isUserNotificationSettingValid).withMessage('Should have a valid video auto blacklist notification setting'),
|
||||||
body('blacklistOnMyVideo')
|
body('blacklistOnMyVideo')
|
||||||
|
|
|
@ -31,15 +31,15 @@ import {
|
||||||
} from '@shared/models'
|
} from '@shared/models'
|
||||||
import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants'
|
||||||
import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models'
|
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 { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils'
|
||||||
import { ThumbnailModel } from '../video/thumbnail'
|
import { ThumbnailModel } from '../video/thumbnail'
|
||||||
import { VideoModel } from '../video/video'
|
import { VideoModel } from '../video/video'
|
||||||
import { VideoBlacklistModel } from '../video/video-blacklist'
|
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 { VideoAbuseModel } from './video-abuse'
|
||||||
import { VideoCommentAbuseModel } from './video-comment-abuse'
|
import { VideoCommentAbuseModel } from './video-comment-abuse'
|
||||||
import { VideoCommentModel } from '../video/video-comment'
|
|
||||||
|
|
||||||
export enum ScopeNames {
|
export enum ScopeNames {
|
||||||
FOR_API = 'FOR_API'
|
FOR_API = 'FOR_API'
|
||||||
|
@ -149,7 +149,7 @@ export enum ScopeNames {
|
||||||
'(' +
|
'(' +
|
||||||
'SELECT count(*) ' +
|
'SELECT count(*) ' +
|
||||||
'FROM "videoAbuse" ' +
|
'FROM "videoAbuse" ' +
|
||||||
'WHERE "videoId" = "VideoAbuse"."videoId" ' +
|
'WHERE "videoId" = "VideoAbuse"."videoId" AND "videoId" IS NOT NULL' +
|
||||||
')'
|
')'
|
||||||
),
|
),
|
||||||
'countReportsForVideo'
|
'countReportsForVideo'
|
||||||
|
@ -164,7 +164,7 @@ export enum ScopeNames {
|
||||||
'row_number() OVER (PARTITION BY "videoId" ORDER BY "createdAt") AS nth ' +
|
'row_number() OVER (PARTITION BY "videoId" ORDER BY "createdAt") AS nth ' +
|
||||||
'FROM "videoAbuse" ' +
|
'FROM "videoAbuse" ' +
|
||||||
') t ' +
|
') t ' +
|
||||||
'WHERE t.id = "VideoAbuse".id' +
|
'WHERE t.id = "VideoAbuse".id AND t.id IS NOT NULL' +
|
||||||
')'
|
')'
|
||||||
),
|
),
|
||||||
'nthReportForVideo'
|
'nthReportForVideo'
|
||||||
|
@ -172,51 +172,22 @@ export enum ScopeNames {
|
||||||
[
|
[
|
||||||
literal(
|
literal(
|
||||||
'(' +
|
'(' +
|
||||||
'SELECT count("videoAbuse"."id") ' +
|
'SELECT count("abuse"."id") ' +
|
||||||
'FROM "videoAbuse" ' +
|
'FROM "abuse" ' +
|
||||||
'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' +
|
'WHERE "abuse"."reporterAccountId" = "AbuseModel"."reporterAccountId"' +
|
||||||
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
|
||||||
'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
|
|
||||||
'WHERE "account"."id" = "AbuseModel"."reporterAccountId" ' +
|
|
||||||
')'
|
')'
|
||||||
),
|
),
|
||||||
'countReportsForReporter__video'
|
'countReportsForReporter'
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
literal(
|
literal(
|
||||||
'(' +
|
'(' +
|
||||||
'SELECT count(DISTINCT "videoAbuse"."id") ' +
|
'SELECT count("abuse"."id") ' +
|
||||||
'FROM "videoAbuse" ' +
|
'FROM "abuse" ' +
|
||||||
`WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "AbuseModel"."reporterAccountId" ` +
|
'WHERE "abuse"."flaggedAccountId" = "AbuseModel"."flaggedAccountId"' +
|
||||||
')'
|
')'
|
||||||
),
|
),
|
||||||
'countReportsForReporter__deletedVideo'
|
'countReportsForReportee'
|
||||||
],
|
|
||||||
[
|
|
||||||
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'
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -224,13 +195,18 @@ export enum ScopeNames {
|
||||||
{
|
{
|
||||||
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
||||||
as: 'ReporterAccount',
|
as: 'ReporterAccount',
|
||||||
required: true,
|
required: !!options.searchReporter,
|
||||||
where: searchAttribute(options.searchReporter, 'name')
|
where: searchAttribute(options.searchReporter, 'name')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
model: AccountModel.scope({
|
||||||
|
method: [
|
||||||
|
AccountScopeNames.SUMMARY,
|
||||||
|
{ actorRequired: false } as AccountSummaryOptions
|
||||||
|
]
|
||||||
|
}),
|
||||||
as: 'FlaggedAccount',
|
as: 'FlaggedAccount',
|
||||||
required: true,
|
required: !!options.searchReportee,
|
||||||
where: searchAttribute(options.searchReportee, 'name')
|
where: searchAttribute(options.searchReportee, 'name')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -243,35 +219,36 @@ export enum ScopeNames {
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: VideoModel.unscoped(),
|
model: VideoModel.unscoped(),
|
||||||
attributes: [ 'name', 'id', 'uuid' ],
|
attributes: [ 'name', 'id', 'uuid' ]
|
||||||
required: true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: VideoAbuseModel,
|
model: VideoAbuseModel.unscoped(),
|
||||||
required: options.filter === 'video' || !!options.videoIs || videoRequired,
|
required: options.filter === 'video' || !!options.videoIs || videoRequired,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: VideoModel,
|
attributes: [ 'id', 'uuid', 'name', 'nsfw' ],
|
||||||
|
model: VideoModel.unscoped(),
|
||||||
required: videoRequired,
|
required: videoRequired,
|
||||||
where: searchAttribute(options.searchVideo, 'name'),
|
where: searchAttribute(options.searchVideo, 'name'),
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
|
attributes: [ 'filename', 'fileUrl' ],
|
||||||
model: ThumbnailModel
|
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'),
|
where: searchAttribute(options.searchVideoChannel, 'name'),
|
||||||
required: true,
|
required: !!options.searchVideoChannel
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: AccountModel.scope(AccountScopeNames.SUMMARY),
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributes: [ 'id', 'reason', 'unfederated' ],
|
attributes: [ 'id', 'reason', 'unfederated' ],
|
||||||
|
@ -304,19 +281,19 @@ export class AbuseModel extends Model<AbuseModel> {
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Default(null)
|
@Default(null)
|
||||||
@Is('VideoAbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason'))
|
@Is('AbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason'))
|
||||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.REASON.max))
|
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.REASON.max))
|
||||||
reason: string
|
reason: string
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Default(null)
|
@Default(null)
|
||||||
@Is('VideoAbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state'))
|
@Is('AbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state'))
|
||||||
@Column
|
@Column
|
||||||
state: AbuseState
|
state: AbuseState
|
||||||
|
|
||||||
@AllowNull(true)
|
@AllowNull(true)
|
||||||
@Default(null)
|
@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))
|
@Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.MODERATION_COMMENT.max))
|
||||||
moderationComment: string
|
moderationComment: string
|
||||||
|
|
||||||
|
@ -486,12 +463,12 @@ export class AbuseModel extends Model<AbuseModel> {
|
||||||
|
|
||||||
toFormattedJSON (this: MAbuseFormattable): Abuse {
|
toFormattedJSON (this: MAbuseFormattable): Abuse {
|
||||||
const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
|
const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
|
||||||
|
|
||||||
const countReportsForVideo = this.get('countReportsForVideo') as number
|
const countReportsForVideo = this.get('countReportsForVideo') as number
|
||||||
const nthReportForVideo = this.get('nthReportForVideo') 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 countReportsForReporter = this.get('countReportsForReporter') as number
|
||||||
const countReportsForReporteeVideo = this.get('countReportsForReportee__video') as number
|
const countReportsForReportee = this.get('countReportsForReportee') as number
|
||||||
const countReportsForReporteeDeletedVideo = this.get('countReportsForReportee__deletedVideo') as number
|
|
||||||
|
|
||||||
let video: VideoAbuse
|
let video: VideoAbuse
|
||||||
let comment: VideoCommentAbuse
|
let comment: VideoCommentAbuse
|
||||||
|
@ -512,7 +489,11 @@ export class AbuseModel extends Model<AbuseModel> {
|
||||||
deleted: !abuseModel.Video,
|
deleted: !abuseModel.Video,
|
||||||
blacklisted: abuseModel.Video?.isBlacklisted() || false,
|
blacklisted: abuseModel.Video?.isBlacklisted() || false,
|
||||||
thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(),
|
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,
|
reason: this.reason,
|
||||||
predefinedReasons,
|
predefinedReasons,
|
||||||
|
|
||||||
reporterAccount: this.ReporterAccount.toFormattedJSON(),
|
reporterAccount: this.ReporterAccount
|
||||||
|
? this.ReporterAccount.toFormattedJSON()
|
||||||
|
: null,
|
||||||
|
|
||||||
|
flaggedAccount: this.FlaggedAccount
|
||||||
|
? this.FlaggedAccount.toFormattedJSON()
|
||||||
|
: null,
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
id: this.state,
|
id: this.state,
|
||||||
|
@ -553,14 +540,15 @@ export class AbuseModel extends Model<AbuseModel> {
|
||||||
|
|
||||||
createdAt: this.createdAt,
|
createdAt: this.createdAt,
|
||||||
updatedAt: this.updatedAt,
|
updatedAt: this.updatedAt,
|
||||||
count: countReportsForVideo || 0,
|
|
||||||
nth: nthReportForVideo || 0,
|
countReportsForReporter: (countReportsForReporter || 0),
|
||||||
countReportsForReporter: (countReportsForReporterVideo || 0) + (countReportsForReporterDeletedVideo || 0),
|
countReportsForReportee: (countReportsForReportee || 0),
|
||||||
countReportsForReportee: (countReportsForReporteeVideo || 0) + (countReportsForReporteeDeletedVideo || 0),
|
|
||||||
|
|
||||||
// FIXME: deprecated in 2.3, remove this
|
// FIXME: deprecated in 2.3, remove this
|
||||||
startAt: null,
|
startAt: null,
|
||||||
endAt: null
|
endAt: null,
|
||||||
|
count: countReportsForVideo || 0,
|
||||||
|
nth: nthReportForVideo || 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ export enum ScopeNames {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SummaryOptions = {
|
export type SummaryOptions = {
|
||||||
|
actorRequired?: boolean // Default: true
|
||||||
whereActor?: WhereOptions
|
whereActor?: WhereOptions
|
||||||
withAccountBlockerIds?: number[]
|
withAccountBlockerIds?: number[]
|
||||||
}
|
}
|
||||||
|
@ -65,12 +66,12 @@ export type SummaryOptions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const query: FindOptions = {
|
const query: FindOptions = {
|
||||||
attributes: [ 'id', 'name' ],
|
attributes: [ 'id', 'name', 'actorId' ],
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
||||||
model: ActorModel.unscoped(),
|
model: ActorModel.unscoped(),
|
||||||
required: true,
|
required: options.actorRequired ?? true,
|
||||||
where: whereActor,
|
where: whereActor,
|
||||||
include: [
|
include: [
|
||||||
serverInclude,
|
serverInclude,
|
||||||
|
|
|
@ -51,11 +51,11 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Default(null)
|
@Default(null)
|
||||||
@Is(
|
@Is(
|
||||||
'UserNotificationSettingVideoAbuseAsModerator',
|
'UserNotificationSettingAbuseAsModerator',
|
||||||
value => throwIfNotValid(value, isUserNotificationSettingValid, 'videoAbuseAsModerator')
|
value => throwIfNotValid(value, isUserNotificationSettingValid, 'abuseAsModerator')
|
||||||
)
|
)
|
||||||
@Column
|
@Column
|
||||||
videoAbuseAsModerator: UserNotificationSettingValue
|
abuseAsModerator: UserNotificationSettingValue
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Default(null)
|
@Default(null)
|
||||||
|
@ -166,7 +166,7 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM
|
||||||
return {
|
return {
|
||||||
newCommentOnMyVideo: this.newCommentOnMyVideo,
|
newCommentOnMyVideo: this.newCommentOnMyVideo,
|
||||||
newVideoFromSubscription: this.newVideoFromSubscription,
|
newVideoFromSubscription: this.newVideoFromSubscription,
|
||||||
videoAbuseAsModerator: this.videoAbuseAsModerator,
|
abuseAsModerator: this.abuseAsModerator,
|
||||||
videoAutoBlacklistAsModerator: this.videoAutoBlacklistAsModerator,
|
videoAutoBlacklistAsModerator: this.videoAutoBlacklistAsModerator,
|
||||||
blacklistOnMyVideo: this.blacklistOnMyVideo,
|
blacklistOnMyVideo: this.blacklistOnMyVideo,
|
||||||
myVideoPublished: this.myVideoPublished,
|
myVideoPublished: this.myVideoPublished,
|
||||||
|
|
|
@ -168,28 +168,26 @@ enum ScopeNames {
|
||||||
'(' +
|
'(' +
|
||||||
`SELECT concat_ws(':', "abuses", "acceptedAbuses") ` +
|
`SELECT concat_ws(':', "abuses", "acceptedAbuses") ` +
|
||||||
'FROM (' +
|
'FROM (' +
|
||||||
'SELECT COUNT("videoAbuse"."id") AS "abuses", ' +
|
'SELECT COUNT("abuse"."id") AS "abuses", ' +
|
||||||
`COUNT("videoAbuse"."id") FILTER (WHERE "videoAbuse"."state" = ${AbuseState.ACCEPTED}) AS "acceptedAbuses" ` +
|
`COUNT("abuse"."id") FILTER (WHERE "abuse"."state" = ${AbuseState.ACCEPTED}) AS "acceptedAbuses" ` +
|
||||||
'FROM "videoAbuse" ' +
|
'FROM "abuse" ' +
|
||||||
'INNER JOIN "video" ON "videoAbuse"."videoId" = "video"."id" ' +
|
'INNER JOIN "account" ON "account"."id" = "abuse"."flaggedAccountId" ' +
|
||||||
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
|
||||||
'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
|
|
||||||
'WHERE "account"."userId" = "UserModel"."id"' +
|
'WHERE "account"."userId" = "UserModel"."id"' +
|
||||||
') t' +
|
') t' +
|
||||||
')'
|
')'
|
||||||
),
|
),
|
||||||
'videoAbusesCount'
|
'abusesCount'
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
literal(
|
literal(
|
||||||
'(' +
|
'(' +
|
||||||
'SELECT COUNT("videoAbuse"."id") ' +
|
'SELECT COUNT("abuse"."id") ' +
|
||||||
'FROM "videoAbuse" ' +
|
'FROM "abuse" ' +
|
||||||
'INNER JOIN "account" ON "account"."id" = "videoAbuse"."reporterAccountId" ' +
|
'INNER JOIN "account" ON "account"."id" = "abuse"."reporterAccountId" ' +
|
||||||
'WHERE "account"."userId" = "UserModel"."id"' +
|
'WHERE "account"."userId" = "UserModel"."id"' +
|
||||||
')'
|
')'
|
||||||
),
|
),
|
||||||
'videoAbusesCreatedCount'
|
'abusesCreatedCount'
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
literal(
|
literal(
|
||||||
|
@ -780,8 +778,8 @@ export class UserModel extends Model<UserModel> {
|
||||||
const videoQuotaUsed = this.get('videoQuotaUsed')
|
const videoQuotaUsed = this.get('videoQuotaUsed')
|
||||||
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
|
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
|
||||||
const videosCount = this.get('videosCount')
|
const videosCount = this.get('videosCount')
|
||||||
const [ videoAbusesCount, videoAbusesAcceptedCount ] = (this.get('videoAbusesCount') as string || ':').split(':')
|
const [ abusesCount, abusesAcceptedCount ] = (this.get('abusesCount') as string || ':').split(':')
|
||||||
const videoAbusesCreatedCount = this.get('videoAbusesCreatedCount')
|
const abusesCreatedCount = this.get('abusesCreatedCount')
|
||||||
const videoCommentsCount = this.get('videoCommentsCount')
|
const videoCommentsCount = this.get('videoCommentsCount')
|
||||||
|
|
||||||
const json: User = {
|
const json: User = {
|
||||||
|
@ -815,14 +813,14 @@ export class UserModel extends Model<UserModel> {
|
||||||
videosCount: videosCount !== undefined
|
videosCount: videosCount !== undefined
|
||||||
? parseInt(videosCount + '', 10)
|
? parseInt(videosCount + '', 10)
|
||||||
: undefined,
|
: undefined,
|
||||||
videoAbusesCount: videoAbusesCount
|
abusesCount: abusesCount
|
||||||
? parseInt(videoAbusesCount, 10)
|
? parseInt(abusesCount, 10)
|
||||||
: undefined,
|
: undefined,
|
||||||
videoAbusesAcceptedCount: videoAbusesAcceptedCount
|
abusesAcceptedCount: abusesAcceptedCount
|
||||||
? parseInt(videoAbusesAcceptedCount, 10)
|
? parseInt(abusesAcceptedCount, 10)
|
||||||
: undefined,
|
: undefined,
|
||||||
videoAbusesCreatedCount: videoAbusesCreatedCount !== undefined
|
abusesCreatedCount: abusesCreatedCount !== undefined
|
||||||
? parseInt(videoAbusesCreatedCount + '', 10)
|
? parseInt(abusesCreatedCount + '', 10)
|
||||||
: undefined,
|
: undefined,
|
||||||
videoCommentsCount: videoCommentsCount !== undefined
|
videoCommentsCount: videoCommentsCount !== undefined
|
||||||
? parseInt(videoCommentsCount + '', 10)
|
? parseInt(videoCommentsCount + '', 10)
|
||||||
|
|
|
@ -61,6 +61,7 @@ type AvailableWithStatsOptions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SummaryOptions = {
|
export type SummaryOptions = {
|
||||||
|
actorRequired?: boolean // Default: true
|
||||||
withAccount?: boolean // Default: false
|
withAccount?: boolean // Default: false
|
||||||
withAccountBlockerIds?: number[]
|
withAccountBlockerIds?: number[]
|
||||||
}
|
}
|
||||||
|
@ -121,7 +122,7 @@ export type SummaryOptions = {
|
||||||
{
|
{
|
||||||
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
|
||||||
model: ActorModel.unscoped(),
|
model: ActorModel.unscoped(),
|
||||||
required: true,
|
required: options.actorRequired ?? true,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
attributes: [ 'host' ],
|
attributes: [ 'host' ],
|
||||||
|
|
|
@ -164,7 +164,7 @@ describe('Test user notifications API validators', function () {
|
||||||
const correctFields: UserNotificationSetting = {
|
const correctFields: UserNotificationSetting = {
|
||||||
newVideoFromSubscription: UserNotificationSettingValue.WEB,
|
newVideoFromSubscription: UserNotificationSettingValue.WEB,
|
||||||
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
||||||
videoAbuseAsModerator: UserNotificationSettingValue.WEB,
|
abuseAsModerator: UserNotificationSettingValue.WEB,
|
||||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB,
|
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB,
|
||||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB,
|
blacklistOnMyVideo: UserNotificationSettingValue.WEB,
|
||||||
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
set -eu
|
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)
|
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)
|
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
|
// Order of the tests we want to execute
|
||||||
import './activitypub'
|
import './activitypub'
|
||||||
import './check-params'
|
import './check-params'
|
||||||
|
import './moderation'
|
||||||
import './notifications'
|
import './notifications'
|
||||||
import './redundancy'
|
import './redundancy'
|
||||||
import './search'
|
import './search'
|
||||||
|
|
384
server/tests/api/moderation/abuses.ts
Normal file
384
server/tests/api/moderation/abuses.ts
Normal file
|
@ -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)
|
||||||
|
})
|
||||||
|
})
|
2
server/tests/api/moderation/index.ts
Normal file
2
server/tests/api/moderation/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './abuses'
|
||||||
|
export * from './blocklist'
|
|
@ -11,7 +11,7 @@ import {
|
||||||
MockInstancesIndex,
|
MockInstancesIndex,
|
||||||
registerUser,
|
registerUser,
|
||||||
removeVideoFromBlacklist,
|
removeVideoFromBlacklist,
|
||||||
reportVideoAbuse,
|
reportAbuse,
|
||||||
unfollow,
|
unfollow,
|
||||||
updateCustomConfig,
|
updateCustomConfig,
|
||||||
updateCustomSubConfig,
|
updateCustomSubConfig,
|
||||||
|
@ -74,12 +74,12 @@ describe('Test moderation notifications', function () {
|
||||||
|
|
||||||
const name = 'video for abuse ' + uuidv4()
|
const name = 'video for abuse ' + uuidv4()
|
||||||
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
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 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 () {
|
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 name = 'video for abuse ' + uuidv4()
|
||||||
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
|
||||||
const uuid = resVideo.body.video.uuid
|
const video = resVideo.body.video
|
||||||
|
|
||||||
await waitJobs(servers)
|
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 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 */
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
import * as chai from 'chai'
|
|
||||||
import 'mocha'
|
import 'mocha'
|
||||||
|
import * as chai from 'chai'
|
||||||
import {
|
import {
|
||||||
addVideoToBlacklist,
|
addVideoToBlacklist,
|
||||||
askResetPassword,
|
askResetPassword,
|
||||||
|
@ -11,7 +11,7 @@ import {
|
||||||
createUser,
|
createUser,
|
||||||
flushAndRunServer,
|
flushAndRunServer,
|
||||||
removeVideoFromBlacklist,
|
removeVideoFromBlacklist,
|
||||||
reportVideoAbuse,
|
reportAbuse,
|
||||||
resetPassword,
|
resetPassword,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
setAccessTokensToServers,
|
setAccessTokensToServers,
|
||||||
|
@ -30,10 +30,15 @@ describe('Test emails', function () {
|
||||||
let userId: number
|
let userId: number
|
||||||
let userId2: number
|
let userId2: number
|
||||||
let userAccessToken: string
|
let userAccessToken: string
|
||||||
|
|
||||||
let videoUUID: string
|
let videoUUID: string
|
||||||
|
let videoId: number
|
||||||
|
|
||||||
let videoUserUUID: string
|
let videoUserUUID: string
|
||||||
|
|
||||||
let verificationString: string
|
let verificationString: string
|
||||||
let verificationString2: string
|
let verificationString2: string
|
||||||
|
|
||||||
const emails: object[] = []
|
const emails: object[] = []
|
||||||
const user = {
|
const user = {
|
||||||
username: 'user_1',
|
username: 'user_1',
|
||||||
|
@ -76,6 +81,7 @@ describe('Test emails', function () {
|
||||||
}
|
}
|
||||||
const res = await uploadVideo(server.url, server.accessToken, attributes)
|
const res = await uploadVideo(server.url, server.accessToken, attributes)
|
||||||
videoUUID = res.body.video.uuid
|
videoUUID = res.body.video.uuid
|
||||||
|
videoId = res.body.video.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -179,7 +185,7 @@ describe('Test emails', function () {
|
||||||
this.timeout(10000)
|
this.timeout(10000)
|
||||||
|
|
||||||
const reason = 'my super bad reason'
|
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)
|
await waitJobs(server)
|
||||||
expect(emails).to.have.lengthOf(3)
|
expect(emails).to.have.lengthOf(3)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import './users-verification'
|
|
||||||
import './blocklist'
|
|
||||||
import './user-subscriptions'
|
import './user-subscriptions'
|
||||||
import './users'
|
import './users'
|
||||||
import './users-multiple-servers'
|
import './users-multiple-servers'
|
||||||
|
import './users-verification'
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
import * as chai from 'chai'
|
|
||||||
import 'mocha'
|
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 {
|
import {
|
||||||
addVideoCommentThread,
|
addVideoCommentThread,
|
||||||
blockUser,
|
blockUser,
|
||||||
|
@ -10,6 +11,7 @@ import {
|
||||||
createUser,
|
createUser,
|
||||||
deleteMe,
|
deleteMe,
|
||||||
flushAndRunServer,
|
flushAndRunServer,
|
||||||
|
getAbusesList,
|
||||||
getAccountRatings,
|
getAccountRatings,
|
||||||
getBlacklistedVideosList,
|
getBlacklistedVideosList,
|
||||||
getCustomConfig,
|
getCustomConfig,
|
||||||
|
@ -19,7 +21,6 @@ import {
|
||||||
getUserInformation,
|
getUserInformation,
|
||||||
getUsersList,
|
getUsersList,
|
||||||
getUsersListPaginationAndSort,
|
getUsersListPaginationAndSort,
|
||||||
getVideoAbusesList,
|
|
||||||
getVideoChannel,
|
getVideoChannel,
|
||||||
getVideosList,
|
getVideosList,
|
||||||
installPlugin,
|
installPlugin,
|
||||||
|
@ -29,15 +30,15 @@ import {
|
||||||
registerUserWithChannel,
|
registerUserWithChannel,
|
||||||
removeUser,
|
removeUser,
|
||||||
removeVideo,
|
removeVideo,
|
||||||
reportVideoAbuse,
|
reportAbuse,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
testImage,
|
testImage,
|
||||||
unblockUser,
|
unblockUser,
|
||||||
|
updateAbuse,
|
||||||
updateCustomSubConfig,
|
updateCustomSubConfig,
|
||||||
updateMyAvatar,
|
updateMyAvatar,
|
||||||
updateMyUser,
|
updateMyUser,
|
||||||
updateUser,
|
updateUser,
|
||||||
updateVideoAbuse,
|
|
||||||
uploadVideo,
|
uploadVideo,
|
||||||
userLogin,
|
userLogin,
|
||||||
waitJobs
|
waitJobs
|
||||||
|
@ -46,7 +47,6 @@ import { follow } from '../../../../shared/extra-utils/server/follows'
|
||||||
import { logout, serverLogin, setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
|
import { logout, serverLogin, setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
|
||||||
import { getMyVideos } from '../../../../shared/extra-utils/videos/videos'
|
import { getMyVideos } from '../../../../shared/extra-utils/videos/videos'
|
||||||
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
|
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
|
||||||
import { CustomConfig } from '@shared/models/server'
|
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
|
@ -302,10 +302,10 @@ describe('Test users', function () {
|
||||||
expect(userGet.videosCount).to.equal(0)
|
expect(userGet.videosCount).to.equal(0)
|
||||||
expect(userGet.videoCommentsCount).to.be.a('number')
|
expect(userGet.videoCommentsCount).to.be.a('number')
|
||||||
expect(userGet.videoCommentsCount).to.equal(0)
|
expect(userGet.videoCommentsCount).to.equal(0)
|
||||||
expect(userGet.videoAbusesCount).to.be.a('number')
|
expect(userGet.abusesCount).to.be.a('number')
|
||||||
expect(userGet.videoAbusesCount).to.equal(0)
|
expect(userGet.abusesCount).to.equal(0)
|
||||||
expect(userGet.videoAbusesAcceptedCount).to.be.a('number')
|
expect(userGet.abusesAcceptedCount).to.be.a('number')
|
||||||
expect(userGet.videoAbusesAcceptedCount).to.equal(0)
|
expect(userGet.abusesAcceptedCount).to.equal(0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -895,9 +895,9 @@ describe('Test users', function () {
|
||||||
|
|
||||||
expect(user.videosCount).to.equal(0)
|
expect(user.videosCount).to.equal(0)
|
||||||
expect(user.videoCommentsCount).to.equal(0)
|
expect(user.videoCommentsCount).to.equal(0)
|
||||||
expect(user.videoAbusesCount).to.equal(0)
|
expect(user.abusesCount).to.equal(0)
|
||||||
expect(user.videoAbusesCreatedCount).to.equal(0)
|
expect(user.abusesCreatedCount).to.equal(0)
|
||||||
expect(user.videoAbusesAcceptedCount).to.equal(0)
|
expect(user.abusesAcceptedCount).to.equal(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should report correct videos count', async function () {
|
it('Should report correct videos count', async function () {
|
||||||
|
@ -924,26 +924,26 @@ describe('Test users', function () {
|
||||||
expect(user.videoCommentsCount).to.equal(1)
|
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'
|
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 abuseId = res1.body.data[0].id
|
||||||
|
|
||||||
const res2 = await getUserInformation(server.url, server.accessToken, user17Id, true)
|
const res2 = await getUserInformation(server.url, server.accessToken, user17Id, true)
|
||||||
const user2: User = res2.body
|
const user2: User = res2.body
|
||||||
|
|
||||||
expect(user2.videoAbusesCount).to.equal(1) // number of incriminations
|
expect(user2.abusesCount).to.equal(1) // number of incriminations
|
||||||
expect(user2.videoAbusesCreatedCount).to.equal(1) // number of reports created
|
expect(user2.abusesCreatedCount).to.equal(1) // number of reports created
|
||||||
|
|
||||||
const body: AbuseUpdate = { state: AbuseState.ACCEPTED }
|
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 res3 = await getUserInformation(server.url, server.accessToken, user17Id, true)
|
||||||
const user3: User = res3.body
|
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.reporterAccount.host).to.equal('localhost:' + servers[0].port)
|
||||||
expect(abuse.video.id).to.equal(servers[0].video.id)
|
expect(abuse.video.id).to.equal(servers[0].video.id)
|
||||||
expect(abuse.video.channel).to.exist
|
expect(abuse.video.channel).to.exist
|
||||||
expect(abuse.count).to.equal(1)
|
expect(abuse.video.countReports).to.equal(1)
|
||||||
expect(abuse.nth).to.equal(1)
|
expect(abuse.video.nthReport).to.equal(1)
|
||||||
expect(abuse.countReportsForReporter).to.equal(1)
|
expect(abuse.countReportsForReporter).to.equal(1)
|
||||||
expect(abuse.countReportsForReportee).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.id).to.equal(AbuseState.PENDING)
|
||||||
expect(abuse1.state.label).to.equal('Pending')
|
expect(abuse1.state.label).to.equal('Pending')
|
||||||
expect(abuse1.moderationComment).to.be.null
|
expect(abuse1.moderationComment).to.be.null
|
||||||
expect(abuse1.count).to.equal(1)
|
expect(abuse1.video.countReports).to.equal(1)
|
||||||
expect(abuse1.nth).to.equal(1)
|
expect(abuse1.video.nthReport).to.equal(1)
|
||||||
|
|
||||||
const abuse2: Abuse = res1.body.data[1]
|
const abuse2: Abuse = res1.body.data[1]
|
||||||
expect(abuse2.reason).to.equal('my super bad reason 2')
|
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[]) {
|
for (const abuse of res2.body.data as Abuse[]) {
|
||||||
if (abuse.video.id === video3.id) {
|
if (abuse.video.id === video3.id) {
|
||||||
expect(abuse.count).to.equal(1, "wrong reports count for video 3")
|
expect(abuse.video.countReports).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.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.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")
|
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 =
|
export type MAbuseFormattable =
|
||||||
MAbuse &
|
MAbuse &
|
||||||
Use<'ReporterAccount', MAccountFormattable> &
|
Use<'ReporterAccount', MAccountFormattable> &
|
||||||
|
Use<'FlaggedAccount', MAccountFormattable> &
|
||||||
Use<'VideoAbuse', MVideoAbuseFormattable> &
|
Use<'VideoAbuse', MVideoAbuseFormattable> &
|
||||||
Use<'VideoCommentAbuse', MCommentAbuseFormattable>
|
Use<'VideoCommentAbuse', MCommentAbuseFormattable>
|
||||||
|
|
|
@ -516,7 +516,7 @@ function getAllNotificationsSettings () {
|
||||||
return {
|
return {
|
||||||
newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
videoAbuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
|
||||||
|
|
|
@ -18,6 +18,9 @@ export interface VideoAbuse {
|
||||||
|
|
||||||
thumbnailPath?: string
|
thumbnailPath?: string
|
||||||
channel?: VideoChannel
|
channel?: VideoChannel
|
||||||
|
|
||||||
|
countReports: number
|
||||||
|
nthReport: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VideoCommentAbuse {
|
export interface VideoCommentAbuse {
|
||||||
|
@ -36,9 +39,12 @@ export interface VideoCommentAbuse {
|
||||||
|
|
||||||
export interface Abuse {
|
export interface Abuse {
|
||||||
id: number
|
id: number
|
||||||
|
|
||||||
reason: string
|
reason: string
|
||||||
predefinedReasons?: AbusePredefinedReasonsString[]
|
predefinedReasons?: AbusePredefinedReasonsString[]
|
||||||
|
|
||||||
reporterAccount: Account
|
reporterAccount: Account
|
||||||
|
flaggedAccount: Account
|
||||||
|
|
||||||
state: VideoConstant<AbuseState>
|
state: VideoConstant<AbuseState>
|
||||||
moderationComment?: string
|
moderationComment?: string
|
||||||
|
@ -49,13 +55,18 @@ export interface Abuse {
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
|
|
||||||
// FIXME: deprecated in 2.3, remove this
|
|
||||||
startAt: null
|
|
||||||
endAt: null
|
|
||||||
|
|
||||||
count?: number
|
|
||||||
nth?: number
|
|
||||||
|
|
||||||
countReportsForReporter?: number
|
countReportsForReporter?: number
|
||||||
countReportsForReportee?: 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 {
|
export interface UserNotificationSetting {
|
||||||
newVideoFromSubscription: UserNotificationSettingValue
|
newVideoFromSubscription: UserNotificationSettingValue
|
||||||
newCommentOnMyVideo: UserNotificationSettingValue
|
newCommentOnMyVideo: UserNotificationSettingValue
|
||||||
videoAbuseAsModerator: UserNotificationSettingValue
|
abuseAsModerator: UserNotificationSettingValue
|
||||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue
|
videoAutoBlacklistAsModerator: UserNotificationSettingValue
|
||||||
blacklistOnMyVideo: UserNotificationSettingValue
|
blacklistOnMyVideo: UserNotificationSettingValue
|
||||||
myVideoPublished: UserNotificationSettingValue
|
myVideoPublished: UserNotificationSettingValue
|
||||||
|
|
|
@ -31,10 +31,13 @@ export interface User {
|
||||||
videoQuotaDaily: number
|
videoQuotaDaily: number
|
||||||
videoQuotaUsed?: number
|
videoQuotaUsed?: number
|
||||||
videoQuotaUsedDaily?: number
|
videoQuotaUsedDaily?: number
|
||||||
|
|
||||||
videosCount?: number
|
videosCount?: number
|
||||||
videoAbusesCount?: number
|
|
||||||
videoAbusesAcceptedCount?: number
|
abusesCount?: number
|
||||||
videoAbusesCreatedCount?: number
|
abusesAcceptedCount?: number
|
||||||
|
abusesCreatedCount?: number
|
||||||
|
|
||||||
videoCommentsCount? : number
|
videoCommentsCount? : number
|
||||||
|
|
||||||
theme: string
|
theme: string
|
||||||
|
|
|
@ -893,7 +893,7 @@ paths:
|
||||||
$ref: '#/components/schemas/NotificationSettingValue'
|
$ref: '#/components/schemas/NotificationSettingValue'
|
||||||
newCommentOnMyVideo:
|
newCommentOnMyVideo:
|
||||||
$ref: '#/components/schemas/NotificationSettingValue'
|
$ref: '#/components/schemas/NotificationSettingValue'
|
||||||
videoAbuseAsModerator:
|
abuseAsModerator:
|
||||||
$ref: '#/components/schemas/NotificationSettingValue'
|
$ref: '#/components/schemas/NotificationSettingValue'
|
||||||
videoAutoBlacklistAsModerator:
|
videoAutoBlacklistAsModerator:
|
||||||
$ref: '#/components/schemas/NotificationSettingValue'
|
$ref: '#/components/schemas/NotificationSettingValue'
|
||||||
|
@ -1618,7 +1618,7 @@ paths:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
state:
|
state:
|
||||||
$ref: '#/components/schemas/VideoAbuseStateSet'
|
$ref: '#/components/schemas/AbuseStateSet'
|
||||||
moderationComment:
|
moderationComment:
|
||||||
type: string
|
type: string
|
||||||
description: Update the report comment visible only to the moderation team
|
description: Update the report comment visible only to the moderation team
|
||||||
|
@ -3584,20 +3584,20 @@ components:
|
||||||
label:
|
label:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
VideoAbuseStateSet:
|
AbuseStateSet:
|
||||||
type: integer
|
type: integer
|
||||||
enum:
|
enum:
|
||||||
- 1
|
- 1
|
||||||
- 2
|
- 2
|
||||||
- 3
|
- 3
|
||||||
description: 'The video playlist privacy (Pending = `1`, Rejected = `2`, Accepted = `3`)'
|
description: 'The video playlist privacy (Pending = `1`, Rejected = `2`, Accepted = `3`)'
|
||||||
VideoAbuseStateConstant:
|
AbuseStateConstant:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: '#/components/schemas/VideoAbuseStateSet'
|
$ref: '#/components/schemas/AbuseStateSet'
|
||||||
label:
|
label:
|
||||||
type: string
|
type: string
|
||||||
VideoAbusePredefinedReasons:
|
AbusePredefinedReasons:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
@ -3960,11 +3960,11 @@ components:
|
||||||
type: string
|
type: string
|
||||||
example: The video is a spam
|
example: The video is a spam
|
||||||
predefinedReasons:
|
predefinedReasons:
|
||||||
$ref: '#/components/schemas/VideoAbusePredefinedReasons'
|
$ref: '#/components/schemas/AbusePredefinedReasons'
|
||||||
reporterAccount:
|
reporterAccount:
|
||||||
$ref: '#/components/schemas/Account'
|
$ref: '#/components/schemas/Account'
|
||||||
state:
|
state:
|
||||||
$ref: '#/components/schemas/VideoAbuseStateConstant'
|
$ref: '#/components/schemas/AbuseStateConstant'
|
||||||
moderationComment:
|
moderationComment:
|
||||||
type: string
|
type: string
|
||||||
example: Decided to ban the server since it spams us regularly
|
example: Decided to ban the server since it spams us regularly
|
||||||
|
@ -4690,11 +4690,11 @@ components:
|
||||||
description: The user daily video quota
|
description: The user daily video quota
|
||||||
videosCount:
|
videosCount:
|
||||||
type: integer
|
type: integer
|
||||||
videoAbusesCount:
|
abusesCount:
|
||||||
type: integer
|
type: integer
|
||||||
videoAbusesAcceptedCount:
|
abusesAcceptedCount:
|
||||||
type: integer
|
type: integer
|
||||||
videoAbusesCreatedCount:
|
abusesCreatedCount:
|
||||||
type: integer
|
type: integer
|
||||||
videoCommentsCount:
|
videoCommentsCount:
|
||||||
type: integer
|
type: integer
|
||||||
|
|
Loading…
Reference in New Issue
Block a user