News: Beiträge – Titel optional, Datumsprüfung, Bildregeln

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5.5 committed 2026-09-30 16:45:42 +00:00
1 parent 434bab0b7a
commit d320730251
2 files changed
+40 -6

No files matched your search

+16 -6
View File
@@ -42,7 +42,8 @@ export function visibleUntilFor(duration, from, dateIso, now = from) {
case '3m': return addMonths(from, 3)
case 'open': return null
case 'date': {
if (typeof dateIso !== 'string' || !DATE_RE.test(dateIso) || Number.isNaN(Date.parse(dateIso))) {
if (typeof dateIso !== 'string' || !DATE_RE.test(dateIso) || Number.isNaN(Date.parse(dateIso))
|| new Date(`${dateIso}T00:00:00Z`).toISOString().slice(0, 10) !== dateIso) {
throw httpError(400, 'Bitte wähle ein gültiges Datum.', 'date')
}
const today = berlinDay(now)
@@ -69,8 +70,8 @@ export function validatePostInput(input) {
const str = (v) => (typeof v === 'string' ? v.trim() : '')
const type = src.type
if (!TYPES.includes(type)) throw httpError(400, 'Bitte wähle eine Art von Beitrag.', 'type')
// Der Titel ist optional (leer gespeichert)
const title = str(src.title)
if (!title) throw httpError(400, 'Bitte gib einen Titel ein.', 'title')
if (title.length > TITLE_MAX) throw httpError(400, `Der Titel darf höchstens ${TITLE_MAX} Zeichen lang sein.`, 'title')
const text = str(src.text)
if (text.length > TEXT_MAX) throw httpError(400, `Der Text darf höchstens ${TEXT_MAX} Zeichen lang sein.`, 'text')
@@ -111,7 +112,10 @@ async function requireImage(projectId, imageId) {
export async function createPost({ customerId, projectId, input, now = new Date() }) {
const v = validatePostInput(input)
const until = visibleUntilFor(v.duration, now, v.date, now)
if (v.imageId) await requireImage(projectId, v.imageId)
if (v.imageId) {
await requireImage(projectId, v.imageId)
await claimNewsImage(projectId, v.imageId)
}
const iso = now.toISOString()
const doc = await createDocument(config.collections.newsPosts, {
customerId, projectId,
@@ -121,7 +125,6 @@ export async function createPost({ customerId, projectId, input, now = new Date(
visibleFrom: iso, visibleUntil: until ? until.toISOString() : null,
takenDownAt: null, createdAt: iso, updatedAt: iso,
})
if (v.imageId) await claimNewsImage(projectId, v.imageId)
return doc
}
@@ -153,9 +156,16 @@ export async function updatePost({ customerId, projectId, id, input, now = new D
const v = validatePostInput(input)
// Relative Dauern zaehlen ab dem urspruenglichen Beginn, damit ein Bearbeiten nichts verlaengert
const from = new Date(post.visibleFrom)
const until = visibleUntilFor(v.duration, from, v.date, now)
// Unverändertes Datum bleibt speicherbar, auch wenn es inzwischen unter "morgen" liegt
const sameDate = v.duration === 'date' && post.duration === 'date' && DATE_RE.test(v.date || '')
&& post.visibleUntil === berlinTime(v.date, 23, 59, 59, 999).toISOString()
const until = sameDate ? new Date(post.visibleUntil) : visibleUntilFor(v.duration, from, v.date, now)
const imageId = v.imageId || null
if (imageId && imageId !== post.imageId) await requireImage(projectId, imageId)
if (imageId && imageId !== post.imageId) {
await requireImage(projectId, imageId)
const used = (await projectPosts(projectId)).some((p) => p.$id !== id && p.imageId === imageId)
if (used) throw httpError(400, 'Dieses Foto gehört schon zu einem anderen Beitrag.', 'imageId')
}
patch = {
type: v.type, title: v.title, text: v.text, paper: v.paper, duration: v.duration,
visibleUntil: until ? until.toISOString() : null, imageId,