From 6c226ba59f6519cf53be00a96529d3eb1c64ff19 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Mon, 6 May 2024 01:51:40 -0400 Subject: [PATCH] Add permission check for removing playlist item --- src/components/itemContextMenu.js | 10 ++--- src/components/shortcuts.js | 75 +++++++++++++++++++++---------- 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index fd7d82b42e..263a557164 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -280,11 +280,11 @@ export function getCommands(options) { }); } - if (item.PlaylistItemId && options.playlistId) { + if (item.PlaylistItemId && options.playlistId && options.canEditPlaylist) { commands.push({ name: globalize.translate('RemoveFromPlaylist'), id: 'removefromplaylist', - icon: 'remove' + icon: 'playlist_remove' }); } @@ -292,7 +292,7 @@ export function getCommands(options) { commands.push({ name: globalize.translate('RemoveFromCollection'), id: 'removefromcollection', - icon: 'remove' + icon: 'playlist_remove' }); } @@ -696,6 +696,6 @@ export function show(options) { } export default { - getCommands: getCommands, - show: show + getCommands, + show }; diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index cdf51b4661..099bed83c7 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -2,6 +2,7 @@ * Module shortcuts. * @module components/shortcuts */ +import { getPlaylistsApi } from '@jellyfin/sdk/lib/utils/api/playlists-api'; import { playbackManager } from './playback/playbackmanager'; import inputManager from '../scripts/inputManager'; @@ -12,6 +13,7 @@ import recordingHelper from './recordingcreator/recordinghelper'; import ServerConnections from './ServerConnections'; import toast from './toast/toast'; import * as userSettings from '../scripts/settings/userSettings'; +import { toApi } from 'utils/jellyfin-apiclient/compat'; function playAllFromHere(card, serverId, queue) { const parent = card.parentNode; @@ -100,7 +102,7 @@ function notifyRefreshNeeded(childElement, itemsContainer) { } } -function showContextMenu(card, options) { +function showContextMenu(card, options = {}) { getItem(card).then(item => { const playlistId = card.getAttribute('data-playlistid'); const collectionId = card.getAttribute('data-collectionid'); @@ -110,28 +112,55 @@ function showContextMenu(card, options) { item.PlaylistItemId = elem ? elem.getAttribute('data-playlistitemid') : null; } - import('./itemContextMenu').then((itemContextMenu) => { - ServerConnections.getApiClient(item.ServerId).getCurrentUser().then(user => { - itemContextMenu.show(Object.assign({ - item: item, + const apiClient = ServerConnections.getApiClient(item.ServerId); + const api = toApi(apiClient); + + Promise.all([ + // Import the item menu component + import('./itemContextMenu'), + // Fetch the current user + apiClient.getCurrentUser(), + // Fetch playlist perms if item is a child of a playlist + playlistId ? + getPlaylistsApi(api) + .getPlaylistUser({ + playlistId, + userId: apiClient.getCurrentUserId() + }) + .then(({ data }) => data) + .catch(() => { + // If a user doesn't have access, then the request will 404 and throw + return { CanEdit: false }; + }) : + // Not a playlist item + Promise.resolve({ CanEdit: false }) + ]) + .then(([ + itemContextMenu, + user, + playlistPerms + ]) => { + return itemContextMenu.show({ + item, play: true, queue: true, playAllFromHere: item.Type === 'Season' || !item.IsFolder, queueAllFromHere: !item.IsFolder, - playlistId: playlistId, - collectionId: collectionId, - user: user - }, options || {})) - .then(result => { - if (result.command === 'playallfromhere' || result.command === 'queueallfromhere') { - executeAction(card, options.positionTo, result.command); - } else if (result.updated || result.deleted) { - notifyRefreshNeeded(card, options.itemsContainer); - } - }) - .catch(() => { /* no-op */ }); - }); - }); + playlistId, + canEditPlaylist: !!playlistPerms.CanEdit, + collectionId, + user, + ...options + }); + }) + .then(result => { + if (result.command === 'playallfromhere' || result.command === 'queueallfromhere') { + executeAction(card, options.positionTo, result.command); + } else if (result.updated || result.deleted) { + notifyRefreshNeeded(card, options.itemsContainer); + } + }) + .catch(() => { /* no-op */ }); }); } @@ -406,8 +435,8 @@ export function getShortcutAttributesHtml(item, serverId) { } export default { - on: on, - off: off, - onClick: onClick, - getShortcutAttributesHtml: getShortcutAttributesHtml + on, + off, + onClick, + getShortcutAttributesHtml };