Dies ist App.js
/**
* Bugema University Vocational Training School Electronic Records Management System
* Main application entry point
*/
// Import required modules
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const compression = require('compression');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const helmet = require('helmet');
const cors = require('cors');
const flash = require('connect-flash');
const mongoose = require('mongoose');
const expressLayouts = require('express-ejs-layouts');
// Import custom modules
const env = require('./config/env');
const { connectToDatabase } = require('./config/database');
const { securityHeaders } = require('./config/security');
const logger = require('./utils/logger');
const { notFoundHandler, errorHandler } = require('./utils/errorHandler');
// Create Express application
const app = express();
// Set up view engine and views directory
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Set up express layouts
app.use(expressLayouts);
app.set('layout', 'layouts/main');
console.log('Step 1: Starting app.js execution...');
// Database connection and server startup
connectToDatabase()
.then(() => {
logger.info('MongoDB Atlas connection established successfully');
// Start server after successful database connection
const PORT = env.port || 3000;
console.log('Attempting to start the server...');
const server = app.listen(PORT, '0.0.0.0', function(err) {
if (err) {
console.error('ERROR STARTING SERVER:', err);
process.exit(1);
}
const serverInfo = server.address();
console.log('\n\n==========================================================');
console.log(`*** SERVER STARTED SUCCESSFULLY ***`);
console.log(`
console.log('==========================================================\n');
});
})
.catch((err) => {
logger.error(`Failed to connect to MongoDB Atlas: ${err.message}`);
process.exit(1);
});
// Security middleware
app.use(helmet({
contentSecurityPolicy: securityHeaders.contentSecurityPolicy,
xContentTypeOptions: true,
xFrameOptions: securityHeaders.xFrameOptions,
xXssProtection: true,
hsts: env.isProd ? securityHeaders.hsts : false,
referrerPolicy: securityHeaders.referrerPolicy,
}));
console.log('Middleware setup complete.');
// Request parsing middleware
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
// Cookie parser middleware
app.use(cookieParser(env.sessionSecret));
// Server-side session configuration
app.use(session({
secret: env.sessionSecret,
resave: false,
saveUninitialized: false,
store: process.env.SKIP_DB_CONNECT === 'true' ? undefined : MongoStore.create({
mongoUrl: env.mongodbUri,
ttl: 14 * 24 * 60 * 60,
autoRemove: 'native',
collectionName: 'sessions',
crypto: {
secret: env.sessionSecret,
},
}),
cookie: {
httpOnly: true,
secure: env.isProd,
sameSite: 'strict',
maxAge: 14 * 24 * 60 * 60 * 1000,
},
}));
// Verify session is being tracked
if (!env.isProd) {
app.use((req, res, next) => {
console.log('
next();
});
}
// Flash messages middleware
app.use(flash());
// Cross-Origin Resource Sharing
app.use(cors({
origin: env.isProd ? 'https://erms.bugema.ac.ug' : true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
}));
// HTTP request logging
app.use(morgan(env.isProd ? 'combined' : 'dev', { stream: logger.stream }));
// Compression middleware
app.use(compression());
// Serve static files
app.use(express.static(path.join(__dirname, 'public')));
// Custom middleware to make some variables available to all templates
app.use((req, res, next) => {
res.locals.user = req.session.user || null;
res.locals.flashMessages = req.flash();
res.locals.currentPath = req.path;
res.locals.appName = 'Bugema ERMS';
res.locals.year = new Date().getFullYear();
next();
});
// Import routes
const authRoutes = require('./routes/auth');
const authWebRoutes = require('./routes/auth-web');
const studentRoutes = require('./routes/students');
const programRoutes = require('./routes/programs');
const courseRoutes = require('./routes/courses');
const enrollmentRoutes = require('./routes/enrollments');
const assessmentRoutes = require('./routes/assessments');
const paymentRoutes = require('./routes/payments');
const documentRoutes = require('./routes/documents');
const reportRoutes = require('./routes/reports');
const adminRoutes = require('./routes/admin');
const registrarRoutes = require('./routes/registrar');
const financeRoutes = require('./routes/finance');
const userRoutes = require('./routes/users');
const dashboardRoutes = require('./routes/dashboard');
// API routes
app.use('/api/auth', authRoutes);
app.use('/api/students', studentRoutes);
app.use('/api/programs', programRoutes);
app.use('/api/courses', courseRoutes);
app.use('/api/enrollments', enrollmentRoutes);
app.use('/api/assessments', assessmentRoutes);
app.use('/api/payments', paymentRoutes);
app.use('/api/documents', documentRoutes);
app.use('/api/reports', reportRoutes);
app.use('/api/users', userRoutes);
// Web routes
app.use('/auth', authWebRoutes);
app.use('/admin', adminRoutes);
app.use('/registrar', registrarRoutes);
app.use('/finance', financeRoutes);
app.use('/dashboard', dashboardRoutes);
console.log('Routes registered.');
// Root route - redirect to login or dashboard
app.get('/', (req, res) => {
console.log('
if (req.session.user) {
const role = req.session.user.role;
switch (role) {
case 'admin':
return res.redirect('/admin/dashboard');
case 'registrar':
return res.redirect('/registrar/dashboard');
case 'finance':
return res.redirect('/finance/dashboard');
case 'student':
return res.redirect('/dashboard');
default:
return res.redirect('/auth/login');
}
} else {
console.log('
res.redirect('/auth/login');
}
});
// Error handling middleware
app.use(notFoundHandler);
app.use(errorHandler);
// Handle uncaught exceptions
process.on('uncaughtException', (err) => {
logger.error('UNCAUGHT EXCEPTION!
logger.error(`${err.name}: ${err.message}`, { stack: err.stack });
process.exit(1);
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
logger.error('UNHANDLED REJECTION!
logger.error(`${err.name}: ${err.message}`, { stack: err.stack });
process.exit(1);
});
// Check for required environment variables
if (!env.port || !env.mongodbUri || !env.jwtSecret) {
console.error('Missing required environment variables. Please check your configuration.');
process.exit(1);
}
module.exports = app;
< /code>
Dies ist auth-Web.js < /p>
/**
* Authentication Web Routes
* Routes for web authentication UI
*/
const express = require('express');
const router = express.Router();
const { authenticate } = require('../middleware/auth');
const authWebController = require('../controllers/authWebController');
// Login page
router.get('/login', (req, res) => {
// If user is already logged in, redirect to appropriate dashboard
if (req.session.user) {
const role = req.session.user.role;
switch (role) {
case 'admin':
case 'superadmin':
return res.redirect('/admin/dashboard');
case 'registrar':
return res.redirect('/registrar/dashboard');
case 'finance':
return res.redirect('/finance/dashboard');
case 'student':
return res.redirect('/dashboard');
default:
return res.redirect('/');
}
}
res.render('auth/login', {
title: 'Login',
page: 'auth',
message: req.flash('error'),
success: req.flash('success')
});
});
// Forgot password page
router.get('/forgot-password', (req, res) => {
res.render('auth/forgot-password', {
title: 'Forgot Password',
page: 'auth',
message: req.flash('error'),
success: req.flash('success')
});
});
// Process forgot password form
router.post('/forgot-password', authWebController.forgotPassword);
// Reset password page
router.get('/reset-password/:token', (req, res) => {
res.render('auth/reset-password', {
title: 'Reset Password',
page: 'auth',
token: req.params.token,
message: req.flash('error'),
success: req.flash('success')
});
});
// Process reset password form
router.post('/reset-password/:token', authWebController.resetPassword);
// Account activation page
router.get('/activate/:token', authWebController.activateAccount);
// Process login form
router.post('/login', authWebController.login);
// Logout - must be authenticated
router.get('/logout', authenticate, authWebController.logout);
module.exports = router;
this is error.ejs
Error Details:
[url=javascript:history.back()]
Go Back
[/url]
Return Home
.error-page {
padding: 2rem;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.error-page h1 {
font-size: 5rem;
color: #dc3545;
}
.error-page h2 {
color: #343a40;
}
.error-details {
max-width: 600px;
margin: 0 auto;
}
.error-actions {
margin-top: 2rem;
}
pre {
background-color: #f8f9fa;
padding: 1rem;
border-radius: 4px;
overflow-x: auto;
}
< /code>
Dies ist auth.js < /p>
/**
* Authentication Routes
* Defines routes for user authentication and profile management
*/
const express = require('express');
const router = express.Router();
const { check } = require('express-validator');
const authController = require('../controllers/authController');
const { authenticate, authorize } = require('../middleware/auth');
// Validation schemas
const registerValidation = [
check('username').trim().isLength({ min: 4, max: 20 }).withMessage('Username must be between 4 and 20 characters'),
check('email').trim().isEmail().withMessage('Please provide a valid email address'),
check('password').isLength({ min: 8 }).withMessage('Password must be at least 8 characters long'),
check('firstName').trim().notEmpty().withMessage('First name is required'),
check('lastName').trim().notEmpty().withMessage('Last name is required'),
check('role').optional().isIn(['superadmin', 'admin', 'registrar', 'finance', 'student', 'lecturer']).withMessage('Invalid role')
];
const loginValidation = [
check('login').trim().notEmpty().withMessage('Email or username is required'),
check('password').notEmpty().withMessage('Password is required')
];
const passwordResetValidation = [
check('password').isLength({ min: 8 }).withMessage('Password must be at least 8 characters long')
];
const passwordChangeValidation = [
check('currentPassword').notEmpty().withMessage('Current password is required'),
check('newPassword').isLength({ min: 8 }).withMessage('New password must be at least 8 characters long')
];
const forgotPasswordValidation = [
check('email').trim().isEmail().withMessage('Please provide a valid email address')
];
const refreshTokenValidation = [
check('refreshToken').notEmpty().withMessage('Refresh token is required')
];
const profileValidation = [
check('firstName').optional().trim().notEmpty().withMessage('First name cannot be empty'),
check('lastName').optional().trim().notEmpty().withMessage('Last name cannot be empty'),
check('phoneNumber').optional().trim().matches(/^\+?[0-9]{10,15}$/).withMessage('Please provide a valid phone number')
];
// Public routes (no authentication required)
router.post('/register', registerValidation, authController.register);
router.post('/login', loginValidation, authController.login);
router.get('/verify/:token', authController.verifyEmail);
router.post('/forgot-password', forgotPasswordValidation, authController.forgotPassword);
router.post('/reset-password/:token', passwordResetValidation, authController.resetPassword);
router.post('/refresh-token', refreshTokenValidation, authController.refreshToken);
router.post('/logout', refreshTokenValidation, authController.logout);
// Protected routes (authentication required)
router.use(authenticate);
router.get('/me', authController.getProfile);
router.patch('/profile', profileValidation, authController.updateProfile);
router.post('/change-password', passwordChangeValidation, authController.changePassword);
// Admin-only routes
router.post('/register-admin',
authenticate,
authorize(['superadmin', 'admin']),
registerValidation,
authController.register
);
module.exports = router;
< /code>
Hier wird handelt, wenn ich auf den Link klicke < /p>
2025-05-18 20:42:13 info: Successfully connected to MongoDB Atlas
2025-05-18 20:42:13 info: MongoDB Atlas connection established successfully
Attempting to start the server...
==========================================================
*** SERVER STARTED SUCCESSFULLY ***
==========================================================
cookie: {
path: '/',
_expires: 2025-05-31T07:25:36.990Z,
originalMaxAge: 1209600000,
httpOnly: true,
secure: false,
sameSite: 'strict'
},
flash: {}
}
2025-05-18 20:42:19 info: GET / 404 1.789 ms - 139
^Z
[1]+ Stopped npm run dev
snow@snow:~/Desktop/ERMS$
< /code>
Ich möchte, wenn ich auf den Link klicke. die Seiten (Anmeldung) wie erwartet geöffnet.