Entscheidungen vom 04.10.2026: - Projekt-Routen (website-projects, preview, gitea, services, analyse) fuer jeden Mitarbeiter (Label mitarbeiter oder admin); Kunden-, Mitarbeiter- und Finanz-Verwaltung bleiben nur fuer Admins - Neue Repos aus der Vorlage werden privat angelegt - Archivierte Projekte sieht der Kunde nicht mehr: Projektliste, Projektdetails, Preview-Zugang, Funktionen (Mitarbeiter-Ansicht schon) - Projektliste des Kunden mit Limit (Appwrite liefert sonst nur 25) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
95 lines
4.1 KiB
JavaScript
95 lines
4.1 KiB
JavaScript
// Admin-API (WOMS): Website-Analyse je Projekt ein-/ausschalten. Einschalten nur mit Zustimmung des Kunden in Textform (Datum + Weg).
|
|
import { Router } from 'express'
|
|
import { config } from '../../config.js'
|
|
import { getDocument } from '../../services/appwriteAdmin.js'
|
|
import { requireAppwriteTeam } from '../../middleware/appwriteStaff.js'
|
|
import { activateAnalyse, analyseEligibility, controllerView, deactivateAnalyse, ELIGIBILITY_MESSAGES, validateTextform } from '../../services/analyse.js'
|
|
import { getFeatureDoc } from '../../services/siteFeatures.js'
|
|
|
|
const router = Router()
|
|
// Projekt-Aktionen: jeder Mitarbeiter (nicht nur Admins)
|
|
router.use(requireAppwriteTeam)
|
|
|
|
function sendError(res, err) {
|
|
const status = [400, 403, 404, 409, 503].includes(err.status) && !err.type ? err.status : 500
|
|
if (status === 500) console.error('[admin-analyse]', err.message)
|
|
res.status(status).json({ error: status === 500 ? 'Die Analyse konnte nicht geändert werden' : err.message })
|
|
}
|
|
|
|
// Lesezugriff fuer das WOMS: Zustand + AVV-Angaben (nie siteKey oder Geheimnisse)
|
|
router.get('/:projectId', async (req, res) => {
|
|
try {
|
|
let project
|
|
try {
|
|
project = await getDocument(config.collections.websiteProjects, req.params.projectId)
|
|
} catch (err) {
|
|
if (err.status === 404) return res.status(404).json({ error: 'Projekt nicht gefunden' })
|
|
throw err
|
|
}
|
|
const customerId = project.customerId || ''
|
|
const [doc, eligibility, controller] = await Promise.all([
|
|
customerId ? getFeatureDoc(customerId, project.$id, 'analyse') : null,
|
|
analyseEligibility(customerId, project.$id),
|
|
controllerView(customerId),
|
|
])
|
|
res.json({
|
|
enabled: config.analyse.enabled,
|
|
state: doc ? doc.state || 'off' : null,
|
|
accentColor: doc?.accentColor || '#111111',
|
|
avvVersion: config.analyse.avvVersion,
|
|
avvAcceptedAt: doc?.avvAcceptedAt || null,
|
|
avvAcceptedBy: doc?.avvAcceptedBy || null,
|
|
avvConsentDate: doc?.avvConsentDate || null,
|
|
avvConsentChannel: doc?.avvConsentChannel || null,
|
|
privacy: { ok: controller.ok, missing: controller.missing },
|
|
activatedAt: doc?.activatedAt || null,
|
|
offSince: doc?.offSince || null,
|
|
eligible: eligibility.ok,
|
|
reasonText: eligibility.reason ? ELIGIBILITY_MESSAGES[eligibility.reason] : null,
|
|
})
|
|
} catch (err) {
|
|
sendError(res, err)
|
|
}
|
|
})
|
|
|
|
router.post('/:projectId', async (req, res) => {
|
|
try {
|
|
if (!config.analyse.enabled) return res.status(409).json({ error: 'Website-Analyse ist noch nicht freigeschaltet' })
|
|
const { on, textformDate, textformChannel, audienceConfirmed, avvConfirmedVerbally } = req.body || {}
|
|
if (typeof on !== 'boolean') return res.status(400).json({ error: 'on muss true oder false sein' })
|
|
let textform
|
|
if (on) {
|
|
if (avvConfirmedVerbally !== undefined) return res.status(400).json({ error: 'Zustimmung in Textform nötig' })
|
|
if (audienceConfirmed !== true) {
|
|
return res.status(400).json({ error: 'Bitte bestätigen, dass die Website sich nicht gezielt an Kinder unter 16 Jahren richtet' })
|
|
}
|
|
textform = validateTextform({ date: textformDate, channel: textformChannel })
|
|
}
|
|
let project
|
|
try {
|
|
project = await getDocument(config.collections.websiteProjects, req.params.projectId)
|
|
} catch (err) {
|
|
if (err.status === 404) return res.status(404).json({ error: 'Projekt nicht gefunden' })
|
|
throw err
|
|
}
|
|
const customerId = project.customerId
|
|
if (!customerId) return res.status(400).json({ error: 'Projekt hat keinen Kunden' })
|
|
const by = String(req.appwriteUser?.name || req.appwriteUser?.email || 'Mitarbeiter').slice(0, 100)
|
|
const { doc } = on
|
|
? await activateAnalyse({
|
|
customerId,
|
|
projectId: project.$id,
|
|
consent: { accepted: true, avvVersion: config.analyse.avvVersion },
|
|
by,
|
|
textform,
|
|
audienceConfirmed,
|
|
})
|
|
: await deactivateAnalyse({ customerId, projectId: project.$id, by })
|
|
res.json({ ok: true, state: doc?.state || 'off' })
|
|
} catch (err) {
|
|
sendError(res, err)
|
|
}
|
|
})
|
|
|
|
export default router
|