Split types and typings
[oweals/peertube.git] / server / models / video / video-blacklist.ts
1 import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
2 import { getBlacklistSort, SortType, throwIfNotValid, searchAttribute } from '../utils'
3 import { VideoModel } from './video'
4 import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
5 import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist'
6 import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos'
7 import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
8 import { FindOptions } from 'sequelize'
9 import { ThumbnailModel } from './thumbnail'
10 import * as Bluebird from 'bluebird'
11 import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/types/models'
12
13 @Table({
14   tableName: 'videoBlacklist',
15   indexes: [
16     {
17       fields: [ 'videoId' ],
18       unique: true
19     }
20   ]
21 })
22 export class VideoBlacklistModel extends Model<VideoBlacklistModel> {
23
24   @AllowNull(true)
25   @Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason', true))
26   @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_BLACKLIST.REASON.max))
27   reason: string
28
29   @AllowNull(false)
30   @Column
31   unfederated: boolean
32
33   @AllowNull(false)
34   @Default(null)
35   @Is('VideoBlacklistType', value => throwIfNotValid(value, isVideoBlacklistTypeValid, 'type'))
36   @Column
37   type: VideoBlacklistType
38
39   @CreatedAt
40   createdAt: Date
41
42   @UpdatedAt
43   updatedAt: Date
44
45   @ForeignKey(() => VideoModel)
46   @Column
47   videoId: number
48
49   @BelongsTo(() => VideoModel, {
50     foreignKey: {
51       allowNull: false
52     },
53     onDelete: 'cascade'
54   })
55   Video: VideoModel
56
57   static listForApi (parameters: {
58     start: number
59     count: number
60     sort: SortType
61     search?: string
62     type?: VideoBlacklistType
63   }) {
64     const { start, count, sort, search, type } = parameters
65
66     function buildBaseQuery (): FindOptions {
67       return {
68         offset: start,
69         limit: count,
70         order: getBlacklistSort(sort.sortModel, sort.sortValue)
71       }
72     }
73
74     const countQuery = buildBaseQuery()
75
76     const findQuery = buildBaseQuery()
77     findQuery.include = [
78       {
79         model: VideoModel,
80         required: true,
81         where: searchAttribute(search, 'name'),
82         include: [
83           {
84             model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }),
85             required: true
86           },
87           {
88             model: ThumbnailModel,
89             attributes: [ 'type', 'filename' ],
90             required: false
91           }
92         ]
93       }
94     ]
95
96     if (type) {
97       countQuery.where = { type }
98       findQuery.where = { type }
99     }
100
101     return Promise.all([
102       VideoBlacklistModel.count(countQuery),
103       VideoBlacklistModel.findAll(findQuery)
104     ]).then(([ count, rows ]) => {
105       return {
106         data: rows,
107         total: count
108       }
109     })
110   }
111
112   static loadByVideoId (id: number): Bluebird<MVideoBlacklist> {
113     const query = {
114       where: {
115         videoId: id
116       }
117     }
118
119     return VideoBlacklistModel.findOne(query)
120   }
121
122   toFormattedJSON (this: MVideoBlacklistFormattable): VideoBlacklist {
123     return {
124       id: this.id,
125       createdAt: this.createdAt,
126       updatedAt: this.updatedAt,
127       reason: this.reason,
128       unfederated: this.unfederated,
129       type: this.type,
130
131       video: this.Video.toFormattedJSON()
132     }
133   }
134 }