tractatus/src/routes/contact.routes.js
TheFlow fe3035913e feat(crm): implement unified contact form system
Complete CRM foundation with contact modal in footer

Backend:
- Contact.model.js: Full CRUD model with statistics tracking
- contact.controller.js: Submit, list, assign, respond, update, delete
- contact.routes.js: Public submission + admin management endpoints
- routes/index.js: Mount contact routes at /api/contact

Frontend:
- footer.js: Replace mailto link with Contact Us modal button
- Contact modal: Form with type, name, email, org, subject, message
- CSRF protection: Extracts token from cookie (like newsletter)
- Rate limiting: formRateLimiter (5/min)
- Validation: Input sanitization + required fields
- UX: Success/error messages, auto-close on success

Admin UI:
- navbar-admin.js: New 'CRM & Communications' section
- Links: Contact Management, Case Submissions, Media Inquiries

Foundation for multi-project CRM across tractatus, family-history, sydigital

Next: Build /admin/contact-management.html page
2025-10-24 16:56:21 +13:00

95 lines
2.9 KiB
JavaScript

/**
* Contact Routes
* Public contact form and admin management
*/
const express = require('express');
const router = express.Router();
const contactController = require('../controllers/contact.controller');
const { authenticateToken, requireRole } = require('../middleware/auth.middleware');
const { validateRequired } = require('../middleware/validation.middleware');
const { asyncHandler } = require('../middleware/error.middleware');
const { createInputValidationMiddleware } = require('../middleware/input-validation.middleware');
const { formRateLimiter } = require('../middleware/rate-limit.middleware');
const { csrfProtection } = require('../middleware/csrf-protection.middleware');
/**
* Public Routes
*/
// Validation schema for contact submission
const contactSubmitSchema = {
'type': { required: false, type: 'string', maxLength: 50 },
'name': { required: true, type: 'name', maxLength: 100 },
'email': { required: true, type: 'email', maxLength: 254 },
'organization': { required: false, type: 'string', maxLength: 200 },
'phone': { required: false, type: 'phone', maxLength: 50 },
'subject': { required: false, type: 'string', maxLength: 200 },
'message': { required: true, type: 'string', maxLength: 5000 }
};
// POST /api/contact/submit - Submit contact form
router.post('/submit',
formRateLimiter, // 5 requests per minute
csrfProtection, // CSRF validation
createInputValidationMiddleware(contactSubmitSchema),
validateRequired(['name', 'email', 'message']),
asyncHandler(contactController.submit)
);
/**
* Admin Routes (require authentication)
*/
// GET /api/contact/admin/stats - Get contact statistics
router.get('/admin/stats',
authenticateToken,
requireRole('admin', 'moderator'),
asyncHandler(contactController.getStats)
);
// GET /api/contact/admin/list - List contacts with filtering
router.get('/admin/list',
authenticateToken,
requireRole('admin', 'moderator'),
asyncHandler(contactController.list)
);
// GET /api/contact/admin/:id - Get single contact
router.get('/admin/:id',
authenticateToken,
requireRole('admin', 'moderator'),
asyncHandler(contactController.getById)
);
// POST /api/contact/admin/:id/assign - Assign contact to user
router.post('/admin/:id/assign',
authenticateToken,
requireRole('admin', 'moderator'),
asyncHandler(contactController.assign)
);
// POST /api/contact/admin/:id/respond - Mark as responded
router.post('/admin/:id/respond',
authenticateToken,
requireRole('admin', 'moderator'),
validateRequired(['content']),
asyncHandler(contactController.respond)
);
// PUT /api/contact/admin/:id - Update contact
router.put('/admin/:id',
authenticateToken,
requireRole('admin', 'moderator'),
asyncHandler(contactController.update)
);
// DELETE /api/contact/admin/:id - Delete contact
router.delete('/admin/:id',
authenticateToken,
requireRole('admin'),
asyncHandler(contactController.deleteContact)
);
module.exports = router;