|
| 1 | +import { NextRequest, NextResponse } from 'next/server'; |
| 2 | +import { getDb } from '@/lib/db'; |
| 3 | + |
| 4 | +const SECRET = process.env.CRAWLPROOF_WEBHOOK_SECRET!; |
| 5 | + |
| 6 | +function verify(req: NextRequest): boolean { |
| 7 | + const auth = req.headers.get('authorization') ?? ''; |
| 8 | + const token = auth.startsWith('Bearer ') ? auth.slice(7) : auth; |
| 9 | + return token === SECRET; |
| 10 | +} |
| 11 | + |
| 12 | +export async function POST(req: NextRequest) { |
| 13 | + if (!verify(req)) { |
| 14 | + console.error('CrawlProof webhook: unauthorized'); |
| 15 | + return NextResponse.json({ error: 'unauthorized' }, { status: 401 }); |
| 16 | + } |
| 17 | + |
| 18 | + const payload = await req.json(); |
| 19 | + const { type, data } = payload; |
| 20 | + |
| 21 | + console.log('CrawlProof webhook:', type); |
| 22 | + |
| 23 | + const db = getDb(); |
| 24 | + |
| 25 | + if (type === 'blog.publish' || type === 'blog.update') { |
| 26 | + const { slug, title, excerpt = null, content = '', cover_image = null, author = null, published_at = null } = data; |
| 27 | + |
| 28 | + if (!slug || !title) { |
| 29 | + return NextResponse.json({ error: 'slug and title are required' }, { status: 400 }); |
| 30 | + } |
| 31 | + |
| 32 | + await db.sql` |
| 33 | + INSERT INTO blog_posts (slug, title, excerpt, content, cover_image, author, published_at, updated_at, status) |
| 34 | + VALUES ( |
| 35 | + ${slug}, ${title}, ${excerpt}, ${content}, ${cover_image}, ${author}, |
| 36 | + ${published_at ?? new Date().toISOString()}, |
| 37 | + ${new Date().toISOString()}, |
| 38 | + 'published' |
| 39 | + ) |
| 40 | + ON CONFLICT(slug) DO UPDATE SET |
| 41 | + title = excluded.title, |
| 42 | + excerpt = excluded.excerpt, |
| 43 | + content = excluded.content, |
| 44 | + cover_image = excluded.cover_image, |
| 45 | + author = excluded.author, |
| 46 | + updated_at = excluded.updated_at, |
| 47 | + status = 'published' |
| 48 | + `; |
| 49 | + |
| 50 | + return NextResponse.json({ received: true, slug }); |
| 51 | + } |
| 52 | + |
| 53 | + if (type === 'blog.delete') { |
| 54 | + const { slug } = data; |
| 55 | + if (!slug) return NextResponse.json({ error: 'slug required' }, { status: 400 }); |
| 56 | + await db.sql`DELETE FROM blog_posts WHERE slug = ${slug}`; |
| 57 | + return NextResponse.json({ received: true, deleted: slug }); |
| 58 | + } |
| 59 | + |
| 60 | + if (type === 'blog.unpublish') { |
| 61 | + const { slug } = data; |
| 62 | + if (!slug) return NextResponse.json({ error: 'slug required' }, { status: 400 }); |
| 63 | + await db.sql`UPDATE blog_posts SET status = 'draft', updated_at = ${new Date().toISOString()} WHERE slug = ${slug}`; |
| 64 | + return NextResponse.json({ received: true, slug }); |
| 65 | + } |
| 66 | + |
| 67 | + return NextResponse.json({ received: true, type }); |
| 68 | +} |
0 commit comments