routes/access/networksImpl.js

/**
 * @module access/networks
 */

const NetworkDatabase = require('../../database/models/network');
const DeviceDatabase = require('../../database/models/device');
const Auth0UserManager = require('../../database/models/user');

/**
 * Retrieves all networks belonging to the requesting user and sends them in an http request response.
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 */
async function getNetworks(req, res) {
    try {
		const result = await NetworkDatabase.getByUser(req.apiUser);
		res.send({networks: result});
	}
	catch(error) {
		res.sendStatus(401);
		console.log(error);
	}
}

/**
 * Creates a new network for the current user and sends a http request to the user with the newly created network.
 *
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 *
 */
async function createNetwork(req, res) {
    try {
		const result = await NetworkDatabase.createWithUser(req.body.name, req.apiUser);
		res.send(result);
	}
	catch(error) {
		res.sendStatus(401);
		console.log(error);
	}
}

/**
 * Gets a single network and returns it in the http response.
 *
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 */
async function getNetwork(req, res){
    try {
    	if (await NetworkDatabase.checkPermissions(req.params.network_id, ['view'], req.apiUser)){
    		const result = await NetworkDatabase.get(req.params.network_id);

			res.send(result);
        }
		else {
    		res.sendStatus(404);
		}
	}
	catch(error) {
		res.sendStatus(500);
		console.log(error);
	}
}

/**
 * Gets all the devices that belong to the specified network and returns them in the http response.
 *
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 */
async function getNetworkDevices(req, res) {
    try {

    	if (await NetworkDatabase.checkPermissions(req.params.network_id, ['view'], req.apiUser)){
    		const network = await NetworkDatabase.get(req.params.network_id);
			const devices = await DeviceDatabase.getMany(network.devices);

			res.send({devices: devices});
        }
		else {
			console.log("Missing permissions to see the network devices.");
    		res.sendStatus(401);
		}
	}
	catch(error) {
		res.sendStatus(401);
		console.log("Error: ", error);
	}
}

/**
 * Adds an existing device as a device in the network.
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 */
async function addNetworkDevice(req, res) {
	try {
		if (await NetworkDatabase.checkPermissions(req.params.network_id, ['edit'], req.apiUser)) {
			const result = await NetworkDatabase.addDevice(req.body.network_id, req.body.device_id)
			res.send(result);
		}
		else {
			res.sendStatus(404);
		}
	}
	catch(error) {
		res.sendStatus(401);
		console.log(error);
	}
}

/**
 * Removes an existing device as a device in the network. This function does not do anything to the actual device object, it just disassociates it from the network.
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 */
async function removeNetworkDevice(req, res) {
    try {
    	if (await NetworkDatabase.checkPermissions(req.params.network_id, ['edit'], req.apiUser)) {
        	const result = await NetworkDatabase.removeDevice(req.body.network_id, req.body.device_id);
			res.send(result);
        }
		else {
    		res.sendStatus(404);
		}
	}
	catch (error) {
		res.sendStatus(401);
		console.log(error);
	}
}

/**
 * Deletes the network. Does not delete devices belonging to the network.
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 */
async function deleteNetwork(req, res) {
	try {
		if (await NetworkDatabase.checkPermissions(req.body.network_id, ['delete'], req.apiUser)){

			 const result = await NetworkDatabase.del(req.body.network_id);
			 res.send(result);
		}
		else {
			res.sendStatus(401);
		}

	}
	catch(error) {
		res.sendStatus(401);
		console.error(error);
	}
}

/**
 * Updates permissions to view and edit a network.
 * @param {Object} req - An Express request object.
 * @param {Object} res - An Express response object.
 * @returns {Promise.<void>}
 */
async function updateNetworkPermissions(req, res) {
	try {
		const network_id = req.body.network_id;

		if (await NetworkDatabase.checkPermissions(network_id, ['edit'], req.apiUser)) {

			const network = await NetworkDatabase.get(network_id);
			const owner = network.owner;

			for (const [key, value] of Object.entries(req.body.permissions)) {

				// don't modify owner permissions
				if (key.toString() !== owner.toString()) {

					// check if the user already has permissions
					if (network.permissions.hasOwnProperty(key)) {
							// get the added permissions, only allow adding view and edit
						const addPermissions = value.filter((el) => !network.permissions[key].includes(el) && (el === 'view' || el === 'edit'));

						console.log(value);
						// get the removed permissions
						const removedPermissions = network.permissions[key].filter((el) => !value.includes(el));
						console.log(addPermissions);
						console.log(removedPermissions);
						// add permissions
						await NetworkDatabase.addPermissions(network_id, addPermissions, key, req.apiUser, false);

						// remove permissions
						await NetworkDatabase.removePermissions(network_id, removedPermissions, key, req.apiUser, false);

					}
					else {

						// if the user doesn't have any permissions, add the specified ones (but only view and edit)
						const addPermissions = value.filter((el) => (el === 'view' || el === 'edit'));

						// add permissions
						await NetworkDatabase.addPermissions(network_id, addPermissions, key, req.apiUser, false);
					}

					// if the user has permissions, make sure
					if (await NetworkDatabase.hasAnyPermissions(network_id, key)) {
						await Auth0UserManager.addNetworkToUser(key, network_id);
					}
					else {
						await Auth0UserManager.removeNetworkFromUser(key, network_id);
					}
				}
			}
			res.sendStatus(200);
		}
		else {
			res.sendStatus(404);
		}
	}
	catch(error) {
		console.error(error);
		res.sendStatus(404);
	}
}

module.exports = {
	getNetworks: getNetworks,
	getNetwork: getNetwork,
	deleteNetwork: deleteNetwork,
	createNetwork: createNetwork,
	getNetworkDevices: getNetworkDevices,
    addNetworkDevice: addNetworkDevice,
    removeNetworkDevice: removeNetworkDevice,
	updateNetworkPermissions: updateNetworkPermissions
};