aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/activitypub/client.ts2
-rw-r--r--server/controllers/api/video-playlist.ts4
-rw-r--r--server/lib/activitypub/url.ts7
-rw-r--r--server/middlewares/validators/videos/video-playlists.ts19
-rw-r--r--server/models/video/video-playlist-element.ts21
-rw-r--r--server/tests/api/check-params/video-playlists.ts5
-rw-r--r--server/tests/api/videos/video-playlists.ts35
7 files changed, 53 insertions, 40 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index acce53713..1da44d096 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -159,7 +159,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId',
159 asyncMiddleware(videoPlaylistsGetValidator('all')), 159 asyncMiddleware(videoPlaylistsGetValidator('all')),
160 asyncMiddleware(videoPlaylistController) 160 asyncMiddleware(videoPlaylistController)
161) 161)
162activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', 162activityPubClientRouter.get('/video-playlists/:playlistId/videos/:playlistElementId',
163 executeIfActivityPub, 163 executeIfActivityPub,
164 asyncMiddleware(videoPlaylistElementAPGetValidator), 164 asyncMiddleware(videoPlaylistElementAPGetValidator),
165 videoPlaylistElementController 165 videoPlaylistElementController
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index 88a2314fb..41a0e07ff 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -297,7 +297,6 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response)
297 const position = await VideoPlaylistElementModel.getNextPositionOf(videoPlaylist.id, t) 297 const position = await VideoPlaylistElementModel.getNextPositionOf(videoPlaylist.id, t)
298 298
299 const playlistElement = await VideoPlaylistElementModel.create({ 299 const playlistElement = await VideoPlaylistElementModel.create({
300 url: getVideoPlaylistElementActivityPubUrl(videoPlaylist, video),
301 position, 300 position,
302 startTimestamp: body.startTimestamp || null, 301 startTimestamp: body.startTimestamp || null,
303 stopTimestamp: body.stopTimestamp || null, 302 stopTimestamp: body.stopTimestamp || null,
@@ -305,6 +304,9 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response)
305 videoId: video.id 304 videoId: video.id
306 }, { transaction: t }) 305 }, { transaction: t })
307 306
307 playlistElement.url = getVideoPlaylistElementActivityPubUrl(videoPlaylist, playlistElement)
308 await playlistElement.save({ transaction: t })
309
308 videoPlaylist.changed('updatedAt', true) 310 videoPlaylist.changed('updatedAt', true)
309 await videoPlaylist.save({ transaction: t }) 311 await videoPlaylist.save({ transaction: t })
310 312
diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts
index b54e038a4..58030be2c 100644
--- a/server/lib/activitypub/url.ts
+++ b/server/lib/activitypub/url.ts
@@ -8,7 +8,8 @@ import {
8 MVideoId, 8 MVideoId,
9 MVideoUrl, 9 MVideoUrl,
10 MVideoUUID, 10 MVideoUUID,
11 MAbuseId 11 MAbuseId,
12 MVideoPlaylistElement
12} from '../../types/models' 13} from '../../types/models'
13import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist' 14import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist'
14import { MVideoFileVideoUUID } from '../../types/models/video/video-file' 15import { MVideoFileVideoUUID } from '../../types/models/video/video-file'
@@ -22,8 +23,8 @@ function getVideoPlaylistActivityPubUrl (videoPlaylist: MVideoPlaylist) {
22 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid 23 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid
23} 24}
24 25
25function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, video: MVideoUUID) { 26function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, videoPlaylistElement: MVideoPlaylistElement) {
26 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/' + video.uuid 27 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/videos/' + videoPlaylistElement.id
27} 28}
28 29
29function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) { 30function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) {
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts
index 07fd8533c..4647eae44 100644
--- a/server/middlewares/validators/videos/video-playlists.ts
+++ b/server/middlewares/validators/videos/video-playlists.ts
@@ -199,16 +199,6 @@ const videoPlaylistsAddVideoValidator = [
199 if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return 199 if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return
200 200
201 const videoPlaylist = getPlaylist(res) 201 const videoPlaylist = getPlaylist(res)
202 const video = res.locals.onlyVideo
203
204 const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideo(videoPlaylist.id, video.id)
205 if (videoPlaylistElement) {
206 res.status(409)
207 .json({ error: 'This video in this playlist already exists' })
208 .end()
209
210 return
211 }
212 202
213 if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) { 203 if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) {
214 return 204 return
@@ -258,15 +248,18 @@ const videoPlaylistsUpdateOrRemoveVideoValidator = [
258const videoPlaylistElementAPGetValidator = [ 248const videoPlaylistElementAPGetValidator = [
259 param('playlistId') 249 param('playlistId')
260 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), 250 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
261 param('videoId') 251 param('playlistElementId')
262 .custom(isIdOrUUIDValid).withMessage('Should have an video id/uuid'), 252 .custom(isIdValid).withMessage('Should have an playlist element id'),
263 253
264 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 254 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
265 logger.debug('Checking videoPlaylistElementAPGetValidator parameters', { parameters: req.params }) 255 logger.debug('Checking videoPlaylistElementAPGetValidator parameters', { parameters: req.params })
266 256
267 if (areValidationErrors(req, res)) return 257 if (areValidationErrors(req, res)) return
268 258
269 const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideoForAP(req.params.playlistId, req.params.videoId) 259 const playlistElementId = parseInt(req.params.playlistElementId + '', 10)
260 const playlistId = req.params.playlistId
261
262 const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndElementIdForAP(playlistId, playlistElementId)
270 if (!videoPlaylistElement) { 263 if (!videoPlaylistElement) {
271 res.status(404) 264 res.status(404)
272 .json({ error: 'Video playlist element not found' }) 265 .json({ error: 'Video playlist element not found' })
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts
index ba92e129a..d357766e9 100644
--- a/server/models/video/video-playlist-element.ts
+++ b/server/models/video/video-playlist-element.ts
@@ -44,10 +44,6 @@ import { MUserAccountId } from '@server/types/models'
44 fields: [ 'videoId' ] 44 fields: [ 'videoId' ]
45 }, 45 },
46 { 46 {
47 fields: [ 'videoPlaylistId', 'videoId' ],
48 unique: true
49 },
50 {
51 fields: [ 'url' ], 47 fields: [ 'url' ],
52 unique: true 48 unique: true
53 } 49 }
@@ -60,8 +56,8 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
60 @UpdatedAt 56 @UpdatedAt
61 updatedAt: Date 57 updatedAt: Date
62 58
63 @AllowNull(false) 59 @AllowNull(true)
64 @Is('VideoPlaylistUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) 60 @Is('VideoPlaylistUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url', true))
65 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.URL.max)) 61 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.URL.max))
66 url: string 62 url: string
67 63
@@ -185,12 +181,11 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
185 return VideoPlaylistElementModel.findByPk(playlistElementId) 181 return VideoPlaylistElementModel.findByPk(playlistElementId)
186 } 182 }
187 183
188 static loadByPlaylistAndVideoForAP ( 184 static loadByPlaylistAndElementIdForAP (
189 playlistId: number | string, 185 playlistId: number | string,
190 videoId: number | string 186 playlistElementId: number
191 ): Bluebird<MVideoPlaylistElementVideoUrlPlaylistPrivacy> { 187 ): Bluebird<MVideoPlaylistElementVideoUrlPlaylistPrivacy> {
192 const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId } 188 const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId }
193 const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId }
194 189
195 const query = { 190 const query = {
196 include: [ 191 include: [
@@ -201,10 +196,12 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
201 }, 196 },
202 { 197 {
203 attributes: [ 'url' ], 198 attributes: [ 'url' ],
204 model: VideoModel.unscoped(), 199 model: VideoModel.unscoped()
205 where: videoWhere
206 } 200 }
207 ] 201 ],
202 where: {
203 id: playlistElementId
204 }
208 } 205 }
209 206
210 return VideoPlaylistElementModel.findOne(query) 207 return VideoPlaylistElementModel.findOne(query)
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts
index 46ec00d46..179ae9201 100644
--- a/server/tests/api/check-params/video-playlists.ts
+++ b/server/tests/api/check-params/video-playlists.ts
@@ -346,11 +346,6 @@ describe('Test video playlists API validator', function () {
346 const res = await addVideoInPlaylist(params) 346 const res = await addVideoInPlaylist(params)
347 playlistElementId = res.body.videoPlaylistElement.id 347 playlistElementId = res.body.videoPlaylistElement.id
348 }) 348 })
349
350 it('Should fail if the video was already added in the playlist', async function () {
351 const params = getBase({}, { expectedStatus: 409 })
352 await addVideoInPlaylist(params)
353 })
354 }) 349 })
355 350
356 describe('When updating an element in a playlist', function () { 351 describe('When updating an element in a playlist', function () {
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts
index 52b32998d..0bfb5bcd4 100644
--- a/server/tests/api/videos/video-playlists.ts
+++ b/server/tests/api/videos/video-playlists.ts
@@ -552,6 +552,9 @@ describe('Test video playlists', function () {
552 { 552 {
553 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 }) 553 const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
554 playlistElementNSFW = res.body.videoPlaylistElement.id 554 playlistElementNSFW = res.body.videoPlaylistElement.id
555
556 await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 4 })
557 await addVideo({ videoId: nsfwVideoServer1 })
555 } 558 }
556 559
557 await waitJobs(servers) 560 await waitJobs(servers)
@@ -563,10 +566,10 @@ describe('Test video playlists', function () {
563 for (const server of servers) { 566 for (const server of servers) {
564 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) 567 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
565 568
566 expect(res.body.total).to.equal(6) 569 expect(res.body.total).to.equal(8)
567 570
568 const videoElements: VideoPlaylistElement[] = res.body.data 571 const videoElements: VideoPlaylistElement[] = res.body.data
569 expect(videoElements).to.have.lengthOf(6) 572 expect(videoElements).to.have.lengthOf(8)
570 573
571 expect(videoElements[0].video.name).to.equal('video 0 server 1') 574 expect(videoElements[0].video.name).to.equal('video 0 server 1')
572 expect(videoElements[0].position).to.equal(1) 575 expect(videoElements[0].position).to.equal(1)
@@ -598,6 +601,16 @@ describe('Test video playlists', function () {
598 expect(videoElements[5].startTimestamp).to.equal(5) 601 expect(videoElements[5].startTimestamp).to.equal(5)
599 expect(videoElements[5].stopTimestamp).to.be.null 602 expect(videoElements[5].stopTimestamp).to.be.null
600 603
604 expect(videoElements[6].video.name).to.equal('NSFW video')
605 expect(videoElements[6].position).to.equal(7)
606 expect(videoElements[6].startTimestamp).to.equal(4)
607 expect(videoElements[6].stopTimestamp).to.be.null
608
609 expect(videoElements[7].video.name).to.equal('NSFW video')
610 expect(videoElements[7].position).to.equal(8)
611 expect(videoElements[7].startTimestamp).to.be.null
612 expect(videoElements[7].stopTimestamp).to.be.null
613
601 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2) 614 const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
602 expect(res3.body.data).to.have.lengthOf(2) 615 expect(res3.body.data).to.have.lengthOf(2)
603 } 616 }
@@ -807,6 +820,8 @@ describe('Test video playlists', function () {
807 'video 1 server 3', 820 'video 1 server 3',
808 'video 3 server 1', 821 'video 3 server 1',
809 'video 4 server 1', 822 'video 4 server 1',
823 'NSFW video',
824 'NSFW video',
810 'NSFW video' 825 'NSFW video'
811 ]) 826 ])
812 } 827 }
@@ -836,6 +851,8 @@ describe('Test video playlists', function () {
836 'video 2 server 3', 851 'video 2 server 3',
837 'video 1 server 3', 852 'video 1 server 3',
838 'video 4 server 1', 853 'video 4 server 1',
854 'NSFW video',
855 'NSFW video',
839 'NSFW video' 856 'NSFW video'
840 ]) 857 ])
841 } 858 }
@@ -865,7 +882,9 @@ describe('Test video playlists', function () {
865 'video 2 server 3', 882 'video 2 server 3',
866 'NSFW video', 883 'NSFW video',
867 'video 1 server 3', 884 'video 1 server 3',
868 'video 4 server 1' 885 'video 4 server 1',
886 'NSFW video',
887 'NSFW video'
869 ]) 888 ])
870 889
871 for (let i = 1; i <= elements.length; i++) { 890 for (let i = 1; i <= elements.length; i++) {
@@ -1023,10 +1042,10 @@ describe('Test video playlists', function () {
1023 for (const server of servers) { 1042 for (const server of servers) {
1024 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) 1043 const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
1025 1044
1026 expect(res.body.total).to.equal(4) 1045 expect(res.body.total).to.equal(6)
1027 1046
1028 const elements: VideoPlaylistElement[] = res.body.data 1047 const elements: VideoPlaylistElement[] = res.body.data
1029 expect(elements).to.have.lengthOf(4) 1048 expect(elements).to.have.lengthOf(6)
1030 1049
1031 expect(elements[0].video.name).to.equal('video 0 server 1') 1050 expect(elements[0].video.name).to.equal('video 0 server 1')
1032 expect(elements[0].position).to.equal(1) 1051 expect(elements[0].position).to.equal(1)
@@ -1039,6 +1058,12 @@ describe('Test video playlists', function () {
1039 1058
1040 expect(elements[3].video.name).to.equal('video 4 server 1') 1059 expect(elements[3].video.name).to.equal('video 4 server 1')
1041 expect(elements[3].position).to.equal(4) 1060 expect(elements[3].position).to.equal(4)
1061
1062 expect(elements[4].video.name).to.equal('NSFW video')
1063 expect(elements[4].position).to.equal(5)
1064
1065 expect(elements[5].video.name).to.equal('NSFW video')
1066 expect(elements[5].position).to.equal(6)
1042 } 1067 }
1043 }) 1068 })
1044 1069