DTP Base provides a scalable and secure Node.js application development harness ready for production service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

257 lines
7.5 KiB

// task.js
// Copyright (C) 2024 DTP Technologies, LLC
// All Rights Reserved
'use strict';
import express from 'express';
import { SiteController, SiteError } from '../../lib/site-lib.js';
import { populateTaskId, populateSessionId } from './lib/populators.js';
export default class TaskController extends SiteController {
static get name ( ) { return 'TaskController'; }
static get slug ( ) { return 'task'; }
constructor (dtp) {
super(dtp, TaskController);
}
async start ( ) {
const { dtp } = this;
const {
limiter: limiterService,
session: sessionService,
} = dtp.services;
const limiterConfig = limiterService.config.task;
const multer = this.createMulter(TaskController.slug, {
limits: {
fileSize: 1024 * 1000 * 5,
},
});
const authCheck = sessionService.authCheckMiddleware({ requireLogin: true });
const router = express.Router();
dtp.app.use('/task', authCheck, router);
router.use(async (req, res, next) => {
res.locals.currentView = TaskController.name;
return next();
});
async function checkTaskOwnership (req, res, next) {
if (Array.isArray(res.locals.task.project.managers) && (res.locals.task.project.managers.length > 0)) {
res.locals.manager = res.locals.task.project.managers.find((manager) => manager._id.equals(req.user._id));
}
if (!res.locals.manager && !res.locals.task.user._id.equals(req.user._id)) {
return next(new SiteError(401, 'This is not your task'));
}
return next();
}
async function checkSessionOwnership (req, res, next) {
if (Array.isArray(res.locals.task.project.managers) && (res.locals.task.project.managers.length > 0)) {
res.locals.manager = res.locals.task.project.managers.find((manager) => manager._id.equals(req.user._id));
}
if (!res.locals.manager && !res.locals.session.user._id.equals(req.user._id)) {
throw new SiteError(401, 'This is not your session');
}
return next();
}
router.param('taskId', populateTaskId(this));
router.param('sessionId', populateSessionId(this));
router.post(
'/:taskId/session/start',
limiterService.create(limiterConfig.postStartTaskSession),
this.postStartTaskSession.bind(this),
);
router.post(
'/:taskId/session/:sessionId/screenshot',
checkSessionOwnership,
limiterService.create(limiterConfig.postTaskSessionScreenshot),
multer.single('image'),
this.postTaskSessionScreenshot.bind(this),
);
router.post(
'/:taskId/session/:sessionId/status',
limiterService.create(limiterConfig.postTaskSessionStatus),
checkSessionOwnership,
this.postTaskSessionStatus.bind(this),
);
router.post(
'/:taskId/session/:sessionId/close',
limiterService.create(limiterConfig.postCloseTaskSession),
checkSessionOwnership,
this.postCloseTaskSession.bind(this),
);
router.post(
'/:taskId/start',
limiterService.create(limiterConfig.postStartTask),
checkTaskOwnership,
this.postStartTask.bind(this),
);
router.post(
'/:taskId/close',
limiterService.create(limiterConfig.postCloseTask),
checkTaskOwnership,
this.postCloseTask.bind(this),
);
router.post(
'/',
limiterService.create(limiterConfig.postCreateTask),
this.postCreateTask.bind(this),
);
router.get(
'/:taskId/session/:sessionId',
limiterService.create(limiterConfig.getTaskSessionView),
checkSessionOwnership,
this.getTaskSessionView.bind(this),
);
router.get(
'/:taskId',
limiterService.create(limiterConfig.getTaskView),
checkTaskOwnership,
this.getTaskView.bind(this),
);
}
async postStartTaskSession (req, res) {
const { task: taskService } = this.dtp.services;
try {
res.locals.session = await taskService.createTaskSession(res.locals.task);
res.status(200).json({
success: true,
session: res.locals.session,
});
} catch (error) {
this.log.error('failed to create task session', { error });
res.status(error.statusCode || 500).json({
success: false,
message: error.message,
});
}
}
async postTaskSessionScreenshot (req, res) {
const { task: taskService } = this.dtp.services;
try {
await taskService.addTaskSessionScreenshot(res.locals.session, req.file);
res.status(200).json({ success: true });
} catch (error) {
this.log.error('failed to add task session screenshot', { error });
res.status(error.statusCode || 500).json({
success: false,
message: error.message,
});
}
}
async postTaskSessionStatus (req, res) {
const { task: taskService } = this.dtp.services;
try {
this.log.debug('updating task session status', {
sessionId: res.locals.session._id,
params: req.body,
});
await taskService.setTaskSessionStatus(res.locals.session, req.body.status);
const displayList = this.createDisplayList('set-session-status');
displayList.showNotification(
'Session status updated',
'success',
'bottom-center',
5000,
);
res.status(200).json({ success: true, displayList });
} catch (error) {
this.log.error('failed to update task session status', { error });
res.status(error.statusCode || 500).json({
success: false,
message: error.message,
});
}
}
async postCloseTaskSession (req, res) {
const { task: taskService } = this.dtp.services;
try {
await taskService.closeTaskSession(res.locals.session);
res.status(200).json({ success: true });
} catch (error) {
this.log.error('failed to close task session', { error });
res.status(error.statusCode || 500).json({
success: false,
message: error.message,
});
}
}
async postStartTask (req, res, next) {
const { task: taskService } = this.dtp.services;
try {
await taskService.startTask(res.locals.task);
res.redirect(`/task/${res.locals.task._id}`);
} catch (error) {
this.log.error('failed to close task session', { error });
return next(error);
}
}
async postCloseTask (req, res, next) {
const { task: taskService } = this.dtp.services;
try {
await taskService.closeTask(res.locals.task);
res.redirect('/');
} catch (error) {
this.log.error('failed to close task', { error });
return next(error);
}
}
async postCreateTask (req, res, next) {
const { task: taskService } = this.dtp.services;
try {
res.locals.task = await taskService.createTask(req.user, req.body);
res.redirect(`/task/${res.locals.task._id}`);
} catch (error) {
this.log.error('failed to create new task', { error });
return next(error);
}
}
async getTaskSessionView (req, res) {
res.render('task/session/view');
}
async getTaskView (req, res, next) {
const { report: reportService, task: taskService } = this.dtp.services;
try {
res.locals.pagination = this.getPaginationParameters(req, 50);
res.locals.sessions = await taskService.getSessionsForTask(
res.locals.task,
res.locals.pagination,
);
res.locals.weekStartDate = reportService.startOfWeek();
res.render('task/view');
} catch (error) {
this.log.error('failed to present the Task view', { error });
return next(error);
}
}
}