@manyos/smileconnect-api 1.36.4 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app.js CHANGED
@@ -33,6 +33,7 @@ const ciRelationRoutes = require('./routes/ciRelationRoutes');
33
33
  const peopleRelationRoutes = require('./routes/peopleRelationRoutes');
34
34
  const appConfigRoutes = require('./routes/appConfigRoutes');
35
35
  const scriptRoutes = require('./routes/scriptRoutes');
36
+ const customFormRoutes = require('./routes/customFormRoutes');
36
37
  const relatedObjectsController = require('./controller/relatedObjectsController');
37
38
  const addRequestId = require('express-request-id')();
38
39
  const compression = require('compression');
@@ -273,6 +274,16 @@ app.use('/v1/templates/(|incidents|problems|workorders|changes|tasks)', function
273
274
  next();
274
275
  }, templateRoutes);
275
276
 
277
+ //formhandling
278
+ app.use('/v1/customForms/:formName', function(req, res, next) {
279
+ req.formConfig = {
280
+ formName: req.params.formName,
281
+ configName: 'custom_' + req.params.formName
282
+ }
283
+ req.parentEventBase = 'customForm'
284
+ next();
285
+ }, customFormRoutes);
286
+
276
287
  //tickethandling worklogs
277
288
  app.use('/v1/:ticketType/:parentId/worklogs', function(req, res, next) {
278
289
  log.debug('params1', req.params);
package/conf/clients.json CHANGED
@@ -135,6 +135,20 @@
135
135
  "impersonateUser": "rhannemann",
136
136
  "translateSelectionFieldsX": false
137
137
  },
138
+ "custom_Sample:Enrollments": {
139
+ "formName": "Sample:Enrollments",
140
+ "basequery": "1=1",
141
+ "fields": [
142
+ "Enrollment ID",
143
+ "Enrollee Login",
144
+ "Class ID",
145
+ "Class Title",
146
+ "Class Location",
147
+ "Class Cost",
148
+ "Department",
149
+ "Class Start Date & Time"
150
+ ]
151
+ },
138
152
  "cmdbobject": {
139
153
  "basequery": "'Data Set Id' = \"BMC.ASSET\" AND ('Mark As Deleted' = \"No\" OR 'Mark As Deleted' = $NULL$)",
140
154
  "fields": [
package/conf/mapping.json CHANGED
@@ -1,4 +1,38 @@
1
1
  {
2
+ "custom_Sample:Enrollments": [
3
+ {
4
+ "oldName": "Enrollment ID",
5
+ "newName": "id"
6
+ },
7
+ {
8
+ "oldName": "Enrollee Login",
9
+ "newName": "userId"
10
+ },
11
+ {
12
+ "oldName": "Class ID",
13
+ "newName": "classId"
14
+ },
15
+ {
16
+ "oldName": "Class Title",
17
+ "newName": "classTitle"
18
+ },
19
+ {
20
+ "oldName": "Class Location",
21
+ "newName": "location"
22
+ },
23
+ {
24
+ "oldName": "Class Start Date & Time",
25
+ "newName": "startDate"
26
+ },
27
+ {
28
+ "oldName": "Class Cost",
29
+ "newName": "cost"
30
+ },
31
+ {
32
+ "oldName": "Department",
33
+ "newName": "department"
34
+ }
35
+ ],
2
36
  "cmdbobject": [
3
37
  {
4
38
  "oldName": "Instance Id",
@@ -0,0 +1,196 @@
1
+ require('dotenv').config();
2
+ const path = require('path');
3
+ const log = require('@manyos/logger').setupLog('SMILEconnect_' + path.basename(__filename));
4
+ const arquery = require('../util/arquery');
5
+ const CacheService = require ('../util/cache.service');
6
+ const config = require('../util/config');
7
+ const CONSTANTS = require('../util/constants');
8
+ const searchUtil = require('../util/searchUtil');
9
+ const {getIncludeArray, applyMapping} = require('../util/paramHelper');
10
+ const scriptController = require('./scriptController');
11
+ const mappingUtil = require('../util/mappingUtil');
12
+
13
+ const ticketCache = new CacheService(process.env.CACHETTL_TICKETS || 1); // Create a new cache service instance
14
+
15
+ function getRecords(formConfig, clientConfig, includeString, customOptions) {
16
+ let query = '1=1';
17
+ return queryRecords(formConfig, clientConfig, query, null, null, customOptions, includeString);
18
+ }
19
+
20
+ async function createRecord(formConfig, clientConfig, data) {
21
+ const allScripts = clientConfig[formConfig.configName].scripts;
22
+ let scripts
23
+ if (allScripts) {
24
+ scripts = allScripts.POST
25
+ }
26
+
27
+ //run preScripts
28
+ if (scripts && scripts.preMapping) {
29
+ await scriptController.runScripts(scripts.preMapping, data, clientConfig.clientId);
30
+ }
31
+
32
+ const requestType = formConfig.requestType;
33
+
34
+ const mapping = config.getMapping(formConfig.configName)
35
+ log.debug('mapping', mapping);
36
+
37
+ const fields = mappingUtil.getFieldsForCreate(mapping, mapping, clientConfig[formConfig.configName].fields)
38
+
39
+ data = mappingUtil.applyMapping2Remedy(data, mapping, clientConfig[formConfig.configName].constants, fields);
40
+
41
+ //run postScripts
42
+ if (scripts && scripts.postMapping) {
43
+ await scriptController.runScripts(scripts.postMapping, data, clientConfig.clientId);
44
+ }
45
+
46
+ const result = await arquery.createEntry(formConfig.formName, data, clientConfig.options)
47
+
48
+ log.debug('RecordCreateResult', result.data);
49
+ const recordCreateId = Object.values(result)[0];
50
+ //Find change id
51
+ const resultInterfaceCreate = await arquery.executeARQuery(formConfig.formName, null, "'1'=\"" + recordCreateId + "\"", formConfig.ticketIdField, clientConfig.options)
52
+ if (resultInterfaceCreate.data && Array.isArray(resultInterfaceCreate.data) && resultInterfaceCreate.data.length > 0) {
53
+ const recordCreateId = resultInterfaceCreate.data[0][formConfig.ticketIdField];
54
+ } else {
55
+ log.error('Cannot create Record', resultInterfaceCreate);
56
+ throw({message: 'Cannot create Record', details : resultInterfaceCreate});
57
+ }
58
+
59
+ //run afterExecution
60
+ if (scripts && scripts.afterExecution) {
61
+ await scriptController.runScripts(scripts.afterExecution, data, clientConfig.clientId);
62
+ }
63
+ return recordCreateId;
64
+ }
65
+
66
+ function queryRecords(formConfig, clientConfig, query, mapping, customFields, customOptions, includeString) {
67
+ const includeArray = getIncludeArray(includeString);
68
+ log.debug('Get config for', formConfig.configName)
69
+ let fields = clientConfig[formConfig.configName].fields;
70
+ const baseQuery = clientConfig[formConfig.configName].basequery;
71
+
72
+ //check for customFields
73
+ if (customFields !== null && customFields !== undefined) {
74
+ fields = customFields;
75
+ }
76
+
77
+ log.debug('fields', fields, customFields);
78
+ const options = {
79
+ ...clientConfig.options, ...customOptions
80
+ };
81
+
82
+ log.debug('use joined options', options);
83
+
84
+ const key = baseQuery + fields.toString() + query + JSON.stringify(options) + includeArray;
85
+ log.debug('Cachekey is ', key);
86
+ if (mapping == null || mapping == undefined) {
87
+ mapping = config.getMapping(formConfig.configName);
88
+ }
89
+ log.debug('mapping', mapping);
90
+
91
+ return ticketCache.get(key, async function () {
92
+ const result = await arquery.executeARQuery(formConfig.formName, baseQuery || null, query, fields.toString() || '1', options);
93
+ const records = [];
94
+ if (result && result.data && result.data.length) {
95
+ let x = 0;
96
+ for (x=0; x< result.data.length; x++) {
97
+ const ticket = await handleRecord(formConfig, result.data[x], mapping, clientConfig, includeArray);
98
+ records.push(ticket);
99
+ }
100
+ }
101
+ log.debug('records', records);
102
+ return {
103
+ "data": records
104
+ };
105
+ });
106
+ }
107
+
108
+ async function handleRecord(formConfig, record, mapping, clientConfig, includeArray, globalRelationObjects) {
109
+ const allScripts = clientConfig[formConfig.configName].scripts;
110
+ let scripts = [];
111
+ if (allScripts) {
112
+ scripts = allScripts.GET || [];
113
+ }
114
+
115
+ //run preScripts
116
+ if (scripts && scripts.preMapping) {
117
+ const preScripts = scripts.preMapping;
118
+ try {
119
+ for (let x = 0; x < preScripts.length; x++) {
120
+ const result = await scriptController.executeScript(preScripts[x], record, null, clientConfig.clientId);
121
+ }
122
+ } catch (error) {
123
+ throw error;
124
+ }
125
+ }
126
+
127
+ applyMapping(record, mapping);
128
+
129
+ //run postScripts
130
+ if (scripts && scripts.postMapping) {
131
+ const postScripts = scripts.postMapping;
132
+ try {
133
+ for (let x = 0; x < postScripts.length; x++) {
134
+ const result = await scriptController.executeScript(postScripts[x], record, null, clientConfig.clientId);
135
+ }
136
+ } catch (error) {
137
+ throw error;
138
+ }
139
+ }
140
+ return record;
141
+ }
142
+
143
+ async function getRecord(formConfig, clientConfig, id, mapping, includeString) {
144
+ const query = `'1'=\"${id}\"`;
145
+ const returnValue = await queryRecords(formConfig, clientConfig, query, mapping, null, null, includeString);
146
+ const record = returnValue.data[0];
147
+ return {data: record};
148
+ }
149
+
150
+ async function updateRecord(formConfig, clientConfig, id, recordData) {
151
+ const allScripts = clientConfig[formConfig.configName].scripts;
152
+ let scripts
153
+ if (allScripts) {
154
+ scripts = allScripts.PUT
155
+ }
156
+ const fields = clientConfig[formConfig.configName].fields
157
+
158
+ //run preScripts
159
+ if (scripts && scripts.preMapping) {
160
+ await scriptController.runScripts(scripts.preMapping, recordData, clientConfig.clientId);
161
+ }
162
+
163
+ const mapping = config.getMapping(formConfig.configName);
164
+
165
+ recordData = mappingUtil.applyMapping2Remedy(recordData, mapping, undefined, fields);
166
+
167
+ //run postMapping
168
+ if (scripts && scripts.postMapping) {
169
+ await scriptController.runScripts(scripts.postMapping, recordData, clientConfig.clientId);
170
+ }
171
+
172
+ const update = await arquery.updateEntry(formConfig.formName, id, recordData);
173
+
174
+ //run afterExecution
175
+ if (scripts && scripts.afterExecution) {
176
+ await scriptController.runScripts(scripts.afterExecution, recordData, clientConfig.clientId);
177
+ }
178
+
179
+ return update;
180
+ }
181
+
182
+ function searchRecords(formConfig, clientConfig, searchString, fields, options, includeString) {
183
+ const mapping = config.getMapping(formConfig.configName);
184
+ const mappedString = searchUtil.applyMapping(searchString, mapping);
185
+ const customFields = searchUtil.getCustomFields(clientConfig[formConfig.configName].fields, mapping, fields);
186
+ options.sort = searchUtil.applySortMapping(options.sort, mapping);
187
+ return queryRecords(formConfig, clientConfig, mappedString, null, customFields, options, includeString);
188
+ }
189
+
190
+ module.exports = {
191
+ getRecord,
192
+ getRecords,
193
+ createRecord,
194
+ updateRecord,
195
+ searchRecords
196
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manyos/smileconnect-api",
3
- "version": "1.36.4",
3
+ "version": "1.38.0",
4
4
  "description": "A proxy and abstraction layer for BMCs IT Service Management Suite",
5
5
  "main": "app.js",
6
6
  "scripts": {
@@ -0,0 +1,173 @@
1
+ const path = require('path');
2
+ const log = require('@manyos/logger').setupLog('SMILEconnect_' + path.basename(__filename));
3
+ const {body, validationResult, oneOf} = require('express-validator/check');
4
+ const customFormController = require('../controller/customFormController');
5
+ const eventLog = require('../controller/eventLogController');
6
+ const CONSTANTS = require('../util/constants');
7
+
8
+ module.exports = (function() {
9
+ const routes = require('express').Router();
10
+
11
+ const errorFormatter = ({location, msg, param, value, nestedErrors}) => {
12
+ // Build your resulting errors however you want! String, object, whatever - it works!
13
+ return `${location}[${param}]: ${msg}`;
14
+ };
15
+
16
+ routes.get('/', function (req, res, next) {
17
+ eventLog.setEventData(
18
+ req,
19
+ req.parentEventBase,
20
+ CONSTANTS.EVENT_ACTION_QUERY,
21
+ req.formConfig.formName
22
+ );
23
+ const includeString = req.query.include;
24
+
25
+ const options = {};
26
+ const limit = req.query.limit;
27
+ if (limit != null && limit != undefined) {
28
+ options.limit = Number.parseInt(limit);
29
+ }
30
+
31
+ const offset = req.query.offset;
32
+ if (offset != null && offset != undefined) {
33
+ options.offset = Number.parseInt(offset);
34
+ }
35
+
36
+ customFormController.getRecords(req.formConfig, req.user.config, includeString, options).then(function (result) {
37
+ log.debug('result', result);
38
+ req.result = {data:result.data};
39
+ next();
40
+ }).catch(function (reason) {
41
+ next(reason);
42
+ });
43
+ });
44
+
45
+ routes.post('/', function (req, res, next) {
46
+ //todo Errorhandling prüfen. Wenn parameter fehlen, wird nicht zurückgegeben welche
47
+ const origData = JSON.parse(JSON.stringify(req.body));
48
+ const includeString = req.query.include;
49
+ eventLog.setEventData(
50
+ req,
51
+ req.parentEventBase,
52
+ CONSTANTS.EVENT_ACTION_CREATE,
53
+ req.formConfig.formName,
54
+ null,
55
+ origData
56
+ );
57
+ const errors = validationResult(req).formatWith(errorFormatter);
58
+ if (!errors.isEmpty()) {
59
+ req.errorStatus = 422;
60
+ next(errors.array());
61
+ } else {
62
+ customFormController.createRecord(req.formConfig, req.user.config, req.body.data).then(async function (createResult) {
63
+ const recordId = createResult;
64
+ eventLog.setTicketId(req, recordId);
65
+ req.eventData.ticketNumber = recordId;
66
+ getRecord(req, res, next, req.user.config, recordId, null, includeString);
67
+ }).catch(function (reason) {
68
+ next(reason);
69
+ });
70
+ }
71
+ });
72
+
73
+ routes.post('/search', [
74
+ body('searchString').isLength({ min: 1})
75
+ ], function (req, res, next) {
76
+
77
+ const origData = JSON.parse(JSON.stringify(req.body));
78
+ const includeString = req.query.include;
79
+ eventLog.setEventData(
80
+ req,
81
+ req.parentEventBase,
82
+ CONSTANTS.EVENT_ACTION_SEARCH,
83
+ req.parentForm,
84
+ null,
85
+ origData
86
+ );
87
+ const options = {};
88
+ const offset = req.body.offset;
89
+ if (offset != null && offset != undefined && Number.isInteger(offset)) {
90
+ options.offset = offset;
91
+ }
92
+ const limit = req.body.limit;
93
+ if (limit != null && limit != undefined && Number.isInteger(limit)) {
94
+ options.limit = limit;
95
+ }
96
+ // check sorting
97
+ const sort = req.body.sort;
98
+ if (sort != null && sort != undefined) {
99
+ options.sort = sort;
100
+ }
101
+ log.debug('start global search', req.body);
102
+ const valResult = validationResult(req).formatWith(errorFormatter);
103
+ log.debug('validationResult', valResult.array());
104
+ if (!valResult.isEmpty()) {
105
+ next(valResult.array());
106
+ } else {
107
+ customFormController.searchRecords(req.formConfig, req.user.config, req.body.searchString, req.body.fields, options, includeString).then(function (result) {
108
+ log.debug('result', result);
109
+ req.result = {data:result.data};
110
+ next();
111
+ }).catch(function (reason) {
112
+ next(reason);
113
+ });
114
+ }
115
+ });
116
+
117
+ routes.get('/:id', function (req, res, next) {
118
+ const id = req.params.id;
119
+ const includeString = req.query.include;
120
+ eventLog.setEventData(
121
+ req,
122
+ req.parentEventBase,
123
+ CONSTANTS.EVENT_ACTION_SEARCH,
124
+ req.parentForm,
125
+ id
126
+ );
127
+
128
+ getRecord(req, res, next, req.user.config, id, null, includeString);
129
+
130
+ });
131
+
132
+ function getRecord(req, res, next, clientConfig, id, mapping, includeString) {
133
+ customFormController.getRecord(req.formConfig, clientConfig, id, mapping, includeString).then(function (result) {
134
+ log.debug('result', result);
135
+ req.includeObjectsList = result.included;
136
+ req.result = {data:result.data || {}};
137
+ if (!result.data) {
138
+ req.responseStatus = 404;
139
+ }
140
+ next();
141
+ }).catch(function (reason) {
142
+ next (reason);
143
+ })
144
+ }
145
+
146
+ routes.put('/:id', function (req, res, next) {
147
+ const id = req.params.id;
148
+ const origData = JSON.parse(JSON.stringify(req.body));
149
+ const includeString = req.query.include;
150
+ eventLog.setEventData(
151
+ req,
152
+ req.parentEventBase,
153
+ CONSTANTS.EVENT_ACTION_MODIFY,
154
+ req.formConfig.formName,
155
+ id,
156
+ origData
157
+ );
158
+ const errors = validationResult(req).formatWith(errorFormatter);
159
+ if (!errors.isEmpty()) {
160
+ req.errorStatus = 422;
161
+ next(errors.array());
162
+ } else {
163
+ customFormController.updateRecord(req.formConfig, req.user.config, id, req.body.data)
164
+ .then(async function (updateResult) {
165
+ getRecord(req, res, next, req.user.config, id, null, includeString);
166
+ }).catch(function (reason) {
167
+ next(reason);
168
+ });
169
+ }
170
+ });
171
+
172
+ return routes;
173
+ })();
@@ -45,7 +45,7 @@ module.exports = (function() {
45
45
  });
46
46
  });
47
47
 
48
- ticketRoutes.post('/', [body('data.summary').isLength({min: 3})], function (req, res, next) {
48
+ ticketRoutes.post('/', function (req, res, next) {
49
49
  //todo Errorhandling prüfen. Wenn parameter fehlen, wird nicht zurückgegeben welche
50
50
  const origData = JSON.parse(JSON.stringify(req.body));
51
51
  const includeString = req.query.include;
@@ -133,10 +133,7 @@ module.exports = (function() {
133
133
 
134
134
  });
135
135
 
136
- ticketWorkLogRoutes.post('/',[
137
- body('data.summary').isLength({ min: 1, max: 100}),
138
- body('data.text').isLength({ min: 1})
139
- ],
136
+ ticketWorkLogRoutes.post('/',
140
137
  function (req, res, next) {
141
138
  const origData = JSON.parse(JSON.stringify(req.body));
142
139
  const ticketId = req.parentId;
package/util/arquery.js CHANGED
@@ -63,7 +63,7 @@ async function executeARQuery(form, baseQuery, query, fields, options) {
63
63
  + "/" + form
64
64
  + "/" + fullQuery
65
65
  + "?port=" + port
66
- + "&fields=" + fields;
66
+ + "&fields=" + encodeURIComponent(fields);
67
67
 
68
68
  if (options != null && options != undefined) {
69
69
  if (options.dateFormat != null && options.dateFormat != undefined) {
package/util/config.js CHANGED
@@ -147,7 +147,7 @@ function checkMapping() {
147
147
  const mappingKeys = Object.keys(mappings);
148
148
  //delete too many
149
149
  mappingKeys.forEach(key=>{
150
- if (!mappingDefs.includes(key) && !key.startsWith('cmdbobject_')) {
150
+ if (!mappingDefs.includes(key) && !key.startsWith('cmdbobject_') && !key.startsWith('custom_')) {
151
151
  log.info('delete from mapping', key);
152
152
  delete mappings[key];
153
153
  }
@@ -192,7 +192,7 @@ function checkClientConfig(client) {
192
192
  const clientConfigKeys = Object.keys(clientConfig);
193
193
  //delete too many
194
194
  clientConfigKeys.forEach(key=>{
195
- if (!clientKeys.includes(key) && !(key === 'options')) {
195
+ if (!clientKeys.includes(key) && !(key === 'options') && !(key.startsWith('custom_'))) {
196
196
  log.info('delete from clientconfig', key);
197
197
  delete clientConfig[key];
198
198
  } else if (clientKeys.includes(key) && !(key === 'options')) {