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.
 
 
 
 

216 lines
6.0 KiB

// client.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 { populateClientId, populateProjectId } from './lib/populators.js';
export default class ClientController extends SiteController {
static get name ( ) { return 'ClientController'; }
static get slug ( ) { return 'client'; }
constructor (dtp) {
super(dtp, ClientController.slug);
}
async start ( ) {
const { dtp } = this;
const {
limiter: limiterService,
session: sessionService,
} = dtp.services;
const limiterConfig = limiterService.config.client;
const authCheck = sessionService.authCheckMiddleware({ requireLogin: true });
function checkClientOwnership (req, res, next) {
if (!res.locals.client.user._id.equals(req.user._id)) {
throw new SiteError(401, 'This is not your client');
}
return next();
}
function checkProjectOwnership (req, res, next) {
if (!res.locals.project.user._id.equals(req.user._id)) {
throw new SiteError(401, 'This is not your client');
}
return next();
}
const router = express.Router();
dtp.app.use('/client', authCheck, router);
router.param('clientId', populateClientId(this));
router.param('projectId', populateProjectId(this));
router.post(
'/:clientId/project/:projectId',
limiterService.create(limiterConfig.postProjectUpdate),
checkClientOwnership,
this.postProjectUpdate.bind(this),
);
router.post(
'/:clientId/project',
limiterService.create(limiterConfig.postProjectCreate),
checkClientOwnership,
this.postProjectCreate.bind(this),
);
router.post(
'/:clientId',
limiterService.create(limiterConfig.postClientUpdate),
checkClientOwnership,
this.postClientUpdate.bind(this),
);
router.post(
'/',
limiterService.create(limiterConfig.postClientCreate),
this.postClientCreate.bind(this),
);
router.get(
'/:clientId/project/create',
limiterService.create(limiterConfig.getProjectCreate),
checkClientOwnership,
this.getProjectCreate.bind(this),
);
router.get(
'/:clientId/project/:projectId/edit',
limiterService.create(limiterConfig.getProjectEditor),
checkProjectOwnership,
this.getProjectEditor.bind(this),
);
router.get(
'/:clientId/project/:projectId',
limiterService.create(limiterConfig.getProjectView),
checkProjectOwnership,
this.getProjectView.bind(this),
);
router.get(
'/create',
limiterService.create(limiterConfig.getClientEditor),
this.getClientEditor.bind(this),
);
router.get(
'/:clientId/edit',
limiterService.create(limiterConfig.getClientEditor),
checkClientOwnership,
this.getClientEditor.bind(this),
);
router.get(
'/:clientId',
limiterService.create(limiterConfig.getClientView),
checkClientOwnership,
this.getClientView.bind(this),
);
router.get(
'/',
limiterService.create(limiterConfig.getHome),
this.getHome.bind(this),
);
return router;
}
async postProjectUpdate (req, res, next) {
const { client: clientService } = this.dtp.services;
try {
await clientService.updateProject(res.locals.project, req.body);
res.redirect(`/client/${res.locals.client._id}/project/${res.locals.project._id}`);
} catch (error) {
this.log.error('failed to update client project', { error });
return next(error);
}
}
async postProjectCreate (req, res, next) {
const { client: clientService } = this.dtp.services;
try {
res.locals.project = await clientService.createProject(res.locals.client, req.body);
res.redirect(`/client/${res.locals.client._id}/project/${res.locals.project._id}`);
} catch (error) {
this.log.error('failed to create client project', { error });
return next(error);
}
}
async postClientUpdate (req, res, next) {
const { client: clientService } = this.dtp.services;
try {
await clientService.updateClient(res.locals.client, req.body);
res.redirect(`/client/${res.locals.client._id}`);
} catch (error) {
this.log.error('failed to create client', { error });
return next(error);
}
}
async postClientCreate (req, res, next) {
const { client: clientService } = this.dtp.services;
try {
res.locals.client = await clientService.createClient(req.user, req.body);
res.redirect(`/client/${res.locals.client._id}`);
} catch (error) {
this.log.error('failed to create client', { error });
return next(error);
}
}
async getProjectCreate (req, res) {
res.render('client/project/editor');
}
async getProjectEditor (req, res) {
res.render('client/project/editor');
}
async getProjectView (req, res, next) {
const { task: taskService } = this.dtp.services;
try {
res.locals.taskGrid = await taskService.getTaskGridForProject(res.locals.project);
res.render('client/project/view');
} catch (error) {
this.log.error('failed to present project view', { error });
return next(error);
}
}
async getClientEditor (req, res) {
res.render('client/editor');
}
async getClientView (req, res, next) {
const { client: clientService } = this.dtp.services;
try {
res.locals.projects = await clientService.getProjectsForClient(res.locals.client);
res.render('client/view');
} catch (error) {
this.log.error('failed to present client home view', { error });
return next(error);
}
}
async getHome (req, res, next) {
const { client: clientService } = this.dtp.services;
try {
res.locals.clients = await clientService.getClientsForUser(req.user);
res.render('client/dashboard');
} catch (error) {
this.log.error('failed to present client home view', { error });
return next(error);
}
}
}