Repository navigation
feat: respect per-user library and label restrictions when reporting availability (Plex, Jellyfin, Emby) #3296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Izakun
wants to merge
19
commits into
seerr-team:develop
Choose a base branch
from
Izakun:feat/per-user-library-scope
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
5231ed2
feat(plex): respect per-user library restrictions when reporting avai…
Izakun ea25f33
feat(plex): optionally grant library access when a request is approved
Izakun f91e04b
feat(jellyfin): respect per-user library restrictions when reporting …
Izakun f3cab77
fix: address review feedback on library sharing restrictions
Izakun 8a802e6
fix(media): drop deep links for restricted media
Izakun 552c4db
fix(requests): apply library restrictions to request media
Izakun a00bc31
fix(plex): grant the most exclusive label a user is allowed to see
Izakun 009cbed
docs(settings): describe which label the grant setting applies
Izakun 4914b8b
chore(plex): log the resolved visible item count
Izakun f9bc03d
docs(jellyfin): correct the claim that access is per library only
Izakun 95b112e
fix(emby): match library policy entries on the guid as well
Izakun d72a015
feat(jellyfin,emby): honour tag restrictions alongside library access
Izakun e7e76ec
fix(requests): complete already available media before any arr lookup
Izakun 6ae0211
test(plex): use fictional names in the grant label fixtures
Izakun e2dd49a
fix(media): drop items the per-user downgrade took out of the filter
Izakun d30d065
fix(media): keep the page full for a restricted user
Izakun 49d4251
fix(plex): only grant the label named after the user
Izakun e3a05be
fix(requests): grant the label once the download makes the media avai…
Izakun 817f3e8
fix(requests): grant the label outside the completing transaction
Izakun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| import { | ||
| isAllowedByLabelFilter, | ||
| parsePlexLabelFilter, | ||
| } from '@server/api/plextv'; | ||
| import assert from 'node:assert/strict'; | ||
| import { describe, it } from 'node:test'; | ||
|
|
||
| describe('parsePlexLabelFilter', () => { | ||
| it('returns empty lists when no restriction is set', () => { | ||
| for (const value of [undefined, null, '']) { | ||
| assert.deepEqual(parsePlexLabelFilter(value), { allow: [], deny: [] }); | ||
| } | ||
| }); | ||
|
|
||
| it('parses a single allowed label', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label=Family'), { | ||
| allow: ['Family'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('parses several comma separated labels', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label=Family,Kids'), { | ||
| allow: ['Family', 'Kids'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('decodes url encoded values, as returned by plex.tv', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label=Family%2CKids'), { | ||
| allow: ['Family', 'Kids'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('parses negated restrictions into the deny list', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label!=Private'), { | ||
| allow: [], | ||
| deny: ['Private'], | ||
| }); | ||
| }); | ||
|
|
||
| it('handles allow and deny clauses in the same filter', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label=Family&label!=Private'), { | ||
| allow: ['Family'], | ||
| deny: ['Private'], | ||
| }); | ||
| }); | ||
|
|
||
| it('ignores clauses that are not label based', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('contentRating=PG&label=Family'), { | ||
| allow: ['Family'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('keeps encoded separators inside a label value', () => { | ||
| // %26 is `&`, which must not be mistaken for a clause separator. | ||
| assert.deepEqual(parsePlexLabelFilter('label=Tom%20%26%20Jerry'), { | ||
| allow: ['Tom & Jerry'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('does not throw on a malformed encoding', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label=100%'), { | ||
| allow: ['100%'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
|
|
||
| it('drops empty values and surrounding whitespace', () => { | ||
| assert.deepEqual(parsePlexLabelFilter('label= Family , ,Kids '), { | ||
| allow: ['Family', 'Kids'], | ||
| deny: [], | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| describe('isAllowedByLabelFilter', () => { | ||
| it('hides everything when the restrictions cannot be satisfied', () => { | ||
| assert.equal( | ||
| isAllowedByLabelFilter({ allow: [], deny: [], allowNothing: true }, [ | ||
| 'Family', | ||
| ]), | ||
| false | ||
| ); | ||
| }); | ||
|
|
||
| it('allows anything when no restriction applies', () => { | ||
| assert.equal(isAllowedByLabelFilter({ allow: [], deny: [] }, []), true); | ||
| assert.equal( | ||
| isAllowedByLabelFilter({ allow: [], deny: [] }, ['Family']), | ||
| true | ||
| ); | ||
| }); | ||
|
|
||
| it('requires one of the allowed labels', () => { | ||
| const filter = { allow: ['Family', 'Kids'], deny: [] }; | ||
|
|
||
| assert.equal(isAllowedByLabelFilter(filter, ['Family']), true); | ||
| assert.equal(isAllowedByLabelFilter(filter, ['Other', 'Kids']), true); | ||
| assert.equal(isAllowedByLabelFilter(filter, ['Other']), false); | ||
| }); | ||
|
|
||
| it('hides unlabelled media when an allow list is set', () => { | ||
| assert.equal( | ||
| isAllowedByLabelFilter({ allow: ['Family'], deny: [] }, []), | ||
| false | ||
| ); | ||
| }); | ||
|
|
||
| it('denies media carrying a denied label, even when also allowed', () => { | ||
| assert.equal( | ||
| isAllowedByLabelFilter({ allow: ['Family'], deny: ['Private'] }, [ | ||
| 'Family', | ||
| 'Private', | ||
| ]), | ||
| false | ||
| ); | ||
| }); | ||
|
|
||
| it('compares labels case insensitively', () => { | ||
| assert.equal( | ||
| isAllowedByLabelFilter({ allow: ['family'], deny: [] }, ['Family']), | ||
| true | ||
| ); | ||
| assert.equal( | ||
| isAllowedByLabelFilter({ allow: [], deny: ['private'] }, ['PRIVATE']), | ||
| false | ||
| ); | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.