feat: add JSON import functionality for content creation in the admin dashboard
This commit is contained in:
13
admin/src/app/actualites/import/page.tsx
Normal file
13
admin/src/app/actualites/import/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import ImportJsonForm from '@/components/ImportJsonForm';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Import JSON - CMS Afrohub',
|
||||
};
|
||||
|
||||
export default function ImportJsonPage() {
|
||||
return (
|
||||
<div className="py-8">
|
||||
<ImportJsonForm />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import DeleteActualitesButton from '@/components/DeleteActualitesButton';
|
||||
import DeleteInterviewButton from '@/components/DeleteInterviewButton';
|
||||
import DeleteEventButton from '@/components/DeleteEventButton';
|
||||
import ApproveContentButton from '@/components/ApproveContentButton';
|
||||
import { FileJson } from 'lucide-react';
|
||||
|
||||
async function getData() {
|
||||
const posts = await prisma.blogPost.findMany({ orderBy: { createdAt: 'desc' } });
|
||||
@@ -50,6 +51,7 @@ export default async function ActualitesCMSPage() {
|
||||
<Plus className="w-4 h-4" />
|
||||
Nouvel Événement
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
64
admin/src/app/api/external/articles/route.ts
vendored
Normal file
64
admin/src/app/api/external/articles/route.ts
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { generateSlug } from '@/lib/utils'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Simple API Key authentication
|
||||
const apiKey = request.headers.get('x-api-key')
|
||||
const expectedApiKey = process.env.EXTERNAL_API_KEY
|
||||
|
||||
if (!expectedApiKey) {
|
||||
console.error('EXTERNAL_API_KEY is not defined in environment variables.')
|
||||
return NextResponse.json({ error: 'Server configuration error' }, { status: 500 })
|
||||
}
|
||||
|
||||
if (apiKey !== expectedApiKey) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const body = await request.json()
|
||||
|
||||
// Validation
|
||||
const { title, excerpt, content, author, imageUrl, type, tags, status, publishedAt } = body
|
||||
|
||||
if (!title || !excerpt || !content || !author || !imageUrl) {
|
||||
return NextResponse.json({
|
||||
error: 'Missing required fields: title, excerpt, content, author, imageUrl'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
const rawSlug = generateSlug(title)
|
||||
const slug = `${rawSlug}-${Math.random().toString(36).substring(2, 7)}`
|
||||
|
||||
// Si un "type" est fourni, on l'ajoute automatiquement aux tags pour le catégoriser
|
||||
const finalTags = tags || []
|
||||
if (type && typeof type === 'string' && !finalTags.includes(type)) {
|
||||
finalTags.push(type)
|
||||
}
|
||||
|
||||
const post = await prisma.blogPost.create({
|
||||
data: {
|
||||
title,
|
||||
excerpt,
|
||||
content,
|
||||
author,
|
||||
imageUrl,
|
||||
slug,
|
||||
tags: finalTags,
|
||||
status: status || 'PUBLISHED',
|
||||
publishedAt: publishedAt ? new Date(publishedAt) : new Date(Date.now() - 60000), // -1 min to ensure visibility
|
||||
date: new Date()
|
||||
}
|
||||
})
|
||||
|
||||
revalidatePath('/actualites')
|
||||
revalidatePath('/')
|
||||
|
||||
return NextResponse.json({ success: true, post }, { status: 201 })
|
||||
} catch (error) {
|
||||
console.error('POST /api/external/articles error:', error)
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
58
admin/src/app/api/external/events/route.ts
vendored
Normal file
58
admin/src/app/api/external/events/route.ts
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { generateSlug } from '@/lib/utils'
|
||||
import { revalidatePath } from 'next/cache'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Simple API Key authentication
|
||||
const apiKey = request.headers.get('x-api-key')
|
||||
const expectedApiKey = process.env.EXTERNAL_API_KEY
|
||||
|
||||
if (!expectedApiKey) {
|
||||
console.error('EXTERNAL_API_KEY is not defined in environment variables.')
|
||||
return NextResponse.json({ error: 'Server configuration error' }, { status: 500 })
|
||||
}
|
||||
|
||||
if (apiKey !== expectedApiKey) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const body = await request.json()
|
||||
|
||||
// Validation
|
||||
const { title, description, date, location, thumbnailUrl, link, tags, status, publishedAt } = body
|
||||
|
||||
if (!title || !description || !date || !location || !thumbnailUrl) {
|
||||
return NextResponse.json({
|
||||
error: 'Missing required fields: title, description, date, location, thumbnailUrl'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
const rawSlug = generateSlug(title)
|
||||
const slug = `${rawSlug}-${Math.random().toString(36).substring(2, 7)}`
|
||||
|
||||
const event = await prisma.event.create({
|
||||
data: {
|
||||
title,
|
||||
description,
|
||||
date: new Date(date),
|
||||
location,
|
||||
thumbnailUrl,
|
||||
link,
|
||||
slug,
|
||||
tags: tags || [],
|
||||
status: status || 'PUBLISHED',
|
||||
publishedAt: publishedAt ? new Date(publishedAt) : new Date()
|
||||
}
|
||||
})
|
||||
|
||||
revalidatePath('/evenements')
|
||||
revalidatePath('/')
|
||||
|
||||
return NextResponse.json({ success: true, event }, { status: 201 })
|
||||
} catch (error) {
|
||||
console.error('POST /api/external/events error:', error)
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user