Support unban/unallow
This commit is contained in:
parent
606a9343d9
commit
65483a6ef0
4 changed files with 117 additions and 40 deletions
1
.ackrc
1
.ackrc
|
|
@ -1,5 +1,6 @@
|
||||||
--ignore-dir=.svelte-kit
|
--ignore-dir=.svelte-kit
|
||||||
--ignore-dir=android
|
--ignore-dir=android
|
||||||
|
--ignore-dir=target
|
||||||
--ignore-dir=build
|
--ignore-dir=build
|
||||||
--ignore-dir=ios/DerivedData
|
--ignore-dir=ios/DerivedData
|
||||||
--ignore-dir=ios/App/App/public
|
--ignore-dir=ios/App/App/public
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import {ManagementMethod} from "@welshman/util"
|
import {ManagementMethod} from "@welshman/util"
|
||||||
import {manageRelay, displayProfileByPubkey} from "@welshman/app"
|
import {manageRelay, displayProfileByPubkey} from "@welshman/app"
|
||||||
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
|
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
|
||||||
|
import UserMinus from "@assets/icons/user-minus.svg?dataurl"
|
||||||
import MinusCircle from "@assets/icons/minus-circle.svg?dataurl"
|
import MinusCircle from "@assets/icons/minus-circle.svg?dataurl"
|
||||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
deriveSpaceMembers,
|
deriveSpaceMembers,
|
||||||
deriveSpaceBannedPubkeyItems,
|
deriveSpaceBannedPubkeyItems,
|
||||||
deriveUserIsSpaceAdmin,
|
deriveUserIsSpaceAdmin,
|
||||||
|
deriveSupportedMethods,
|
||||||
} from "@app/core/state"
|
} from "@app/core/state"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
|
|
@ -37,6 +39,9 @@
|
||||||
const members = deriveSpaceMembers(url)
|
const members = deriveSpaceMembers(url)
|
||||||
const bans = deriveSpaceBannedPubkeyItems(url)
|
const bans = deriveSpaceBannedPubkeyItems(url)
|
||||||
const userIsAdmin = deriveUserIsSpaceAdmin(url)
|
const userIsAdmin = deriveUserIsSpaceAdmin(url)
|
||||||
|
const supportedMethods = deriveSupportedMethods(url)
|
||||||
|
const canBan = $derived($supportedMethods.includes(ManagementMethod.BanPubkey))
|
||||||
|
const canUnallow = $derived($supportedMethods.includes(ManagementMethod.UnallowPubkey))
|
||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
|
|
@ -52,6 +57,25 @@
|
||||||
|
|
||||||
const addMember = () => pushModal(SpaceMembersAdd, {url})
|
const addMember = () => pushModal(SpaceMembersAdd, {url})
|
||||||
|
|
||||||
|
const unallowMember = (pubkey: string) =>
|
||||||
|
pushModal(Confirm, {
|
||||||
|
title: "Remove User",
|
||||||
|
message: `Are you sure you want to remove @${displayProfileByPubkey(pubkey)} from the space?`,
|
||||||
|
confirm: async () => {
|
||||||
|
const {error} = await manageRelay(url, {
|
||||||
|
method: ManagementMethod.UnallowPubkey,
|
||||||
|
params: [pubkey],
|
||||||
|
})
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
pushToast({theme: "error", message: error})
|
||||||
|
} else {
|
||||||
|
pushToast({message: "User has successfully been removed!"})
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const banMember = (pubkey: string) =>
|
const banMember = (pubkey: string) =>
|
||||||
pushModal(Confirm, {
|
pushModal(Confirm, {
|
||||||
title: "Ban User",
|
title: "Ban User",
|
||||||
|
|
@ -94,25 +118,37 @@
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<Profile {pubkey} {url} />
|
<Profile {pubkey} {url} />
|
||||||
</div>
|
</div>
|
||||||
<div class="relative">
|
{#if canBan || canUnallow}
|
||||||
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
|
<div class="relative">
|
||||||
<Icon icon={MenuDots} />
|
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
|
||||||
</Button>
|
<Icon icon={MenuDots} />
|
||||||
{#if menuPubkey === pubkey}
|
</Button>
|
||||||
<Popover hideOnClick onClose={closeMenu}>
|
{#if menuPubkey === pubkey}
|
||||||
<ul
|
<Popover hideOnClick onClose={closeMenu}>
|
||||||
transition:fly
|
<ul
|
||||||
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
|
transition:fly
|
||||||
<li>
|
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
|
||||||
<Button class="text-error" onclick={() => banMember(pubkey)}>
|
{#if canUnallow}
|
||||||
<Icon icon={MinusCircle} />
|
<li>
|
||||||
Ban User
|
<Button onclick={() => unallowMember(pubkey)}>
|
||||||
</Button>
|
<Icon icon={UserMinus} />
|
||||||
</li>
|
Remove User
|
||||||
</ul>
|
</Button>
|
||||||
</Popover>
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{#if canBan}
|
||||||
|
<li>
|
||||||
|
<Button class="text-error" onclick={() => banMember(pubkey)}>
|
||||||
|
<Icon icon={MinusCircle} />
|
||||||
|
Ban User
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</Popover>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
import {manageRelay} from "@welshman/app"
|
import {manageRelay} from "@welshman/app"
|
||||||
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
|
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
|
||||||
import Restart from "@assets/icons/restart.svg?dataurl"
|
import Restart from "@assets/icons/restart.svg?dataurl"
|
||||||
|
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
||||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||||
import {fly} from "@lib/transition"
|
import {fly} from "@lib/transition"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
|
|
@ -15,7 +16,7 @@
|
||||||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||||
import Profile from "@app/components/Profile.svelte"
|
import Profile from "@app/components/Profile.svelte"
|
||||||
import {deriveSpaceBannedPubkeyItems} from "@app/core/state"
|
import {deriveSpaceBannedPubkeyItems, deriveSupportedMethods} from "@app/core/state"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -25,6 +26,9 @@
|
||||||
const {url}: Props = $props()
|
const {url}: Props = $props()
|
||||||
|
|
||||||
const bans = deriveSpaceBannedPubkeyItems(url)
|
const bans = deriveSpaceBannedPubkeyItems(url)
|
||||||
|
const supportedMethods = deriveSupportedMethods(url)
|
||||||
|
const canUnban = $derived($supportedMethods.includes(ManagementMethod.UnbanPubkey))
|
||||||
|
const canRestore = $derived($supportedMethods.includes(ManagementMethod.AllowPubkey))
|
||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
|
|
@ -36,6 +40,20 @@
|
||||||
menuPubkey = undefined
|
menuPubkey = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unbanMember = async (pubkey: string) => {
|
||||||
|
const {error} = await manageRelay(url, {
|
||||||
|
method: ManagementMethod.UnbanPubkey,
|
||||||
|
params: [pubkey],
|
||||||
|
})
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
pushToast({theme: "error", message: error})
|
||||||
|
} else {
|
||||||
|
pushToast({message: "User has successfully been removed from the ban list!"})
|
||||||
|
back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const restoreMember = async (pubkey: string) => {
|
const restoreMember = async (pubkey: string) => {
|
||||||
const {error} = await manageRelay(url, {
|
const {error} = await manageRelay(url, {
|
||||||
method: ManagementMethod.AllowPubkey,
|
method: ManagementMethod.AllowPubkey,
|
||||||
|
|
@ -45,7 +63,7 @@
|
||||||
if (error) {
|
if (error) {
|
||||||
pushToast({theme: "error", message: error})
|
pushToast({theme: "error", message: error})
|
||||||
} else {
|
} else {
|
||||||
pushToast({message: "User has successfully been restored!"})
|
pushToast({message: "User has successfully been restored to membership!"})
|
||||||
back()
|
back()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,25 +84,37 @@
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<Profile {pubkey} {url} />
|
<Profile {pubkey} {url} />
|
||||||
</div>
|
</div>
|
||||||
<div class="relative">
|
{#if canUnban || canRestore}
|
||||||
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
|
<div class="relative">
|
||||||
<Icon icon={MenuDots} />
|
<Button class="btn btn-circle btn-ghost btn-sm" onclick={() => toggleMenu(pubkey)}>
|
||||||
</Button>
|
<Icon icon={MenuDots} />
|
||||||
{#if menuPubkey === pubkey}
|
</Button>
|
||||||
<Popover hideOnClick onClose={closeMenu}>
|
{#if menuPubkey === pubkey}
|
||||||
<ul
|
<Popover hideOnClick onClose={closeMenu}>
|
||||||
transition:fly
|
<ul
|
||||||
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
|
transition:fly
|
||||||
<li>
|
class="menu absolute right-0 z-popover mt-2 w-48 gap-1 rounded-box bg-base-100 p-2 shadow-md">
|
||||||
<Button onclick={() => restoreMember(pubkey)}>
|
{#if canUnban}
|
||||||
<Icon icon={Restart} />
|
<li>
|
||||||
Restore User
|
<Button onclick={() => unbanMember(pubkey)}>
|
||||||
</Button>
|
<Icon icon={CloseCircle} />
|
||||||
</li>
|
Unban User
|
||||||
</ul>
|
</Button>
|
||||||
</Popover>
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{#if canRestore}
|
||||||
|
<li>
|
||||||
|
<Button onclick={() => restoreMember(pubkey)}>
|
||||||
|
<Icon icon={Restart} />
|
||||||
|
Restore User
|
||||||
|
</Button>
|
||||||
|
</li>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
</Popover>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import {
|
||||||
fromPairs,
|
fromPairs,
|
||||||
groupBy,
|
groupBy,
|
||||||
remove,
|
remove,
|
||||||
|
simpleCache,
|
||||||
} from "@welshman/lib"
|
} from "@welshman/lib"
|
||||||
import type {Override} from "@welshman/lib"
|
import type {Override} from "@welshman/lib"
|
||||||
import type {RepositoryUpdate} from "@welshman/net"
|
import type {RepositoryUpdate} from "@welshman/net"
|
||||||
|
|
@ -1124,6 +1125,15 @@ export const deriveSocketStatus = (url: string) =>
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const deriveSupportedMethods = simpleCache(([url]: [string]) => {
|
||||||
|
return readable<ManagementMethod[]>([], set => {
|
||||||
|
manageRelay(url, {
|
||||||
|
method: ManagementMethod.SupportedMethods,
|
||||||
|
params: [],
|
||||||
|
}).then(({result = []}) => set(result))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
export const deriveTimeout = (timeout: number) => {
|
export const deriveTimeout = (timeout: number) => {
|
||||||
const store = writable<boolean>(false)
|
const store = writable<boolean>(false)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue