← back to Jill Website
src/routes/admin.ts
187 lines
import { Router, Request, Response } from 'express';
import multer from 'multer';
import path from 'path';
import { PageContentModel } from '../models/PageContent';
import { requireAuth } from '../middleware/auth';
// Configure multer for file uploads
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, path.join(__dirname, '../../public/uploads'));
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 5 * 1024 * 1024 }, // 5MB limit
fileFilter: (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif|webp/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (extname && mimetype) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed'));
}
}
});
export function createAdminRouter(pageContentModel?: PageContentModel): Router {
const router = Router();
const model = pageContentModel || new PageContentModel();
// All admin routes require authentication
router.use(requireAuth);
// GET /admin - Admin CMS interface
router.get('/', async (req: Request, res: Response) => {
try {
const pages = await model.findAll();
res.render('admin', {
pages,
currentYear: new Date().getFullYear()
});
} catch (error) {
console.error('Error loading admin page:', error);
res.status(500).json({
success: false,
error: 'Failed to load admin page'
});
}
});
// GET /admin/api/pages - Get all pages
router.get('/api/pages', async (req: Request, res: Response) => {
try {
const pages = await model.findAll();
res.json({
success: true,
data: pages
});
} catch (error) {
console.error('Error fetching pages:', error);
res.status(500).json({
success: false,
error: 'Failed to fetch pages'
});
}
});
// GET /admin/api/pages/:id - Get single page
router.get('/api/pages/:id', async (req: Request, res: Response) => {
try {
const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) {
return res.status(400).json({
success: false,
error: 'Invalid page ID'
});
}
const page = await model.findById(id);
if (!page) {
return res.status(404).json({
success: false,
error: 'Page not found'
});
}
res.json({
success: true,
data: page
});
} catch (error) {
console.error('Error fetching page:', error);
res.status(500).json({
success: false,
error: 'Failed to fetch page'
});
}
});
// PUT /admin/api/pages/:id - Update page content
router.put('/api/pages/:id', async (req: Request, res: Response) => {
try {
if (!req.body) {
return res.status(400).json({
success: false,
error: 'Request body is required'
});
}
const idParam = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
const id = parseInt(idParam, 10);
if (isNaN(id)) {
return res.status(400).json({
success: false,
error: 'Invalid page ID'
});
}
const { page_title, content, gallery_images } = req.body;
// Get existing page to preserve slug
const existingPage = await model.findById(id);
if (!existingPage) {
return res.status(404).json({
success: false,
error: 'Page not found'
});
}
const updatedPage = await model.update(existingPage.page_slug, {
page_slug: existingPage.page_slug,
page_title: page_title || existingPage.page_title,
content: content || existingPage.content,
gallery_images: gallery_images || existingPage.gallery_images
});
res.json({
success: true,
data: updatedPage,
message: 'Page updated successfully'
});
} catch (error) {
console.error('Error updating page:', error);
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Failed to update page'
});
}
});
// POST /admin/api/upload - Upload image
router.post('/api/upload', upload.single('image'), (req: Request, res: Response) => {
try {
if (!req.file) {
return res.status(400).json({
success: false,
error: 'No file uploaded'
});
}
const imageUrl = `/uploads/${req.file.filename}`;
res.json({
success: true,
data: { url: imageUrl },
message: 'Image uploaded successfully'
});
} catch (error) {
console.error('Error uploading image:', error);
res.status(500).json({
success: false,
error: 'Failed to upload image'
});
}
});
return router;
}
export default createAdminRouter();