Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die README; an keiner Stelle Bedeutung, nur Zeichensetzung.
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
/**
|
|
* Schwärzung im Freitext.
|
|
*
|
|
* Im Editor markiert man einen Bereich und wählt eine Stufe. Gespeichert wird
|
|
* als Auszeichnung:
|
|
*
|
|
* Der Hinweis kam von [[c4]]Wachmann Perreira, Sektor B[[/c4]] am 27.08.
|
|
*
|
|
* Der Server ersetzt den Inhalt für niedrigere Stufen. **Der echte Wert
|
|
* verlässt den Server nicht** - deshalb gibt diese Datei Segmente zurück und
|
|
* nicht etwa den vollen Text mit einem Sichtbarkeits-Flag. Was der Client
|
|
* ausblenden müsste, hat er schon.
|
|
*
|
|
* Die Länge wird auf ein festes Raster gerundet. Ein Balken exakter Länge
|
|
* verriete sonst, wie lang der Name war, und bei kurzen Einschüben ist das
|
|
* genug, um zu raten. Siehe docs/05-akten-und-vorlagen.md.
|
|
*/
|
|
|
|
/** Auf dieses Vielfache wird die Länge eines Balkens gerundet. */
|
|
const LENGTH_GRID = 8
|
|
|
|
const MARKUP = /\[\[c([0-5])\]\]([\s\S]*?)\[\[\/c\1\]\]/g
|
|
|
|
export type Segment =
|
|
| { kind: 'text'; text: string }
|
|
| { kind: 'redacted'; requiredLevel: number; blockLength: number }
|
|
|
|
/** Auf das Raster gerundete Länge, mindestens ein Block. */
|
|
export function barLength(rawLength: number): number {
|
|
return Math.max(LENGTH_GRID, Math.ceil(rawLength / LENGTH_GRID) * LENGTH_GRID)
|
|
}
|
|
|
|
/**
|
|
* Zerlegt einen Text in Segmente und wendet dabei die Stufe des Lesers an.
|
|
* Bereiche über seiner Stufe kommen ohne ihren Inhalt zurück.
|
|
*/
|
|
export function redactForLevel(source: string, viewerLevel: number): Segment[] {
|
|
const segments: Segment[] = []
|
|
let cursor = 0
|
|
|
|
MARKUP.lastIndex = 0
|
|
let match: RegExpExecArray | null
|
|
while ((match = MARKUP.exec(source)) !== null) {
|
|
if (match.index > cursor) {
|
|
segments.push({ kind: 'text', text: source.slice(cursor, match.index) })
|
|
}
|
|
|
|
const requiredLevel = Number(match[1])
|
|
const content = match[2] ?? ''
|
|
|
|
if (viewerLevel >= requiredLevel) {
|
|
segments.push({ kind: 'text', text: content })
|
|
} else {
|
|
segments.push({
|
|
kind: 'redacted',
|
|
requiredLevel,
|
|
blockLength: barLength(content.length),
|
|
})
|
|
}
|
|
|
|
cursor = match.index + match[0].length
|
|
}
|
|
|
|
if (cursor < source.length) {
|
|
segments.push({ kind: 'text', text: source.slice(cursor) })
|
|
}
|
|
|
|
return segments
|
|
}
|
|
|
|
/**
|
|
* Die höchste Stufe, die in einem Text ausgezeichnet ist. Damit lässt sich an
|
|
* einem Eintrag anzeigen, dass er geschwärzte Stellen enthält, ohne den Text
|
|
* zu übertragen.
|
|
*/
|
|
export function highestRedactionLevel(source: string): number {
|
|
let highest = 0
|
|
MARKUP.lastIndex = 0
|
|
let match: RegExpExecArray | null
|
|
while ((match = MARKUP.exec(source)) !== null) {
|
|
highest = Math.max(highest, Number(match[1]))
|
|
}
|
|
return highest
|
|
}
|
|
|
|
/**
|
|
* Entfernt die Auszeichnung, behält den Inhalt. Für Leser, die alles sehen
|
|
* dürfen, und für den Volltextindex hoher Stufen.
|
|
*/
|
|
export function stripMarkup(source: string): string {
|
|
return source.replace(MARKUP, (_full, _level, content: string) => content)
|
|
}
|
|
|
|
/**
|
|
* Entfernt ausgezeichnete Bereiche samt Inhalt. Genau das tut auch die
|
|
* Funktion `strip_redactions` in der Migration, bevor der Suchvektor gefüllt
|
|
* wird - beide müssen dasselbe Ergebnis liefern.
|
|
*/
|
|
export function stripRedacted(source: string): string {
|
|
return source.replace(MARKUP, ' ')
|
|
}
|
|
|
|
/** Fügt eine Auszeichnung um einen markierten Bereich ein. */
|
|
export function markRedaction(source: string, start: number, end: number, level: number): string {
|
|
if (start >= end || level < 0 || level > 5) return source
|
|
return (
|
|
source.slice(0, start) +
|
|
`[[c${level}]]` +
|
|
source.slice(start, end) +
|
|
`[[/c${level}]]` +
|
|
source.slice(end)
|
|
)
|
|
}
|