diff --git a/app/src/routes/(app)/orte/+page.svelte b/app/src/routes/(app)/orte/+page.svelte index 1dddc1e..9e8241e 100644 --- a/app/src/routes/(app)/orte/+page.svelte +++ b/app/src/routes/(app)/orte/+page.svelte @@ -32,8 +32,8 @@ onMount(async () => { [orte, ausfaelle] = await Promise.all([ - api.get('/veranstaltungsorte', { sort: 'name' }), - api.get('/ort_ausfaelle', { sort: 'von' }), + api.get('/orte', { sort: 'name' }), + api.get('/ort-ausfaelle', { sort: 'von' }), ]); loading = false; }); @@ -55,10 +55,10 @@ try { const data = { name: fName.trim(), adresse: fAdresse.trim() || null, typ: fTyp, aktiv: fAktiv }; if (editOrtId) { - const u = await api.put('/veranstaltungsorte/' + editOrtId, data); + const u = await api.put('/orte/' + editOrtId, data); orte = orte.map(o => o.id === editOrtId ? u : o); } else { - const n = await api.post('/veranstaltungsorte', data); + const n = await api.post('/orte', data); orte = [...orte, n].sort((a, b) => a.name.localeCompare(b.name)); } showOrtForm = false; @@ -71,7 +71,7 @@ async function ortLoeschen(id: string) { if (!confirm('Ort wirklich löschen? Alle verknüpften Termine verlieren die Ortzuordnung.')) return; - await api.del('/veranstaltungsorte/' + id); + await api.del('/orte/' + id); orte = orte.filter(o => o.id !== id); ausfaelle = ausfaelle.filter(a => a.ort_id !== id); } @@ -86,7 +86,7 @@ if (aVon > aBis) { ausfallError = 'Bis muss nach Von liegen.'; return; } ausfallError = ''; ausfallSaving = true; try { - const n = await api.post('/ort_ausfaelle', { + const n = await api.post('/ort-ausfaelle', { ort_id: aOrtId, von: aVon, bis: aBis, grund: aGrund.trim() || null, }); ausfaelle = [...ausfaelle, n].sort((a, b) => a.von.localeCompare(b.von)); @@ -99,7 +99,7 @@ } async function ausfallLoeschen(id: string) { - await api.del('/ort_ausfaelle/' + id); + await api.del('/ort-ausfaelle/' + id); ausfaelle = ausfaelle.filter(a => a.id !== id); } diff --git a/app/src/routes/(app)/termine/+page.svelte b/app/src/routes/(app)/termine/+page.svelte index 88a4d01..62c1b4a 100644 --- a/app/src/routes/(app)/termine/+page.svelte +++ b/app/src/routes/(app)/termine/+page.svelte @@ -67,8 +67,8 @@ isAdmin() ? api.get('/users', { rolle: 'trainer' }) : Promise.resolve([]), - api.get('/veranstaltungsorte', { sort: 'name', aktiv: 'true' }), - api.get('/ort_ausfaelle', { sort: 'von' }), + api.get('/orte', { sort: 'name', aktiv: 'true' }), + api.get('/ort-ausfaelle', { sort: 'von' }), ]); loading = false; }); diff --git a/app/src/routes/api/users/+server.ts b/app/src/routes/api/users/+server.ts new file mode 100644 index 0000000..4f8e7d4 --- /dev/null +++ b/app/src/routes/api/users/+server.ts @@ -0,0 +1,18 @@ +import { json } from '@sveltejs/kit'; +import { getDb, rows } from '$lib/server/db'; +import { requireAuth } from '$lib/server/auth'; + +export async function GET({ request, url }) { + const u = await requireAuth(request); + const db = getDb(); + const rolle = url.searchParams.get('rolle'); + + let query = 'SELECT id, verein_id, email, name, rolle, created FROM users WHERE verein_id = ?'; + const params: unknown[] = [u.verein_id]; + + if (rolle) { query += ' AND rolle = ?'; params.push(rolle); } + query += ' ORDER BY name'; + + const users = db.prepare(query).all(...params); + return json(users); +} diff --git a/app/src/routes/api/users/[id]/+server.ts b/app/src/routes/api/users/[id]/+server.ts new file mode 100644 index 0000000..8a18995 --- /dev/null +++ b/app/src/routes/api/users/[id]/+server.ts @@ -0,0 +1,47 @@ +import { json, error } from '@sveltejs/kit'; +import { getDb } from '$lib/server/db'; +import { requireAuth, hashPassword } from '$lib/server/auth'; + +export async function GET({ request, params }) { + const u = await requireAuth(request); + const db = getDb(); + const row = db.prepare( + 'SELECT id, verein_id, email, name, rolle, created FROM users WHERE id = ? AND verein_id = ?' + ).get(params.id, u.verein_id); + if (!row) throw error(404, 'User nicht gefunden'); + return json(row); +} + +export async function PUT({ request, params }) { + const u = await requireAuth(request); + const db = getDb(); + const body = await request.json(); + + const existing = db.prepare('SELECT id FROM users WHERE id = ? AND verein_id = ?').get(params.id, u.verein_id); + if (!existing) throw error(404, 'User nicht gefunden'); + + const fields: string[] = []; + const vals: unknown[] = []; + + if (body.name !== undefined) { fields.push('name = ?'); vals.push(body.name); } + if (body.email !== undefined) { fields.push('email = ?'); vals.push(body.email.toLowerCase()); } + if (body.rolle !== undefined) { fields.push('rolle = ?'); vals.push(body.rolle || null); } + if (body.password) { fields.push('password_hash = ?'); vals.push(await hashPassword(body.password)); } + if (!fields.length) throw error(400, 'Keine Felder zum Aktualisieren'); + + fields.push("updated = strftime('%Y-%m-%dT%H:%M:%SZ','now')"); + vals.push(params.id, u.verein_id); + + db.prepare(`UPDATE users SET ${fields.join(', ')} WHERE id = ? AND verein_id = ?`).run(...vals); + const row = db.prepare('SELECT id, verein_id, email, name, rolle, created FROM users WHERE id = ?').get(params.id); + return json(row); +} + +export async function DELETE({ request, params }) { + const u = await requireAuth(request); + if (u.sub === params.id) throw error(400, 'Eigenen Account nicht löschbar'); + const db = getDb(); + const result = db.prepare('DELETE FROM users WHERE id = ? AND verein_id = ?').run(params.id, u.verein_id); + if (result.changes === 0) throw error(404, 'User nicht gefunden'); + return new Response(null, { status: 204 }); +}