Check element belongs to the playlist

This commit is contained in:
Chocobozzz
2026-07-01 13:15:42 +02:00
parent 8a4bc0ddf2
commit 39018a16cf
3 changed files with 63 additions and 17 deletions
@@ -30,8 +30,13 @@ describe('Test video playlists API validator', function () {
let playlist: VideoPlaylistCreateResult let playlist: VideoPlaylistCreateResult
let userPlaylist: VideoPlaylistCreateResult let userPlaylist: VideoPlaylistCreateResult
let privatePlaylistUUID: string let privatePlaylistUUID: string
let privatePlaylistElementId: number
let anotherChannelPlaylistUUID: string let anotherChannelPlaylistUUID: string
let anotherChannelPlaylistElementId: number
let privateForEditorPlaylistUUID: string let privateForEditorPlaylistUUID: string
let watchLaterPlaylistId: number let watchLaterPlaylistId: number
@@ -93,6 +98,9 @@ describe('Test video playlists API validator', function () {
} }
}) })
anotherChannelPlaylistUUID = created.uuid anotherChannelPlaylistUUID = created.uuid
const { id } = await command.addElement({ playlistId: created.shortUUID, attributes: { videoId } })
anotherChannelPlaylistElementId = id
} }
{ {
@@ -103,6 +111,9 @@ describe('Test video playlists API validator', function () {
} }
}) })
privatePlaylistUUID = created.uuid privatePlaylistUUID = created.uuid
const { id } = await command.addElement({ playlistId: created.shortUUID, attributes: { videoId } })
privatePlaylistElementId = id
} }
{ {
@@ -548,9 +559,33 @@ describe('Test video playlists API validator', function () {
}) })
it('Should fail for an editor with elements of a private or another channel playlist', async function () { it('Should fail for an editor with elements of a private or another channel playlist', async function () {
for (const playlistId of [ privatePlaylistUUID, anotherChannelPlaylistUUID ]) { await command.updateElement(getBase(
await command.updateElement(getBase({}, { playlistId, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: editorToken })) {},
} {
playlistId: privatePlaylistUUID,
elementId: privatePlaylistElementId,
expectedStatus: HttpStatusCode.FORBIDDEN_403,
token: editorToken
}
))
await command.updateElement(
getBase(
{},
{
playlistId: anotherChannelPlaylistUUID,
elementId: anotherChannelPlaylistElementId,
expectedStatus: HttpStatusCode.FORBIDDEN_403,
token: editorToken
}
)
)
})
it('Should fail if the element id does not belong to the playlist', async function () {
const params = getBase({}, { elementId: anotherChannelPlaylistElementId, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
await command.updateElement(params)
}) })
it('Should fail with an unknown or incorrect playlist id', async function () { it('Should fail with an unknown or incorrect playlist id', async function () {
@@ -288,8 +288,7 @@ export const videoPlaylistsUpdateOrRemoveVideoValidator = [
isValidPlaylistIdParam('playlistId'), isValidPlaylistIdParam('playlistId'),
param('playlistElementId') param('playlistElementId')
.customSanitizer(toCompleteUUID) .custom(isIdValid).withMessage('Should have an element id'),
.custom(isIdValid).withMessage('Should have an element id/uuid/short uuid'),
body('startTimestamp') body('startTimestamp')
.optional() .optional()
@@ -305,16 +304,6 @@ export const videoPlaylistsUpdateOrRemoveVideoValidator = [
const videoPlaylist = getPlaylist(res) const videoPlaylist = getPlaylist(res)
const videoPlaylistElement = await VideoPlaylistElementModel.loadById(req.params.playlistElementId)
if (!videoPlaylistElement) {
res.fail({
status: HttpStatusCode.NOT_FOUND_404,
message: req.t('Video playlist element not found')
})
return
}
res.locals.videoPlaylistElement = videoPlaylistElement
if ( if (
!await checkCanManagePlaylist({ !await checkCanManagePlaylist({
user: res.locals.oauth.token.User, user: res.locals.oauth.token.User,
@@ -325,6 +314,20 @@ export const videoPlaylistsUpdateOrRemoveVideoValidator = [
}) })
) return ) return
const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndElement({
videoPlaylistId: videoPlaylist.id,
elementId: req.params.playlistElementId
})
if (!videoPlaylistElement) {
res.fail({
status: HttpStatusCode.NOT_FOUND_404,
message: req.t('Video playlist element not found')
})
return
}
res.locals.videoPlaylistElement = videoPlaylistElement
return next() return next()
} }
] ]
@@ -205,8 +205,16 @@ export class VideoPlaylistElementModel extends SequelizeModel<VideoPlaylistEleme
return VideoPlaylistElementModel.findOne(query) return VideoPlaylistElementModel.findOne(query)
} }
static loadById (playlistElementId: number | string): Promise<MVideoPlaylistElement> { static loadByPlaylistAndElement (options: {
return VideoPlaylistElementModel.findByPk(playlistElementId) videoPlaylistId: number
elementId: number | string
}): Promise<MVideoPlaylistElement> {
return VideoPlaylistElementModel.findOne({
where: {
id: options.elementId,
videoPlaylistId: options.videoPlaylistId
}
})
} }
static loadByPlaylistAndElementIdForAP ( static loadByPlaylistAndElementIdForAP (