]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/abuse/abuse.ts
Remove deprecated abuse api
[github/Chocobozzz/PeerTube.git] / server / models / abuse / abuse.ts
index 28ecf82533e4cec69048f7dabc98be4e8099b8ca..290270fe284305a6e78332694f8a2be847f6cd57 100644 (file)
@@ -1,6 +1,6 @@
 import * as Bluebird from 'bluebird'
 import { invert } from 'lodash'
-import { literal, Op, QueryTypes, WhereOptions } from 'sequelize'
+import { literal, Op, QueryTypes } from 'sequelize'
 import {
   AllowNull,
   BelongsTo,
@@ -17,27 +17,29 @@ import {
   UpdatedAt
 } from 'sequelize-typescript'
 import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses'
+import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse'
 import {
-  Abuse,
   AbuseFilter,
   AbuseObject,
   AbusePredefinedReasons,
-  abusePredefinedReasonsMap,
   AbusePredefinedReasonsString,
   AbuseState,
   AbuseVideoIs,
-  VideoAbuse,
-  VideoCommentAbuse
+  AdminAbuse,
+  AdminVideoAbuse,
+  AdminVideoCommentAbuse,
+  UserAbuse,
+  UserVideoAbuse
 } from '@shared/models'
 import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants'
-import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models'
+import { MAbuseAdminFormattable, MAbuseAP, MAbuseFull, MAbuseReporter, MAbuseUserFormattable, MUserAccountId } from '../../types/models'
 import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account'
 import { getSort, throwIfNotValid } from '../utils'
 import { ThumbnailModel } from '../video/thumbnail'
-import { VideoModel } from '../video/video'
+import { ScopeNames as VideoScopeNames, VideoModel } from '../video/video'
 import { VideoBlacklistModel } from '../video/video-blacklist'
 import { ScopeNames as VideoChannelScopeNames, SummaryOptions as ChannelSummaryOptions, VideoChannelModel } from '../video/video-channel'
-import { VideoCommentModel } from '../video/video-comment'
+import { ScopeNames as CommentScopeNames, VideoCommentModel } from '../video/video-comment'
 import { buildAbuseListQuery, BuildAbusesQueryOptions } from './abuse-query-builder'
 import { VideoAbuseModel } from './video-abuse'
 import { VideoCommentAbuseModel } from './video-comment-abuse'
@@ -51,6 +53,16 @@ export enum ScopeNames {
     return {
       attributes: {
         include: [
+          [
+            literal(
+              '(' +
+                'SELECT count(*) ' +
+                'FROM "abuseMessage" ' +
+                'WHERE "abuseId" = "AbuseModel"."id"' +
+              ')'
+            ),
+            'countMessages'
+          ],
           [
             // we don't care about this count for deleted videos, so there are not included
             literal(
@@ -140,7 +152,7 @@ export enum ScopeNames {
               model: VideoModel.unscoped(),
               include: [
                 {
-                  attributes: [ 'filename', 'fileUrl' ],
+                  attributes: [ 'filename', 'fileUrl', 'type' ],
                   model: ThumbnailModel
                 },
                 {
@@ -253,39 +265,69 @@ export class AbuseModel extends Model<AbuseModel> {
   })
   VideoAbuse: VideoAbuseModel
 
-  // FIXME: deprecated in 2.3. Remove these validators
-  static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MAbuse> {
-    const videoWhere: WhereOptions = {}
-
-    if (videoId) videoWhere.videoId = videoId
-    if (uuid) videoWhere.deletedVideo = { uuid }
-
+  static loadByIdWithReporter (id: number): Bluebird<MAbuseReporter> {
     const query = {
+      where: {
+        id
+      },
       include: [
         {
-          model: VideoAbuseModel,
-          required: true,
-          where: videoWhere
+          model: AccountModel,
+          as: 'ReporterAccount'
         }
-      ],
-      where: {
-        id
-      }
+      ]
     }
+
     return AbuseModel.findOne(query)
   }
 
-  static loadById (id: number): Bluebird<MAbuse> {
+  static loadFull (id: number): Bluebird<MAbuseFull> {
     const query = {
       where: {
         id
-      }
+      },
+      include: [
+        {
+          model: AccountModel.scope(AccountScopeNames.SUMMARY),
+          required: false,
+          as: 'ReporterAccount'
+        },
+        {
+          model: AccountModel.scope(AccountScopeNames.SUMMARY),
+          as: 'FlaggedAccount'
+        },
+        {
+          model: VideoAbuseModel,
+          required: false,
+          include: [
+            {
+              model: VideoModel.scope([ VideoScopeNames.WITH_ACCOUNT_DETAILS ])
+            }
+          ]
+        },
+        {
+          model: VideoCommentAbuseModel,
+          required: false,
+          include: [
+            {
+              model: VideoCommentModel.scope([
+                CommentScopeNames.WITH_ACCOUNT
+              ]),
+              include: [
+                {
+                  model: VideoModel
+                }
+              ]
+            }
+          ]
+        }
+      ]
     }
 
     return AbuseModel.findOne(query)
   }
 
-  static async listForApi (parameters: {
+  static async listForAdminApi (parameters: {
     start: number
     count: number
     sort: string
@@ -353,69 +395,98 @@ export class AbuseModel extends Model<AbuseModel> {
     return { total, data }
   }
 
-  toFormattedJSON (this: MAbuseFormattable): Abuse {
-    const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
+  static async listForUserApi (parameters: {
+    user: MUserAccountId
 
-    const countReportsForVideo = this.get('countReportsForVideo') as number
-    const nthReportForVideo = this.get('nthReportForVideo') as number
+    start: number
+    count: number
+    sort: string
 
-    const countReportsForReporter = this.get('countReportsForReporter') as number
-    const countReportsForReportee = this.get('countReportsForReportee') as number
+    id?: number
+    search?: string
+    state?: AbuseState
+  }) {
+    const {
+      start,
+      count,
+      sort,
+      search,
+      user,
+      state,
+      id
+    } = parameters
+
+    const queryOptions: BuildAbusesQueryOptions = {
+      start,
+      count,
+      sort,
+      id,
+      search,
+      state,
+      reporterAccountId: user.Account.id
+    }
+
+    const [ total, data ] = await Promise.all([
+      AbuseModel.internalCountForApi(queryOptions),
+      AbuseModel.internalListForApi(queryOptions)
+    ])
 
-    let video: VideoAbuse
-    let comment: VideoCommentAbuse
+    return { total, data }
+  }
 
-    if (this.VideoAbuse) {
-      const abuseModel = this.VideoAbuse
-      const entity = abuseModel.Video || abuseModel.deletedVideo
+  buildBaseVideoCommentAbuse (this: MAbuseUserFormattable) {
+    if (!this.VideoCommentAbuse) return null
 
-      video = {
-        id: entity.id,
-        uuid: entity.uuid,
-        name: entity.name,
-        nsfw: entity.nsfw,
+    const abuseModel = this.VideoCommentAbuse
+    const entity = abuseModel.VideoComment
 
-        startAt: abuseModel.startAt,
-        endAt: abuseModel.endAt,
+    return {
+      id: entity.id,
+      threadId: entity.getThreadId(),
 
-        deleted: !abuseModel.Video,
-        blacklisted: abuseModel.Video?.isBlacklisted() || false,
-        thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(),
+      text: entity.text ?? '',
 
-        channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel,
+      deleted: entity.isDeleted(),
 
-        countReports: countReportsForVideo,
-        nthReport: nthReportForVideo
+      video: {
+        id: entity.Video.id,
+        name: entity.Video.name,
+        uuid: entity.Video.uuid
       }
     }
+  }
+
+  buildBaseVideoAbuse (this: MAbuseUserFormattable): UserVideoAbuse {
+    if (!this.VideoAbuse) return null
 
-    if (this.VideoCommentAbuse) {
-      const abuseModel = this.VideoCommentAbuse
-      const entity = abuseModel.VideoComment || abuseModel.deletedComment
+    const abuseModel = this.VideoAbuse
+    const entity = abuseModel.Video || abuseModel.deletedVideo
 
-      comment = {
-        id: entity.id,
-        text: entity.text,
+    return {
+      id: entity.id,
+      uuid: entity.uuid,
+      name: entity.name,
+      nsfw: entity.nsfw,
 
-        deleted: !abuseModel.VideoComment,
+      startAt: abuseModel.startAt,
+      endAt: abuseModel.endAt,
 
-        video: {
-          id: entity.Video.id,
-          name: entity.Video.name,
-          uuid: entity.Video.uuid
-        }
-      }
+      deleted: !abuseModel.Video,
+      blacklisted: abuseModel.Video?.isBlacklisted() || false,
+      thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(),
+
+      channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel
     }
+  }
+
+  buildBaseAbuse (this: MAbuseUserFormattable, countMessages: number): UserAbuse {
+    const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
 
     return {
       id: this.id,
       reason: this.reason,
       predefinedReasons,
 
-      reporterAccount: this.ReporterAccount
-        ? this.ReporterAccount.toFormattedJSON()
-        : null,
-
       flaggedAccount: this.FlaggedAccount
         ? this.FlaggedAccount.toFormattedJSON()
         : null,
@@ -425,23 +496,60 @@ export class AbuseModel extends Model<AbuseModel> {
         label: AbuseModel.getStateLabel(this.state)
       },
 
-      moderationComment: this.moderationComment,
+      countMessages,
+
+      createdAt: this.createdAt,
+      updatedAt: this.updatedAt
+    }
+  }
+
+  toFormattedAdminJSON (this: MAbuseAdminFormattable): AdminAbuse {
+    const countReportsForVideo = this.get('countReportsForVideo') as number
+    const nthReportForVideo = this.get('nthReportForVideo') as number
+
+    const countReportsForReporter = this.get('countReportsForReporter') as number
+    const countReportsForReportee = this.get('countReportsForReportee') as number
+
+    const countMessages = this.get('countMessages') as number
+
+    const baseVideo = this.buildBaseVideoAbuse()
+    const video: AdminVideoAbuse = baseVideo
+      ? Object.assign(baseVideo, {
+        countReports: countReportsForVideo,
+        nthReport: nthReportForVideo
+      })
+      : null
+
+    const comment: AdminVideoCommentAbuse = this.buildBaseVideoCommentAbuse()
+
+    const abuse = this.buildBaseAbuse(countMessages || 0)
 
+    return Object.assign(abuse, {
       video,
       comment,
 
-      createdAt: this.createdAt,
-      updatedAt: this.updatedAt,
+      moderationComment: this.moderationComment,
+
+      reporterAccount: this.ReporterAccount
+        ? this.ReporterAccount.toFormattedJSON()
+        : null,
 
       countReportsForReporter: (countReportsForReporter || 0),
-      countReportsForReportee: (countReportsForReportee || 0),
+      countReportsForReportee: (countReportsForReportee || 0)
+    })
+  }
 
-      // FIXME: deprecated in 2.3, remove this
-      startAt: null,
-      endAt: null,
-      count: countReportsForVideo || 0,
-      nth: nthReportForVideo || 0
-    }
+  toFormattedUserJSON (this: MAbuseUserFormattable): UserAbuse {
+    const countMessages = this.get('countMessages') as number
+
+    const video = this.buildBaseVideoAbuse()
+    const comment = this.buildBaseVideoCommentAbuse()
+    const abuse = this.buildBaseAbuse(countMessages || 0)
+
+    return Object.assign(abuse, {
+      video,
+      comment
+    })
   }
 
   toActivityPubObject (this: MAbuseAP): AbuseObject {
@@ -506,8 +614,10 @@ export class AbuseModel extends Model<AbuseModel> {
   }
 
   private static getPredefinedReasonsStrings (predefinedReasons: AbusePredefinedReasons[]): AbusePredefinedReasonsString[] {
+    const invertedPredefinedReasons = invert(abusePredefinedReasonsMap)
+
     return (predefinedReasons || [])
-      .filter(r => r in AbusePredefinedReasons)
-      .map(r => invert(abusePredefinedReasonsMap)[r] as AbusePredefinedReasonsString)
+      .map(r => invertedPredefinedReasons[r] as AbusePredefinedReasonsString)
+      .filter(v => !!v)
   }
 }