Merge pull request #55 from R0m1k3/dev

Dev
This commit is contained in:
LogiFlow authored and GitHub committed 2025-10-10 11:37:41 +02:00
commit 3ca7932d9e
3 files changed
+49 -5

No files matched your search

+8
View File
@@ -14,6 +14,10 @@ run = ["npm", "run", "start"]
localPort = 5000
externalPort = 80
[[ports]]
localPort = 33821
externalPort = 8099
[[ports]]
localPort = 34045
externalPort = 3003
@@ -46,6 +50,10 @@ externalPort = 8081
localPort = 40537
externalPort = 3000
[[ports]]
localPort = 41803
externalPort = 8008
[[ports]]
localPort = 42161
externalPort = 6000
+3
View File
@@ -11,6 +11,9 @@ Preferred communication style: Simple, everyday language.
## Recent Changes
### October 10, 2025
- **Calendar Permissions System**: Implemented comprehensive page-based permissions for calendar access. Admin users see all scheduled posts with full edit/delete rights. Standard users see only posts from their assigned pages via `user_page_permissions` table, but can only edit/delete their own posts (ownership check via `post.userId`). GET /api/scheduled-posts filters posts by accessible pages (admin bypass). DELETE and PATCH /api/scheduled-posts enforce ownership validation (admin can modify any post, users limited to own posts).
- **Scheduled Posts Data Sync Fix**: Fixed critical bug where editing scheduled post time via PATCH /api/scheduled-posts/:id updated `scheduled_posts.scheduledAt` but not `posts.scheduledFor`, causing calendar/database inconsistency. Now both tables are synchronized: updating scheduledAt automatically updates scheduledFor via `storage.updatePost()`.
- **Scheduled Posts Validation**: Added validation to POST /api/posts requiring `pageIds` when `scheduledFor` is provided. Prevents orphaned scheduled posts that would be invisible in calendar. Returns 400 error: "Les posts programmés nécessitent au moins une page cible".
- **AI Assistant Admin-Only Access**: Restricted access to AI Assistant to administrators only. Route `/ai` now requires admin role with `adminOnly` prop. Sidebar moved "Assistant IA" link to Administration section (visible only to admins). Backend endpoints (`/api/ai/models`, `/api/ai/generate`, `/api/ai/generations`) protected with `requireAdmin` middleware. Standard users attempting to access AI features see "Accès refusé" message and receive 403 responses.
### October 9, 2025
+38 -5
View File
@@ -611,6 +611,11 @@ export async function registerRoutes(app: Express): Promise<Server> {
// Set status to "scheduled" if scheduledFor is provided, otherwise "draft"
if (postFields.scheduledFor) {
postFields.status = "scheduled";
// Validate that scheduled posts require at least one page
if (!pageIds || !Array.isArray(pageIds) || pageIds.length === 0) {
return res.status(400).json({ error: "Les posts programmés nécessitent au moins une page cible" });
}
}
// Create the post
@@ -758,7 +763,23 @@ export async function registerRoutes(app: Express): Promise<Server> {
const start = startDate ? new Date(startDate as string) : undefined;
const end = endDate ? new Date(endDate as string) : undefined;
const scheduledPosts = await storage.getScheduledPosts(userId, start, end);
let scheduledPosts;
if (user.role === 'admin') {
// Admin voit tous les posts programmés
const allUsers = await storage.getAllUsers();
const allPostsPromises = allUsers.map(u => storage.getScheduledPosts(u.id, start, end));
const allPostsArrays = await Promise.all(allPostsPromises);
scheduledPosts = allPostsArrays.flat();
} else {
// User voit uniquement les posts des pages qui lui sont attribuées
const accessiblePages = await storage.getUserAccessiblePages(userId);
const accessiblePageIds = accessiblePages.map(p => p.id);
const userScheduledPosts = await storage.getScheduledPosts(userId, start, end);
scheduledPosts = userScheduledPosts.filter(sp => accessiblePageIds.includes(sp.pageId));
}
res.json(scheduledPosts);
} catch (error) {
console.error("Error fetching scheduled posts:", error);
@@ -772,14 +793,19 @@ export async function registerRoutes(app: Express): Promise<Server> {
const userId = user.id;
const { id } = req.params;
// Verify the scheduled post belongs to the user before deleting
// Verify the scheduled post exists
const scheduledPost = await storage.getScheduledPost(id);
if (!scheduledPost) {
return res.status(404).json({ error: "Scheduled post not found" });
}
const post = await storage.getPost(scheduledPost.postId);
if (!post || post.userId !== userId) {
if (!post) {
return res.status(404).json({ error: "Post not found" });
}
// Admin peut tout supprimer, user peut supprimer uniquement ses propres posts
if (user.role !== 'admin' && post.userId !== userId) {
return res.status(403).json({ error: "Unauthorized" });
}
@@ -797,14 +823,19 @@ export async function registerRoutes(app: Express): Promise<Server> {
const userId = user.id;
const { id } = req.params;
// Verify the scheduled post belongs to the user before updating
// Verify the scheduled post exists
const scheduledPost = await storage.getScheduledPost(id);
if (!scheduledPost) {
return res.status(404).json({ error: "Scheduled post not found" });
}
const post = await storage.getPost(scheduledPost.postId);
if (!post || post.userId !== userId) {
if (!post) {
return res.status(404).json({ error: "Post not found" });
}
// Admin peut tout modifier, user peut modifier uniquement ses propres posts
if (user.role !== 'admin' && post.userId !== userId) {
return res.status(403).json({ error: "Unauthorized" });
}
@@ -814,6 +845,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
if (scheduledAt) {
updateData.scheduledAt = new Date(scheduledAt);
// Synchroniser avec la table posts
await storage.updatePost(scheduledPost.postId, { scheduledFor: new Date(scheduledAt) });
}
if (pageId) {