@manyos/smileconnect-api 1.28.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.
Files changed (141) hide show
  1. package/.github/workflows/nodejs.yml +26 -0
  2. package/CHANGELOG.md +75 -0
  3. package/Dockerfile +21 -0
  4. package/README.md +1 -0
  5. package/app.js +316 -0
  6. package/conf/clients.json +2491 -0
  7. package/conf/mapping.json +1048 -0
  8. package/conf/scripts/p1.js +11 -0
  9. package/conf/scripts/p2.js +1 -0
  10. package/conf/scripts/p3.js +1 -0
  11. package/conf/scripts/p4.js +2 -0
  12. package/conf/scripts/script1.js +2 -0
  13. package/conf/scripts/script2.js +2 -0
  14. package/conf/scripts/script3.js +2 -0
  15. package/controller/cmdbobjectController.js +291 -0
  16. package/controller/eventLogController.js +78 -0
  17. package/controller/orgdataController.js +440 -0
  18. package/controller/relatedObjectsController.js +194 -0
  19. package/controller/scriptController.js +213 -0
  20. package/controller/taskController.js +368 -0
  21. package/controller/templateController.js +97 -0
  22. package/controller/ticketCIRelationController.js +522 -0
  23. package/controller/ticketController.js +329 -0
  24. package/controller/ticketWorkLogController.js +195 -0
  25. package/docs/.gitattributes +48 -0
  26. package/docs/404.html +13 -0
  27. package/docs/CNAME +1 -0
  28. package/docs/Gemfile +7 -0
  29. package/docs/Gemfile.lock +249 -0
  30. package/docs/_config.yml +257 -0
  31. package/docs/_data/SocialNetworks.yml +92 -0
  32. package/docs/_data/ui-text.yml +494 -0
  33. package/docs/_includes/disqus.html +17 -0
  34. package/docs/_includes/ext-css.html +7 -0
  35. package/docs/_includes/ext-js.html +7 -0
  36. package/docs/_includes/fb-comment.html +14 -0
  37. package/docs/_includes/footer-minimal.html +16 -0
  38. package/docs/_includes/footer-scripts.html +32 -0
  39. package/docs/_includes/footer.html +51 -0
  40. package/docs/_includes/google_analytics.html +14 -0
  41. package/docs/_includes/gtag.html +11 -0
  42. package/docs/_includes/gtm_body.html +6 -0
  43. package/docs/_includes/gtm_head.html +9 -0
  44. package/docs/_includes/head.html +131 -0
  45. package/docs/_includes/header.html +76 -0
  46. package/docs/_includes/just_comments.html +4 -0
  47. package/docs/_includes/matomo.html +17 -0
  48. package/docs/_includes/nav.html +57 -0
  49. package/docs/_includes/social-share.html +42 -0
  50. package/docs/_includes/staticman-comment.html +22 -0
  51. package/docs/_includes/staticman-comments.html +81 -0
  52. package/docs/_layouts/base.html +35 -0
  53. package/docs/_layouts/default.html +9 -0
  54. package/docs/_layouts/minimal.html +26 -0
  55. package/docs/_layouts/page.html +26 -0
  56. package/docs/_layouts/post.html +82 -0
  57. package/docs/_posts/2015-02-28-test-markdown.md +77 -0
  58. package/docs/aboutme.md +18 -0
  59. package/docs/css/bootstrap-social.css +147 -0
  60. package/docs/css/bootstrap-theme.css +476 -0
  61. package/docs/css/bootstrap-theme.css.map +1 -0
  62. package/docs/css/bootstrap-theme.min.css +5 -0
  63. package/docs/css/bootstrap.css +6566 -0
  64. package/docs/css/bootstrap.css.map +1 -0
  65. package/docs/css/bootstrap.min.css +5 -0
  66. package/docs/css/main-minimal.css +13 -0
  67. package/docs/css/main.css +788 -0
  68. package/docs/css/normalize.css +427 -0
  69. package/docs/css/pygment_highlights.css +61 -0
  70. package/docs/css/staticman.css +180 -0
  71. package/docs/eventlog/events.md +65 -0
  72. package/docs/feed.xml +24 -0
  73. package/docs/general/architecture.md +10 -0
  74. package/docs/general/config.md +192 -0
  75. package/docs/general/field-management.md +119 -0
  76. package/docs/general/release-notes.md +9 -0
  77. package/docs/getting-started.md +19 -0
  78. package/docs/howto/cmdbobjects.md +339 -0
  79. package/docs/howto/incident-worklogs.md +186 -0
  80. package/docs/howto/incidents.md +244 -0
  81. package/docs/howto/sample-config.md +518 -0
  82. package/docs/howto/token.md +71 -0
  83. package/docs/howto/worklog-attachment.md +113 -0
  84. package/docs/img/404-southpark.jpg +0 -0
  85. package/docs/img/architecture.jpeg +0 -0
  86. package/docs/img/attachment-upload.png +0 -0
  87. package/docs/img/avatar-icon.png +0 -0
  88. package/docs/img/bgimage.png +0 -0
  89. package/docs/img/gb-isapi.jpg +0 -0
  90. package/docs/img/install-steps.gif +0 -0
  91. package/docs/img/workflow.png +0 -0
  92. package/docs/index.md +41 -0
  93. package/docs/installation.md +123 -0
  94. package/docs/js/bootstrap.js +2306 -0
  95. package/docs/js/bootstrap.min.js +7 -0
  96. package/docs/js/jquery-1.11.2.min.js +4 -0
  97. package/docs/js/main.js +140 -0
  98. package/docs/js/staticman.js +54 -0
  99. package/docs/openapi.json +15097 -0
  100. package/docs/postinstall.md +169 -0
  101. package/docs/preinstall.md +19 -0
  102. package/docs/spec/index.html +24 -0
  103. package/docs/staticman.yml +110 -0
  104. package/docs/tags.html +34 -0
  105. package/docs/workflow.md +127 -0
  106. package/nodemon.json +3 -0
  107. package/package.json +46 -0
  108. package/routes/appConfigRoutes.js +352 -0
  109. package/routes/ciRelationRoutes.js +38 -0
  110. package/routes/cmdbObjectRoutes.js +154 -0
  111. package/routes/organisationRoutes.js +121 -0
  112. package/routes/peopleRelationRoutes.js +38 -0
  113. package/routes/personRoutes.js +131 -0
  114. package/routes/supportgroupRoutes.js +122 -0
  115. package/routes/taskRoutes.js +306 -0
  116. package/routes/templateRoutes.js +67 -0
  117. package/routes/ticketRoutes.js +181 -0
  118. package/routes/ticketWorkLogRoutes.js +185 -0
  119. package/screwdriver.yaml +52 -0
  120. package/test/appTest.js +3 -0
  121. package/test/changeTest.js +541 -0
  122. package/test/cmdbobjectTest.js +167 -0
  123. package/test/files/logo.png +0 -0
  124. package/test/incidentTest.js +539 -0
  125. package/test/orgdataTest.js +156 -0
  126. package/test/problemTest.js +512 -0
  127. package/test/templateTest.js +80 -0
  128. package/test/testUtils.js +21 -0
  129. package/test/workorderTest.js +544 -0
  130. package/util/arquery.js +416 -0
  131. package/util/auth.js +37 -0
  132. package/util/cache.service.js +52 -0
  133. package/util/config.js +361 -0
  134. package/util/constants.js +73 -0
  135. package/util/mappingUtil.js +96 -0
  136. package/util/paramHelper.js +43 -0
  137. package/util/relationUtil.js +63 -0
  138. package/util/responsehandler.js +92 -0
  139. package/util/schemas/clientConfigSchema.js +180 -0
  140. package/util/schemas/fieldMappingSchema.js +211 -0
  141. package/util/searchUtil.js +148 -0
@@ -0,0 +1,213 @@
1
+ const path = require('path');
2
+ const log = require('@manyos/logger').setupLog('SMILEcatalog_' + path.basename(__filename));
3
+
4
+ const fs = require('fs');
5
+
6
+ const basePath = 'conf';
7
+ const basePathGlobalScripts = basePath + '/scripts';
8
+
9
+ require('dotenv').config();
10
+ const {NodeVM} = require('vm2');
11
+
12
+ //const adapter = require('../util/adapter').getAdapter();
13
+
14
+ function recFindByExt(base,ext,files,result) {
15
+ const isRoot = (files == undefined);
16
+ files = files || fs.readdirSync(base)
17
+ result = result || []
18
+
19
+ files.forEach(
20
+ function (file) {
21
+ const newbase = path.join(base,file)
22
+
23
+ if ( fs.statSync(newbase).isDirectory() ) {
24
+ result = recFindByExt(newbase,ext,fs.readdirSync(newbase),result)
25
+ }
26
+ else {
27
+ if ( file.substr(-1*(ext.length+1)) == '.' + ext ) {
28
+ result.push(newbase)
29
+ }
30
+ }
31
+ }
32
+ )
33
+ //only in root
34
+ if (isRoot) {
35
+ result = result.map(item => item.replace(base, ''));
36
+ }
37
+ return result
38
+ }
39
+
40
+ async function executeScriptInternal(scriptId, requestData, params, executedByScript) {
41
+
42
+ const code = await getGlobalScript(scriptId);
43
+
44
+ if (code == undefined || !code) {
45
+ throw (`Script ${scriptId} does not exist!`);
46
+ }
47
+
48
+ return executeCode(code, requestData, params, null, executedByScript);
49
+ }
50
+
51
+ async function executeScript(scriptId, requestData, params) {
52
+ return executeScriptInternal(scriptId, requestData, params, false)
53
+ }
54
+
55
+ async function executeCode(code, requestData, params, logStream, executedByScript) {
56
+ //todo should only be added once
57
+ /*if (logStream) {
58
+ log.addStream(logStream);
59
+ }*/
60
+
61
+ //try to set user data for sandbox
62
+
63
+ async function executeScriptByScript(scriptId, requestData, params) {
64
+ return executeScriptInternal(scriptId, requestData, params, true)
65
+ }
66
+
67
+ const sandbox = {
68
+ requestData,
69
+ params,
70
+ log,
71
+ script:executeScriptByScript,
72
+ env: {}//process.env
73
+ };
74
+
75
+ sandbox.executedByScript = executedByScript === true;
76
+
77
+ const vm = new NodeVM({
78
+ require: {
79
+ external: true
80
+ },
81
+ sandbox: sandbox,
82
+ wrapper: "none"
83
+ });
84
+
85
+ log.debug('Create vm with sandbox', sandbox);
86
+
87
+ log.debug('run Script', code);
88
+
89
+ //todo Add timeout
90
+ try {
91
+ const result = await vm.run(
92
+ `return new Promise(async function(resolve, reject) {try {${code}} catch (error) {reject(error);}});`,
93
+ 'vm.js');
94
+ log.debug('script ended', result);
95
+ return result;
96
+ } catch (e) {
97
+ throw e;
98
+ }
99
+ }
100
+
101
+ async function getGlobalScript(scriptId) {
102
+ const fileName = basePathGlobalScripts + `/${scriptId}.js`;
103
+ return readScriptFromFile(fileName);
104
+ }
105
+
106
+ async function setGlobalScript(scriptId, code) {
107
+ return setScript(basePathGlobalScripts, scriptId, code);
108
+ }
109
+
110
+ async function setScript(dir, scriptId, code) {
111
+ //create folder first
112
+ log.debug('Create dir', dir);
113
+ if (!fs.existsSync(dir)){
114
+ fs.mkdirSync(dir);
115
+ }
116
+ //create subfolders
117
+ const scriptIdSplit = scriptId.split('/');
118
+ if (scriptIdSplit && scriptIdSplit.length > 1) {
119
+ let subDirName = dir;
120
+ for (x=0; x<scriptIdSplit.length -1; x++) {
121
+ subDirName = subDirName + '/' + scriptIdSplit[x];
122
+ if (!fs.existsSync(subDirName)){
123
+ fs.mkdirSync(subDirName);
124
+ }
125
+ }
126
+ }
127
+
128
+ //create file
129
+ const fileName = `${dir}/${scriptId}.js`;
130
+ log.debug('Write file', fileName);
131
+ return new Promise((res, rej) => {
132
+ fs.writeFile(fileName, code, (err) => {
133
+ if (err) {
134
+ rej(err);
135
+ }
136
+ log.debug(`script written: ${fileName}`);
137
+ res(true);
138
+ });
139
+ });
140
+ }
141
+
142
+ async function deleteScript(dir, scriptId) {
143
+ return new Promise((res, rej) => {
144
+ fs.unlink(`${dir}/${scriptId}.js`, (err) => {
145
+ if (err) {
146
+ rej(err);
147
+ }
148
+ log.debug(`script removed: ${dir}/${scriptId}`);
149
+ res({
150
+ id: scriptId,
151
+ status: "deleted"
152
+ });
153
+ });
154
+ });
155
+ }
156
+
157
+ async function deleteGlobalScript(scriptId) {
158
+ return deleteScript(basePathGlobalScripts, scriptId);
159
+ }
160
+
161
+ async function readScriptFromFile(fileName) {
162
+ log.debug('Read file', fileName);
163
+ const script = fs.readFileSync(fileName,{encoding: 'utf8'});
164
+ log.debug('found script', script);
165
+ return script;
166
+ }
167
+
168
+ async function getScripts(pathName, catalogType, catalogId) {
169
+ const files = recFindByExt(pathName,'js')
170
+ const scriptNames = files.map(file => file.substr(0, file.length-3));
171
+ log.debug(scriptNames);
172
+ const scripts = [];
173
+ for (let x=0; x<scriptNames.length; x++) {
174
+ if (!catalogType) {
175
+ const script = {
176
+ id: scriptNames[x],
177
+ code: await getGlobalScript(scriptNames[x])
178
+ };
179
+ scripts.push(script);
180
+ } else {
181
+ const script = {
182
+ id: scriptNames[x],
183
+ code: await getCatalogScript(catalogType, catalogId, scriptNames[x])
184
+ };
185
+ scripts.push(script);
186
+ }
187
+ }
188
+ return scripts;
189
+ }
190
+
191
+ async function getGlobalScripts() {
192
+ const path = `${basePathGlobalScripts}/`;
193
+ return getScripts(path);
194
+ }
195
+
196
+ async function runScripts(scripts, data) {
197
+ try {
198
+ for (let x = 0; x < scripts.length; x++) {
199
+ await executeScript(scripts[x], data);
200
+ }
201
+ } catch (error) {
202
+ throw error;
203
+ }
204
+ }
205
+
206
+ module.exports = {
207
+ executeScript,
208
+ getGlobalScript,
209
+ getGlobalScripts,
210
+ setGlobalScript,
211
+ deleteGlobalScript,
212
+ runScripts
213
+ };
@@ -0,0 +1,368 @@
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 relationUtil = require('../util/relationUtil');
9
+ const mappingUtil = require('../util/mappingUtil');
10
+ const scriptController = require('./scriptController');
11
+
12
+ const taskCache = new CacheService(process.env.CACHETTL_TASK || 0); // Create a new cache service instance
13
+
14
+ function getTasks(config, category) {
15
+ let query = '1=1';
16
+ if (category)
17
+ query = `'Category' = \"${category}\"`;
18
+ return queryTasks(config, query);
19
+ }
20
+
21
+ function getTasksByRootRequest(config, rootRequestId, rootRequestForm) {
22
+ const query = `'RootRequestID' = \"${rootRequestId}\" AND 'RootRequestFormName' = \"${rootRequestForm}\"`;
23
+ return queryTasks(config, query);
24
+ }
25
+
26
+ async function createTask(clientConfig, rootForm, rootRequestId, taskData, createTaskFlow) {
27
+ const scripts = clientConfig.task.scripts.POST;
28
+ const fields = clientConfig.task.fields;
29
+
30
+ log.debug('data', taskData);
31
+ let subQuery = "'1' = \"rootRequestId\"";
32
+ if (rootForm === CONSTANTS.FORM_WORKORDER) {
33
+ subQuery = `'Work Order ID'=\"${rootRequestId}\"`;
34
+ } else if (rootForm === CONSTANTS.FORM_INCIDENT) {
35
+ subQuery = `'Incident Number'=\"${rootRequestId}\"`;
36
+ } else if (rootForm === CONSTANTS.FORM_PROBLEM) {
37
+ subQuery = `'Problem Investigation ID'=\"${rootRequestId}\"`;
38
+ } else if (rootForm === CONSTANTS.FORM_CHANGE) {
39
+ subQuery = `'Infrastructure Change ID'=\"${rootRequestId}\"`;
40
+ }
41
+ //Read instanceId from Root request
42
+
43
+ const rootRequest = await arquery.executeARQuery(rootForm, null, subQuery, "InstanceId", clientConfig.options)
44
+ log.debug('found RootRequest', rootRequest);
45
+ if (rootRequest.data && Array.isArray(rootRequest.data)) {
46
+ let allTask = [];
47
+ if (Array.isArray(taskData)) {
48
+ allTask = taskData;
49
+ } else {
50
+ allTask.push(taskData);
51
+ }
52
+
53
+ const mapping = config.getMapping('newTask');
54
+ //add required data
55
+
56
+ const allTaskFinal = [];
57
+ allTask.forEach(thisTask => {
58
+ thisTask.TaskName = thisTask.summary;
59
+ thisTask.TaskType = 2000;
60
+ thisTask.Status = 1000;
61
+ thisTask.RootRequestFormName = rootForm;
62
+ thisTask.RootRequestMode = "1";
63
+ thisTask.RootRequestName = rootRequestId;
64
+ thisTask.RootRequestInstanceId = rootRequest.data[0]['InstanceId'];
65
+ thisTask.sequence = thisTask.sequence || "1";
66
+ allTaskFinal.push(thisTask);
67
+ });
68
+
69
+ fields.push('TaskName', 'RootRequestInstanceId', 'TaskType', 'Status', 'RootRequestFormName', 'RootRequestMode', 'RootRequestName', 'sequence')
70
+
71
+ //run preScripts
72
+ if (scripts && scripts.preMapping) {
73
+ await scriptController.runScripts(scripts.preMapping, taskData);
74
+ }
75
+
76
+ taskData = mappingUtil.applyMapping2Remedy(taskData, mapping, clientConfig.task.constants, fields);
77
+
78
+ //run postScripts
79
+ if (scripts && scripts.postMapping) {
80
+ await scriptController.runScripts(scripts.postMapping, taskData);
81
+ }
82
+
83
+ const taskResult = await arquery.createEntry('TMS:Task', taskData, clientConfig.options)
84
+
85
+ //run afterExecution
86
+ if (scripts && scripts.afterExecution) {
87
+ await scriptController.runScripts(scripts.afterExecution, data);
88
+ }
89
+
90
+ log.debug('Create Task Result', taskResult);
91
+ let flowBuilderRequest = {
92
+ "RootRequestFormName" : rootForm,
93
+ "RootRequestName" : rootRequestId,
94
+ "RootRequestInstanceId" : rootRequest.data[0]['InstanceId'],
95
+ "zTmpInternalCommand" : "CREATE",
96
+ "Parent Type" : "0",
97
+ "ParentID" : rootRequest.data[0]['InstanceId'],
98
+ "Parent Name" : rootRequestId
99
+ };
100
+ log.debug('createFlow', createTaskFlow === true);
101
+ if (createTaskFlow != null && createTaskFlow === true ) {
102
+ const mappingflow = config.getMapping('flowBuilder');
103
+
104
+ flowBuilderRequest = mappingUtil.applyMapping2Remedy(flowBuilderRequest, mappingflow, clientConfig.flowBuilder.constants);
105
+
106
+ const taskFlowResult = await arquery.createEntry('TMS:FlowBuilder', flowBuilderRequest, clientConfig.options)
107
+ log.debug('TaskFlowBuilder Result', taskFlowResult);
108
+ return taskResult;
109
+ } else {
110
+ log.debug('Task flow update not requested');
111
+ return taskResult;
112
+ }
113
+ }
114
+ }
115
+
116
+ async function createWorklog(clientConfig, taskId, summary, text, attachment) {
117
+ const task = await getTask(clientConfig,taskId)
118
+ const fields = clientConfig.taskWorklog.fields;
119
+
120
+ const taskInstanceId = task.instanceId;
121
+
122
+ const scripts = clientConfig.taskWorklog.scripts.POST;
123
+
124
+ const mapping = config.getMapping('taskWorklog');
125
+
126
+ log.debug('mapping', mapping);
127
+ let data = {
128
+ "Secure Log" : "Yes",
129
+ "summary" : summary,
130
+ "text" : text,
131
+ "TaskOrTaskGroupID" : taskId,
132
+ "TaskOrTaskGroupInstanceId" : taskInstanceId
133
+ };
134
+
135
+ fields.push(
136
+ 'Secure Log',
137
+ 'TaskOrTaskGroupID',
138
+ 'TaskOrTaskGroupInstanceId'
139
+ );
140
+
141
+ //run preScripts
142
+ if (scripts && scripts.preMapping) {
143
+ await scriptController.runScripts(scripts.preMapping, data);
144
+ }
145
+
146
+ data = mappingUtil.applyMapping2Remedy(data, mapping, clientConfig.taskWorklog.constants, fields);
147
+
148
+ //run postScripts
149
+ if (scripts && scripts.postMapping) {
150
+ await scriptController.runScripts(scripts.postMapping, data);
151
+ }
152
+
153
+ const result = await arquery.createEntry('TMS:WorkInfo', data, clientConfig.options)
154
+
155
+ //run afterExecution
156
+ if (scripts && scripts.afterExecution) {
157
+ await scriptController.runScripts(scripts.afterExecution, data);
158
+ }
159
+
160
+ return(result);
161
+ //todo add attachment handling
162
+ }
163
+
164
+ function queryTasks(clientConfig, query) {
165
+ const scripts = clientConfig.task.scripts.GET;
166
+
167
+ const key = clientConfig.task.basequery + clientConfig.task.fields.toString() + query;
168
+ log.debug('Cachekey is', key);
169
+
170
+ const mapping = config.getMapping('task');
171
+ log.debug('mapping', mapping);
172
+
173
+ return taskCache.get(key, async function () {
174
+ const result = await arquery.executeARQuery('TMS:Task', clientConfig.task.basequery || null, query, clientConfig.task.fields.toString() || '1', clientConfig.options)
175
+ const globalRelationObjects = relationUtil.prepareGlobalRelationObject();
176
+ if (result.data && Array.isArray(result.data)) {
177
+ let x;
178
+ for (x=0; x< result.data.length; x++) {
179
+ const element = result.data[x];
180
+ //check for included objects
181
+ const customerId = element['Customer Person ID'];
182
+ if (customerId != null && customerId !== undefined)
183
+ globalRelationObjects.persons.add(customerId);
184
+
185
+ const supportGroupId = element['Support Group ID'];
186
+ if (supportGroupId != null && supportGroupId !== undefined)
187
+ globalRelationObjects.supportgroups.add(supportGroupId);
188
+
189
+ const supportGroupId2 = element['Support Group ID 2'];
190
+ if (supportGroupId2 != null && supportGroupId2 !== undefined)
191
+ globalRelationObjects.supportgroups.add(supportGroupId2);
192
+
193
+ const requestorId = element['Requested By Person ID'];
194
+ if (requestorId != null && requestorId !== undefined)
195
+ globalRelationObjects.supportgroups.add(requestorId);
196
+
197
+ //run preScripts
198
+ if (scripts && scripts.preMapping) {
199
+ await scriptController.runScripts(scripts.preMapping, element);
200
+ }
201
+
202
+ //Apply mapping
203
+ mapping.forEach(function (mappingEntry) {
204
+ try {
205
+ Object.defineProperty(element, mappingEntry.newName, Object.getOwnPropertyDescriptor(element, mappingEntry.oldName));
206
+ delete element[mappingEntry.oldName];
207
+ } catch (e) {
208
+ //ignore missing mapping
209
+ }
210
+ });
211
+ delete element['Request ID'];
212
+
213
+ //run preScripts
214
+ if (scripts && scripts.postMapping) {
215
+ await scriptController.runScripts(scripts.postMapping, element);
216
+ }
217
+ }
218
+ return ({
219
+ "data": result.data,
220
+ "included": {
221
+ "persons": Array.from(globalRelationObjects.persons),
222
+ "organisations": Array.from(globalRelationObjects.organisations),
223
+ "supportgroups": Array.from(globalRelationObjects.supportgroups)
224
+ }});
225
+ }
226
+ else {
227
+ return ({"data":[]});
228
+ }
229
+ })
230
+ }
231
+
232
+ async function queryWorklogs(clientConfig, query, mapping) {
233
+
234
+ const scripts = clientConfig.taskWorklog.scripts.GET;
235
+
236
+ const fields = clientConfig.taskWorklog.fields;
237
+ const basequery = clientConfig.taskWorklog.basequery;
238
+ const key = 'worklog' + basequery + fields.toString() + query;
239
+ log.debug('Cachekey is ', key);
240
+ if (mapping == null || mapping == undefined) {
241
+ mapping = config.getMapping('taskWorklog');
242
+ }
243
+ log.debug('mapping', mapping);
244
+ log.debug('fields', fields);
245
+
246
+ return taskCache.get(key, async function () {
247
+ const result = await arquery.executeARQuery(CONSTANTS.FORM_TASK_WORKLOG, basequery || null, query, fields.toString() || '1', clientConfig.options)
248
+ if (result.data && Array.isArray(result.data)) {
249
+ let x;
250
+ for (x=0; x< result.data.length; x++) {
251
+ const element = result.data[x];
252
+
253
+ //run preScripts
254
+ if (scripts && scripts.preMapping) {
255
+ await scriptController.runScripts(scripts.preMapping, element);
256
+ }
257
+
258
+ //Apply mapping
259
+ mapping.forEach(function (mappingEntry) {
260
+ try {
261
+ Object.defineProperty(element, mappingEntry.newName, Object.getOwnPropertyDescriptor(element, mappingEntry.oldName));
262
+ delete element[mappingEntry.oldName];
263
+ } catch (e) {
264
+ //ignore missing mapping
265
+ }
266
+ });
267
+ //delete element['Entry ID'];
268
+
269
+ //run postScripts
270
+ if (scripts && scripts.postMapping) {
271
+ await scriptController.runScripts(scripts.postMapping, element);
272
+ }
273
+ }
274
+ return {
275
+ "data": result.data
276
+ };
277
+ } else {
278
+ return {"data":[]};
279
+ }
280
+ });
281
+ }
282
+
283
+ async function getTask(clientConfig, id) {
284
+ const query = `'Task ID'=\"${id}\"`;
285
+ const tasks = await queryTasks(clientConfig, query);
286
+ return tasks.data[0];
287
+ }
288
+
289
+ async function getTaskByRootRequest(config, rootRequestId, taskId) {
290
+ const query = `'Task ID'=\"${taskId}\" AND 'RootRequestID' = \"${rootRequestId}\"`;
291
+ const returnValue = await queryTasks(config, query);
292
+ const task = returnValue.data[0];
293
+ return {data: task, included: returnValue.included};
294
+ }
295
+
296
+ function getTaskWorklogs(config, taskId) {
297
+ const query = `'TaskOrTaskGroupID'=\"${taskId}\"`;
298
+ return queryWorklogs(config, query);
299
+ }
300
+
301
+ async function getTaskWorklog(config, taskId, worklogId) {
302
+ const query = `'TaskOrTaskGroupID'=\"${taskId}\" AND 'Work Info ID'=\"${worklogId}\"`;
303
+ const returnValue = await queryWorklogs(config, query);
304
+ log.debug ('rtn', returnValue);
305
+ const worklog = returnValue.data[0];
306
+ return {data: worklog, included: returnValue.included};
307
+ }
308
+
309
+ async function updateTask(clientConfig, id, taskData) {
310
+ const mapping = config.getMapping('task');
311
+ const taskConstants = clientConfig.task.constants;
312
+ const scripts = clientConfig.task.scripts.PUT;
313
+ const fields = clientConfig.task.fields;
314
+
315
+ //run preScripts
316
+ if (scripts && scripts.preMapping) {
317
+ await scriptController.runScripts(scripts.preMapping, taskData);
318
+ }
319
+
320
+ taskData = mappingUtil.applyMapping2Remedy(taskData, mapping, taskConstants, fields);
321
+
322
+ //run postScripts
323
+ if (scripts && scripts.postMapping) {
324
+ await scriptController.runScripts(scripts.postMapping, taskData);
325
+ }
326
+
327
+ const result = await arquery.updateEntry('TMS:Task', id, taskData);
328
+
329
+ //run afterExecution
330
+ if (scripts && scripts.afterExecution) {
331
+ await scriptController.runScripts(scripts.afterExecution, taskData);
332
+ }
333
+ return result;
334
+ }
335
+
336
+ function setWorklogAttachment(clientConfig, worklogId, file, attachmentId) {
337
+ const fieldId = getAttachmentFieldId(attachmentId);
338
+ return arquery.setAttachment(CONSTANTS.FORM_TASK_WORKLOG, worklogId, fieldId, file);
339
+ }
340
+
341
+ function getWorklogAttachment(clientConfig, worklogId, attachmentId) {
342
+ const fieldId = getAttachmentFieldId(attachmentId);
343
+ return arquery.getAttachment(CONSTANTS.FORM_TASK_WORKLOG, worklogId, fieldId);
344
+ }
345
+
346
+ function getAttachmentFieldId(attachmentId) {
347
+ let attachmentFieldId = 10001831;
348
+ if (attachmentId == 2) {
349
+ attachmentFieldId = 10001832;
350
+ } else if (attachmentId == 3) {
351
+ attachmentFieldId = 10001833;
352
+ }
353
+ log.debug('AttachmentFieldId', attachmentFieldId);
354
+ return attachmentFieldId;
355
+ }
356
+
357
+ module.exports = {
358
+ getTaskByRootRequest,
359
+ getTasks,
360
+ getTaskWorklogs,
361
+ getTaskWorklog,
362
+ updateTask,
363
+ createTask,
364
+ getTasksByRootRequest,
365
+ createWorklog,
366
+ setWorklogAttachment,
367
+ getWorklogAttachment
368
+ };
@@ -0,0 +1,97 @@
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 {getIncludeArray, applyMapping} = require('../util/paramHelper');
8
+ const relationUtil = require('../util/relationUtil');
9
+
10
+ const templateCache = new CacheService(process.env.CACHETTL_TEMPLATE || 1); // Create a new cache service instance
11
+
12
+ function getTemplates(ticketConfig, config, includeString, customOptions) {
13
+ let query = '1=1';
14
+ return queryTemplates(ticketConfig, config, query, null, null, customOptions, includeString);
15
+ }
16
+
17
+ function queryTemplates(ticketConfig, clientConfig, query, mapping, customFields, customOptions, includeString) {
18
+ log.debug('config', ticketConfig);
19
+ const includeArray = getIncludeArray(includeString);
20
+ log.debug('ticketConfig.requestType', ticketConfig.requestType);
21
+ let fields = clientConfig[ticketConfig.requestTemplate].fields;
22
+
23
+ log.debug('fieldi', fields);
24
+ log.debug('else', ticketConfig.requestTemplate);
25
+ const baseQuery = clientConfig[ticketConfig.requestTemplate].basequery;
26
+
27
+ //check for customFields
28
+ if (customFields !== null && customFields !== undefined) {
29
+ fields = customFields;
30
+ }
31
+
32
+ log.debug('fields', fields, customFields);
33
+ const options = {
34
+ ...clientConfig.options, ...customOptions
35
+
36
+ };
37
+
38
+ log.debug('use joined options', options);
39
+
40
+ const key = baseQuery + fields.toString() + query + JSON.stringify(options) + includeArray;
41
+ log.debug('Cachekey is ', key);
42
+ if (mapping == null || mapping == undefined) {
43
+ mapping = config.getMapping(ticketConfig.requestTemplate);
44
+ }
45
+ log.debug('mapping', mapping);
46
+
47
+ return templateCache.get(key, async function () {
48
+ const result = await arquery.executeARQuery(ticketConfig.forms.template, baseQuery || null, query, fields.toString() || '1', options);
49
+ const globalRelationObjects = relationUtil.prepareGlobalRelationObject();
50
+ const tickets = [];
51
+ if (result && result.data && result.data.length) {
52
+ let x = 0;
53
+ for (x=0; x< result.data.length; x++) {
54
+ //const ticket = await handleTemplate(ticketConfig, result.data[x], mapping, clientConfig, includeArray, globalRelationObjects);
55
+ const ticket = result.data[x];
56
+ applyMapping(ticket, mapping, ticketConfig.templateRequestId);
57
+ tickets.push(ticket);
58
+ }
59
+ }
60
+ log.debug('tickets', tickets);
61
+ return {
62
+ "data": tickets,
63
+ "included": globalRelationObjects
64
+ };
65
+ });
66
+ }
67
+
68
+ async function getTemplate(ticketConfig, config, id, mapping, includeString) {
69
+ let query = `'179'="${id}"`;
70
+ /*const requestType = ticketConfig.requestType;
71
+ if (requestType === 'incident') {
72
+ query = `'HPD Template ID'=\"${id}\"`;
73
+ } else if (requestType === 'change') {
74
+ query = `'Infrastructure Change ID'=\"${id}\"`;
75
+ } else if (requestType === 'problem') {
76
+ query = `'Problem Investigation ID'=\"${id}\"`;
77
+ } else if (requestType === 'workOrder') {
78
+ query = `'Work Order ID'=\"${id}\"`;
79
+ }*/
80
+ const returnValue = await queryTemplates(ticketConfig, config, query, mapping, null, null, includeString);
81
+ const ticket = returnValue.data[0];
82
+ return {data: ticket, included: returnValue.included};
83
+ }
84
+
85
+ /*
86
+ function searchTicket(ticketConfig, clientConfig, searchString, fields, options, includeString) {
87
+ const mapping = config.getMapping(ticketConfig.requestType);
88
+ const mappedString = searchUtil.applyMapping(searchString, mapping);
89
+ const customFields = searchUtil.getCustomFields(clientConfig[ticketConfig.requestType].fields, mapping, fields);
90
+ options.sort = searchUtil.applySortMapping(options.sort, mapping);
91
+ return queryTickets(ticketConfig, clientConfig, mappedString, null, customFields, options, includeString);
92
+ }*/
93
+
94
+ module.exports = {
95
+ getTemplate,
96
+ getTemplates
97
+ };