f047_neu_Edit-der-Namen #28

Merged
trachi93 merged 14 commits from f047_neu_Edit-der-Namen into development 2025-08-19 09:30:13 +02:00
14 changed files with 425 additions and 330 deletions

View File

@@ -1,3 +1,31 @@
<script lang="ts">
export let href = null;
export let type: 'button' | 'submit' | 'reset' = 'button';
export let size = 'md';
export let variant = 'primary';
export let fullWidth = false;
export let align = 'center';
export let disabled = false;
let classNames = '';
export { classNames as class };
</script>
{#if href}
<a on:click {href} class:w-full={fullWidth} class="button {variant} {size} {classNames} {align}"
><slot />
</a>
{:else}
<button
on:click
{type}
{disabled}
class:w-full={fullWidth}
class="button {variant} {size} {classNames} {align}"
>
<slot />
</button>
{/if}
<style>
.button {
@apply inline-flex;
@@ -172,31 +200,3 @@
@apply justify-end;
}
</style>
<script lang="ts">
export let href = null;
export let type = 'button';
export let size = 'md';
export let variant = 'primary';
export let fullWidth = false;
export let align = 'center';
export let disabled = false;
let classNames = '';
export { classNames as class };
</script>
{#if href}
<a on:click {href} class:w-full={fullWidth} class="button {variant} {size} {classNames} {align}"
><slot />
</a>
{:else}
<button
on:click
{type}
{disabled}
class:w-full={fullWidth}
class="button {variant} {size} {classNames} {align}"
>
<slot />
</button>
{/if}

View File

@@ -0,0 +1,90 @@
<script lang="ts">
import Edit from '$lib/icons/Edit.svelte';
import Trash from '$lib/icons/Trash.svelte';
import { tick } from 'svelte';
interface ListItem {
name: string;
token?: string;
// add other properties as needed
}
let {
list,
editedName = $bindable(),
currentName,
onSave = () => {},
onDelete = () => {}
} = $props();
let localName = $state(currentName);
let wasCancelled = $state(false);
let error: string = $derived(validateName(localName));
let isEditing = $state(false);
let inputRef: HTMLInputElement;
function validateName(name: string) {
const trimmed = name.trim();
if (!trimmed) {
return 'Name darf nicht leer sein.';
}
const duplicate = list.some(
(item: ListItem) => item.name === trimmed && item.name !== currentName
);
if (duplicate) return 'Name existiert bereits.';
return '';
}
function commitIfValid() {
if (!error && !wasCancelled && localName != currentName) {
const trimmedName: string = localName.trim();
inputRef?.blur();
isEditing = false;
onSave(trimmedName, currentName);
} else {
localName = currentName;
resetEdit();
}
}
function resetEdit() {
wasCancelled = false;
inputRef?.blur();
isEditing = false;
}
function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Enter') {
event.preventDefault();
commitIfValid();
} else if (event.key === 'Escape') {
event.preventDefault();
localName = currentName;
resetEdit();
}
}
async function startEdit() {
isEditing = true;
await tick();
inputRef?.focus();
}
</script>
<div>
<input
bind:this={inputRef}
bind:value={localName}
onblur={commitIfValid}
onkeydown={handleKeydown}
/>
<button onclick={startEdit}><Edit /></button>
<button onclick={() => onDelete(currentName)}><Trash /></button>
{#if error}
<p style="color: red;">{error}</p>
{/if}
</div>

Binary file not shown.

View File

@@ -31,10 +31,16 @@ export const getCrimesListByToken = async (vorgangToken: string) => {
* @param vorgangToken
* @returns vorgangObj with keys `token`, `name`, `pin` || undefined
*/
export const getVorgangByToken = (vorgangToken: string): {token: string, name:string, pin: string} | undefined => {
const getVorgangSQLStmt = `SELECT token, name, pin FROM cases WHERE token = ?`;
export const getVorgangByToken = (
vorgangToken: string
): { token: string; name: string; pin: string } | undefined => {
const getVorgangSQLStmt = `SELECT token, name, pin
FROM cases
WHERE token = ?`;
const statement = db.prepare(getVorgangSQLStmt);
const result = statement.get(vorgangToken) as {token: string, name:string, pin: string} | undefined;
const result = statement.get(vorgangToken) as
| { token: string; name: string; pin: string }
| undefined;
return result;
};
@@ -44,10 +50,16 @@ export const getVorgangByToken = (vorgangToken: string): {token: string, name:st
* @param vorgangName
* @returns vorgangObj with keys `token`, `name`, `pin` || undefined
*/
export const getVorgangByName = (vorgangName: string): {token: string, name: string, pin: string} | undefined => {
const getVorgangByNameSQLStmt = `SELECT token, name, pin FROM cases WHERE name = ?`;
export const getVorgangByName = (
vorgangName: string
): { token: string; name: string; pin: string } | undefined => {
const getVorgangByNameSQLStmt = `SELECT token, name, pin
FROM cases
WHERE name = ?`;
const statement = db.prepare(getVorgangByNameSQLStmt);
const result = statement.get(vorgangName) as {token: string, name: string, pin: string} | undefined;
const result = statement.get(vorgangName) as
| { token: string; name: string; pin: string }
| undefined;
return result;
};
@@ -88,13 +100,22 @@ export const getListOfVorgänge = async () => {
* Fetches list of vorgänge from database
* @returns list with of available vorgaenge
*/
export const getVorgaenge = (): {vorgangToken: string, vorgangName: string, vorgangPIN: string}[] => {
const getVorgaengeSQLStmt = `SELECT token, name, pin from cases`;
export const getVorgaenge = (): {
vorgangToken: string;
vorgangName: string;
vorgangPIN: string;
}[] => {
const getVorgaengeSQLStmt = `SELECT token, name, pin
from cases`;
const statement = db.prepare(getVorgaengeSQLStmt);
const result = statement.all() as { token: string; name: string; pin: string }[];
const vorgaenge_list: {vorgangToken: string, vorgangName: string, vorgangPIN: string}[] = [];
const vorgaenge_list: { vorgangToken: string; vorgangName: string; vorgangPIN: string }[] = [];
for (const resultItem of result) {
const vorg = { vorgangToken: resultItem.token, vorgangName: resultItem.name, vorgangPIN: resultItem.pin };
const vorg = {
vorgangToken: resultItem.token,
vorgangName: resultItem.name,
vorgangPIN: resultItem.pin
};
vorgaenge_list.push(vorg);
}

View File

@@ -14,9 +14,6 @@
const target = ev.currentTarget as HTMLElement | null;
if (!target) return;
let filename = target.id.split('del__')[1];
// delete request
// --------------
let url = `/api/list/${filename}`;
@@ -46,13 +43,16 @@
<ul role="list" class="divide-y divide-gray-100">
{#each vorgangList as vorgangItem}
<li>
<a href="/list/{vorgangItem.vorgangToken}?pin={vorgangItem.vorgangPIN}" class="flex justify-between gap-x-6 py-5">
<a
href="/list/{vorgangItem.vorgangToken}?pin={vorgangItem.vorgangPIN}"
class="flex justify-between gap-x-6 py-5"
>
<div class="flex gap-x-4">
<!-- Ordner -->
<Folder />
<div class="min-w-0 flex-auto">
<span class="text-sm font-semibold leading-6 text-gray-900">{vorgangItem.vorgangName}</span>
<!-- Delete button -->
<span class="text-sm font-semibold leading-6 text-gray-900"
>{vorgangItem.vorgangName}</span
>
<button
style="padding: 2px"
id="del__{vorgangItem.vorgangToken}"

View File

@@ -1,16 +0,0 @@
import { getVorgangByToken, getCrimesListByToken } from '$lib/server/vorgangService';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, url }) => {
const vorgangToken = params.vorgang;
const vorgangPIN = url.searchParams.get('pin');
const crimesList = await getCrimesListByToken(vorgangToken);
const vorgang = getVorgangByToken(vorgangToken);
return {
crimesList,
vorgangPIN,
vorgang
};
};

View File

@@ -1,7 +1,5 @@
<script lang="ts">
Review

Wie du beschrieben hast, unnötige Kommentare und console.logs raus

Wie du beschrieben hast, unnötige Kommentare und console.logs raus
Review

Sollte soweit passen, ansonsten bitte selbstständig rauslöschen

Sollte soweit passen, ansonsten bitte selbstständig rauslöschen
import shortenFileSize from '$lib/helper/shortenFileSize';
import { page } from '$app/stores';
import timeElapsed from '$lib/helper/timeElapsed';
import Alert from '$lib/components/Alert.svelte';
@@ -11,280 +9,210 @@
import ModalContent from '$lib/components/Modal/ModalContent.svelte';
import ModalFooter from '$lib/components/Modal/ModalFooter.svelte';
import Cube from '$lib/icons/Cube.svelte';
import Edit from '$lib/icons/Edit.svelte';
import Trash from '$lib/icons/Trash.svelte';
import { invalidate, invalidateAll } from '$app/navigation';
import NameItemEditor from '$lib/components/NameItemEditor.svelte';
/** export let data; */
/** @type {import('./$types').PageData} */
export let data;
//Seite für die Tatort-Liste
let { data } = $props();
console.log('tatorte: debug ', data);
interface ListItem {
//sollte Typ Vorgang sein, aber der einfachheit ist es noch ListItem, damit die Komponente NameItemEditor für Vorgang und Tatort eingesetzt werden kann
name: string;
size: number;
lastModified: string | number | Date;
show_button?: boolean;
prefix?: string;
// add other properties as needed
}
const vorgang = data.vorgang;
const crimesList: ListItem[] = data.crimesList;
const vorgangPIN: string = data.vorgangPIN;
let vorgangName: string = data.vorgang.vorgangName;
let crimesList: ListItem[] = $state(data.crimesList);
const vorgangPIN: string = data.vorgang.vorgangPIN;
let vorgangToken: string = data.vorgang.vorgangToken;
let open = false;
$: open;
let inProgress = false;
$: inProgress;
let err = false;
$: err;
//Variablen für Modal
let open = $state(false);
let inProgress = $state(false);
let isError = $state(false);
let rename_input;
$: rename_input;
//Variable um nur admin UI anzuzeigen
let admin = data?.user?.admin;
function uploadSuccessful() {
open = false;
}
async function handleSave(newName: string, oldName: string) {
open = true;
inProgress = true;
try {
const res = await fetch(`/api/list/${vorgangToken}/${oldName}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ vorgangToken, oldName, newName })
})
.then(() => {
inProgress = false;
})
.catch((err) => {
inProgress = false;
isError = true;
console.log('ERROR', err);
});
function defocus_element(i: number) {
let item = crimesList[i];
let text_field_id = `label__${item.name}`;
let text_field = document.getElementById(text_field_id);
if (text_field) {
text_field.setAttribute('contenteditable', 'false');
text_field.textContent = item.name;
}
// reshow button
crimesList[i].show_button = true;
return;
}
async function handleEditFieldInput(ev: KeyboardEvent, listItemIndex: number) {
let item = crimesList[listItemIndex];
if (ev.key == 'Escape') {
let text_field_id = `label__${item.name}`;
let text_field = document.getElementById(text_field_id);
if (text_field) {
text_field.setAttribute('contenteditable', 'false');
text_field.textContent = item.name;
}
// reshow button
item.show_button = true;
return;
}
if (ev.key == 'Enter') {
let name_field = ev.currentTarget as HTMLElement | null;
let new_name = name_field
? name_field.textContent || (name_field as any).innerText || ''
: '';
if (new_name == '') {
alert('Bitte einen gültigen Namen eingeben.');
ev.preventDefault();
return;
}
// actual upload
// -------------
// to prevent from item being selected
ev.preventDefault();
// construct PUT URL
const url = $page.url.pathname.split('?')[0];
let data_obj: { new_name: string; old_name: string } = { new_name: '', old_name: '' };
data_obj['new_name'] = new_name;
data_obj['old_name'] =
ev.currentTarget && (ev.currentTarget as HTMLElement).id
? (ev.currentTarget as HTMLElement).id.split('__')[1]
: '';
open = true;
inProgress = true;
const response = await fetch(url, { method: 'PUT', body: JSON.stringify(data_obj) });
inProgress = false;
if (!response.ok) {
err = true;
if (response.status == 400) {
let json_res = await response.json();
return;
}
throw new Error(`Fehlgeschlagen: ${response.status}`);
if (!res.ok) {
const msg = await res.text();
console.error('❌ Fehler beim Umbenennen:', msg);
isError = true;
inProgress = false;
} else {
uploadSuccessful();
setTimeout(() => {
window.location.reload();
}, 500);
await invalidateAll();
crimesList = data.crimesList;
open = false;
inProgress = false;
}
} catch (err) {
console.error('⚠️ Netzwerkfehler:', err);
inProgress = false;
}
}
// --- upload finished ---
async function handleDelete(tatort: string) {
open = true;
inProgress = true;
let url = new URL(data.url);
url.pathname += `/${tatort}`;
console.log('Delete tatort: ', `/api${url.pathname}`, url.pathname);
return;
try {
const res = await fetch(`/api${url.pathname}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ vorgangToken, tatort })
})
.then(() => {
inProgress = false;
})
.catch((err) => {
isError = true;
inProgress = false;
console.log('ERROR', err);
});
if (!res.ok) {
const msg = await res.text();
console.error('❌ Fehler beim Löschen:', msg);
} else {
console.log('🗑️ Erfolgreich gelöscht:', url.pathname);
await invalidateAll();
crimesList = data.crimesList;
}
} catch (err) {
isError = true;
inProgress = false;
console.error('⚠️ Netzwerkfehler beim Löschen:', err);
}
}
function constructMailToLink() {
const subject = "Link zum Tatvorgang";
const link = $page.url.toString().split('?')[0];
const subject = 'Link zum Tatvorgang';
const link = data.url.origin + data.url.pathname;
const body = `Hallo,
hier ist der Link zum Tatvorgang:
${link}
hier ist der Link zum Tatvorgang:
${link}
Der Zugangs-PIN wird zur Sicherheit über einen zweiten Kommunikationskanal übermittelt.
Der Zugangs-PIN wird zur Sicherheit über einen zweiten Kommunikationskanal übermittelt.
Mit freundlichen Grüßen,
`;
Mit freundlichen Grüßen,
`;
const mailtoLink = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
return mailtoLink;
}
function closeModal() {
open = false;
isError = false;
}
</script>
<div class="-z-10 bg-white">
<div class="flex flex-col items-center justify-center w-full">
<h1 class="text-xl">Vorgang {vorgang.name}</h1>
{#if data?.user?.admin}
Zugangs-PIN: {vorgang.pin}
<a href="{constructMailToLink()}"><Button>Share Link</Button></a>
{/if}
</div>
<div class="mx-auto flex justify-center max-w-7xl h-full">
<ul class="divide-y divide-gray-100">
{#each crimesList as item, crimeListItemIndex}
<li>
<a
href="/view/{$page.params.vorgang}/{item.name}?pin={vorgangPIN}"
class=" flex justify-between gap-x-6 py-5"
aria-label="zum 3D-modell"
>
{#if data.vorgang && data.crimesList}
<div class="-z-10 bg-white">
<div class="flex flex-col items-center justify-center w-full">
<h1 class="text-xl">Vorgang {vorgangName}</h1>
{#if admin}
Zugangs-PIN: {vorgangPIN}
<a class="pt-2 pb-6" href={constructMailToLink()}><Button>Share Link</Button></a>
{/if}
</div>
<div class="mx-auto flex justify-center max-w-7xl h-full">
<ul class="divide-y divide-gray-100">
{#each data.crimesList as item, crimeListItemIndex}
<li>
<div class=" flex gap-x-4">
<Cube />
<a
href="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
class=" flex justify-between gap-x-6 py-5"
aria-label="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
title={item.name}
>
<Cube />
</a>
<div class="min-w-0 flex-auto">
{#if data?.user?.admin}
<span
id="label__{item.name}"
class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
contenteditable={!item.show_button}
role="textbox"
tabindex="0"
aria-label="Dateiname bearbeiten"
on:focusout={() => {
defocus_element(crimeListItemIndex);
}}
on:keydown|stopPropagation={// event needed to identify ID
// TO-DO: check if event is needed or if index is sufficient
async (ev) => {
handleEditFieldInput(ev, crimeListItemIndex);
}}>{item.name}</span
>
{#if item.show_button}
<button
style="padding: 2px"
id="edit__{item.name}"
aria-label="Datei umbenennen"
on:click|preventDefault={(ev) => {
let text_field_id = `label__${item.name}`;
let text_field = document.getElementById(text_field_id);
if (text_field) {
text_field.setAttribute('contenteditable', 'true');
text_field.focus();
text_field.textContent = '';
}
// hide button
item.show_button = false;
}}
>
<Edit />
</button>
{/if}
<button
style="padding: 2px"
id="del__{item.name}"
on:click|preventDefault={async (ev) => {
let delete_item = window.confirm('Bist du sicher?');
if (delete_item) {
// bucket: tatort, name: <vorgang>/item-name
let vorgang = $page.params.vorgang;
let filename = '';
if (ev && ev.currentTarget && (ev.currentTarget as HTMLElement).id) {
filename = (ev.currentTarget as HTMLElement).id.split('del__')[1];
}
// delete request
// --------------
let url = new URL($page.url);
url.pathname += `/${filename}`;
try {
const response = await fetch(`/api${url.pathname}`, { method: 'DELETE' });
if (response.status == 204) {
setTimeout(() => {
window.location.reload();
}, 500);
}
} catch (error) {
if (error instanceof Error) {
console.log(error.message);
} else {
console.log(error);
}
}
}
}}
aria-label="Datei löschen"
>
<Trash />
</button>
{#if admin}
<NameItemEditor
list={data.crimesList}
editedName={data.crimeNames[crimeListItemIndex]}
currentName={item.name}
onSave={handleSave}
onDelete={handleDelete}
></NameItemEditor>
{:else}
<span class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
>{item.name}</span
>
{/if}
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
{shortenFileSize(item.size)}
</p>
{#if item.size}
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
{shortenFileSize(item.size)}
</p>
{/if}
</div>
</div>
<div class="hidden sm:flex sm:flex-col sm:items-end">
<p class="text-sm leading-6 text-gray-900">3D Tatort</p>
<p class="mt-1 text-xs leading-5 text-gray-500">
Zuletzt geändert <time datetime="2023-01-23T13:23Z"
>{timeElapsed(new Date(item.lastModified))}</time
>
</p>
{#if item.lastModified}
<p class="mt-1 text-xs leading-5 text-gray-500">
Zuletzt geändert <time datetime="2023-01-23T13:23Z"
>{timeElapsed(new Date(item.lastModified))}</time
>
</p>
{/if}
</div>
</a>
</li>
{/each}
</ul>
</div>
</li>
{/each}
</ul>
</div>
<Modal {open}
><ModalTitle>Umbenennen</ModalTitle><ModalContent>
{#if inProgress}
<p class="py-2 mb-1">Vorgang läuft...</p>
{/if}
{#if err}
<Alert class="w-full" type="error">Fehler beim Umbenennen</Alert>
{/if}
</ModalContent>
<ModalFooter><Button disabled={inProgress} on:click={uploadSuccessful}>Ok</Button></ModalFooter>
</Modal>
</div>
<Modal {open}
><ModalTitle>Umbenennen</ModalTitle><ModalContent>
{#if inProgress}
<p class="py-2 mb-1">Vorgang läuft...</p>
{:else if isError}
<Alert class="w-full" type="error">Fehler beim Umbenennen</Alert>
{:else}
<Alert class="w-full">Umbenennen erfolgreich</Alert>
{/if}
</ModalContent>
<ModalFooter><Button disabled={inProgress} on:click={closeModal}>Ok</Button></ModalFooter>
</Modal>
</div>
{/if}
<style>
ul {

View File

@@ -0,0 +1,27 @@
import { redirect } from '@sveltejs/kit';
export async function load({fetch, params, url}){
const vorgangResponse = await fetch(`/api/list`);
const vorgangList = await vorgangResponse.json()
const vorgangToken = params.vorgang;
const crimesListResponse = await fetch(`/api/list/${vorgangToken}`)
const crimesList = await crimesListResponse.json();
const vorgang = vorgangList.find(v => v.vorgangToken === vorgangToken); //vorgang sollte ein eigener Typ werden, und dann kann man es hier vernünftig typisieren
if(!vorgang || !crimesList){
throw new Error(`Fehlgeschlagen, es wurden keine Daten zum token gefunden`);
}
//Variabeln für NameItemEditor
const crimeNames: string[] = crimesList.map((l) => l.name);
if (crimesList.length === 0) {
throw redirect(302, '/upload'); // weiterleiten auf die hinzufügen seite
Review

Ok, aber warum. Erwarte ich hier nicht dann die Liste??

Ok, aber warum. Erwarte ich hier nicht dann die Liste??
Review

Ich habe die Umleitung gesetzt, wenn die Liste leer ist, also wenn keine Dateien zum Anzeigen vorhanden sind. So kann man quasi direkt eine Datei neu upload. Wenn nicht gewünscht bitte eigenständig bearbeiten

Ich habe die Umleitung gesetzt, wenn die Liste leer ist, also wenn keine Dateien zum Anzeigen vorhanden sind. So kann man quasi direkt eine Datei neu upload. Wenn nicht gewünscht bitte eigenständig bearbeiten
}
return {
vorgang,
vorgangList,
crimesList,
url,
crimeNames
}
}

View File

@@ -1,34 +0,0 @@
import { client } from '$lib/minio';
import { json } from '@sveltejs/kit';
// rename operation for crimes
export async function PUT({ request }: {request: Request}) {
const data = await request.json();
// Vorgang
const vorgangToken = request.url.split('/').at(-1);
// prepare copy, incl. check if new name exists already
const crimeOldName = data["old_name"];
const crimeS3FullBucketPathOld = `/tatort/${vorgangToken}/${crimeOldName}`;
const crimeNewName = `${vorgangToken}/${data["new_name"]}`;
try {
await client.statObject('tatort', crimeNewName);
return json({ msg: 'Die Datei existiert bereits.' }, { status: 400 });
} catch (error) {
// continue operation
console.log(error, 'continue operation');
}
// actual copy operation
await client.copyObject('tatort', crimeNewName, crimeS3FullBucketPathOld)
// delete
await client.removeObject('tatort', `${vorgangToken}/${crimeOldName}`)
// return success or failure
return json({ success: 'success' }, { status: 200 });
};

View File

@@ -0,0 +1,14 @@
import { getVorgaenge } from '$lib/server/vorgangService';
import { json } from '@sveltejs/kit';
export async function GET({ locals }) {
if (!locals.user) {
return json({ error: 'Unauthorized' }, { status: 401 });
}
const vorgaenge = getVorgaenge();
return new Response(JSON.stringify(vorgaenge), {
status: 200
});
}

View File

@@ -1,5 +1,10 @@
import { client } from '$lib/minio';
import { deleteVorgangByToken, vorgangNameExists } from '$lib/server/vorgangService';
import {
deleteVorgangByToken,
getCrimesListByToken,
vorgangNameExists
} from '$lib/server/vorgangService';
import { json } from '@sveltejs/kit';
export async function DELETE({ params }) {
const vorgangToken = params.vorgang;
@@ -38,3 +43,21 @@ export async function HEAD({ params }) {
return new Response(null, { status: 500 });
}
}
export async function GET({ params, locals }) {
if (!locals.user) {
return json({ error: 'Unauthorized' }, { status: 401 });
}
try {
const vorgangToken = params.vorgang;
const crimesList = await getCrimesListByToken(vorgangToken);
return new Response(JSON.stringify(crimesList), {
status: 200
});
} catch (err) {
console.error('Fehler im GET-Handler:', err);
return new Response(null, { status: 500 });
}
}

View File

@@ -1,4 +1,6 @@
import { BUCKET, client } from '$lib/minio';
import { json } from '@sveltejs/kit';
import { getVorgangByName } from '$lib/server/vorgangService';
export async function GET() {
const stream = client.listObjectsV2(BUCKET, '', true);
@@ -23,7 +25,6 @@ export async function GET() {
});
}
export async function DELETE({ request }: { request: Request }) {
const url_fragments = request.url.split('/');
const item = url_fragments.at(-1);
@@ -33,3 +34,32 @@ export async function DELETE({ request }: { request: Request }) {
return new Response(null, { status: 204 });
}
// rename operation for crimes
export async function PUT({ params, request }) {
const data = await request.json();
const vorgangToken = params.vorgang;
// prepare copy, incl. check if new name exists already
const crimeOldName = data['oldName'];
const crimeS3FullBucketPathOld = `/tatort/${vorgangToken}/${crimeOldName}`;
const crimeNewName = `${vorgangToken}/${data['newName']}`;
if (!crimeOldName || !crimeNewName) {
return json({ msg: 'Der Name darf nicht leer sein.' }, { status: 400 });
}
try {
await client.statObject('tatort', crimeNewName);
return json({ msg: 'Die Datei existiert bereits.' }, { status: 400 });
} catch (error) {
console.log(error, 'continue operation');
}
await client.copyObject('tatort', crimeNewName, crimeS3FullBucketPathOld);
await client.removeObject('tatort', `${vorgangToken}/${crimeOldName}`);
return json({ success: 'success' }, { status: 200 });
}

View File

@@ -2,10 +2,12 @@ import { db } from '$lib/server/dbService';
/** @type {import('./$types').RequestHandler} */
export async function GET({ params }) {
const vorgangName = params.vorgang;
const vorgangToken = params.vorgang;
const getPINSQLStatement = `SELECT pin FROM cases WHERE name = ?;`;
const row = db.prepare(getPINSQLStatement).get(vorgangName);
const getPINSQLStatement = `SELECT pin
FROM cases
WHERE token = ?;`;
const row = db.prepare(getPINSQLStatement).get(vorgangToken);
const vorgangPIN = row?.pin;
if (vorgangPIN) {

View File

@@ -0,0 +1,10 @@
//Rollenabfrage ob Benutzer admin ist
import { json } from "@sveltejs/kit";
export async function GET({locals}) {
const isAdmin = locals.user?.admin === true;
const data = {admin: isAdmin}
return json(data)
}