Add new pages and improve blog content display functionality
Implement new routes for articles, categories, and individual articles. Update the UI to display articles with improved content rendering, including safe HTML and media embeds. Refactor storage to use a database and add image upload capabilities. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 413891e8-d784-4bea-b9f5-91a5a68316b4 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: b96b221e-0ed6-418f-80df-e4670bf5ba4b Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/413891e8-d784-4bea-b9f5-91a5a68316b4/cftwqyT Replit-Helium-Checkpoint-Created: true
This commit is contained in:
+94
-4
@@ -1,16 +1,106 @@
|
||||
import type { Express } from "express";
|
||||
import { createServer, type Server } from "http";
|
||||
import { storage } from "./storage";
|
||||
import { insertArticleSchema } from "@shared/schema";
|
||||
import { seedDatabase } from "./seed";
|
||||
import multer from "multer";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
const uploadDir = path.join(process.cwd(), "client/public/uploads");
|
||||
if (!fs.existsSync(uploadDir)) {
|
||||
fs.mkdirSync(uploadDir, { recursive: true });
|
||||
}
|
||||
|
||||
const upload = multer({
|
||||
storage: multer.diskStorage({
|
||||
destination: (_req, _file, cb) => cb(null, uploadDir),
|
||||
filename: (_req, file, cb) => {
|
||||
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
|
||||
const ext = path.extname(file.originalname);
|
||||
cb(null, uniqueSuffix + ext);
|
||||
},
|
||||
}),
|
||||
limits: { fileSize: 10 * 1024 * 1024 },
|
||||
fileFilter: (_req, file, cb) => {
|
||||
const allowed = /jpeg|jpg|png|gif|webp/;
|
||||
const ext = allowed.test(path.extname(file.originalname).toLowerCase());
|
||||
const mime = allowed.test(file.mimetype);
|
||||
cb(null, ext && mime);
|
||||
},
|
||||
});
|
||||
|
||||
export async function registerRoutes(
|
||||
httpServer: Server,
|
||||
app: Express
|
||||
): Promise<Server> {
|
||||
// put application routes here
|
||||
// prefix all routes with /api
|
||||
await seedDatabase();
|
||||
|
||||
// use storage to perform CRUD operations on the storage interface
|
||||
// e.g. storage.insertUser(user) or storage.getUserByUsername(username)
|
||||
app.get("/api/articles", async (_req, res) => {
|
||||
const articles = await storage.getArticles();
|
||||
res.json(articles);
|
||||
});
|
||||
|
||||
app.get("/api/articles/featured", async (_req, res) => {
|
||||
const articles = await storage.getFeaturedArticles();
|
||||
res.json(articles);
|
||||
});
|
||||
|
||||
app.get("/api/articles/popular", async (req, res) => {
|
||||
const limit = parseInt(req.query.limit as string) || 5;
|
||||
const articles = await storage.getPopularArticles(limit);
|
||||
res.json(articles);
|
||||
});
|
||||
|
||||
app.get("/api/articles/category/:category", async (req, res) => {
|
||||
const articles = await storage.getArticlesByCategory(req.params.category);
|
||||
res.json(articles);
|
||||
});
|
||||
|
||||
app.get("/api/articles/:slug", async (req, res) => {
|
||||
const article = await storage.getArticleBySlug(req.params.slug);
|
||||
if (!article) {
|
||||
return res.status(404).json({ message: "Article not found" });
|
||||
}
|
||||
await storage.incrementViews(article.id);
|
||||
res.json({ ...article, views: article.views + 1 });
|
||||
});
|
||||
|
||||
app.post("/api/articles", async (req, res) => {
|
||||
const parsed = insertArticleSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ message: "Invalid article data", errors: parsed.error.flatten() });
|
||||
}
|
||||
const article = await storage.createArticle(parsed.data);
|
||||
res.status(201).json(article);
|
||||
});
|
||||
|
||||
app.patch("/api/articles/:id", async (req, res) => {
|
||||
const id = parseInt(req.params.id);
|
||||
const partial = insertArticleSchema.partial().safeParse(req.body);
|
||||
if (!partial.success) {
|
||||
return res.status(400).json({ message: "Invalid article data", errors: partial.error.flatten() });
|
||||
}
|
||||
const article = await storage.updateArticle(id, partial.data);
|
||||
if (!article) {
|
||||
return res.status(404).json({ message: "Article not found" });
|
||||
}
|
||||
res.json(article);
|
||||
});
|
||||
|
||||
app.delete("/api/articles/:id", async (req, res) => {
|
||||
const id = parseInt(req.params.id);
|
||||
await storage.deleteArticle(id);
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
app.post("/api/upload", upload.single("image"), (req, res) => {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ message: "No file uploaded" });
|
||||
}
|
||||
const url = `/uploads/${req.file.filename}`;
|
||||
res.json({ url });
|
||||
});
|
||||
|
||||
return httpServer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user