Initial commit
Next.js + Express event management app for Hope Family Church.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { scheduleAutomations } = require('../controllers/automationController');
|
||||
const { protect, supervisor } = require('../middleware/authMiddleware');
|
||||
|
||||
// Schedule multiple automation emails for an event
|
||||
router.post('/schedule', protect, supervisor, scheduleAutomations);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,9 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getBanner, setBanner } = require('../controllers/bannerController');
|
||||
const { protect, supervisor } = require('../middleware/authMiddleware');
|
||||
|
||||
router.get('/', getBanner);
|
||||
router.post('/', protect, supervisor, setBanner);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,11 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { previewBroadcast, sendBroadcast, scheduleBroadcast } = require('../controllers/broadcastController');
|
||||
const { protect, supervisor } = require('../middleware/authMiddleware');
|
||||
|
||||
// All routes require supervisor (or admin via middleware logic) access
|
||||
router.post('/preview', protect, supervisor, previewBroadcast);
|
||||
router.post('/send', protect, supervisor, sendBroadcast);
|
||||
router.post('/schedule', protect, supervisor, scheduleBroadcast);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getEventCashup, saveEventCashupDraft, closeEvent, reopenEvent, getCashupAudit } = require('../controllers/cashupController');
|
||||
const { protect, supervisor, admin } = require('../middleware/authMiddleware');
|
||||
|
||||
router.get('/audit', protect, supervisor, getCashupAudit);
|
||||
router.get('/event/:eventId', protect, supervisor, getEventCashup);
|
||||
router.put('/event/:eventId/draft', protect, admin, saveEventCashupDraft);
|
||||
router.post('/event/:eventId/close', protect, admin, closeEvent);
|
||||
router.post('/event/:eventId/reopen', protect, admin, reopenEvent);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getEventCosts, createEventCost, updateEventCost, deleteEventCost } = require('../controllers/costController');
|
||||
const { protect, supervisor, admin } = require('../middleware/authMiddleware');
|
||||
|
||||
// Mounted at /api — paths below match the documented /api/events/:eventId/costs and /api/costs/:id shape
|
||||
router.get('/events/:eventId/costs', protect, supervisor, getEventCosts);
|
||||
router.post('/events/:eventId/costs', protect, admin, createEventCost);
|
||||
router.put('/costs/:id', protect, admin, updateEventCost);
|
||||
router.delete('/costs/:id', protect, admin, deleteEventCost);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,86 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
createEvent,
|
||||
getEvents,
|
||||
getAllEvents,
|
||||
getEventsAll,
|
||||
getEventById,
|
||||
updateEvent,
|
||||
getEventNotifyRecipients,
|
||||
updateEventNotifyRecipients,
|
||||
deleteEvent,
|
||||
createEventOption,
|
||||
updateEventOption,
|
||||
deleteEventOption,
|
||||
createOptionVariant,
|
||||
updateOptionVariant,
|
||||
deleteOptionVariant,
|
||||
listEventAttachments,
|
||||
uploadEventAttachment,
|
||||
deleteEventAttachment,
|
||||
attachmentsStatus,
|
||||
attachmentsSync,
|
||||
emailEventAttendees,
|
||||
scheduleEmailEventAttendees,
|
||||
whatsappEventAttendees,
|
||||
scheduleWhatsappEventAttendees,
|
||||
getEventByAlias
|
||||
} = require('../controllers/eventController');
|
||||
const { protect, admin, supervisor, optionalAuth } = require('../middleware/authMiddleware');
|
||||
|
||||
// Public routes
|
||||
router.get('/', getEvents);
|
||||
|
||||
// Staff/supervisor/admin: all events including hidden, optional past/inactive filters
|
||||
router.get('/all', protect, getEventsAll);
|
||||
|
||||
// Admin routes
|
||||
router.get('/admin/all', protect, admin, getAllEvents);
|
||||
router.get('/attachments/status', protect, admin, attachmentsStatus);
|
||||
router.post('/attachments/sync', protect, admin, attachmentsSync);
|
||||
|
||||
// Public route for single event (keep after specific admin routes).
|
||||
// optionalAuth populates req.user when a valid token is present so staff/supervisor/admin
|
||||
// can still load inactive events (e.g. for cashup or editing) without being 404'd.
|
||||
router.get('/:id', optionalAuth, getEventById);
|
||||
router.get('/by-alias/:redirectUrl', getEventByAlias);
|
||||
|
||||
// Create/Update/Delete event
|
||||
router.post('/', protect, supervisor, createEvent);
|
||||
router.route('/:id')
|
||||
.put(protect, supervisor, updateEvent)
|
||||
.delete(protect, admin, deleteEvent);
|
||||
|
||||
// Notification recipients: who gets registration/payment/daily-summary emails for this event
|
||||
router.route('/:id/notify-recipients')
|
||||
.get(protect, supervisor, getEventNotifyRecipients)
|
||||
.put(protect, supervisor, updateEventNotifyRecipients);
|
||||
|
||||
// Attachments routes
|
||||
router.get('/:id/attachments', listEventAttachments); // public read (used by event detail page)
|
||||
router.post('/:id/attachments', protect, supervisor, ...uploadEventAttachment);
|
||||
router.delete('/:eventId/attachments/:attachmentId', protect, supervisor, deleteEventAttachment);
|
||||
|
||||
// Bulk email attendees
|
||||
router.post('/:id/email-attendees', protect, supervisor, emailEventAttendees);
|
||||
// Schedule bulk email to attendees
|
||||
router.post('/:id/email-attendees/schedule', protect, supervisor, scheduleEmailEventAttendees);
|
||||
// Bulk WhatsApp message to attendees
|
||||
router.post('/:id/whatsapp-attendees', protect, supervisor, whatsappEventAttendees);
|
||||
// Schedule bulk WhatsApp message to attendees
|
||||
router.post('/:id/whatsapp-attendees/schedule', protect, supervisor, scheduleWhatsappEventAttendees);
|
||||
|
||||
// Event options routes
|
||||
router.post('/:id/options', protect, supervisor, createEventOption);
|
||||
router.route('/options/:id')
|
||||
.put(protect, supervisor, updateEventOption)
|
||||
.delete(protect, admin, deleteEventOption);
|
||||
|
||||
// Option variant routes
|
||||
router.post('/options/:id/variants', protect, supervisor, createOptionVariant);
|
||||
router.route('/variants/:id')
|
||||
.put(protect, supervisor, updateOptionVariant)
|
||||
.delete(protect, admin, deleteOptionVariant);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,9 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { listFormResponses } = require('../controllers/formController');
|
||||
const { protect, staff } = require('../middleware/authMiddleware');
|
||||
|
||||
// Staff or higher can view submitted forms
|
||||
router.get('/responses', protect, staff, listFormResponses);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,33 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
createPayment,
|
||||
getPayments,
|
||||
getUserPayments,
|
||||
getPaymentById,
|
||||
getPaymentsByRegistration,
|
||||
getPaymentsByEvent,
|
||||
assignDonationToRegistration,
|
||||
createYocoCheckout,
|
||||
sendPaymentLink,
|
||||
createRefund,
|
||||
getPaymentStats
|
||||
} = require('../controllers/paymentController');
|
||||
const { protect, supervisor, staff, admin} = require('../middleware/authMiddleware');
|
||||
|
||||
// Protected routes
|
||||
router.post('/', protect, supervisor, createPayment);
|
||||
router.post('/yoco-checkout', protect, createYocoCheckout);
|
||||
router.post('/yoco-checkout/send', protect, supervisor, sendPaymentLink);
|
||||
router.get('/mypayments', protect, getUserPayments);
|
||||
router.get('/:id', protect, getPaymentById);
|
||||
router.get('/registration/:registrationId', protect, getPaymentsByRegistration);
|
||||
|
||||
// Admin/Staff routes
|
||||
router.get('/', protect, supervisor, getPayments);
|
||||
router.get('/event/:eventId', protect, staff, getPaymentsByEvent);
|
||||
router.put('/assign-donation', protect, supervisor, assignDonationToRegistration);
|
||||
router.post('/refund', protect, supervisor, createRefund);
|
||||
router.get('/admin/stats', protect, admin, getPaymentStats);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,37 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
createRegistration,
|
||||
getRegistrations,
|
||||
getUserRegistrations,
|
||||
getRegistrationById,
|
||||
updateRegistrationStatus,
|
||||
cancelRegistration,
|
||||
getRegistrationsByEvent,
|
||||
createManualRegistration,
|
||||
updateRegistrationOptions,
|
||||
submitFormResponses, replaceFormResponses,
|
||||
getFormDraft, saveFormDraft,
|
||||
} = require('../controllers/registrationController');
|
||||
const { protect, supervisor, staff, optionalAuth } = require('../middleware/authMiddleware');
|
||||
|
||||
// Registration - auth optional when event doesn't require it
|
||||
router.post('/', optionalAuth, createRegistration);
|
||||
router.get('/myregistrations', protect, getUserRegistrations);
|
||||
router.put('/:id/options', protect, updateRegistrationOptions);
|
||||
router.delete('/:id', protect, cancelRegistration);
|
||||
|
||||
// Registration detail + forms — optionalAuth so guests can access with just the registrationId
|
||||
router.get('/:id', optionalAuth, getRegistrationById);
|
||||
router.get('/:id/forms/draft', optionalAuth, getFormDraft);
|
||||
router.put('/:id/forms/draft', optionalAuth, saveFormDraft);
|
||||
router.post('/:id/forms/responses', optionalAuth, submitFormResponses);
|
||||
router.put('/:id/forms/responses', protect, supervisor, replaceFormResponses);
|
||||
|
||||
// Admin/Staff routes
|
||||
router.get('/', protect, staff, getRegistrations);
|
||||
router.put('/:id', protect, staff, updateRegistrationStatus);
|
||||
router.get('/event/:eventId', protect, staff, getRegistrationsByEvent);
|
||||
router.post('/manual', protect, supervisor, createManualRegistration);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { generatePdf, emailPdf } = require('../controllers/reportController');
|
||||
const { protect } = require('../middleware/authMiddleware');
|
||||
|
||||
// Generate and download PDF
|
||||
router.post('/pdf', protect, generatePdf);
|
||||
|
||||
// Email PDF to current user
|
||||
router.post('/email', protect, emailPdf);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,11 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { listScheduledEmails, updateScheduledEmail, deleteScheduledEmail } = require('../controllers/scheduledEmailsController');
|
||||
const { protect, supervisor } = require('../middleware/authMiddleware');
|
||||
|
||||
// All routes require supervisor (or admin via middleware logic) access
|
||||
router.get('/', protect, supervisor, listScheduledEmails);
|
||||
router.patch('/:id', protect, supervisor, updateScheduledEmail);
|
||||
router.delete('/:id', protect, supervisor, deleteScheduledEmail);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,16 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
getSections,
|
||||
createSection,
|
||||
deleteSection,
|
||||
updateSection
|
||||
} = require('../controllers/sectionController');
|
||||
const { protect, admin, supervisor, staff } = require('../middleware/authMiddleware');
|
||||
|
||||
router.get('/', protect, staff, getSections);
|
||||
router.post('/', protect, supervisor, createSection);
|
||||
router.delete('/:id', protect, admin, deleteSection);
|
||||
router.put('/:id', protect, supervisor, updateSection);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getSettings, getAllSettings, updateSettings, needsSetup, testSmtp } = require('../controllers/settingsController');
|
||||
const { protect, admin } = require('../middleware/authMiddleware');
|
||||
|
||||
router.get('/needs-setup', needsSetup);
|
||||
router.get('/all', protect, admin, getAllSettings);
|
||||
router.get('/', getSettings);
|
||||
router.put('/', protect, admin, updateSettings);
|
||||
router.post('/test-smtp', protect, admin, testSmtp);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { setupRegister, runSetup } = require('../controllers/settingsController');
|
||||
const { protect, admin } = require('../middleware/authMiddleware');
|
||||
|
||||
// Step 1 of setup: create the admin account, returns a JWT token
|
||||
router.post('/register', setupRegister);
|
||||
|
||||
// Step 2 of setup: finalize settings (requires the token from /register)
|
||||
router.post('/', protect, admin, runSetup);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,13 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getStaffDashboardStats, getSupervisorDashboardStats, getAdminDashboardStats } = require('../controllers/statsController');
|
||||
const { protect, staff, supervisor, admin } = require('../middleware/authMiddleware');
|
||||
|
||||
// One endpoint per dashboard — each returns exactly what that dashboard renders in a
|
||||
// single response instead of the dashboard making several separate calls (and, previously,
|
||||
// pulling full payments/events lists just to reduce them to a couple of numbers).
|
||||
router.get('/staff', protect, staff, getStaffDashboardStats);
|
||||
router.get('/supervisor', protect, supervisor, getSupervisorDashboardStats);
|
||||
router.get('/admin', protect, admin, getAdminDashboardStats);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,39 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
generateTickets,
|
||||
getTickets,
|
||||
getUserTickets,
|
||||
getTicketById,
|
||||
getTicketByQrCode,
|
||||
getScanPreview,
|
||||
scanTicket,
|
||||
getTicketsByEvent,
|
||||
markTicketsAsEmailSent,
|
||||
emailTickets,
|
||||
sendTicketsTo,
|
||||
getRecentScans,
|
||||
getScanStats
|
||||
} = require('../controllers/ticketController');
|
||||
const { protect, admin, supervisor, staff } = require('../middleware/authMiddleware');
|
||||
|
||||
// Protected routes
|
||||
router.get('/mytickets', protect, getUserTickets);
|
||||
router.get('/:id', protect, getTicketById);
|
||||
router.post('/email', protect, emailTickets);
|
||||
|
||||
// Staff routes
|
||||
router.post('/send-to', protect, staff, sendTicketsTo);
|
||||
router.get('/scan-preview/:qrCode', protect, staff, getScanPreview);
|
||||
router.get('/qr/:qrCode', protect, staff, getTicketByQrCode);
|
||||
router.post('/scan/:qrCode', protect, staff, scanTicket);
|
||||
router.get('/event/:eventId', protect, staff, getTicketsByEvent);
|
||||
router.get('/scans/recent', protect, staff, getRecentScans);
|
||||
router.get('/scans/stats', protect, staff, getScanStats);
|
||||
|
||||
// Admin routes
|
||||
router.post('/generate', protect, supervisor, generateTickets);
|
||||
router.get('/', protect, supervisor, getTickets);
|
||||
router.put('/email-sent', protect, admin, markTicketsAsEmailSent);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,41 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const { upload, uploadEventImage, uploadLogo, uploadLogoImage } = 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);
|
||||
|
||||
// @route POST /api/uploads/logo
|
||||
// @desc Upload site logo — admin, OR allowed during first-time setup (no users yet)
|
||||
// @access Admin or setup
|
||||
|
||||
async function logoAccess(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));
|
||||
}
|
||||
}
|
||||
|
||||
router.post('/logo', logoAccess, (req, res, next) => {
|
||||
uploadLogo.single('image')(req, res, (err) => {
|
||||
if (err) req.multerError = err;
|
||||
next();
|
||||
});
|
||||
}, uploadLogoImage);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,52 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
registerUser,
|
||||
loginUser,
|
||||
getUserProfile,
|
||||
updateUserProfile,
|
||||
getUsers,
|
||||
checkUserExists,
|
||||
getUserById,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
anonymizeUser,
|
||||
requestPasswordReset,
|
||||
resetPassword,
|
||||
activateAccount,
|
||||
revokeMySession,
|
||||
adminRevokeUserSessions,
|
||||
closeAccount,
|
||||
} = require('../controllers/userController');
|
||||
const { protect, admin, supervisor, loginLimiter} = require('../middleware/authMiddleware');
|
||||
|
||||
// Public routes
|
||||
router.post('/', registerUser);
|
||||
router.post('/login', loginLimiter, loginUser);
|
||||
router.post('/forgot', requestPasswordReset);
|
||||
router.post('/reset', resetPassword);
|
||||
router.post('/activate', activateAccount);
|
||||
|
||||
// Protected routes
|
||||
router.route('/profile')
|
||||
.get(protect, getUserProfile)
|
||||
.put(protect, updateUserProfile);
|
||||
|
||||
router.post('/revoke-sessions', protect, revokeMySession);
|
||||
router.post('/close-account', protect, closeAccount);
|
||||
|
||||
// Admin routes
|
||||
router.route('/')
|
||||
.get(protect, supervisor, getUsers);
|
||||
|
||||
router.get('/check-exists', protect, supervisor, checkUserExists);
|
||||
|
||||
router.route('/:id')
|
||||
.get(protect, admin, getUserById)
|
||||
.put(protect, admin, updateUser)
|
||||
.delete(protect, admin, deleteUser);
|
||||
|
||||
router.post('/:id/revoke-sessions', protect, admin, adminRevokeUserSessions);
|
||||
router.post('/:id/anonymize', protect, admin, anonymizeUser);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,9 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { handleYocoWebhook, handleWhatsappWebhook } = require('../controllers/webhookController');
|
||||
|
||||
// Yoco webhook endpoint
|
||||
router.post('/yoco', handleYocoWebhook);
|
||||
router.post('/whatsapp', handleWhatsappWebhook);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { previewWhatsAppBroadcast, sendWhatsAppBroadcast, scheduleWhatsAppBroadcast } = require('../controllers/whatsappBroadcastController');
|
||||
const { protect, supervisor } = require('../middleware/authMiddleware');
|
||||
|
||||
router.post('/preview', protect, supervisor, previewWhatsAppBroadcast);
|
||||
router.post('/send', protect, supervisor, sendWhatsAppBroadcast);
|
||||
router.post('/schedule', protect, supervisor, scheduleWhatsAppBroadcast);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,37 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
getConfigHandler,
|
||||
saveConfigHandler,
|
||||
createInstanceHandler,
|
||||
deleteInstanceHandler,
|
||||
getStatusHandler,
|
||||
getQrHandler,
|
||||
requestCodeHandler,
|
||||
logoutHandler,
|
||||
startHandler,
|
||||
restartHandler,
|
||||
handleWebhook,
|
||||
} = require('../controllers/whatsappController');
|
||||
const { protect, admin } = require('../middleware/authMiddleware');
|
||||
|
||||
// Public webhook (called by WAWP servers)
|
||||
router.post('/webhook', handleWebhook);
|
||||
|
||||
// Admin-only: credentials config
|
||||
router.get( '/config', protect, admin, getConfigHandler);
|
||||
router.post('/config', protect, admin, saveConfigHandler);
|
||||
|
||||
// Admin-only: instance lifecycle
|
||||
router.post('/create-instance', protect, admin, createInstanceHandler);
|
||||
router.post('/delete-instance', protect, admin, deleteInstanceHandler);
|
||||
|
||||
// Admin-only: session management
|
||||
router.get( '/status', protect, admin, getStatusHandler);
|
||||
router.get( '/qr', protect, admin, getQrHandler);
|
||||
router.post('/request-code', protect, admin, requestCodeHandler);
|
||||
router.post('/logout', protect, admin, logoutHandler);
|
||||
router.post('/start', protect, admin, startHandler);
|
||||
router.post('/restart', protect, admin, restartHandler);
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,18 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getAllYocoTransactions, getUnreconciledYocoTransactions, reconcileYocoTransaction, ignoreYocoTransaction } = require('../controllers/yocoTransactionsController');
|
||||
const { protect, supervisor} = require('../middleware/authMiddleware');
|
||||
|
||||
// GET all Yoco transactions (admin/supervisor)
|
||||
router.get('/', protect, supervisor, getAllYocoTransactions);
|
||||
|
||||
// GET all unreconciled Yoco transactions (admin/supervisor)
|
||||
router.get('/unreconciled', protect, supervisor, getUnreconciledYocoTransactions);
|
||||
|
||||
// POST reconcile a Yoco transaction
|
||||
router.post('/:id/reconcile', protect, supervisor, reconcileYocoTransaction);
|
||||
|
||||
// POST ignore a Yoco transaction
|
||||
router.post('/:id/ignore', protect, supervisor, ignoreYocoTransaction);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user