Add admin dashboard and Replit authentication integration

Integrates Replit authentication using OpenID Connect, adds an admin dashboard route with video management and thumbnail upload capabilities, and updates dependencies.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 890577b1-c154-40a4-a177-a0c6d55320c3
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/890577b1-c154-40a4-a177-a0c6d55320c3/1jMBtLj
This commit is contained in:
sebastjanartic
2025-09-02 12:01:00 +00:00
parent 12df511504
commit c71720454f
12 changed files with 975 additions and 31 deletions
+109
View File
@@ -16,6 +16,8 @@ import fs from "fs";
import session from "express-session";
import sharp from "sharp";
import fetch from "node-fetch";
import { setupAuth, isAuthenticated, isAdmin } from "./replitAuth";
import { ObjectStorageService, ObjectNotFoundError } from "./objectStorage";
// Extend express session
declare module "express-session" {
@@ -56,6 +58,9 @@ const authenticate = (req: Request, res: Response, next: any) => {
};
export async function registerRoutes(app: Express): Promise<Server> {
// Setup Replit Auth first
await setupAuth(app);
// Add compression middleware for better performance
app.use(compression({
level: 6,
@@ -850,6 +855,110 @@ export async function registerRoutes(app: Express): Promise<Server> {
}
});
// ===== ADMIN ROUTES =====
// Auth route to get current user
app.get('/api/auth/user', isAuthenticated, async (req: any, res) => {
try {
const userId = req.user.claims.sub;
const user = await storage.getUser(userId);
res.json(user);
} catch (error) {
console.error("Error fetching user:", error);
res.status(500).json({ message: "Failed to fetch user" });
}
});
// Admin video management
app.get('/api/admin/videos', isAdmin, async (req, res) => {
try {
const limit = parseInt(req.query.limit as string) || 50;
const offset = parseInt(req.query.offset as string) || 0;
const search = req.query.search as string;
const videos = await storage.getVideos(limit, offset, search);
const total = await storage.getVideoCount(search);
res.json({ videos, total, limit, offset });
} catch (error) {
console.error("Error fetching admin videos:", error);
res.status(500).json({ message: "Failed to fetch videos" });
}
});
app.patch('/api/admin/videos/:id', isAdmin, async (req, res) => {
try {
const videoId = req.params.id;
const updateData = updateVideoSchema.parse(req.body);
const updatedVideo = await storage.updateVideo(videoId, updateData);
if (!updatedVideo) {
return res.status(404).json({ message: "Video not found" });
}
res.json(updatedVideo);
} catch (error) {
console.error("Error updating video:", error);
if (error instanceof z.ZodError) {
res.status(400).json({ message: "Invalid video data", errors: error.errors });
} else {
res.status(500).json({ message: "Failed to update video" });
}
}
});
// Thumbnail upload
app.post('/api/admin/thumbnails/upload', isAdmin, async (req, res) => {
try {
const objectStorageService = new ObjectStorageService();
const uploadURL = await objectStorageService.getThumbnailUploadURL();
res.json({ uploadURL });
} catch (error) {
console.error("Error getting thumbnail upload URL:", error);
res.status(500).json({ message: "Failed to get upload URL" });
}
});
// Serve uploaded objects
app.get("/objects/:objectPath(*)", async (req, res) => {
const objectStorageService = new ObjectStorageService();
try {
const objectFile = await objectStorageService.getObjectFile(req.path);
objectStorageService.downloadObject(objectFile, res);
} catch (error) {
console.error("Error serving object:", error);
if (error instanceof ObjectNotFoundError) {
return res.sendStatus(404);
}
return res.sendStatus(500);
}
});
// User management (super admin only)
app.patch('/api/admin/users/:id/admin', isAuthenticated, async (req: any, res) => {
try {
const currentUserId = req.user.claims.sub;
const currentUser = await storage.getUser(currentUserId);
if (!currentUser?.isSuperAdmin) {
return res.status(403).json({ message: "Super admin access required" });
}
const userId = req.params.id;
const { isAdmin } = req.body;
const updatedUser = await storage.updateUser(userId, { isAdmin });
if (!updatedUser) {
return res.status(404).json({ message: "User not found" });
}
res.json(updatedUser);
} catch (error) {
console.error("Error updating user admin status:", error);
res.status(500).json({ message: "Failed to update user" });
}
});
const httpServer = createServer(app);
return httpServer;
}