f047_Edit-der-Namen #15

Closed
jared wants to merge 11 commits from f047_Edit-der-Namen into development
12 changed files with 270 additions and 121 deletions
Showing only changes of commit 0b4d189439 - Show all commits

View File

@@ -1,4 +1,15 @@
<!DOCTYPE html>
<html lang="de">
<head>
</head>
<body>
<h1>Du wurdest automatisch ausgeloggt</h1> <h1>Du wurdest automatisch ausgeloggt</h1>
<p>Lösche deine Cookies aus dem Browser und logge dich neu ein</p> <p>Lösche deine Cookies aus dem Browser und logge dich neu ein</p>
<p>Code %sveltekit.status%</p> <p>Code %sveltekit.status%</p>
<p>%sveltekit.error.message%</p> <p>%sveltekit.error.message%</p>
</body>
</html>

View File

@@ -1,10 +0,0 @@
import { getListOfVorgänge } from '$lib/server/vorgangService';
import type { PageServerLoad } from '../../(token-based)/view/$types';
export const load: PageServerLoad = async () => {
const caseList = await getListOfVorgänge();
return {
caseList
};
};

View File

@@ -11,11 +11,12 @@
let { data } = $props(); let { data } = $props();
const caseList: ListItem[] = data.caseList; const caseList: ListItem[] = $state(data.caseList);
//Variabeln für EditableItem //Variabeln für EditableItem
let names: string[] = $state(caseList.map((l) => l.name)); let names: string[] = $state(caseList.map((l) => l.name));
let editedName: string = $state(''); let editedName: string = $state('');
let currentName: string = $state('');
async function delete_item(ev: Event) { async function delete_item(ev: Event) {
let delete_item = window.confirm('Bist du sicher?'); let delete_item = window.confirm('Bist du sicher?');
@@ -47,7 +48,7 @@
} }
} }
async function handleSave(newName: string, oldName: string) { async function handleUpdateCase(newName: string, oldName: string) {
console.log('Eltern, speichern erfolgreich', newName, oldName); console.log('Eltern, speichern erfolgreich', newName, oldName);
try { try {
const res = await fetch(`/api/list/${oldName}`, { const res = await fetch(`/api/list/${oldName}`, {
@@ -60,9 +61,11 @@
if (!res.ok) { if (!res.ok) {
const msg = await res.text(); const msg = await res.text();
console.error('❌ Fehler beim Speichern:', msg); console.error('❌ Fehler beim Speichern Update:', msg);
} else { } else {
console.log('✅ Erfolgreich gespeichert:', newName); console.log('✅ Erfolgreich gespeichert:', newName);
await invalidate('');
currentName = newName;
} }
} catch (err) { } catch (err) {
console.error('⚠️ Netzwerkfehler:', err); console.error('⚠️ Netzwerkfehler:', err);
@@ -84,13 +87,7 @@
const msg = await res.text(); const msg = await res.text();
console.error('❌ Fehler beim Löschen:', msg); console.error('❌ Fehler beim Löschen:', msg);
} else { } else {
setTimeout(() => {
window.location.reload();
}, 500);
//await invalidate('/api/list');
console.log('🗑️ Erfolgreich gelöscht:', vorgang); console.log('🗑️ Erfolgreich gelöscht:', vorgang);
await invalidate('/api/list'); // funktioniert nicht vernünftig
} }
} catch (err) { } catch (err) {
console.error('⚠️ Netzwerkfehler beim Löschen:', err); console.error('⚠️ Netzwerkfehler beim Löschen:', err);
@@ -109,24 +106,26 @@
<div class="flex gap-x-4"> <div class="flex gap-x-4">
<!-- Ordner --> <!-- Ordner -->
<a <a
href="/list/{item.name}?token={item.token}" href="/list/{currentName}?token={item.token}"
class="bg-red-500 flex justify-between gap-x-6 py-5" class=" flex justify-between gap-x-6 py-5"
> >
<Folder /> <Folder />
</a> </a>
{#if data.user.admin}
<div class="min-w-0 flex-auto"> <div class="min-w-0 flex-auto">
<EditableItem <EditableItem
list={caseList} list={caseList}
bind:editedName={names[i]} bind:editedName={names[i]}
currentName={item.name} currentName={item.name}
onSave={handleSave} onSave={handleUpdateCase}
onDelete={handleDelete} onDelete={handleDelete}
></EditableItem> ></EditableItem>
</div> </div>
{:else}
<div class="hidden sm:flex sm:flex-col sm:items-end"> <div class="hidden sm:flex sm:flex-col sm:items-end">
<p class="text-sm leading-6 text-gray-900">Vorgang</p> <p class="text-sm leading-6 text-gray-900">Vorgang</p>
</div> </div>
{/if}
</div> </div>
</li> </li>
{/each} {/each}

View File

@@ -0,0 +1,24 @@
export async function load({ fetch, url }) {
//const caseToken = url.searchParams.get('token');
const adminRes = await fetch(`/api/user`)
const user = await adminRes.json()
console.log("load Vorgang; ", user);
const res = await fetch(`/api/list`, {
/* headers: {
Authorization: `Bearer ${caseToken}`
} */
});
const data = await res.json();
const caseList = data.caseList
console.log("load Vorgang; ", caseList, user);
return {
caseList,
user
};
};

View File

@@ -1,15 +0,0 @@
import { getVorgangByCaseId } from '$lib/server/vorgangService';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params, url }) => {
const caseId = params.vorgang;
const caseToken = url.searchParams.get('token');
const crimesList = await getVorgangByCaseId(caseId);
return {
caseId,
crimesList,
caseToken
};
};

View File

@@ -1,5 +1,4 @@
<script lang="ts"> <script lang="ts">
import { page } from '$app/stores';
import Alert from '$lib/components/Alert.svelte'; import Alert from '$lib/components/Alert.svelte';
import Button from '$lib/components/Button.svelte'; import Button from '$lib/components/Button.svelte';
import Modal from '$lib/components/Modal/Modal.svelte'; import Modal from '$lib/components/Modal/Modal.svelte';
@@ -10,9 +9,14 @@
import Cube from '$lib/icons/Cube.svelte'; import Cube from '$lib/icons/Cube.svelte';
import shortenFileSize from '$lib/helper/shortenFileSize.js'; import shortenFileSize from '$lib/helper/shortenFileSize.js';
import timeElapsed from '$lib/helper/timeElapsed.js'; import timeElapsed from '$lib/helper/timeElapsed.js';
import { invalidate } from '$app/navigation';
import { page } from '$app/stores';
//Seite für die Tatort-Liste
let { data } = $props(); let { data } = $props();
Outdated
Review

s. o.

s. o.
Outdated
Review

Ja, das können wir mal im Daily ansprechen, ich habe ein Ticket daraus gemacht.

Ja, das können wir mal im Daily ansprechen, ich habe ein Ticket daraus gemacht.
console.log('tatorte: debug ', data);
interface ListItem { interface ListItem {
name: string; name: string;
size?: number; size?: number;
@@ -21,15 +25,15 @@
// add other properties as needed // add other properties as needed
} }
const crimesList: ListItem[] = data.crimesList; const crimesList: ListItem[] = $state(data.crimesList);
const token: string = data.caseToken; const token: string | null = data.caseToken;
let vorgang = data.caseId; let vorgang = data.caseId;
/* export let vorgang = $page.params.vorgang; */ /* export let vorgang = $page.params.vorgang; */
//Variabeln für EditableItem //Variabeln für EditableItem
let names: string[] = $state(crimesList.map((l) => l.name)); let names: string[] = $state(crimesList.map((l) => l.name));
let editedName: string = $state(''); let editedName: string = $state('');
let currentName: string = $state('');
let open = $state(false); let open = $state(false);
let inProgress = $state(false); let inProgress = $state(false);
let err = $state(false); let err = $state(false);
@@ -128,14 +132,22 @@
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ oldName, newName }) body: JSON.stringify({ vorgang, oldName, newName })
}); });
const clone = res.clone();
const data = await res.json();
let message = data.message;
let error = !data.success;
console.log('Tatort Update: ', message);
if (!res.ok) { if (!res.ok) {
const msg = await res.text(); const msg = await clone.text();
console.error('❌ Fehler beim Speichern:', msg); console.error('❌ Fehler beim Speichern:', msg);
} else { } else {
console.log('✅ Erfolgreich gespeichert:', newName); console.log('✅ Erfolgreich gespeichert:', newName);
await invalidate('');
currentName = newName;
} }
} catch (err) { } catch (err) {
console.error('⚠️ Netzwerkfehler:', err); console.error('⚠️ Netzwerkfehler:', err);
@@ -143,15 +155,6 @@
} }
async function handleDelete(tatort: string) { async function handleDelete(tatort: string) {
// delete request
// --------------
/* let url = new URL($page.url);
url.pathname += `/${filename}`;
try {
const response = await fetch(`/api${url.pathname}`, { method: 'DELETE' }); */
let url = new URL($page.url); let url = new URL($page.url);
url.pathname += `/${tatort}`; url.pathname += `/${tatort}`;
console.log('Delete tatort: ', `/api${url.pathname}`, url.pathname); console.log('Delete tatort: ', `/api${url.pathname}`, url.pathname);
@@ -164,7 +167,6 @@
}, },
body: JSON.stringify({ vorgang, tatort }) body: JSON.stringify({ vorgang, tatort })
}); });
console.log('res delete', res);
if (!res.ok) { if (!res.ok) {
const msg = await res.text(); const msg = await res.text();
@@ -188,7 +190,7 @@
<li> <li>
<div class=" flex gap-x-4"> <div class=" flex gap-x-4">
<a <a
href="/view/{$page.params.vorgang}/{item.name}?token={token}" href="/view/{$page.params.vorgang}/{currentName}?token={token}"
class=" flex justify-between gap-x-6 py-5" class=" flex justify-between gap-x-6 py-5"
aria-label="zum 3D-modell" aria-label="zum 3D-modell"
> >
@@ -214,7 +216,6 @@
</p> </p>
{/if} {/if}
</div> </div>
<div>{item.name}</div>
</div> </div>
<div class="hidden sm:flex sm:flex-col sm:items-end"> <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="text-sm leading-6 text-gray-900">3D Tatort</p>

View File

@@ -0,0 +1,34 @@
// load für die Tatort-Liste
export async function load({ fetch, params, url }) {
const caseId = params.vorgang;
const caseToken = url.searchParams.get('token');
const adminRes = await fetch(`/api/user`)
const user = await adminRes.json()
const res = await fetch(`/api/list/${caseId}`, {
headers: {
Authorization: `Bearer ${caseToken}`
}
});
const data = await res.json();
const crimesList = data.crimesList
return {
caseId,
crimesList,
caseToken,
user
};
};

View File

@@ -1,4 +1,4 @@
import { client } from '$lib/minio'; /* import { client } from '$lib/minio';
import { json } from '@sveltejs/kit'; import { json } from '@sveltejs/kit';
@@ -33,3 +33,4 @@ export async function PUT({ request }: {request: Request}) {
return json({ success: 'success' }, { status: 200 }); return json({ success: 'success' }, { status: 200 });
}; };
*/

View File

@@ -0,0 +1,27 @@
import { getListOfVorgänge } from "$lib/server/vorgangService";
import { json } from "@sveltejs/kit";
//Get für die Vorgangsliste mit token, daher authorized Abfrage
export async function GET({locals, url, request}) {
/* if(!locals.user?.admin){
return new Response('Unauthorized',{status: 401})
}
const urlToken = url.searchParams.get('token');
const caseToken = request.headers.get('Authorization')?.replace('Bearer ', '');
if(!(urlToken || caseToken)) return new Response('Unauthorized', { status: 401 });
*/
let caseList;
try {
caseList = await getListOfVorgänge();
} catch (err) {
console.error('Fehler beim Laden der Liste:', err);
}
if(!caseList) return new Response(`Keine Liste vorhanden ${caseList}`, {status: 404})
const data = {caseList}
return json(data)
}

View File

@@ -1,71 +1,99 @@
import { client } from '$lib/minio'; import { BUCKET, client } from '$lib/minio';
import { getVorgangByCaseId } from '$lib/server/vorgangService';
import type { RequestHandler } from '@sveltejs/kit'; import type { RequestHandler } from '@sveltejs/kit';
import { json } from '@sveltejs/kit'; import { json } from '@sveltejs/kit';
// Seite für die Vorgangs-Liste
//Get für die Tatortliste mit token, daher authorized Abfrage
export async function GET({locals,request, params, url}) {
if(!locals.user?.admin){
return new Response('Unauthorized',{status: 401})
}
const caseId = params.vorgang;
const urlToken = url.searchParams.get('token');
const caseToken = request.headers.get('Authorization')?.replace('Bearer ', '');
if(!(urlToken || caseToken)) return new Response('Unauthorized', { status: 401 });
const crimesList = await getVorgangByCaseId(caseId);
const data = {
caseId,
crimesList,
caseToken
}
return json(data)
}
// rename operation // rename operation
export async function PUT({ request }: {request: Request}) { export const PUT: RequestHandler= async ({request, locals}) => {
const data = await request.json(); if(!locals.user?.admin){
return new Response('Forbidden', { status: 403 });
// Vorgang
const vorgang = request.url.split('/').at(-1);
// prepare copy, incl. check if new name exists already
const old_name = data["old_name"];
const src_full_path = `/tatort/${vorgang}/${old_name}`;
const new_name = `${vorgang}/${data["new_name"]}`;
try {
await client.statObject('tatort', new_name);
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', new_name, src_full_path)
// delete
await client.removeObject('tatort', `${vorgang}/${old_name}`)
// return success or failure
return json({ success: 'success' }, { status: 200 });
};
/* export const PUT: RequestHandler = async ({ request, params }) => {
const { filename } = params;
const { oldName, newName} = await request.json(); const { oldName, newName} = await request.json();
if (!newName || !newName.trim()) { if (!newName || !newName.trim()) {
return new Response('Ungültiger Name', { status: 400 }); return new Response('Ungültiger Name', { status: 400 });
} }
const index = mockList.findIndex((name) => name === oldName);
if (index === -1) {
return new Response('Name nicht gefunden', { status: 404 }); try {
const stat = await client.statObject(BUCKET, newName).catch(()=> null)
if(stat){
return json({ error: 'Datei mit dem neuen Namen existiert bereits.' }, { status: 409 });
}
// 2. Kopieren
const Object_list:string[] = await new Promise((resolve, reject) => {
const res: string[] = [];
const items_str = client.listObjects(BUCKET, oldName, true);
items_str.on('data', (obj) => {
if (obj.name) res.push(obj.name);
});
items_str.on('error', reject);
items_str.on('end', async () => {
try {
for (const oldKey of res) {
const oldPath = `${oldName}/`;
const newPath = `${newName}/`;
const newKey = oldKey.replace(oldPath, newPath);
await client.copyObject(BUCKET, newKey, `/${BUCKET}/${oldKey}`);
}
resolve(res);
} catch (err) {
reject(err);
}
});
});
//3. Löschen
await client.removeObjects(BUCKET, Object_list)
const data = { success: true, message: 'Datei erfolgreich umbenannt.' }
return json(data, { status: 200 });
} catch (err) {
console.error('Fehler beim Umbenennen', err)
return json({error: `Fehler beim Umbenennen der Datei ${oldName} zu ${newName}`}, {status: 500})
} }
if (mockList.includes(newName)) {
return new Response('Name existiert bereits', { status: 409 });
}
console.log('📥 PUT-Request empfangen:', mockList);
mockList[index] = newName;
console.log('📄 Datei:', filename);
console.log('🔁 Umbenennen:', oldName, '→', newName, mockList);
// return new Response(JSON.stringify({ success: true }), { status: 200 });
return json({ success: true, updated: newName });
}; };
*/
export const DELETE: RequestHandler = async ({ request })=> { //body: {request}, keine params // params= de?param1=value&params2 export const DELETE: RequestHandler = async ({ request })=> { //body: {request}, keine params // params= de?param1=value&params2
// const vorgang = params.vorgang; // const vorgang = params.vorgang;
@@ -73,7 +101,7 @@ export const DELETE: RequestHandler = async ({ request })=> { //body: {request},
const object_list:string[] = await new Promise((resolve, reject) => { const object_list:string[] = await new Promise((resolve, reject) => {
const res: string[] = []; const res: string[] = [];
const items_str = client.listObjects('tatort', vorgang, true); const items_str = client.listObjects(BUCKET, vorgang, true);
items_str.on('data', (obj) => { items_str.on('data', (obj) => {
if(obj.name) res.push(obj.name); if(obj.name) res.push(obj.name);

View File

@@ -1,6 +1,9 @@
import { BUCKET, client } from '$lib/minio'; import { BUCKET, client } from '$lib/minio';
import type { RequestHandler } from '@sveltejs/kit'; import type { RequestHandler } from '@sveltejs/kit';
import { json } from '@sveltejs/kit';
// Seite für die Tatorte-Liste
export async function GET() { export async function GET() {
const stream = client.listObjectsV2(BUCKET, '', true); const stream = client.listObjectsV2(BUCKET, '', true);
const result = new ReadableStream({ const result = new ReadableStream({
@@ -22,6 +25,42 @@ export async function GET() {
'content-type': 'text/event-stream' 'content-type': 'text/event-stream'
} }
}); });
}
export const PUT: RequestHandler= async ({request, locals}) => {
if(!locals.user?.admin){
return new Response('Forbidden', { status: 403 });
}
const {vorgang, oldName, newName} = await request.json();
if (!newName || !newName.trim()) {
return new Response('Ungültiger Name', { status: 400 });
}
const oldKey = `${vorgang}/${oldName}`;
const newKey = `${vorgang}/${newName}`;
console.log("PUT Tatorte-Liste: ", vorgang, oldKey, newKey);
try {
const stat = await client.statObject(BUCKET, newKey).catch(()=> null)
if(stat){
return json({ error: 'Datei mit dem neuen Namen existiert bereits.' }, { status: 409 });
}
// 2. Kopieren
await client.copyObject(BUCKET, newKey, `/${BUCKET}/${oldKey}`);
//3. Löschen
await client.removeObject(BUCKET, oldKey)
const data = { success: true, message: 'Datei erfolgreich umbenannt.' }
return json(data);
} catch (err) {
console.error('Fehler beim Umbenennen', err)
return json({error: 'Fehler beim Umbenennen der Datei'}, {status: 500})
}
} }
export const DELETE: RequestHandler = async ({ request })=> { //body: {request}, keine params // params= de?param1=value&params2 export const DELETE: RequestHandler = async ({ request })=> { //body: {request}, keine params // params= de?param1=value&params2

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)
}