feat(rbac): implement NIP-29 room roles and permission gating (#47)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {sortBy} from "@welshman/lib"
|
||||
import {goto} from "$app/navigation"
|
||||
import type {RoomMeta} from "@welshman/util"
|
||||
import {displayRelayUrl, makeRoomMeta} from "@welshman/util"
|
||||
@@ -27,10 +28,12 @@
|
||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import ProfileCircles from "@app/components/ProfileCircles.svelte"
|
||||
import RoleBadge from "@app/components/RoleBadge.svelte"
|
||||
import RoomMembers from "@app/components/RoomMembers.svelte"
|
||||
import RoomEdit from "@app/components/RoomEdit.svelte"
|
||||
import RoomName from "@app/components/RoomName.svelte"
|
||||
import RoomImage from "@app/components/RoomImage.svelte"
|
||||
import {deriveRoomRoles, hasPermission} from "@app/core/roles"
|
||||
import {
|
||||
deriveRoom,
|
||||
deriveRoomMembers,
|
||||
@@ -58,13 +61,29 @@
|
||||
|
||||
const room = deriveRoom(url, h)
|
||||
const members = deriveRoomMembers(url, h)
|
||||
const roomRoles = deriveRoomRoles(url, h)
|
||||
const userIsAdmin = deriveUserIsRoomAdmin(url, h)
|
||||
const canEditMetadata = hasPermission(url, h, 9002)
|
||||
const membershipStatus = deriveUserRoomMembershipStatus(url, h)
|
||||
const userRooms = deriveUserRooms(url)
|
||||
|
||||
const isFavorite = $derived($userRooms.includes(h))
|
||||
const shouldNotify = deriveShouldNotify(url, h)
|
||||
|
||||
const roleRows = $derived.by(() =>
|
||||
sortBy(
|
||||
role => -(role.order ?? -Infinity),
|
||||
Array.from($roomRoles.roles.values()).map(role => ({
|
||||
name: role.name,
|
||||
label: role.label,
|
||||
color: role.color,
|
||||
order: role.order,
|
||||
permissionsLabel: role.permissions.join(", "),
|
||||
accessLabel: Array.from(role.access).join(", "),
|
||||
})),
|
||||
),
|
||||
)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
const toggleMenu = () => {
|
||||
@@ -152,7 +171,7 @@
|
||||
<ul
|
||||
transition:fly
|
||||
class="bg-alt menu absolute right-0 z-popover w-48 gap-1 rounded-box p-2 shadow-md">
|
||||
{#if $userIsAdmin}
|
||||
{#if $canEditMetadata}
|
||||
<li>
|
||||
<Button onclick={startEdit}>
|
||||
<Icon icon={Pen} />
|
||||
@@ -247,7 +266,7 @@
|
||||
<div class="card2 card2-sm bg-alt flex items-center justify-between gap-4">
|
||||
<div class="flex items-center gap-4">
|
||||
<span>Members:</span>
|
||||
<ProfileCircles pubkeys={$members} />
|
||||
<ProfileCircles pubkeys={$members.map(member => member.pubkey)} />
|
||||
</div>
|
||||
<Button class="btn btn-neutral btn-sm" onclick={showMembers}>View All</Button>
|
||||
</div>
|
||||
@@ -256,6 +275,33 @@
|
||||
<span class="text-error">Member list not available from this relay</span>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $userIsAdmin && roleRows.length > 0}
|
||||
<div class="card2 card2-sm bg-alt col-4">
|
||||
<strong class="text-lg">Role Definitions</strong>
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each roleRows as role (role.name)}
|
||||
<div class="rounded-box bg-base-300 p-3 flex flex-col gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<RoleBadge
|
||||
role={role.name}
|
||||
label={role.label}
|
||||
color={role.color}
|
||||
class="badge-md" />
|
||||
{#if role.order !== undefined}
|
||||
<span class="text-xs opacity-70">Order {role.order}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if role.permissionsLabel}
|
||||
<p class="text-xs opacity-75">Permissions: {role.permissionsLabel}</p>
|
||||
{/if}
|
||||
{#if role.accessLabel}
|
||||
<p class="text-xs opacity-75">Access: {role.accessLabel}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="card2 card2-sm bg-alt col-4">
|
||||
<strong class="text-lg">Room Settings</strong>
|
||||
<div class="flex items-center justify-between">
|
||||
|
||||
Reference in New Issue
Block a user