Site Settings -> Branding now supports a Primary/Secondary/Accent brand color system applied site-wide (buttons, nav, hover states, links) and to outgoing email header/CTA colors, plus a favicon upload alongside the existing logo upload, a live preview panel (website/email x desktop/mobile), and logo-based color suggestions. The setup wizard's Branding step got the same treatment. Fixes two related bugs found along the way: the setup wizard's logo/favicon upload was missing its auth token, and a static favicon.ico in Next's special app/ convention path was silently overriding the dynamic one. Also replaces every "Hope Events"/"Hope Family Church" default (org name, email subjects, WhatsApp messages, report metadata, API docs) with a neutral "Cross Code" placeholder, and the optional legal settings (operator name, IO details, website URL, effective date) with obviously-generic placeholders instead of defaulting to real personal/organisational details -- since this platform is deployed for multiple organisations. Adds SETTINGS.md documenting every setting's default behaviour. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
53 lines
1.8 KiB
JavaScript
53 lines
1.8 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
|
|
const { upload, uploadEventImage, uploadLogo, uploadLogoImage, uploadFavicon, uploadFaviconImage } = require('../controllers/uploadController');
|
|
const { protect, supervisor, admin } = require('../middleware/authMiddleware');
|
|
const prisma = require('../config/db');
|
|
|
|
// @route POST /api/uploads/event-image
|
|
// @desc Upload an image for an event
|
|
// @access Private (Supervisor+ recommended)
|
|
router.post('/event-image', protect, supervisor, (req, res, next) => {
|
|
upload.single('image')(req, res, (err) => {
|
|
if (err) {
|
|
req.multerError = err;
|
|
}
|
|
next();
|
|
});
|
|
}, uploadEventImage);
|
|
|
|
// Shared access rule for branding assets (logo, favicon): admin, OR allowed
|
|
// during first-time setup (no users yet).
|
|
async function brandingAssetAccess(req, res, next) {
|
|
try {
|
|
const count = await prisma.user.count();
|
|
if (count === 0) return next(); // first-time setup
|
|
return protect(req, res, () => admin(req, res, next));
|
|
} catch {
|
|
return protect(req, res, () => admin(req, res, next));
|
|
}
|
|
}
|
|
|
|
// @route POST /api/uploads/logo
|
|
// @desc Upload site logo — admin, OR allowed during first-time setup (no users yet)
|
|
// @access Admin or setup
|
|
router.post('/logo', brandingAssetAccess, (req, res, next) => {
|
|
uploadLogo.single('image')(req, res, (err) => {
|
|
if (err) req.multerError = err;
|
|
next();
|
|
});
|
|
}, uploadLogoImage);
|
|
|
|
// @route POST /api/uploads/favicon
|
|
// @desc Upload site favicon — admin, OR allowed during first-time setup (no users yet)
|
|
// @access Admin or setup
|
|
router.post('/favicon', brandingAssetAccess, (req, res, next) => {
|
|
uploadFavicon.single('image')(req, res, (err) => {
|
|
if (err) req.multerError = err;
|
|
next();
|
|
});
|
|
}, uploadFaviconImage);
|
|
|
|
module.exports = router;
|