Also check Seerr parent permissions (#1631)

## Description
When saving Seerr permissions on the WebUI, if a "parent" permission is
checked, only its bit is flipped and its children's bits are not. So
clients must check if a user has the permission _or_ its parent.

For example, if just "Request 4K" is checked, the flags for "Request 4K
Movies" and "Request 4K TV" will not set explicitly.

### Related issues
Fixes #1630

### Testing
Emulator & unit tests, also manually reviewed API requests/responses on
Seerr's web UI

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-06-27 14:28:57 -04:00 • committed by GitHub
parent a8ade9171e
commit 21e720c420
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 92 additions and 14 deletions

View file

@ -7,6 +7,7 @@ import com.github.damontecres.wholphin.services.SeerrUserConfig
*/
enum class SeerrPermission(
private val flag: Int,
vararg val parents: SeerrPermission,
) {
// Source: https://github.com/seerr-team/seerr/blob/develop/server/lib/permissions.ts
NONE(0),
@ -17,28 +18,28 @@ enum class SeerrPermission(
REQUEST(32),
VOTE(64),
AUTO_APPROVE(128),
AUTO_APPROVE_MOVIE(256),
AUTO_APPROVE_TV(512),
AUTO_APPROVE_MOVIE(256, AUTO_APPROVE),
AUTO_APPROVE_TV(512, AUTO_APPROVE),
REQUEST_4K(1024),
REQUEST_4K_MOVIE(2048),
REQUEST_4K_TV(4096),
REQUEST_4K_MOVIE(2048, REQUEST_4K),
REQUEST_4K_TV(4096, REQUEST_4K),
REQUEST_ADVANCED(8192),
REQUEST_VIEW(16384),
AUTO_APPROVE_4K(32768),
AUTO_APPROVE_4K_MOVIE(65536),
AUTO_APPROVE_4K_TV(131072),
REQUEST_MOVIE(262144),
REQUEST_TV(524288),
AUTO_APPROVE_4K_MOVIE(65536, AUTO_APPROVE_4K),
AUTO_APPROVE_4K_TV(131072, AUTO_APPROVE_4K),
REQUEST_MOVIE(262144, REQUEST),
REQUEST_TV(524288, REQUEST),
MANAGE_ISSUES(1048576),
VIEW_ISSUES(2097152),
CREATE_ISSUES(4194304),
VIEW_ISSUES(2097152, MANAGE_ISSUES),
CREATE_ISSUES(4194304, MANAGE_ISSUES),
AUTO_REQUEST(8388608),
AUTO_REQUEST_MOVIE(16777216),
AUTO_REQUEST_TV(33554432),
AUTO_REQUEST_MOVIE(16777216, AUTO_REQUEST),
AUTO_REQUEST_TV(33554432, AUTO_REQUEST),
RECENT_VIEW(67108864),
WATCHLIST_VIEW(134217728),
MANAGE_BLACKLIST(268435456),
VIEW_BLACKLIST(1073741824),
VIEW_BLACKLIST(1073741824, MANAGE_BLACKLIST),
;
internal fun hasPermission(permissions: Int) = flag.and(permissions) == flag
@ -48,5 +49,8 @@ enum class SeerrPermission(
* Check whether the user has the given permissions (or is an admin)
*/
fun SeerrUserConfig?.hasPermission(permission: SeerrPermission): Boolean {
return permission.hasPermission(this?.permissions ?: return false) || SeerrPermission.ADMIN.hasPermission(permissions)
if (this?.permissions == null) return false
return permission.hasPermission(permissions) ||
permission.parents.any { hasPermission(it) } ||
SeerrPermission.ADMIN.hasPermission(permissions)
}

View file

@ -0,0 +1,74 @@
package com.github.damontecres.wholphin.test
import com.github.damontecres.wholphin.data.model.SeerrPermission
import com.github.damontecres.wholphin.data.model.hasPermission
import com.github.damontecres.wholphin.services.SeerrUserConfig
import org.junit.Assert
import org.junit.Test
class TestSeerrPermission {
@Test
fun `Is Admin`() {
val user =
SeerrUserConfig(
id = 0,
permissions = 2,
)
Assert.assertTrue(user.hasPermission(SeerrPermission.ADMIN))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_MOVIE))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_TV))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K))
}
@Test
fun `Request any 4k has request movie 4k`() {
val user =
SeerrUserConfig(
id = 0,
permissions = 1024,
)
Assert.assertFalse(user.hasPermission(SeerrPermission.ADMIN))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_MOVIE))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_TV))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K))
}
@Test
fun `Request movie 4k and does not have request tv 4k`() {
val user =
SeerrUserConfig(
id = 0,
permissions = 2048,
)
Assert.assertFalse(user.hasPermission(SeerrPermission.ADMIN))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_MOVIE))
Assert.assertFalse(user.hasPermission(SeerrPermission.REQUEST_4K_TV))
Assert.assertFalse(user.hasPermission(SeerrPermission.REQUEST_4K))
}
@Test
fun `Has explicit request 4k and children`() {
val user =
SeerrUserConfig(
id = 0,
permissions = 7168,
)
Assert.assertFalse(user.hasPermission(SeerrPermission.ADMIN))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_MOVIE))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_TV))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K))
}
@Test
fun `Has explicit request 4k children`() {
val user =
SeerrUserConfig(
id = 0,
permissions = 6144,
)
Assert.assertFalse(user.hasPermission(SeerrPermission.ADMIN))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_MOVIE))
Assert.assertTrue(user.hasPermission(SeerrPermission.REQUEST_4K_TV))
Assert.assertFalse(user.hasPermission(SeerrPermission.REQUEST_4K))
}
}