const express = require('express') const router = express.Router() const db = require('@QMI/qmi-cloud-common/mongo'); const passport = require('../passport-okta'); const fs = require('fs-extra'); const cli = require('@QMI/qmi-cloud-common/cli'); const sendEmail = require("@QMI/qmi-cloud-common/send-email"); const requestIp = require('request-ip'); const utils = require('../utils'); var qmiConfig = require('@QMI/qmi-cloud-common/qmi-config').qmiConfig; async function asyncForEach(array, callback) { for (let index = 0; index < array.length; index++) { await callback(array[index], index, array); } } const MYQUEUES = require('@QMI/qmi-cloud-common/queues'); const queues = MYQUEUES.queues; const TF_APPLY_QUEUE = MYQUEUES.TF_APPLY_QUEUE; const TF_APPLY_QSEOK_QUEUE = MYQUEUES.TF_APPLY_QSEOK_QUEUE; const TF_DESTROY_QUEUE = MYQUEUES.TF_DESTROY_QUEUE; const STOP_CONTAINER_QUEUE = MYQUEUES.STOP_CONTAINER_QUEUE; const SYNAPSE_QUEUE = MYQUEUES.SYNAPSE_QUEUE; /** * @swagger * /users: * get: * description: Get all users * summary: Get all users * parameters: * - name: filter * in: query * required: false * type: object * content: * application/json: * schema: * type: object * produces: * - application/json * responses: * 200: * description: User */ router.get('/', passport.ensureAuthenticated, async (req, res, next) => { try { const filter = req.query.filter? JSON.parse(req.query.filter) : {}; const result = await db.user.get(filter, "-msGroups"); return res.json(result); } catch (error) { next(error); } }); router.get('/myclientip', (req, res, next) => { const ipAddress = requestIp.getClientIp(req); return res.send(ipAddress); }); /** * @swagger * /users/me: * get: * description: Get profile logged-in user * summary: Get logged-in user * produces: * - application/json * responses: * 200: * description: User */ router.get('/me', passport.ensureAuthenticated, async (req, res, next) => { try { const result = await db.user.getById(req.user._id); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}: * get: * description: Get profile for an user * summary: Get profile for an user * parameters: * - name: userId * in: path * type: string * required: true * produces: * - application/json * responses: * 200: * description: User */ router.get('/:userId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; const result = await db.user.getById(userId); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}: * put: * description: Update profile for an user * summary: Update profile for an user * tags: * - admin * parameters: * - name: userId * in: path * type: string * required: true * - in: body * name: body * description: User object * required: true * produces: * - application/json * responses: * 200: * description: User */ router.put('/:userId', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; const result = await db.user.update(userId, req.body); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions: * post: * description: Start a new Terraform provision * summary: Start a new Terraform provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * scenario: * type: string * description: * type: string * options: * type: object * properties: * vm1: * type: object * properties: * vmType: * type: string * version: * type: object * properties: * name: * type: string * image: * type: string * responses: * 200: * description: Provision * 404: * description: Scenario not found * 400: * description: Invalid options */ router.post('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; req.body.user = userId; const scenarioSource = await db.scenario.getOne({name: req.body.scenario}); if (!scenarioSource) { return res.status(404).json({"msg": "Scenario not found "}); } const filterProvisions = {"user": userId, "isDestroyed": false, "isDeleted": false, "scenario": scenarioSource.name }; const result = await db.provision.get(filterProvisions); if ( scenarioSource.numSimultaneousProvisions && result.total >= scenarioSource.numSimultaneousProvisions ) { return res.status(400).json({"msg": "Number of simultaneous provisions reached for this scenario: " + scenarioSource.numSimultaneousProvisions}); } //if (!req.body.options || !req.body.options.vm1 || !req.body.options.vm1.vmType ) { // return res.status(400).json({"msg": "Invalid options"}); //} req.body.scenarioVersion = scenarioSource.version; if ( req.body.scheduleData && req.body.scheduleData.is24x7 !== undefined ) { const schedule = await db.schedule.add(req.body.scheduleData); req.body.schedule = schedule._id; } else { req.body.schedule = null; } req.body.terraformImage = scenarioSource.terraformImage || process.env.DOCKERIMAGE_TERRAFORM; //---Accomodation old QDI Cloud Storage if (req.body.vmImage) { req.body.options = {}; if (req.body.vmImage.db) { if (req.body.scenario === 'azqmi-synapse'){ req.body.options['sku'] = { selected: { value: req.body.vmImage.db.version.image, name: req.body.vmImage.db.version.name } }; } else { req.body.options['db'] = { selected: { value: req.body.vmImage.db.version.image, name: req.body.vmImage.db.version.name } }; } } if (req.body.vmImage.qdi_sa_id) { req.body.options['qdi_sa_id'] = { selected: { value: req.body.vmImage.qdi_sa_id.version.image, name: req.body.vmImage.qdi_sa_id.version.name } }; } if (req.body.vmImage.qdi_repl_id) { req.body.options['qdi_repl_id'] = { selected: { value: req.body.vmImage.qdi_repl_id.version.image, name: req.body.vmImage.qdi_repl_id.version.name } }; } if (req.body.vmImage.qdisacc_name) { req.body.options['qdisacc_name'] = { selected: { value: req.body.vmImage.qdisacc_name.version.image, name: req.body.vmImage.qdisacc_name.version.name } }; } if (req.body.vmImage.qdisacc_accesskey) { req.body.options['qdisacc_accesskey'] = { selected: { value: req.body.vmImage.qdisacc_accesskey.version.image, name: req.body.vmImage.qdisacc_accesskey.version.name } }; } } let theUser = await db.user.getById(userId); if (theUser && theUser.msGroups && theUser.msGroups.length){ const forced_destroy_groups = qmiConfig().forced_destroy_groups; const forced_destroy_period_days = qmiConfig().forced_destroy_period_days; let isGroupFound = theUser.msGroups.some( ai => forced_destroy_groups.includes(ai) ); if (isGroupFound) { let dd = new Date(); dd.setDate(dd.getDate() + forced_destroy_period_days); req.body['forcedDestroyDate'] = dd; } } if ( req.body.parent ) { let parentProv = await db.provision.getById(req.body.parent); if ( parentProv && parentProv.forcedDestroyDate ) { req.body['forcedDestroyDate'] = parentProv.forcedDestroyDate; } } delete req.body['vmImage']; //--- const provision = await db.provision.add(req.body); if ( provision.scenario === "azqmi-qseok" ){ queues[TF_APPLY_QSEOK_QUEUE].add("tf_apply_qseok_job", { scenario: req.body.scenario, vmType: req.body.vmType || null, nodeCount: req.body.nodeCount, id: provision._id, user: req.user, _scenario: scenarioSource }); } else { queues[TF_APPLY_QUEUE].add("tf_apply_job", { scenario: req.body.scenario, vmType: req.body.vmType, nodeCount: req.body.nodeCount, id: provision._id, user: req.user, _scenario: scenarioSource }); } return res.status(200).json(provision); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}: * get: * description: Get provision details * summary: Get provision details * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * produces: * - application/json * responses: * 200: * description: Provision */ router.get('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); return res.json(provision); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}: * put: * description: Update Provision by ID * summary: Update Provision by ID * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * - in: body * name: body * description: Provision object * required: true * produces: * - application/json * responses: * 200: * description: Provision */ router.put('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { const triggerUser = req.user; let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found provision with id "+req.params.id}); } try { let schedule; var msg = ""; let patch = req.body || {}; if ( req.body.scheduleData ) { if ( req.body.scheduleData._id ) { schedule = await db.schedule.update(req.body.scheduleData._id, req.body.scheduleData); msg += `Updated running schedule (${schedule._id}). `; } else { schedule = await db.schedule.add(req.body.scheduleData); msg += `New running schedule (${schedule._id}). `; } var tagsEdit = { "24x7": schedule.is24x7? " " : false, "StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false, "ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false } cli.updateVmsTags(provision._id, tagsEdit); patch.schedule = schedule._id; delete patch['scheduleData']; } var resShared = null; var resProvision = await db.provision.update(provision._id, patch); if ( patch.user ) { msg += `Changed owner (${patch.user}).`; resShared = await db.sharedProvision.updateMany({"provision": provision._id}, {"user": patch.user}); } let result = { provision: resProvision, sharedProvision: resShared } db.event.add({ user: triggerUser._id, provision: provision._id, type: 'provision.update', message: msg }); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}: * delete: * description: Delete Provision by ID * summary: Delete a Terraform Provision by ID * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.delete('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const triggerUser = req.user; const provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } //var delDest = provision.destroy._id; //if ( provision.destroy ) { // delDest = await db.destroy.del(provision.destroy._id); //} const delProv = await db.provision.update(req.params.id, {"isDeleted": true}); //Move folder if (fs.existsSync(`/provisions/${provision.scenario}_${req.params.id}`)) { fs.moveSync(`/provisions/${provision.scenario}_${req.params.id}`, `/provisions/deleted/${provision.scenario}_${req.params.id}`, { overwrite: true }) } db.event.add({ user: triggerUser._id, provision: provision._id, type: 'provision.delete-history' }); return res.json({"provision": delProv, "destroy": delProv.destroy}); } catch (error) { next(error); } }); /** * /users/{userId}/provisions/{id}/barracuda: * get: * description: Barracuda - get details and provision status * summary: Barracuda - get details and provision status * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ /*router.get('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found provision with id "+req.params.id}); } if ( !provision.barracudaAppId ) { console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAppId value!`); return res.status(404).json({"msg": "Not found Barracuda App for this provision"}); } var app = await barracuda.getApp(provision); return res.json(app); } catch (error) { next(error); } });*/ /** * /users/{userId}/provisions/{id}/barracuda: * post: * description: Barracuda - give a provision external access * summary: Barracuda - give a provision external access * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ /*router.post('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found provision with id "+req.params.id}); } if ( !provision.barracudaAzureFqdn ) { console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAzureFqdn value!`); return res.json(provision); } if ( provision.barracudaAppId ) { console.log(`APIUser# Provision (${req.params.id}) already have a Barracuda App (${provision.barracudaAppId})!`); return res.json(provision); } console.log(`APIUser# Calling Barracuda service to create App and DNS CName for provision (${provision._id})`); barracuda.createApp(provision); return res.json(provision); } catch (error) { next(error); } });*/ /** * /users/{userId}/provisions/{id}/barracuda: * delete: * description: Barracuda - delete a provision external access * summary: Barracuda - delete a provision external access * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ /*router.delete('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found provision with id "+req.params.id}); } if ( !provision.barracudaAppId ) { console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAppId value!`); return res.json({}); } console.log(`APIUser# Calling Barracuda service to delete App and DNS CName for provision (${provision._id})`); barracuda.deleteApp(provision); return res.json(provision); } catch (error) { next(error); } });*/ /** * @swagger * /users/{userId}/provisions/{id}/abort: * post: * description: Abort provision * summary: Abort provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/abort', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found provision with id "+req.params.id}); } queues[STOP_CONTAINER_QUEUE].add("tf_abort_apply_job", { provId: provision._id, user: req.user }); return res.json({"status": "aborting"}); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/deallocatevms: * post: * description: Stop all VMs for this provision * summary: Stop all VMs for this provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/deallocatevms', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const triggerUser = req.user; let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found provision with id "+req.params.id}); } //Set DivvyTags according to Schedule if ( provision.schedule && req.body.isStartupTimeEnable !== undefined ) { console.log("APIUser# Set DivvyTags according to schedule"); var schedule = await db.schedule.update(provision.schedule._id, { "isStartupTimeEnable": req.body.isStartupTimeEnable }); var tagsEdit = { "24x7": schedule.is24x7? " " : false, "StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false, "ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false } cli.updateVmsTags(provision._id, tagsEdit); } if (provision.scenario === 'azqmi-synapse') { queues[SYNAPSE_QUEUE].add("synapse_job", { provId: provision._id, tasktype: 'pause', user: req.user }); } else if(provision.scenario === 'awsqmi-rds') { cli.stopDb(provision._id, triggerUser._id); } else { cli.deallocate(provision._id, triggerUser._id); } provision.statusVms = "Stopping"; return res.json(provision); } catch (error) { db.provision.update(req.params.id, {"statusVms": "Error_Stopping"}); next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/startvms: * post: * description: Start all VMs for this provision * summary: Start all VMs for this provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/startvms', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const triggerUser = req.user; let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } //Re-enable DivvyTags according to schedule if ( provision.schedule ) { let schedule = await db.schedule.getById(provision.schedule._id); console.log("APIUser# Re-enabling DivvyTags according to schedule"); var tagsEdit = { "24x7": schedule.is24x7? " " : false, "StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false, "ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false } cli.updateVmsTags(provision._id, tagsEdit); } if (provision.scenario === 'azqmi-synapse') { queues[SYNAPSE_QUEUE].add("synapse_job", { provId: provision._id, tasktype: 'resume', user: req.user }); } else if(provision.scenario === 'awsqmi-rds') { cli.startDb(provision._id, triggerUser._id); } else { cli.start(provision._id, triggerUser._id); } provision.statusVms = "Starting"; return res.json(provision); } catch (error) { db.provision.update(req.params.id, {"statusVms": "Error_Starting"}); next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/rotate-sa-key: * post: * description: Rotate Storage Account AccessKey * summary: Rotate Storage Account AccessKey * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * - name: keyName * in: query * type: string * required: false * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/rotate-sa-key', passport.ensureAuthenticated, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } const modProvision = await cli.rotateStorageAccountKey(provision._id, req.query.keyName); if (modProvision) { sendEmail.sendRotateKey(modProvision, modProvision.user); } db.event.add({ user: req.user._id, provision: provision._id, type: `rotated-key.az-sa`, message: `` }); return res.json(modProvision); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/rotate-awsiam-key: * post: * description: Rotate AWS IAM user Access Key * summary: Rotate AWS IAM user Access Key * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/rotate-awsiam-key', passport.ensureAuthenticated, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } const modProvision = await cli.rotateIAMUserAccessKey(provision); if (modProvision) { sendEmail.sendRotateAWSKey(modProvision, modProvision.user); } db.event.add({ user: req.user._id, provision: provision._id, type: `rotated-key.aws-iam`, message: `` }); return res.json(modProvision); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/get-awsiam-key: * get: * description: Check AWS IAM user Access Key * summary: Check AWS IAM user Access Key * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.get('/:userId/provisions/:id/get-awsiam-key', passport.ensureAuthenticated, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } const result = await cli.checkIAMUserAccessKey(provision); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/extend: * post: * description: Extend this provision Running more time * summary: Extend this provision Running more time * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/extend', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } /*if ( provision.countExtend === 5 ) { return res.status(200).json({"msg": "You have reached the limit for the number of times to extend the Running VMs period."}); }*/ let timeRunning = db.utils.getNewTimeRunning(provision); let countExtend = db.utils.getNewCountExtend(provision); provision = await db.provision.update(req.params.id, {"runningFrom":new Date(), "timeRunning": timeRunning, "countExtend": countExtend, "pendingNextAction": null}); console.log(`APIUser# Extending running period fo provision (${provision._id}), new total extends: ${countExtend}`); return res.json(provision); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/destroy: * post: * description: Destroy a Terraform Provision * summary: Destroy a Terraform Provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.post('/:userId/provisions/:id/destroy', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; let provision = await db.provision.getById(req.params.id); if (!provision){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } if ( provision.destroy && provision.destroy.status !== 'error' ) { console.log(`APIUser# This provision is already destroyed or being destroyed right now: ${provision._id}`); return res.status(200).json(provision); } // console.log(`APIUser# Queueing destroy provision: ${provision._id}`); const destroyJob = await db.destroy.add({ "user": userId }); provision = await db.provision.update(req.params.id, {"destroy": destroyJob._id}); const scenarioSource = await db.scenario.getOne({name: provision.scenario}); queues[TF_DESTROY_QUEUE].add("tf_destroy_job", { scenario: provision.scenario, provId: provision._id, user: req.user, id: destroyJob._id, _scenario: scenarioSource }); //Check children provisions let children = await db.provision.get({ "parent": provision._id, "isDestroyed": false, "isDeleted": false }); if (children.results.length > 0 ) { await asyncForEach(children.results, async function(child) { if ( !child.destroy || child.destroy.status === 'error' ) { console.log(`APIUser# Queueing destroy children provision: ${child._id}`); let destroyJobChild = await db.destroy.add({ "user": userId }); await db.provision.update(child._id, {"destroy": destroyJobChild._id}); let scenarioSourceChild = await db.scenario.getOne({name: child.scenario}); queues[TF_DESTROY_QUEUE].add("tf_destroy_job", { scenario: child.scenario, provId: child._id, user: req.user, id: destroyJobChild._id, _scenario: scenarioSourceChild }); } else { console.log(`APIUser# This child provision is already destroyed or being destroyed right now: ${child._id}`); } }) } return res.status(200).json(provision); } catch (error) { return res.status(error.output.statusCode).json({"err":error}); } }); /** * @swagger * /users/{userId}/provisions/{id}/share/{withUserId}: * put: * description: Share provision with another user * summary: Share provision with another user * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * - name: withUserId * in: path * type: string * required: true * - in: body * name: body * responses: * 200: * description: Provision * 404: * description: Not found * */ router.put('/:userId/provisions/:id/share/:withUserId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; let provision = await db.provision.getById(req.params.id); var shareWithUser = await db.user.getById(req.params.withUserId); if (!provision || !shareWithUser){ return res.status(404).json({"msg": "Not found privision with id "+req.params.id}); } if ( req.params.withUserId === provision.user._id ) { return res.status(400).json({"msg": "Can't share with the same user"}); } let found = await db.sharedProvision.getOne({ "user": provision.user._id, "provision": provision._id, "sharedWithUser": req.params.withUserId }); if ( !found ) { let canManage = req.body && req.body.type === "manage"; found = await db.sharedProvision.add({"user": provision.user._id, "provision": provision._id, "sharedWithUser": req.params.withUserId, "canManage": canManage}) sendEmail.sendSharedProvision(provision, shareWithUser); db.event.add({ user: userId, provision: provision._id, type: 'provision.share', 'message': `Start sharing with user (${req.params.withUserId}) with "${canManage? 'manage' : 'view'}" permission` }); } return res.json(found); } catch (error) { return res.status(error.output.statusCode).json({"err":error}); } }); /** * @swagger * /users/{userId}/provisions/{id}/share/{withUserId}: * delete: * description: Stop sharing this provision with another user * summary: Stop sharing this provision with another user * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * - name: withUserId * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.delete('/:userId/provisions/:id/share/:withUserId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; if ( req.params.withUserId === userId ) { return res.status(400).json({"msg": "Can't share with the same user"}); } const result = await db.sharedProvision.delMany({"provision": req.params.id, "sharedWithUser": req.params.withUserId}); db.event.add({ user: userId, provision: req.params.id, type: 'provision.stop-share', 'message': `Stop sharing with user (${req.params.withUserId})` }); return res.json(result); } catch (error) { return res.status(error.output.statusCode).json({"err":error}); } }); /** * @swagger * /users/{userId}/provisions/{id}/share: * delete: * description: Stop sharing this provision with everybody * summary: Stop sharing this provision with everybody * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.delete('/:userId/provisions/:id/share', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; if ( req.params.withUserId === userId ) { return res.status(400).json({"msg": "Can't share with the same user"}); } const result = await db.sharedProvision.delMany({"provision": req.params.id, "sharedWithUser": req.params.withUserId}); return res.json(result); } catch (error) { return res.status(error.output.statusCode).json({"err":error}); } }); /** * @swagger * /users/{userId}/provisions/{id}/share: * get: * description: Get shares of this provision * summary: Get shares of this provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.get('/:userId/provisions/:id/share', passport.ensureAuthenticated, async (req, res, next) => { try { let result = await db.sharedProvision.get({"provision": req.params.id}); return res.json(result); } catch (error) { return res.status(error.output.statusCode).json({"err":error}); } }); /** * @swagger * /users/{userId}/sharedprovisions: * get: * description: Get provision shared with me * summary: Get provision shared with me * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * responses: * 200: * description: Provision * 404: * description: Not found * */ router.get('/:userId/sharedprovisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; let out = await db.sharedProvision.get({"sharedWithUser": userId}); return res.json(out); } catch (error) { return res.status(error.output.statusCode).json({"err":error}); } }); /** * @swagger * /users/{userId}/provisions: * get: * description: Get all Provisions for an User * summary: Get all Provisions for an User * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * responses: * 200: * description: JSON Array */ router.get('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; const filter = {"user": userId, "isDeleted": false, $or: [ { isUIHidden: { $exists: false } }, { isUIHidden: false } ] }; const result = await db.provision.get(filter); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/events: * get: * description: Get all Events for an User * summary: Get all Events for an User * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * responses: * 200: * description: JSON Array */ router.get('/:userId/events', passport.ensureAuthenticated, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; const result = await db.event.get({"user": userId}); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/provisions/{id}/events: * get: * description: Get all Events for an User and Provision * summary: Get all Events for an User and Provision * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * - name: id * in: path * type: string * required: true * responses: * 200: * description: JSON Array */ router.get('/:userId/provisions/:id/events', passport.ensureAuthenticated, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; const result = await db.event.get({"provision": req.params.id}); return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/scenarios: * get: * description: Get all Provisions for an User * summary: Get all Provisions for an User * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * responses: * 200: * description: JSON Array */ router.get('/:userId/scenarios', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { let filter = {}; if (req.user.role === "user") { filter.isAdminOnly = false; } filter.isDisabled = filter.isDisabled || false; var result = await db.scenario.get(filter); if (req.user.role === "user") { result.results = result.results.filter( scenario => { let noAllowedUsers = !scenario.allowedUsers || scenario.allowedUsers.length === 0; if ( noAllowedUsers ) { return true; } else { let allowedUserIds = scenario.allowedUsers.map( u=> u._id.toString()); return allowedUserIds.indexOf(req.user._id.toString()) !== -1; } }); } return res.json(result); } catch (error) { next(error); } }); /** * @swagger * /users/{userId}/destroyprovisions: * get: * description: Get all Destroy Provisions for an User * summary: Get all Destroy Provisions for an User * produces: * - application/json * parameters: * - name: userId * in: path * type: string * required: true * responses: * 200: * description: JSON Array */ router.get('/:userId/destroyprovisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; const result = await db.destroy.get({"user": userId}); return res.json(result); } catch (error) { next(error); } }); router.get('/:userId/settitle', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => { try { const userId = req.params.userId === 'me'? req.user._id : req.params.userId; let patch = {}; if ( req.query.title ) { patch['jobTitle'] = req.query.title; } const result = await db.user.update(userId, patch); utils.saveUserPhoto(result.upn, result.oid); return res.json(result); } catch (error) { next(error); } }); module.exports = router;