diff --git a/.replit b/.replit index 8bbc693..f9a4cd6 100644 --- a/.replit +++ b/.replit @@ -38,6 +38,10 @@ externalPort = 4200 localPort = 38631 externalPort = 8080 +[[ports]] +localPort = 39065 +externalPort = 8081 + [[ports]] localPort = 40537 externalPort = 3000 diff --git a/client/src/App.tsx b/client/src/App.tsx index 57062bd..7fd12f2 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -69,7 +69,7 @@ function Router() { {() => } {() => } {() => } - {() => } + {() => } {() => } {() => } {() => } diff --git a/client/src/components/sidebar.tsx b/client/src/components/sidebar.tsx index f0154c0..3e6e0a2 100644 --- a/client/src/components/sidebar.tsx +++ b/client/src/components/sidebar.tsx @@ -63,7 +63,6 @@ export default function Sidebar({ onLinkClick }: SidebarProps = {}) { { icon: PlusCircle, label: "Nouvelle publication", href: "/new", badge: null }, { icon: Calendar, label: "Calendrier", href: "/calendar", badge: null }, { icon: Images, label: "Médiathèque", href: "/media", badge: null }, - { icon: Bot, label: "Assistant IA", href: "/ai", badge: null }, ]; const statsItems = [ @@ -212,6 +211,30 @@ export default function Sidebar({ onLinkClick }: SidebarProps = {}) { )} + handleLinkClick("/ai", e)} + className={` + flex items-center gap-3 px-4 py-3 rounded-xl transition-all relative group cursor-pointer + ${location === "/ai" + ? 'bg-gradient-to-r from-primary/10 to-secondary/10 text-primary shadow-sm' + : 'text-muted-foreground hover:bg-sidebar-accent hover:text-foreground' + } + ${isCollapsed ? 'justify-center' : ''} + `} + data-testid="link-assistant-ia" + > + {location === "/ai" && ( +
+ )} + + {!isCollapsed && Assistant IA} + {isCollapsed && ( +
+ Assistant IA +
+ )} +
handleLinkClick("/users", e)} diff --git a/replit.md b/replit.md index 22b6fd7..2c7e2e7 100644 --- a/replit.md +++ b/replit.md @@ -10,6 +10,9 @@ Preferred communication style: Simple, everyday language. ## Recent Changes +### October 10, 2025 +- **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 - **AI Variants Position**: Repositioned AI-generated text variations to display after "Contenu" card and before "Texte de la publication" card in new-post page for better workflow - **Calendar Auto-Refresh**: Fixed calendar not updating after creating a new scheduled post. Added `queryClient.invalidateQueries` with `refetchType: 'all'` in `createPostMutation.onSuccess` to force cache invalidation and immediate refetch @@ -47,7 +50,7 @@ These transformation URLs are stored in the database (`facebookLandscapeUrl`, `f ### Authentication & Authorization -Authentication uses **Passport.js** with local strategy and `bcrypt` for password hashing. User roles (`admin`, `user`) control access, with `admin` having full access and `user` limited to publishing features. Session management is via `express-session` with HTTP-only cookies, `sameSite: 'lax'`, and a 7-day duration, secured by a `SESSION_SECRET` environment variable. Routes are protected on both the backend (middleware `requireAuth`, `requireAdmin`) and frontend (`ProtectedRoute` component). +Authentication uses **Passport.js** with local strategy and `bcrypt` for password hashing. User roles (`admin`, `user`) control access, with `admin` having full access and `user` limited to publishing features (posts, calendar, media, history). The **AI Assistant** is restricted to administrators only. Session management is via `express-session` with HTTP-only cookies, `sameSite: 'lax'`, and a 7-day duration, secured by a `SESSION_SECRET` environment variable. Routes are protected on both the backend (middleware `requireAuth`, `requireAdmin`) and frontend (`ProtectedRoute` component with optional `adminOnly` prop). ### UI/UX Decisions diff --git a/server/routes.ts b/server/routes.ts index 7582533..4b4dcc7 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -424,7 +424,7 @@ export async function registerRoutes(app: Express): Promise { }); // Get available AI models from OpenRouter - app.get("/api/ai/models", requireAuth, async (req, res) => { + app.get("/api/ai/models", requireAdmin, async (req, res) => { try { const models = await openRouterService.getAvailableModels(); res.json({ models }); @@ -435,7 +435,7 @@ export async function registerRoutes(app: Express): Promise { }); // AI text generation - app.post("/api/ai/generate", requireAuth, async (req, res) => { + app.post("/api/ai/generate", requireAdmin, async (req, res) => { try { const user = req.user as User; const userId = user.id; @@ -937,7 +937,7 @@ export async function registerRoutes(app: Express): Promise { }); // AI Generations - app.get("/api/ai/generations", requireAuth, async (req, res) => { + app.get("/api/ai/generations", requireAdmin, async (req, res) => { try { const user = req.user as User; const userId = user.id;