/* global __appdir */ var path = require('path') var Sequelize = require('sequelize') var db = require(path.join(__appdir, 'lib', 'sequelize')) var express = require('express') const { decorateApp } = require('@awaitjs/express') var router = decorateApp(express.Router()) const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse')) const log = require(path.join(__appdir, 'lib', 'log')) // Permission check middleware router.all(['', '/:x'], async (req, res, next) => { switch (req.method) { case 'GET': if (!await req.user.hasPermission('ipxeconfigs.view')) return res.status(403).send({ error: 'Missing permission', permission: 'ipxeconfigs.view' }) break case 'POST': case 'PUT': case 'DELETE': if (!await req.user.hasPermission('ipxeconfigs.edit')) return res.status(403).send({ error: 'Missing permission', permission: 'ipxeconfigs.edit' }) break default: return res.status(400).send() } next() }) // ############################################################################ // ########################### GET requests ################################# router.getAsync('', async (req, res) => { const configs = await db.config.findAll({ include: [{ association: 'groups', attributes: [] }, { association: 'clients', attributes: [] }], attributes: { include: [ [Sequelize.fn('COUNT', Sequelize.col('groups.id')), 'groupCount'], [Sequelize.fn('COUNT', Sequelize.col('clients.id')), 'clientCount'] ] }, group: ['id'] }) res.status(200).send(configs) }) router.getAsync('/:id', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) const config = await db.config.findOne({ where: { id: req.params.id }, include: ['groups', 'clients'] }) if (config) res.status(200).send(config) else HttpResponse.notFound(req.params.id).send(res) }) router.getAsync('/:id/entries', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) const config = await db.config.findOne({ where: { id: req.params.id }, include: ['entries'], order: [[db.config.associations.entries, db.config.associations.entries.through, 'sortValue', 'ASC']] }) if (config) res.status(200).send(config.entries) else HttpResponse.notFound(req.params.id).send(res) }) router.getAsync('/:id/groups', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) const config = await db.config.findOne({ where: { id: req.params.id }, include: ['groups'] }) if (config) res.status(200).send(config.groups) else HttpResponse.notFound(req.params.id).send(res) }) router.getAsync('/:id/clients', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) const config = await db.config.findOne({ where: { id: req.params.id }, include: ['clients'] }) if (config) res.status(200).send(config.clients) else HttpResponse.notFound(req.params.id).send(res) }) // ############################################################################ // ########################## POST requests ################################# router.postAsync(['', '/:id'], async (req, res) => { if (req.query.delete !== undefined && req.query.delete !== 'false') { if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res) const user = await db.user.findOne({ where: { id: req.user.id } }) // Only need to log batch request if there is more than one ipxeconfig to delete. if (req.body.ids.length > 1) { await log({ category: 'IPXECONFIG_BATCH_DELETE', description: 'Batch deletion of ' + req.body.ids.length + ' ipxe configs initiated by user.', user, userId: req.user.id }) } let deletionCounter = 0 // Delete every config on its own, to get a better log for (let index in req.body.ids) { const config = await db.config.findOne({ where: { id: req.body.ids[index] } }) const count = await db.config.destroy({ where: { id: req.body.ids[index] } }) if (count !== 1) { await log({ category: 'ERROR_IPXECONFIG_DELETE', description: '[' + config.id + '] ' + config.name + ': Ipxe config could not be deleted.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault, user, userId: req.user.id }) } else { await log({ category: 'IPXECONFIG_DELETE', description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully deleted.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault, user, userId: req.user.id }) deletionCounter++ } } if (req.body.ids.length > 1) { log({ category: 'IPXECONFIG_BATCH_DELETE', description: deletionCounter + '/' + req.body.ids.length + ' ipxe configs successfully deleted.', user, userId: req.user.id }) } HttpResponse.successBatch('deleted', 'ipxe config', deletionCounter).send(res) } else { let config let action = 'updated' if (req.params.id === undefined) { config = await db.config.create(req.body.data) log({ category: 'IPXECONFIG_CREATE', description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully created.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault, userId: req.user.id }) action = 'created' } else if (req.params.id > 0) { config = await db.config.findOne({ where: { id: req.params.id } }) if (!config) return HttpResponse.notFound(req.params.id).send(res) else { await config.update(req.body.data) log({ category: 'IPXECONFIG_EDIT', description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully edited.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault, userId: req.user.id }) } } else { return HttpResponse.invalidId().send(res) } await config.setEntries([]) if (req.body.entries.length > 0) { const promises = [] req.body.entries.forEach((entry, index) => { promises.push(config.addEntry(entry.id, { through: { sortValue: index, customName: entry.customName, keyBind: entry.keyBind } })) }) await Promise.all(promises) } HttpResponse.success(action, 'ipxe entry', config.id).send(res) } }) // ############################################################################ // ########################### PUT requests ################################# router.putAsync('/:id/groups', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res) const config = await db.config.findOne({ where: { id: req.params.id } }) if (config) { await config.setGroups(req.body.ids) HttpResponse.success('set', 'clients of ipxe config', config.id).send(res) log({ category: 'IPXECONFIG_SET_GROUPS', description: '[' + config.id + '] ' + config.name + ': ' + req.body.ids.length + ' groups successfully set.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault + '\n' + 'Groups: ' + req.body.ids, userId: req.user.id }) } else { HttpResponse.notFound(req.params.id).send(res) } }) router.putAsync('/:id/clients', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) if (!Array.isArray(req.body.ids)) return HttpResponse.invalidBodyValue('ids', 'an array').send(res) const config = await db.config.findOne({ where: { id: req.params.id } }) if (config) { await config.setClients(req.body.ids) log({ category: 'IPXECONFIG_SET_CLIENTS', description: '[' + config.id + '] ' + config.name + ': ' + req.body.ids.length + ' clients successfully set.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault + '\n' + 'Clients: ' + req.body.ids, userId: req.user.id }) HttpResponse.success('set', 'clients of ipxe config', config.id).send(res) } else { HttpResponse.notFound(req.params.id).send(res) } }) router.putAsync('/:id/default', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) const config = await db.config.findOne({ where: { id: req.params.id } }) const oldDefault = await db.config.findOne({ where: { isDefault: true } }) if (config) { await db.config.update({ isDefault: false }, { where: { isDefault: true } }) await config.update({ isDefault: true }) log({ category: 'IPXECONFIG_SET_DEFAULT', description: '[' + config.id + '] ' + config.name + ': Config successfully set as default.\n' + 'Old Default: [' + oldDefault.id + '] ' + oldDefault.name + '\n' + 'New Default: [' + config.id + '] ' + config.name, userId: req.user.id }) HttpResponse.success('set as default:', 'config', config.id).send(res) } else { HttpResponse.notFound(req.params.id).send(res) } }) // ############################################################################ // ########################## DELETE requests ############################### router.deleteAsync('/:id', async (req, res) => { if (!(req.params.id > 0)) return HttpResponse.invalidId().send(res) const config = await db.config.findOne({ where: { id: req.params.id } }) const count = await db.config.destroy({ where: { id: req.params.id } }) if (count) { log({ category: 'IPXECONFIG_DELETE', description: '[' + config.id + '] ' + config.name + ': Ipxe config successfully deleted.\n' + 'ID: ' + config.id + '\n' + 'Name: ' + config.name + '\n' + 'Description: ' + config.description + '\n' + 'Default Entry: ' + config.defaultEntry + '\n' + 'Timeout: ' + config.timeout + '\n' + 'Default Config: ' + config.isDefault, userId: req.user.id }) HttpResponse.success('deleted', 'config', req.params.id).send(res) } else HttpResponse.notFound(req.params.id).send(res) }) // ############################################################################ // ############################################################################ module.exports.router = router