f052_admin_area #27

Merged
jared merged 13 commits from f052_admin_area into development 2025-08-21 11:08:45 +02:00
Showing only changes of commit 723ec0773d - Show all commits

View File

@@ -1,174 +1,194 @@
<script lang="ts">
import {onMount} from 'svelte';
import Button from "$lib/components/Button.svelte";
import { onMount } from 'svelte';
import Button from '$lib/components/Button.svelte';
import jsSHA from 'jssha'
import jsSHA from 'jssha';
const {data} = $props();
const { data } = $props();
let userName = $state('')
let userPassword = $state('')
let userList: { userId: string; userName: string }[] = $state([])
let addUserError = $state(false);
let addUserSuccess = $state(false);
const currentUser: string = data.user.id;
let userName = $state('');
let userPassword = $state('');
let userList: { userId: string; userName: string }[] = $state([]);
let addUserError = $state(false);
let addUserSuccess = $state(false);
const currentUser: string = data.user.id;
onMount(async () => {
userList = await getUsers();
})
onMount(async () => {
try {
userList = await getUsers();
} catch (error) {
console.log(`An error occured while retrieving users: ${error}`);
trachi93 marked this conversation as resolved Outdated
Outdated
Review

try catch block benutzen

try catch block benutzen
}
trachi93 marked this conversation as resolved Outdated
Outdated
Review

sowas kann man ganz gut in eine constante auslagern also ein enum oder objekt, welches alle routen hält und ich diese dann nur referenzieren muss. das sind solche "magic strings"

sowas kann man ganz gut in eine constante auslagern also ein enum oder objekt, welches alle routen hält und ich diese dann nur referenzieren muss. das sind solche "magic strings"

müsste ganzheitlich getan werden -> Ticket angelegt

müsste ganzheitlich getan werden -> Ticket angelegt
});
async function getUsers() {
const URL = "/api/users"
const response = await fetch(URL);
async function getUsers() {
const URL = '/api/users';
return await response.json();
}
try {
trachi93 marked this conversation as resolved Outdated
Outdated
Review

Try Catch block

Try Catch block
const response = await fetch(URL);
return await response.json();
} catch (error) {
console.log(`Error fetching users: ${error}`);
return null;
}
}
async function addUser() {
if (userName == "") {
alert("Der Benutzername darf nicht leer sein.")
return;
}
async function addUser() {
if (userName == '') {
alert('Der Benutzername darf nicht leer sein.');
jared marked this conversation as resolved Outdated
Outdated
Review

s.o.

s.o.
return;
trachi93 marked this conversation as resolved Outdated
Outdated
Review

Das hashen von Passwörtern solle stets im Backend erfolgen. Hier sollte auch auf eine sichere Methode geachtet werden die noch eine Salt wert einfügt z.B. bycrpty o.ä.

Das hashen von Passwörtern solle stets im Backend erfolgen. Hier sollte auch auf eine sichere Methode geachtet werden die noch eine Salt wert einfügt z.B. bycrpty o.ä.

manuelles hashen wurde durch bcrypt ausgetauscht.

manuelles hashen wurde durch bcrypt ausgetauscht.
}
if (userPassword == "") {
alert("Das Passwort darf nicht leer sein.")
return;
}
if (userPassword == '') {
alert('Das Passwort darf nicht leer sein.');
return;
}
const URL = "/api/users";
const hashedUserPassword = new jsSHA('SHA-512', 'TEXT').update(userPassword).getHash('HEX');
const userData = {userName: userName, userPassword: hashedUserPassword}
const URL = '/api/users';
const hashedUserPassword = new jsSHA('SHA-512', 'TEXT').update(userPassword).getHash('HEX');
const userData = { userName: userName, userPassword: hashedUserPassword };
const response = await fetch(URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
})
try {
trachi93 marked this conversation as resolved Outdated
Outdated
Review

Performanter wäre es wenn du dir nach dem Erstellen des Users, dieses zurück liefern lässt. Damit reduzierst du Traffic

sowas wie
const newUser = await response.json();
userList = [...userList, newUser];

Performanter wäre es wenn du dir nach dem Erstellen des Users, dieses zurück liefern lässt. Damit reduzierst du Traffic sowas wie const newUser = await response.json(); userList = [...userList, newUser];
const response = await fetch(URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData)
});
if (response.ok) {
userList = await getUsers();
addUserSuccess = true;
resetInput();
} else {
addUserError = true;
}
}
if (response.ok) {
const newUser = await response.json();
userList = [...userList, newUser];
addUserSuccess = true;
resetInput();
} else {
addUserError = true;
}
} catch (error) {
trachi93 marked this conversation as resolved Outdated
Outdated
Review

try catch

try catch
console.log(`Error creating user: ${error}`);
addUserError = true;
}
}
function resetInput() {
userName = "";
userPassword = "";
addUserError = false;
setInterval(() => {
addUserSuccess = false;
}, 5000);
}
function resetInput() {
userName = '';
userPassword = '';
addUserError = false;
setInterval(() => {
addUserSuccess = false;
}, 5000);
}
async function deleteUser(userId: string) {
const URL = `/api/users/${userId}`;
async function deleteUser(userId: string) {
const URL = `/api/users/${userId}`;
const response = await fetch(URL, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
})
try {
const response = await fetch(URL, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
});
if (response.status == 204) {
userList = await getUsers();
} else {
alert("Nutzer konnte nicht gelöscht werden")
}
}
if (response.status == 204) {
userList = await getUsers();
} else {
alert('Nutzer konnte nicht gelöscht werden');
}
} catch (error) {
console.log(`Error deleting users: ${error}`);
}
}
</script>
<h1 class="flex justify-center text-3xl md:text-4xl font-bold text-gray-800 dark:text-white tracking-tight mb-4">
Benutzerverwaltung
Benutzerverwaltung
</h1>
<h1 class="flex justify-center text-lg md:text-xl font-medium text-gray-800 dark:text-white tracking-tight mb-2">
Benutzerliste
Benutzerliste
</h1>
<div class="w-1/4 mx-auto">
<table class="min-w-full border border-gray-300 rounded overflow-hidden">
<thead class="bg-gray-100 dark:bg-gray-700">
<tr>
<th class="text-left px-4 py-2">Benutzername</th>
<th class="text-center px-4 py-2">Entfernen</th>
</tr>
</thead>
<tbody>
{#each userList as userItem}
<tr class="border-t border-gray-200 dark:border-gray-600">
<td class="px-4 py-2 text-gray-800 dark:text-white">{userItem.userName}</td>
<td class="px-4 py-2 text-center">
<button
class="text-red-600 hover:text-red-800 focus:outline-none focus:ring-2 focus:ring-red-500 rounded-full p-1 transition"
on:click={() => deleteUser(userItem.userId)}
aria-label="Delete user"
>
{#if (userItem.userName != currentUser)}
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12"/>
</svg>
{/if}
</button>
</td>
</tr>
{/each}
</tbody>
</table>
<table class="min-w-full border border-gray-300 rounded overflow-hidden">
<thead class="bg-gray-100 dark:bg-gray-700">
<tr>
<th class="text-left px-4 py-2">Benutzername</th>
<th class="text-center px-4 py-2">Entfernen</th>
</tr>
</thead>
<tbody>
{#each userList as userItem}
<tr class="border-t border-gray-200 dark:border-gray-600">
<td class="px-4 py-2 text-gray-800 dark:text-white">{userItem.userName}</td>
<td class="px-4 py-2 text-center">
<button
class="text-red-600 hover:text-red-800 focus:outline-none focus:ring-2 focus:ring-red-500 rounded-full p-1 transition"
on:click={() => deleteUser(userItem.userId)}
aria-label="Delete user"
>
{#if (userItem.userName != currentUser)}
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
{/if}
</button>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
<h1 style="margin-top: 50px;"
class="flex justify-center text-lg md:text-xl font-medium text-gray-800 dark:text-white tracking-tight mb-2">
Neuer Nutzer
class="flex justify-center text-lg md:text-xl font-medium text-gray-800 dark:text-white tracking-tight mb-2">
Neuer Nutzer
</h1>
<div class="mx-auto flex justify-center">
<form>
<div class="form-group">
<label for="username">Benutzername</label>
<input bind:value={userName} type="text" id="username" placeholder="Namen eingeben"/>
</div>
<form>
<div class="form-group">
<label for="username">Benutzername</label>
<input bind:value={userName} type="text" id="username" placeholder="Namen eingeben" />
</div>
<div class="form-group">
<label for="password">Passwort</label>
<input bind:value={userPassword} type="password" id="password" placeholder="Passwort vergeben"/>
</div>
</form>
<div class="form-group">
<label for="password">Passwort</label>
<input bind:value={userPassword} type="password" id="password" placeholder="Passwort vergeben" />
</div>
</form>
</div>
<div class="mx-auto flex flex-col items-center space-y-4" style="margin-top: 20px;">
{#if addUserError}
<div class="flex items-center bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 rounded shadow-sm"
role="alert">
<svg class="h-5 w-5 mr-3 text-yellow-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01M12 5a7 7 0 100 14 7 7 0 000-14z"/>
</svg>
<span class="text-sm font-medium">Der Benutzer konnte nicht hinzugefügt werden.</span>
</div>
{/if}
{#if addUserSuccess}
<div class="flex items-center bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 rounded shadow-sm"
role="alert">
<svg class="h-5 w-5 mr-3 text-yellow-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01M12 5a7 7 0 100 14 7 7 0 000-14z"/>
</svg>
<span class="text-sm font-medium">Der Benutzer wurde hinzugefügt.</span>
</div>
{/if}
{#if addUserError}
<div class="flex items-center bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 rounded shadow-sm"
role="alert">
<svg class="h-5 w-5 mr-3 text-yellow-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01M12 5a7 7 0 100 14 7 7 0 000-14z" />
</svg>
<span class="text-sm font-medium">Der Benutzer konnte nicht hinzugefügt werden.</span>
</div>
{/if}
{#if addUserSuccess}
<div class="flex items-center bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 rounded shadow-sm"
role="alert">
<svg class="h-5 w-5 mr-3 text-yellow-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01M12 5a7 7 0 100 14 7 7 0 000-14z" />
</svg>
<span class="text-sm font-medium">Der Benutzer wurde hinzugefügt.</span>
</div>
{/if}
<Button on:click={addUser}>Benutzer hinzufügen</Button>
<Button on:click={addUser}>Benutzer hinzufügen</Button>
</div>
<style>