From 34f8fd54907f088d29de6c92f41df70615bec633 Mon Sep 17 00:00:00 2001 From: Jared Date: Tue, 17 Jun 2025 16:19:22 +0200 Subject: [PATCH] refactor login page, change routes to token-based, add service classes --- src/lib/components/{ui => }/Alert.svelte | 0 src/lib/components/BaseInputField.svelte | 32 ++++ src/lib/components/{ui => }/Button.svelte | 0 .../{ui => }/DeleteIconButton.svelte | 4 +- src/lib/components/Footer.svelte | 37 ++++ src/lib/components/Header.svelte | 36 ++++ .../components/{ui => }/Modal/Modal.svelte | 0 .../{ui => }/Modal/ModalContent.svelte | 0 .../{ui => }/Modal/ModalFooter.svelte | 0 .../{ui => }/Modal/ModalTitle.svelte | 0 .../components/{ui => }/Notification.svelte | 0 src/lib/components/{ui => }/Panel.svelte | 0 src/lib/components/{ui => }/Select.svelte | 0 src/lib/helper/caseNumberOccupied.js | 22 --- src/lib/helper/caseNumberOccupied.ts | 2 +- src/lib/helper/{getCode.js => getCode.ts} | 0 src/lib/server/authService.ts | 29 +++ src/lib/server/s3ClientService.ts | 58 ++++++ src/lib/server/vorgangService.ts | 68 +++++++ src/routes/(angemeldet)/+layout.server.ts | 2 +- src/routes/(angemeldet)/+layout.svelte | 65 +------ src/routes/(angemeldet)/tatorte/+page.svelte | 12 +- src/routes/(angemeldet)/upload/+page.svelte | 12 +- src/routes/(angemeldet)/view/+page.server.ts | 75 -------- src/routes/(token-based)/+layout.server.ts | 10 ++ src/routes/(token-based)/+layout.svelte | 16 ++ .../list/+page.svelte | 0 .../list/[vorgang]/+page.svelte | 17 +- .../list/[vorgang]/+server.ts | 0 .../list/[vorgang]/[tatort]/+server.ts | 0 src/routes/(token-based)/view/+page.server.ts | 6 + .../view/+page.svelte | 2 +- .../view/[vorgang]/[tatort]/+page.server.ts | 0 .../view/[vorgang]/[tatort]/+page.svelte | 4 +- src/routes/anmeldung/+page.server.ts | 35 +--- src/routes/anmeldung/+page.svelte | 166 ++++++++---------- 36 files changed, 405 insertions(+), 305 deletions(-) rename src/lib/components/{ui => }/Alert.svelte (100%) create mode 100644 src/lib/components/BaseInputField.svelte rename src/lib/components/{ui => }/Button.svelte (100%) rename src/lib/components/{ui => }/DeleteIconButton.svelte (92%) create mode 100644 src/lib/components/Footer.svelte create mode 100644 src/lib/components/Header.svelte rename src/lib/components/{ui => }/Modal/Modal.svelte (100%) rename src/lib/components/{ui => }/Modal/ModalContent.svelte (100%) rename src/lib/components/{ui => }/Modal/ModalFooter.svelte (100%) rename src/lib/components/{ui => }/Modal/ModalTitle.svelte (100%) rename src/lib/components/{ui => }/Notification.svelte (100%) rename src/lib/components/{ui => }/Panel.svelte (100%) rename src/lib/components/{ui => }/Select.svelte (100%) delete mode 100644 src/lib/helper/caseNumberOccupied.js rename src/lib/helper/{getCode.js => getCode.ts} (100%) create mode 100644 src/lib/server/authService.ts create mode 100644 src/lib/server/s3ClientService.ts create mode 100644 src/lib/server/vorgangService.ts delete mode 100644 src/routes/(angemeldet)/view/+page.server.ts create mode 100644 src/routes/(token-based)/+layout.server.ts create mode 100644 src/routes/(token-based)/+layout.svelte rename src/routes/{(angemeldet) => (token-based)}/list/+page.svelte (100%) rename src/routes/{(angemeldet) => (token-based)}/list/[vorgang]/+page.svelte (94%) rename src/routes/{(angemeldet) => (token-based)}/list/[vorgang]/+server.ts (100%) rename src/routes/{(angemeldet) => (token-based)}/list/[vorgang]/[tatort]/+server.ts (100%) create mode 100644 src/routes/(token-based)/view/+page.server.ts rename src/routes/{(angemeldet) => (token-based)}/view/+page.svelte (98%) rename src/routes/{(angemeldet) => (token-based)}/view/[vorgang]/[tatort]/+page.server.ts (100%) rename src/routes/{(angemeldet) => (token-based)}/view/[vorgang]/[tatort]/+page.svelte (97%) diff --git a/src/lib/components/ui/Alert.svelte b/src/lib/components/Alert.svelte similarity index 100% rename from src/lib/components/ui/Alert.svelte rename to src/lib/components/Alert.svelte diff --git a/src/lib/components/BaseInputField.svelte b/src/lib/components/BaseInputField.svelte new file mode 100644 index 0000000..d4d7c90 --- /dev/null +++ b/src/lib/components/BaseInputField.svelte @@ -0,0 +1,32 @@ + + +
+ +
+
+ +
+
+ {#if error} +

{error}

+ {/if} +
diff --git a/src/lib/components/ui/Button.svelte b/src/lib/components/Button.svelte similarity index 100% rename from src/lib/components/ui/Button.svelte rename to src/lib/components/Button.svelte diff --git a/src/lib/components/ui/DeleteIconButton.svelte b/src/lib/components/DeleteIconButton.svelte similarity index 92% rename from src/lib/components/ui/DeleteIconButton.svelte rename to src/lib/components/DeleteIconButton.svelte index f0d329f..9efab9e 100644 --- a/src/lib/components/ui/DeleteIconButton.svelte +++ b/src/lib/components/DeleteIconButton.svelte @@ -14,8 +14,8 @@ + +
+ +
\ No newline at end of file diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte new file mode 100644 index 0000000..4e13909 --- /dev/null +++ b/src/lib/components/Header.svelte @@ -0,0 +1,36 @@ + + +
+
+ +
+
diff --git a/src/lib/components/ui/Modal/Modal.svelte b/src/lib/components/Modal/Modal.svelte similarity index 100% rename from src/lib/components/ui/Modal/Modal.svelte rename to src/lib/components/Modal/Modal.svelte diff --git a/src/lib/components/ui/Modal/ModalContent.svelte b/src/lib/components/Modal/ModalContent.svelte similarity index 100% rename from src/lib/components/ui/Modal/ModalContent.svelte rename to src/lib/components/Modal/ModalContent.svelte diff --git a/src/lib/components/ui/Modal/ModalFooter.svelte b/src/lib/components/Modal/ModalFooter.svelte similarity index 100% rename from src/lib/components/ui/Modal/ModalFooter.svelte rename to src/lib/components/Modal/ModalFooter.svelte diff --git a/src/lib/components/ui/Modal/ModalTitle.svelte b/src/lib/components/Modal/ModalTitle.svelte similarity index 100% rename from src/lib/components/ui/Modal/ModalTitle.svelte rename to src/lib/components/Modal/ModalTitle.svelte diff --git a/src/lib/components/ui/Notification.svelte b/src/lib/components/Notification.svelte similarity index 100% rename from src/lib/components/ui/Notification.svelte rename to src/lib/components/Notification.svelte diff --git a/src/lib/components/ui/Panel.svelte b/src/lib/components/Panel.svelte similarity index 100% rename from src/lib/components/ui/Panel.svelte rename to src/lib/components/Panel.svelte diff --git a/src/lib/components/ui/Select.svelte b/src/lib/components/Select.svelte similarity index 100% rename from src/lib/components/ui/Select.svelte rename to src/lib/components/Select.svelte diff --git a/src/lib/helper/caseNumberOccupied.js b/src/lib/helper/caseNumberOccupied.js deleted file mode 100644 index e727abf..0000000 --- a/src/lib/helper/caseNumberOccupied.js +++ /dev/null @@ -1,22 +0,0 @@ -import { client } from '$lib/minio'; - -/** - * Check if caseNumber is used - * @param {string} caseNumber - * @returns {Promise} - */ -export default async function caseNumberOccupied(caseNumber) { - const prefix = `${caseNumber}`; - const promise = new Promise((resolve) => { - let stream = client.listObjectsV2('tatort', prefix, false, ''); - stream.on('data', () => { - stream.destroy(); - resolve(true); - }); - stream.on('end', () => { - resolve(false); - }); - }); - - return promise; -} diff --git a/src/lib/helper/caseNumberOccupied.ts b/src/lib/helper/caseNumberOccupied.ts index 0d95f73..3c6b08d 100644 --- a/src/lib/helper/caseNumberOccupied.ts +++ b/src/lib/helper/caseNumberOccupied.ts @@ -1,7 +1,7 @@ import { client } from '$lib/minio'; export default async function caseNumberOccupied (caseNumber: string): Promise { - const prefix = `${caseNumber}/config.json`; + const prefix = `${caseNumber}`; const promise: Promise = new Promise((resolve) => { const stream = client.listObjectsV2('tatort', prefix, false, ''); stream.on('data', () => { diff --git a/src/lib/helper/getCode.js b/src/lib/helper/getCode.ts similarity index 100% rename from src/lib/helper/getCode.js rename to src/lib/helper/getCode.ts diff --git a/src/lib/server/authService.ts b/src/lib/server/authService.ts new file mode 100644 index 0000000..98155c8 --- /dev/null +++ b/src/lib/server/authService.ts @@ -0,0 +1,29 @@ +import { dev } from '$app/environment'; +import { fail, redirect, type Cookies, type RequestEvent } from '@sveltejs/kit'; +import { authenticate } from '$lib/auth'; + +const COOKIE_NAME = 'session'; + +export const loginUser = async ({ request, cookies }: { request: Request; cookies: Cookies }) => { + const data = await request.formData(); + const user = data.get('user'); + const password = data.get('password'); + + const token = authenticate(user, password); + + if (!token) return fail(400, { user, incorrect: true }); + + cookies.set(COOKIE_NAME, token, { + path: '/', + httpOnly: true, + sameSite: 'strict', + secure: !dev + }); + return redirect(303, '/'); +}; + +export const logoutUser = async (event: RequestEvent) => { + event.cookies.delete(COOKIE_NAME, { path: '/' }); + event.locals.user = null; + return { success: true }; +}; diff --git a/src/lib/server/s3ClientService.ts b/src/lib/server/s3ClientService.ts new file mode 100644 index 0000000..beb1411 --- /dev/null +++ b/src/lib/server/s3ClientService.ts @@ -0,0 +1,58 @@ +import { client } from '$lib/minio'; + +const BUCKET = 'tatort'; + +export const getVorgang = ({ params }) => { + const prefix = params.vorgang ? `${params.vorgang}/` : ''; + const stream = client.listObjectsV2('tatort', prefix, false, ''); + const result = new ReadableStream({ + start(controller) { + stream.on('data', (data) => { + if (prefix === '') { + if (data.prefix) + controller.enqueue(`${JSON.stringify({ ...data, name: data.prefix.slice(0, -1) })}\n`); + return; + } + + const name = data.name.slice(prefix.length); + if (name === 'config.json') return; + // zugangscode datei + if (name === '__perm__') return; + + controller.enqueue(`${JSON.stringify({ ...data, name, prefix })}\n`); + }); + stream.on('end', () => { + controller.close(); + }); + }, + cancel() { + stream.destroy(); + } + }); + + return new Response(result, { + headers: { + 'content-type': 'text/event-stream' + } + }); +}; + + +export const checkIfExactDirectoryExists = (dir: string): Promise => { + return new Promise((resolve, reject) => { + const prefix = dir.endsWith('/') ? dir : `${dir}/`; + + const stream = client.listObjectsV2(BUCKET, prefix, false, ''); + + stream.on('data', (obj) => { + if (obj.prefix === undefined && obj.name.startsWith(prefix)) { + stream.destroy(); + resolve(true); + } + }); + + stream.on('error', (err) => reject(err)); + + stream.on('end', () => resolve(false)); + }); +} diff --git a/src/lib/server/vorgangService.ts b/src/lib/server/vorgangService.ts new file mode 100644 index 0000000..cb0dda7 --- /dev/null +++ b/src/lib/server/vorgangService.ts @@ -0,0 +1,68 @@ +import { fail, redirect } from '@sveltejs/kit'; +import { client } from '$lib/minio'; +import { checkIfExactDirectoryExists } from './s3ClientService'; + +/** + * + * @param request + * @returns + */ +export const getVorgangByCaseNumber = async ( request: Request) => { + const data = await request.formData(); + const caseNumber = data.get('caseNumber'); + const user_token = data.get('token'); + + if (!caseNumber) { + return fail(400, { + success: false, + caseNumber, + error: { message: 'Die Vorgangsnummer darf nicht leer sein.' } + }); + } + + if (typeof caseNumber === 'string' && !(await checkIfExactDirectoryExists(caseNumber))) { + return fail(400, { + success: false, + caseNumber, + error: { message: 'Die Vorgangsnummer existiert in dieser Anwendung nicht.' } + }); + } + + + const token = await getTokenOrNull(caseNumber); + + if (token && token != user_token) { + return fail(400, { + success: false, + caseNumber, + error: { message: 'Der Token ist falsch.' } + }); + } + + redirect(303, `/list/${caseNumber}`); + } + + +const getTokenOrNull = async (vorgang) => { + const code_name = '__perm__'; + const obj_path = `${vorgang}/${code_name}`; + + let resp = null; + let code_saved = ''; + + try { + resp = await client.getObject('tatort', obj_path); + + code_saved = await new Response(resp).text(); + } catch (error) { + if (error.name == 'S3Error') { + resp = null; + } + } + + if (resp != null) { + return code_saved; + } else { + return null; + } +} diff --git a/src/routes/(angemeldet)/+layout.server.ts b/src/routes/(angemeldet)/+layout.server.ts index 0454232..5251779 100644 --- a/src/routes/(angemeldet)/+layout.server.ts +++ b/src/routes/(angemeldet)/+layout.server.ts @@ -1,5 +1,5 @@ import { redirect, type ServerLoadEvent } from '@sveltejs/kit'; -import type { PageServerLoad } from './view/[vorgang]/[tatort]/$types'; +import type { PageServerLoad } from '../anmeldung/$types'; export const load: PageServerLoad = (event: ServerLoadEvent) => { if (!event.locals.user && event.url.pathname !== '/anmeldung') throw redirect(303, '/anmeldung'); diff --git a/src/routes/(angemeldet)/+layout.svelte b/src/routes/(angemeldet)/+layout.svelte index 00beb40..a3a4cd5 100644 --- a/src/routes/(angemeldet)/+layout.svelte +++ b/src/routes/(angemeldet)/+layout.svelte @@ -1,73 +1,18 @@
-
- -
+
+
-
diff --git a/src/routes/(angemeldet)/tatorte/+page.svelte b/src/routes/(angemeldet)/tatorte/+page.svelte index 6798fe5..44acb50 100644 --- a/src/routes/(angemeldet)/tatorte/+page.svelte +++ b/src/routes/(angemeldet)/tatorte/+page.svelte @@ -1,10 +1,10 @@ + +
+
+ +
+ +
+ +
+
diff --git a/src/routes/(angemeldet)/list/+page.svelte b/src/routes/(token-based)/list/+page.svelte similarity index 100% rename from src/routes/(angemeldet)/list/+page.svelte rename to src/routes/(token-based)/list/+page.svelte diff --git a/src/routes/(angemeldet)/list/[vorgang]/+page.svelte b/src/routes/(token-based)/list/[vorgang]/+page.svelte similarity index 94% rename from src/routes/(angemeldet)/list/[vorgang]/+page.svelte rename to src/routes/(token-based)/list/[vorgang]/+page.svelte index 8b18f66..695d7c9 100644 --- a/src/routes/(angemeldet)/list/[vorgang]/+page.svelte +++ b/src/routes/(token-based)/list/[vorgang]/+page.svelte @@ -5,12 +5,12 @@ import timeElapsed from '$lib/helper/timeElapsed'; - import Alert from '$lib/components/ui/Alert.svelte'; - import Button from '$lib/components/ui/Button.svelte'; - import Modal from '$lib/components/ui/Modal/Modal.svelte'; - import ModalTitle from '$lib/components/ui/Modal/ModalTitle.svelte'; - import ModalContent from '$lib/components/ui/Modal/ModalContent.svelte'; - import ModalFooter from '$lib/components/ui/Modal/ModalFooter.svelte'; + import Alert from '$lib/components/Alert.svelte'; + import Button from '$lib/components/Button.svelte'; + import Modal from '$lib/components/Modal/Modal.svelte'; + import ModalTitle from '$lib/components/Modal/ModalTitle.svelte'; + 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'; @@ -92,7 +92,6 @@ let text_field = document.getElementById(text_field_id); if (text_field) { - text_field.setAttribute('contenteditable', 'false'); text_field.setAttribute('contenteditable', 'false'); text_field.textContent = item.name; } @@ -173,9 +172,9 @@ >
- +
- {#if data.user.admin} + {#if data?.user?.admin} getVorgangByCaseNumber(request) +} \ No newline at end of file diff --git a/src/routes/(angemeldet)/view/+page.svelte b/src/routes/(token-based)/view/+page.svelte similarity index 98% rename from src/routes/(angemeldet)/view/+page.svelte rename to src/routes/(token-based)/view/+page.svelte index 041414d..cd8c641 100644 --- a/src/routes/(angemeldet)/view/+page.svelte +++ b/src/routes/(token-based)/view/+page.svelte @@ -1,5 +1,5 @@
@@ -21,88 +18,75 @@ Landeswappen Niedersachsen

- Anmeldung zum 3D Tatort + Willkommen beim 3D Tatort

- -
-
-
- -
-
- -
-
- {#if form?.error?.caseNumber} -

{form.error.caseNumber}

- {/if} -
-
-
- -
-
- - - Anmelden - -
-
-
- -
- -
-
- -
- -
- -
-
- -
- +
+
+
+ + +
+
- - - + +
+
+ +
+
+ + Anmelden + +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+
+
+ +