Shop Review B I-6, I-7: Archiv der bestaetigten Rechtstexte, G09 ohne Link-Ersatz
I-6: Neue Collection shopRechtstexteArchiv (ID r + 35 Hex aus sha256(shopId + hash)); das Bestaetigen legt die Fassung samt Versand-/Zahlungstext und Gewaehrleistungstext ab, G09 zeigt die Fassung zum rechtstexteHash der Bestellung (Rueckfall mit Warnung auf die aktuell bestaetigte), loescheShopDaten loescht das Archiv mit. I-7: Grenzen AGB 20000, Belehrung 12000, Formular 3000 plus Pruefung der maskierten Laenge beim Speichern; G09 ersetzt die AGB nie mehr durch einen Link, sondern scheitert (Marker bleibt offen, wird wiederholt). Test mit Texten in Hoechstlaenge gegen die Grenzen der Warteschlange. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2f4f360a21
commit
08d837d690
17 files changed
+288
-65
No files matched your search
@@ -0,0 +1,60 @@
|
||||
import { createHash } from 'node:crypto'
|
||||
import { config } from '../../config.js'
|
||||
import { createDocument, getDocument } from '../appwriteAdmin.js'
|
||||
|
||||
/**
|
||||
* Archiv der bestaetigten Rechtstexte eines Shops (Review B, I-6). Beim Bestaetigen wird die Fassung samt Hash abgelegt; G09 zeigt dem
|
||||
* Kaeufer die Fassung zum Hash seiner Bestellung (bestellung.rechtstexteHash), nicht die beim Mailversand aktuelle. So passen Mail und
|
||||
* Bestellung zusammen, und der Haendler kann spaeter belegen, welche Belehrung ein Kaeufer bekam (§ 356 Abs. 3 BGB).
|
||||
* Eine Fassung je Dokument, ID = 'r' + die ersten 35 Hex-Zeichen von sha256(shopId + hash); dieselbe Fassung ein zweites Mal
|
||||
* (409) ist kein Fehler. Inhalt (texte, JSON): agb, widerrufsbelehrung, widerrufsformular, impressumUrl, datenschutzUrl,
|
||||
* versandUndZahlung, gewaehrleistung.
|
||||
*/
|
||||
|
||||
const col = () => config.collections.shopRechtstexteArchiv
|
||||
|
||||
/** Dokument-ID der Fassung (hoechstens 36 Zeichen, nur Hex nach dem 'r'). */
|
||||
export const archivId = (shopId, hash) => `r${createHash('sha256').update(`${String(shopId)}${String(hash)}`).digest('hex').slice(0, 35)}`
|
||||
|
||||
/**
|
||||
* Legt die Fassung an, falls es sie noch nicht gibt.
|
||||
* @param {{ shopId: string, customerId: string, hash: string, texte: object, at: string, von: string }} p
|
||||
* @returns {Promise<{ angelegt: boolean }>}
|
||||
*/
|
||||
export async function archiviereRechtstexte({ shopId, customerId, hash, texte, at, von }) {
|
||||
if (typeof shopId !== 'string' || shopId === '' || typeof hash !== 'string' || !/^[0-9a-f]{64}$/.test(hash)) throw new TypeError('archiviereRechtstexte: shopId oder hash fehlt')
|
||||
try {
|
||||
await createDocument(
|
||||
col(),
|
||||
{ shopId, customerId: String(customerId ?? ''), hash, texte: JSON.stringify(texte), bestaetigtAt: at, bestaetigtVon: String(von ?? '').slice(0, 255) },
|
||||
archivId(shopId, hash),
|
||||
)
|
||||
return { angelegt: true }
|
||||
} catch (err) {
|
||||
if (err?.status === 409) return { angelegt: false }
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Die archivierte Fassung zum Hash oder null, wenn es sie nicht gibt (zum Beispiel bei Bestellungen vor der Einfuehrung des Archivs).
|
||||
* Andere Fehler (Datenbank) werfen, damit G09 nicht mit falschen Texten rausgeht, sondern wiederholt wird.
|
||||
* @returns {Promise<object|null>}
|
||||
*/
|
||||
export async function holeArchivierteRechtstexte(shopId, hash) {
|
||||
if (typeof shopId !== 'string' || shopId === '' || typeof hash !== 'string' || hash === '') return null
|
||||
let doc
|
||||
try {
|
||||
doc = await getDocument(col(), archivId(shopId, hash))
|
||||
} catch (err) {
|
||||
if (err?.status === 404) return null
|
||||
throw err
|
||||
}
|
||||
if (doc?.shopId !== shopId || doc?.hash !== hash) return null
|
||||
try {
|
||||
const texte = JSON.parse(doc.texte)
|
||||
return texte !== null && typeof texte === 'object' && !Array.isArray(texte) ? texte : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user