// user.js // Copyright (C) 2021 Digital Telepresence, LLC // License: Apache-2.0 'use strict'; const DTP_COMPONENT_NAME = 'user'; const express = require('express'); const mongoose = require('mongoose'); const multer = require('multer'); const { SiteController, SiteError } = require('../../lib/site-lib'); class UserController extends SiteController { constructor (dtp) { super(dtp, DTP_COMPONENT_NAME); } async start ( ) { const { dtp } = this; const { limiter: limiterService, otpAuth: otpAuthService } = dtp.services; const upload = multer({ dest: "/tmp" }); const router = express.Router(); dtp.app.use('/user', router); const otpMiddleware = otpAuthService.middleware('Account', { adminRequired: false, otpRequired: false, otpRedirectURL: async (req) => { return `/user/${req.user._id}`; }, }); router.use( async (req, res, next) => { try { res.locals.currentView = 'user'; res.locals.pageTitle = 'Manage your user account.'; return next(); } catch (error) { return next(error); } }, ); async function checkProfileOwner (req, res, next) { if (!req.user || !req.user._id.equals(res.locals.userProfile._id)) { return next(new SiteError(403, 'This is not your user account or profile')); } return next(); } router.param('userId', this.populateUser.bind(this)); router.post('/:userId/settings', limiterService.create(limiterService.config.user.postUpdateSettings), upload.none(), this.postUpdateSettings.bind(this), ); router.post('/', limiterService.create(limiterService.config.user.postCreate), this.postCreateUser.bind(this), ); router.get('/:userId/settings', limiterService.create(limiterService.config.user.getSettings), otpMiddleware, checkProfileOwner, this.getUserSettingsView.bind(this), ); router.get('/:userId', limiterService.create(limiterService.config.user.getUserProfile), otpMiddleware, checkProfileOwner, this.getUserView.bind(this), ); } async populateUser (req, res, next, userId) { const { user: userService } = this.dtp.services; try { userId = mongoose.Types.ObjectId(userId); } catch (error) { return next(new SiteError(406, 'Invalid User')); } try { if (!req.user._id.equals(userId)) { return next(new Error('Invalid account ID')); } res.locals.userProfile = await userService.getUserAccount(userId); return next(); } catch (error) { this.log.error('failed to populate userId', { userId, error }); return next(error); } } async postCreateUser (req, res, next) { const { user: userService } = this.dtp.services; try { res.locals.user = await userService.create(req.body); req.login(res.locals.user, (error) => { if (error) { return next(error); } res.redirect(`/user/${res.locals.user._id}`); }); } catch (error) { this.log.error('failed to create new user', { error }); return next(error); } } async postUpdateSettings (req, res) { const { user: userService, displayEngine: displayEngineService } = this.dtp.services; try { const displayList = displayEngineService.createDisplayList('app-settings'); await userService.updateSettings(req.user, req.body); displayList.showNotification( 'Member account settings updated successfully.', 'success', 'bottom-center', 6000, ); res.status(200).json({ success: true, displayList }); } catch (error) { this.log.error('failed to update account settings', { error }); return res.status(error.statusCode || 500).json({ success: false, message: error.message, }); } } async getUserSettingsView (req, res, next) { try { res.locals.startTab = req.query.st || 'watch'; res.render('user/settings'); } catch (error) { this.log.error('failed to produce user settings view', { error }); return next(error); } } async getUserView (req, res, next) { try { res.render('user/profile'); } catch (error) { this.log.error('failed to produce user profile view', { error }); return next(error); } } } module.exports = async (dtp) => { let controller = new UserController(dtp); return controller; };