maj url photo + page 404 + gestion programmation d'article
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { generateSlug } from "@/lib/utils";
|
||||
import { ContentStatus } from "@prisma/client";
|
||||
|
||||
export async function createBlogPost(data: {
|
||||
title: string;
|
||||
@@ -14,6 +15,8 @@ export async function createBlogPost(data: {
|
||||
tags?: string[];
|
||||
metaTitle?: string;
|
||||
metaDescription?: string;
|
||||
publishedAt?: Date;
|
||||
status?: ContentStatus;
|
||||
}) {
|
||||
try {
|
||||
const slug = data.slug || generateSlug(data.title);
|
||||
@@ -23,10 +26,12 @@ export async function createBlogPost(data: {
|
||||
...data,
|
||||
slug,
|
||||
tags: data.tags || [],
|
||||
publishedAt: data.publishedAt || new Date(),
|
||||
status: data.status || ContentStatus.PUBLISHED,
|
||||
},
|
||||
});
|
||||
revalidatePath("/blog");
|
||||
return { success: true, data: post };
|
||||
return { success: true, id: post.id };
|
||||
} catch (error) {
|
||||
console.error("Failed to create blog post:", error);
|
||||
return { success: false, error: "Erreur lors de la création de l'article" };
|
||||
@@ -43,6 +48,8 @@ export async function updateBlogPost(id: string, data: {
|
||||
tags?: string[];
|
||||
metaTitle?: string;
|
||||
metaDescription?: string;
|
||||
publishedAt?: Date;
|
||||
status?: ContentStatus;
|
||||
}) {
|
||||
try {
|
||||
const slug = data.slug || generateSlug(data.title);
|
||||
@@ -56,7 +63,7 @@ export async function updateBlogPost(id: string, data: {
|
||||
},
|
||||
});
|
||||
revalidatePath("/blog");
|
||||
return { success: true, data: post };
|
||||
return { success: true, id: post.id };
|
||||
} catch (error) {
|
||||
console.error("Failed to update blog post:", error);
|
||||
return { success: false, error: "Erreur lors de la mise à jour" };
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { generateSlug } from "@/lib/utils";
|
||||
import { ContentStatus } from "@prisma/client";
|
||||
|
||||
export async function createEvent(data: {
|
||||
title: string;
|
||||
@@ -15,6 +16,8 @@ export async function createEvent(data: {
|
||||
tags?: string[];
|
||||
metaTitle?: string;
|
||||
metaDescription?: string;
|
||||
publishedAt?: Date;
|
||||
status?: ContentStatus;
|
||||
}) {
|
||||
try {
|
||||
const slug = data.slug || generateSlug(data.title);
|
||||
@@ -24,6 +27,8 @@ export async function createEvent(data: {
|
||||
...data,
|
||||
slug,
|
||||
tags: data.tags || [],
|
||||
publishedAt: data.publishedAt || new Date(),
|
||||
status: data.status || ContentStatus.PUBLISHED,
|
||||
},
|
||||
});
|
||||
revalidatePath("/blog");
|
||||
@@ -46,6 +51,8 @@ export async function updateEvent(id: string, data: {
|
||||
tags?: string[];
|
||||
metaTitle?: string;
|
||||
metaDescription?: string;
|
||||
publishedAt?: Date;
|
||||
status?: ContentStatus;
|
||||
}) {
|
||||
try {
|
||||
const slug = data.slug || generateSlug(data.title);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { InterviewType } from "@prisma/client";
|
||||
import { InterviewType, ContentStatus } from "@prisma/client";
|
||||
import { generateSlug } from "@/lib/utils";
|
||||
|
||||
export async function createInterview(data: {
|
||||
@@ -20,6 +20,8 @@ export async function createInterview(data: {
|
||||
tags?: string[];
|
||||
metaTitle?: string;
|
||||
metaDescription?: string;
|
||||
publishedAt?: Date;
|
||||
status?: ContentStatus;
|
||||
}) {
|
||||
try {
|
||||
const slug = data.slug || generateSlug(data.title);
|
||||
@@ -29,6 +31,8 @@ export async function createInterview(data: {
|
||||
...data,
|
||||
slug,
|
||||
tags: data.tags || [],
|
||||
publishedAt: data.publishedAt || new Date(),
|
||||
status: data.status || ContentStatus.PUBLISHED,
|
||||
},
|
||||
});
|
||||
revalidatePath("/blog");
|
||||
@@ -54,6 +58,8 @@ export async function updateInterview(id: string, data: {
|
||||
tags?: string[];
|
||||
metaTitle?: string;
|
||||
metaDescription?: string;
|
||||
publishedAt?: Date;
|
||||
status?: ContentStatus;
|
||||
}) {
|
||||
try {
|
||||
const slug = data.slug || generateSlug(data.title);
|
||||
|
||||
138
admin/src/app/actions/taxonomies.ts
Normal file
138
admin/src/app/actions/taxonomies.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
'use server';
|
||||
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function getAllTags() {
|
||||
try {
|
||||
const [blogPosts, interviews, events] = await Promise.all([
|
||||
prisma.blogPost.findMany({ select: { tags: true } }),
|
||||
prisma.interview.findMany({ select: { tags: true } }),
|
||||
prisma.event.findMany({ select: { tags: true } }),
|
||||
]);
|
||||
|
||||
const allTags = new Set<string>();
|
||||
blogPosts.forEach(p => p.tags.forEach(t => allTags.add(t)));
|
||||
interviews.forEach(i => i.tags.forEach(t => allTags.add(t)));
|
||||
events.forEach(e => e.tags.forEach(t => allTags.add(t)));
|
||||
|
||||
return Array.from(allTags).sort();
|
||||
} catch (error) {
|
||||
console.error('Error fetching tags:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteTagGlobally(tagName: string) {
|
||||
try {
|
||||
// This is expensive as we need to update all records
|
||||
// In a real app, a Tag model would be better
|
||||
|
||||
const [blogPosts, interviews, events] = await Promise.all([
|
||||
prisma.blogPost.findMany({ where: { tags: { has: tagName } } }),
|
||||
prisma.interview.findMany({ where: { tags: { has: tagName } } }),
|
||||
prisma.event.findMany({ where: { tags: { has: tagName } } }),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
...blogPosts.map(p => prisma.blogPost.update({
|
||||
where: { id: p.id },
|
||||
data: { tags: { set: p.tags.filter(t => t !== tagName) } }
|
||||
})),
|
||||
...interviews.map(i => prisma.interview.update({
|
||||
where: { id: i.id },
|
||||
data: { tags: { set: i.tags.filter(t => t !== tagName) } }
|
||||
})),
|
||||
...events.map(e => prisma.event.update({
|
||||
where: { id: e.id },
|
||||
data: { tags: { set: e.tags.filter(t => t !== tagName) } }
|
||||
}))
|
||||
]);
|
||||
|
||||
revalidatePath('/taxonomies');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error deleting tag globally:', error);
|
||||
return { success: false, error: 'Erreur lors de la suppression du tag' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function renameTagGlobally(oldName: string, newName: string) {
|
||||
try {
|
||||
const cleanNewName = newName.trim().toLowerCase();
|
||||
if (!cleanNewName) return { success: false, error: 'Nouveau nom invalide' };
|
||||
|
||||
const [blogPosts, interviews, events] = await Promise.all([
|
||||
prisma.blogPost.findMany({ where: { tags: { has: oldName } } }),
|
||||
prisma.interview.findMany({ where: { tags: { has: oldName } } }),
|
||||
prisma.event.findMany({ where: { tags: { has: oldName } } }),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
...blogPosts.map(p => prisma.blogPost.update({
|
||||
where: { id: p.id },
|
||||
data: { tags: { set: p.tags.map(t => t === oldName ? cleanNewName : t) } }
|
||||
})),
|
||||
...interviews.map(i => prisma.interview.update({
|
||||
where: { id: i.id },
|
||||
data: { tags: { set: i.tags.map(t => t === oldName ? cleanNewName : t) } }
|
||||
})),
|
||||
...events.map(e => prisma.event.update({
|
||||
where: { id: e.id },
|
||||
data: { tags: { set: e.tags.map(t => t === oldName ? cleanNewName : t) } }
|
||||
}))
|
||||
]);
|
||||
|
||||
revalidatePath('/taxonomies');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error renaming tag globally:', error);
|
||||
return { success: false, error: 'Erreur lors du renommage du tag' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTagUsage(tagName: string) {
|
||||
try {
|
||||
const [blogPosts, interviews, events] = await Promise.all([
|
||||
prisma.blogPost.findMany({
|
||||
where: { tags: { has: tagName } },
|
||||
select: { id: true, title: true, status: true, author: true }
|
||||
}),
|
||||
prisma.interview.findMany({
|
||||
where: { tags: { has: tagName } },
|
||||
select: { id: true, title: true, status: true, guestName: true }
|
||||
}),
|
||||
prisma.event.findMany({
|
||||
where: { tags: { has: tagName } },
|
||||
select: { id: true, title: true, status: true, location: true }
|
||||
}),
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
blogPosts: blogPosts.map(p => ({
|
||||
id: p.id,
|
||||
title: p.title,
|
||||
status: p.status,
|
||||
type: 'blog'
|
||||
})),
|
||||
interviews: interviews.map(i => ({
|
||||
id: i.id,
|
||||
title: i.title,
|
||||
status: i.status,
|
||||
type: 'interview'
|
||||
})),
|
||||
events: events.map(e => ({
|
||||
id: e.id,
|
||||
title: e.title,
|
||||
status: e.status,
|
||||
type: 'event'
|
||||
})),
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error fetching tag usage:', error);
|
||||
return { success: false, error: 'Erreur lors de la récupération de l\'usage' };
|
||||
}
|
||||
}
|
||||
42
admin/src/app/actions/upload.ts
Normal file
42
admin/src/app/actions/upload.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
'use server';
|
||||
|
||||
import { writeFile, mkdir } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
|
||||
export async function uploadImage(formData: FormData) {
|
||||
try {
|
||||
const file = formData.get('file') as File;
|
||||
if (!file) {
|
||||
return { success: false, error: 'Aucun fichier fourni' };
|
||||
}
|
||||
|
||||
const bytes = await file.arrayBuffer();
|
||||
const buffer = Buffer.from(bytes);
|
||||
|
||||
// Create a unique filename
|
||||
const fileExtension = file.name.split('.').pop();
|
||||
const fileName = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}.${fileExtension}`;
|
||||
|
||||
// Path for the ROOT public/uploads (where the main site will look)
|
||||
const rootPublicDir = join(process.cwd(), '..', 'public', 'uploads');
|
||||
// Path for the ADMIN public/uploads (where the admin app can see it for preview)
|
||||
const adminPublicDir = join(process.cwd(), 'public', 'uploads');
|
||||
|
||||
// Ensure both directories exist
|
||||
await mkdir(rootPublicDir, { recursive: true });
|
||||
await mkdir(adminPublicDir, { recursive: true });
|
||||
|
||||
// Save to both
|
||||
await writeFile(join(rootPublicDir, fileName), buffer);
|
||||
await writeFile(join(adminPublicDir, fileName), buffer);
|
||||
|
||||
// Return the relative URL
|
||||
return {
|
||||
success: true,
|
||||
url: `/uploads/${fileName}`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error during image upload:', error);
|
||||
return { success: false, error: 'Erreur lors de l\'upload de l\'image' };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user