/* global __appdir */ const path = require('path') const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends')) var axios = require('axios') class IdoitBackend extends ExternalBackends { /* * Returns the credential structure / fields, defined in the backends. */ getCredentials () { return [ { type: 'text', id: 1, name: 'API URL', icon: 'link' }, { type: 'password', id: 2, name: 'API Token', icon: 'vpn_key', show: false }, { type: 'switch', id: 3, name: 'Login', icon: 'lock_open', elements: [ { type: 'text', id: 4, name: 'Username', icon: 'person_outline' }, { type: 'password', id: 5, name: 'Password', icon: 'lock', show: false } ] } ] } /* * Checks the connection of a given backend. * idoIT: Checks if we can get a valid session id. If so the connection must be successfull. * * return: true / { error: , message: } */ async checkConnection (credentials) { const c = this.mapCredentials(credentials) const body = this.getBody('idoit.version', { 'apikey': c.apikey }, 'version_check') const headers = await this.getHeaders(c) if (headers.error) return headers // Axios request const result = await this.axiosRequest(c.url, [body], headers) if (result.error) return { error: 'IDOIT_ERROR', message: result.message } // Check if it actually returned some legit idoit stuff and not just a valid response. if (result.length === 1 && result[0].id === 'version_check') return true else return { error: 'IDOIT_ERROR', message: 'The request returned an invalid response!' } } // Return the list of object types created in iDoIT. async getObjectTypes (credentials) { const c = this.mapCredentials(credentials) const body = this.getBody('cmdb.object_types', { 'apikey': c.apikey }, 'object_types') const headers = await this.getHeaders(c) if (headers.error) return headers var result = {} result.types = await this.axiosRequest(c.url, [body], headers) result.types = result.types[0].result var types = [] result.types.forEach(type => { types.push({ id: type.id, title: type.title }) }) return types } getSyncTypes () { return ['None', 'Two-Way', 'Upload Only', 'Upload Then Delete', 'Upload Mirror', 'Download Only', 'Download Then Delete', 'Download Mirror'] } /* * Gets all objects and searches for the uuid to get the requested client. * */ async getClient (credentials, client) { const c = this.mapCredentials(credentials) const paramsObjects = { 'apikey': c.apikey, 'filter': { 'type': 10 }, 'categories': ['C__CATG__MODEL'] } const body = this.getBody('cmdb.objects', paramsObjects, 'objects') const headers = await this.getHeaders(c) if (headers.error) return headers // Get all client objects. const clients = await this.axiosRequest(c.url, [body], headers) let result = clients[0].result.filter(x => x.categories.C__CATG__MODEL.length > 0 && x.categories.C__CATG__MODEL[0].productid === client.uuid) return result.length >= 1 ? result.map(x => x.id) : { error: 'NO_CLIENT_FOUND', msg: 'There is no client matching with the provided uuid.' } } async getObjects (credentials) { const c = this.mapCredentials(credentials) const body = this.getBody('cmdb.objects', { 'apikey': c.apikey }, 'objects') const headers = await this.getHeaders(c) if (headers.error) return headers const objects = await this.axiosRequest(c.url, [body], headers) return objects[0] } async getObject (credentials, oid) { const c = this.mapCredentials(credentials) const body = this.getBody('cmdb.object.read', { 'apikey': c.apikey, 'id': oid }, 'object_read') const bodyChilds = this.getBody('cmdb.location_tree', { 'apikey': c.apikey, 'id': oid }, 'object_location_tree') const headers = await this.getHeaders(c) if (headers.error) return headers var result = {} result.object = await this.axiosRequest(c.url, [body], headers) result.childs = await this.axiosRequest(c.url, [bodyChilds], headers) result.object = result.object[0].result result.childs = result.childs[0].result return result } async deleteObjects (credentials, objectIds) { const c = this.mapCredentials(credentials) const headers = await this.getHeaders(c) if (headers.error) return headers let bodies = [] bodies.push(this.getBody('cmdb.object.quickpurge', { 'id': objectIds, 'apikey': c.apikey }, 'batch_quickpurge')) let deleteRequest = await this.axiosRequest(c.url, bodies, headers) const errorRegex = /(?<=\s#)[0-9]+/g const failedDeletions = deleteRequest[0].result.message.match(errorRegex) let result = [] if (failedDeletions) for (let failedObjId of failedDeletions) result.push({ error: true, message: `Deletion of object ${failedObjId} was skipped.`, id: failedObjId }) return result } // Function to use the same session for multiple requests async getDataTree (credentials, objects) { const c = this.mapCredentials(credentials) const headers = await this.getHeaders(c) if (headers.error) return headers let bodies = [] let gids = {} // Prepare all the batch request bodies. for (let element of objects) { bodies.push(this.getBody('cmdb.location_tree', { 'id': element.eid, 'apikey': c.apikey }, element.eid)) gids[element.eid] = element.gid } // Send all the batch request and post proccess the result into one array. let requestResult = await this.axiosRequest(c.url, bodies, headers) // Post process the data. let result = [] for (let res of requestResult) { result.push({ gid: gids[res.id], childs: res.result }) } return result } /* * Adds the client to the backend. * * credentials: * The client parameters are all optional. * client: { * title: , parentId: , * network: { mac: , ip: } * } */ async addClient (credentials, client) { const c = this.mapCredentials(credentials) const headers = await this.getHeaders(c) if (headers.error) return headers let params = { 'apikey': c.apikey, 'title': client.name, 'purpose': client.purpose === 'Pool PC' ? 7 : undefined, 'categories': {} } client.parentId = parseInt(client.parentId) if (client.type === 'CLIENT') { params['type'] = 10 if (client.parentId) params.categories.C__CATG__LOCATION = { 'data': { 'parent': client.parentId } } } else if (client.type === 'SERVER') { params['type'] = 5 if (client.location && client.location.bay === null) params.categories.C__CATG__LOCATION = { 'data': { 'parent': client.parentId, 'option': client.location.assembly, 'insertion': client.location.insertion, 'pos': client.location.slot } } if (client.formfactor) params.categories.C__CATG__FORMFACTOR = { 'data': { 'formfactor': client.formfactor.formfactor, 'rackunits': client.formfactor.rackunits } } // Rack segmentation if (client.location.bay !== undefined && client.location.bay !== null) { // Get all assigned objects of the rack (parentid) to check for existing rack segments at slot position. const rackobjectsBody = this.getBody('cmdb.category.read', { 'apikey': c.apikey, 'object': client.parentId, 'objID': client.parentId, 'category': 'C__CATG__OBJECT' }, 'get_rack_objects') const rackobjects = await this.axiosRequest(c.url, [rackobjectsBody], headers) // Get the name of the rack console.log('') console.log('Get Rack Name:') const rackBody = this.getBody('cmdb.category.read', { 'apikey': c.apikey, 'object': client.parentId, 'objID': client.parentId, 'category': 'C__CATG__GLOBAL' }, 'get_rack') const rack = await this.axiosRequest(c.url, [rackBody], headers) if (!rack[0].result) return { error: 'IDOIT_ERROR', message: rack[0].error.message } const rackName = rack[0].result[0].title let objectPositionBodies = [] // For each segmentation object in the rack get the slot number console.log('') console.log('Get Slot IDs Request:') for (let obj in rackobjects[0].result) { const object = rackobjects[0].result[obj] if (object.assigned_object.type !== 'C__OBJTYPE__RACK_SEGMENT') continue objectPositionBodies.push(this.getBody('cmdb.category.read', { 'apikey': c.apikey, 'object': object.objID, 'objID': object.objID, 'category': 'C__CATG__LOCATION' }, 'get_rack_object_position_' + object.objID)) } let objectPositions = await this.axiosRequest(c.url, objectPositionBodies, headers) if (objectPositions.length >= 1) objectPositions = objectPositions.filter(x => parseInt(x.result[0].pos.title) === parseInt(client.location.slot)) // There should only be one segment object for the rack slot if so set it as parent var chassisId if (objectPositions.length === 1) chassisId = parseInt(objectPositions[0].result[0].objID) else { // Create a new rack segment const createSegmentParamObject = { 'apikey': c.apikey, 'type': 92, 'title': rackName + ' Slot ' + client.location.slot, 'categories': { 'C__CATS__CHASSIS': { 'data': { 'front_x': 2, 'front_y': 1, 'rear_x': 0, 'rear_y': 0 } }, 'C__CATS__CHASSIS_SLOT': [ { 'title': 'Bay 1', 'insertion': 'front', 'from_x': 0, 'to_x': 0, 'from_y': 0, 'to_y': 0 }, { 'title': 'Bay 2', 'insertion': 'front', 'from_x': 1, 'to_x': 1, 'from_y': 0, 'to_y': 0 } ], 'C__CATG__LOCATION': { 'data': { 'parent': client.parentId, 'option': client.location.option, 'insertion': client.location.insertion, 'pos': client.location.slot } } } } console.log('') console.log('Create Segment Request:') const createSegmentParam = this.getBody('cmdb.object.create', createSegmentParamObject, 'create_segment') const createSegment = await this.axiosRequest(c.url, [createSegmentParam], headers) chassisId = createSegment[0].result.id /* // Set the new rack units height. (Needs an extra request, why? I DONT KNOW... idoit...) const setSegmentSizeParams = this.getBody('cmdb.category.save', { 'apikey': c.apikey, 'object': chassisId, 'objID': chassisId, 'category': 'C__CATG__FORMFACTOR', 'data': { 'rackunits': client.formfactor.rackunits } }, 'set_segment_size') await this.axiosRequest(c.url, [setSegmentSizeParams], headers) */ } } } // Add categories to the object if (client.uuid) params.categories.C__CATG__MODEL = { 'data': { 'productid': client.uuid } } if (client.networks) { params.categories.C__CATG__IP = [] for (let index in client.networks) { const network = client.networks[index] let networkparams = {} if (network.ip) networkparams.ipv4_address = network.ip if (network.hostname) networkparams.hostname = network.hostname if (network.domain) networkparams.domain = network.domain if (network.net) networkparams.net = network.net if (network.primary) networkparams.primary = network.primary ? 1 : 0 params.categories.C__CATG__IP.push(networkparams) } } // Add contact assignment to the object. if (client.contacts) { // Get the persons ids. let readPersonBodies = [] for (let index in client.contacts) { readPersonBodies.push(this.getBody('cmdb.objects.read', { 'apikey': c.apikey, 'filter': { 'type': 'C__OBJTYPE__PERSON', 'first_name': client.contacts[index].first_name, 'last_name': client.contacts[index].last_name } }, 'read_persons_' + index)) } console.log('') console.log('Read Person Request:') const requestReadPersons = await this.axiosRequest(c.url, readPersonBodies, headers) if (requestReadPersons.error) return requestReadPersons const error = requestReadPersons.filter(x => x.error) if (error.length === 0) { const personIds = requestReadPersons.map(x => { if (x.result.length === 1) return x.result[0].id }).filter(Boolean) params.categories.C__CATG__CONTACT = [] for (let index in personIds) { params.categories.C__CATG__CONTACT.push({ 'contact': personIds[index] }) } } else console.log(error) } // Add operating system information. if (client.runtime && client.runtime.operating_system) { // Get the operating system ids. console.log('') console.log('Get OS Request:') const getOSParam = { 'apikey': c.apikey, 'filter': { 'type': 35, // 35 = Operating System 'title': client.runtime.operating_system.name } } const getOSBody = this.getBody('cmdb.objects.read', getOSParam, 'get_os') const requestGetOS = await this.axiosRequest(c.url, [getOSBody], headers) // Extra request for getting the id of the version number console.log('') console.log('Get OS-Version Request:') const getOSVersionParam = { 'apikey': c.apikey, 'objID': requestGetOS[0].result[0].id, 'catgID': 'C__CATG__VERSION' } const getOSVersionBody = this.getBody('cmdb.category.read', getOSVersionParam, 'get_os_version') const requestGetOSVersion = await this.axiosRequest(c.url, [getOSVersionBody], headers) const osVersion = requestGetOSVersion[0].result.filter(x => x.title === client.runtime.operating_system.version) // Add the result of the OS request (ids) to the create request. if (requestGetOS[0].result) { params.categories.C__CATG__OPERATING_SYSTEM = { 'data': { 'application': requestGetOS[0].result[0].id, 'assigned_version': osVersion[0].id } } } } // Send the create request. console.log('') console.log('Create Client Request:') const body = this.getBody('cmdb.object.create', params, 'client_create') const requestCreate = await this.axiosRequest(c.url, [body], headers) // Error handling if (requestCreate.error) return { error: requestCreate.errno, message: 'Connection was refused.' } else if (requestCreate[0].error) return { error: 'IDOIT_ERROR', message: requestCreate[0].error.message } // Add mac address: Network port is a subcategory of network so it need an extra request. let macRequests = [] const hostnameIds = requestCreate[0].result.categories.C__CATG__IP if (client.networks) { let macBodies = [] for (let index in client.networks) { const network = client.networks[index] // For the ip adresses // network.id = requestCreate[0].result.categories.C__CATG__IP[index] let addresses = [] // Push the ids as string if (hostnameIds.length > index) addresses.push('' + hostnameIds[index]) let paramsMac = { 'object': requestCreate[0].result.id, 'objID': requestCreate[0].result.id, 'category': 'C__CATG__NETWORK_PORT', 'data': { 'mac': network.mac, 'addresses': addresses }, 'apikey': c.apikey } if (network.device) { if (network.device.speed) { paramsMac.data.speed = parseFloat(network.device.speed) // MB/s GB/s ... etc not supported?! Only Mbit/s Gbit/s ... paramsMac.data.speed_type = null } if (network.device.name) paramsMac.data.title = network.device.name if (network.device.type) paramsMac.data.port_type = network.device.type } macBodies.push(this.getBody('cmdb.category.save', paramsMac, 'add_mac_address_' + index)) } console.log('') console.log('Add MAC Request:') const response = await this.axiosRequest(c.url, macBodies, headers) macRequests.push(response) } // If chassis id is set, assign the object to the chassis bay if (chassisId) { // Read bay ids const paramsSlots = { 'object': chassisId, 'objID': chassisId, 'category': 'C__CATS__CHASSIS_SLOT', 'apikey': c.apikey } console.log('') console.log('Read Rack Slots:') const readSlotsParam = this.getBody('cmdb.category.read', paramsSlots, 'read_slots') const readSlots = await this.axiosRequest(c.url, [readSlotsParam], headers) const bays = readSlots[0].result console.log('') console.log('Assign to Rack Slot:') const assignToSlotBody = this.getBody('cmdb.category.save', { 'apikey': c.apikey, 'objID': chassisId, 'object': chassisId, 'category': 'C__CATS__CHASSIS_DEVICES', 'data': { 'assigned_device': requestCreate[0].result.id, 'assigned_slots': [bays[client.location.bay].id] } }, 'assign_to_slot') await this.axiosRequest(c.url, [assignToSlotBody], headers) } // Purpose for Clients: // 1 = Production | 5 = PVS // 2 = Test | 7 = Pool PC // 3 = Quality Assurance | 8 = Mitarbeiter Arbeitsplatz return { succes: true, id: requestCreate[0].result.id, type: params.type, message: requestCreate[0].result.message, macRequests: macRequests } } /* * Updates the client information in the backend. * * credentials: * The client parameters are all optional. * client: { * id: , title: , parentId: , * system: { model: , manufacturer: , serialnumber: }, * cpu: { model: , manufacturer: , type: , frequency: , cores: }, * ram: [{ title: , manufacturer: , type: , capacity: , unit: }, ...], * drives: [{model: ,}, serial: , capacity: , unit: , type: , formfactor: , connection: ...] * } */ async updateClient (credentials, client) { const c = this.mapCredentials(credentials) const headers = await this.getHeaders(c) if (headers.error) return headers // Parse needed because db values are strings. (Other backends need strings as external ids) client.id = parseInt(client.id) client.parentId = parseInt(client.parentId) let bodies = [] // workaround for the fucking idoit shit. -.- let requestResults = [] // Update title of the object if (client.name) bodies.push(this.getBody('cmdb.object.update', { 'id': client.id, 'title': client.name, 'apikey': c.apikey }, 'update_title')) // 'object' should be 'objID' but there is a fucking bug in the idoit api. Soo let's add both parameters because else it will break when they fix it. // Update the productid to the uuid. if (client.uuid) { let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__MODEL', 'data': { 'productid': client.uuid }, 'apikey': c.apikey } bodies.push(this.getBody('cmdb.category.save', params, 'update_uuid')) } if (client.parentId) { // Update the object. Location let paramsLocation = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__LOCATION', 'data': { 'parent': client.parentId }, 'apikey': c.apikey } bodies.push(this.getBody('cmdb.category.save', paramsLocation, 'update_parent')) } // Update the object. Model data. if (client.system) { let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__MODEL', 'data': { 'manufacturer': client.system.manufacturer, 'title': client.system.model, 'serial': client.system.serialnumber }, 'apikey': c.apikey } bodies.push(this.getBody('cmdb.category.save', params, 'update_model')) } // Update networks & Check if there is at least one network which will get updated. if (client.networks && client.networks.filter(network => Object.keys(network).length >= 4).length !== 0) { let parmReadNetwork = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__IP', 'apikey': c.apikey } const ips = await this.axiosRequest(c.url, [this.getBody('cmdb.category.read', parmReadNetwork, 'read_ips')], headers) parmReadNetwork.category = 'C__CATG__NETWORK_PORT' const macs = await this.axiosRequest(c.url, [this.getBody('cmdb.category.read', parmReadNetwork, 'read_macs')], headers) for (let index in client.networks) { const network = client.networks[index] if (network.ip && network.hostname && network.domain) { // Update ip addresses let paramsIp = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__IP', 'data': { 'ipv4_address': network.ip, 'hostname': network.hostname, 'domain': network.domain, 'net': network.net }, 'apikey': c.apikey } if (ips[0].result.length > index) paramsIp.entry = parseInt(ips[0].result[index].id) bodies.push(this.getBody('cmdb.category.save', paramsIp, 'update_ip')) } // Update mac addresses if (network.mac) { let paramsMac = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__NETWORK_PORT', 'data': { 'mac': network.mac }, 'apikey': c.apikey } if (macs[0].result.length > index) paramsMac.entry = parseInt(macs[0].result[index].id) bodies.push(this.getBody('cmdb.category.save', paramsMac, 'update_mac')) } } } // Update the object. CPU data. // TODO: Delete cpu if exists? if (client.cpus) { let counter = 1 for (let cpu of client.cpus) { if (cpu.unit === 'MHz') cpu.unit = 2 else if (cpu.unit === 'GHz') cpu.unit = 3 let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__CPU', 'data': { 'manufacturer': cpu.manufacturer, 'title': cpu.model, 'type': cpu.type, 'frequency': parseFloat(cpu.frequency), 'frequency_unit': cpu.unit, 'cores': parseInt(cpu.cores) }, 'apikey': c.apikey } counter++ bodies.push(this.getBody('cmdb.category.save', params, 'create_cpu_' + counter)) } } // GPUS if (client.gpus) { let counter = 1 for (let gpu of client.gpus) { let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__GRAPHIC', 'data': { 'manufacturer': gpu.manufacturer, 'title': gpu.model, 'memory': gpu.memory, 'unit': gpu.unit }, 'apikey': c.apikey } counter++ bodies.push(this.getBody('cmdb.category.save', params, 'create_gpu_' + counter)) } } // Update the object. Ram data. if (client.ram) { let counter = 1 for (let module of client.ram.modules) { // Add KB and TB if (module.unit === 'MB') module.unit = 2 else if (module.unit === 'GB') module.unit = 3 let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__MEMORY', 'data': { 'title': module.model, 'manufacturer': module.manufacturer, 'type': module.type, 'capacity': parseFloat(module.capacity), 'unit': module.unit, 'description': JSON.stringify({ serialnumber: module.serialnumber, formfactor: module.formfactor, speed: module.speed }) }, 'apikey': c.apikey } counter++ bodies.push(this.getBody('cmdb.category.save', params, 'create_memory_' + counter)) } } // Update the object. Drive data. if (client.drives) { let counter = 1 for (let index in client.drives) { const drive = client.drives[index] // UNIT if (drive.unit === 'GB') drive.unit = 3 else if (drive.unit === 'MB') drive.unit = 2 else if (drive.unit === 'TB') drive.unit = 4 else if (drive.unit === 'KB') drive.unit = 1 else if (drive.unit === 'B') drive.unit = 0 if (drive.type === 'Solid State Device') drive.type = 'SSD' else if (drive.type === '5400 rpm') drive.type = 'Hard disk' else if (drive.type === '7200 rpm') drive.type = 'Hard disk' else if (drive.type === '') drive.type = 'Hard disk' let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__STORAGE_DEVICE', 'data': { 'category_id': counter, 'title': drive.model, 'type': drive.type, 'firmware': drive.firmware, // 'manufacturer': , // 'model': , 'capacity': parseFloat(drive.capacity), 'unit': drive.unit, 'serial': drive.serial, 'connected': drive.connection }, 'apikey': c.apikey } bodies.push(this.getBody('cmdb.category.save', params, 'create_drive_' + counter)) counter++ } } if (bodies.length > 0) { const requestUpdate = await this.axiosRequest(c.url, bodies, headers) requestResults.push(requestUpdate) if (requestUpdate.error) return requestUpdate } // 10 is the idoit object id for clients. // 5 is the idoit object id for servers. let type = 0 if (client.type === 'CLIENT') type = 10 else if (client.type === 'SERVER') type = 5 const result = { success: true, id: client.id, type: type, response: requestResults } return result } async getFileList (credentials, externalId) { const c = this.mapCredentials(credentials) const body = this.getBody('cmdb.category.read', { 'objID': externalId, 'category': 'C__CATG__FILE', apikey: c.apikey }, 'filelist') const headers = await this.getHeaders(c) if (headers.error) return headers const result = await this.axiosRequest(c.url, [body], headers) return result[0].result } async getFile (credentials, externalId, filename) { const c = this.mapCredentials(credentials) const body = this.getBody('cmdb.category.read', { 'objID': externalId, 'category': 'C__CATG__FILE', apikey: c.apikey }, 'filelist') const headers = await this.getHeaders(c) if (headers.error) return headers const files = await this.axiosRequest(c.url, [body], headers) let fileObjId = files[0].result.find(x => x.file.title === filename).file.id const body2 = this.getBody('cmdb.category.read', { 'objID': fileObjId, 'category': 'C__CMDB__SUBCAT__FILE_VERSIONS', apikey: c.apikey }, 'file') let result = await this.axiosRequest(c.url, [body2], headers) result = result[0].result[0] return { filename: result.file_title, value: result.file_content.value, md5: result.md5_hash } } async uploadFiles (credentials, externalId, files) { const c = this.mapCredentials(credentials) const headers = await this.getHeaders(c) if (headers.error) return headers let result = [] for (var key in files) { const filename = files[key].name /* eslint-disable */ const buffer = new Buffer.from(files[key].data) /* eslint-enable */ // Create the fileObject where the file gets uplaoded to. const body = this.getBody('cmdb.object.create', { 'type': 29, 'title': files[key].name, 'apikey': c.apikey }, 'createFileObject_' + key) const fileObject = await this.axiosRequest(c.url, [body], headers) // Upload file to fileobject. const paramsUploadFile = { 'object': fileObject[0].result.id, // <-- workaround for the idoit api bug (wrong mapping of objID) 'objID': fileObject[0].result.id, 'data': { 'file_content': buffer.toString('base64'), 'file_physical': filename, 'file_title': filename, 'version_description': key }, 'category': 'C__CMDB__SUBCAT__FILE_VERSIONS', 'apikey': c.apikey } const bodyUploadFile = this.getBody('cmdb.category.save', paramsUploadFile, 'uploadFile_' + key) const uploadFile = await this.axiosRequest(c.url, [bodyUploadFile], headers) // Connect the file with the client (object). const paramsConnectFile = { 'object': externalId, 'objID': externalId, 'data': { 'file': fileObject[0].result.id }, 'category': 'C__CATG__FILE', 'apikey': c.apikey } const bodyConnect = this.getBody('cmdb.category.save', paramsConnectFile, 'uploadFile_' + key) const connectFile = await this.axiosRequest(c.url, [bodyConnect], headers) result.push({ createObject: fileObject, uploadFile: uploadFile, connectObjectFile: connectFile }) } return result } // Helper function, to map the array of credential objects into a single js object. mapCredentials (credentials) { const c = JSON.parse(credentials) const login = c.find(x => x.id === 3) var mapped = { url: c.find(x => x.id === 1).value, apikey: c.find(x => x.id === 2).value, login: login.value } if (mapped.login) { mapped.username = login.elements.find(x => x.id === 4).value mapped.password = login.elements.find(x => x.id === 5).value } return mapped } // Method for making the axios request and error handling. async axiosRequest (url, bodies, headers, batchRequestSize = 400) { let config = { timeout: 180000, headers: headers } // Split batchrequest in multiple request let batchRequests = [] // For spliceing the array a while loop seems to be the most efficient: // https://ourcodeworld.com/articles/read/278/how-to-split-an-array-into-chunks-of-the-same-size-easily-in-javascript while (bodies.length) { batchRequests = [...batchRequests, bodies.splice(0, batchRequestSize)] } // Make all batch request and return the result of all. let results = [] let requestCounter = 1 for (let i = 0; i < batchRequests.length; i++) { // Axios error handling try { console.log(requestCounter + '/' + batchRequests.length + ' requests sent') requestCounter++ const responses = await axios.post(url, batchRequests[i], config) if (Array.isArray(responses.data)) results = [...results, ...responses.data] else results = [...results, responses.data] } catch (error) { let errorResponse = { error: true } if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx errorResponse['data'] = error.response.data errorResponse['status'] = error.response.status errorResponse['headers'] = error.response.headers } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in node.js let errorMsg = '' if (error.code) errorMsg += '[' + error.code + '] ' if (error.errno) errorMsg += '[' + error.errno + '] ' if (error.message) errorMsg += error.message errorResponse['message'] = errorMsg } else { // Something happened in setting up the request that triggered an Error errorResponse['message'] = error.message } return errorResponse } } return results } // Body wrapper for the requests to remove duplicated code. getBody (method, params, id) { return { 'version': '2.0', 'method': method, 'params': { ...params, 'language': 'en' }, 'id': id } } // Returns the header. Sets the session id if needed. async getHeaders (credentials = {}) { let headers = { 'Content-Type': 'application/json' } // Get a session id for the header if (credentials.login && credentials.username && credentials.password) { const header = { ...headers, 'X-RPC-Auth-Username': credentials.username, 'X-RPC-Auth-Password': credentials.password } const sessionRequest = await this.axiosRequest(credentials.url, [this.getBody('idoit.login', { 'apikey': credentials.apikey, 'language': 'en' }, 'login')], header) // Axios errors if (sessionRequest.error) return sessionRequest // Idoit error if (sessionRequest[0].error) return { error: 'IDOIT_ERROR', message: sessionRequest[0].error.message } headers = { ...headers, 'X-RPC-Auth-Session': sessionRequest[0].result['session-id'] } } return headers } } module.exports = IdoitBackend