mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
3 files changed
+49
-5
No files matched your search
@@ -14,6 +14,10 @@ run = ["npm", "run", "start"]
|
|||||||
localPort = 5000
|
localPort = 5000
|
||||||
externalPort = 80
|
externalPort = 80
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
localPort = 33821
|
||||||
|
externalPort = 8099
|
||||||
|
|
||||||
[[ports]]
|
[[ports]]
|
||||||
localPort = 34045
|
localPort = 34045
|
||||||
externalPort = 3003
|
externalPort = 3003
|
||||||
@@ -46,6 +50,10 @@ externalPort = 8081
|
|||||||
localPort = 40537
|
localPort = 40537
|
||||||
externalPort = 3000
|
externalPort = 3000
|
||||||
|
|
||||||
|
[[ports]]
|
||||||
|
localPort = 41803
|
||||||
|
externalPort = 8008
|
||||||
|
|
||||||
[[ports]]
|
[[ports]]
|
||||||
localPort = 42161
|
localPort = 42161
|
||||||
externalPort = 6000
|
externalPort = 6000
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ Preferred communication style: Simple, everyday language.
|
|||||||
## Recent Changes
|
## Recent Changes
|
||||||
|
|
||||||
### October 10, 2025
|
### 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.
|
- **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
|
### October 9, 2025
|
||||||
|
|||||||
+38
-5
@@ -611,6 +611,11 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
// Set status to "scheduled" if scheduledFor is provided, otherwise "draft"
|
// Set status to "scheduled" if scheduledFor is provided, otherwise "draft"
|
||||||
if (postFields.scheduledFor) {
|
if (postFields.scheduledFor) {
|
||||||
postFields.status = "scheduled";
|
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
|
// 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 start = startDate ? new Date(startDate as string) : undefined;
|
||||||
const end = endDate ? new Date(endDate 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);
|
res.json(scheduledPosts);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching scheduled posts:", 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 userId = user.id;
|
||||||
const { id } = req.params;
|
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);
|
const scheduledPost = await storage.getScheduledPost(id);
|
||||||
if (!scheduledPost) {
|
if (!scheduledPost) {
|
||||||
return res.status(404).json({ error: "Scheduled post not found" });
|
return res.status(404).json({ error: "Scheduled post not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const post = await storage.getPost(scheduledPost.postId);
|
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" });
|
return res.status(403).json({ error: "Unauthorized" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,14 +823,19 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
const { id } = req.params;
|
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);
|
const scheduledPost = await storage.getScheduledPost(id);
|
||||||
if (!scheduledPost) {
|
if (!scheduledPost) {
|
||||||
return res.status(404).json({ error: "Scheduled post not found" });
|
return res.status(404).json({ error: "Scheduled post not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const post = await storage.getPost(scheduledPost.postId);
|
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" });
|
return res.status(403).json({ error: "Unauthorized" });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,6 +845,8 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
|
|
||||||
if (scheduledAt) {
|
if (scheduledAt) {
|
||||||
updateData.scheduledAt = new Date(scheduledAt);
|
updateData.scheduledAt = new Date(scheduledAt);
|
||||||
|
// Synchroniser avec la table posts
|
||||||
|
await storage.updatePost(scheduledPost.postId, { scheduledFor: new Date(scheduledAt) });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pageId) {
|
if (pageId) {
|
||||||
|
|||||||
Reference in new issue
Block a user