Mitarbeiter-Zugang: Review-Punkte (fail closed, Kunden-Konto bleibt, Probelauf robuster)

- removeEmployeeEntry: nur 404 heisst "kein Konto", jeder andere Fehler bricht ab
- Mitarbeiter loeschen (Admin-Panel): Konto ohne Mitarbeiter-Label (Kunde mit
  altem employees-Eintrag) bleibt bestehen, nur der Eintrag geht
- Mitarbeiter bearbeiten gibt nie automatisch das Label (der Eintrag kann von
  einem Kunden stammen); nur Neuanlage bekommt "mitarbeiter"
- --rechte: --offen-lassen <ids>, unlesbare Listen als Fehler statt Abbruch
  (--anwenden verweigert dann), --sicherung <datei> + docker-cp-Hinweis,
  Bucket-Einstellung transformations wird mitgeschickt
- getEmployeeByEmail entfernt (unbenutzt)
- Tests: write/users-unverified, zweiter Lauf idempotent, >100 Dokumente,
  Loeschen mit Kunden- und Mitarbeiter-Konto

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-03 11:00:48 +00:00
1 parent 2659385205
commit 10b393687c
6 files changed
+139 -40

No files matched your search

+19 -7
View File
@@ -14,7 +14,7 @@ import {
updateDocument,
Query,
} from './appwriteAdmin.js'
import { ADMIN_LABEL, STAFF_LABEL, isAdminAccount } from './staffLabels.js'
import { ADMIN_LABEL, STAFF_LABEL, isAdminAccount, isStaffAccount } from './staffLabels.js'
function httpError(status, message) {
const error = new Error(message)
@@ -46,12 +46,13 @@ async function employeeWithUser(employee) {
return sanitizeEmployee(employee, user)
}
// Jeder Mitarbeiter traegt das Label "mitarbeiter" (Zugang zum Ticketsystem, siehe staffLabels.js);
// isAdmin undefined laesst "admin" unveraendert
async function setStaffLabels(userId, isAdmin) {
// Neue Mitarbeiter bekommen das Label "mitarbeiter" (Zugang zum Ticketsystem, siehe staffLabels.js). Beim
// Bearbeiten nie automatisch: ein employees-Eintrag kann von einem Kunden stammen (frueher selbst anlegbar);
// Zugang fuer Bestandskonten nur per scripts/mitarbeiter-zugang.mjs --label
async function setStaffLabels(userId, { isAdmin, grantStaff = false }) {
const user = await getUserById(userId)
const labels = new Set(user.labels || [])
labels.add(STAFF_LABEL)
if (grantStaff) labels.add(STAFF_LABEL)
if (isAdmin === true) labels.add(ADMIN_LABEL)
if (isAdmin === false) labels.delete(ADMIN_LABEL)
await updateAppwriteUserLabels(userId, [...labels])
@@ -81,7 +82,7 @@ export async function createEmployeeWithLogin(payload) {
const user = await createAppwriteUser({ email, password, name: displayName })
let employee
try {
await setStaffLabels(user.$id, isAdmin)
await setStaffLabels(user.$id, { isAdmin, grantStaff: true })
employee = await createDocument(config.collections.employees, {
userId: user.$id,
displayName,
@@ -135,7 +136,9 @@ export async function updateEmployeeWithLogin(employeeId, payload, actorUserId)
if (password) {
await updateAppwriteUserPassword(employee.userId, password)
}
await setStaffLabels(employee.userId, payload?.isAdmin === undefined ? undefined : Boolean(payload.isAdmin))
if (payload?.isAdmin !== undefined) {
await setStaffLabels(employee.userId, { isAdmin: Boolean(payload.isAdmin) })
}
const updated = await updateDocument(config.collections.employees, employeeId, {
displayName,
@@ -153,7 +156,16 @@ export async function deleteEmployeeWithLogin(employeeId, actorUserId) {
throw httpError(400, 'Der eigene angemeldete Account kann nicht gelöscht werden')
}
// Konto ohne Mitarbeiter-Label (z. B. Kunde mit altem employees-Eintrag): nur den Eintrag loeschen, das Konto ist
// sein Portal-Login. Konto nicht lesbar -> abbrechen statt zu raten
const user = employee.userId
? await getUserById(employee.userId).catch((err) => {
if (err.status === 404) return null
throw err
})
: null
await deleteDocument(config.collections.employees, employeeId)
if (!isStaffAccount(user)) return { success: true, accountKept: Boolean(user) }
await deleteAppwriteUser(employee.userId).catch((error) => {
error.message = `Mitarbeiter entfernt, Login konnte nicht gelöscht werden: ${error.message}`
throw error