fix: canManage-Getter und Fehlerbehandlung in seedDefaults

- Neuer Getter canManage prüft, ob der aktive User Admin im Team ist
  (analog zu canEdit in trails.svelte.ts)
- seedDefaults() wirft jetzt gleich wenn keine Admin-Rechte vorhanden
  sind statt später 403 zu bekommen
- Bessere Fehlerbehandlung in der Schleife: bricht ab und zeigt,
  wie viele Flags bereits angelegt wurden
- Kommentar zu DEFAULT_FLAGS erweitert um das Label-Matching-Verhalten

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Michelberger 2026-08-06 18:07:40 +02:00
parent 6fd459e938
commit f432b47df1

View file

@ -1,5 +1,5 @@
import { getContext, setContext } from 'svelte'
import { api } from './pocketbase.svelte'
import { api, auth } from './pocketbase.svelte'
import { getTeamContext } from './teams.svelte'
import type { TrailFlagsResponse } from '$lib/types'
@ -10,6 +10,10 @@ const KEY = Symbol('trailFlag')
* dort kämen bei jedem Containerstart zurück, auch nachdem sie jemand gelöscht
* hat. Stattdessen legt sie die Flag-Verwaltung auf Knopfdruck an.
*
* Der Abgleich läuft über das Label. Wird ein Standard-Flag umbenannt, legt
* ein erneuter Aufruf es wieder neu an. Das ist hinnehmbar, weil die
* Flag-Verwaltung den Knopf nur zeigt, solange noch gar keine Flags existieren.
*
* icon: Name eines Lucide-Icons (lucide-svelte)
*/
export const DEFAULT_FLAGS = [
@ -39,6 +43,21 @@ export class TrailFlagStore {
return this.records.find((r) => r.id === id)
}
/**
* Flag-Typen anlegen, ändern und löschen darf nur, wer das Team führt
* dieselbe Regel wie in createRule/updateRule/deleteRule der Collection.
* Die Prüfung hier blendet nur UI aus; durchgesetzt wird sie serverseitig.
*/
get canManage(): boolean {
const uid = auth.user?.id
if (!uid) return false
const team = this.teams.records.find((t) => t.id === this.teams.activeId)
if (!team) return false
return team.owner === uid || ((team.admins ?? []) as string[]).includes(uid)
}
async load() {
this.loading = true
this.error = null
@ -89,14 +108,26 @@ export class TrailFlagStore {
async seedDefaults(): Promise<number> {
const teamId = this.teams.activeId
if (!teamId) throw new Error('Kein aktives Team')
if (!this.canManage) {
throw new Error('Dafür brauchst du Administratorrechte im Team.')
}
const existing = new Set(this.scoped.map((f) => f.label))
let created = 0
for (const flag of DEFAULT_FLAGS) {
if (existing.has(flag.label)) continue
await api.collection('trail_flags').create({ ...flag, team: teamId })
created++
try {
await api.collection('trail_flags').create({ ...flag, team: teamId })
created++
} catch (e: any) {
// Bricht mitten in der Schleife etwas ab, sollen die bereits
// angelegten Flags nicht verschwiegen werden.
throw new Error(
`${created} von ${DEFAULT_FLAGS.length} Typen angelegt, dann: ` +
(e.message ?? 'unbekannter Fehler'),
)
}
}
return created