Analyse: Zielgruppen-Bestätigung in Historie, Rücknahme bei Fehler nach Dokument-Update, handelnde Person mit Name und E-Mail
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3d05472b25
commit
f401dc14d7
7 files changed
+108
-56
No files matched your search
@@ -23,6 +23,9 @@ export const ANALYSE_ATTRIBUTES = [
|
||||
{ key: 'avvConsentChannel', type: 'string', size: 10, required: false },
|
||||
{ key: 'removalTicketId', type: 'string', size: 40, required: false },
|
||||
{ key: 'publishTicketId', type: 'string', size: 40, required: false },
|
||||
// Zielgruppen-Bestaetigung (nicht an Kinder unter 16): bestaetigt + Fassung des Bestaetigungstextes
|
||||
{ key: 'audienceConfirmed', type: 'boolean', required: false },
|
||||
{ key: 'audienceTextVersion', type: 'string', size: 20, required: false },
|
||||
]
|
||||
|
||||
const str = (key, size) => ({ key, type: 'string', size, required: false })
|
||||
@@ -40,6 +43,8 @@ export const CONSENT_ATTRIBUTES = [
|
||||
str('acceptedBy', 100),
|
||||
str('textformDate', 10),
|
||||
str('textformChannel', 10),
|
||||
{ key: 'audienceConfirmed', type: 'boolean', required: false },
|
||||
str('audienceTextVersion', 20),
|
||||
]
|
||||
export const CONSENT_INDEXES = [{ key: 'projectId_idx', type: 'key', attributes: ['projectId'] }]
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ router.post('/:projectId', async (req, res) => {
|
||||
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' })
|
||||
|
||||
@@ -37,6 +37,12 @@ function fail(res, err, fallback) {
|
||||
return res.status(500).json({ error: fallback })
|
||||
}
|
||||
|
||||
// Handelnde Person: bei Admin-Sitzung (adminName/adminEmail, siehe auth.js) der Admin, sonst der Kunde
|
||||
const actingPerson = (session) =>
|
||||
session.adminName || session.adminEmail
|
||||
? { name: session.adminName, email: session.adminEmail }
|
||||
: { name: session.name, email: session.email }
|
||||
|
||||
const ANALYSE_OFF = 'Website-Analyse ist noch nicht freigeschaltet'
|
||||
const ANALYSE_ERROR = 'Die Website-Analyse konnte gerade nicht geändert werden. Bitte versuch es später noch einmal oder schreib uns im Chat.'
|
||||
|
||||
@@ -183,7 +189,7 @@ router.post('/analyse/activate', analyseGuard, async (req, res) => {
|
||||
accentColor,
|
||||
consent,
|
||||
by: 'customer',
|
||||
actor: { name: req.session.name, email: req.session.email },
|
||||
actor: actingPerson(req.session),
|
||||
})
|
||||
res.json({ ok: true, state: doc.state })
|
||||
} catch (err) {
|
||||
@@ -200,7 +206,7 @@ router.post('/analyse/deactivate', analyseGuard, async (req, res) => {
|
||||
customerId: getSessionCustomerId(req),
|
||||
projectId: analyseProjectId(req.body?.projectId),
|
||||
by: 'customer',
|
||||
actor: { name: req.session.name, email: req.session.email },
|
||||
actor: actingPerson(req.session),
|
||||
})
|
||||
res.json({ ok: true, state: doc?.state || 'off' })
|
||||
} catch (err) {
|
||||
|
||||
+46
-30
@@ -102,6 +102,9 @@ export async function controllerView(customerId) {
|
||||
return { company, address, email, ok, missing }
|
||||
}
|
||||
|
||||
/** "Name <E-Mail>" (oder was davon da ist), max. 100 Zeichen */
|
||||
const personLabel = (p) => (p?.name && p?.email ? `${p.name} <${p.email}>` : p?.name || p?.email || '').slice(0, 100)
|
||||
|
||||
const berlinToday = (now) => new Intl.DateTimeFormat('sv-SE', { timeZone: 'Europe/Berlin' }).format(now)
|
||||
|
||||
/**
|
||||
@@ -168,7 +171,7 @@ function privacyTicket(customerId, project, siteKey) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function activateAnalyse({ customerId, projectId, accentColor, consent, by = 'customer', actor, textform, now = new Date() }) {
|
||||
export async function activateAnalyse({ customerId, projectId, accentColor, consent, by = 'customer', actor, textform, audienceConfirmed, now = new Date() }) {
|
||||
const viaCustomer = by === 'customer'
|
||||
let accepted
|
||||
let proof = { date: '', channel: '' }
|
||||
@@ -176,9 +179,11 @@ export async function activateAnalyse({ customerId, projectId, accentColor, cons
|
||||
if (!consent || consent.accepted !== true || consent.avvVersion !== config.analyse.avvVersion) {
|
||||
throw httpError(400, 'Bitte den Auftragsverarbeitungsvertrag bestätigen')
|
||||
}
|
||||
accepted = String(actor?.name || actor?.email || '').slice(0, 100)
|
||||
// Name und E-Mail der handelnden Person (bei Admin-Sitzung der Admin, siehe Route)
|
||||
accepted = personLabel(actor)
|
||||
if (!accepted) throw httpError(400, 'Bitte melde Dich neu an')
|
||||
} else {
|
||||
if (audienceConfirmed !== true) throw httpError(400, 'Bitte bestätigen, dass die Website sich nicht gezielt an Kinder unter 16 Jahren richtet')
|
||||
const t = validateTextform(textform, { today: berlinToday(now) })
|
||||
proof = { date: t.date, channel: t.channel }
|
||||
accepted = String(by).slice(0, 100)
|
||||
@@ -206,42 +211,53 @@ export async function activateAnalyse({ customerId, projectId, accentColor, cons
|
||||
// Erst beim Sammeldienst anmelden: schlaegt das fehl, bleibt das Dokument unveraendert (erneut versuchbar)
|
||||
await analyseDeps.client.putSite(siteKey, { projectId, domains: analyseDomains(project), active: true })
|
||||
const at = now.toISOString()
|
||||
const entry = {
|
||||
customerId,
|
||||
projectId,
|
||||
siteKey,
|
||||
event: 'on',
|
||||
avvVersion: config.analyse.avvVersion,
|
||||
via: viaCustomer ? 'portal' : 'woms',
|
||||
acceptedAt: at,
|
||||
acceptedBy: accepted,
|
||||
textformDate: proof.date,
|
||||
textformChannel: proof.channel,
|
||||
audienceConfirmed: true, // Kunden-Haken enthaelt die Zielgruppen-Aussage; Mitarbeiter bestaetigen sie getrennt
|
||||
audienceTextVersion: config.analyse.avvVersion,
|
||||
}
|
||||
let updated = false
|
||||
try {
|
||||
await analyseDeps.recordConsent({
|
||||
customerId,
|
||||
projectId,
|
||||
doc = await updateDocument(config.collections.portalFeatures, existing.$id, {
|
||||
...stateFields('active'),
|
||||
siteKey,
|
||||
event: 'on',
|
||||
avvVersion: config.analyse.avvVersion,
|
||||
via: viaCustomer ? 'portal' : 'woms',
|
||||
acceptedAt: at,
|
||||
acceptedBy: accepted,
|
||||
textformDate: proof.date,
|
||||
textformChannel: proof.channel,
|
||||
accentColor: color,
|
||||
avvVersion: entry.avvVersion,
|
||||
avvAcceptedAt: at,
|
||||
avvAcceptedBy: accepted,
|
||||
avvConsentDate: proof.date,
|
||||
avvConsentChannel: proof.channel,
|
||||
audienceConfirmed: true,
|
||||
audienceTextVersion: entry.audienceTextVersion,
|
||||
activatedAt: at,
|
||||
offSince: '',
|
||||
activatedMailAt: '', // jede neue Aktivierung bekommt ihre K18
|
||||
privacyTicketId: '', // und ihre Tickets
|
||||
removalTicketId: '',
|
||||
publishTicketId: '',
|
||||
})
|
||||
updated = true
|
||||
// Nachweis erst nach dem Dokument: scheitert er, wird alles zurueckgenommen (kein "on" ohne aktives Dokument)
|
||||
await analyseDeps.recordConsent(entry)
|
||||
} catch (err) {
|
||||
// Ohne Nachweis keine Aktivierung: Messdienst zuruecknehmen
|
||||
await analyseDeps.client
|
||||
.putSite(siteKey, { projectId, domains: analyseDomains(project), active: false })
|
||||
.catch((e) => console.warn(`[analyse] Rücknahme für Projekt ${projectId} fehlgeschlagen:`, e.message))
|
||||
if (updated) {
|
||||
await updateDocument(config.collections.portalFeatures, existing.$id, { ...stateFields(existing.state || 'off'), offSince: existing.offSince || '' })
|
||||
.catch((e) => console.warn(`[analyse] Zurücksetzen für Projekt ${projectId} fehlgeschlagen:`, e.message))
|
||||
}
|
||||
throw err
|
||||
}
|
||||
doc = await updateDocument(config.collections.portalFeatures, existing.$id, {
|
||||
...stateFields('active'),
|
||||
siteKey,
|
||||
accentColor: color,
|
||||
avvVersion: config.analyse.avvVersion,
|
||||
avvAcceptedAt: at,
|
||||
avvAcceptedBy: accepted,
|
||||
avvConsentDate: proof.date,
|
||||
avvConsentChannel: proof.channel,
|
||||
activatedAt: at,
|
||||
offSince: '',
|
||||
activatedMailAt: '', // jede neue Aktivierung bekommt ihre K18
|
||||
privacyTicketId: '', // und ihre Tickets
|
||||
removalTicketId: '',
|
||||
publishTicketId: '',
|
||||
})
|
||||
changed = true
|
||||
} else if (existing.accentColor !== color) {
|
||||
doc = await updateDocument(config.collections.portalFeatures, existing.$id, { accentColor: color })
|
||||
@@ -288,7 +304,7 @@ export async function deactivateAnalyse({ customerId, projectId, now = new Date(
|
||||
avvVersion: config.analyse.avvVersion,
|
||||
via: by === 'customer' || by === 'system' ? 'portal' : 'woms',
|
||||
acceptedAt: now.toISOString(),
|
||||
acceptedBy: String((by === 'customer' && (actor?.name || actor?.email)) || by).slice(0, 100),
|
||||
acceptedBy: (by === 'customer' && personLabel(actor)) || String(by).slice(0, 100),
|
||||
textformDate: '',
|
||||
textformChannel: '',
|
||||
})
|
||||
|
||||
+19
-11
@@ -7,8 +7,8 @@ import { schemaKeys } from './support/schema.js'
|
||||
import { mailSink } from './support/mailSink.js'
|
||||
|
||||
// Das Setup-Skript laedt config.js: erst nach useTestEnv() importieren, daher die Attributnamen hier fest
|
||||
const ANALYSE_KEYS = ['accentColor', 'avvVersion', 'avvAcceptedAt', 'avvAcceptedBy', 'activatedAt', 'offSince', 'privacyTicketId', 'activatedMailAt', 'avvConsentDate', 'avvConsentChannel', 'removalTicketId', 'publishTicketId']
|
||||
const CONSENT_KEYS = ['customerId', 'projectId', 'siteKey', 'event', 'avvVersion', 'via', 'acceptedAt', 'acceptedBy', 'textformDate', 'textformChannel']
|
||||
const ANALYSE_KEYS = ['accentColor', 'avvVersion', 'avvAcceptedAt', 'avvAcceptedBy', 'activatedAt', 'offSince', 'privacyTicketId', 'activatedMailAt', 'avvConsentDate', 'avvConsentChannel', 'removalTicketId', 'publishTicketId', 'audienceConfirmed', 'audienceTextVersion']
|
||||
const CONSENT_KEYS = ['customerId', 'projectId', 'siteKey', 'event', 'avvVersion', 'via', 'acceptedAt', 'acceptedBy', 'textformDate', 'textformChannel', 'audienceConfirmed', 'audienceTextVersion']
|
||||
const aw = await startAppwriteMock({
|
||||
schema: {
|
||||
portalFeatures: [...schemaKeys('portalFeatures'), ...ANALYSE_KEYS],
|
||||
@@ -101,7 +101,7 @@ test('Einschalten: Dokument, Sammeldienst, Neubau, Ticket, Mail K18', async () =
|
||||
assert.match(d.siteKey, /^[a-z0-9]{16,40}$/)
|
||||
assert.equal(d.accentColor, '#1a73e8')
|
||||
assert.equal(d.avvVersion, config.analyse.avvVersion)
|
||||
assert.equal(d.avvAcceptedBy, 'Kunde Eins')
|
||||
assert.equal(d.avvAcceptedBy, 'Kunde Eins <eins@example.invalid>')
|
||||
assert.ok(d.avvAcceptedAt && d.activatedAt)
|
||||
assert.deepEqual(puts, [{ siteKey: d.siteKey, projectId: 'p1', domains: ['baeckerei.project.webklar.com', 'baeckerei.de', 'www.baeckerei.de'], active: true }])
|
||||
assert.deepEqual(rebuilds, ['p1'])
|
||||
@@ -149,7 +149,7 @@ test('Ausschalten: off, offSince, Sammeldienst inaktiv, Neubau; erneut = nichts'
|
||||
|
||||
test('Wieder einschalten: gleicher siteKey, offSince leer, neues Ticket und Historie', async () => {
|
||||
const before = await doc('c1', 'p1')
|
||||
const { doc: d } = await an.activateAnalyse({ customerId: 'c1', projectId: 'p1', consent: consent(), by: 'Kenso', textform, now: NOW })
|
||||
const { doc: d } = await an.activateAnalyse({ customerId: 'c1', projectId: 'p1', consent: consent(), by: 'Kenso', textform, audienceConfirmed: true, now: NOW })
|
||||
assert.equal(d.siteKey, before.siteKey)
|
||||
assert.equal(d.state, 'active')
|
||||
assert.equal(d.offSince, '')
|
||||
@@ -257,7 +257,7 @@ test('gesperrte Analyse: Kunde 403, Mitarbeiter darf', async () => {
|
||||
const g = await sf.ensureFeatureDoc('c1', 'p10', 'analyse')
|
||||
await sf.disable(g.$id, {})
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p10', ...cust() }), { status: 403, message: 'Analyse wurde gesperrt – bitte melde dich bei uns' })
|
||||
const r = await an.activateAnalyse({ customerId: 'c1', projectId: 'p10', consent: consent(), by: 'Kenso', textform, now: NOW })
|
||||
const r = await an.activateAnalyse({ customerId: 'c1', projectId: 'p10', consent: consent(), by: 'Kenso', textform, audienceConfirmed: true, now: NOW })
|
||||
assert.equal(r.doc.state, 'active')
|
||||
})
|
||||
|
||||
@@ -326,7 +326,8 @@ test('Kunde ohne actor-Namen oder Mitarbeiter ohne Textform: 400', async () => {
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p13', consent: consent() }), { status: 400 })
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p13', consent: consent(), actor: {} }), { status: 400 })
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p13', consent: consent(), by: 'Kenso', now: NOW }), { status: 400 })
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p13', by: 'Kenso', textform: { date: '2026-10-01', channel: 'chat' }, now: NOW }), { status: 400 })
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p13', by: 'Kenso', textform, now: NOW }), { status: 400 }) // ohne Zielgruppen-Bestätigung
|
||||
await assert.rejects(an.activateAnalyse({ customerId: 'c1', projectId: 'p13', by: 'Kenso', audienceConfirmed: true, textform: { date: '2026-10-01', channel: 'chat' }, now: NOW }), { status: 400 })
|
||||
assert.equal(puts.length, 0)
|
||||
assert.equal((await consents('p13')).length, 0)
|
||||
})
|
||||
@@ -339,12 +340,16 @@ test('Historie: Kunde, Aus, An durch Mitarbeiter in zeitlicher Folge; Portal-Dok
|
||||
assert.equal(h[0].event, 'on')
|
||||
assert.equal(h[0].via, 'portal')
|
||||
assert.equal(h[0].avvVersion, '2026-10-02')
|
||||
assert.equal(h[0].acceptedBy, 'Kunde Eins')
|
||||
assert.equal(h[0].acceptedBy, 'Kunde Eins <eins@example.invalid>')
|
||||
assert.equal(h[0].customerId, 'c1')
|
||||
assert.equal(h[0].siteKey, d1.siteKey)
|
||||
assert.match(h[0].acceptedAt, /^\d{4}-\d\d-\d\dT[\d:.]+Z$/)
|
||||
assert.equal(h[0].acceptedAt, d1.avvAcceptedAt)
|
||||
assert.equal(d1.avvAcceptedBy, 'Kunde Eins')
|
||||
assert.equal(d1.avvAcceptedBy, 'Kunde Eins <eins@example.invalid>')
|
||||
assert.equal(d1.audienceConfirmed, true)
|
||||
assert.equal(d1.audienceTextVersion, '2026-10-02')
|
||||
assert.equal(h[0].audienceConfirmed, true)
|
||||
assert.equal(h[0].audienceTextVersion, '2026-10-02')
|
||||
assert.equal(d1.avvConsentDate, '')
|
||||
assert.equal(d1.avvConsentChannel, '')
|
||||
// Farbwechsel und erneutes Aktivieren: keine neue Zeile
|
||||
@@ -354,17 +359,19 @@ test('Historie: Kunde, Aus, An durch Mitarbeiter in zeitlicher Folge; Portal-Dok
|
||||
// Marker zurücksetzen beim Wiedereinschalten
|
||||
await updateDocument(config.collections.portalFeatures, d1.$id, { removalTicketId: 'r1', publishTicketId: 'u1' })
|
||||
await an.deactivateAnalyse({ customerId: 'c1', projectId: 'p14', now: NOW, actor })
|
||||
const { doc: d3 } = await an.activateAnalyse({ customerId: 'c1', projectId: 'p14', consent: consent(), by: 'Kenso', textform, now: NOW })
|
||||
const { doc: d3 } = await an.activateAnalyse({ customerId: 'c1', projectId: 'p14', consent: consent(), by: 'Kenso', textform, audienceConfirmed: true, now: NOW })
|
||||
assert.equal(d3.privacyTicketId && d3.privacyTicketId !== d1.privacyTicketId, true, 'neues Datenschutz-Ticket')
|
||||
assert.equal(d3.removalTicketId, '')
|
||||
assert.equal(d3.publishTicketId, '')
|
||||
h = await consents('p14')
|
||||
assert.deepEqual(h.map((x) => x.event), ['on', 'off', 'on'])
|
||||
assert.deepEqual(h.map((x) => x.via), ['portal', 'portal', 'woms'])
|
||||
assert.equal(h[1].acceptedBy, 'Kunde Eins')
|
||||
assert.equal(h[1].acceptedBy, 'Kunde Eins <eins@example.invalid>')
|
||||
assert.equal(h[2].acceptedBy, 'Kenso')
|
||||
assert.equal(h[2].textformDate, '2026-10-02')
|
||||
assert.equal(h[2].textformChannel, 'email')
|
||||
assert.equal(h[2].audienceConfirmed, true)
|
||||
assert.equal(d3.audienceConfirmed, true)
|
||||
assert.equal(d3.avvConsentDate, '2026-10-02')
|
||||
assert.equal(d3.avvAcceptedBy, 'Kenso')
|
||||
})
|
||||
@@ -382,7 +389,8 @@ test('recordConsent scheitert: putSite wird zurückgenommen, Dokument bleibt aus
|
||||
assert.equal(puts.length, 2)
|
||||
assert.equal(puts[0].active, true)
|
||||
assert.equal(puts[1].active, false)
|
||||
assert.equal((await doc('c1', 'p15')).state, 'off')
|
||||
assert.equal((await doc('c1', 'p15')).state, 'off', 'Dokument zurückgesetzt')
|
||||
assert.equal((await doc('c1', 'p15')).offSince, '')
|
||||
assert.equal(analyseTickets().filter((t) => t.details.includes('Rollback')).length, 0)
|
||||
})
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import { useTestEnv } from './support/testEnv.js'
|
||||
import { schemaKeys } from './support/schema.js'
|
||||
import { mailSink } from './support/mailSink.js'
|
||||
|
||||
const ANALYSE_KEYS = ['accentColor', 'avvVersion', 'avvAcceptedAt', 'avvAcceptedBy', 'activatedAt', 'offSince', 'privacyTicketId', 'activatedMailAt', 'avvConsentDate', 'avvConsentChannel', 'removalTicketId', 'publishTicketId']
|
||||
const CONSENT_KEYS = ['customerId', 'projectId', 'siteKey', 'event', 'avvVersion', 'via', 'acceptedAt', 'acceptedBy', 'textformDate', 'textformChannel']
|
||||
const ANALYSE_KEYS = ['accentColor', 'avvVersion', 'avvAcceptedAt', 'avvAcceptedBy', 'activatedAt', 'offSince', 'privacyTicketId', 'activatedMailAt', 'avvConsentDate', 'avvConsentChannel', 'removalTicketId', 'publishTicketId', 'audienceConfirmed', 'audienceTextVersion']
|
||||
const CONSENT_KEYS = ['customerId', 'projectId', 'siteKey', 'event', 'avvVersion', 'via', 'acceptedAt', 'acceptedBy', 'textformDate', 'textformChannel', 'audienceConfirmed', 'audienceTextVersion']
|
||||
const aw = await startAppwriteMock({
|
||||
schema: { portalFeatures: [...schemaKeys('portalFeatures'), ...ANALYSE_KEYS], subscriptions: schemaKeys('subscriptions'), analyseConsents: CONSENT_KEYS },
|
||||
})
|
||||
@@ -221,6 +221,9 @@ test('Admin: 401, 400, 200', async () => {
|
||||
assert.equal(h.length, 1)
|
||||
assert.equal(h[0].via, 'woms')
|
||||
assert.equal(h[0].acceptedBy, 'kenso@webklar.com')
|
||||
assert.equal(h[0].audienceConfirmed, true)
|
||||
assert.equal(h[0].audienceTextVersion, config.analyse.avvVersion)
|
||||
assert.equal(d.audienceConfirmed, true)
|
||||
assert.equal(h[0].textformDate, todayBerlin())
|
||||
assert.equal(h[0].textformChannel, 'chat')
|
||||
const off = await adminPost('p6', { on: false })
|
||||
@@ -316,8 +319,18 @@ test('Kunden-Aktivierung schreibt Historie mit Sitzungsnamen; fehlende Angaben:
|
||||
await post(`${A}/activate`, { projectId: 'p3', consent: consent() }, { cookie })
|
||||
const h = consentsOf('p3')
|
||||
assert.equal(h.length, before + 1)
|
||||
assert.equal(h.at(-1).acceptedBy, 'Kunde Eins')
|
||||
assert.equal(h.at(-1).acceptedBy, 'Kunde Eins <k@example.invalid>')
|
||||
assert.equal(h.at(-1).audienceConfirmed, true)
|
||||
assert.equal(h.at(-1).via, 'portal')
|
||||
const admin = (await rawGet('/api/admin/analyse/p9', { headers: { Authorization: 'Bearer jwt-admin' } })).body
|
||||
assert.deepEqual(admin.privacy, { ok: false, missing: ['firma', 'email'] })
|
||||
})
|
||||
|
||||
test('Admin-Sitzung (Impersonation): handelnde Person ist der Admin, nicht der Kunde', async () => {
|
||||
aw.seed('websiteProjects', { $id: 'p20', customerId: 'c1', projectName: 'Imp', subdomain: 'imp', isPublic: true })
|
||||
const c = sessionCookie({ customerId: 'c1', appwriteUserId: 'u1', name: 'Kunde Eins', email: 'k@example.invalid', adminName: 'Kenso', adminEmail: 'kenso@webklar.com' })
|
||||
assert.equal((await post(`${A}/activate`, { projectId: 'p20', consent: consent() }, { cookie: c })).status, 200)
|
||||
const h = consentsOf('p20')
|
||||
assert.equal(h[0].acceptedBy, 'Kenso <kenso@webklar.com>')
|
||||
assert.equal((await featureDoc('c1', 'p20')).avvAcceptedBy, 'Kenso <kenso@webklar.com>')
|
||||
})
|
||||
+13
-10
@@ -30,8 +30,8 @@ function mockClient({ attrs = [], consentsExist = false, consentAttrs = [], inde
|
||||
}
|
||||
}
|
||||
|
||||
test('Schema: 12 Attribute mit Groessen, alle optional', () => {
|
||||
const sizes = Object.fromEntries(ANALYSE_ATTRIBUTES.map((a) => [a.key, a.size]))
|
||||
test('Schema: 14 Attribute mit Groessen, alle optional', () => {
|
||||
const sizes = Object.fromEntries(ANALYSE_ATTRIBUTES.filter((a) => a.type === 'string').map((a) => [a.key, a.size]))
|
||||
assert.deepEqual(sizes, {
|
||||
accentColor: 7,
|
||||
avvVersion: 20,
|
||||
@@ -45,30 +45,33 @@ test('Schema: 12 Attribute mit Groessen, alle optional', () => {
|
||||
avvConsentChannel: 10,
|
||||
removalTicketId: 40,
|
||||
publishTicketId: 40,
|
||||
audienceTextVersion: 20,
|
||||
})
|
||||
assert.equal(ANALYSE_ATTRIBUTES.length, 12)
|
||||
assert.ok(ANALYSE_ATTRIBUTES.every((a) => a.required === false && a.type === 'string'))
|
||||
assert.equal(ANALYSE_ATTRIBUTES.length, 14)
|
||||
assert.equal(ANALYSE_ATTRIBUTES.find((a) => a.key === 'audienceConfirmed').type, 'boolean')
|
||||
assert.ok(ANALYSE_ATTRIBUTES.every((a) => a.required === false))
|
||||
})
|
||||
|
||||
test('Schema: Historien-Collection analyseConsents', () => {
|
||||
assert.equal(config.collections.analyseConsents, 'analyseConsents')
|
||||
const sizes = Object.fromEntries(CONSENT_ATTRIBUTES.map((a) => [a.key, a.size]))
|
||||
const sizes = Object.fromEntries(CONSENT_ATTRIBUTES.filter((a) => a.type === 'string').map((a) => [a.key, a.size]))
|
||||
assert.deepEqual(sizes, {
|
||||
customerId: 36, projectId: 36, siteKey: 40, event: 8, avvVersion: 20, via: 8,
|
||||
acceptedAt: 40, acceptedBy: 100, textformDate: 10, textformChannel: 10,
|
||||
acceptedAt: 40, acceptedBy: 100, textformDate: 10, textformChannel: 10, audienceTextVersion: 20,
|
||||
})
|
||||
assert.equal(CONSENT_ATTRIBUTES.find((a) => a.key === 'audienceConfirmed').type, 'boolean')
|
||||
assert.deepEqual(CONSENT_INDEXES.map((i) => i.attributes), [['projectId']])
|
||||
})
|
||||
|
||||
test('main legt nur fehlende Attribute an und die fehlende Collection samt Index', async () => {
|
||||
const client = mockClient({ attrs: ['accentColor'] })
|
||||
const result = await main({ client, log: () => {} })
|
||||
assert.equal(client.calls.attrs.filter((k) => k.startsWith('portalFeatures.')).length, 11)
|
||||
assert.equal(client.calls.attrs.filter((k) => k.startsWith('portalFeatures.')).length, 13)
|
||||
assert.ok(!client.calls.attrs.includes('portalFeatures.accentColor'))
|
||||
assert.equal(client.calls.attrs.filter((k) => k.startsWith('analyseConsents.')).length, 10)
|
||||
assert.equal(client.calls.attrs.filter((k) => k.startsWith('analyseConsents.')).length, 12)
|
||||
assert.deepEqual(client.calls.collections, [{ id: 'analyseConsents', name: 'analyseConsents' }])
|
||||
assert.deepEqual(client.calls.indexes, ['analyseConsents.projectId_idx'])
|
||||
assert.equal(result.missing.length, 21)
|
||||
assert.equal(result.missing.length, 25)
|
||||
})
|
||||
|
||||
test('main ueberspringt vorhandene Collection, Attribute und Index', async () => {
|
||||
@@ -87,7 +90,7 @@ test('main --check legt nichts an und meldet missing', async () => {
|
||||
const client = mockClient({ attrs: ['accentColor'] })
|
||||
const result = await main({ check: true, client, log: () => {} })
|
||||
assert.deepEqual(client.calls, { attrs: [], collections: [], indexes: [] })
|
||||
assert.equal(result.missing.length, 21)
|
||||
assert.equal(result.missing.length, 25)
|
||||
assert.equal(result.missingCollection, true)
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user