Files
bmp-website-2026/src/scripts/preload-netzwerk-page-cms.ts
2026-07-31 16:41:02 +02:00

188 lines
5.4 KiB
TypeScript

import 'dotenv/config'
import config from '@payload-config'
import crypto from 'crypto'
import { getPayload, type Payload } from 'payload'
import { mediaByFilename } from './mediaByFilename'
import { netzwerkContent } from '@/spa/netzwerkContent'
const safeRemoteName = (url: string) => {
const parsed = new URL(url)
const ext = parsed.pathname.split('/').pop()?.includes('.') ? `.${parsed.pathname.split('.').pop()}` : '.jpg'
const hash = crypto.createHash('sha1').update(url).digest('hex').slice(0, 10)
return `${parsed.hostname.replace(/[^a-z0-9]+/gi, '-')}-${hash}${ext}`.toLowerCase()
}
const filenameForSource = (source: string) => {
if (source.startsWith('http')) return safeRemoteName(source)
return source.split('?')[0]?.split('/').filter(Boolean).pop()
}
const itemsWithImageUploads = async <T extends { image?: string }>(payload: Payload, items: T[]) =>
Promise.all(
items.map(async (item) => {
const filename = item.image ? filenameForSource(item.image) : undefined
return {
...item,
imageUpload: filename ? await mediaByFilename(payload, filename) : undefined,
}
}),
)
const partnersForPayload = netzwerkContent.partners.items.map(({ id, ...partner }, index) => ({
...partner,
stableId: id,
active: true,
showOnHomepage: true,
sortOrder: index,
_status: 'published' as const,
}))
async function upsertPartners(payload: Payload) {
await Promise.all(
partnersForPayload.map(async (partner) => {
const existing = await payload.find({
collection: 'partners',
limit: 1,
pagination: false,
draft: true,
overrideAccess: true,
where: {
stableId: { equals: partner.stableId },
},
})
const doc = existing.docs[0]
if (doc) {
await payload.update({
collection: 'partners',
id: doc.id,
overrideAccess: true,
context: { disableRevalidate: true },
data: partner as never,
})
return
}
await payload.create({
collection: 'partners',
overrideAccess: true,
context: { disableRevalidate: true },
data: partner as never,
})
}),
)
}
async function juryMembersForPage(payload: Payload) {
const existing = await payload.find({
collection: 'jury-mitglieder',
limit: 300,
pagination: false,
draft: true,
overrideAccess: true,
sort: 'sortOrder',
})
if (existing.docs.length) {
return existing.docs.filter((member) => member.active !== false).map((member) => member.id)
}
const membersWithUploads = await itemsWithImageUploads(payload, netzwerkContent.jury.members)
const created = await Promise.all(
membersWithUploads.map((member, index) =>
payload.create({
collection: 'jury-mitglieder',
overrideAccess: true,
context: { disableRevalidate: true },
data: {
name: member.name,
image: member.imageUpload,
imageAlt: member.name,
role: member.role,
bio: member.bio,
sortOrder: index,
active: true,
_status: 'published',
},
}),
),
)
return created.map((member) => member.id)
}
async function main() {
const payload = await getPayload({ config })
const pageResult = await payload.find({
collection: 'pages',
limit: 1,
pagination: false,
draft: true,
overrideAccess: true,
where: {
or: [{ spaPath: { equals: '/netzwerk' } }, { slug: { equals: 'netzwerk' } }, { slug: { equals: 'network' } }],
},
})
const page = pageResult.docs[0]
if (!page) throw new Error('Netzwerk page not found. Expected spaPath=/netzwerk or slug=netzwerk/network.')
const heroImage = await mediaByFilename(payload, netzwerkContent.hero.imageFilename)
const sponsoringImage = await mediaByFilename(payload, netzwerkContent.sponsoring.imageFilename)
const { imageFilename: _heroFilename, ...heroContent } = netzwerkContent.hero
const { imageFilename: _sponsoringFilename, ...sponsoringContent } = netzwerkContent.sponsoring
const { items: _partnerItems, tiers: partnerTiers, ...partnerSectionContent } = netzwerkContent.partners
const existingGreetingVideo = page.netzwerk?.patronage?.greetingVideo || null
const [patronPeople, juryMembers] = await Promise.all([
itemsWithImageUploads(payload, netzwerkContent.patronage.people),
juryMembersForPage(payload),
])
await payload.update({
collection: 'pages',
id: page.id,
overrideAccess: true,
context: { disableRevalidate: true },
data: {
netzwerk: {
...netzwerkContent,
hero: {
...heroContent,
image: heroImage,
},
patronage: {
...netzwerkContent.patronage,
greetingVideo: existingGreetingVideo,
people: patronPeople,
},
jury: {
...netzwerkContent.jury,
members: juryMembers,
},
sponsoring: {
...sponsoringContent,
image: sponsoringImage,
},
partners: {
...partnerSectionContent,
tiers: partnerTiers.map(({ tier, label, note }) => ({ tier, label, note })),
},
},
} as never,
})
await upsertPartners(payload)
payload.logger.info(`Preloaded Netzwerk CMS fields for page ${page.id}`)
process.exit(0)
}
main().catch((error) => {
console.error(error)
process.exit(1)
})