admin Berreich mit Passwort
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ node_modules
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
/data
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
Binary file not shown.
@@ -1,65 +1,60 @@
|
||||
<script lang="ts">
|
||||
let passwort = '';
|
||||
let eingeloggt = false;
|
||||
let fehler = false;
|
||||
let anmeldungen = [];
|
||||
|
||||
async function login() {
|
||||
const res = await fetch('/api/admin/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ passwort }),
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
eingeloggt = true;
|
||||
fehler = false;
|
||||
const result = await fetch('/api/admin/anmeldungen');
|
||||
anmeldungen = await result.json();
|
||||
} else {
|
||||
fehler = true;
|
||||
}
|
||||
let passwort = '';
|
||||
let eingeloggt = false;
|
||||
let fehler = false;
|
||||
|
||||
async function login() {
|
||||
const res = await fetch('/api/admin/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ passwort }),
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
eingeloggt = true;
|
||||
fehler = false;
|
||||
} else {
|
||||
fehler = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="p-6 max-w-4xl mx-auto">
|
||||
{#if !eingeloggt}
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-2xl font-bold">Admin Login</h1>
|
||||
<input type="password" bind:value={passwort} placeholder="Passwort" class="input w-full" />
|
||||
<button on:click={login} class="bg-blue-600 text-white px-4 py-2 rounded">Login</button>
|
||||
{#if fehler}
|
||||
<p class="text-red-600">Falsches Passwort</p>
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="p-6 max-w-lg mx-auto">
|
||||
{#if !eingeloggt}
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-2xl font-bold">Admin Login</h1>
|
||||
<input type="password" bind:value={passwort} placeholder="Passwort" class="input w-full" />
|
||||
<button on:click={login} class="bg-blue-600 text-white px-4 py-2 rounded">Login</button>
|
||||
{#if fehler}
|
||||
<p class="text-red-600">Falsches Passwort</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-2xl font-bold mb-4">Admin-Bereich</h1>
|
||||
<div class="flex flex-col gap-4">
|
||||
<a href="/admin/anmeldungen" class="bg-blue-600 text-white px-4 py-3 rounded text-center hover:bg-blue-700">
|
||||
📝 Anmeldungen anzeigen
|
||||
</a>
|
||||
<a href="/admin/dienststellen" class="bg-green-600 text-white px-4 py-3 rounded text-center hover:bg-green-700">
|
||||
🏢 Dienststellen verwalten
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<p><a href="/admin/dienststellen" class="text-blue-600 underline">Dienststellen verwalten</a></p>
|
||||
<h1 class="text-2xl font-bold mb-4">Alle Anmeldungen</h1>
|
||||
<table class="w-full border text-sm">
|
||||
<thead>
|
||||
<tr class="bg-gray-200">
|
||||
<th class="p-2 text-left">Name</th>
|
||||
<th class="p-2 text-left">E-Mail</th>
|
||||
<th class="p-2 text-left">Wunsch 1–3</th>
|
||||
<th class="p-2 text-left">Datum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each anmeldungen as a}
|
||||
<tr class="border-t">
|
||||
<td class="p-2">{a.anrede} {a.vorname} {a.nachname}</td>
|
||||
<td class="p-2">{a.email}</td>
|
||||
<td class="p-2">{a.wunsch1}, {a.wunsch2}, {a.wunsch3}</td>
|
||||
<td class="p-2">{new Date(a.timestamp).toLocaleDateString()}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.input {
|
||||
@apply border rounded px-3 py-2 w-full;
|
||||
}
|
||||
<button
|
||||
on:click={async () => {
|
||||
await fetch('/api/admin/logout', { method: 'POST' });
|
||||
location.reload();
|
||||
}}
|
||||
class="text-sm text-red-600 underline"
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.input {
|
||||
@apply border rounded px-3 py-2 w-full;
|
||||
}
|
||||
</style>
|
||||
8
src/routes/admin/anmeldungen/+page.server.ts
Normal file
8
src/routes/admin/anmeldungen/+page.server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { PageServerLoad } from '../../api/admin/anmeldungen/$types';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export const load: PageServerLoad = async ({ cookies }) => {
|
||||
if (cookies.get('admin_session') !== 'true') {
|
||||
throw redirect(303, '/admin');
|
||||
}
|
||||
};
|
||||
40
src/routes/admin/anmeldungen/+page.svelte
Normal file
40
src/routes/admin/anmeldungen/+page.svelte
Normal file
@@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
let anmeldungen = [];
|
||||
|
||||
async function ladeAnmeldungen() {
|
||||
const res = await fetch('/api/admin/anmeldungen');
|
||||
anmeldungen = await res.json();
|
||||
}
|
||||
onMount(ladeAnmeldungen);
|
||||
|
||||
</script>
|
||||
|
||||
<div class="p-6 max-w-4xl mx-auto">
|
||||
<h1 class="text-2xl font-bold mb-4">Alle Anmeldungen</h1>
|
||||
<table class="w-full border text-sm">
|
||||
<thead>
|
||||
<tr class="bg-gray-200">
|
||||
<th class="p-2 text-left">Name</th>
|
||||
<th class="p-2 text-left">E-Mail</th>
|
||||
<th class="p-2 text-left">Wunsch 1–3</th>
|
||||
<th class="p-2 text-left">Datum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each anmeldungen as a}
|
||||
<tr class="border-t">
|
||||
<td class="p-2">{a.anrede} {a.vorname} {a.nachname}</td>
|
||||
<td class="p-2">{a.email}</td>
|
||||
<td class="p-2">{a.wunsch1.name}<br>{a.wunsch2.name}<br>{a.wunsch3.name}</td>
|
||||
<td class="p-2">{new Date(a.timestamp).toLocaleDateString()}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.input {
|
||||
@apply border rounded px-3 py-2 w-full;
|
||||
}
|
||||
8
src/routes/admin/dienststellen/+page.server.ts
Normal file
8
src/routes/admin/dienststellen/+page.server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export const load: PageServerLoad = async ({ cookies }) => {
|
||||
if (cookies.get('admin_session') !== 'true') {
|
||||
throw redirect(303, '/admin'); // zurück zur Login-Seite
|
||||
}
|
||||
};
|
||||
@@ -5,11 +5,11 @@ const prisma = new PrismaClient();
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
const anmeldungen = await prisma.anmeldung.findMany({
|
||||
//include: {
|
||||
// wunsch1: true,
|
||||
// wunsch2: true,
|
||||
// wunsch3: true
|
||||
//};
|
||||
include: {
|
||||
wunsch1: true,
|
||||
wunsch2: true,
|
||||
wunsch3: true
|
||||
},
|
||||
orderBy: { timestamp: 'desc' }
|
||||
});
|
||||
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export const GET: RequestHandler = async () => {
|
||||
function checkAuth(cookies: any) {
|
||||
return cookies.get('admin_session') === 'true';
|
||||
}
|
||||
|
||||
export const GET: RequestHandler = async ({ cookies }) => {
|
||||
if (!checkAuth(cookies)) return new Response('Nicht erlaubt', { status: 401 });
|
||||
const dienststellen = await prisma.dienststelle.findMany({ orderBy: { name: 'asc' } });
|
||||
return new Response(JSON.stringify(dienststellen));
|
||||
return json(dienststellen);
|
||||
};
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
export const POST: RequestHandler = async ({ cookies, request }) => {
|
||||
if (!checkAuth(cookies)) return new Response('Nicht erlaubt', { status: 401 });
|
||||
const { name } = await request.json();
|
||||
try {
|
||||
const created = await prisma.dienststelle.create({ data: { name } });
|
||||
return new Response(JSON.stringify(created));
|
||||
return json(created);
|
||||
} catch (e) {
|
||||
return new Response(JSON.stringify({ error: 'Dienststelle existiert bereits' }), { status: 400 });
|
||||
return json({ error: 'Dienststelle existiert bereits' }, { status: 400 });
|
||||
}
|
||||
};
|
||||
|
||||
export const DELETE: RequestHandler = async ({ url }) => {
|
||||
export const DELETE: RequestHandler = async ({ cookies, url }) => {
|
||||
if (!checkAuth(cookies)) return new Response('Nicht erlaubt', { status: 401 });
|
||||
const id = Number(url.searchParams.get('id'));
|
||||
await prisma.dienststelle.delete({ where: { id } });
|
||||
return new Response(JSON.stringify({ success: true }));
|
||||
return json({ success: true });
|
||||
};
|
||||
@@ -1,13 +1,20 @@
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
const ADMIN_PASS = 'supergeheim'; // Passwort hier festlegen
|
||||
const ADMIN_PASS = 'supergeheim'; // 🔒 Besser aus .env lesen
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
export const POST: RequestHandler = async ({ request, cookies }) => {
|
||||
const { passwort } = await request.json();
|
||||
|
||||
if (passwort === ADMIN_PASS) {
|
||||
return new Response(JSON.stringify({ success: true }));
|
||||
cookies.set('admin_session', 'true', {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
sameSite: 'strict',
|
||||
maxAge: 60 * 60 * 4 // 4 Stunden
|
||||
});
|
||||
return json({ success: true });
|
||||
}
|
||||
|
||||
return new Response('Unauthorized', { status: 401 });
|
||||
return json({ error: 'Falsches Passwort' }, { status: 401 });
|
||||
};
|
||||
6
src/routes/api/admin/logout/+server.ts
Normal file
6
src/routes/api/admin/logout/+server.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
export const POST: RequestHandler = async ({ cookies }) => {
|
||||
cookies.delete('admin_session', { path: '/' });
|
||||
return new Response('Ausgeloggt');
|
||||
};
|
||||
Reference in New Issue
Block a user