import { config } from '../config.js' import { createAppwriteUser, createDocument, deleteAppwriteUser, deleteDocument, getDocument, getUserById, listDocuments, updateAppwriteUserEmail, updateAppwriteUserLabels, updateAppwriteUserName, updateAppwriteUserPassword, updateDocument, Query, } from './appwriteAdmin.js' function httpError(status, message) { const error = new Error(message) error.status = status return error } function normalizeEmail(value) { return String(value || '').trim().toLowerCase() } function normalizeShortcode(value) { return String(value || '').trim().toUpperCase().slice(0, 10) } function sanitizeEmployee(employee, user) { return { $id: employee.$id, userId: employee.userId, displayName: employee.displayName || user?.name || '', email: employee.email || user?.email || '', shortcode: employee.shortcode || '', isAdmin: Boolean(user?.labels?.includes('admin')), } } async function employeeWithUser(employee) { const user = await getUserById(employee.userId).catch(() => null) return sanitizeEmployee(employee, user) } async function setAdminLabel(userId, isAdmin) { const user = await getUserById(userId) const labels = new Set(user.labels || []) if (isAdmin) labels.add('admin') else labels.delete('admin') await updateAppwriteUserLabels(userId, [...labels]) } export async function listEmployeesForAdmin() { const employees = await listDocuments(config.collections.employees, [ Query.orderAsc('displayName'), Query.limit(500), ]) return Promise.all(employees.map(employeeWithUser)) } export async function createEmployeeWithLogin(payload) { const displayName = String(payload?.displayName || '').trim() const email = normalizeEmail(payload?.email) const password = String(payload?.password || '') const shortcode = normalizeShortcode(payload?.shortcode) const isAdmin = Boolean(payload?.isAdmin) if (!displayName) throw httpError(400, 'Name ist erforderlich') if (!email) throw httpError(400, 'E-Mail ist erforderlich') if (password.length < 8) { throw httpError(400, 'Passwort muss mindestens 8 Zeichen haben') } const user = await createAppwriteUser({ email, password, name: displayName }) let employee try { await setAdminLabel(user.$id, isAdmin) employee = await createDocument(config.collections.employees, { userId: user.$id, displayName, email, shortcode, }) } catch (error) { await deleteAppwriteUser(user.$id).catch(() => {}) throw error } return { employee: await employeeWithUser(employee) } } export async function updateEmployeeWithLogin(employeeId, payload, actorUserId) { const employee = await getDocument(config.collections.employees, employeeId) .catch(() => null) if (!employee) throw httpError(404, 'Mitarbeiter nicht gefunden') const displayName = payload?.displayName === undefined ? employee.displayName : String(payload.displayName || '').trim() const email = payload?.email === undefined ? normalizeEmail(employee.email) : normalizeEmail(payload.email) const shortcode = payload?.shortcode === undefined ? employee.shortcode || '' : normalizeShortcode(payload.shortcode) const password = typeof payload?.password === 'string' ? payload.password : '' if ( employee.userId === actorUserId && payload?.isAdmin === false ) { throw httpError(400, 'Die eigene Admin-Berechtigung kann nicht entfernt werden') } if (!displayName) throw httpError(400, 'Name ist erforderlich') if (!email) throw httpError(400, 'E-Mail ist erforderlich') if (password && password.length < 8) { throw httpError(400, 'Passwort muss mindestens 8 Zeichen haben') } const user = await getUserById(employee.userId) if (email !== normalizeEmail(user.email)) { await updateAppwriteUserEmail(employee.userId, email) } if (displayName !== (user.name || '')) { await updateAppwriteUserName(employee.userId, displayName) } if (password) { await updateAppwriteUserPassword(employee.userId, password) } if (payload?.isAdmin !== undefined) { await setAdminLabel(employee.userId, Boolean(payload.isAdmin)) } const updated = await updateDocument(config.collections.employees, employeeId, { displayName, email, shortcode, }) return { employee: await employeeWithUser(updated) } } export async function deleteEmployeeWithLogin(employeeId, actorUserId) { const employee = await getDocument(config.collections.employees, employeeId) .catch(() => null) if (!employee) throw httpError(404, 'Mitarbeiter nicht gefunden') if (employee.userId === actorUserId) { throw httpError(400, 'Der eigene angemeldete Account kann nicht gelöscht werden') } await deleteDocument(config.collections.employees, employeeId) await deleteAppwriteUser(employee.userId).catch((error) => { error.message = `Mitarbeiter entfernt, Login konnte nicht gelöscht werden: ${error.message}` throw error }) return { success: true } }