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 (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) })