Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/controllers/activityLogController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const ActivityLog = require('../models/activityLog');
const StudentLog = require('../models/studentLog');
const { hasPermission } = require('../utilities/permissions');

const activityLogController = function () {
async function fetchSupportDailyLog(req, res) {
try {
const { studentId } = req.params;
const { requestor } = req.body;

if (!studentId) return res.status(400).json({ error: 'Missing studentId' });

if (!(await hasPermission(requestor, 'fetchSupportDailyLog'))) {
return res
.status(403)
.json({ error: 'Forbidden: Only support role can access this endpoint' });
}

// Fetch logs for the specified student asssuming this
// student is a assigned to the support staff.
// Need to add a check for that in the future.
const logs = await StudentLog.find({studentId}).sort({date:-1}) ;


// Log the activity of viewing the student's daily log
await ActivityLog.create({
actor_id: requestor.requestorId,
action_type: 'view_student_daily_log',
metadata: { viewedStudentId: studentId },
created_at: new Date(),
});

// Return the all logs to the client.
res.json(logs);

} catch (err) {
console.log(err);
res.status(500).json({ error: err.message });
}
}

return {
fetchSupportDailyLog,
};
};

module.exports = activityLogController;
27 changes: 27 additions & 0 deletions src/models/activityLog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const mongoose = require('mongoose');

const ActivityLogSchema = new mongoose.Schema(
{
actor_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'UserProfile',
required: true,
},
action_type: {
type: String,
required: true,
},
metadata: {
type: mongoose.Schema.Types.Mixed,
default: {},
},
},
{
timestamps: {
createdAt: 'created_at',
updatedAt: false,
},
},
);

module.exports = mongoose.model('ActivityLog', ActivityLogSchema);
19 changes: 19 additions & 0 deletions src/models/studentLog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const mongoose = require('mongoose');

const StudentLogSchema = new mongoose.Schema({
studentId: {
type: String,
required: true
},
date: {
type: Date,
required: true
},
log: {
type: String,
required: true
},
})

module.exports = mongoose.model('StudentLog', StudentLogSchema);

11 changes: 11 additions & 0 deletions src/routes/activityLogRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const express = require('express');
const activityLogRouter = express.Router();
// Invoke the controller factory
const controller = require('../controllers/activityLogController')();

activityLogRouter
.route('/:studentId')
.get(controller.fetchSupportDailyLog);

// Export the INSTANCE
module.exports = activityLogRouter;
55 changes: 23 additions & 32 deletions src/startup/middleware.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/* eslint-disable complexity */
/* eslint-disable no-magic-numbers */
const jwt = require('jsonwebtoken');
const moment = require('moment');

const express = require('express');
const config = require('../config');
const webhookController = require('../controllers/lbdashboard/webhookController'); // your new controller
const { Bids } = require('../models/lbdashboard/bids'); // or wherever you're getting Bids

const { webhookTest } = webhookController(Bids);

const jwtVerificationLogic = require('../utilities/jwtVerificationLogic');

const paypalAuthMiddleware = (req, res, next) => {
const authHeader = req.header('Paypal-Auth-Algo');
if (!authHeader) {
Expand Down Expand Up @@ -123,40 +123,31 @@ module.exports = function (app) {
if (openPaths.includes(req.path)) {
return next(); // Allow PayPal requests through
}
if (!req.header('Authorization')) {
res.status(401).send({ 'error:': 'Unauthorized request' });
return;
}
const authToken = req.header(config.REQUEST_AUTHKEY);

let payload = '';
// HEADER EXTRACTION
const authHeader = req.header('Authorization');
const payload = jwtVerificationLogic(authHeader, res);

try {
payload = jwt.verify(authToken, config.JWT_SECRET);
} catch (error) {
res.status(401).send('Invalid token');
return;
}
if (
!payload ||
!payload.expiryTimestamp ||
!payload.userid ||
!payload.role ||
moment().isAfter(payload.expiryTimestamp)
) {
res.status(401).send('Unauthorized request');
return;
}
// FIX: If payload is a response object (meaning logic already sent a 401), STOP HERE.
if (res.headersSent) return;

// ATTACH DATA & CONTINUE
// Now we know payload is the valid decoded token
const requestor = {
requestorId: payload.userid,
role: payload.role,
permissions: payload.permissions,
};

const requestor = {};
requestor.requestorId = payload.userid;
requestor.role = payload.role;
requestor.permissions = payload.permissions;
req.user = requestor;

req.body.requestor = requestor;
next();
if (req.body) {
req.body.requestor = requestor;
}

return next();
});

// Apply PayPal middleware only to specific route
// PROTECTED ROUTES
app.post('/api/lb/myWebhooks/', paypalAuthMiddleware, webhookTest);
};
4 changes: 4 additions & 0 deletions src/startup/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,15 @@ const recipeRouter = require('../routes/kitchenInventory/recipeRouter')();

const jobHitsAndApplicationsRoutes = require('../routes/jobAnalytics/JobHitsAndApplicationsRoutes');


// Education Portal
const educatorRoutes = require('../routes/educatorRoutes');
const activityLogRouter = require('../routes/activityLogRouter');


module.exports = function (app) {
app.use('/api/bm/summary-dashboard', summaryDashboardRouter);
app.use('/api/support/daily-log', activityLogRouter);
app.use('/api', forgotPwdRouter);
app.use('/api', loginRouter);
app.use('/api', forcePwdRouter);
Expand Down
34 changes: 34 additions & 0 deletions src/utilities/jwtVerificationLogic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const moment = require('moment');
const config = require('../config');
const jwt = require('jsonwebtoken');

const jwtVerificationLogic = (authHeader, res) => {
if (!authHeader) {
return res.status(401).json({ error: 'Unauthorized request: No header' });
}

let authToken = authHeader;
// If it has Bearer, strip it. If not, use it as is.
if (authHeader.startsWith('Bearer ')) {
[, authToken] = authHeader.split(' ');
}

let payload;
try {
payload = jwt.verify(authToken, config.JWT_SECRET);
} catch (error) {
return res.status(401).json({ error: 'Invalid token', details: error.message });
}

// Ensure mock date in test is not in the past
const isExpired = moment().isAfter(payload.expiryTimestamp);
if (!payload.userid || !payload.role || isExpired) {
// eslint-disable-next-line no-console
console.log('Auth failed. Expiry:', payload.expiryTimestamp);
return res.status(401).send('Unauthorized request: Token expired or invalid payload');
}

return payload;
};

module.exports = jwtVerificationLogic;
Loading