fix(nav): show the player game-data groups to staff #24
@@ -21,7 +21,12 @@ enum class MenuAccess {
|
|||||||
/** Visible to any signed-in account (§5, "My Account"). */
|
/** Visible to any signed-in account (§5, "My Account"). */
|
||||||
SIGNED_IN,
|
SIGNED_IN,
|
||||||
|
|
||||||
/** Visible only to a player — the linked game-data groups (§6.3). */
|
/**
|
||||||
|
* The linked game-data groups (§6.3). Visible to any player **or** staff:
|
||||||
|
* staff are a superset of players (all player abilities plus their staff
|
||||||
|
* tools), and the backend's player self-service surface is role-agnostic, so
|
||||||
|
* a signed-in admin/editor/moderator sees + uses their own characters too.
|
||||||
|
*/
|
||||||
PLAYER,
|
PLAYER,
|
||||||
|
|
||||||
/** Visible to any staff role (admin/editor/moderator) — the M10 staff surface (§1). */
|
/** Visible to any staff role (admin/editor/moderator) — the M10 staff surface (§1). */
|
||||||
@@ -70,7 +75,7 @@ fun visibleEntries(entries: List<MenuEntry>, session: Session): List<MenuEntry>
|
|||||||
when (entry.access) {
|
when (entry.access) {
|
||||||
MenuAccess.PUBLIC -> true
|
MenuAccess.PUBLIC -> true
|
||||||
MenuAccess.SIGNED_IN -> session is Session.SignedIn
|
MenuAccess.SIGNED_IN -> session is Session.SignedIn
|
||||||
MenuAccess.PLAYER -> session is Session.SignedIn && session.user.isPlayer
|
MenuAccess.PLAYER -> session is Session.SignedIn && (session.user.isPlayer || session.user.isStaff)
|
||||||
MenuAccess.STAFF -> session is Session.SignedIn && session.user.isStaff
|
MenuAccess.STAFF -> session is Session.SignedIn && session.user.isStaff
|
||||||
MenuAccess.MODERATOR -> session is Session.SignedIn && session.user.isModerator
|
MenuAccess.MODERATOR -> session is Session.SignedIn && session.user.isModerator
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,12 +37,16 @@ class MenuAccessTest {
|
|||||||
assertTrue(visible.contains(Routes.HOME))
|
assertTrue(visible.contains(Routes.HOME))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun staffSeeAccountButNoPlayerOnlyGroups() {
|
@Test fun staffSeeThePlayerGameDataGroups() {
|
||||||
val visible = routes(signedIn(Role.EDITOR))
|
// Staff are a superset of players: every staff role sees the PLAYER-access
|
||||||
assertTrue(visible.contains(Routes.ACCOUNT))
|
// game-data groups too (their own linked characters, via the role-agnostic
|
||||||
// No PLAYER-access entry (the M4 game-data groups) leaks to staff.
|
// /player self-service surface), on top of their staff entries.
|
||||||
val playerOnly = APP_MENU.filter { it.access == MenuAccess.PLAYER }.map { it.route }
|
val playerGroups = APP_MENU.filter { it.access == MenuAccess.PLAYER }.map { it.route }
|
||||||
assertTrue(playerOnly.none { visible.contains(it) })
|
for (role in listOf(Role.ADMIN, Role.EDITOR, Role.MODERATOR)) {
|
||||||
|
val visible = routes(signedIn(role))
|
||||||
|
assertTrue("$role should see Account", visible.contains(Routes.ACCOUNT))
|
||||||
|
assertTrue("$role should see the player game-data groups", playerGroups.all { visible.contains(it) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test fun publicEntryCountIsStableAcrossSessions() {
|
@Test fun publicEntryCountIsStableAcrossSessions() {
|
||||||
@@ -58,10 +62,13 @@ class MenuAccessTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test fun playerAccessGatedFunction() {
|
@Test fun playerAccessGatedFunction() {
|
||||||
// A synthetic PLAYER-gated entry is visible to a player, hidden from staff/anon.
|
// A PLAYER-gated entry is visible to a player AND to every staff role
|
||||||
|
// (staff superset), hidden only from an unrecognized role and anon.
|
||||||
val entries = listOf(MenuEntry("game", 0, MenuAccess.PLAYER))
|
val entries = listOf(MenuEntry("game", 0, MenuAccess.PLAYER))
|
||||||
assertTrue(visibleEntries(entries, signedIn(Role.PLAYER)).isNotEmpty())
|
for (role in listOf(Role.PLAYER, Role.ADMIN, Role.EDITOR, Role.MODERATOR)) {
|
||||||
assertTrue(visibleEntries(entries, signedIn(Role.ADMIN)).isEmpty())
|
assertTrue("$role should see a PLAYER entry", visibleEntries(entries, signedIn(role)).isNotEmpty())
|
||||||
|
}
|
||||||
|
assertTrue(visibleEntries(entries, signedIn(Role.UNKNOWN)).isEmpty())
|
||||||
assertTrue(visibleEntries(entries, Session.SignedOut).isEmpty())
|
assertTrue(visibleEntries(entries, Session.SignedOut).isEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user