fix(seed-forms): tighten auth guard + per-form idempotency to handle partial failures
- Fix auth bypass when SYNC_SECRET env var is unset: now defaults to empty string - Change idempotency check from totalDocs >= 2 to per-form existence checks - Allow reuse of existing forms instead of creating duplicates if one creation fails - Handles partial seed state gracefully (e.g., birthday form exists but group form missing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
65498e2da5
commit
b5c34f6f0b
1 changed files with 136 additions and 124 deletions
|
|
@ -5,142 +5,154 @@ import config from '@payload-config'
|
|||
|
||||
export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||
const secret = req.nextUrl.searchParams.get('secret')
|
||||
if (!secret || secret !== process.env['SYNC_SECRET']) {
|
||||
const SYNC_SECRET = process.env['SYNC_SECRET'] ?? ''
|
||||
if (!SYNC_SECRET || secret !== SYNC_SECRET) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
// Idempotency check
|
||||
const existing = await payload.find({
|
||||
// Check idempotency per form separately
|
||||
const existingBirthday = await payload.find({
|
||||
collection: 'forms',
|
||||
where: { title: { in: ['Дні народження', 'Групові відвідування'] } },
|
||||
limit: 2,
|
||||
where: { title: { equals: 'Дні народження' } },
|
||||
limit: 1,
|
||||
overrideAccess: true,
|
||||
})
|
||||
if (existing.totalDocs >= 2) {
|
||||
return NextResponse.json({ message: 'Forms already seeded', count: existing.totalDocs })
|
||||
const existingGroup = await payload.find({
|
||||
collection: 'forms',
|
||||
where: { title: { equals: 'Групові відвідування' } },
|
||||
limit: 1,
|
||||
overrideAccess: true,
|
||||
})
|
||||
if (existingBirthday.totalDocs >= 1 && existingGroup.totalDocs >= 1) {
|
||||
return NextResponse.json({ message: 'Forms already seeded', count: 2 })
|
||||
}
|
||||
|
||||
// ── 1. Birthday form ──────────────────────────────────────────────
|
||||
const birthdayForm = await payload.create({
|
||||
collection: 'forms',
|
||||
data: {
|
||||
title: 'Дні народження',
|
||||
fields: [
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'name',
|
||||
label: "Ваше ім'я",
|
||||
required: true,
|
||||
placeholder: 'Іван Іванов',
|
||||
},
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'phone',
|
||||
label: 'Телефон',
|
||||
required: true,
|
||||
placeholder: '+38 (0__) ___-__-__',
|
||||
},
|
||||
{
|
||||
blockType: 'email',
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
placeholder: 'your@email.com',
|
||||
},
|
||||
{
|
||||
blockType: 'number',
|
||||
name: 'childAge',
|
||||
label: 'Вік іменинника',
|
||||
placeholder: '7',
|
||||
},
|
||||
{
|
||||
blockType: 'number',
|
||||
name: 'guestCount',
|
||||
label: 'Кількість гостей',
|
||||
placeholder: '15',
|
||||
},
|
||||
{
|
||||
blockType: 'date',
|
||||
name: 'preferredDate',
|
||||
label: 'Бажана дата',
|
||||
required: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
blockType: 'textarea',
|
||||
name: 'wishes',
|
||||
label: 'Побажання',
|
||||
placeholder: 'Тема свята, улюблені герої, особливі побажання...',
|
||||
},
|
||||
],
|
||||
submitButtonLabel: 'Замовити святкування',
|
||||
confirmationType: 'message',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
const birthdayForm =
|
||||
existingBirthday.docs[0] ??
|
||||
(await payload.create({
|
||||
collection: 'forms',
|
||||
data: {
|
||||
title: 'Дні народження',
|
||||
fields: [
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'name',
|
||||
label: "Ваше ім'я",
|
||||
required: true,
|
||||
placeholder: 'Іван Іванов',
|
||||
},
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'phone',
|
||||
label: 'Телефон',
|
||||
required: true,
|
||||
placeholder: '+38 (0__) ___-__-__',
|
||||
},
|
||||
{
|
||||
blockType: 'email',
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
placeholder: 'your@email.com',
|
||||
},
|
||||
{
|
||||
blockType: 'number',
|
||||
name: 'childAge',
|
||||
label: 'Вік іменинника',
|
||||
placeholder: '7',
|
||||
},
|
||||
{
|
||||
blockType: 'number',
|
||||
name: 'guestCount',
|
||||
label: 'Кількість гостей',
|
||||
placeholder: '15',
|
||||
},
|
||||
{
|
||||
blockType: 'date',
|
||||
name: 'preferredDate',
|
||||
label: 'Бажана дата',
|
||||
required: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
blockType: 'textarea',
|
||||
name: 'wishes',
|
||||
label: 'Побажання',
|
||||
placeholder: 'Тема свята, улюблені герої, особливі побажання...',
|
||||
},
|
||||
],
|
||||
submitButtonLabel: 'Замовити святкування',
|
||||
confirmationType: 'message',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
}))
|
||||
|
||||
// ── 2. Group visits form ──────────────────────────────────────────
|
||||
const groupForm = await payload.create({
|
||||
collection: 'forms',
|
||||
data: {
|
||||
title: 'Групові відвідування',
|
||||
fields: [
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'name',
|
||||
label: "Ваше ім'я",
|
||||
required: true,
|
||||
placeholder: 'Іван Іванов',
|
||||
},
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'phone',
|
||||
label: 'Телефон',
|
||||
required: true,
|
||||
placeholder: '+38 (0__) ___-__-__',
|
||||
},
|
||||
{
|
||||
blockType: 'email',
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
placeholder: 'your@email.com',
|
||||
},
|
||||
{
|
||||
blockType: 'number',
|
||||
name: 'groupSize',
|
||||
label: 'Кількість учасників',
|
||||
required: true,
|
||||
placeholder: '30',
|
||||
},
|
||||
{
|
||||
blockType: 'date',
|
||||
name: 'preferredDate',
|
||||
label: 'Бажана дата',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
blockType: 'select',
|
||||
name: 'groupType',
|
||||
label: 'Тип групи',
|
||||
options: [
|
||||
{ label: 'Шкільна екскурсія', value: 'school' },
|
||||
{ label: 'Дитячий садок', value: 'kindergarten' },
|
||||
{ label: 'Корпоратив', value: 'corporate' },
|
||||
{ label: 'Інше', value: 'other' },
|
||||
],
|
||||
},
|
||||
{
|
||||
blockType: 'textarea',
|
||||
name: 'message',
|
||||
label: 'Повідомлення',
|
||||
placeholder: 'Додаткові побажання або запитання...',
|
||||
},
|
||||
],
|
||||
submitButtonLabel: 'Надіслати заявку',
|
||||
confirmationType: 'message',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
})
|
||||
const groupForm =
|
||||
existingGroup.docs[0] ??
|
||||
(await payload.create({
|
||||
collection: 'forms',
|
||||
data: {
|
||||
title: 'Групові відвідування',
|
||||
fields: [
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'name',
|
||||
label: "Ваше ім'я",
|
||||
required: true,
|
||||
placeholder: 'Іван Іванов',
|
||||
},
|
||||
{
|
||||
blockType: 'text',
|
||||
name: 'phone',
|
||||
label: 'Телефон',
|
||||
required: true,
|
||||
placeholder: '+38 (0__) ___-__-__',
|
||||
},
|
||||
{
|
||||
blockType: 'email',
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
placeholder: 'your@email.com',
|
||||
},
|
||||
{
|
||||
blockType: 'number',
|
||||
name: 'groupSize',
|
||||
label: 'Кількість учасників',
|
||||
required: true,
|
||||
placeholder: '30',
|
||||
},
|
||||
{
|
||||
blockType: 'date',
|
||||
name: 'preferredDate',
|
||||
label: 'Бажана дата',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
blockType: 'select',
|
||||
name: 'groupType',
|
||||
label: 'Тип групи',
|
||||
options: [
|
||||
{ label: 'Шкільна екскурсія', value: 'school' },
|
||||
{ label: 'Дитячий садок', value: 'kindergarten' },
|
||||
{ label: 'Корпоратив', value: 'corporate' },
|
||||
{ label: 'Інше', value: 'other' },
|
||||
],
|
||||
},
|
||||
{
|
||||
blockType: 'textarea',
|
||||
name: 'message',
|
||||
label: 'Повідомлення',
|
||||
placeholder: 'Додаткові побажання або запитання...',
|
||||
},
|
||||
],
|
||||
submitButtonLabel: 'Надіслати заявку',
|
||||
confirmationType: 'message',
|
||||
} as never,
|
||||
overrideAccess: true,
|
||||
}))
|
||||
|
||||
// ── 3. Link forms to globals ──────────────────────────────────────
|
||||
await payload.updateGlobal({
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue