src/app/api/admin/vitrine/sync/route.ts
Annotation non disponible
Lance npm run annotate (nécessite ANTHROPIC_API_KEY dans .env.local) pour générer une annotation française par Claude Haiku 4.5.
Concepts détectés — comprends la théorie
Route API Next.js
3 occurrencesCe fichier est une route API Next.js (App Router). Voir le contrat API complet pour les conventions de réponse et d'auth.
Voir l'article général
ORM Prisma
1 occurrenceCe fichier accède à la base de données via Prisma. Prisma est l'ORM utilisé côté backend pour les requêtes typées sur PostgreSQL.
Voir l'article général
1 export
POST
Code source· typescript
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma/client'
import { getSession } from '@/lib/auth/session'
export async function POST(req: NextRequest) {
try {
const session = await getSession()
if (!session) return NextResponse.json({ error: 'Non autorise' }, { status: 401 })
const { pages, tenantId: bodyTenantId } = await req.json()
const tenantId = (session.tenantId as string) || bodyTenantId
if (!tenantId) return NextResponse.json({ error: 'tenantId manquant' }, { status: 400 })
await prisma.$transaction(async (tx) => {
for (const page of pages) {
// ✅ FIX : upsert la page elle-même (titre, slug, ordre, visible, estAccueil)
await tx.vitrinePage.upsert({
where: { id: page.id },
create: {
id: page.id,
tenantId,
titre: page.titre,
slug: page.slug,
parentId: page.parentId ?? null,
ordre: page.ordre ?? 0,
visible: page.visible ?? true,
estAccueil: page.estAccueil ?? false,
type: page.type ?? 'STANDARD',
},
update: {
titre: page.titre,
slug: page.slug,
parentId: page.parentId ?? null,
ordre: page.ordre ?? 0,
visible: page.visible ?? true,
estAccueil: page.estAccueil ?? false,
},
})
if (!page.sections) continue
// ✅ Supprimer les sections qui ne sont plus dans la page
const sectionIds = page.sections.map((s: any) => s.id)
await tx.vitrineSection.deleteMany({
where: { pageId: page.id, id: { notIn: sectionIds } },
})
for (const section of page.sections) {
await tx.vitrineSection.upsert({
where: { id: section.id },
create: {
id: section.id,
tenantId,
pageId: page.id,
type: section.type,
nom: section.nom,
ordre: section.ordre,
visible: section.visible,
config: section.config ?? {},
},
update: {
pageId: page.id,
nom: section.nom,
ordre: section.ordre,
visible: section.visible,
config: section.config ?? {},
},
})
if (!section.blocs) continue
const blocIds = section.blocs.map((b: any) => b.id)
await tx.sectionBloc.deleteMany({
where: { sectionId: section.id, id: { notIn: blocIds } },
})
for (const bloc of section.blocs) {
await tx.sectionBloc.upsert({
where: { id: bloc.id },
create: {
id: bloc.id,
sectionId: section.id,
type: bloc.type,
ordre: bloc.ordre,
contenu: bloc.contenu ?? {},
mediaId: bloc.mediaId ?? null,
albumId: bloc.albumId ?? null,
categorieId: bloc.categorieId ?? null,
},
update: {
ordre: bloc.ordre,
contenu: bloc.contenu ?? {},
mediaId: bloc.mediaId ?? null,
albumId: bloc.albumId ?? null,
categorieId: bloc.categorieId ?? null,
},
})
}
}
}
})
return NextResponse.json({ ok: true })
} catch (e) {
console.error(e)
return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 })
}
}
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma/client'
import { getSession } from '@/lib/auth/session'
export async function POST(req: NextRequest) {
try {
const session = await getSession()
if (!session) return NextResponse.json({ error: 'Non autorise' }, { status: 401 })
const { pages, tenantId: bodyTenantId } = await req.json()
const tenantId = (session.tenantId as string) || bodyTenantId
if (!tenantId) return NextResponse.json({ error: 'tenantId manquant' }, { status: 400 })
await prisma.$transaction(async (tx) => {
for (const page of pages) {
// ✅ FIX : upsert la page elle-même (titre, slug, ordre, visible, estAccueil)
await tx.vitrinePage.upsert({
where: { id: page.id },
create: {
id: page.id,
tenantId,
titre: page.titre,
slug: page.slug,
parentId: page.parentId ?? null,
ordre: page.ordre ?? 0,
visible: page.visible ?? true,
estAccueil: page.estAccueil ?? false,
type: page.type ?? 'STANDARD',
},
update: {
titre: page.titre,
slug: page.slug,
parentId: page.parentId ?? null,
ordre: page.ordre ?? 0,
visible: page.visible ?? true,
estAccueil: page.estAccueil ?? false,
},
})
if (!page.sections) continue
// ✅ Supprimer les sections qui ne sont plus dans la page
const sectionIds = page.sections.map((s: any) => s.id)
await tx.vitrineSection.deleteMany({
where: { pageId: page.id, id: { notIn: sectionIds } },
})
for (const section of page.sections) {
await tx.vitrineSection.upsert({
where: { id: section.id },
create: {
id: section.id,
tenantId,
pageId: page.id,
type: section.type,
nom: section.nom,
ordre: section.ordre,
visible: section.visible,
config: section.config ?? {},
},
update: {
pageId: page.id,
nom: section.nom,
ordre: section.ordre,
visible: section.visible,
config: section.config ?? {},
},
})
if (!section.blocs) continue
const blocIds = section.blocs.map((b: any) => b.id)
await tx.sectionBloc.deleteMany({
where: { sectionId: section.id, id: { notIn: blocIds } },
})
for (const bloc of section.blocs) {
await tx.sectionBloc.upsert({
where: { id: bloc.id },
create: {
id: bloc.id,
sectionId: section.id,
type: bloc.type,
ordre: bloc.ordre,
contenu: bloc.contenu ?? {},
mediaId: bloc.mediaId ?? null,
albumId: bloc.albumId ?? null,
categorieId: bloc.categorieId ?? null,
},
update: {
ordre: bloc.ordre,
contenu: bloc.contenu ?? {},
mediaId: bloc.mediaId ?? null,
albumId: bloc.albumId ?? null,
categorieId: bloc.categorieId ?? null,
},
})
}
}
}
})
return NextResponse.json({ ok: true })
} catch (e) {
console.error(e)
return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 })
}
}