@manyos/smileconnect-api 1.56.0 → 1.57.1

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
@@ -264,7 +264,8 @@ app.use(function (req, res, next) {
264
264
  //set globalscript params
265
265
  app.use(function (req, res, next) {
266
266
  req.globalScriptParams = {
267
- query: req.query
267
+ query: req.query,
268
+ user: req.user
268
269
  }
269
270
  // Für Scripte einen globalen parameter bereitstellen, der den org. Body enthält. Damit hat man auch noch in Post Scripten Zugriff auf customAttributes die beim Mapping entfernt werden.
270
271
  if (req.body) {
package/conf/clients.json CHANGED
@@ -1994,7 +1994,8 @@
1994
1994
  "Class Location",
1995
1995
  "Class Cost",
1996
1996
  "Department",
1997
- "Class Start Date & Time"
1997
+ "Class Start Date & Time",
1998
+ "Name"
1998
1999
  ]
1999
2000
  },
2000
2001
  "custom_CTM:People": {
@@ -2009,9 +2010,7 @@
2009
2010
  "postMapping": []
2010
2011
  },
2011
2012
  "PUT": {
2012
- "preMapping": [
2013
- "slash"
2014
- ],
2013
+ "preMapping": [],
2015
2014
  "postMapping": [],
2016
2015
  "afterExecution": []
2017
2016
  },
@@ -2075,6 +2074,9 @@
2075
2074
  "fields_AST:ComputerSystem": [
2076
2075
  "DNS Host Name"
2077
2076
  ],
2077
+ "fields_AST:Cluster": [
2078
+ "InstanceId"
2079
+ ],
2078
2080
  "fields_AST:LANEndpoint": [
2079
2081
  "MACAddress"
2080
2082
  ],
@@ -2086,21 +2088,12 @@
2086
2088
  ],
2087
2089
  "scripts": {
2088
2090
  "GET": {
2089
- "preMapping": [
2090
- "script1",
2091
- "script2"
2092
- ],
2093
- "postMapping": [
2094
- "script1"
2095
- ]
2091
+ "preMapping": [],
2092
+ "postMapping": []
2096
2093
  },
2097
2094
  "POST": {
2098
- "preMapping": [
2099
- "scriptPutPre"
2100
- ],
2101
- "postMapping": [
2102
- "scriptPutPost"
2103
- ]
2095
+ "preMapping": [],
2096
+ "postMapping": []
2104
2097
  }
2105
2098
  }
2106
2099
  },
@@ -2325,7 +2318,7 @@
2325
2318
  "scripts": {
2326
2319
  "GET": {
2327
2320
  "preMapping": [
2328
- "p2"
2321
+ "createRecord"
2329
2322
  ],
2330
2323
  "postMapping": [],
2331
2324
  "afterExecution": []
package/conf/mapping.json CHANGED
@@ -77,6 +77,12 @@
77
77
  "newName": "macAddress"
78
78
  }
79
79
  ],
80
+ "cmdbobject_AST:Cluster": [
81
+ {
82
+ "oldName": "InstanceId",
83
+ "newName": "id"
84
+ }
85
+ ],
80
86
  "change": [
81
87
  {
82
88
  "oldName": "Infrastructure Change ID",
@@ -342,7 +342,7 @@ async function updateCmdbObject(ticketConfig, clientConfig, id, ciData, classId,
342
342
  await scriptController.runScripts(scripts.postMapping, ciData, clientConfig.clientId, globalScriptParams);
343
343
  }
344
344
 
345
- const update = await arquery.updateEntry(formName, ci['Request ID'], ciData);
345
+ const update = await arquery.updateEntry(formName, ci['Request ID'], ciData, clientConfig.options);
346
346
 
347
347
  //run afterExecution
348
348
  if (scripts && scripts.afterExecution) {
@@ -403,27 +403,34 @@ async function createCmdbObject(assetConfig, clientConfig, classId, ciData, glob
403
403
 
404
404
  const mapping = getClassMapping(classId);
405
405
 
406
- const classFields = getClassFields(clientConfig, classId)
406
+ const classFields = getClassFields(clientConfig, classId);
407
407
 
408
- //Constants work only on new.
409
- ciData = mappingUtil.applyMapping2Remedy(ciData, mapping, undefined, classFields);
408
+ const reconIdField = await config.getFormFieldById(classId, 400129200);
409
+ const instanceIdField = await config.getFormFieldById(classId, 179);
410
+ const dataSetIdField = await config.getFormFieldById(classId, 400127400);
410
411
 
411
- //run postMapping
412
- if (scripts && scripts.postMapping) {
413
- await scriptController.runScripts(scripts.postMapping, ciData, clientConfig.clientId, globalScriptParams);
412
+ if (!reconIdField || !instanceIdField || !dataSetIdField) {
413
+ throw ({message: "RecondId, InstanceId or Dataset not found on form", field:{reconIdField, instanceIdField, dataSetIdField}})
414
414
  }
415
+ //Constants work only on new.
416
+ ciData = mappingUtil.applyMapping2Remedy(ciData, mapping, undefined, classFields);
415
417
 
416
418
  //Default to BMC.ASSET if no Dataset is provided
417
- if (!ciData['Data Set Id']) {
418
- ciData['Data Set Id'] = "BMC.ASSET"
419
+ if (!ciData[dataSetIdField.name]) {
420
+ ciData[dataSetIdField.name] = "BMC.ASSET"
419
421
  }
420
422
  //Add reconId only for Asset Dataset
421
- if (ciData['Data Set Id'] === "BMC.ASSET") {
422
- ciData['400129200'] = reconId;
423
+ if (ciData[dataSetIdField.name] === "BMC.ASSET") {
424
+ ciData[reconIdField.name] = reconId;
425
+ }
426
+ ciData[instanceIdField.name] = instanceId;
427
+
428
+ //run postMapping
429
+ if (scripts && scripts.postMapping) {
430
+ await scriptController.runScripts(scripts.postMapping, ciData, clientConfig.clientId, globalScriptParams);
423
431
  }
424
- ciData['Instance Id'] = instanceId;
425
432
 
426
- const update = await arquery.createEntry(classId, ciData);
433
+ const update = await arquery.createEntry(classId, ciData, clientConfig.options);
427
434
 
428
435
  //run afterExecution
429
436
  if (scripts && scripts.afterExecution) {
@@ -181,7 +181,7 @@ async function updateRecord(formConfig, clientConfig, id, recordData, globalScri
181
181
 
182
182
  const internalId = await getInternalId(formConfig, clientConfig, id)
183
183
 
184
- const update = await arquery.updateEntry(formConfig.formName, internalId, recordData);
184
+ const update = await arquery.updateEntry(formConfig.formName, internalId, recordData, clientConfig.options);
185
185
 
186
186
  //run afterExecution
187
187
  if (scripts && scripts.afterExecution) {
@@ -445,7 +445,7 @@ async function updateTask(clientConfig, id, taskData, globalScriptParams) {
445
445
  await scriptController.runScripts(scripts.postMapping, taskData, clientConfig.clientId, globalScriptParams);
446
446
  }
447
447
 
448
- const result = await arquery.updateEntry('TMS:Task', id, taskData);
448
+ const result = await arquery.updateEntry('TMS:Task', id, taskData, clientConfig.options);
449
449
 
450
450
  //flow update
451
451
  const taskQuery = `'1' = "${id}"`
@@ -44,7 +44,7 @@ async function createTicket(ticketConfig, clientConfig, data, globalScriptParams
44
44
 
45
45
  const result = await arquery.createEntry(ticketConfig.forms.new, data, clientConfig.options)
46
46
 
47
- log.debug('TicketCreateResult', result.data);
47
+ log.debug('TicketCreateResult', result);
48
48
  const ticketCreateId = Object.values(result)[0];
49
49
  //Find change id
50
50
  const resultInterfaceCreate = await arquery.executeARQuery(ticketConfig.forms.new, null, "'1'=\"" + ticketCreateId + "\"", ticketConfig.ticketIdField, clientConfig.options)
@@ -123,6 +123,8 @@ async function handleTicket(ticketConfig, ticket, mapping, clientConfig, include
123
123
  scripts = allScripts.GET || [];
124
124
  }
125
125
 
126
+ globalScriptParams.id = ticket[ticketConfig.requestIdField]
127
+
126
128
  const requestType = ticketConfig.requestType;
127
129
  if (requestType === 'incident') {
128
130
  checkFieldsIncident(ticket, globalRelationObjects);
@@ -312,7 +314,7 @@ async function updateTicket(ticketConfig, clientConfig, id, ticketData, globalSc
312
314
  relations.keepCIs = [ticket.data.serviceReconId]
313
315
  }
314
316
  //todo Abfangen wenn getTicket nichts liefert.
315
- const update = await arquery.updateEntry(ticketConfig.forms.regular, ticket.data.internalId, ticketData);
317
+ const update = await arquery.updateEntry(ticketConfig.forms.regular, ticket.data.internalId, ticketData, clientConfig.options);
316
318
  await ticketCIRelationController.updateRelations(ticketConfig, clientConfig, id, relations);
317
319
  //run afterExecution
318
320
  if (scripts && scripts.afterExecution) {
package/docs/_sidebar.md CHANGED
@@ -11,6 +11,7 @@
11
11
  - [Mapping](configuration/mapping)
12
12
  - [Client Configuration](configuration/clients)
13
13
  - [Events](configuration/events)
14
+ - [Webhooks](configuration/webhooks)
14
15
 
15
16
  - Data manipulation
16
17
 
package/docs/adapter.md CHANGED
@@ -308,6 +308,9 @@ e.g.
308
308
  }
309
309
  ```
310
310
 
311
+ * impersonateUser
312
+
313
+ Can be used to set the user during adapter calls.
311
314
 
312
315
  * countOnly (only search)
313
316
 
@@ -320,6 +323,7 @@ const options = {
320
323
  limit: 100,
321
324
  offset: 100,
322
325
  dafeFormat: "yyyy-MM-dd HH:mm:ss.SSSZ",
326
+ impersonateUser: "Allen",
323
327
  sort: {
324
328
  "Name": 1,
325
329
  "Status": -1
@@ -312,6 +312,21 @@ ADMIN_USERS=username1, username2
312
312
 
313
313
  Loglevel of the api. Defaults to *error*
314
314
 
315
+ ## Certificates
316
+
317
+ ### NODE_EXTRA_CA_CERTS
318
+
319
+ If you need to validate custom certificates in your webhooks you can define a file with them here.
320
+
321
+ Sample:
322
+
323
+ *NODE_EXTRA_CA_CERTS = "/home/node/app/ssl/Chain.crt"*
324
+
325
+ This file needs to be available within the container.
326
+
327
+ [See also](https://nodejs.org/api/cli.html#node_extra_ca_certsfile)
328
+
329
+
315
330
  # GUI
316
331
 
317
332
  ## SMILEconnect
@@ -381,3 +396,15 @@ Use this to disable modules in SMILEconnect.
381
396
 
382
397
  Sample:
383
398
  *REACT_APP_DISABLED_MODULES=workOrder,problem*
399
+
400
+ ### REACT_APP_MAPPING_SYNC
401
+ If you need to disable the Field Sync from Form mapping to new mapping (for example incident to newIncident),
402
+ you can set this parameter to DISABLE
403
+ Sample:
404
+ *REACT_APP_MAPPING_SYNC=DISABLE*
405
+
406
+ ### REACT_APP_MAPPING_SYNC_CHECK
407
+ If you need to disable the Field Sync Warning From form mapping to new mapping (for example incident to newIncident),
408
+ you can set this parameter to DISABLE.
409
+ Sample:
410
+ *REACT_APP_MAPPING_SYNC_CHECK=DISABLE*
@@ -0,0 +1,97 @@
1
+ # Webhooks
2
+
3
+ ## Sample
4
+
5
+ ```json
6
+ [
7
+ {
8
+ "client": "isms",
9
+ "webhooks": [
10
+ {
11
+ "name": "allInc",
12
+ "url": "https://myUrl.example.com",
13
+ "event": "INC",
14
+ "secret": "123geheim",
15
+ "insecure": false,
16
+ "jsonSpace": 2,
17
+ "auth": {
18
+ "type": "basic",
19
+ "user": "user123",
20
+ "password": "pass123"
21
+ },
22
+ "scripts": [
23
+ "p1",
24
+ "p4"
25
+ ]
26
+ }
27
+ ]
28
+ }
29
+ ]
30
+ ```
31
+
32
+ ## Configuration Options
33
+
34
+ ### name
35
+
36
+ Name of the webhook.
37
+
38
+ ### url
39
+
40
+ Url that will be called. All webhooks will be sent as POST requests.
41
+
42
+ ### event
43
+
44
+ The event that the webhook subscribed to. The system will check if the definition is contained in the actual event.
45
+
46
+ e.g.
47
+
48
+ * INC will capture all Incident events.
49
+ * modified will capture all modified events.
50
+
51
+ ### secret
52
+
53
+ This mechanism can be used if the webhook endpoint does not support authentication but still wants to verify that the sent webhook is valid and was sent by your system.
54
+
55
+ If set the body of the request will hashed and the signature will be added to the header as *x-isapi-signature* in the format *algorithm:signature*
56
+
57
+ e.g. The following body with the secret *123geheim* will generate the below signature header.
58
+
59
+ ```json
60
+ {
61
+ "event": "TestOnly",
62
+ "objectId": "Test1234",
63
+ "objectId2": "Test1234.3"
64
+ }
65
+ ```
66
+
67
+ "x-isapi-signature": "sha256:66976bf984b48cd18441b489c50a886dcf51f910e82d3736e8c5e00110c3df95"
68
+
69
+ ### insecure
70
+
71
+ Disables SSL certification validation. Use this with caution.
72
+
73
+ ### jsonSpace
74
+
75
+ When set the body of the webhook will be formatted with spaces.
76
+
77
+ ### auth
78
+
79
+ If your endpoint requires authentication this can be used.
80
+
81
+ #### type
82
+
83
+ Type of authentication. Currently only basic is supported.
84
+
85
+ #### user
86
+
87
+ Username for basic authentication.
88
+
89
+ #### password
90
+
91
+ Passwort for basic authentication.
92
+
93
+ ###
94
+
95
+ ### scripts
96
+
97
+ An array of scripts that are executed when the webhook is fired. Can be used to transform data or to populate the outbound request with ticket data.
package/docs/releases.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## API
4
4
 
5
+ ### 1.57.1 - 25.03.22
6
+ Remove misleading error from CustomFormMappings
7
+
8
+ ### 1.57.0 - 25.03.22
9
+
10
+ Add impersonate to update requests.
11
+ Impersonate works not on the following requests:
12
+ - Add/Read Attachments
13
+ - Ticket/CI Relations
14
+
15
+ Make DatasetId-, ReconId- & InstanceId-Fields dynamic on CMDBCreate Operations
16
+
5
17
  ### 1.56.0 - 03.03.22
6
18
  Support Script Rename with references
7
19
  Add event to globalScriptParams
@@ -182,12 +194,16 @@ Update Record added to [Remedy Adapter](adapter#remedy).
182
194
  The eventmanager will check all outbound webhooks for an event. If one fails, the whole Event will be set to error and the details will be added to the error message.
183
195
 
184
196
  ## GUI
197
+ ### 1.9.2 - 08.03.22
198
+ Fixed: Sync mapping not working correctly in some situations
199
+ Feat: Mapping: Added warning to "new" Form mapping, if a mapping is missing (you can disble this with parameter REACT_APP_MAPPING_SYNC_CHECK=DISABLE
200
+ Feat: Use the following Parameter to disable sync from module mapping to new mapping REACT_APP_MAPPING_SYNC=DISABLE
185
201
 
186
- ### 1.8.2 - 2.3.22
202
+ ### 1.8.2 - 02.03.22
187
203
  Fixed: delete webhooks for client when client is deleted
188
204
  Fixed: delete button / menu is hidden when client or scriptname is too long
189
205
 
190
- ### 1.8.0 - 3.2.22
206
+ ### 1.8.0 - 03.02.22
191
207
  Fixed wrong Script Config for Custom Form Scripts (attribute clients instead of scripts)
192
208
  Fixed Scrolling
193
209
  Fixed navigation error from "Import/Export" to a client
package/docs/scripts.md CHANGED
@@ -115,8 +115,12 @@ Global script params are set by the application and handed over to the script. T
115
115
 
116
116
  **classId**: the classId of cmdbobjects. Only set in POST & PUT actions
117
117
 
118
+ **event**: the event that this transaction creates. e.g. INC_Create, CHG_TAS_Modify
119
+
118
120
  **sourceData**: Contains the original body for PUT/POST request. This can be used scripts to access custom data that was removed during mapping.
119
121
 
122
+ **user**: Contains the full configuration of the client. The attribute user.config.options.impersonateUser might be overwritten by the dynamic passed value if user.config.options.allowDynamicImpersonate ist set to true.
123
+
120
124
  ```json
121
125
  {
122
126
  "query": {
@@ -127,13 +131,42 @@ Global script params are set by the application and handed over to the script. T
127
131
  "sourceData": {
128
132
  "data": {
129
133
  "summary": "Short summary",
130
- "notes": "Some details here",
134
+ "notes": "Some details here"
131
135
  },
132
136
  "customData": {
133
137
  "foo": "bar"
134
138
  }
135
139
  },
136
- "id": "INC000000001507"
140
+ "event": "INC_Modify",
141
+ "id": "INC000000001507",
142
+ "user": {
143
+ "id": "255e90dc-73ab-42d9-b952-60cec716c4e8",
144
+ "azp": "isms",
145
+ "scope": "profile issm",
146
+ "exp": 1648203329,
147
+ "config": {
148
+ "options": {
149
+ "dateFormat": "dd.MM.yyyy HH:mm.ss",
150
+ "clientLimit": 100000,
151
+ "impersonateUser": "Bob",
152
+ "allowDynamicImpersonate": true,
153
+ "translateSelectionFields": false
154
+ },
155
+ "custom_Sample:Enrollments": {
156
+ "basequery": "1=1",
157
+ "fields": [
158
+ "Enrollment ID",
159
+ "Enrollee Login",
160
+ "Class ID",
161
+ "Class Title",
162
+ "Class Location",
163
+ "Class Cost",
164
+ "Department",
165
+ "Class Start Date & Time"
166
+ ]
167
+ }
168
+ }
169
+ }
137
170
  }
138
171
  ```
139
172
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manyos/smileconnect-api",
3
- "version": "1.56.0",
3
+ "version": "1.57.1",
4
4
  "description": "A proxy and abstraction layer for BMCs IT Service Management Suite",
5
5
  "main": "app.js",
6
6
  "scripts": {
package/util/arquery.js CHANGED
@@ -362,7 +362,7 @@ function applyMapping(entryData, mapping, constants) {
362
362
  return entryData;
363
363
  }
364
364
 
365
- function updateEntry(form, id, entryData) {
365
+ function updateEntry(form, id, entryData, clientOptions) {
366
366
  let port = 0;
367
367
  if (process.env.AR_PORT && process.env.AR_PORT != undefined)
368
368
  port = process.env.AR_PORT;
@@ -376,13 +376,16 @@ function updateEntry(form, id, entryData) {
376
376
  log.debug('New Entry', myEntry);
377
377
  //log.debug('object', Object.keys(entryData));
378
378
  return new Promise((resolve, reject) => {
379
- const uri = process.env.BASEURL
379
+ let uri = process.env.BASEURL
380
380
  + "/" + process.env.AR_SERVER
381
381
  + "/" + form
382
382
  + "?port=" + port;
383
383
 
384
+ if (clientOptions && clientOptions.impersonateUser) {
385
+ uri = uri + "&impersonateUser=" + clientOptions.impersonateUser;
386
+ }
384
387
 
385
- var options = {
388
+ const options = {
386
389
  method: 'PUT',
387
390
  uri: uri,
388
391
  body: myEntry,
package/util/config.js CHANGED
@@ -583,6 +583,15 @@ function getFields(form) {
583
583
  });
584
584
  }
585
585
 
586
+ async function getFormFieldById(form, fieldId) {
587
+ const formFields = await getFields(form);
588
+ if (formFields && Array.isArray(formFields)) {
589
+ return formFields.find(item => item.fieldId === fieldId)
590
+ } else {
591
+ return null
592
+ }
593
+ }
594
+
586
595
  const ticketConfig = {
587
596
  "workorders": {
588
597
  "forms": {
@@ -689,5 +698,6 @@ module.exports = {
689
698
  ticketConfig,
690
699
  getCustomFormMapping,
691
700
  setCustomFormMapping,
692
- getDesignPackage
701
+ getDesignPackage,
702
+ getFormFieldById
693
703
  };
@@ -153,7 +153,7 @@ function applyCustomFormMapping2Remedy(entryData, mapping, constants, fields) {
153
153
  delete entryData[mappedName];
154
154
  }
155
155
  } catch (e) {
156
- log.error('mappingError', e)
156
+ //log.error('mappingError', e)
157
157
  }
158
158
  })
159
159