diff options
author | Chocobozzz <me@florianbigard.com> | 2019-04-18 11:28:17 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-04-24 16:26:20 +0200 |
commit | 1735c825726edaa0af5035cb6cbb0cc0db502c6d (patch) | |
tree | 7bbb442f2cb4d7be58a4e08d87f5974403a3047c /server/models/video | |
parent | e8bafea35bc930cb8ac5b2d521a188642a1adffe (diff) | |
download | PeerTube-1735c825726edaa0af5035cb6cbb0cc0db502c6d.tar.gz PeerTube-1735c825726edaa0af5035cb6cbb0cc0db502c6d.tar.zst PeerTube-1735c825726edaa0af5035cb6cbb0cc0db502c6d.zip |
Update sequelize
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/schedule-video-update.ts | 8 | ||||
-rw-r--r-- | server/models/video/tag.ts | 8 | ||||
-rw-r--r-- | server/models/video/video-abuse.ts | 2 | ||||
-rw-r--r-- | server/models/video/video-blacklist.ts | 21 | ||||
-rw-r--r-- | server/models/video/video-caption.ts | 10 | ||||
-rw-r--r-- | server/models/video/video-change-ownership.ts | 2 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 17 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 47 | ||||
-rw-r--r-- | server/models/video/video-import.ts | 4 | ||||
-rw-r--r-- | server/models/video/video-playlist-element.ts | 20 | ||||
-rw-r--r-- | server/models/video/video-playlist.ts | 28 | ||||
-rw-r--r-- | server/models/video/video-streaming-playlist.ts | 18 | ||||
-rw-r--r-- | server/models/video/video.ts | 169 |
13 files changed, 175 insertions, 179 deletions
diff --git a/server/models/video/schedule-video-update.ts b/server/models/video/schedule-video-update.ts index abddc1111..b9e9ed9a0 100644 --- a/server/models/video/schedule-video-update.ts +++ b/server/models/video/schedule-video-update.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Sequelize, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { ScopeNames as VideoScopeNames, VideoModel } from './video' | 2 | import { ScopeNames as VideoScopeNames, VideoModel } from './video' |
3 | import { VideoPrivacy } from '../../../shared/models/videos' | 3 | import { VideoPrivacy } from '../../../shared/models/videos' |
4 | import { Transaction } from 'sequelize' | 4 | import { Op, Transaction } from 'sequelize' |
5 | 5 | ||
6 | @Table({ | 6 | @Table({ |
7 | tableName: 'scheduleVideoUpdate', | 7 | tableName: 'scheduleVideoUpdate', |
@@ -51,7 +51,7 @@ export class ScheduleVideoUpdateModel extends Model<ScheduleVideoUpdateModel> { | |||
51 | attributes: [ 'id' ], | 51 | attributes: [ 'id' ], |
52 | where: { | 52 | where: { |
53 | updateAt: { | 53 | updateAt: { |
54 | [Sequelize.Op.lte]: new Date() | 54 | [Op.lte]: new Date() |
55 | } | 55 | } |
56 | } | 56 | } |
57 | } | 57 | } |
@@ -64,7 +64,7 @@ export class ScheduleVideoUpdateModel extends Model<ScheduleVideoUpdateModel> { | |||
64 | const query = { | 64 | const query = { |
65 | where: { | 65 | where: { |
66 | updateAt: { | 66 | updateAt: { |
67 | [Sequelize.Op.lte]: new Date() | 67 | [Op.lte]: new Date() |
68 | } | 68 | } |
69 | }, | 69 | }, |
70 | include: [ | 70 | include: [ |
diff --git a/server/models/video/tag.ts b/server/models/video/tag.ts index b39621eaf..048b47613 100644 --- a/server/models/video/tag.ts +++ b/server/models/video/tag.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import * as Sequelize from 'sequelize' | 2 | import { QueryTypes, Transaction } from 'sequelize' |
3 | import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 3 | import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
4 | import { isVideoTagValid } from '../../helpers/custom-validators/videos' | 4 | import { isVideoTagValid } from '../../helpers/custom-validators/videos' |
5 | import { throwIfNotValid } from '../utils' | 5 | import { throwIfNotValid } from '../utils' |
@@ -37,7 +37,7 @@ export class TagModel extends Model<TagModel> { | |||
37 | }) | 37 | }) |
38 | Videos: VideoModel[] | 38 | Videos: VideoModel[] |
39 | 39 | ||
40 | static findOrCreateTags (tags: string[], transaction: Sequelize.Transaction) { | 40 | static findOrCreateTags (tags: string[], transaction: Transaction) { |
41 | if (tags === null) return [] | 41 | if (tags === null) return [] |
42 | 42 | ||
43 | const tasks: Bluebird<TagModel>[] = [] | 43 | const tasks: Bluebird<TagModel>[] = [] |
@@ -72,10 +72,10 @@ export class TagModel extends Model<TagModel> { | |||
72 | 72 | ||
73 | const options = { | 73 | const options = { |
74 | bind: { threshold, count, videoPrivacy: VideoPrivacy.PUBLIC, videoState: VideoState.PUBLISHED }, | 74 | bind: { threshold, count, videoPrivacy: VideoPrivacy.PUBLIC, videoState: VideoState.PUBLISHED }, |
75 | type: Sequelize.QueryTypes.SELECT | 75 | type: QueryTypes.SELECT as QueryTypes.SELECT |
76 | } | 76 | } |
77 | 77 | ||
78 | return TagModel.sequelize.query(query, options) | 78 | return TagModel.sequelize.query<{ name }>(query, options) |
79 | .then(data => data.map(d => d.name)) | 79 | .then(data => data.map(d => d.name)) |
80 | } | 80 | } |
81 | } | 81 | } |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index eacd651cc..1ac7919b3 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -39,7 +39,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
39 | 39 | ||
40 | @AllowNull(true) | 40 | @AllowNull(true) |
41 | @Default(null) | 41 | @Default(null) |
42 | @Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isVideoAbuseModerationCommentValid, 'moderationComment')) | 42 | @Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isVideoAbuseModerationCommentValid, 'moderationComment', true)) |
43 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max)) | 43 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max)) |
44 | moderationComment: string | 44 | moderationComment: string |
45 | 45 | ||
diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index 2619b4950..d9fe9dfc9 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts | |||
@@ -1,22 +1,11 @@ | |||
1 | import { | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | AllowNull, | ||
3 | BelongsTo, | ||
4 | Column, | ||
5 | CreatedAt, | ||
6 | DataType, | ||
7 | Default, | ||
8 | ForeignKey, | ||
9 | Is, Model, | ||
10 | Table, | ||
11 | UpdatedAt, | ||
12 | IFindOptions | ||
13 | } from 'sequelize-typescript' | ||
14 | import { getSortOnModel, SortType, throwIfNotValid } from '../utils' | 2 | import { getSortOnModel, SortType, throwIfNotValid } from '../utils' |
15 | import { VideoModel } from './video' | 3 | import { VideoModel } from './video' |
16 | import { VideoChannelModel, ScopeNames as VideoChannelScopeNames } from './video-channel' | 4 | import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel' |
17 | import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' | 5 | import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' |
18 | import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' | 6 | import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' |
19 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 7 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
8 | import { FindOptions } from 'sequelize' | ||
20 | 9 | ||
21 | @Table({ | 10 | @Table({ |
22 | tableName: 'videoBlacklist', | 11 | tableName: 'videoBlacklist', |
@@ -30,7 +19,7 @@ import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | |||
30 | export class VideoBlacklistModel extends Model<VideoBlacklistModel> { | 19 | export class VideoBlacklistModel extends Model<VideoBlacklistModel> { |
31 | 20 | ||
32 | @AllowNull(true) | 21 | @AllowNull(true) |
33 | @Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason')) | 22 | @Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason', true)) |
34 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_BLACKLIST.REASON.max)) | 23 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_BLACKLIST.REASON.max)) |
35 | reason: string | 24 | reason: string |
36 | 25 | ||
@@ -63,7 +52,7 @@ export class VideoBlacklistModel extends Model<VideoBlacklistModel> { | |||
63 | Video: VideoModel | 52 | Video: VideoModel |
64 | 53 | ||
65 | static listForApi (start: number, count: number, sort: SortType, type?: VideoBlacklistType) { | 54 | static listForApi (start: number, count: number, sort: SortType, type?: VideoBlacklistType) { |
66 | const query: IFindOptions<VideoBlacklistModel> = { | 55 | const query: FindOptions = { |
67 | offset: start, | 56 | offset: start, |
68 | limit: count, | 57 | limit: count, |
69 | order: getSortOnModel(sort.sortModel, sort.sortValue), | 58 | order: getSortOnModel(sort.sortModel, sort.sortValue), |
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index f2dbbfde8..45c60e26b 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import { OrderItem, Transaction } from 'sequelize' |
2 | import { | 2 | import { |
3 | AllowNull, | 3 | AllowNull, |
4 | BeforeDestroy, | 4 | BeforeDestroy, |
@@ -115,19 +115,19 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
115 | return VideoCaptionModel.findOne(query) | 115 | return VideoCaptionModel.findOne(query) |
116 | } | 116 | } |
117 | 117 | ||
118 | static insertOrReplaceLanguage (videoId: number, language: string, transaction: Sequelize.Transaction) { | 118 | static insertOrReplaceLanguage (videoId: number, language: string, transaction: Transaction) { |
119 | const values = { | 119 | const values = { |
120 | videoId, | 120 | videoId, |
121 | language | 121 | language |
122 | } | 122 | } |
123 | 123 | ||
124 | return VideoCaptionModel.upsert<VideoCaptionModel>(values, { transaction, returning: true }) | 124 | return (VideoCaptionModel.upsert<VideoCaptionModel>(values, { transaction, returning: true }) as any) // FIXME: typings |
125 | .then(([ caption ]) => caption) | 125 | .then(([ caption ]) => caption) |
126 | } | 126 | } |
127 | 127 | ||
128 | static listVideoCaptions (videoId: number) { | 128 | static listVideoCaptions (videoId: number) { |
129 | const query = { | 129 | const query = { |
130 | order: [ [ 'language', 'ASC' ] ], | 130 | order: [ [ 'language', 'ASC' ] ] as OrderItem[], |
131 | where: { | 131 | where: { |
132 | videoId | 132 | videoId |
133 | } | 133 | } |
@@ -140,7 +140,7 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
140 | return VIDEO_LANGUAGES[language] || 'Unknown' | 140 | return VIDEO_LANGUAGES[language] || 'Unknown' |
141 | } | 141 | } |
142 | 142 | ||
143 | static deleteAllCaptionsOfRemoteVideo (videoId: number, transaction: Sequelize.Transaction) { | 143 | static deleteAllCaptionsOfRemoteVideo (videoId: number, transaction: Transaction) { |
144 | const query = { | 144 | const query = { |
145 | where: { | 145 | where: { |
146 | videoId | 146 | videoId |
diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts index 85e688c4f..a4f4d53f1 100644 --- a/server/models/video/video-change-ownership.ts +++ b/server/models/video/video-change-ownership.ts | |||
@@ -43,7 +43,7 @@ enum ScopeNames { | |||
43 | { model: () => VideoFileModel } | 43 | { model: () => VideoFileModel } |
44 | ] | 44 | ] |
45 | } | 45 | } |
46 | ] | 46 | ] as any // FIXME: sequelize typings |
47 | } | 47 | } |
48 | }) | 48 | }) |
49 | export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel> { | 49 | export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel> { |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 5b5075344..901006dea 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -9,7 +9,6 @@ import { | |||
9 | DefaultScope, | 9 | DefaultScope, |
10 | ForeignKey, | 10 | ForeignKey, |
11 | HasMany, | 11 | HasMany, |
12 | IFindOptions, | ||
13 | Is, | 12 | Is, |
14 | Model, | 13 | Model, |
15 | Scopes, | 14 | Scopes, |
@@ -31,12 +30,12 @@ import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttr | |||
31 | import { VideoModel } from './video' | 30 | import { VideoModel } from './video' |
32 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' | 31 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' |
33 | import { ServerModel } from '../server/server' | 32 | import { ServerModel } from '../server/server' |
34 | import { DefineIndexesOptions } from 'sequelize' | 33 | import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' |
35 | import { AvatarModel } from '../avatar/avatar' | 34 | import { AvatarModel } from '../avatar/avatar' |
36 | import { VideoPlaylistModel } from './video-playlist' | 35 | import { VideoPlaylistModel } from './video-playlist' |
37 | 36 | ||
38 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 37 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
39 | const indexes: DefineIndexesOptions[] = [ | 38 | const indexes: ModelIndexesOptions[] = [ |
40 | buildTrigramSearchIndex('video_channel_name_trigram', 'name'), | 39 | buildTrigramSearchIndex('video_channel_name_trigram', 'name'), |
41 | 40 | ||
42 | { | 41 | { |
@@ -69,7 +68,7 @@ type AvailableForListOptions = { | |||
69 | }) | 68 | }) |
70 | @Scopes({ | 69 | @Scopes({ |
71 | [ScopeNames.SUMMARY]: (withAccount = false) => { | 70 | [ScopeNames.SUMMARY]: (withAccount = false) => { |
72 | const base: IFindOptions<VideoChannelModel> = { | 71 | const base: FindOptions = { |
73 | attributes: [ 'name', 'description', 'id', 'actorId' ], | 72 | attributes: [ 'name', 'description', 'id', 'actorId' ], |
74 | include: [ | 73 | include: [ |
75 | { | 74 | { |
@@ -112,13 +111,13 @@ type AvailableForListOptions = { | |||
112 | }, | 111 | }, |
113 | model: ActorModel, | 112 | model: ActorModel, |
114 | where: { | 113 | where: { |
115 | [Sequelize.Op.or]: [ | 114 | [Op.or]: [ |
116 | { | 115 | { |
117 | serverId: null | 116 | serverId: null |
118 | }, | 117 | }, |
119 | { | 118 | { |
120 | serverId: { | 119 | serverId: { |
121 | [ Sequelize.Op.in ]: Sequelize.literal(inQueryInstanceFollow) | 120 | [ Op.in ]: Sequelize.literal(inQueryInstanceFollow) |
122 | } | 121 | } |
123 | } | 122 | } |
124 | ] | 123 | ] |
@@ -172,13 +171,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
172 | 171 | ||
173 | @AllowNull(true) | 172 | @AllowNull(true) |
174 | @Default(null) | 173 | @Default(null) |
175 | @Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description')) | 174 | @Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description', true)) |
176 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.DESCRIPTION.max)) | 175 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.DESCRIPTION.max)) |
177 | description: string | 176 | description: string |
178 | 177 | ||
179 | @AllowNull(true) | 178 | @AllowNull(true) |
180 | @Default(null) | 179 | @Default(null) |
181 | @Is('VideoChannelSupport', value => throwIfNotValid(value, isVideoChannelSupportValid, 'support')) | 180 | @Is('VideoChannelSupport', value => throwIfNotValid(value, isVideoChannelSupportValid, 'support', true)) |
182 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.SUPPORT.max)) | 181 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.SUPPORT.max)) |
183 | support: string | 182 | support: string |
184 | 183 | ||
@@ -313,7 +312,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
313 | limit: options.count, | 312 | limit: options.count, |
314 | order: getSort(options.sort), | 313 | order: getSort(options.sort), |
315 | where: { | 314 | where: { |
316 | [Sequelize.Op.or]: [ | 315 | [Op.or]: [ |
317 | Sequelize.literal( | 316 | Sequelize.literal( |
318 | 'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))' | 317 | 'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))' |
319 | ), | 318 | ), |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index cb5f1cbbe..5f7cd3671 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import { | 1 | import { |
3 | AllowNull, | 2 | AllowNull, |
4 | BeforeDestroy, | 3 | BeforeDestroy, |
@@ -7,7 +6,6 @@ import { | |||
7 | CreatedAt, | 6 | CreatedAt, |
8 | DataType, | 7 | DataType, |
9 | ForeignKey, | 8 | ForeignKey, |
10 | IFindOptions, | ||
11 | Is, | 9 | Is, |
12 | Model, | 10 | Model, |
13 | Scopes, | 11 | Scopes, |
@@ -32,6 +30,7 @@ import { UserModel } from '../account/user' | |||
32 | import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' | 30 | import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' |
33 | import { regexpCapture } from '../../helpers/regexp' | 31 | import { regexpCapture } from '../../helpers/regexp' |
34 | import { uniq } from 'lodash' | 32 | import { uniq } from 'lodash' |
33 | import { FindOptions, Op, Order, Sequelize, Transaction } from 'sequelize' | ||
35 | 34 | ||
36 | enum ScopeNames { | 35 | enum ScopeNames { |
37 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 36 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
@@ -86,7 +85,7 @@ enum ScopeNames { | |||
86 | } | 85 | } |
87 | ] | 86 | ] |
88 | } | 87 | } |
89 | ] | 88 | ] as any // FIXME: sequelize typings |
90 | }, | 89 | }, |
91 | [ScopeNames.WITH_IN_REPLY_TO]: { | 90 | [ScopeNames.WITH_IN_REPLY_TO]: { |
92 | include: [ | 91 | include: [ |
@@ -120,7 +119,7 @@ enum ScopeNames { | |||
120 | } | 119 | } |
121 | ] | 120 | ] |
122 | } | 121 | } |
123 | ] | 122 | ] as any // FIXME: sequelize typings |
124 | } | 123 | } |
125 | }) | 124 | }) |
126 | @Table({ | 125 | @Table({ |
@@ -244,8 +243,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
244 | } | 243 | } |
245 | } | 244 | } |
246 | 245 | ||
247 | static loadById (id: number, t?: Sequelize.Transaction) { | 246 | static loadById (id: number, t?: Transaction) { |
248 | const query: IFindOptions<VideoCommentModel> = { | 247 | const query: FindOptions = { |
249 | where: { | 248 | where: { |
250 | id | 249 | id |
251 | } | 250 | } |
@@ -256,8 +255,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
256 | return VideoCommentModel.findOne(query) | 255 | return VideoCommentModel.findOne(query) |
257 | } | 256 | } |
258 | 257 | ||
259 | static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Sequelize.Transaction) { | 258 | static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction) { |
260 | const query: IFindOptions<VideoCommentModel> = { | 259 | const query: FindOptions = { |
261 | where: { | 260 | where: { |
262 | id | 261 | id |
263 | } | 262 | } |
@@ -270,8 +269,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
270 | .findOne(query) | 269 | .findOne(query) |
271 | } | 270 | } |
272 | 271 | ||
273 | static loadByUrlAndPopulateAccount (url: string, t?: Sequelize.Transaction) { | 272 | static loadByUrlAndPopulateAccount (url: string, t?: Transaction) { |
274 | const query: IFindOptions<VideoCommentModel> = { | 273 | const query: FindOptions = { |
275 | where: { | 274 | where: { |
276 | url | 275 | url |
277 | } | 276 | } |
@@ -282,8 +281,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
282 | return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT ]).findOne(query) | 281 | return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT ]).findOne(query) |
283 | } | 282 | } |
284 | 283 | ||
285 | static loadByUrlAndPopulateReplyAndVideo (url: string, t?: Sequelize.Transaction) { | 284 | static loadByUrlAndPopulateReplyAndVideo (url: string, t?: Transaction) { |
286 | const query: IFindOptions<VideoCommentModel> = { | 285 | const query: FindOptions = { |
287 | where: { | 286 | where: { |
288 | url | 287 | url |
289 | } | 288 | } |
@@ -307,7 +306,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
307 | videoId, | 306 | videoId, |
308 | inReplyToCommentId: null, | 307 | inReplyToCommentId: null, |
309 | accountId: { | 308 | accountId: { |
310 | [Sequelize.Op.notIn]: Sequelize.literal( | 309 | [Op.notIn]: Sequelize.literal( |
311 | '(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')' | 310 | '(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')' |
312 | ) | 311 | ) |
313 | } | 312 | } |
@@ -336,15 +335,15 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
336 | const userAccountId = user ? user.Account.id : undefined | 335 | const userAccountId = user ? user.Account.id : undefined |
337 | 336 | ||
338 | const query = { | 337 | const query = { |
339 | order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ], | 338 | order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order, |
340 | where: { | 339 | where: { |
341 | videoId, | 340 | videoId, |
342 | [ Sequelize.Op.or ]: [ | 341 | [ Op.or ]: [ |
343 | { id: threadId }, | 342 | { id: threadId }, |
344 | { originCommentId: threadId } | 343 | { originCommentId: threadId } |
345 | ], | 344 | ], |
346 | accountId: { | 345 | accountId: { |
347 | [Sequelize.Op.notIn]: Sequelize.literal( | 346 | [Op.notIn]: Sequelize.literal( |
348 | '(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')' | 347 | '(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')' |
349 | ) | 348 | ) |
350 | } | 349 | } |
@@ -366,12 +365,12 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
366 | }) | 365 | }) |
367 | } | 366 | } |
368 | 367 | ||
369 | static listThreadParentComments (comment: VideoCommentModel, t: Sequelize.Transaction, order: 'ASC' | 'DESC' = 'ASC') { | 368 | static listThreadParentComments (comment: VideoCommentModel, t: Transaction, order: 'ASC' | 'DESC' = 'ASC') { |
370 | const query = { | 369 | const query = { |
371 | order: [ [ 'createdAt', order ] ], | 370 | order: [ [ 'createdAt', order ] ] as Order, |
372 | where: { | 371 | where: { |
373 | id: { | 372 | id: { |
374 | [ Sequelize.Op.in ]: Sequelize.literal('(' + | 373 | [ Op.in ]: Sequelize.literal('(' + |
375 | 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + | 374 | 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + |
376 | `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + | 375 | `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + |
377 | 'UNION ' + | 376 | 'UNION ' + |
@@ -380,7 +379,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
380 | ') ' + | 379 | ') ' + |
381 | 'SELECT id FROM children' + | 380 | 'SELECT id FROM children' + |
382 | ')'), | 381 | ')'), |
383 | [ Sequelize.Op.ne ]: comment.id | 382 | [ Op.ne ]: comment.id |
384 | } | 383 | } |
385 | }, | 384 | }, |
386 | transaction: t | 385 | transaction: t |
@@ -391,9 +390,9 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
391 | .findAll(query) | 390 | .findAll(query) |
392 | } | 391 | } |
393 | 392 | ||
394 | static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Sequelize.Transaction, order: 'ASC' | 'DESC' = 'ASC') { | 393 | static listAndCountByVideoId (videoId: number, start: number, count: number, t?: Transaction, order: 'ASC' | 'DESC' = 'ASC') { |
395 | const query = { | 394 | const query = { |
396 | order: [ [ 'createdAt', order ] ], | 395 | order: [ [ 'createdAt', order ] ] as Order, |
397 | offset: start, | 396 | offset: start, |
398 | limit: count, | 397 | limit: count, |
399 | where: { | 398 | where: { |
@@ -407,7 +406,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
407 | 406 | ||
408 | static listForFeed (start: number, count: number, videoId?: number) { | 407 | static listForFeed (start: number, count: number, videoId?: number) { |
409 | const query = { | 408 | const query = { |
410 | order: [ [ 'createdAt', 'DESC' ] ], | 409 | order: [ [ 'createdAt', 'DESC' ] ] as Order, |
411 | offset: start, | 410 | offset: start, |
412 | limit: count, | 411 | limit: count, |
413 | where: {}, | 412 | where: {}, |
@@ -457,7 +456,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
457 | const query = { | 456 | const query = { |
458 | where: { | 457 | where: { |
459 | updatedAt: { | 458 | updatedAt: { |
460 | [Sequelize.Op.lt]: beforeUpdatedAt | 459 | [Op.lt]: beforeUpdatedAt |
461 | }, | 460 | }, |
462 | videoId | 461 | videoId |
463 | } | 462 | } |
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index ec10085d6..588a13a4f 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts | |||
@@ -55,13 +55,13 @@ export class VideoImportModel extends Model<VideoImportModel> { | |||
55 | 55 | ||
56 | @AllowNull(true) | 56 | @AllowNull(true) |
57 | @Default(null) | 57 | @Default(null) |
58 | @Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl')) | 58 | @Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl', true)) |
59 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) | 59 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) |
60 | targetUrl: string | 60 | targetUrl: string |
61 | 61 | ||
62 | @AllowNull(true) | 62 | @AllowNull(true) |
63 | @Default(null) | 63 | @Default(null) |
64 | @Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri')) | 64 | @Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri', true)) |
65 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) // Use the same constraints than URLs | 65 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) // Use the same constraints than URLs |
66 | magnetUri: string | 66 | magnetUri: string |
67 | 67 | ||
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index 3396b1136..eeb3d6bbd 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts | |||
@@ -15,12 +15,12 @@ import { | |||
15 | } from 'sequelize-typescript' | 15 | } from 'sequelize-typescript' |
16 | import { VideoModel } from './video' | 16 | import { VideoModel } from './video' |
17 | import { VideoPlaylistModel } from './video-playlist' | 17 | import { VideoPlaylistModel } from './video-playlist' |
18 | import * as Sequelize from 'sequelize' | ||
19 | import { getSort, throwIfNotValid } from '../utils' | 18 | import { getSort, throwIfNotValid } from '../utils' |
20 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 19 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
21 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 20 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
22 | import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' | 21 | import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' |
23 | import * as validator from 'validator' | 22 | import * as validator from 'validator' |
23 | import { AggregateOptions, Op, Sequelize, Transaction } from 'sequelize' | ||
24 | 24 | ||
25 | @Table({ | 25 | @Table({ |
26 | tableName: 'videoPlaylistElement', | 26 | tableName: 'videoPlaylistElement', |
@@ -96,7 +96,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
96 | }) | 96 | }) |
97 | Video: VideoModel | 97 | Video: VideoModel |
98 | 98 | ||
99 | static deleteAllOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) { | 99 | static deleteAllOf (videoPlaylistId: number, transaction?: Transaction) { |
100 | const query = { | 100 | const query = { |
101 | where: { | 101 | where: { |
102 | videoPlaylistId | 102 | videoPlaylistId |
@@ -140,7 +140,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
140 | return VideoPlaylistElementModel.findOne(query) | 140 | return VideoPlaylistElementModel.findOne(query) |
141 | } | 141 | } |
142 | 142 | ||
143 | static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number, t?: Sequelize.Transaction) { | 143 | static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number, t?: Transaction) { |
144 | const query = { | 144 | const query = { |
145 | attributes: [ 'url' ], | 145 | attributes: [ 'url' ], |
146 | offset: start, | 146 | offset: start, |
@@ -159,8 +159,8 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
159 | }) | 159 | }) |
160 | } | 160 | } |
161 | 161 | ||
162 | static getNextPositionOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) { | 162 | static getNextPositionOf (videoPlaylistId: number, transaction?: Transaction) { |
163 | const query = { | 163 | const query: AggregateOptions<number> = { |
164 | where: { | 164 | where: { |
165 | videoPlaylistId | 165 | videoPlaylistId |
166 | }, | 166 | }, |
@@ -176,14 +176,14 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
176 | firstPosition: number, | 176 | firstPosition: number, |
177 | endPosition: number, | 177 | endPosition: number, |
178 | newPosition: number, | 178 | newPosition: number, |
179 | transaction?: Sequelize.Transaction | 179 | transaction?: Transaction |
180 | ) { | 180 | ) { |
181 | const query = { | 181 | const query = { |
182 | where: { | 182 | where: { |
183 | videoPlaylistId, | 183 | videoPlaylistId, |
184 | position: { | 184 | position: { |
185 | [Sequelize.Op.gte]: firstPosition, | 185 | [Op.gte]: firstPosition, |
186 | [Sequelize.Op.lte]: endPosition | 186 | [Op.lte]: endPosition |
187 | } | 187 | } |
188 | }, | 188 | }, |
189 | transaction, | 189 | transaction, |
@@ -198,13 +198,13 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
198 | fromPosition: number, | 198 | fromPosition: number, |
199 | toPosition?: number, | 199 | toPosition?: number, |
200 | by = 1, | 200 | by = 1, |
201 | transaction?: Sequelize.Transaction | 201 | transaction?: Transaction |
202 | ) { | 202 | ) { |
203 | const query = { | 203 | const query = { |
204 | where: { | 204 | where: { |
205 | videoPlaylistId, | 205 | videoPlaylistId, |
206 | position: { | 206 | position: { |
207 | [Sequelize.Op.gte]: fromPosition | 207 | [Op.gte]: fromPosition |
208 | } | 208 | } |
209 | }, | 209 | }, |
210 | transaction | 210 | transaction |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index 073609c24..3e436acfc 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -15,7 +15,6 @@ import { | |||
15 | Table, | 15 | Table, |
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import * as Sequelize from 'sequelize' | ||
19 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' | 18 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' |
20 | import { buildServerIdsFollowedBy, buildWhereIdOrUUID, getSort, isOutdated, throwIfNotValid } from '../utils' | 19 | import { buildServerIdsFollowedBy, buildWhereIdOrUUID, getSort, isOutdated, throwIfNotValid } from '../utils' |
21 | import { | 20 | import { |
@@ -43,6 +42,7 @@ import { activityPubCollectionPagination } from '../../helpers/activitypub' | |||
43 | import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model' | 42 | import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model' |
44 | import { ThumbnailModel } from './thumbnail' | 43 | import { ThumbnailModel } from './thumbnail' |
45 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' | 44 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' |
45 | import { fn, literal, Op, Transaction } from 'sequelize' | ||
46 | 46 | ||
47 | enum ScopeNames { | 47 | enum ScopeNames { |
48 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', | 48 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', |
@@ -74,7 +74,11 @@ type AvailableForListOptions = { | |||
74 | attributes: { | 74 | attributes: { |
75 | include: [ | 75 | include: [ |
76 | [ | 76 | [ |
77 | Sequelize.literal('(SELECT COUNT("id") FROM "videoPlaylistElement" WHERE "videoPlaylistId" = "VideoPlaylistModel"."id")'), | 77 | fn('COUNT', 'toto'), |
78 | 'coucou' | ||
79 | ], | ||
80 | [ | ||
81 | literal('(SELECT COUNT("id") FROM "videoPlaylistElement" WHERE "videoPlaylistId" = "VideoPlaylistModel"."id")'), | ||
78 | 'videosLength' | 82 | 'videosLength' |
79 | ] | 83 | ] |
80 | ] | 84 | ] |
@@ -116,13 +120,13 @@ type AvailableForListOptions = { | |||
116 | // Only list local playlists OR playlists that are on an instance followed by actorId | 120 | // Only list local playlists OR playlists that are on an instance followed by actorId |
117 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) | 121 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) |
118 | const actorWhere = { | 122 | const actorWhere = { |
119 | [ Sequelize.Op.or ]: [ | 123 | [ Op.or ]: [ |
120 | { | 124 | { |
121 | serverId: null | 125 | serverId: null |
122 | }, | 126 | }, |
123 | { | 127 | { |
124 | serverId: { | 128 | serverId: { |
125 | [ Sequelize.Op.in ]: Sequelize.literal(inQueryInstanceFollow) | 129 | [ Op.in ]: literal(inQueryInstanceFollow) |
126 | } | 130 | } |
127 | } | 131 | } |
128 | ] | 132 | ] |
@@ -155,7 +159,7 @@ type AvailableForListOptions = { | |||
155 | } | 159 | } |
156 | 160 | ||
157 | const where = { | 161 | const where = { |
158 | [Sequelize.Op.and]: whereAnd | 162 | [Op.and]: whereAnd |
159 | } | 163 | } |
160 | 164 | ||
161 | const accountScope = { | 165 | const accountScope = { |
@@ -206,7 +210,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
206 | name: string | 210 | name: string |
207 | 211 | ||
208 | @AllowNull(true) | 212 | @AllowNull(true) |
209 | @Is('VideoPlaylistDescription', value => throwIfNotValid(value, isVideoPlaylistDescriptionValid, 'description')) | 213 | @Is('VideoPlaylistDescription', value => throwIfNotValid(value, isVideoPlaylistDescriptionValid, 'description', true)) |
210 | @Column | 214 | @Column |
211 | description: string | 215 | description: string |
212 | 216 | ||
@@ -344,7 +348,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
344 | model: VideoPlaylistElementModel.unscoped(), | 348 | model: VideoPlaylistElementModel.unscoped(), |
345 | where: { | 349 | where: { |
346 | videoId: { | 350 | videoId: { |
347 | [Sequelize.Op.any]: videoIds | 351 | [Op.any]: videoIds |
348 | } | 352 | } |
349 | }, | 353 | }, |
350 | required: true | 354 | required: true |
@@ -368,7 +372,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
368 | .then(e => !!e) | 372 | .then(e => !!e) |
369 | } | 373 | } |
370 | 374 | ||
371 | static loadWithAccountAndChannelSummary (id: number | string, transaction: Sequelize.Transaction) { | 375 | static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction) { |
372 | const where = buildWhereIdOrUUID(id) | 376 | const where = buildWhereIdOrUUID(id) |
373 | 377 | ||
374 | const query = { | 378 | const query = { |
@@ -381,7 +385,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
381 | .findOne(query) | 385 | .findOne(query) |
382 | } | 386 | } |
383 | 387 | ||
384 | static loadWithAccountAndChannel (id: number | string, transaction: Sequelize.Transaction) { | 388 | static loadWithAccountAndChannel (id: number | string, transaction: Transaction) { |
385 | const where = buildWhereIdOrUUID(id) | 389 | const where = buildWhereIdOrUUID(id) |
386 | 390 | ||
387 | const query = { | 391 | const query = { |
@@ -412,7 +416,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
412 | return VIDEO_PLAYLIST_TYPES[type] || 'Unknown' | 416 | return VIDEO_PLAYLIST_TYPES[type] || 'Unknown' |
413 | } | 417 | } |
414 | 418 | ||
415 | static resetPlaylistsOfChannel (videoChannelId: number, transaction: Sequelize.Transaction) { | 419 | static resetPlaylistsOfChannel (videoChannelId: number, transaction: Transaction) { |
416 | const query = { | 420 | const query = { |
417 | where: { | 421 | where: { |
418 | videoChannelId | 422 | videoChannelId |
@@ -489,7 +493,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
489 | label: VideoPlaylistModel.getTypeLabel(this.type) | 493 | label: VideoPlaylistModel.getTypeLabel(this.type) |
490 | }, | 494 | }, |
491 | 495 | ||
492 | videosLength: this.get('videosLength'), | 496 | videosLength: this.get('videosLength') as number, |
493 | 497 | ||
494 | createdAt: this.createdAt, | 498 | createdAt: this.createdAt, |
495 | updatedAt: this.updatedAt, | 499 | updatedAt: this.updatedAt, |
@@ -499,7 +503,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
499 | } | 503 | } |
500 | } | 504 | } |
501 | 505 | ||
502 | toActivityPubObject (page: number, t: Sequelize.Transaction): Promise<PlaylistObject> { | 506 | toActivityPubObject (page: number, t: Transaction): Promise<PlaylistObject> { |
503 | const handler = (start: number, count: number) => { | 507 | const handler = (start: number, count: number) => { |
504 | return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t) | 508 | return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t) |
505 | } | 509 | } |
diff --git a/server/models/video/video-streaming-playlist.ts b/server/models/video/video-streaming-playlist.ts index e50b5d106..b30267e09 100644 --- a/server/models/video/video-streaming-playlist.ts +++ b/server/models/video/video-streaming-playlist.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, HasMany, Is, Model, Table, UpdatedAt, DataType } from 'sequelize-typescript' |
2 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' | 2 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' |
3 | import { throwIfNotValid } from '../utils' | 3 | import { throwIfNotValid } from '../utils' |
4 | import { VideoModel } from './video' | 4 | import { VideoModel } from './video' |
5 | import * as Sequelize from 'sequelize' | ||
6 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 5 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
7 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 6 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
8 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
@@ -11,6 +10,7 @@ import { VideoFileModel } from './video-file' | |||
11 | import { join } from 'path' | 10 | import { join } from 'path' |
12 | import { sha1 } from '../../helpers/core-utils' | 11 | import { sha1 } from '../../helpers/core-utils' |
13 | import { isArrayOf } from '../../helpers/custom-validators/misc' | 12 | import { isArrayOf } from '../../helpers/custom-validators/misc' |
13 | import { QueryTypes, Op } from 'sequelize' | ||
14 | 14 | ||
15 | @Table({ | 15 | @Table({ |
16 | tableName: 'videoStreamingPlaylist', | 16 | tableName: 'videoStreamingPlaylist', |
@@ -26,7 +26,7 @@ import { isArrayOf } from '../../helpers/custom-validators/misc' | |||
26 | fields: [ 'p2pMediaLoaderInfohashes' ], | 26 | fields: [ 'p2pMediaLoaderInfohashes' ], |
27 | using: 'gin' | 27 | using: 'gin' |
28 | } | 28 | } |
29 | ] | 29 | ] as any // FIXME: sequelize typings |
30 | }) | 30 | }) |
31 | export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistModel> { | 31 | export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistModel> { |
32 | @CreatedAt | 32 | @CreatedAt |
@@ -46,7 +46,7 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod | |||
46 | 46 | ||
47 | @AllowNull(false) | 47 | @AllowNull(false) |
48 | @Is('VideoStreamingPlaylistInfoHashes', value => throwIfNotValid(value, v => isArrayOf(v, isVideoFileInfoHashValid), 'info hashes')) | 48 | @Is('VideoStreamingPlaylistInfoHashes', value => throwIfNotValid(value, v => isArrayOf(v, isVideoFileInfoHashValid), 'info hashes')) |
49 | @Column(DataType.ARRAY(DataType.STRING)) | 49 | @Column({ type: DataType.ARRAY(DataType.STRING) }) // FIXME: typings |
50 | p2pMediaLoaderInfohashes: string[] | 50 | p2pMediaLoaderInfohashes: string[] |
51 | 51 | ||
52 | @AllowNull(false) | 52 | @AllowNull(false) |
@@ -82,15 +82,13 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod | |||
82 | static doesInfohashExist (infoHash: string) { | 82 | static doesInfohashExist (infoHash: string) { |
83 | const query = 'SELECT 1 FROM "videoStreamingPlaylist" WHERE $infoHash = ANY("p2pMediaLoaderInfohashes") LIMIT 1' | 83 | const query = 'SELECT 1 FROM "videoStreamingPlaylist" WHERE $infoHash = ANY("p2pMediaLoaderInfohashes") LIMIT 1' |
84 | const options = { | 84 | const options = { |
85 | type: Sequelize.QueryTypes.SELECT, | 85 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
86 | bind: { infoHash }, | 86 | bind: { infoHash }, |
87 | raw: true | 87 | raw: true |
88 | } | 88 | } |
89 | 89 | ||
90 | return VideoModel.sequelize.query(query, options) | 90 | return VideoModel.sequelize.query<any>(query, options) |
91 | .then(results => { | 91 | .then(results => results.length === 1) |
92 | return results.length === 1 | ||
93 | }) | ||
94 | } | 92 | } |
95 | 93 | ||
96 | static buildP2PMediaLoaderInfoHashes (playlistUrl: string, videoFiles: VideoFileModel[]) { | 94 | static buildP2PMediaLoaderInfoHashes (playlistUrl: string, videoFiles: VideoFileModel[]) { |
@@ -108,7 +106,7 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod | |||
108 | const query = { | 106 | const query = { |
109 | where: { | 107 | where: { |
110 | p2pMediaLoaderPeerVersion: { | 108 | p2pMediaLoaderPeerVersion: { |
111 | [Sequelize.Op.ne]: P2P_MEDIA_LOADER_PEER_VERSION | 109 | [Op.ne]: P2P_MEDIA_LOADER_PEER_VERSION |
112 | } | 110 | } |
113 | } | 111 | } |
114 | } | 112 | } |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 9840d17fd..329cebd28 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -3,7 +3,18 @@ import { maxBy } from 'lodash' | |||
3 | import * as magnetUtil from 'magnet-uri' | 3 | import * as magnetUtil from 'magnet-uri' |
4 | import * as parseTorrent from 'parse-torrent' | 4 | import * as parseTorrent from 'parse-torrent' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import * as Sequelize from 'sequelize' | 6 | import { |
7 | CountOptions, | ||
8 | FindOptions, | ||
9 | IncludeOptions, | ||
10 | ModelIndexesOptions, | ||
11 | Op, | ||
12 | QueryTypes, | ||
13 | ScopeOptions, | ||
14 | Sequelize, | ||
15 | Transaction, | ||
16 | WhereOptions | ||
17 | } from 'sequelize' | ||
7 | import { | 18 | import { |
8 | AllowNull, | 19 | AllowNull, |
9 | BeforeDestroy, | 20 | BeforeDestroy, |
@@ -16,8 +27,6 @@ import { | |||
16 | ForeignKey, | 27 | ForeignKey, |
17 | HasMany, | 28 | HasMany, |
18 | HasOne, | 29 | HasOne, |
19 | IFindOptions, | ||
20 | IIncludeOptions, | ||
21 | Is, | 30 | Is, |
22 | IsInt, | 31 | IsInt, |
23 | IsUUID, | 32 | IsUUID, |
@@ -45,7 +54,7 @@ import { | |||
45 | isVideoStateValid, | 54 | isVideoStateValid, |
46 | isVideoSupportValid | 55 | isVideoSupportValid |
47 | } from '../../helpers/custom-validators/videos' | 56 | } from '../../helpers/custom-validators/videos' |
48 | import { generateImageFromVideoFile, getVideoFileResolution } from '../../helpers/ffmpeg-utils' | 57 | import { getVideoFileResolution } from '../../helpers/ffmpeg-utils' |
49 | import { logger } from '../../helpers/logger' | 58 | import { logger } from '../../helpers/logger' |
50 | import { getServerActor } from '../../helpers/utils' | 59 | import { getServerActor } from '../../helpers/utils' |
51 | import { | 60 | import { |
@@ -54,11 +63,9 @@ import { | |||
54 | CONSTRAINTS_FIELDS, | 63 | CONSTRAINTS_FIELDS, |
55 | HLS_REDUNDANCY_DIRECTORY, | 64 | HLS_REDUNDANCY_DIRECTORY, |
56 | HLS_STREAMING_PLAYLIST_DIRECTORY, | 65 | HLS_STREAMING_PLAYLIST_DIRECTORY, |
57 | PREVIEWS_SIZE, | ||
58 | REMOTE_SCHEME, | 66 | REMOTE_SCHEME, |
59 | STATIC_DOWNLOAD_PATHS, | 67 | STATIC_DOWNLOAD_PATHS, |
60 | STATIC_PATHS, | 68 | STATIC_PATHS, |
61 | THUMBNAILS_SIZE, | ||
62 | VIDEO_CATEGORIES, | 69 | VIDEO_CATEGORIES, |
63 | VIDEO_LANGUAGES, | 70 | VIDEO_LANGUAGES, |
64 | VIDEO_LICENCES, | 71 | VIDEO_LICENCES, |
@@ -111,7 +118,7 @@ import { ThumbnailModel } from './thumbnail' | |||
111 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 118 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
112 | 119 | ||
113 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 120 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
114 | const indexes: Sequelize.DefineIndexesOptions[] = [ | 121 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ |
115 | buildTrigramSearchIndex('video_name_trigram', 'name'), | 122 | buildTrigramSearchIndex('video_name_trigram', 'name'), |
116 | 123 | ||
117 | { fields: [ 'createdAt' ] }, | 124 | { fields: [ 'createdAt' ] }, |
@@ -123,7 +130,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [ | |||
123 | fields: [ 'originallyPublishedAt' ], | 130 | fields: [ 'originallyPublishedAt' ], |
124 | where: { | 131 | where: { |
125 | originallyPublishedAt: { | 132 | originallyPublishedAt: { |
126 | [Sequelize.Op.ne]: null | 133 | [Op.ne]: null |
127 | } | 134 | } |
128 | } | 135 | } |
129 | }, | 136 | }, |
@@ -131,7 +138,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [ | |||
131 | fields: [ 'category' ], // We don't care videos with an unknown category | 138 | fields: [ 'category' ], // We don't care videos with an unknown category |
132 | where: { | 139 | where: { |
133 | category: { | 140 | category: { |
134 | [Sequelize.Op.ne]: null | 141 | [Op.ne]: null |
135 | } | 142 | } |
136 | } | 143 | } |
137 | }, | 144 | }, |
@@ -139,7 +146,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [ | |||
139 | fields: [ 'licence' ], // We don't care videos with an unknown licence | 146 | fields: [ 'licence' ], // We don't care videos with an unknown licence |
140 | where: { | 147 | where: { |
141 | licence: { | 148 | licence: { |
142 | [Sequelize.Op.ne]: null | 149 | [Op.ne]: null |
143 | } | 150 | } |
144 | } | 151 | } |
145 | }, | 152 | }, |
@@ -147,7 +154,7 @@ const indexes: Sequelize.DefineIndexesOptions[] = [ | |||
147 | fields: [ 'language' ], // We don't care videos with an unknown language | 154 | fields: [ 'language' ], // We don't care videos with an unknown language |
148 | where: { | 155 | where: { |
149 | language: { | 156 | language: { |
150 | [Sequelize.Op.ne]: null | 157 | [Op.ne]: null |
151 | } | 158 | } |
152 | } | 159 | } |
153 | }, | 160 | }, |
@@ -222,10 +229,10 @@ type AvailableForListIDsOptions = { | |||
222 | 229 | ||
223 | @Scopes({ | 230 | @Scopes({ |
224 | [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { | 231 | [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { |
225 | const query: IFindOptions<VideoModel> = { | 232 | const query: FindOptions = { |
226 | where: { | 233 | where: { |
227 | id: { | 234 | id: { |
228 | [ Sequelize.Op.any ]: options.ids | 235 | [ Op.in ]: options.ids // FIXME: sequelize any seems broken |
229 | } | 236 | } |
230 | }, | 237 | }, |
231 | include: [ | 238 | include: [ |
@@ -256,21 +263,21 @@ type AvailableForListIDsOptions = { | |||
256 | return query | 263 | return query |
257 | }, | 264 | }, |
258 | [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { | 265 | [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { |
259 | const query: IFindOptions<VideoModel> = { | 266 | const query: FindOptions = { |
260 | raw: true, | 267 | raw: true, |
261 | attributes: [ 'id' ], | 268 | attributes: [ 'id' ], |
262 | where: { | 269 | where: { |
263 | id: { | 270 | id: { |
264 | [ Sequelize.Op.and ]: [ | 271 | [ Op.and ]: [ |
265 | { | 272 | { |
266 | [ Sequelize.Op.notIn ]: Sequelize.literal( | 273 | [ Op.notIn ]: Sequelize.literal( |
267 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' | 274 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' |
268 | ) | 275 | ) |
269 | } | 276 | } |
270 | ] | 277 | ] |
271 | }, | 278 | }, |
272 | channelId: { | 279 | channelId: { |
273 | [ Sequelize.Op.notIn ]: Sequelize.literal( | 280 | [ Op.notIn ]: Sequelize.literal( |
274 | '(' + | 281 | '(' + |
275 | 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + | 282 | 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + |
276 | buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + | 283 | buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + |
@@ -288,12 +295,12 @@ type AvailableForListIDsOptions = { | |||
288 | // Always list public videos | 295 | // Always list public videos |
289 | privacy: VideoPrivacy.PUBLIC, | 296 | privacy: VideoPrivacy.PUBLIC, |
290 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding | 297 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding |
291 | [ Sequelize.Op.or ]: [ | 298 | [ Op.or ]: [ |
292 | { | 299 | { |
293 | state: VideoState.PUBLISHED | 300 | state: VideoState.PUBLISHED |
294 | }, | 301 | }, |
295 | { | 302 | { |
296 | [ Sequelize.Op.and ]: { | 303 | [ Op.and ]: { |
297 | state: VideoState.TO_TRANSCODE, | 304 | state: VideoState.TO_TRANSCODE, |
298 | waitTranscoding: false | 305 | waitTranscoding: false |
299 | } | 306 | } |
@@ -318,7 +325,7 @@ type AvailableForListIDsOptions = { | |||
318 | } | 325 | } |
319 | 326 | ||
320 | if (options.filter || options.accountId || options.videoChannelId) { | 327 | if (options.filter || options.accountId || options.videoChannelId) { |
321 | const videoChannelInclude: IIncludeOptions = { | 328 | const videoChannelInclude: IncludeOptions = { |
322 | attributes: [], | 329 | attributes: [], |
323 | model: VideoChannelModel.unscoped(), | 330 | model: VideoChannelModel.unscoped(), |
324 | required: true | 331 | required: true |
@@ -331,7 +338,7 @@ type AvailableForListIDsOptions = { | |||
331 | } | 338 | } |
332 | 339 | ||
333 | if (options.filter || options.accountId) { | 340 | if (options.filter || options.accountId) { |
334 | const accountInclude: IIncludeOptions = { | 341 | const accountInclude: IncludeOptions = { |
335 | attributes: [], | 342 | attributes: [], |
336 | model: AccountModel.unscoped(), | 343 | model: AccountModel.unscoped(), |
337 | required: true | 344 | required: true |
@@ -371,8 +378,8 @@ type AvailableForListIDsOptions = { | |||
371 | 378 | ||
372 | // Force actorId to be a number to avoid SQL injections | 379 | // Force actorId to be a number to avoid SQL injections |
373 | const actorIdNumber = parseInt(options.followerActorId.toString(), 10) | 380 | const actorIdNumber = parseInt(options.followerActorId.toString(), 10) |
374 | query.where[ 'id' ][ Sequelize.Op.and ].push({ | 381 | query.where[ 'id' ][ Op.and ].push({ |
375 | [ Sequelize.Op.in ]: Sequelize.literal( | 382 | [ Op.in ]: Sequelize.literal( |
376 | '(' + | 383 | '(' + |
377 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + | 384 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + |
378 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | 385 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + |
@@ -391,8 +398,8 @@ type AvailableForListIDsOptions = { | |||
391 | } | 398 | } |
392 | 399 | ||
393 | if (options.withFiles === true) { | 400 | if (options.withFiles === true) { |
394 | query.where[ 'id' ][ Sequelize.Op.and ].push({ | 401 | query.where[ 'id' ][ Op.and ].push({ |
395 | [ Sequelize.Op.in ]: Sequelize.literal( | 402 | [ Op.in ]: Sequelize.literal( |
396 | '(SELECT "videoId" FROM "videoFile")' | 403 | '(SELECT "videoId" FROM "videoFile")' |
397 | ) | 404 | ) |
398 | }) | 405 | }) |
@@ -406,8 +413,8 @@ type AvailableForListIDsOptions = { | |||
406 | } | 413 | } |
407 | 414 | ||
408 | if (options.tagsOneOf) { | 415 | if (options.tagsOneOf) { |
409 | query.where[ 'id' ][ Sequelize.Op.and ].push({ | 416 | query.where[ 'id' ][ Op.and ].push({ |
410 | [ Sequelize.Op.in ]: Sequelize.literal( | 417 | [ Op.in ]: Sequelize.literal( |
411 | '(' + | 418 | '(' + |
412 | 'SELECT "videoId" FROM "videoTag" ' + | 419 | 'SELECT "videoId" FROM "videoTag" ' + |
413 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 420 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
@@ -418,8 +425,8 @@ type AvailableForListIDsOptions = { | |||
418 | } | 425 | } |
419 | 426 | ||
420 | if (options.tagsAllOf) { | 427 | if (options.tagsAllOf) { |
421 | query.where[ 'id' ][ Sequelize.Op.and ].push({ | 428 | query.where[ 'id' ][ Op.and ].push({ |
422 | [ Sequelize.Op.in ]: Sequelize.literal( | 429 | [ Op.in ]: Sequelize.literal( |
423 | '(' + | 430 | '(' + |
424 | 'SELECT "videoId" FROM "videoTag" ' + | 431 | 'SELECT "videoId" FROM "videoTag" ' + |
425 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 432 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
@@ -437,19 +444,19 @@ type AvailableForListIDsOptions = { | |||
437 | 444 | ||
438 | if (options.categoryOneOf) { | 445 | if (options.categoryOneOf) { |
439 | query.where[ 'category' ] = { | 446 | query.where[ 'category' ] = { |
440 | [ Sequelize.Op.or ]: options.categoryOneOf | 447 | [ Op.or ]: options.categoryOneOf |
441 | } | 448 | } |
442 | } | 449 | } |
443 | 450 | ||
444 | if (options.licenceOneOf) { | 451 | if (options.licenceOneOf) { |
445 | query.where[ 'licence' ] = { | 452 | query.where[ 'licence' ] = { |
446 | [ Sequelize.Op.or ]: options.licenceOneOf | 453 | [ Op.or ]: options.licenceOneOf |
447 | } | 454 | } |
448 | } | 455 | } |
449 | 456 | ||
450 | if (options.languageOneOf) { | 457 | if (options.languageOneOf) { |
451 | query.where[ 'language' ] = { | 458 | query.where[ 'language' ] = { |
452 | [ Sequelize.Op.or ]: options.languageOneOf | 459 | [ Op.or ]: options.languageOneOf |
453 | } | 460 | } |
454 | } | 461 | } |
455 | 462 | ||
@@ -498,7 +505,7 @@ type AvailableForListIDsOptions = { | |||
498 | } | 505 | } |
499 | ] | 506 | ] |
500 | } | 507 | } |
501 | ] | 508 | ] as any // FIXME: sequelize typings |
502 | }, | 509 | }, |
503 | [ ScopeNames.WITH_ACCOUNT_DETAILS ]: { | 510 | [ ScopeNames.WITH_ACCOUNT_DETAILS ]: { |
504 | include: [ | 511 | include: [ |
@@ -550,7 +557,7 @@ type AvailableForListIDsOptions = { | |||
550 | } | 557 | } |
551 | ] | 558 | ] |
552 | } | 559 | } |
553 | ] | 560 | ] as any // FIXME: sequelize typings |
554 | }, | 561 | }, |
555 | [ ScopeNames.WITH_TAGS ]: { | 562 | [ ScopeNames.WITH_TAGS ]: { |
556 | include: [ () => TagModel ] | 563 | include: [ () => TagModel ] |
@@ -656,19 +663,19 @@ export class VideoModel extends Model<VideoModel> { | |||
656 | 663 | ||
657 | @AllowNull(true) | 664 | @AllowNull(true) |
658 | @Default(null) | 665 | @Default(null) |
659 | @Is('VideoCategory', value => throwIfNotValid(value, isVideoCategoryValid, 'category')) | 666 | @Is('VideoCategory', value => throwIfNotValid(value, isVideoCategoryValid, 'category', true)) |
660 | @Column | 667 | @Column |
661 | category: number | 668 | category: number |
662 | 669 | ||
663 | @AllowNull(true) | 670 | @AllowNull(true) |
664 | @Default(null) | 671 | @Default(null) |
665 | @Is('VideoLicence', value => throwIfNotValid(value, isVideoLicenceValid, 'licence')) | 672 | @Is('VideoLicence', value => throwIfNotValid(value, isVideoLicenceValid, 'licence', true)) |
666 | @Column | 673 | @Column |
667 | licence: number | 674 | licence: number |
668 | 675 | ||
669 | @AllowNull(true) | 676 | @AllowNull(true) |
670 | @Default(null) | 677 | @Default(null) |
671 | @Is('VideoLanguage', value => throwIfNotValid(value, isVideoLanguageValid, 'language')) | 678 | @Is('VideoLanguage', value => throwIfNotValid(value, isVideoLanguageValid, 'language', true)) |
672 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.LANGUAGE.max)) | 679 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.LANGUAGE.max)) |
673 | language: string | 680 | language: string |
674 | 681 | ||
@@ -684,13 +691,13 @@ export class VideoModel extends Model<VideoModel> { | |||
684 | 691 | ||
685 | @AllowNull(true) | 692 | @AllowNull(true) |
686 | @Default(null) | 693 | @Default(null) |
687 | @Is('VideoDescription', value => throwIfNotValid(value, isVideoDescriptionValid, 'description')) | 694 | @Is('VideoDescription', value => throwIfNotValid(value, isVideoDescriptionValid, 'description', true)) |
688 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max)) | 695 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max)) |
689 | description: string | 696 | description: string |
690 | 697 | ||
691 | @AllowNull(true) | 698 | @AllowNull(true) |
692 | @Default(null) | 699 | @Default(null) |
693 | @Is('VideoSupport', value => throwIfNotValid(value, isVideoSupportValid, 'support')) | 700 | @Is('VideoSupport', value => throwIfNotValid(value, isVideoSupportValid, 'support', true)) |
694 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.SUPPORT.max)) | 701 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.SUPPORT.max)) |
695 | support: string | 702 | support: string |
696 | 703 | ||
@@ -754,7 +761,7 @@ export class VideoModel extends Model<VideoModel> { | |||
754 | updatedAt: Date | 761 | updatedAt: Date |
755 | 762 | ||
756 | @AllowNull(false) | 763 | @AllowNull(false) |
757 | @Default(Sequelize.NOW) | 764 | @Default(DataType.NOW) |
758 | @Column | 765 | @Column |
759 | publishedAt: Date | 766 | publishedAt: Date |
760 | 767 | ||
@@ -999,12 +1006,12 @@ export class VideoModel extends Model<VideoModel> { | |||
999 | distinct: true, | 1006 | distinct: true, |
1000 | offset: start, | 1007 | offset: start, |
1001 | limit: count, | 1008 | limit: count, |
1002 | order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ]), | 1009 | order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings |
1003 | where: { | 1010 | where: { |
1004 | id: { | 1011 | id: { |
1005 | [ Sequelize.Op.in ]: Sequelize.literal('(' + rawQuery + ')') | 1012 | [ Op.in ]: Sequelize.literal('(' + rawQuery + ')') |
1006 | }, | 1013 | }, |
1007 | [ Sequelize.Op.or ]: [ | 1014 | [ Op.or ]: [ |
1008 | { privacy: VideoPrivacy.PUBLIC }, | 1015 | { privacy: VideoPrivacy.PUBLIC }, |
1009 | { privacy: VideoPrivacy.UNLISTED } | 1016 | { privacy: VideoPrivacy.UNLISTED } |
1010 | ] | 1017 | ] |
@@ -1021,10 +1028,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1021 | required: false, | 1028 | required: false, |
1022 | // We only want videos shared by this actor | 1029 | // We only want videos shared by this actor |
1023 | where: { | 1030 | where: { |
1024 | [ Sequelize.Op.and ]: [ | 1031 | [ Op.and ]: [ |
1025 | { | 1032 | { |
1026 | id: { | 1033 | id: { |
1027 | [ Sequelize.Op.not ]: null | 1034 | [ Op.not ]: null |
1028 | } | 1035 | } |
1029 | }, | 1036 | }, |
1030 | { | 1037 | { |
@@ -1070,13 +1077,13 @@ export class VideoModel extends Model<VideoModel> { | |||
1070 | return Bluebird.all([ | 1077 | return Bluebird.all([ |
1071 | // FIXME: typing issue | 1078 | // FIXME: typing issue |
1072 | VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findAll(query as any), | 1079 | VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findAll(query as any), |
1073 | VideoModel.sequelize.query(rawCountQuery, { type: Sequelize.QueryTypes.SELECT }) | 1080 | VideoModel.sequelize.query<{ total: number }>(rawCountQuery, { type: QueryTypes.SELECT }) |
1074 | ]).then(([ rows, totals ]) => { | 1081 | ]).then(([ rows, totals ]) => { |
1075 | // totals: totalVideos + totalVideoShares | 1082 | // totals: totalVideos + totalVideoShares |
1076 | let totalVideos = 0 | 1083 | let totalVideos = 0 |
1077 | let totalVideoShares = 0 | 1084 | let totalVideoShares = 0 |
1078 | if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10) | 1085 | if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total + '', 10) |
1079 | if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10) | 1086 | if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total + '', 10) |
1080 | 1087 | ||
1081 | const total = totalVideos + totalVideoShares | 1088 | const total = totalVideos + totalVideoShares |
1082 | return { | 1089 | return { |
@@ -1087,7 +1094,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1087 | } | 1094 | } |
1088 | 1095 | ||
1089 | static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) { | 1096 | static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) { |
1090 | const query: IFindOptions<VideoModel> = { | 1097 | const query: FindOptions = { |
1091 | offset: start, | 1098 | offset: start, |
1092 | limit: count, | 1099 | limit: count, |
1093 | order: getVideoSort(sort), | 1100 | order: getVideoSort(sort), |
@@ -1158,7 +1165,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1158 | throw new Error('Try to filter all-local but no user has not the see all videos right') | 1165 | throw new Error('Try to filter all-local but no user has not the see all videos right') |
1159 | } | 1166 | } |
1160 | 1167 | ||
1161 | const query: IFindOptions<VideoModel> = { | 1168 | const query: FindOptions = { |
1162 | offset: options.start, | 1169 | offset: options.start, |
1163 | limit: options.count, | 1170 | limit: options.count, |
1164 | order: getVideoSort(options.sort) | 1171 | order: getVideoSort(options.sort) |
@@ -1225,8 +1232,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1225 | if (options.startDate || options.endDate) { | 1232 | if (options.startDate || options.endDate) { |
1226 | const publishedAtRange = {} | 1233 | const publishedAtRange = {} |
1227 | 1234 | ||
1228 | if (options.startDate) publishedAtRange[ Sequelize.Op.gte ] = options.startDate | 1235 | if (options.startDate) publishedAtRange[ Op.gte ] = options.startDate |
1229 | if (options.endDate) publishedAtRange[ Sequelize.Op.lte ] = options.endDate | 1236 | if (options.endDate) publishedAtRange[ Op.lte ] = options.endDate |
1230 | 1237 | ||
1231 | whereAnd.push({ publishedAt: publishedAtRange }) | 1238 | whereAnd.push({ publishedAt: publishedAtRange }) |
1232 | } | 1239 | } |
@@ -1234,8 +1241,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1234 | if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { | 1241 | if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { |
1235 | const originallyPublishedAtRange = {} | 1242 | const originallyPublishedAtRange = {} |
1236 | 1243 | ||
1237 | if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Sequelize.Op.gte ] = options.originallyPublishedStartDate | 1244 | if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Op.gte ] = options.originallyPublishedStartDate |
1238 | if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Sequelize.Op.lte ] = options.originallyPublishedEndDate | 1245 | if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Op.lte ] = options.originallyPublishedEndDate |
1239 | 1246 | ||
1240 | whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) | 1247 | whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) |
1241 | } | 1248 | } |
@@ -1243,8 +1250,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1243 | if (options.durationMin || options.durationMax) { | 1250 | if (options.durationMin || options.durationMax) { |
1244 | const durationRange = {} | 1251 | const durationRange = {} |
1245 | 1252 | ||
1246 | if (options.durationMin) durationRange[ Sequelize.Op.gte ] = options.durationMin | 1253 | if (options.durationMin) durationRange[ Op.gte ] = options.durationMin |
1247 | if (options.durationMax) durationRange[ Sequelize.Op.lte ] = options.durationMax | 1254 | if (options.durationMax) durationRange[ Op.lte ] = options.durationMax |
1248 | 1255 | ||
1249 | whereAnd.push({ duration: durationRange }) | 1256 | whereAnd.push({ duration: durationRange }) |
1250 | } | 1257 | } |
@@ -1256,7 +1263,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1256 | whereAnd.push( | 1263 | whereAnd.push( |
1257 | { | 1264 | { |
1258 | id: { | 1265 | id: { |
1259 | [ Sequelize.Op.in ]: Sequelize.literal( | 1266 | [ Op.in ]: Sequelize.literal( |
1260 | '(' + | 1267 | '(' + |
1261 | 'SELECT "video"."id" FROM "video" ' + | 1268 | 'SELECT "video"."id" FROM "video" ' + |
1262 | 'WHERE ' + | 1269 | 'WHERE ' + |
@@ -1282,7 +1289,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1282 | ) | 1289 | ) |
1283 | } | 1290 | } |
1284 | 1291 | ||
1285 | const query: IFindOptions<VideoModel> = { | 1292 | const query: FindOptions = { |
1286 | attributes: { | 1293 | attributes: { |
1287 | include: attributesInclude | 1294 | include: attributesInclude |
1288 | }, | 1295 | }, |
@@ -1290,7 +1297,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1290 | limit: options.count, | 1297 | limit: options.count, |
1291 | order: getVideoSort(options.sort), | 1298 | order: getVideoSort(options.sort), |
1292 | where: { | 1299 | where: { |
1293 | [ Sequelize.Op.and ]: whereAnd | 1300 | [ Op.and ]: whereAnd |
1294 | } | 1301 | } |
1295 | } | 1302 | } |
1296 | 1303 | ||
@@ -1312,7 +1319,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1312 | return VideoModel.getAvailableForApi(query, queryOptions) | 1319 | return VideoModel.getAvailableForApi(query, queryOptions) |
1313 | } | 1320 | } |
1314 | 1321 | ||
1315 | static load (id: number | string, t?: Sequelize.Transaction) { | 1322 | static load (id: number | string, t?: Transaction) { |
1316 | const where = buildWhereIdOrUUID(id) | 1323 | const where = buildWhereIdOrUUID(id) |
1317 | const options = { | 1324 | const options = { |
1318 | where, | 1325 | where, |
@@ -1322,7 +1329,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1322 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1329 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) |
1323 | } | 1330 | } |
1324 | 1331 | ||
1325 | static loadWithRights (id: number | string, t?: Sequelize.Transaction) { | 1332 | static loadWithRights (id: number | string, t?: Transaction) { |
1326 | const where = buildWhereIdOrUUID(id) | 1333 | const where = buildWhereIdOrUUID(id) |
1327 | const options = { | 1334 | const options = { |
1328 | where, | 1335 | where, |
@@ -1336,7 +1343,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1336 | ]).findOne(options) | 1343 | ]).findOne(options) |
1337 | } | 1344 | } |
1338 | 1345 | ||
1339 | static loadOnlyId (id: number | string, t?: Sequelize.Transaction) { | 1346 | static loadOnlyId (id: number | string, t?: Transaction) { |
1340 | const where = buildWhereIdOrUUID(id) | 1347 | const where = buildWhereIdOrUUID(id) |
1341 | 1348 | ||
1342 | const options = { | 1349 | const options = { |
@@ -1348,7 +1355,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1348 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1355 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) |
1349 | } | 1356 | } |
1350 | 1357 | ||
1351 | static loadWithFiles (id: number, t?: Sequelize.Transaction, logging?: boolean) { | 1358 | static loadWithFiles (id: number, t?: Transaction, logging?: boolean) { |
1352 | return VideoModel.scope([ | 1359 | return VideoModel.scope([ |
1353 | ScopeNames.WITH_FILES, | 1360 | ScopeNames.WITH_FILES, |
1354 | ScopeNames.WITH_STREAMING_PLAYLISTS, | 1361 | ScopeNames.WITH_STREAMING_PLAYLISTS, |
@@ -1366,8 +1373,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1366 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1373 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) |
1367 | } | 1374 | } |
1368 | 1375 | ||
1369 | static loadByUrl (url: string, transaction?: Sequelize.Transaction) { | 1376 | static loadByUrl (url: string, transaction?: Transaction) { |
1370 | const query: IFindOptions<VideoModel> = { | 1377 | const query: FindOptions = { |
1371 | where: { | 1378 | where: { |
1372 | url | 1379 | url |
1373 | }, | 1380 | }, |
@@ -1377,8 +1384,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1377 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) | 1384 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) |
1378 | } | 1385 | } |
1379 | 1386 | ||
1380 | static loadByUrlAndPopulateAccount (url: string, transaction?: Sequelize.Transaction) { | 1387 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction) { |
1381 | const query: IFindOptions<VideoModel> = { | 1388 | const query: FindOptions = { |
1382 | where: { | 1389 | where: { |
1383 | url | 1390 | url |
1384 | }, | 1391 | }, |
@@ -1393,11 +1400,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1393 | ]).findOne(query) | 1400 | ]).findOne(query) |
1394 | } | 1401 | } |
1395 | 1402 | ||
1396 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) { | 1403 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number) { |
1397 | const where = buildWhereIdOrUUID(id) | 1404 | const where = buildWhereIdOrUUID(id) |
1398 | 1405 | ||
1399 | const options = { | 1406 | const options = { |
1400 | order: [ [ 'Tags', 'name', 'ASC' ] ], | 1407 | order: [ [ 'Tags', 'name', 'ASC' ] ] as any, // FIXME: sequelize typings |
1401 | where, | 1408 | where, |
1402 | transaction: t | 1409 | transaction: t |
1403 | } | 1410 | } |
@@ -1421,11 +1428,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1421 | .findOne(options) | 1428 | .findOne(options) |
1422 | } | 1429 | } |
1423 | 1430 | ||
1424 | static loadForGetAPI (id: number | string, t?: Sequelize.Transaction, userId?: number) { | 1431 | static loadForGetAPI (id: number | string, t?: Transaction, userId?: number) { |
1425 | const where = buildWhereIdOrUUID(id) | 1432 | const where = buildWhereIdOrUUID(id) |
1426 | 1433 | ||
1427 | const options = { | 1434 | const options = { |
1428 | order: [ [ 'Tags', 'name', 'ASC' ] ], | 1435 | order: [ [ 'Tags', 'name', 'ASC' ] ] as any, // FIXME: sequelize typings |
1429 | where, | 1436 | where, |
1430 | transaction: t | 1437 | transaction: t |
1431 | } | 1438 | } |
@@ -1489,7 +1496,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1489 | 'LIMIT 1' | 1496 | 'LIMIT 1' |
1490 | 1497 | ||
1491 | const options = { | 1498 | const options = { |
1492 | type: Sequelize.QueryTypes.SELECT, | 1499 | type: QueryTypes.SELECT, |
1493 | bind: { followerActorId, videoId }, | 1500 | bind: { followerActorId, videoId }, |
1494 | raw: true | 1501 | raw: true |
1495 | } | 1502 | } |
@@ -1509,14 +1516,14 @@ export class VideoModel extends Model<VideoModel> { | |||
1509 | includeLocalVideos: true | 1516 | includeLocalVideos: true |
1510 | } | 1517 | } |
1511 | 1518 | ||
1512 | const query: IFindOptions<VideoModel> = { | 1519 | const query: FindOptions = { |
1513 | attributes: [ field ], | 1520 | attributes: [ field ], |
1514 | limit: count, | 1521 | limit: count, |
1515 | group: field, | 1522 | group: field, |
1516 | having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), { | 1523 | having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), { |
1517 | [ Sequelize.Op.gte ]: threshold | 1524 | [ Op.gte ]: threshold |
1518 | }) as any, // FIXME: typings | 1525 | }) as any, // FIXME: typings |
1519 | order: [ this.sequelize.random() ] | 1526 | order: [ (this.sequelize as any).random() ] |
1520 | } | 1527 | } |
1521 | 1528 | ||
1522 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) | 1529 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) |
@@ -1532,7 +1539,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1532 | required: false, | 1539 | required: false, |
1533 | where: { | 1540 | where: { |
1534 | startDate: { | 1541 | startDate: { |
1535 | [ Sequelize.Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) | 1542 | [ Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) |
1536 | } | 1543 | } |
1537 | } | 1544 | } |
1538 | } | 1545 | } |
@@ -1549,11 +1556,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1549 | } | 1556 | } |
1550 | 1557 | ||
1551 | private static async getAvailableForApi ( | 1558 | private static async getAvailableForApi ( |
1552 | query: IFindOptions<VideoModel>, | 1559 | query: FindOptions, |
1553 | options: AvailableForListIDsOptions, | 1560 | options: AvailableForListIDsOptions, |
1554 | countVideos = true | 1561 | countVideos = true |
1555 | ) { | 1562 | ) { |
1556 | const idsScope = { | 1563 | const idsScope: ScopeOptions = { |
1557 | method: [ | 1564 | method: [ |
1558 | ScopeNames.AVAILABLE_FOR_LIST_IDS, options | 1565 | ScopeNames.AVAILABLE_FOR_LIST_IDS, options |
1559 | ] | 1566 | ] |
@@ -1561,8 +1568,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1561 | 1568 | ||
1562 | // Remove trending sort on count, because it uses a group by | 1569 | // Remove trending sort on count, because it uses a group by |
1563 | const countOptions = Object.assign({}, options, { trendingDays: undefined }) | 1570 | const countOptions = Object.assign({}, options, { trendingDays: undefined }) |
1564 | const countQuery = Object.assign({}, query, { attributes: undefined, group: undefined }) | 1571 | const countQuery: CountOptions = Object.assign({}, query, { attributes: undefined, group: undefined }) |
1565 | const countScope = { | 1572 | const countScope: ScopeOptions = { |
1566 | method: [ | 1573 | method: [ |
1567 | ScopeNames.AVAILABLE_FOR_LIST_IDS, countOptions | 1574 | ScopeNames.AVAILABLE_FOR_LIST_IDS, countOptions |
1568 | ] | 1575 | ] |
@@ -1576,7 +1583,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1576 | 1583 | ||
1577 | if (ids.length === 0) return { data: [], total: count } | 1584 | if (ids.length === 0) return { data: [], total: count } |
1578 | 1585 | ||
1579 | const secondQuery: IFindOptions<VideoModel> = { | 1586 | const secondQuery: FindOptions = { |
1580 | offset: 0, | 1587 | offset: 0, |
1581 | limit: query.limit, | 1588 | limit: query.limit, |
1582 | attributes: query.attributes, | 1589 | attributes: query.attributes, |