allow blocked users to sign up, block server join instead
All checks were successful
deploy / build-and-deploy (push) Successful in 19s
All checks were successful
deploy / build-and-deploy (push) Successful in 19s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -62,17 +62,6 @@ export const signup = {
|
||||
}
|
||||
}
|
||||
|
||||
// check if user is blocked
|
||||
if (uuid) {
|
||||
const blockedUser = await db.getBlockedUserByUuid({ uuid: uuid });
|
||||
if (blockedUser) {
|
||||
throw new ActionError({
|
||||
code: 'FORBIDDEN',
|
||||
message: 'Du bist für die Registrierung gesperrt'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await db.transaction(async (tx) => {
|
||||
const user = await tx.addUser({
|
||||
firstname: input.firstname,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
function onBlockedUserDelete(blockedUser: BlockedUser) {
|
||||
$confirmPopupState = {
|
||||
title: 'Nutzer entblockieren?',
|
||||
message: 'Soll der Nutzer wirklich entblockiert werden?\nDieser kann sich danach wieder registrieren.',
|
||||
message: 'Soll der Nutzer wirklich entblockiert werden?\nDieser kann danach dem Server wieder beitreten.',
|
||||
onConfirm: () => deleteBlockedUser(blockedUser)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
submitButtonTitle: 'Erstellen',
|
||||
confirmPopupTitle: 'Nutzer blockieren',
|
||||
confirmPopupMessage:
|
||||
'Bist du sicher, dass der Nutzer blockiert werden soll?\nEin blockierter Nutzer kann sich nicht mehr registrieren.'
|
||||
'Bist du sicher, dass der Nutzer blockiert werden soll?\nEin blockierter Nutzer kann dem Server nicht mehr beitreten.'
|
||||
}}
|
||||
target={null}
|
||||
keys={[
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import DataTable from '@components/admin/table/DataTable.svelte';
|
||||
import { deleteUser, editUser, type User, users } from '@app/admin/users/users.ts';
|
||||
import { blockUser, deleteUser, editUser, type User, users } from '@app/admin/users/users.ts';
|
||||
import CrudPopup from '@components/admin/popup/CrudPopup.svelte';
|
||||
import { confirmPopupState } from '@components/popup/ConfirmPopup.ts';
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
});
|
||||
|
||||
// callback
|
||||
function onUserBlock(user: User) {
|
||||
$confirmPopupState = {
|
||||
title: 'Nutzer sperren?',
|
||||
message: 'Soll der Nutzer wirklich gesperrt werden?\nEin gesperrter Nutzer kann dem Server nicht mehr beitreten.',
|
||||
onConfirm: () => blockUser(user)
|
||||
};
|
||||
}
|
||||
|
||||
function onUserDelete(user: User) {
|
||||
$confirmPopupState = {
|
||||
title: 'Nutzer löschen?',
|
||||
@@ -27,6 +35,14 @@
|
||||
<span>{value.charAt(0).toUpperCase() + value.slice(1)}</span>
|
||||
{/snippet}
|
||||
|
||||
{#snippet blockAction(user: User)}
|
||||
{#if user.uuid}
|
||||
<button class="cursor-pointer" onclick={() => onUserBlock(user)}>
|
||||
<span class="iconify iconify-[heroicons--no-symbol]"></span>
|
||||
</button>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
<DataTable
|
||||
data={users}
|
||||
count={true}
|
||||
@@ -39,6 +55,7 @@
|
||||
{ key: 'edition', label: 'Edition', width: 5, sortable: true, transform: edition },
|
||||
{ key: 'uuid', label: 'UUID', width: 23 }
|
||||
]}
|
||||
extraActions={blockAction}
|
||||
onEdit={(user) => (editPopupUser = user)}
|
||||
onDelete={onUserDelete}
|
||||
/>
|
||||
|
||||
@@ -58,6 +58,16 @@ export async function editUser(user: User) {
|
||||
updateWritableArray(users, user, (t) => t.id == user.id);
|
||||
}
|
||||
|
||||
export async function blockUser(user: User) {
|
||||
if (!user.uuid) return;
|
||||
|
||||
const { error } = await actions.user.addBlocked({ uuid: user.uuid, comment: null });
|
||||
if (error) {
|
||||
actionErrorPopup(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteUser(user: User) {
|
||||
const { error } = await actions.user.deleteUser({ id: user.id });
|
||||
if (error) {
|
||||
|
||||
@@ -21,10 +21,11 @@
|
||||
onClick?: (t: T) => void;
|
||||
onEdit?: (t: T) => void;
|
||||
onDelete?: (t: T) => void;
|
||||
extraActions?: Snippet<[T]>;
|
||||
}
|
||||
|
||||
// input
|
||||
let { data, count, keys, onClick, onEdit, onDelete }: Props<any> = $props();
|
||||
let { data, count, keys, onClick, onEdit, onDelete, extraActions }: Props<any> = $props();
|
||||
</script>
|
||||
|
||||
<div class="max-h-screen overflow-x-auto">
|
||||
@@ -39,7 +40,7 @@
|
||||
>{key.label}</SortableTh
|
||||
>
|
||||
{/each}
|
||||
{#if onEdit || onDelete}
|
||||
{#if onEdit || onDelete || extraActions}
|
||||
<SortableTh style="width: 5%"></SortableTh>
|
||||
{/if}
|
||||
</SortableTr>
|
||||
@@ -59,8 +60,11 @@
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
{#if onEdit || onDelete}
|
||||
<td class="px-3">
|
||||
{#if onEdit || onDelete || extraActions}
|
||||
<td class="px-3 whitespace-nowrap">
|
||||
{#if extraActions}
|
||||
{@render extraActions(d)}
|
||||
{/if}
|
||||
{#if onEdit}
|
||||
<button class="cursor-pointer" onclick={() => onEdit(d)}>
|
||||
<span class="iconify iconify-[heroicons--pencil-square]"></span>
|
||||
|
||||
@@ -4,7 +4,12 @@ import { db } from '@db/database.ts';
|
||||
export const GET = externalApi({
|
||||
auth: true,
|
||||
handler: async ({ params }) => {
|
||||
const user = await db.getUserByUuid({ uuid: params['uuid']! });
|
||||
const uuid = params['uuid']!;
|
||||
|
||||
const blockedUser = await db.getBlockedUserByUuid({ uuid });
|
||||
if (blockedUser) return new Response(null, { status: 403 });
|
||||
|
||||
const user = await db.getUserByUuid({ uuid });
|
||||
if (!user) return new Response(null, { status: 404 });
|
||||
|
||||
const strikes = await db.getStrikesByUserId({ userId: user.id });
|
||||
|
||||
Reference in New Issue
Block a user