aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video-playlist.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-03-05 10:58:44 +0100
committerChocobozzz <chocobozzz@cpy.re>2019-03-18 11:17:59 +0100
commitdf0b219d36bf6852cdf2a7ad09ed4a41c6bccefa (patch)
treec4984e854f5dc18e5c27afd73b843bd52c143034 /server/models/video/video-playlist.ts
parent07b1a18aa678d260009a93e36606c5c5f585723d (diff)
downloadPeerTube-df0b219d36bf6852cdf2a7ad09ed4a41c6bccefa.tar.gz
PeerTube-df0b219d36bf6852cdf2a7ad09ed4a41c6bccefa.tar.zst
PeerTube-df0b219d36bf6852cdf2a7ad09ed4a41c6bccefa.zip
Add playlist rest tests
Diffstat (limited to 'server/models/video/video-playlist.ts')
-rw-r--r--server/models/video/video-playlist.ts92
1 files changed, 76 insertions, 16 deletions
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index 397887ebf..ce49f77ec 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -24,7 +24,14 @@ import {
24 isVideoPlaylistPrivacyValid 24 isVideoPlaylistPrivacyValid
25} from '../../helpers/custom-validators/video-playlists' 25} from '../../helpers/custom-validators/video-playlists'
26import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 26import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
27import { CONFIG, CONSTRAINTS_FIELDS, STATIC_PATHS, THUMBNAILS_SIZE, VIDEO_PLAYLIST_PRIVACIES } from '../../initializers' 27import {
28 CONFIG,
29 CONSTRAINTS_FIELDS,
30 STATIC_PATHS,
31 THUMBNAILS_SIZE,
32 VIDEO_PLAYLIST_PRIVACIES,
33 VIDEO_PLAYLIST_TYPES
34} from '../../initializers'
28import { VideoPlaylist } from '../../../shared/models/videos/playlist/video-playlist.model' 35import { VideoPlaylist } from '../../../shared/models/videos/playlist/video-playlist.model'
29import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' 36import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account'
30import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel' 37import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel'
@@ -34,22 +41,25 @@ import { PlaylistObject } from '../../../shared/models/activitypub/objects/playl
34import { activityPubCollectionPagination } from '../../helpers/activitypub' 41import { activityPubCollectionPagination } from '../../helpers/activitypub'
35import { remove } from 'fs-extra' 42import { remove } from 'fs-extra'
36import { logger } from '../../helpers/logger' 43import { logger } from '../../helpers/logger'
44import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model'
37 45
38enum ScopeNames { 46enum ScopeNames {
39 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', 47 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST',
40 WITH_VIDEOS_LENGTH = 'WITH_VIDEOS_LENGTH', 48 WITH_VIDEOS_LENGTH = 'WITH_VIDEOS_LENGTH',
41 WITH_ACCOUNT_AND_CHANNEL = 'WITH_ACCOUNT_AND_CHANNEL' 49 WITH_ACCOUNT_AND_CHANNEL_SUMMARY = 'WITH_ACCOUNT_AND_CHANNEL_SUMMARY',
50 WITH_ACCOUNT = 'WITH_ACCOUNT'
42} 51}
43 52
44type AvailableForListOptions = { 53type AvailableForListOptions = {
45 followerActorId: number 54 followerActorId: number
46 accountId?: number, 55 type?: VideoPlaylistType
56 accountId?: number
47 videoChannelId?: number 57 videoChannelId?: number
48 privateAndUnlisted?: boolean 58 privateAndUnlisted?: boolean
49} 59}
50 60
51@Scopes({ 61@Scopes({
52 [ScopeNames.WITH_VIDEOS_LENGTH]: { 62 [ ScopeNames.WITH_VIDEOS_LENGTH ]: {
53 attributes: { 63 attributes: {
54 include: [ 64 include: [
55 [ 65 [
@@ -59,7 +69,15 @@ type AvailableForListOptions = {
59 ] 69 ]
60 } 70 }
61 }, 71 },
62 [ScopeNames.WITH_ACCOUNT_AND_CHANNEL]: { 72 [ ScopeNames.WITH_ACCOUNT ]: {
73 include: [
74 {
75 model: () => AccountModel,
76 required: true
77 }
78 ]
79 },
80 [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY ]: {
63 include: [ 81 include: [
64 { 82 {
65 model: () => AccountModel.scope(AccountScopeNames.SUMMARY), 83 model: () => AccountModel.scope(AccountScopeNames.SUMMARY),
@@ -71,7 +89,7 @@ type AvailableForListOptions = {
71 } 89 }
72 ] 90 ]
73 }, 91 },
74 [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { 92 [ ScopeNames.AVAILABLE_FOR_LIST ]: (options: AvailableForListOptions) => {
75 // Only list local playlists OR playlists that are on an instance followed by actorId 93 // Only list local playlists OR playlists that are on an instance followed by actorId
76 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) 94 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId)
77 const actorWhere = { 95 const actorWhere = {
@@ -107,6 +125,12 @@ type AvailableForListOptions = {
107 }) 125 })
108 } 126 }
109 127
128 if (options.type) {
129 whereAnd.push({
130 type: options.type
131 })
132 }
133
110 const where = { 134 const where = {
111 [Sequelize.Op.and]: whereAnd 135 [Sequelize.Op.and]: whereAnd
112 } 136 }
@@ -179,6 +203,11 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
179 @Column(DataType.UUID) 203 @Column(DataType.UUID)
180 uuid: string 204 uuid: string
181 205
206 @AllowNull(false)
207 @Default(VideoPlaylistType.REGULAR)
208 @Column
209 type: VideoPlaylistType
210
182 @ForeignKey(() => AccountModel) 211 @ForeignKey(() => AccountModel)
183 @Column 212 @Column
184 ownerAccountId: number 213 ownerAccountId: number
@@ -208,13 +237,10 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
208 name: 'videoPlaylistId', 237 name: 'videoPlaylistId',
209 allowNull: false 238 allowNull: false
210 }, 239 },
211 onDelete: 'cascade' 240 onDelete: 'CASCADE'
212 }) 241 })
213 VideoPlaylistElements: VideoPlaylistElementModel[] 242 VideoPlaylistElements: VideoPlaylistElementModel[]
214 243
215 // Calculated field
216 videosLength?: number
217
218 @BeforeDestroy 244 @BeforeDestroy
219 static async removeFiles (instance: VideoPlaylistModel) { 245 static async removeFiles (instance: VideoPlaylistModel) {
220 logger.info('Removing files of video playlist %s.', instance.url) 246 logger.info('Removing files of video playlist %s.', instance.url)
@@ -227,6 +253,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
227 start: number, 253 start: number,
228 count: number, 254 count: number,
229 sort: string, 255 sort: string,
256 type?: VideoPlaylistType,
230 accountId?: number, 257 accountId?: number,
231 videoChannelId?: number, 258 videoChannelId?: number,
232 privateAndUnlisted?: boolean 259 privateAndUnlisted?: boolean
@@ -242,6 +269,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
242 method: [ 269 method: [
243 ScopeNames.AVAILABLE_FOR_LIST, 270 ScopeNames.AVAILABLE_FOR_LIST,
244 { 271 {
272 type: options.type,
245 followerActorId: options.followerActorId, 273 followerActorId: options.followerActorId,
246 accountId: options.accountId, 274 accountId: options.accountId,
247 videoChannelId: options.videoChannelId, 275 videoChannelId: options.videoChannelId,
@@ -289,7 +317,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
289 .then(e => !!e) 317 .then(e => !!e)
290 } 318 }
291 319
292 static load (id: number | string, transaction: Sequelize.Transaction) { 320 static loadWithAccountAndChannel (id: number | string, transaction: Sequelize.Transaction) {
293 const where = buildWhereIdOrUUID(id) 321 const where = buildWhereIdOrUUID(id)
294 322
295 const query = { 323 const query = {
@@ -298,14 +326,39 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
298 } 326 }
299 327
300 return VideoPlaylistModel 328 return VideoPlaylistModel
301 .scope([ ScopeNames.WITH_ACCOUNT_AND_CHANNEL, ScopeNames.WITH_VIDEOS_LENGTH ]) 329 .scope([ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY, ScopeNames.WITH_VIDEOS_LENGTH ])
302 .findOne(query) 330 .findOne(query)
303 } 331 }
304 332
333 static loadByUrlAndPopulateAccount (url: string) {
334 const query = {
335 where: {
336 url
337 }
338 }
339
340 return VideoPlaylistModel.scope(ScopeNames.WITH_ACCOUNT).findOne(query)
341 }
342
305 static getPrivacyLabel (privacy: VideoPlaylistPrivacy) { 343 static getPrivacyLabel (privacy: VideoPlaylistPrivacy) {
306 return VIDEO_PLAYLIST_PRIVACIES[privacy] || 'Unknown' 344 return VIDEO_PLAYLIST_PRIVACIES[privacy] || 'Unknown'
307 } 345 }
308 346
347 static getTypeLabel (type: VideoPlaylistType) {
348 return VIDEO_PLAYLIST_TYPES[type] || 'Unknown'
349 }
350
351 static resetPlaylistsOfChannel (videoChannelId: number, transaction: Sequelize.Transaction) {
352 const query = {
353 where: {
354 videoChannelId
355 },
356 transaction
357 }
358
359 return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query)
360 }
361
309 getThumbnailName () { 362 getThumbnailName () {
310 const extension = '.jpg' 363 const extension = '.jpg'
311 364
@@ -345,7 +398,12 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
345 398
346 thumbnailPath: this.getThumbnailStaticPath(), 399 thumbnailPath: this.getThumbnailStaticPath(),
347 400
348 videosLength: this.videosLength, 401 type: {
402 id: this.type,
403 label: VideoPlaylistModel.getTypeLabel(this.type)
404 },
405
406 videosLength: this.get('videosLength'),
349 407
350 createdAt: this.createdAt, 408 createdAt: this.createdAt,
351 updatedAt: this.updatedAt, 409 updatedAt: this.updatedAt,
@@ -355,18 +413,20 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
355 } 413 }
356 } 414 }
357 415
358 toActivityPubObject (): Promise<PlaylistObject> { 416 toActivityPubObject (page: number, t: Sequelize.Transaction): Promise<PlaylistObject> {
359 const handler = (start: number, count: number) => { 417 const handler = (start: number, count: number) => {
360 return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count) 418 return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t)
361 } 419 }
362 420
363 return activityPubCollectionPagination(this.url, handler, null) 421 return activityPubCollectionPagination(this.url, handler, page)
364 .then(o => { 422 .then(o => {
365 return Object.assign(o, { 423 return Object.assign(o, {
366 type: 'Playlist' as 'Playlist', 424 type: 'Playlist' as 'Playlist',
367 name: this.name, 425 name: this.name,
368 content: this.description, 426 content: this.description,
369 uuid: this.uuid, 427 uuid: this.uuid,
428 published: this.createdAt.toISOString(),
429 updated: this.updatedAt.toISOString(),
370 attributedTo: this.VideoChannel ? [ this.VideoChannel.Actor.url ] : [], 430 attributedTo: this.VideoChannel ? [ this.VideoChannel.Actor.url ] : [],
371 icon: { 431 icon: {
372 type: 'Image' as 'Image', 432 type: 'Image' as 'Image',