pdf hochladen und Anmeldungen loeschen

This commit is contained in:
titver968
2025-04-24 16:41:56 +02:00
parent e3c8dff646
commit 063f7f433c
11 changed files with 247 additions and 52 deletions

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
let anrede = '';
let vorname = '';
let nachname = '';
@@ -17,9 +18,10 @@
let wunsch1Id = '';
let wunsch2Id = '';
let wunsch3Id = '';
let pdfDateien: File[] = [];
let fehler = '';
let success = false;
let dienststellen: any[];
onMount(async () => {
@@ -28,16 +30,33 @@
});
async function anmelden() {
const data = new FormData();
data.append('anrede', anrede);
data.append('vorname', vorname);
data.append('nachname', nachname);
data.append('geburtsdatum', geburtsdatum);
data.append('strasse', strasse);
data.append('hausnummer', hausnummer);
data.append('ort', ort);
data.append('plz', plz);
data.append('telefon', telefon);
data.append('email', email);
data.append('schulart', schulart);
data.append('zeitraum', zeitraum);
data.append('motivation', motivation);
data.append('wunsch1Id', wunsch1Id);
data.append('wunsch2Id', wunsch2Id);
data.append('wunsch3Id', wunsch3Id);
for (const pdf of pdfDateien) {
data.append('pdfs', pdf);
}
const res = await fetch('/api/anmelden', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
anrede, vorname, nachname, geburtsdatum,
strasse, hausnummer, ort, plz,
telefon, email, schulart, zeitraum, motivation,
wunsch1Id, wunsch2Id, wunsch3Id
})
});
body: data
});
const result = await res.json();
if (!res.ok) {
@@ -108,6 +127,19 @@
class="w-full border border-gray-300 rounded-xl p-3 focus:outline-none focus:ring-2 focus:ring-blue-500 h-32 resize-none" >
</textarea>
<!-- Mehrere PDF Upload -->
<div>
<label for="pdf-upload" class="block text-gray-700 font-medium mb-1">PDFs hochladen (optional):</label>
<input
id="pdf-upload"
type="file"
accept="application/pdf"
multiple
on:change={(e) => pdfDateien = Array.from((e.target as HTMLInputElement).files || [])}
class="input"
/>
</div>
<!-- Button -->
<button type="submit"
class="w-full bg-blue-600 text-white py-3 rounded-xl hover:bg-blue-700 transition-all">

View File

@@ -1,4 +1,4 @@
import type { PageServerLoad } from '../../api/admin/anmeldungen/$types';
import type { PageServerLoad } from './$types';
import { redirect } from '@sveltejs/kit';
export const load: PageServerLoad = async ({ cookies }) => {

View File

@@ -1,6 +1,18 @@
<script lang="ts">
import { onMount } from 'svelte';
let anmeldungen = [];
interface Anmeldung {
anrede: string;
vorname: string;
nachname: string;
email: string;
wunsch1?: { name: string };
wunsch2?: { name: string };
wunsch3?: { name: string };
timestamp: number;
id: number;
}
let anmeldungen: Anmeldung[] = [];
async function ladeAnmeldungen() {
const res = await fetch('/api/admin/anmeldungen');
@@ -18,7 +30,7 @@
await ladeAnmeldungen();
} catch (error) {
console.error(error);
alert('Fehler beim Löschen der Anmeldung.\n' + error.message);
alert('Fehler beim Löschen der Anmeldung.\n' + (error as Error).message);
}
}
@@ -34,6 +46,7 @@
<th class="p-2 text-left">Name</th>
<th class="p-2 text-left">E-Mail</th>
<th class="p-2 text-left">Wunsch 13</th>
<th class="p-2 text-left">Datum</th>
<th class="p-2 text-left">Dateien</th>
<th class="p-2 text-left">Aktionen</th>
</tr>
@@ -48,6 +61,15 @@
{a.wunsch2?.name}<br>
{a.wunsch3?.name}
</td>
<td class="p-2">{new Date(a.timestamp).toLocaleDateString()}</td>
<td class="p-2">
{#each a.pdfs as pdf}
<li>
<a href={pdf.pfad} target="_blank" class="text-blue-600 hover:underline">
PDF ansehen
</a>
</li>
{/each}
</td>
<td class="p-2 text-right">
<button
@@ -71,7 +93,5 @@
</button>
</div>
<style>
.input {
@apply border rounded px-3 py-2 w-full;
<style>
/* Removed unused .input selector */

View File

@@ -1,9 +1,8 @@
//import { PrismaClient } from '@prisma/client';
//import type { RequestHandler } from '@sveltejs/kit';
import { PrismaClient } from '@prisma/client';
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import fs from 'fs/promises';
import path from 'path';
const prisma = new PrismaClient();
@@ -17,7 +16,8 @@ export const GET: RequestHandler = async ({ cookies }) => {
include: {
wunsch1: true,
wunsch2: true,
wunsch3: true
wunsch3: true,
pdfs: true
},
orderBy: { timestamp: 'desc' }
});
@@ -29,7 +29,36 @@ export const GET: RequestHandler = async ({ cookies }) => {
export const DELETE: RequestHandler = async ({ cookies, url }) => {
if (!checkAuth(cookies)) return new Response('Nicht erlaubt', { status: 401 });
const id = Number(url.searchParams.get('id'));
if (!id) return new Response('Ungültige ID', { status: 400 });
await prisma.anmeldung.delete({ where: { id } });
return json({ success: true });
if (isNaN(id)) {
return json({ error: 'Ungültige ID' }, { status: 400 });
}
try {
// 1. Alle PDF-Einträge zur Anmeldung laden
const pdfs = await prisma.pdfDatei.findMany({
where: { anmeldungId: id }
});
// 2. Dateien vom Dateisystem löschen
for (const pdf of pdfs) {
const filePath = path.resolve('static', pdf.pfad.replace(/^\/+/, ''));
try {
await fs.unlink(filePath);
} catch (err) {
console.warn(`Datei konnte nicht gelöscht werden: ${filePath}`, err.message);
// Fehler ignorieren, Datei evtl. manuell entfernt
}
}
// 3. PDF-Datensätze aus DB löschen
await prisma.pdfDatei.deleteMany({
where: {anmeldungId: id}
});
// Anmeldung löschen
await prisma.anmeldung.delete({where: { id } });
return json({ ok: true });
} catch (error) {
console.error('Fehler beim Löschen der Anmeldung:', error);
return json({ error: 'Löschen fehlgeschlagen' }, { status: 500 });
}
};

View File

@@ -1,43 +1,61 @@
import { PrismaClient } from '@prisma/client';
import { json, type RequestHandler } from '@sveltejs/kit';
import { Prisma } from '@prisma/client';
import { writeFile } from 'fs/promises';
import { randomUUID } from 'crypto';
import { json } from '@sveltejs/kit';
const prisma = new PrismaClient();
export const POST: RequestHandler = async ({ request }) => {
const data = await request.json();
export async function POST({ request }) {
const formData = await request.formData();
const get = (key: string) => formData.get(key)?.toString() ?? '';
const pdfs = formData.getAll('pdfs') as File[];
const gespeichertePfade: string[] = [];
for (const pdf of pdfs) {
if (pdf.size > 0 && pdf.type === 'application/pdf') {
const buffer = Buffer.from(await pdf.arrayBuffer());
const dateiname = `${randomUUID()}.pdf`;
const pfad = `/uploads/${dateiname}`;
await writeFile(`static${pfad}`, buffer);
gespeichertePfade.push(pfad);
}
}
try {
await prisma.anmeldung.create({
data: {
anrede: data.anrede,
vorname: data.vorname,
nachname: data.nachname,
geburtsdatum: data.geburtsdatum,
strasse: data.strasse,
hausnummer: data.hausnummer,
ort: data.ort,
plz: data.plz,
telefon: data.telefon,
email: data.email,
schulart: data.schulart,
zeitraum: data.zeitraum,
motivation: data.motivation,
wunsch1Id: data.wunsch1Id,
wunsch2Id: data.wunsch2Id,
wunsch3Id: data.wunsch3Id
anrede: get('anrede'),
vorname: get('vorname'),
nachname: get('nachname'),
geburtsdatum: get('geburtsdatum'),
strasse: get('strasse'),
hausnummer: get('hausnummer'),
ort: get('ort'),
plz: get('plz'),
telefon: get('telefon'),
email: get('email'),
schulart: get('schulart'),
zeitraum: get('zeitraum'),
motivation: get('motivation'),
wunsch1Id: parseInt(get('wunsch1Id')),
wunsch2Id: parseInt(get('wunsch2Id')),
wunsch3Id: parseInt(get('wunsch3Id')),
pdfs: {
create: gespeichertePfade.map((pfad) => ({ pfad }))
}
}
});
return json({ success: true });
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2002') {
// Eindeutigkeit verletzt
return json({ error: 'Diese E-Mail-Adresse wurde bereits verwendet.' }, { status: 400 });
}
} catch (err: unknown) {
if (err instanceof Error && (err as { code?: string }).code === 'P2002') {
return json({ error: 'Diese E-Mail wurde bereits verwendet.' }, { status: 400 });
}
console.error(error);
return json({ error: 'Ein Fehler ist aufgetreten.' }, { status: 500 });
console.error(err);
return json({ error: 'Fehler beim Speichern.' }, { status: 500 });
}
};
}