diff --git a/server/lib/permissions.ts b/server/lib/permissions.ts index edc9f7e183..e42429a9fb 100644 --- a/server/lib/permissions.ts +++ b/server/lib/permissions.ts @@ -28,6 +28,7 @@ export enum Permission { RECENT_VIEW = 67108864, WATCHLIST_VIEW = 134217728, MANAGE_BLOCKLIST = 268435456, + REQUEST_ADVANCED_LANGUAGE = 536870912, VIEW_BLOCKLIST = 1073741824, } diff --git a/src/components/PermissionEdit/index.tsx b/src/components/PermissionEdit/index.tsx index cbba176cba..8efae1dc8f 100644 --- a/src/components/PermissionEdit/index.tsx +++ b/src/components/PermissionEdit/index.tsx @@ -53,6 +53,9 @@ export const messages = defineMessages('components.PermissionEdit', { advancedrequest: 'Advanced Requests', advancedrequestDescription: 'Grant permission to modify advanced media request options.', + advancedrequestLanguage: 'Advanced Requests: Language Profile', + advancedrequestLanguageDescription: + 'Grant permission to override only the language profile on series requests.', autorequest: 'Auto-Request', autorequestDescription: 'Grant permission to automatically submit requests for non-4K media via Plex Watchlist.', @@ -127,6 +130,16 @@ export const PermissionEdit = ({ name: intl.formatMessage(messages.advancedrequest), description: intl.formatMessage(messages.advancedrequestDescription), permission: Permission.REQUEST_ADVANCED, + children: [ + { + id: 'advancedrequest-language', + name: intl.formatMessage(messages.advancedrequestLanguage), + description: intl.formatMessage( + messages.advancedrequestLanguageDescription + ), + permission: Permission.REQUEST_ADVANCED_LANGUAGE, + }, + ], }, { id: 'viewrequests', diff --git a/src/components/RequestModal/AdvancedRequester/index.tsx b/src/components/RequestModal/AdvancedRequester/index.tsx index 0520d7ab27..e5b09b3c57 100644 --- a/src/components/RequestModal/AdvancedRequester/index.tsx +++ b/src/components/RequestModal/AdvancedRequester/index.tsx @@ -111,6 +111,15 @@ const AdvancedRequester = ({ currentHasPermission([Permission.MANAGE_REQUESTS]) && ((type === 'movie' ? quota?.movie.limit : quota?.tv.limit) ?? 0) > 0; + // Users with the legacy "all-or-nothing" Advanced Request permission or + // Manage Requests see every advanced field. Users who only hold a granular + // sub-permission (e.g. REQUEST_ADVANCED_LANGUAGE) only see the matching + // field. This keeps backward compatibility while allowing per-field grants. + const canEditLegacyAdvancedFields = currentHasPermission( + [Permission.MANAGE_REQUESTS, Permission.REQUEST_ADVANCED], + { type: 'or' } + ); + const { data: serverData, isValidating } = useSWR( selectedServer !== null @@ -353,141 +362,155 @@ const AdvancedRequester = ({
{!!data && selectedServer !== null && (
- {data.filter((server) => server.is4k === is4k).length > 1 && ( -
- - -
- )} - {(isValidating || - !serverData || - serverData.profiles.length > 1) && ( -
- - setSelectedServer(Number(e.target.value))} + onBlur={(e) => setSelectedServer(Number(e.target.value))} + className="border-gray-700 bg-gray-800" + > + {data + .filter((server) => server.is4k === is4k) + .map((server) => ( + ))} + +
+ )} + {canEditLegacyAdvancedFields && + (isValidating || + !serverData || + serverData.profiles.length > 1) && ( +
+ + -
- )} - {(isValidating || - !serverData || - serverData.rootFolders.length > 1) && ( -
- - +
+ )} + {canEditLegacyAdvancedFields && + (isValidating || + !serverData || + serverData.rootFolders.length > 1) && ( +
+ + -
- )} + : !isAnime && + serverData.server.activeDirectory === + folder.path + ? intl.formatMessage(messages.default, { + name: intl.formatMessage(messages.folder, { + path: folder.path, + space: formatBytes(folder.freeSpace ?? 0), + }), + }) + : intl.formatMessage(messages.folder, { + path: folder.path, + space: formatBytes(folder.freeSpace ?? 0), + })} + + ))} + +
+ )} {type === 'tv' && + currentHasPermission( + [ + Permission.MANAGE_REQUESTS, + Permission.REQUEST_ADVANCED, + Permission.REQUEST_ADVANCED_LANGUAGE, + ], + { type: 'or' } + ) && (isValidating || !serverData || (serverData.languageProfiles ?? []).length > 1) && ( @@ -540,7 +563,8 @@ const AdvancedRequester = ({ )}
)} - {selectedServer !== null && + {canEditLegacyAdvancedFields && + selectedServer !== null && (isValidating || !serverData || !!serverData?.tags?.length) && (
diff --git a/src/components/RequestModal/TvRequestModal.tsx b/src/components/RequestModal/TvRequestModal.tsx index 2dfed160a3..00aad2bd6d 100644 --- a/src/components/RequestModal/TvRequestModal.tsx +++ b/src/components/RequestModal/TvRequestModal.tsx @@ -714,8 +714,14 @@ const TvRequestModal = ({
- {(hasPermission(Permission.REQUEST_ADVANCED) || - hasPermission(Permission.MANAGE_REQUESTS)) && ( + {hasPermission( + [ + Permission.MANAGE_REQUESTS, + Permission.REQUEST_ADVANCED, + Permission.REQUEST_ADVANCED_LANGUAGE, + ], + { type: 'or' } + ) && (