// 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); } } }