// 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); this.dtp = dtp; } async start ( ) { const { dtp } = this; const router = express.Router(); dtp.app.use('/client', router); const { limiter: limiterService } = dtp.services; const limiterConfig = limiterService.config.client; 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(); } router.param('clientId', this.populateClientId.bind(this)); router.param('projectId', this.populateProjectId.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', 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 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/create'); } 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); } } }