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.
224 lines
6.4 KiB
224 lines
6.4 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';
|
|
|
|
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', this.populateClientId.bind(this));
|
|
router.param('projectId', this.populateProjectId.bind(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(
|
|
'/',
|
|
limiterService.create(limiterConfig.postCreateClient),
|
|
this.postCreateClient.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.getClientCreate),
|
|
this.getClientCreate.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 populateClientId (req, res, next, clientId) {
|
|
const { client: clientService } = this.dtp.services;
|
|
try {
|
|
res.locals.client = await clientService.getClientById(clientId);
|
|
if (!res.locals.client) {
|
|
throw new SiteError(404, 'Client not found');
|
|
}
|
|
if (!res.locals.client.user._id.equals(req.user._id)) {
|
|
throw new SiteError(401, 'This is not your client');
|
|
}
|
|
return next();
|
|
} catch (error) {
|
|
this.log.error('failed to populate client', { error });
|
|
return next(error);
|
|
}
|
|
}
|
|
|
|
async populateProjectId (req, res, next, projectId) {
|
|
const { client: clientService } = this.dtp.services;
|
|
try {
|
|
res.locals.project = await clientService.getProjectById(projectId);
|
|
if (!res.locals.project) {
|
|
throw new SiteError(404, 'Project not found');
|
|
}
|
|
if (!res.locals.project.user._id.equals(req.user._id)) {
|
|
throw new SiteError(401, 'This is not your project');
|
|
}
|
|
return next();
|
|
} catch (error) {
|
|
this.log.error('failed to populate project', { error });
|
|
return next(error);
|
|
}
|
|
}
|
|
|
|
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 postCreateClient (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 getClientCreate (req, res) {
|
|
res.render('client/create');
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|