· 8 years ago · Nov 07, 2017, 11:02 AM
1<sara xmlns="http://www.automic.com/sara/snsc">
2 <references>
3 <variable_types>
4 <var_type value="1">Yes / No</var_type>
5 <var_type value="2">Multi Line Text</var_type>
6 <var_type value="3">Multiple Choice</var_type>
7 <var_type value="4">Numeric Scale</var_type>
8 <var_type value="18">Lookup Select Box</var_type>
9 <var_type value="5">Select Box</var_type>
10 <var_type value="6">Single Line Text</var_type>
11 <var_type value="7">CheckBox</var_type>
12 <var_type value="8">Reference</var_type>
13 <var_type value="9">Date</var_type>
14 <var_type value="10">Date/Time</var_type>
15 <var_type value="11">Label</var_type>
16 <var_type value="12">Break</var_type>
17 <var_type value="14">Macro</var_type>
18 <var_type value="15">UI Page</var_type>
19 <var_type value="16">Wide Single Line Text</var_type>
20 <var_type value="17">Macro with Label</var_type>
21 <var_type value="21">List Collector</var_type>
22 <var_type value="22">Lookup Multiple Choice</var_type>
23 <var_type value="23">HTML</var_type>
24 </variable_types>
25 </references>
26 <package name="snsc" version="1.0-SNAPSHOT">
27 <description/>
28
29 <system_properties>
30 <category>
31 <name>Automic</name>
32 <title>This category consists of all SARA OAuth client settings</title>
33 <properties>
34 <property>
35 <suffix>mid_server</suffix>
36 <description>MID Server name to use</description>
37 <type>string</type>
38 <value/>
39 <ignore_cache>false</ignore_cache>
40 <private>false</private>
41 </property>
42 <property>
43 <suffix>workflow_timeout</suffix>
44 <description>Specifies the time during that the status of service/workflow is checked continuesly. The interval of checking is specified by the parameter x_ausgh_snsc.workflow_delay. If the value equals 0, the duration time will be forever, however the number of executing activities in a workflow context is limited by Max activity count. To change the maximum number of workflow activities:
451. Navigate to Workflow > Workflow Editor.
462. Check out a workflow.
473. In the title bar, click the Workflow Properties icon.
484. Click the Activities tab.
495. In the Max activity count field, enter a value that accommodates the expected number of executing activities for the workflow.
506. Click Update.
51*Note: This value is second(s).</description>
52 <type>string</type>
53 <value>0</value>
54 <ignore_cache>false</ignore_cache>
55 <private>false</private>
56 </property>
57 <property>
58 <suffix>workflow_delay</suffix>
59 <description>Specifies the interval of checking a workflow/service's status. If the value equals 0, the time interval will be 60.
60*Note: This value is second(s).</description>
61 <type>string</type>
62 <value>20</value>
63 <ignore_cache>false</ignore_cache>
64 <private>false</private>
65 </property>
66 <property>
67 <suffix>rest_request_timeout</suffix>
68 <description>Specifies the amount of time the instance waits for a response from the web service provider. If the value equals 0, the timeout will be 60.
69*Note: This value is second(s).</description>
70 <type>string</type>
71 <value>120</value>
72 <ignore_cache>false</ignore_cache>
73 <private>false</private>
74 </property>
75 <property>
76 <suffix>service_active</suffix>
77 <description>The default active status of services after importing. Can be "true" for active and "false" for inactive.</description>
78 <type>boolean</type>
79 <value>true</value>
80 <ignore_cache>false</ignore_cache>
81 <private>false</private>
82 </property>
83 </properties>
84 </category>
85</system_properties>
86
87
88 <tables>
89 <table>
90 <name>x_ausgh_snsc_sara_oauth</name>
91 <label>Sara OAuth</label>
92 <extends_table/>
93 <user_role>x_ausgh_snsc.user</user_role>
94 <is_extendable>false</is_extendable>
95 <dictionary_entries>
96 <column>
97 <name>u_access_token</name>
98 <type>string</type>
99 <label>Access Token</label>
100 <max_length>1000</max_length>
101 <hint>Access token from OAuth</hint>
102 </column>
103 <column>
104 <name>u_refresh_token</name>
105 <type>string</type>
106 <label>Refresh Token</label>
107 <max_length>1000</max_length>
108 <hint>Refresh token from OAuth</hint>
109 </column>
110 <column>
111 <name>u_token_expiry</name>
112 <type>string</type>
113 <label>Token Expiry</label>
114 <max_length>40</max_length>
115 <hint>The lived time of token from OAuth</hint>
116 </column>
117 <column>
118 <name>u_token_type</name>
119 <type>string</type>
120 <label>Token Type</label>
121 <max_length>40</max_length>
122 <hint>The type of token from OAuth</hint>
123 </column>
124 <column>
125 <name>u_user</name>
126 <type>string</type>
127 <label>Technical User</label>
128 <max_length>1000</max_length>
129 <display>true</display>
130 <hint>The AE technical user own this token</hint>
131 </column>
132 </dictionary_entries>
133 </table>
134 <table>
135 <name>x_ausgh_snsc_sara_cat_item</name>
136 <label>Sara Catalog Item</label>
137 <extends_table>sc_cat_item</extends_table>
138 <user_role>x_ausgh_snsc.user</user_role>
139 <is_extendable>false</is_extendable>
140 <dictionary_entries>
141 <column>
142 </column>
143 </dictionary_entries>
144 </table>
145 <table>
146 <name>x_ausgh_snsc_sara_variable</name>
147 <label>Sara Variable</label>
148 <extends_table>item_option_new</extends_table>
149 <user_role>x_ausgh_snsc.user</user_role>
150 <is_extendable>false</is_extendable>
151 <dictionary_entries>
152 <column>
153 <name>u_name</name>
154 <type>string</type>
155 <label>Actual Name</label>
156 <max_length>1000</max_length>
157 <display>true</display>
158 <hint>The actual name of variable in AE</hint>
159 </column>
160 <column>
161 <name>u_readonly</name>
162 <type>boolean</type>
163 <label>Read Only</label>
164 <max_length>40</max_length>
165 <hint>This is read-only field or not</hint>
166 </column>
167 <column>
168 <name>u_is_password</name>
169 <type>boolean</type>
170 <label>Is Password</label>
171 <max_length>40</max_length>
172 <hint>This field is marked as password or not</hint>
173 </column>
174 <column>
175 <name>u_is_lookup</name>
176 <type>boolean</type>
177 <label>Is Lookup Control</label>
178 <max_length>40</max_length>
179 <hint>This control is lookup control or not</hint>
180 </column>
181 <column>
182 <name>u_hash</name>
183 <type>string</type>
184 <label>Sara Variable Hash</label>
185 <max_length>32</max_length>
186 <hint>The hash of current lookup values of control from SAPI</hint>
187 </column>
188 </dictionary_entries>
189 </table>
190 <table>
191 <name>x_ausgh_snsc_sara_definition</name>
192 <label>Sara Definition</label>
193 <extends_table/>
194 <user_role>x_ausgh_snsc.user</user_role>
195 <is_extendable>false</is_extendable>
196 <dictionary_entries>
197 <column>
198 <name>u_name</name>
199 <type>string</type>
200 <label>Name</label>
201 <max_length>1000</max_length>
202 <display>true</display>
203 <hint>Name of catalog item or category</hint>
204 </column>
205 <column>
206 <name>u_consume_url</name>
207 <type>string</type>
208 <label>Consume URL</label>
209 <max_length>1000</max_length>
210 <hint>Consume URL of SAPI service</hint>
211 </column>
212 <column>
213 <name>u_sc_item</name>
214 <type>reference</type>
215 <label>Service Catalog Item</label>
216 <max_length>32</max_length>
217 <reference>sc_cat_item</reference>
218 <reference_cascade_rule>delete</reference_cascade_rule>
219 <hint>The corresponding Catalog item in sc_cat_item table</hint>
220 </column>
221 <column>
222 <name>u_service_catalog_category</name>
223 <type>reference</type>
224 <label>Service Catalog Category</label>
225 <max_length>32</max_length>
226 <reference>sc_category</reference>
227 <reference_cascade_rule>delete</reference_cascade_rule>
228 <hint>The corresponding Category in sc_cateogry table</hint>
229 </column>
230 <column>
231 <name>u_var_set</name>
232 <type>reference</type>
233 <label>Sara Variable Set</label>
234 <max_length>32</max_length>
235 <reference>item_option_new_set</reference>
236 <hint>The corresponding Variable Set in item_option_new_set table</hint>
237 </column>
238 <column>
239 <name>u_parent</name>
240 <type>reference</type>
241 <label>Parent Category</label>
242 <max_length>32</max_length>
243 <reference>sc_category</reference>
244 <hint>Reference to parent category, for catalog item it's the parent category (or catalog in SAPI term), for category it's the target category when it was imported.</hint>
245 </column>
246 <column>
247 <name>u_type</name>
248 <type>string</type>
249 <label>Sara Type</label>
250 <max_length>40</max_length>
251 <hint>Type of entity. Can be catalog, service, category</hint>
252 </column>
253 <column>
254 <name>u_hash</name>
255 <type>string</type>
256 <label>Sara Object Hash</label>
257 <max_length>32</max_length>
258 <hint>The hash of response data from SAPI for Catalog Item</hint>
259 </column>
260 <column>
261 <name>u_active</name>
262 <type>boolean</type>
263 <label>Active</label>
264 <max_length>40</max_length>
265 <hint/>
266 </column>
267 </dictionary_entries>
268 </table>
269 <table>
270 <name>x_ausgh_snsc_sara_lookup</name>
271 <label>Sara Lookup</label>
272 <extends_table/>
273 <user_role>catalog</user_role>
274 <is_extendable>false</is_extendable>
275 <dictionary_entries>
276 <column>
277 <name>u_key</name>
278 <type>string</type>
279 <label>Key</label>
280 <max_length>203</max_length>
281 <hint>The key value of lookup value</hint>
282 </column>
283 <column>
284 <name>u_display_name</name>
285 <type>string</type>
286 <label>Display Name</label>
287 <display>true</display>
288 <max_length>1023</max_length>
289 <hint>The display name value of lookup value</hint>
290 </column>
291 <column>
292 <name>u_control_id</name>
293 <type>reference</type>
294 <label>Lookup Control ID</label>
295 <max_length>32</max_length>
296 <reference>x_ausgh_snsc_sara_variable</reference>
297 <reference_cascade_rule>delete</reference_cascade_rule>
298 <hint>The sys_id of control which owns this lookup value</hint>
299 </column>
300 </dictionary_entries>
301 </table>
302 <table>
303 <name>x_ausgh_snsc_sara_config</name>
304 <label>Sara Configuration</label>
305 <extends_table/>
306 <user_role>x_ausgh_snsc.user</user_role>
307 <is_extendable>false</is_extendable>
308 <dictionary_entries>
309 <column>
310 <name>u_client_id</name>
311 <type>string</type>
312 <label>OAuth Client ID</label>
313 <max_length>1000</max_length>
314 <display>true</display>
315 <hint>Identity of OAuth client</hint>
316 </column>
317 <column>
318 <name>u_client_secret</name>
319 <type>string</type>
320 <label>OAuth Client Secret</label>
321 <max_length>1000</max_length>
322 <hint>OAuth client secret string</hint>
323 </column>
324 <column>
325 <name>u_technical_user</name>
326 <type>string</type>
327 <label>Technical User</label>
328 <max_length>1000</max_length>
329 <hint>The Technical User for authenticating with OAuth Server</hint>
330 </column>
331 <column>
332 <name>u_sapi_endpoint</name>
333 <type>string</type>
334 <label>SAPI Endpoint</label>
335 <max_length>1000</max_length>
336 <hint>URL to SAPI root endpoint</hint>
337 </column>
338 <column>
339 <name>u_token_endpoint</name>
340 <type>string</type>
341 <label>OAuth Token Endpoint</label>
342 <max_length>1000</max_length>
343 <hint>Endpoint for token requesting/refreshing</hint>
344 </column>
345 <column>
346 <name>u_auth_endpoint</name>
347 <type>string</type>
348 <label>OAuth Authorization Endpoint</label>
349 <max_length>1000</max_length>
350 <hint>Authorization endpoint for OAuth authentication</hint>
351 </column>
352 </dictionary_entries>
353 </table>
354
355 <table>
356 <name>x_ausgh_snsc_sc_catalog_ist</name>
357 <label>Service Catalog ImportSet</label>
358 <extends_table>sys_import_set_row</extends_table>
359 <is_extendable>false</is_extendable>
360 <dictionary_entries>
361 <column>
362 <name>id</name>
363 <type>string</type>
364 <label>Id</label>
365 <max_length>32</max_length>
366 <hint>Id</hint>
367 </column>
368 <column>
369 <name>title</name>
370 <type>translated_field</type>
371 <label>Title</label>
372 <max_length>100</max_length>
373 <hint>Title</hint>
374 <mandatory>true</mandatory>
375 <display>true</display>
376 </column>
377 <column>
378 <name>active</name>
379 <type>boolean</type>
380 <label>Active</label>
381 <max_length>40</max_length>
382 <hint/>
383 </column>
384 <column>
385 <name>description</name>
386 <type>translated_text</type>
387 <label>Description</label>
388 <max_length>4000</max_length>
389 <hint>Description</hint>
390 </column>
391 </dictionary_entries>
392 </table>
393 <table>
394 <name>x_ausgh_snsc_sc_category_ist</name>
395 <label>Service Category ImportSet</label>
396 <extends_table>sys_import_set_row</extends_table>
397 <is_extendable>false</is_extendable>
398 <dictionary_entries>
399 <column>
400 <name>id</name>
401 <type>string</type>
402 <label>Id</label>
403 <max_length>32</max_length>
404 <hint>Id</hint>
405 </column>
406 <column>
407 <name>title</name>
408 <type>translated_text</type>
409 <label>Title</label>
410 <max_length>100</max_length>
411 <hint>Title</hint>
412 <mandatory>true</mandatory>
413 <display>true</display>
414 </column>
415 <column>
416 <name>homepage_renderer</name>
417 <type>string</type>
418 <label>Homepage Renderer</label>
419 <max_length>32</max_length>
420 <hint>Homepage Renderer</hint>
421 </column>
422 <column>
423 <name>active</name>
424 <type>boolean</type>
425 <label>Active</label>
426 <max_length>40</max_length>
427 <hint/>
428 </column>
429 <column>
430 <name>description</name>
431 <type>translated_text</type>
432 <label>Description</label>
433 <max_length>4000</max_length>
434 <hint>Description</hint>
435 </column>
436 <column>
437 <name>parent</name>
438 <type>string</type>
439 <label>Parent</label>
440 <max_length>32</max_length>
441 <hint>Parent</hint>
442 </column>
443 <column>
444 <name>sc_catalog</name>
445 <type>string</type>
446 <label>Catalog</label>
447 <max_length>32</max_length>
448 <hint>Catalog</hint>
449 </column>
450
451 </dictionary_entries>
452 </table>
453 <table>
454 <name>x_ausgh_snsc_sara_cat_item_ist</name>
455 <label>Catalog Item ImportSet</label>
456 <extends_table>sys_import_set_row</extends_table>
457 <is_extendable>false</is_extendable>
458 <dictionary_entries>
459 <column>
460 <name>id</name>
461 <type>string</type>
462 <label>Id</label>
463 <max_length>32</max_length>
464 <hint>Id</hint>
465 </column>
466 <column>
467 <name>name</name>
468 <type>translated_text</type>
469 <label>Name</label>
470 <max_length>100</max_length>
471 <hint>Name</hint>
472 <mandatory>true</mandatory>
473 <display>true</display>
474 </column>
475 <column>
476 <name>category</name>
477 <type>string</type>
478 <label>Category Reference</label>
479 <max_length>32</max_length>
480 <hint>Category Reference</hint>
481 </column>
482 <column>
483 <name>active</name>
484 <type>boolean</type>
485 <label>Active</label>
486 <max_length>40</max_length>
487 <hint/>
488 </column>
489 <column>
490 <name>short_description</name>
491 <type>translated_text</type>
492 <label>Short Description</label>
493 <max_length>200</max_length>
494 <hint>Short Description</hint>
495 </column>
496 <column>
497 <name>description</name>
498 <type>translated_html</type>
499 <label>Description</label>
500 <max_length>8000</max_length>
501 <hint>Description</hint>
502 </column>
503 <column>
504 <name>custom_cart</name>
505 <type>string</type>
506 <label>Custom Cart</label>
507 <max_length>32</max_length>
508 <hint>Custom Cart Reference</hint>
509 </column>
510 <column>
511 <name>use_sc_layout</name>
512 <type>boolean</type>
513 <label>Use Catalog Layout</label>
514 <max_length>40</max_length>
515 <hint/>
516 </column>
517 <column>
518 <name>no_quantity</name>
519 <type>boolean</type>
520 <label>No Quantity</label>
521 <max_length>40</max_length>
522 <hint/>
523 </column>
524 <column>
525 <name>workflow</name>
526 <type>string</type>
527 <label>Workflow</label>
528 <max_length>32</max_length>
529 <hint>Workflow Reference</hint>
530 </column>
531 <column>
532 <name>sc_catalogs</name>
533 <type>string</type>
534 <label>Catalogs</label>
535 <max_length>4000</max_length>
536 <hint>Catalogs</hint>
537 </column>
538 </dictionary_entries>
539 </table>
540 <table>
541 <name>x_ausgh_snsc_item_option_new_set_ist</name>
542 <label>Variable Set ImportSet</label>
543 <extends_table>sys_import_set_row</extends_table>
544 <is_extendable>false</is_extendable>
545 <dictionary_entries>
546 <column>
547 <name>id</name>
548 <type>string</type>
549 <label>Id</label>
550 <max_length>32</max_length>
551 <hint>Id</hint>
552 </column>
553 <column>
554 <name>name</name>
555 <type>string</type>
556 <label>Name</label>
557 <max_length>40</max_length>
558 <hint>Name</hint>
559 <mandatory>true</mandatory>
560 <display>true</display>
561 </column>
562 <column>
563 <name>description</name>
564 <type>string</type>
565 <label>Description</label>
566 <max_length>4000</max_length>
567 <hint>Description</hint>
568 </column>
569 <column>
570 <name>title</name>
571 <type>translated_field</type>
572 <label>Title</label>
573 <max_length>80</max_length>
574 <hint>Title</hint>
575 </column>
576 <column>
577 <name>sys_name</name>
578 <type>string</type>
579 <label>Display Name</label>
580 <max_length>255</max_length>
581 <hint>Display Name</hint>
582 </column>
583 <column>
584 <name>display_title</name>
585 <type>boolean</type>
586 <label>Display Title</label>
587 <max_length>40</max_length>
588 <hint/>
589 </column>
590 </dictionary_entries>
591 </table>
592 <table>
593 <name>x_ausgh_snsc_io_set_item_ist</name>
594 <label>Catalog Variable Set ImportSet</label>
595 <extends_table>sys_import_set_row</extends_table>
596 <is_extendable>false</is_extendable>
597 <dictionary_entries>
598 <column>
599 <name>id</name>
600 <type>string</type>
601 <label>Id</label>
602 <max_length>32</max_length>
603 <hint>Id</hint>
604 </column>
605 <column>
606 <name>sc_cat_item</name>
607 <type>string</type>
608 <label>Catalog Item</label>
609 <max_length>32</max_length>
610 <hint>Catalog Item</hint>
611 <mandatory>true</mandatory>
612 <display>true</display>
613 </column>
614 <column>
615 <name>variable_set</name>
616 <type>string</type>
617 <label>Variable Set</label>
618 <max_length>32</max_length>
619 <hint>Variable Set</hint>
620 <mandatory>true</mandatory>
621 </column>
622 </dictionary_entries>
623 </table>
624 <table>
625 <name>x_ausgh_snsc_sara_definition_ist</name>
626 <label>Sara Definition ImportSet</label>
627 <user_role>x_ausgh_snsc.user</user_role>
628 <is_extendable>false</is_extendable>
629 <extends_table>sys_import_set_row</extends_table>
630 <dictionary_entries>
631 <column>
632 <name>id</name>
633 <type>string</type>
634 <label>Id</label>
635 <max_length>32</max_length>
636 <hint>Id</hint>
637 </column>
638 <column>
639 <name>u_name</name>
640 <type>string</type>
641 <label>Name</label>
642 <max_length>1000</max_length>
643 <display>true</display>
644 <hint>Name of catalog item or category</hint>
645 <mandatory>true</mandatory>
646 </column>
647 <column>
648 <name>u_consume_url</name>
649 <type>string</type>
650 <label>Consume URL</label>
651 <max_length>1000</max_length>
652 <hint>Consume URL of SAPI service</hint>
653 </column>
654 <column>
655 <name>u_sc_item</name>
656 <type>string</type>
657 <label>Service Catalog Item</label>
658 <max_length>32</max_length>
659 <hint>The corresponding Catalog item in sc_cat_item table</hint>
660 </column>
661 <column>
662 <name>u_service_catalog_category</name>
663 <type>string</type>
664 <label>Service Catalog Category</label>
665 <max_length>32</max_length>
666 <hint>The corresponding Category in sc_cateogry table</hint>
667 </column>
668 <column>
669 <name>u_var_set</name>
670 <type>string</type>
671 <label>Sara Variable Set</label>
672 <max_length>32</max_length>
673 <hint>The corresponding Variable Set in item_option_new_set table</hint>
674 </column>
675 <column>
676 <name>u_parent</name>
677 <type>string</type>
678 <label>Parent Category</label>
679 <max_length>32</max_length>
680 <hint>Reference to parent category, for catalog item it's the parent category (or catalog in SAPI term), for category it's the target category when it was imported.</hint>
681 </column>
682 <column>
683 <name>u_type</name>
684 <type>string</type>
685 <label>Sara Type</label>
686 <max_length>40</max_length>
687 <hint>Type of entity. Can be catalog, service, category</hint>
688 </column>
689 <column>
690 <name>u_hash</name>
691 <type>string</type>
692 <label>Sara Object Hash</label>
693 <max_length>32</max_length>
694 <hint>The hash of response data from SAPI for Catalog Item</hint>
695 </column>
696 <column>
697 <name>u_active</name>
698 <type>boolean</type>
699 <label>Active</label>
700 <max_length>40</max_length>
701 <hint/>
702 </column>
703 </dictionary_entries>
704 </table>
705 <table>
706 <name>x_ausgh_snsc_sara_variable_ist</name>
707 <label>Sara Variable ImportSet</label>
708 <extends_table>sys_import_set_row</extends_table>
709 <user_role>x_ausgh_snsc.user</user_role>
710 <is_extendable>false</is_extendable>
711 <dictionary_entries>
712 <column>
713 <name>id</name>
714 <type>string</type>
715 <label>Id</label>
716 <max_length>32</max_length>
717 <hint>Id</hint>
718 </column>
719 <column>
720 <name>u_name</name>
721 <type>string</type>
722 <label>Actual Name</label>
723 <max_length>1000</max_length>
724 <display>true</display>
725 <hint>The actual name of variable in AE</hint>
726 <mandatory>true</mandatory>
727 <display>true</display>
728 </column>
729 <column>
730 <name>u_readonly</name>
731 <type>boolean</type>
732 <label>Read Only</label>
733 <max_length>40</max_length>
734 <hint>This is read-only field or not</hint>
735 </column>
736 <column>
737 <name>u_is_password</name>
738 <type>boolean</type>
739 <label>Is Password</label>
740 <max_length>40</max_length>
741 <hint>This field is marked as password or not</hint>
742 </column>
743 <column>
744 <name>u_is_lookup</name>
745 <type>boolean</type>
746 <label>Is Lookup Control</label>
747 <max_length>40</max_length>
748 <hint>This control is lookup control or not</hint>
749 </column>
750 <column>
751 <name>u_hash</name>
752 <type>string</type>
753 <label>Sara Variable Hash</label>
754 <max_length>32</max_length>
755 <hint>The hash of current lookup values of control from SAPI</hint>
756 </column>
757 <column>
758 <name>variable_set</name>
759 <type>string</type>
760 <label>Variable Set</label>
761 <max_length>32</max_length>
762 <hint>Variable Set</hint>
763 </column>
764 <column>
765 <name>type</name>
766 <type>string</type>
767 <label>Type</label>
768 <max_length>40</max_length>
769 <hint>Type</hint>
770 </column>
771 <column>
772 <name>macro</name>
773 <type>string</type>
774 <label>Macro</label>
775 <max_length>32</max_length>
776 <hint>Macro</hint>
777 </column>
778 <column>
779 <name>name</name>
780 <type>string</type>
781 <label>Name</label>
782 <max_length>40</max_length>
783 <hint>Name</hint>
784 </column>
785 <column>
786 <name>cat_item</name>
787 <type>string</type>
788 <label>Catalog Item</label>
789 <max_length>32</max_length>
790 <hint>Catalog Item</hint>
791 </column>
792 <column>
793 <name>help_text</name>
794 <type>translated_text</type>
795 <label>Help text</label>
796 <max_length>4000</max_length>
797 <hint>Help text</hint>
798 </column>
799 <column>
800 <name>show_help</name>
801 <type>boolean</type>
802 <label>Show help</label>
803 <max_length>40</max_length>
804 <hint>Show help</hint>
805 </column>
806 <column>
807 <name>include_none</name>
808 <type>boolean</type>
809 <label>Include none</label>
810 <max_length>40</max_length>
811 <hint>Include none</hint>
812 </column>
813 <column>
814 <name>default_value</name>
815 <type>string</type>
816 <label>Default value</label>
817 <max_length>512</max_length>
818 <hint>Default value</hint>
819 </column>
820 <column>
821 <name>question_text</name>
822 <type>translated_field</type>
823 <label>Question text</label>
824 <max_length>255</max_length>
825 <hint>Question text</hint>
826 </column>
827 <column>
828 <name>mandatory</name>
829 <type>boolean</type>
830 <label>Mandatory</label>
831 <max_length>40</max_length>
832 <hint>Mandatory</hint>
833 </column>
834 <column>
835 <name>list_table</name>
836 <type>list_table</type>
837 <label>List table</label>
838 <max_length>80</max_length>
839 <hint>List table</hint>
840 </column>
841 <column>
842 <name>attributes</name>
843 <type>string</type>
844 <label>Variable attributes</label>
845 <max_length>255</max_length>
846 <hint>Variable attributes</hint>
847 </column>
848 <column>
849 <name>lookup_table</name>
850 <type>table_name</type>
851 <label>Lookup from table</label>
852 <max_length>80</max_length>
853 <hint>Lookup from table</hint>
854 </column>
855 <column>
856 <name>lookup_value</name>
857 <type>field_name</type>
858 <label>Lookup value field</label>
859 <max_length>80</max_length>
860 <hint>Lookup value field</hint>
861 </column>
862 <column>
863 <name>reference_qual</name>
864 <type>string</type>
865 <label>Reference qual</label>
866 <max_length>255</max_length>
867 <hint>Reference qual</hint>
868 </column>
869 <column>
870 <name>active</name>
871 <type>boolean</type>
872 <label>Read Only</label>
873 <max_length>40</max_length>
874 <hint>Active</hint>
875 </column>
876 <column>
877 <name>order</name>
878 <type>integer</type>
879 <label>Order</label>
880 <max_length>40</max_length>
881 <hint>Order</hint>
882 </column>
883 </dictionary_entries>
884 </table>
885 <table>
886 <name>x_ausgh_snsc_sara_lookup_ist</name>
887 <label>Sara Lookup ImportSet</label>
888 <extends_table>sys_import_set_row</extends_table>
889 <user_role>catalog</user_role>
890 <is_extendable>false</is_extendable>
891 <dictionary_entries>
892 <column>
893 <name>id</name>
894 <type>string</type>
895 <label>Id</label>
896 <max_length>32</max_length>
897 <hint>Id</hint>
898 </column>
899 <column>
900 <name>u_key</name>
901 <type>string</type>
902 <label>Key</label>
903 <max_length>203</max_length>
904 <hint>The key value of lookup value</hint>
905 <mandatory>true</mandatory>
906 <display>true</display>
907 </column>
908 <column>
909 <name>u_display_name</name>
910 <type>string</type>
911 <label>Display Name</label>
912 <display>true</display>
913 <max_length>1023</max_length>
914 <hint>The display name value of lookup value</hint>
915 </column>
916 <column>
917 <name>u_control_id</name>
918 <type>string</type>
919 <label>Lookup Control ID</label>
920 <max_length>32</max_length>
921 <hint>The sys_id of control which owns this lookup value</hint>
922 </column>
923 </dictionary_entries>
924 </table>
925</tables>
926
927
928 <transform_maps>
929 <transform_map>
930 <name>x_ausgh_snsc_sc_catalog_transform_map</name>
931 <source_table>x_ausgh_snsc_sc_catalog_ist</source_table>
932 <target_table>sc_catalog</target_table>
933 <copy_empty_fields>false</copy_empty_fields>
934 <active>true</active>
935 <run_business_rules>false</run_business_rules>
936 <fields>
937 <field>
938 <source_field>id</source_field>
939 <target_field>sys_id</target_field>
940 <coalesce>true</coalesce>
941 </field>
942 <field>
943 <source_field>title</source_field>
944 </field>
945 <field>
946 <source_field>active</source_field>
947 </field>
948 <field>
949 <source_field>description</source_field>
950 </field>
951 </fields>
952 </transform_map>
953 <transform_map>
954 <name>x_ausgh_snsc_sc_category_transform_map</name>
955 <source_table>x_ausgh_snsc_sc_category_ist</source_table>
956 <target_table>sc_category</target_table>
957 <copy_empty_fields>false</copy_empty_fields>
958 <active>true</active>
959 <run_business_rules>false</run_business_rules>
960 <fields>
961 <field>
962 <source_field>id</source_field>
963 <target_field>sys_id</target_field>
964 <coalesce>true</coalesce>
965 </field>
966 <field>
967 <source_field>title</source_field>
968 </field>
969 <field>
970 <source_field>homepage_renderer</source_field>
971 </field>
972 <field>
973 <source_field>active</source_field>
974 </field>
975 <field>
976 <source_field>description</source_field>
977 </field>
978 <field>
979 <source_field>parent</source_field>
980 <reference_value_field>sys_id</reference_value_field>
981 <choice_action>reject</choice_action>
982 </field>
983 <field>
984 <source_field>sc_catalog</source_field>
985 <reference_value_field>sys_id</reference_value_field>
986 </field>
987 </fields>
988 </transform_map>
989 <transform_map>
990 <name>x_ausgh_snsc_sc_cat_item_transform_map</name>
991 <source_table>x_ausgh_snsc_sara_cat_item_ist</source_table>
992 <target_table>x_ausgh_snsc_sara_cat_item</target_table>
993 <active>true</active>
994 <run_business_rules>false</run_business_rules>
995 <copy_empty_fields>false</copy_empty_fields>
996 <fields>
997 <field>
998 <source_field>id</source_field>
999 <target_field>sys_id</target_field>
1000 <coalesce>true</coalesce>
1001 </field>
1002 <field>
1003 <source_field>name</source_field>
1004 </field>
1005 <field>
1006 <source_field>category</source_field>
1007 <choice_action>reject</choice_action>
1008 <reference_value_field>sys_id</reference_value_field>
1009 </field>
1010 <field>
1011 <source_field>active</source_field>
1012 </field>
1013 <field>
1014 <source_field>short_description</source_field>
1015 </field>
1016 <field>
1017 <source_field>description</source_field>
1018 </field>
1019 <field>
1020 <source_field>custom_cart</source_field>
1021 <reference_value_field>sys_id</reference_value_field>
1022 <choice_action>reject</choice_action>
1023 </field>
1024 <field>
1025 <source_field>use_sc_layout</source_field>
1026 </field>
1027 <field>
1028 <source_field>no_quantity</source_field>
1029 </field>
1030 <field>
1031 <source_field>workflow</source_field>
1032 <reference_value_field>sys_id</reference_value_field>
1033 <choice_action>reject</choice_action>
1034 </field>
1035 <field>
1036 <source_field>sc_catalogs</source_field>
1037 </field>
1038 </fields>
1039 </transform_map>
1040 <transform_map>
1041 <name>x_ausgh_snsc_item_option_new_set_transform_map</name>
1042 <source_table>x_ausgh_snsc_item_option_new_set_ist</source_table>
1043 <target_table>item_option_new_set</target_table>
1044 <active>true</active>
1045 <run_business_rules>false</run_business_rules>
1046 <copy_empty_fields>false</copy_empty_fields>
1047 <fields>
1048 <field>
1049 <source_field>id</source_field>
1050 <target_field>sys_id</target_field>
1051 <coalesce>true</coalesce>
1052 </field>
1053 <field>
1054 <source_field>name</source_field>
1055 </field>
1056 <field>
1057 <source_field>description</source_field>
1058 </field>
1059 <field>
1060 <source_field>title</source_field>
1061 </field>
1062 <field>
1063 <source_field>sys_name</source_field>
1064 </field>
1065 <field>
1066 <source_field>display_title</source_field>
1067 </field>
1068 </fields>
1069 </transform_map>
1070 <transform_map>
1071 <name>x_ausgh_snsc_io_set_item_transform_map</name>
1072 <source_table>x_ausgh_snsc_io_set_item_ist</source_table>
1073 <target_table>io_set_item</target_table>
1074 <active>true</active>
1075 <run_business_rules>false</run_business_rules>
1076 <copy_empty_fields>false</copy_empty_fields>
1077 <fields>
1078 <field>
1079 <source_field>id</source_field>
1080 <target_field>sys_id</target_field>
1081 <coalesce>true</coalesce>
1082 </field>
1083 <field>
1084 <source_field>sc_cat_item</source_field>
1085 <reference_value_field>sys_id</reference_value_field>
1086 <choice_action>reject</choice_action>
1087 </field>
1088 <field>
1089 <source_field>variable_set</source_field>
1090 <reference_value_field>sys_id</reference_value_field>
1091 <choice_action>reject</choice_action>
1092 </field>
1093 </fields>
1094 </transform_map>
1095 <transform_map>
1096 <name>x_ausgh_snsc_sara_definition_transform_map</name>
1097 <source_table>x_ausgh_snsc_sara_definition_ist</source_table>
1098 <target_table>x_ausgh_snsc_sara_definition</target_table>
1099 <active>true</active>
1100 <run_business_rules>false</run_business_rules>
1101 <copy_empty_fields>false</copy_empty_fields>
1102 <fields>
1103 <field>
1104 <source_field>id</source_field>
1105 <target_field>sys_id</target_field>
1106 <coalesce>true</coalesce>
1107 </field>
1108 <field>
1109 <source_field>u_name</source_field>
1110 </field>
1111 <field>
1112 <source_field>u_consume_url</source_field>
1113 </field>
1114 <field>
1115 <source_field>u_sc_item</source_field>
1116 <reference_value_field>sys_id</reference_value_field>
1117 <choice_action>reject</choice_action>
1118 </field>
1119 <field>
1120 <source_field>u_service_catalog_category</source_field>
1121 <reference_value_field>sys_id</reference_value_field>
1122 <choice_action>reject</choice_action>
1123 </field>
1124 <field>
1125 <source_field>u_var_set</source_field>
1126 <reference_value_field>sys_id</reference_value_field>
1127 <choice_action>reject</choice_action>
1128 </field>
1129 <field>
1130 <source_field>u_parent</source_field>
1131 <reference_value_field>sys_id</reference_value_field>
1132 <choice_action>ignore</choice_action>
1133 </field>
1134 <field>
1135 <source_field>u_type</source_field>
1136 </field>
1137 <field>
1138 <source_field>u_hash</source_field>
1139 </field>
1140 <field>
1141 <source_field>u_active</source_field>
1142 </field>
1143 </fields>
1144 </transform_map>
1145 <transform_map>
1146 <name>x_ausgh_snsc_sara_variable_transform_map</name>
1147 <source_table>x_ausgh_snsc_sara_variable_ist</source_table>
1148 <target_table>x_ausgh_snsc_sara_variable</target_table>
1149 <active>true</active>
1150 <run_business_rules>false</run_business_rules>
1151 <copy_empty_fields>false</copy_empty_fields>
1152 <fields>
1153 <field>
1154 <source_field>id</source_field>
1155 <target_field>sys_id</target_field>
1156 <coalesce>true</coalesce>
1157 </field>
1158 <field>
1159 <source_field>u_name</source_field>
1160 </field>
1161 <field>
1162 <source_field>u_readonly</source_field>
1163 </field>
1164 <field>
1165 <source_field>u_is_password</source_field>
1166 </field>
1167 <field>
1168 <source_field>u_is_lookup</source_field>
1169 </field>
1170 <field>
1171 <source_field>u_hash</source_field>
1172 </field>
1173 <field>
1174 <source_field>variable_set</source_field>
1175 <reference_value_field>id</reference_value_field>
1176 <choice_action>reject</choice_action>
1177 </field>
1178 <field>
1179 <source_field>type</source_field>
1180 </field>
1181 <field>
1182 <source_field>macro</source_field>
1183 </field>
1184 <field>
1185 <source_field>name</source_field>
1186 </field>
1187 <field>
1188 <source_field>cat_item</source_field>
1189 <reference_value_field>sys_id</reference_value_field>
1190 <choice_action>reject</choice_action>
1191 </field>
1192 <field>
1193 <source_field>help_text</source_field>
1194 </field>
1195 <field>
1196 <source_field>show_help</source_field>
1197 </field>
1198 <field>
1199 <source_field>include_none</source_field>
1200 </field>
1201 <field>
1202 <source_field>default_value</source_field>
1203 </field>
1204 <field>
1205 <source_field>question_text</source_field>
1206 </field>
1207 <field>
1208 <source_field>mandatory</source_field>
1209 </field>
1210 <field>
1211 <source_field>list_table</source_field>
1212 </field>
1213 <field>
1214 <source_field>attributes</source_field>
1215 </field>
1216 <field>
1217 <source_field>lookup_table</source_field>
1218 </field>
1219 <field>
1220 <source_field>lookup_value</source_field>
1221 </field>
1222 <field>
1223 <source_field>reference_qual</source_field>
1224 </field>
1225 <field>
1226 <source_field>active</source_field>
1227 </field>
1228 <field>
1229 <source_field>order</source_field>
1230 </field>
1231 </fields>
1232 </transform_map>
1233 <transform_map>
1234 <name>x_ausgh_snsc_sara_lookup_transform_map</name>
1235 <source_table>x_ausgh_snsc_sara_lookup_ist</source_table>
1236 <target_table>x_ausgh_snsc_sara_lookup</target_table>
1237 <active>true</active>
1238 <run_business_rules>false</run_business_rules>
1239 <copy_empty_fields>true</copy_empty_fields>
1240 <fields>
1241 <field>
1242 <source_field>id</source_field>
1243 <target_field>sys_id</target_field>
1244 <coalesce>true</coalesce>
1245 </field>
1246 <field>
1247 <source_field>u_key</source_field>
1248 </field>
1249 <field>
1250 <source_field>u_display_name</source_field>
1251 </field>
1252 <field>
1253 <source_field>u_control_id</source_field>
1254 <reference_value_field>sys_id</reference_value_field>
1255 <choice_action>ignore</choice_action>
1256 </field>
1257 </fields>
1258 </transform_map>
1259</transform_maps>
1260
1261
1262 <script_includes>
1263 <script_include>
1264 <name>SaraCommon</name>
1265 <script><![CDATA[/**
1266 * This class is comprised of global parameters in SARA connector. It shouldn't be instantiated
1267 * and fields will be accessed in static-like fashion (think Java), eg.: SaraCommon.username
1268 */
1269var SaraCommon = Class.create();
1270SaraCommon.prototype = {
1271 initialize: function () {},
1272
1273 type: 'SaraCommon'
1274};
1275
1276SaraCommon.PROP_PREFIX = 'x_ausgh_snsc';
1277SaraCommon.OAUTH_IMPORT_SUCCESS = 0;
1278SaraCommon.OAUTH_AUTHENTICATION_FAILED = 1;
1279SaraCommon.OAUTH_INVALID_TOKEN = 2;
1280SaraCommon.OAUTH_TOKEN_EXPIRED = 3;
1281
1282SaraCommon.DEFAULT_CATALOG = 'Service Catalog';
1283SaraCommon.DEFAULT_AUTOMIC_CATALOG = 'Automic Service Catalog';
1284SaraCommon.DEFAULT_CATEGORY = 'Automic Services';
1285SaraCommon.CATALOGS_LIMIT = 1000;
1286SaraCommon.SERVICES_LIMIT = 10;
1287
1288SaraCommon.WORKFLOW_STATUS_CODE = {
1289 ENDED_OK: 1900
1290};
1291
1292SaraCommon.ROLES = {
1293 ADMIN: 'x_ausgh_snsc.admin',
1294 USER: 'x_ausgh_snsc.user'
1295};
1296
1297SaraCommon.EMPTY_VALUE = {
1298 KEY: 'sara_empty_key',
1299 VALUE: ' '
1300};
1301
1302SaraCommon.CUSTOM_CART_NAME = '';
1303
1304SaraCommon.VAR_TYPE = {
1305 YES_NO: 1,
1306 MULTI_LINE_TEXT: 2,
1307 MULTI_CHOICE: 3,
1308 NUM_SCALE: 4,
1309 SELECT_BOX: 5,
1310 SINGLE_LINE_TEXT: 6,
1311 CHECK_BOX: 7,
1312 REFERENCE: 8,
1313 DATE: 9,
1314 DATE_TIME: 10,
1315 LABEL: 11,
1316 BREAK: 12,
1317 MACRO: 14,
1318 UI_PAGE: 15,
1319 WIDE_SINGLE_LINE_TEXT: 16,
1320 MACRO_WITH_LABEL: 17,
1321 LOOKUP_SELECT_BOX: 18,
1322 CONTAINER_START: 19,
1323 CONTAINER_END: 20,
1324 LIST_COLLECTOR: 21,
1325 LOOKUP_MULTI_CHOICE: 22,
1326 HTML: 23
1327};
1328
1329SaraCommon.CONTROL_NAME = {
1330 CLIENT_SCRIPTS: 'sara_client_scripts',
1331 HIDDEN_CONTROL: 'sara_hidden_control'
1332};
1333
1334SaraCommon.SCOPED_APP = 'x_ausgh_snsc';
1335
1336SaraCommon.SYSTEM_PROPERTY_NAME = {
1337 MID_SERVER: 'mid_server',
1338 REST_REQUEST_TIMEOUT: 'rest_request_timeout',
1339 SERVICE_ACTIVE: 'service_active',
1340 WORKFLOW_TIMEOUT: 'workflow_timeout',
1341 WORKFLOW_DELAY: 'workflow_delay'
1342};
1343
1344SaraCommon.CONFIG_NAME = {
1345 CLIENT_ID: 'client_id',
1346 CLIENT_SECRET: 'client_secret',
1347 TECHNICAL_USER: 'technical_user',
1348 SAPI_ENDPOINT: 'sapi_endpoint',
1349 TOKEN_ENDPOINT: 'token_endpoint',
1350 AUTH_ENDPOINT: 'auth_endpoint'
1351};
1352
1353SaraCommon.REST_NAME = {
1354 SAPI: 'Sara - SAPI Services',
1355 OAUTH: 'Sara - OAuth Services'
1356};
1357
1358// List of properties will be kept when syncing services
1359SaraCommon.KEEP_SERIVCE_PROPERTIES = [];
1360
1361SaraCommon.TABLE_NAME = {
1362 //Sara tables
1363 SARA_CONFIG: 'x_ausgh_snsc_sara_config',
1364 SARA_DEFINITION: 'x_ausgh_snsc_sara_definition',
1365 SARA_INSTALL_LOG: 'u_snsc_install_log',
1366 SARA_LOOKUP: 'x_ausgh_snsc_sara_lookup',
1367 SARA_OAUTH: 'x_ausgh_snsc_sara_oauth',
1368 SARA_VARIABLE: 'x_ausgh_snsc_sara_variable',
1369 SARA_CAT_ITEM: 'x_ausgh_snsc_sara_cat_item',
1370 //ImportSet tables,
1371 SN_CATALOG_IST: 'x_ausgh_snsc_sc_catalog_ist',
1372 SN_CATEGORY_IST: 'x_ausgh_snsc_sc_category_ist',
1373 SN_VARIABLE_SET_IST: 'x_ausgh_snsc_item_option_new_set_ist',
1374 SN_VARIABLE_SET_ITEM_IST: 'x_ausgh_snsc_io_set_item_ist',
1375 SARA_DEFINITION_IST: 'x_ausgh_snsc_sara_definition_ist',
1376 SARA_VARIABLE_IST: 'x_ausgh_snsc_sara_variable_ist',
1377 SARA_LOOKUP_IST: 'x_ausgh_snsc_sara_lookup_ist',
1378 SARA_CAT_ITEM_IST: 'x_ausgh_snsc_sara_cat_item_ist',
1379 //ServiceNow tables
1380 SN_APPLICATION: 'sys_app',
1381 SN_APPLICATION_CATEGORY: 'sys_app_category',
1382 SN_APPLICATION_FILE: 'sys_app_file',
1383 SN_APPLICATION_MENU: 'sys_app_application',
1384 SN_APPLICATION_MODULE: 'sys_app_module',
1385 SN_AUTO_SCRIPT: 'sysauto_script',
1386 SN_CATALOG: 'sc_catalog',
1387 SN_CATALOG_ITEM: 'sc_cat_item',
1388 SN_CATALOG_ITEM_WIZARD: 'sc_cat_item_wizard',
1389 SN_CATALOG_SCRIPT_CLIENT: 'catalog_script_client',
1390 SN_CATEGORY: 'sc_category',
1391 SN_DB_OBJECT: 'sys_db_object',
1392 SN_DICTIONARY: 'sys_dictionary',
1393 SN_DOCUMENTATION: 'sys_documentation',
1394 SN_ECC_QUEUE: 'ecc_queue',
1395 SN_FIX_SCRIPT: 'sys_script_fix',
1396 SN_HOMEPAGE_RENDERER: 'sc_homepage_renderer',
1397 SN_JOURNAL_FIELD: 'sys_journal_field',
1398 SN_METADATA: 'sys_metadata',
1399 SN_PROCESSOR: 'sys_processor',
1400 SN_PROPERTIES: 'sys_properties',
1401 SN_PROPERTIES_CATEGORY: 'sys_properties_category',
1402 SN_PROPERTIES_CATEGORY_RELATIONSHIP: 'sys_properties_category_m2m',
1403 SN_REST_MESSAGE: 'sys_rest_message',
1404 SN_REST_MESSAGE_FN: 'sys_rest_message_fn',
1405 SN_REST_MESSAGE_FN_HEADERS: 'sys_rest_message_fn_headers',
1406 SN_REST_MESSAGE_HEADERS: 'sys_rest_message_headers',
1407 SN_ROLE: 'sys_user_role',
1408 SN_SECURITY_ACL: 'sys_security_acl',
1409 SN_SECURITY_ACL_ROLE: 'sys_security_acl_role',
1410 SN_SCRIPT_INCLUDES: 'sys_script_include',
1411 SN_UI_MACRO: 'sys_ui_macro',
1412 SN_UI_PAGE: 'sys_ui_page',
1413 SN_UI_SCRIPT: 'sys_ui_script',
1414 SN_USER: 'sys_user',
1415 SN_USER_GROUP: 'sys_user_group',
1416 SN_VARIABLE: 'item_option_new',
1417 SN_VARIABLE_SET: 'item_option_new_set',
1418 SN_VARIABLE_SET_ITEM: 'io_set_item',
1419 SN_VARIABLE_VALUE: 'sys_variable_value',
1420 SN_WIZARD: 'expert',
1421 SN_WIZARD_CLIENT_SCRIPT: 'expert_script_client',
1422 SN_WIZARD_PANEL: 'expert_panel',
1423 SN_WIZARD_PANEL_TRANSITION: 'expert_panel_transition',
1424 SN_WIZARD_PANEL_VARIABLE: 'expert_panel_variable',
1425 SN_WIZARD_VARIABLE: 'expert_variable',
1426 SN_WORKFLOW: 'wf_workflow',
1427 SN_WORKFLOW_ACTIVITY: 'wf_activity',
1428 SN_WORKFLOW_ACTIVITY_DEFINITION: 'wf_activity_definition',
1429 SN_WORKFLOW_ACTIVITY_VARIABLE: 'wf_activity_variable',
1430 SN_WORKFLOW_CONDITION: 'wf_condition',
1431 SN_WORKFLOW_STAGE: 'wf_stage',
1432 SN_WORKFLOW_TRANSITION: 'wf_transition',
1433 SN_WORKFLOW_VERSION: 'wf_workflow_version',
1434 SN_TRANSFORM_MAP: 'sys_transform_map'
1435};
1436
1437SaraCommon.AUDIT = {
1438 APPROVAL_HISTORY: 'SNSC_SN_APPROVAL_HISTORY',
1439 APPROVAL_TIMESTAMP: 'SNSC_SN_APPROVAL_TIMESTAMP',
1440 ORDER_ID : 'SNSC_SN_ORDER_ID',
1441 ORDER_NAME: 'SNSC_SN_ORDER_NAME',
1442 ORDER_TIMESTAMP: 'SNSC_SN_ORDER_TIMESTAMP'
1443};
1444]]></script>
1445 <description>This class is comprised of global parameters in SARA connector. It shouldn't be instantiated and fields will be accessed in static-like fashion (think Java), eg.: SaraCommon.username</description>
1446 <active>true</active>
1447 <client_callable>false</client_callable>
1448 <access>public</access>
1449 </script_include>
1450
1451 <script_include>
1452 <name>SaraConfig</name>
1453 <script><![CDATA[/**
1454 * Helper class provides convenient methods to work with SNSC configuration table
1455 */
1456var SaraConfig = Class.create();
1457SaraConfig.prototype = {
1458 initialize: function () {
1459 this.glideHelper = new SaraGlideHelper();
1460
1461 this.DEFAULT_CONFIG_VALUES = {};
1462 this.DEFAULT_CONFIG_VALUES[SaraCommon.CONFIG_NAME.CLIENT_ID] = 'AESYSTEMNAME/1/SERVICE_NOW';
1463 this.DEFAULT_CONFIG_VALUES[SaraCommon.CONFIG_NAME.CLIENT_SECRET] = 'AES_12345';
1464 this.DEFAULT_CONFIG_VALUES[SaraCommon.CONFIG_NAME.TECHNICAL_USER] = 'TECHNICAL_USER';
1465 this.DEFAULT_CONFIG_VALUES[SaraCommon.CONFIG_NAME.SAPI_ENDPOINT] = 'https://mysapihost/';
1466 this.DEFAULT_CONFIG_VALUES[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT] = 'https://oauthhost/oauth2/token';
1467 this.DEFAULT_CONFIG_VALUES[SaraCommon.CONFIG_NAME.AUTH_ENDPOINT] = 'https://oauthhost/oauth2/auth';
1468 },
1469
1470 /**
1471 * Store SARA OAuth client configuration to System Properties
1472 * @param {object} config The configuration of OAuth Client
1473 * - @key {String} SaraCommon.CONFIG_NAME.CLIENT_ID Identity of OAuth client
1474 * - @key {String} SaraCommon.CONFIG_NAME.CLIENT_SECRET OAuth client secret string
1475 * - @key {String} SaraCommon.CONFIG_NAME.TECHNICAL_USER Technical user
1476 * - @key {String} SaraCommon.CONFIG_NAME.SAPI_ENDPOINT URL to SAPI root endpoint
1477 * - @key {String} SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT Endpoint for token requesting/refreshing
1478 * - @key {String} SaraCommon.CONFIG_NAME.AUTH_ENDPOINT Authorization endpoint for OAuth authentication
1479 */
1480 storeClientConfig: function (config) {
1481 if (!gs.hasRole(SaraCommon.ROLES.ADMIN)) {
1482 var message = 'You dont\'t have sufficient permission to do this action. Allowed role: ' + SaraCommon.ROLES.ADMIN;
1483 throw new Error(message);
1484 }
1485 // Clean the old config before storing new one
1486 this.glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_CONFIG, {}, true);
1487
1488 var configData = {};
1489
1490 for (var key in config) {
1491 configData['u_' + key] = config[key];
1492 }
1493
1494 // Store new config
1495 this.glideHelper.persistData(SaraCommon.TABLE_NAME.SARA_CONFIG, configData);
1496 },
1497
1498 /**
1499 * Get the object contains SARA client configuration in following order: Client ID, Client Secret, Technical User,
1500 * SAPI Endpoint, Token Endpoint, Authorization Endpoint
1501 * @return {Object}
1502 */
1503 getClientConfig: function () {
1504 var saraConfig = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_CONFIG, {}, true)[0];
1505 var configData = {};
1506
1507 if (saraConfig) {
1508 for (var key in SaraCommon.CONFIG_NAME) {
1509 var name = SaraCommon.CONFIG_NAME[key];
1510
1511 configData[name] = saraConfig['u_' + name];
1512 }
1513 } else {
1514 configData = this.DEFAULT_CONFIG_VALUES;
1515 }
1516
1517 return configData;
1518 },
1519
1520 /**
1521 * Get base bath of SAPI endpoint
1522 * @return {String}
1523 */
1524 getBasePath: function () {
1525 var configData = this.getClientConfig();
1526
1527 return configData[SaraCommon.CONFIG_NAME.SAPI_ENDPOINT];
1528 },
1529
1530 /**
1531 * Get technical user name
1532 * @param {String}
1533 */
1534 getTechnicalUser: function () {
1535 var configData = this.getClientConfig();
1536
1537 return configData[SaraCommon.CONFIG_NAME.TECHNICAL_USER];
1538 },
1539
1540 type: 'SaraConfig'
1541};
1542]]></script>
1543 <description>Helper class provides convenient methods to work with SNSC configuration table</description>
1544 <active>true</active>
1545 <client_callable>false</client_callable>
1546 <access>public</access>
1547 </script_include>
1548 <script_include>
1549 <name>SaraConsumerImportSet</name>
1550 <script><![CDATA[/**
1551 * Sara consumer class to discover all SAPI catalogs, services and import them into SN as the corresponding catalog categories and items
1552 */
1553var SaraConsumerImportSet = Class.create();
1554SaraConsumerImportSet.prototype = {
1555 initialize: function (tracker) {
1556 if (tracker !== null && tracker !== undefined) {
1557 this.tracker = tracker;
1558 }
1559
1560 // initialize dependencies
1561 var midServer = SaraUtils.getMIDServer();
1562 this.restClient = new SaraRESTClient();
1563 this.restClient.setMIDServer(midServer);
1564
1565 this.username = new SaraConfig().getTechnicalUser();
1566
1567 // inject restClient to the OAuth client instance
1568 this.oauthClient = new SaraOAuthClient(this.restClient);
1569 this.tokens = this.oauthClient.getUserTokens(this.username);
1570
1571 // inject glideHelper
1572 this.glideHelper = new SaraGlideHelper();
1573
1574 this.dal = new SaraConsumerDAL();
1575
1576 this.LOGGER = new SaraLog(this);
1577
1578 /**
1579 * Object store catalogs data of SAPI after discovering
1580 * @structure:
1581 * {
1582 * @{catalogName}: @{SaraModel.CatalogCategory},
1583 * ...
1584 * }
1585 */
1586 this.catalogsData = {};
1587
1588 /**
1589 * Object store services data of SAPI after discovering
1590 * @structure:
1591 * {
1592 * @{catalogName}: {
1593 * @{serviceName}: @{SaraModel.CatalogItem},
1594 * ...
1595 * },
1596 * ...
1597 * }
1598 */
1599 this.servicesData = {};
1600
1601 // Object store catalogs and services number after discovering
1602 this.countData = {
1603 catalogsCount: 0,
1604 servicesCount: 0
1605 };
1606
1607 this.statusCode = '';
1608 this.errorMessage = '';
1609 this.errorUrl = '';
1610 },
1611
1612 /**
1613 * Discover then import the data
1614 * @param {String} targetId The id of category which services will be imported in
1615 * @return {String} The log message
1616 */
1617 discoverAndImport: function (targetId) {
1618 var LOGGER = this.LOGGER;
1619 var response = this.discover();
1620 var message = '';
1621
1622 if (response.error) {
1623 LOGGER.info('Discover data from SAPI not successfully!');
1624 return null;
1625 } else {
1626 message += SaraUtils.formatString('Imported {0} catalog(s) and {1} service(s)!', this.countData.catalogsCount, this.countData.servicesCount);
1627 gs.info("this.catalogsData = " + SaraJSON.stringify(this.catalogsData));
1628 gs.info("this.servicesData = " + SaraJSON.stringify(this.servicesData));
1629
1630 this.doImport(targetId);
1631
1632 return message;
1633 }
1634 },
1635
1636 /**
1637 * Discover SAPI consumer URL, create corresponding list of Catalog Category and Catalog Item
1638 * @return {Object}
1639 * - @key {Boolean} error
1640 * - @key {Object} response
1641 */
1642 discover: function () {
1643 var LOGGER = this.LOGGER;
1644
1645 LOGGER.info('Starting discover...');
1646
1647 // Check permission before do any discover
1648 var checkData = this.checkPermission();
1649 if (checkData.error) {
1650 this.statusCode = 0;
1651 this.errorMessage = checkData.error;
1652 LOGGER.error(checkData.error);
1653 LOGGER.info('Ended discover!');
1654
1655 return checkData;
1656 }
1657
1658 // Log configuration
1659 var configData = new SaraConfig().getClientConfig();
1660 LOGGER.info('OAuth Configuration:\n' +
1661 ' - Client ID = {0}, \n' +
1662 ' - Client Secret = ***, \n' +
1663 ' - Technical User = {1}, \n' +
1664 ' - SAPI Endpoint = {2}, \n' +
1665 ' - Token Endpoint = {3}, \n' +
1666 ' - Authorization Endpoint = {4}, \n' +
1667 ' - MID Server = {5}',
1668 configData[SaraCommon.CONFIG_NAME.CLIENT_ID],
1669 configData[SaraCommon.CONFIG_NAME.TECHNICAL_USER],
1670 configData[SaraCommon.CONFIG_NAME.SAPI_ENDPOINT],
1671 configData[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT],
1672 configData[SaraCommon.CONFIG_NAME.AUTH_ENDPOINT],
1673 SaraUtils.getMIDServer()
1674 );
1675
1676 /* ================================================================================================
1677 * Discover root
1678 * ================================================================================================ */
1679 this.logMessage('Discovering SAPI root...');
1680
1681 var rootData = this.discoverRoot();
1682
1683 // Set percent of progress
1684 this.incrementPercent(5);
1685
1686 if (rootData.error) {
1687 LOGGER.info('Ended discover!');
1688 return rootData;
1689 }
1690
1691 var message = "";
1692 rootData = rootData.jsonData;
1693 if (!rootData._links || !rootData._links.catalogs[0]) {
1694 message = 'No catalog consumer URL found, skip discover!';
1695 this.errorMessage = message;
1696 LOGGER.error(message);
1697 LOGGER.info('Ended discover!');
1698
1699 return rootData;
1700 }
1701 LOGGER.info('Found SAPI Catalogs url: {0}', rootData._links.catalogs[0].href);
1702
1703
1704 /* ================================================================================================
1705 * Discover catalogs
1706 * ================================================================================================ */
1707 this.logMessage('Discovering catalogs...');
1708
1709 var catalogsData = this.discoverCatalogs(rootData._links.catalogs[0].href);
1710
1711 // Set percent of progress
1712 this.incrementPercent(5);
1713
1714 if (catalogsData.error) {
1715 LOGGER.info('Ended discover!');
1716 return catalogsData;
1717 }
1718
1719 catalogsData = catalogsData.jsonData;
1720 if (!catalogsData._links || !catalogsData._links.catalog || !catalogsData._links.catalog[0]) {
1721 message = 'No SAPI catalog found, skip discover!';
1722 this.errorMessage = message;
1723 LOGGER.error(message);
1724 LOGGER.info('Ended discover!');
1725
1726 return catalogsData;
1727 }
1728
1729 /* ================================================================================================
1730 * Discover services
1731 * ================================================================================================ */
1732 var totalCatalogs = this.countData.catalogsCount;
1733 this.percentPerCatalog = 40 / totalCatalogs;
1734
1735 for (var i in catalogsData._links.catalog) {
1736 var catalog = catalogsData._links.catalog[i];
1737 var catalogTitle = catalog.title || catalog.href.replace(/^.*\/(.*)$/, '$1');
1738
1739 this.logMessage('Discovering services of "{0}" catalog...', catalogTitle);
1740
1741 // Set limit for catalogUrl
1742 var catalogUrl = this.getLimitLink(catalog.href, 'services');
1743 var servicesData = this.discoverServices(catalogUrl, catalogTitle, true);
1744
1745 // Set percent of progress
1746 this.incrementPercent(this.percentPerCatalog);
1747
1748 if (servicesData && servicesData.error) {
1749 LOGGER.info('Ended discover!');
1750 return servicesData;
1751 }
1752 }
1753
1754 LOGGER.info('Ended discover!');
1755 return {
1756 error: false
1757 };
1758 },
1759
1760 /**
1761 * Discover root url of SAPI
1762 * @return {Object}
1763 * - @key {Boolean} error
1764 * - @key {Object} response
1765 * - @key {Object} jsonData
1766 */
1767 discoverRoot: function () {
1768 var LOGGER = this.LOGGER;
1769
1770 LOGGER.info('Starting discoverRoot...');
1771
1772 // Make request
1773 var response = this.makeSAPIRequest('/');
1774
1775 if (response.error) {
1776 LOGGER.error(response.error);
1777 LOGGER.info('Ended discoverRoot!');
1778
1779 return response;
1780 }
1781
1782 LOGGER.info('Ended discoverRoot!');
1783 return response;
1784 },
1785
1786 /**
1787 * Discover catalogs url of SAPI
1788 * @param {String} catalogsUrl
1789 * @return {Object}
1790 * - @key {Boolean} error
1791 * - @key {Object} response
1792 * - @key {Object} jsonData
1793 */
1794 discoverCatalogs: function (catalogsUrl) {
1795 var LOGGER = this.LOGGER;
1796
1797 LOGGER.info('Starting discoverCatalogs...');
1798
1799 // Set limit for catalogsUrl
1800 catalogsUrl = this.getLimitLink(catalogsUrl, 'catalog');
1801
1802 // Make request
1803 var response = this.makeSAPIRequest(catalogsUrl);
1804
1805 if (response.error) {
1806 LOGGER.error(response.error);
1807 LOGGER.info('Ended discoverCatalogs!');
1808
1809 return response;
1810 }
1811
1812 var jsonData = response.jsonData;
1813 this.countData.catalogsCount = jsonData.count;
1814 LOGGER.info('Found {0} SAPI Catalogs, start discover each catalog.', jsonData.count);
1815 LOGGER.info('Ended discoverCatalogs!');
1816
1817 return response;
1818 },
1819
1820
1821
1822 /**
1823 * Discover services from catalog url of SAPI
1824 * @param {String} catalogUrl
1825 * @param {String} catalogTitle
1826 * @param {Boolean} firstTime
1827 * @return {Object}
1828 * - @key {Boolean} error
1829 * - @key {Object} response
1830 * - @key {Object} jsonData
1831 */
1832 discoverServices: function (catalogUrl, catalogTitle, firstTime) {
1833 var LOGGER = this.LOGGER;
1834
1835 var name = catalogUrl.replace(/^.*\/(.*)$/, '$1');
1836 LOGGER.info('Found catalog "{0}" : {1}', name, catalogUrl);
1837
1838 LOGGER.info('Starting discoverServices...');
1839 // Add 'embed=service' flag for getting information of services inside catalog
1840 catalogUrl += '&embed=service';
1841
1842 // Make request
1843 var response = this.makeSAPIRequest(catalogUrl, true);
1844 if (response.error) {
1845 LOGGER.error(response.error);
1846 LOGGER.info('Ended discoverServices!');
1847
1848 return response;
1849 }
1850
1851 // Handle response from SAPI
1852 var catalogData = response.jsonData;
1853 var catalogName = catalogData.name;
1854
1855 // This jsonData will be used for generating hash
1856 var hashData = response.jsonData2;
1857
1858 // Do this stuff when first discover
1859 if (firstTime) {
1860 // Reference catalog object of SNSC
1861 var catalogCategory = new SaraModel.CatalogCategory();
1862 catalogCategory.setTitle(catalogTitle);
1863 catalogCategory.setName(catalogName);
1864 catalogCategory.setParent('');
1865 catalogCategory.setActive(true);
1866 catalogCategory.setDescription(catalogData.shortDescription);
1867
1868 // Push catalog object to catalogsData and countData
1869 LOGGER.info('Push catalog object to catalogsData and countData');
1870 this.catalogsData[catalogName] = catalogCategory;
1871 this.servicesData[catalogName] = {};
1872 this.countData.servicesCount += catalogData.count;
1873 }
1874
1875 var servicesData = this.getEmbeddedService(catalogData);
1876
1877 // Handle services data in '_embedded' resource
1878 if (servicesData) {
1879 var servicesLink = catalogData._links.service;
1880 var SERVICE_ACTIVE = SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.SERVICE_ACTIVE) === 'true';
1881
1882 LOGGER.info('Found {0} service(s) of {1} at "{2}"', servicesData.length, catalogName, catalogUrl);
1883
1884 for (var i = 0; i < servicesData.length; i++) {
1885 var service = servicesData[i];
1886 var serviceTitle = servicesLink[i].title || servicesLink[i].href.replace(/^.*\/(.*)$/, '$1');
1887 var isActive = SERVICE_ACTIVE && service.active;
1888
1889 // Reference service object of SNSC
1890 var catalogItem = new SaraModel.CatalogItem();
1891 catalogItem.setName(serviceTitle || service.name);
1892 catalogItem.setActive(isActive);
1893 catalogItem.setWorkflow('Sara Service');
1894 catalogItem.setShortDesc(service.shortDescription);
1895 catalogItem.setDescription(SaraUtils.nl2br(service.description));
1896 catalogItem.setServiceName(service.name);
1897 catalogItem.setConsumeUrl(service._links.consume[0].href);
1898 catalogItem.setCustomCart(SaraCommon.CUSTOM_CART_NAME);
1899
1900 // Generate hash of catalogItem without 'range'
1901 var serviceData = this.getEmbeddedService(hashData, i);
1902 this.injectFieldOrders(serviceData);
1903 var hash = this.generateCatalogItemHash(serviceData);
1904 catalogItem.setHash(hash);
1905
1906 // Handle variables
1907 this.injectFieldOrders(service);
1908 var variables = [];
1909 for (var index in service.forms) {
1910 var form = service.forms[index];
1911
1912 var fields = form.fields;
1913 for (var index2 in fields) {
1914 var field = fields[index2];
1915 var variable = SaraUtils.createCatalogVariable(field);
1916 variables.push(variable);
1917 }
1918 }
1919 catalogItem.setVariables(variables);
1920
1921 // Push service object to servicesData
1922 this.servicesData[catalogName][service.name] = catalogItem;
1923 }
1924 } else {
1925 LOGGER.info('No services found in catalog (name = {0})', catalogName);
1926 }
1927
1928 LOGGER.info('Ended discoverServices!');
1929
1930 // Check the next page
1931 if (catalogData._links.next) {
1932 var nextUrl = catalogData._links.next[0].href;
1933 this.discoverServices(nextUrl, catalogTitle);
1934 }
1935 },
1936
1937 /**
1938 * Get embedded services from catalogData
1939 * @param {Object} catalogData
1940 * @return {Array<Object>|Null}
1941 */
1942 getEmbeddedService: function (catalogData, index) {
1943 if (catalogData._embedded && catalogData._embedded.service && catalogData._embedded.service[0]) {
1944 if (index !== undefined) {
1945 return catalogData._embedded.service[index];
1946 } else {
1947 return catalogData._embedded.service;
1948 }
1949 } else {
1950 return null;
1951 }
1952 },
1953
1954 /**
1955 * Import catalogs and services after discovering by using 'catalogsData' and 'servicesData'
1956 * @param {String} targetId The id of category which services will be imported in
1957 */
1958 doImport: function (targetId) {
1959 var LOGGER = this.LOGGER;
1960
1961 LOGGER.info('Starting doImport...');
1962
1963 if (this.countData.catalogsCount !== 0) {
1964 this.cleanupStagingTables();
1965
1966 this.logMessage('Importing {0} catalog(s)...', this.countData.catalogsCount);
1967 // If there's no target category specified, all catalogs will be imported as new ones in category named 'Automic Services'
1968 if (!targetId) {
1969 LOGGER.info('There is no target category, will import catalogs into default category (name = "{0}")', this.dal.getDefaultCategoryName());
1970 targetId = this.dal.getDefaultCategoryId();
1971 } else {
1972 LOGGER.info('Target category = "{0}" ...', targetId);
1973 }
1974
1975 this.importCategory(targetId);
1976
1977 if (this.countData.servicesCount !== 0) {
1978 this.logMessage('Importing {0} service(s)...', this.countData.servicesCount);
1979 this.importItem();
1980 } else {
1981 this.incrementPercent(25);
1982 LOGGER.info('There are no service be imported!');
1983 }
1984 } else {
1985 this.incrementPercent(50);
1986 LOGGER.info('There are no catalog be imported!');
1987 }
1988
1989 // Make sure that progress always is 100% when completed
1990 this.incrementPercent(100);
1991
1992 LOGGER.info('Ended doImport!');
1993 },
1994
1995 /**
1996 * Import catalog category by using 'catalogsData'
1997 * @param {String} targetCatId Target category id
1998 */
1999 importCategory: function (targetCatId) {
2000 var glideHelper = this.glideHelper;
2001 var LOGGER = this.LOGGER;
2002 var dal = this.dal;
2003
2004 LOGGER.info('Starting importCategory to category: ' + targetCatId);
2005
2006 var targetCategory = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, {sys_id: targetCatId});
2007 if(!targetCategory) {
2008 throw "Target category not found " + targetCatId;
2009 }
2010
2011 var catalogId = targetCategory.sc_catalog;
2012 if(!catalogId) {
2013 catalogId = dal.getDefaultCatalogId();
2014 }
2015
2016 // Save target category id into SaraCommon.TABLE_NAME.SARA_DEFINITION table
2017 dal.saveRootImportCategoryToSaraDefinition(targetCatId);
2018
2019 // Get name of all catalogs in AE
2020 var catalogNames = [];
2021 for (var catalogName in this.catalogsData) {
2022 catalogNames.push(catalogName);
2023 }
2024 LOGGER.info('Catalogs in AE: {0}', catalogNames.join(', '));
2025
2026 this.syncSaraDefinitionCategories(targetCatId, catalogNames);
2027
2028 // Set percent of progress
2029 this.incrementPercent(5);
2030
2031 // Otherwise, check if there's same name category existing under target category
2032 for (catalogName in this.catalogsData) {
2033 var sapiCatalog = this.catalogsData[catalogName];
2034 sapiCatalog.setParent(targetCatId);
2035 this.logMessage('Importing SARA Catalog {0}', catalogName);
2036 LOGGER.info('Catalog {0}: {1}', catalogName, SaraJSON.stringify(sapiCatalog));
2037
2038 var categoryId;
2039
2040 // Check if there's same name category existing under target category
2041 var existingDefinition = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
2042 'u_name': sapiCatalog.name,
2043 'u_parent': targetCatId,
2044 'u_type': 'catalog',
2045 'u_active': true
2046 });
2047
2048 if (existingDefinition) {
2049 LOGGER.info("existing category found {0}, update...", SaraJSON.stringify(existingDefinition));
2050
2051 categoryId = existingDefinition.u_service_catalog_category;
2052 var category = this.glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, {sys_id: categoryId});
2053 category.title = sapiCatalog.title;
2054 category.description = sapiCatalog.description;
2055 category.active = true;
2056 category.parent = targetCatId;
2057 dal.saveOrUpdateCategory(category);
2058
2059 sapiCatalog.setAsNew(false);
2060 sapiCatalog.setSysId(categoryId);
2061 sapiCatalog.setSNCatalog(category.sc_catalog);
2062 }
2063 else {
2064 LOGGER.info("existing category not found, creating...");
2065
2066 sapiCatalog.setAsNew(true);
2067 sapiCatalog.setSNCatalog(catalogId);
2068 definition = dal.saveCategoryToSaraDefinition(sapiCatalog);
2069 sapiCatalog.setSysId(definition.u_service_catalog_category);
2070 }
2071
2072 // Set percent of progress
2073 this.incrementPercent(this.percentPerCatalog);
2074 }
2075
2076 dal.refreshCategory(targetCatId);
2077
2078 LOGGER.info('Ended importCategory!');
2079 },
2080
2081 syncSaraDefinitionCategories: function(targetCatId, catalogNames) {
2082 var LOGGER = this.LOGGER;
2083 var dal = this.dal;
2084 // Get existed catalogs in SNSC
2085 var existedSaraCatalogs = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
2086 'u_parent': targetCatId,
2087 'u_type': 'catalog'
2088 }, true);
2089
2090 if (existedSaraCatalogs.length > 0) {
2091 this.LOGGER.info('Detecting the existed catalog in SNSC which doesn\'t exist anymore in AE');
2092
2093 // Remove the existed catalog in SNSC which doesn't exist anymore in AE
2094 for (var i = 0; i < existedSaraCatalogs.length; i++) {
2095 var existCatalog = existedSaraCatalogs[i];
2096 if (!SaraUtils.inArray(catalogNames, existCatalog.u_name)) {
2097 LOGGER.info('Catalog with name = {0} doesn\'t exist anymore in AE', existCatalog.u_name);
2098 dal.deactivateSaraDefinition(existCatalog);
2099 }
2100 }
2101 }
2102 },
2103
2104 /**
2105 * Import catalog item by using 'servicesData' property
2106 */
2107 importItem: function () {
2108 var LOGGER = this.LOGGER;
2109 var glideHelper = this.glideHelper;
2110 var dal = this.dal;
2111
2112 LOGGER.info('Starting importItems...');
2113
2114 for (var categoryName in this.servicesData) {
2115 var isCatalogNew = this.catalogsData[categoryName].isNew();
2116 var sapiCatalog = this.catalogsData[categoryName];
2117 var categoryId = sapiCatalog.getSysId();
2118 LOGGER.info("Importing sapi service to category (name = {0}, sys_id = {1})", categoryName, categoryId);
2119
2120 var items = this.servicesData[categoryName];
2121 var itemNames = [];
2122
2123 // Get existed catalog items in AE
2124 for (var itemName in items) {
2125 itemNames.push(itemName);
2126 }
2127 LOGGER.info('{0} catalog items under category "{1}": {2}', itemNames.length, categoryName, itemNames.join(', '));
2128
2129 // Get existed catalog items in SNSC
2130 var existedItems = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
2131 'u_parent': categoryId,
2132 'u_type': 'service',
2133 'u_active': true
2134 }, true);
2135
2136 var existDefinition;
2137 if (existedItems.length > 0) {
2138 var msg = 'Detecting the existed catalog item in SNSC which doesn\'t exist anymore in AE...';
2139 this.logMessage(msg);
2140 LOGGER.info(msg);
2141
2142 // Remove the existed catalog item in SNSC which doesn't exist anymore in AE
2143 for (var i = 0; i < existedItems.length; i++) {
2144 existDefinition = existedItems[i];
2145 if (!SaraUtils.inArray(itemNames, existDefinition.u_name)) {
2146 LOGGER.info('Catalog item (name = {0}, parent sys_id = {1}) doesn\'t exist anymore in AE', existDefinition.u_name, existDefinition.u_parent);
2147 dal.deactivateSaraDefinition(existDefinition);
2148 }
2149 }
2150 }
2151
2152 for (itemName in items) {
2153 var importMsg = "Importing sapi service " + itemName;
2154 this.logMessage(importMsg);
2155 LOGGER.info(importMsg);
2156 var sapiService = items[itemName];
2157 LOGGER.info("Set sapi service catalog to " + sapiCatalog.getSNCatalog());
2158 sapiService.setSNCatalog(sapiCatalog.getSNCatalog());
2159 // Set catalog category sys_id for item
2160 sapiService.setCategory(categoryId);
2161
2162 if (isCatalogNew) {
2163 dal.saveSapiService(sapiService);
2164 continue;
2165 }
2166
2167 // Check existing item with same name and same parent category id = item.category
2168 existDefinition = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
2169 'u_name': sapiService.getServiceName(),
2170 'u_parent': sapiService.getCategory(),
2171 'u_type': 'service'
2172 });
2173
2174 if (existDefinition) {
2175 LOGGER.info("existing definition found. Set u_active to true");
2176 existDefinition.u_active = true;
2177 this.dal.saveOrUpdateSaraDefinition(existDefinition);
2178
2179 // Check hash of saraItem and item
2180 LOGGER.debug('New and old hash: {0} - {1}', sapiService.getHash(), existDefinition.u_hash);
2181
2182 if (sapiService.getHash() === existDefinition.u_hash) {
2183 LOGGER.info('Item (name = {0}) is not changed. Start sync lookup...', existDefinition.u_name);
2184 new SaraSync().syncLookup(existDefinition, sapiService);
2185 LOGGER.info("Sync lookup done");
2186 } else {
2187 LOGGER.info('Item (name = {0}) is changed. Update', existDefinition.u_name);
2188
2189 dal.updateSapiService(existDefinition, sapiService);
2190 }
2191 } else {
2192 // Insert new as normal
2193 dal.saveSapiService(sapiService);
2194 }
2195 }
2196
2197 // Set percent of progress
2198 this.incrementPercent(this.percentPerCatalog);
2199 }
2200
2201 LOGGER.info('Ended importItem!');
2202 },
2203
2204 cleanupStagingTables: function() {
2205 var glideHelper = this.glideHelper;
2206 var LOGGER = this.LOGGER;
2207 var dal = this.dal;
2208 LOGGER.info("Start cleanup staing tables...");
2209
2210 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SN_CATALOG_IST);
2211 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATALOG_IST, {}, true);
2212
2213 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SN_CATEGORY_IST);
2214 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY_IST, {}, true);
2215
2216 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SARA_CAT_ITEM_IST);
2217 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_CAT_ITEM_IST, {}, true);
2218
2219 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SN_VARIABLE_SET_IST);
2220 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_VARIABLE_SET_IST, {}, true);
2221
2222 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SN_VARIABLE_SET_ITEM_IST);
2223 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_VARIABLE_SET_ITEM_IST, {}, true);
2224
2225 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SARA_DEFINITION_IST);
2226 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION_IST, {}, true);
2227
2228 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SARA_VARIABLE_IST);
2229 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_VARIABLE_IST, {}, true);
2230
2231 LOGGER.info("Cleanup table {0}", SaraCommon.TABLE_NAME.SARA_LOOKUP_IST);
2232 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_LOOKUP_IST, {}, true);
2233
2234 LOGGER.info("Done!");
2235 },
2236
2237 /**
2238 * Refresh 'catalogsData' and 'servicesData':
2239 * - unsetAsNew() for 'catalogsData' item
2240 * - unsetParent() for 'catalogsData' item
2241 * - unsetSysId() for 'catalogsData' item
2242 * - unsetCategory() for 'servicesData' item
2243 */
2244 refreshImportedData: function () {
2245 var LOGGER = this.LOGGER;
2246
2247 LOGGER.info('Starting refreshImportedData...');
2248
2249 for (var catalogName in this.catalogsData) {
2250 var catalogData = this.catalogsData[catalogName];
2251
2252 catalogData.unsetAsNew();
2253 catalogData.unsetParent();
2254 catalogData.unsetSysId();
2255 }
2256
2257 for (catalogName in this.servicesData) {
2258 var items = this.servicesData[catalogName];
2259
2260 for (var itemName in items) {
2261 var item = items[itemName];
2262
2263 item.unsetCategory();
2264 }
2265 }
2266 LOGGER.info('Ended refreshImportedData!');
2267 },
2268
2269 /**
2270 * Clean up 'catalogsData' and 'servicesData'
2271 */
2272 cleanData: function () {
2273 this.catalogsData = {};
2274 this.servicesData = {};
2275 },
2276
2277 getCatalogsData: function () {
2278 return this.catalogsData;
2279 },
2280
2281 getCatalogData: function (catalogName) {
2282 return this.catalogsData[catalogName];
2283 },
2284
2285 getServicesData: function (catalogName) {
2286 if (catalogName) {
2287 return this.servicesData[catalogName];
2288 } else {
2289 return this.servicesData;
2290 }
2291 },
2292
2293 getStatusCode: function () {
2294 return this.statusCode;
2295 },
2296
2297 getErrorMessage: function () {
2298 return this.errorMessage;
2299 },
2300
2301 //-----------------------------------------------------------------
2302 //Utility methods
2303 //-----------------------------------------------------------------
2304
2305
2306 /**
2307 * Get link with limit parametter of catalog or service
2308 * @param {String} link Origin link
2309 * @param {String} type can be catalog or service
2310 * @param {String}
2311 */
2312 getLimitLink: function (link, type) {
2313 var limitString = 'limit=';
2314 limitString += type === 'catalog' ? SaraCommon.CATALOGS_LIMIT : SaraCommon.SERVICES_LIMIT;
2315
2316 if (link.indexOf('?') !== -1) {
2317 limitString = '&' + limitString;
2318 } else {
2319 limitString = '?' + limitString;
2320 }
2321
2322 return link + limitString;
2323 },
2324
2325 /**
2326 * Private method to check user permission.
2327 * @return {Object}
2328 * - @key {String} error
2329 */
2330 checkPermission: function () {
2331 var LOGGER = this.LOGGER;
2332
2333 var message = "";
2334 if (!gs.hasRole(SaraCommon.ROLES.ADMIN)) {
2335 message = 'You dont\'t have sufficient permission to do this action. Allowed role: ' + SaraCommon.ROLES.ADMIN;
2336
2337 LOGGER.error(message);
2338
2339 return {
2340 error: message
2341 };
2342 }
2343
2344 // check user tokens
2345 if (!this.tokens) {
2346 message = SaraUtils.formatString('No tokens found for user {0}. Skip import!', this.username);
2347
2348 LOGGER.error(message);
2349
2350 return {
2351 error: message
2352 };
2353 }
2354
2355 LOGGER.info('Tokens found for user {0}', this.username);
2356
2357 if (!this.tokens[3]) {
2358 this.tokens[3] = 'bearer';
2359 }
2360
2361 return {
2362 error: false
2363 };
2364 },
2365
2366 /**
2367 * Make request to SAPI and check the response data
2368 * @param {String} url
2369 * @param {Boolean} returnJSONData2
2370 * @return {Object}
2371 * - @key {Boolean} error
2372 * - @key {Object} response
2373 * - @key {Object} jsonData
2374 */
2375 makeSAPIRequest: function (url, returnJSONData2) {
2376 var LOGGER = this.LOGGER;
2377
2378 // Make request
2379 this.tokens = this.oauthClient.getUserTokens(this.username);
2380 var requestUrl = SaraUtils.buildUrl(url);
2381 var request = this.restClient.newSAPIRequest('get', requestUrl);
2382 request.addHeader('Authorization', this.tokens[3] + ' ' + this.tokens[0]);
2383
2384 // Get response
2385 var response = this.restClient.executeWithRefreshToken(request);
2386 var responseObject = response.getResponseObject();
2387
2388 if (response.haveError()) {
2389 this.statusCode = responseObject.statusCode;
2390 this.errorMessage = responseObject.errorMessage;
2391 this.errorUrl = url;
2392
2393 return {
2394 error: true,
2395 response: response
2396 };
2397 }
2398
2399 var result = {
2400 error: false,
2401 response: response,
2402 jsonData: responseObject.bodyObject
2403 };
2404
2405 if (returnJSONData2) {
2406 var jsonData2 = response.getBodyObject();
2407 result.jsonData2 = jsonData2;
2408 }
2409
2410 return result;
2411 },
2412
2413 /**
2414 * Increment specific percent more for tracker if have
2415 * @param {Number} percent
2416 */
2417 incrementPercent: function (percent) {
2418 var LOGGER = this.LOGGER;
2419 try {
2420 var canIncrease = (typeof this.tracker !== 'undefined') && (typeof this.tracker.incrementPercentComplete !== 'undefined');
2421
2422 if (canIncrease) {
2423 this.tracker.incrementPercentComplete(percent);
2424 }
2425 }
2426 catch(err) {
2427 LOGGER.debug("Cannot increase tracker: {0}", err);
2428 }
2429 },
2430
2431 /**
2432 * Log message for tracker can show what is happening inside of SaraConsumerImportSet when importing services.
2433 * You can format message like SaraUtils.formatString method
2434 */
2435 logMessage: function () {
2436 var LOGGER = this.LOGGER;
2437
2438 if ((typeof this.tracker !== 'undefined') && (typeof this.tracker.updateResult !== 'undefined')) {
2439 var message = SaraUtils.formatString.apply(this, arguments);
2440 try {
2441 this.tracker.updateResult({
2442 msg: message
2443 });
2444 } catch (e) {
2445 LOGGER.debug('Cannot log message for tracker: {0}', e);
2446 }
2447 }
2448 },
2449
2450 /**
2451 * Generate hash string of catalogItem. The hash will be generated from 'form' property
2452 * of catalogItem without 'range' property
2453 * @param {SaraModel.CatalogItem} catalogItemData
2454 * @return {String} hash
2455 */
2456 generateCatalogItemHash: function (catalogItemData) {
2457 for (var index in catalogItemData.forms) {
2458 var form = catalogItemData.forms[index];
2459 var fields = form.fields;
2460 for (var index2 in fields) {
2461 delete fields[index2].range;
2462 }
2463 }
2464 var serviceDataStr = SaraJSON.stringify(catalogItemData);
2465 this.LOGGER.info("Calculate hash for catalogItemData: " + serviceDataStr);
2466 var hash = SaraUtils.md5(serviceDataStr);
2467
2468 return hash;
2469 },
2470
2471 injectFieldOrders: function (catalogItemData) {
2472 var count = 0;
2473 for (var index in catalogItemData.forms) {
2474 var form = catalogItemData.forms[index];
2475
2476 var fields = form.fields;
2477 for (var index2 in fields) {
2478 fields[index2].order = count * 100;
2479 count++;
2480 }
2481 }
2482 },
2483
2484 type: 'SaraConsumerImportSet'
2485};
2486]]></script>
2487 <description>SaraConsumerImportSet class to discover all SAPI catalogs, services and import them into SN as the corresponding catalog categories and items using staging tables</description>
2488 <active>true</active>
2489 <client_callable>false</client_callable>
2490 <access>public</access>
2491 </script_include>
2492
2493 <script_include>
2494 <name>SaraConsumerDAL</name>
2495 <script><![CDATA[/**
2496 * Service Catalog Generator to import service definition to Service Catalog
2497 */
2498var SaraConsumerDAL = Class.create();
2499SaraConsumerDAL.prototype = {
2500 initialize: function () {
2501 this.glideHelper = new SaraGlideHelper();
2502 this.LOGGER = new SaraLog(this);
2503 this.TABLES = SaraCommon.TABLE_NAME;
2504 this.typeMaps = this.getTypeMaps();
2505 },
2506
2507 //---------------------------
2508 //Catalog
2509 //---------------------------
2510 getCatalog: function(title) {
2511 return this.glideHelper.getData(this.TABLES.SN_CATALOG, {
2512 'title': title
2513 });
2514 },
2515
2516 /**
2517 * param catalog:
2518 * id: optional - coalesce. sys_id will be transformed to id if presented
2519 * title: required
2520 * description: optional
2521 * active: required
2522 */
2523 saveOrUpdateCatalog: function(catalog) {
2524 SaraUtils.guardNotNullOrEmpty(catalog, "catalog must not be null or empty");
2525 SaraUtils.guardNotNullOrEmpty(catalog.title, "catalog title must not be null or empty");
2526
2527 this.saveOrUpdateEntity(catalog, "catalog");
2528
2529 var result = this.getCatalog(catalog.title);
2530 SaraUtils.guardNotNullOrEmpty(result, "Failed to save or update catalog " + catalog.title);
2531 return result;
2532 },
2533
2534 /**
2535 * Get catalog SaraCommon.DEFAULT_CATALOG, if save or update fail then fall back to SaraCommon.DEFAULT_AUTOMIC_CATALOG
2536 */
2537 getDefaultCatalogId: function() {
2538 if(this._defaultCatalogId) {
2539 return this._defaultCatalogId;
2540 }
2541 var catalog = this.getCatalog(SaraCommon.DEFAULT_CATALOG);
2542 var serviceCatalogId = catalog === undefined ? undefined : catalog.sys_id;
2543
2544 if (!serviceCatalogId) {
2545 // get the first catalog
2546 serviceCatalogId = this.glideHelper.getSysId(this.TABLES.SN_CATALOG);
2547
2548 // if there's no catalog, create a new one
2549 if (!serviceCatalogId) {
2550
2551 serviceCatalogId = this.saveOrUpdateCatalog({
2552 title: SaraCommon.DEFAULT_AUTOMIC_CATALOG,
2553 description: SaraCommon.DEFAULT_AUTOMIC_CATALOG,
2554 active: true
2555 }).sys_id;
2556 this.LOGGER.info("New catalog '" + SaraCommon.DEFAULT_AUTOMIC_CATALOG + "' was created");
2557 }
2558 }
2559 this._defaultCatalogId = serviceCatalogId;
2560
2561 return serviceCatalogId;
2562 },
2563
2564
2565 //---------------------------
2566 //Category
2567 //---------------------------
2568 getCategory: function(catalogId, title, parent) {
2569 var query = {title:title};
2570 if(catalogId) {
2571 query.sc_catalog = catalogId;
2572 }
2573 if(parent) {
2574 query.parent = parent;
2575 }
2576 return this.glideHelper.getData(this.TABLES.SN_CATEGORY, query);
2577 },
2578
2579 /**
2580 * param category:
2581 * id: optional. Blank for insert
2582 * sc_catalog: required
2583 * title: required
2584 * homepage_renderer: optinal
2585 * active: optional
2586 * description: optional
2587 * parent: optional
2588
2589 */
2590 saveOrUpdateCategory: function (category) {
2591 SaraUtils.guardNotNullOrEmpty(category, "category must not be null or empty");
2592 SaraUtils.guardNotNullOrEmpty(category.title, "category.title must not be null or empty");
2593
2594 this.saveOrUpdateEntity(category, "category");
2595
2596 var result = this.getCategory(undefined, category.title, category.parent);
2597 gs.info("result = " + SaraJSON.stringify(result));
2598 SaraUtils.guardNotNullOrEmpty(result, "category is not save or updated correctly");
2599
2600 return result;
2601 },
2602
2603 getDefaultCategoryId: function () {
2604 var glideHelper = this.glideHelper;
2605 var LOGGER = this.LOGGER;
2606
2607 var catalogId = this.getDefaultCatalogId();
2608 var categoryName = this.getDefaultCategoryName();
2609
2610 LOGGER.info('Using catalog {0}', glideHelper.getData(this.TABLES.SN_CATALOG, {'sys_id': catalogId}).title);
2611
2612 var defaultCategory = this.getCategory(catalogId, categoryName);
2613 var sysId = defaultCategory === null ? undefined : defaultCategory.sys_id;
2614
2615 if (!sysId) {
2616 // create default Automic Service category
2617 LOGGER.info('DefaultCategory (name = {0}) doesn\'t exist', categoryName);
2618 sysId = this.saveOrUpdateCategory({
2619 sc_catalog: catalogId,
2620 title: categoryName,
2621 description: categoryName,
2622 active: true
2623 }).sys_id;
2624 }
2625 else {
2626 LOGGER.info('Using DefaultCategory (name = {0})', categoryName);
2627 }
2628
2629 return sysId;
2630 },
2631
2632 getDefaultCategoryName: function() {
2633 return SaraCommon.DEFAULT_CATEGORY;
2634 },
2635
2636 deactivateCategory: function(categoryId) {
2637 var glideHelper = this.glideHelper;
2638 var LOGGER = this.LOGGER;
2639 if(!SaraUtils.isNullOrEmpty(categoryId)) {
2640 // Deactive category in 'SaraCommon.TABLE_NAME.SN_CATEGORY' table
2641 LOGGER.info('Deactivating category (sys_id = {0}) in table "{1}"', categoryId, SaraCommon.TABLE_NAME.SN_CATEGORY);
2642 var category = glideHelper.getData(this.TABLES.SN_CATEGORY, {sys_id: categoryId});
2643 category.active = false;
2644 this.saveOrUpdateCategory(category);
2645 LOGGER.info('Deactivated category (sys_id = {0}) in table "{1}"', categoryId, SaraCommon.TABLE_NAME.SN_CATEGORY);
2646 }
2647 },
2648
2649 refreshCategory: function(categoryId) {
2650 var LOGGER = this.LOGGER;
2651
2652 LOGGER.info('Refreshing target category (sys_id = {0})', categoryId);
2653 var updateData = {
2654 id: categoryId,
2655 active: false
2656 };
2657
2658 this.saveOrUpdateEntity(updateData, "category");
2659 updateData.active = true;
2660 this.saveOrUpdateEntity(updateData, "category");
2661 },
2662
2663
2664 //--------------------------
2665 //Catalog Item
2666 //--------------------------
2667 getCatalogItem: function(categoryId, name) {
2668 return this.glideHelper.getData(this.TABLES.SN_CATALOG_ITEM, {category: categoryId, name: name});
2669 },
2670
2671 /**
2672 * param catItem
2673 * id: optional. Blank for insert
2674 * name: required
2675 * category: required
2676 * active:
2677 * short_description:
2678 * description:
2679 * custom_cart:
2680 * use_sc_layout:
2681 * no_quantity:
2682 */
2683 saveOrUpdateCatalogItem: function(catItem) {
2684 SaraUtils.guardNotNullOrEmpty(catItem, "catItem must not be null or empty");
2685 SaraUtils.guardNotNullOrEmpty(catItem.category, "category must not be null or empty");
2686 SaraUtils.guardNotNullOrEmpty(catItem.name, "name must not be null or empty");
2687
2688 this.saveOrUpdateEntity(catItem, "cat_item");
2689
2690 var result = this.getCatalogItem(catItem.category, catItem.name);
2691 SaraUtils.guardNotNullOrEmpty(result, "catalog item is not save or updated correctly");
2692
2693 return result;
2694 },
2695
2696 saveSapiService: function(sapiService) {
2697 var glideHelper = this.glideHelper;
2698 var LOGGER = this.LOGGER;
2699
2700 LOGGER.info("Start save sapi service " + sapiService.name);
2701 SaraUtils.guardNotNullOrEmpty(sapiService, "sapiService must not be null or empty");
2702
2703 // Workflow sys_id of catalogItem if has
2704 var workflowSysId;
2705 if (sapiService.getWorkflow()) {
2706 workflowSysId = glideHelper.getSysId(SaraCommon.TABLE_NAME.SN_WORKFLOW, {
2707 'name': sapiService.getWorkflow()
2708 });
2709
2710 if(workflowSysId === null) {
2711 var errorMsg = 'There is no Workflow with name '+ sapiService.getWorkflow();
2712 LOGGER.error(errorMsg);
2713 return;
2714 }
2715 } else {
2716 LOGGER.error('There is no Workflow for consuming catalog item. Saving sapi service is aborted!');
2717 return;
2718 }
2719
2720 // Custom cart sys_id of catalogItem if has
2721 var customCartSysId;
2722 if (sapiService.getCustomCart()) {
2723 customCartSysId = glideHelper.getSysId(SaraCommon.TABLE_NAME.SN_UI_MACRO, {
2724 'name': sapiService.getCustomCart()
2725 });
2726 }
2727
2728 //create catalog item
2729 var catalogItemId = this.saveOrUpdateCatalogItem({
2730 'name': sapiService.getName(),
2731 'category': sapiService.getCategory(),
2732 'active': sapiService.isActive(),
2733 'short_description': sapiService.getShortDesc(),
2734 'description': sapiService.getDescription(),
2735 'workflow': workflowSysId,
2736 'custom_cart': customCartSysId,
2737 'use_sc_layout': false,
2738 'no_quantity': true,
2739 'sc_catalogs': sapiService.getSNCatalog()
2740 }).sys_id;
2741
2742 var varSetId = this.saveSapiServiceVariableSet(sapiService, catalogItemId);
2743
2744 // Add new row to SaraCommon.TABLE_NAME.SARA_DEFINITION table, holding additional info. about this services like consume URL, links
2745 // and reference to the variable set that contains Sara fields
2746 var definitionId = this.saveOrUpdateSaraDefinition({
2747 'u_sc_item': catalogItemId,
2748 'u_name': sapiService.getServiceName(),
2749 'u_consume_url': sapiService.getConsumeUrl(),
2750 'u_var_set': varSetId,
2751 'u_parent': sapiService.getCategory(),
2752 'u_type': 'service',
2753 'u_hash': sapiService.getHash(),
2754 'u_is_deleted': false,
2755 'u_active': true
2756 }).sys_id;
2757
2758 LOGGER.info('Saved definition for sapi service (name = "{0}", service name = {1}, sys_id = {2}) in "{3}" table',
2759 sapiService.getName(), sapiService.getServiceName(), definitionId, SaraCommon.TABLE_NAME.SARA_DEFINITION);
2760 },
2761
2762 updateSapiService: function(existDefinition, sapiService) {
2763 var glideHelper = this.glideHelper;
2764 var LOGGER = this.LOGGER;
2765 LOGGER.info('Updating catalog item (name = "{0}", sys_id = {1})...', sapiService.getServiceName(), existDefinition.u_sc_item);
2766 SaraUtils.guardNotNullOrEmpty(existDefinition, "existDefinition must not be null or empty");
2767 SaraUtils.guardNotNullOrEmpty(sapiService, "sapiService must not be null or empty");
2768
2769 var varSetId = this.saveSapiServiceVariableSet(sapiService, existDefinition.u_sc_item);
2770 LOGGER.info('Updated definition with new variable set and hash (sys_id = {0}, varset = {1} hash {2}) for catalog item in "{3}" table...',
2771 existDefinition.sys_id, varSetId, sapiService.getHash(), this.TABLES.SARA_DEFINITION);
2772
2773 existDefinition.u_var_set = varSetId;
2774 existDefinition.u_hash = sapiService.getHash();
2775 this.saveOrUpdateSaraDefinition(existDefinition);
2776
2777 var catItem = glideHelper.getData(this.TABLES.SN_CATALOG_ITEM, {sys_id: existDefinition.u_sc_item});
2778 LOGGER.info("Update catalog item active state according to Sapi service");
2779 catItem.active = sapiService.isActive();
2780 this.saveOrUpdateCatalogItem(catItem);
2781 },
2782
2783 //---------------------------
2784 //Variables and Variables Set
2785 //---------------------------
2786 saveSapiServiceVariableSet: function(sapiService, catalogItemId) {
2787 var glideHelper = this.glideHelper;
2788 var LOGGER = this.LOGGER;
2789 var varSetId = null;
2790
2791 // Process catalog variables
2792 if (sapiService.variables.length > 0) {
2793 var varSetName = SaraUtils.formatString('VarSet_{0}_{1}', SaraUtils.getTimeStamp(), SaraUtils.getRandom());
2794
2795 LOGGER.info('Saving variable set (name = {0})...', varSetName);
2796 varSetId = this.saveOrUpdateVariableSet( {
2797 'name': varSetName,
2798 'description': SaraUtils.formatString('Variable Set containing all variables belong to "{0}" ({1}) catalog item', sapiService.getName(), sapiService.getServiceName()),
2799 'title': SaraUtils.formatString('{0} Variable Set', sapiService.getName()),
2800 'display_title': true
2801 }).sys_id;
2802
2803 LOGGER.info('Saved variable set (name = {0})', varSetName);
2804
2805 //get existing variable set item
2806 var varSetItem = glideHelper.getData(SaraCommon.TABLE_NAME.SN_VARIABLE_SET_ITEM, {
2807 'sc_cat_item': catalogItemId
2808 });
2809
2810 if(!varSetItem) {
2811 varSetItem = {};
2812 }
2813 else {
2814 var oldVarSetId = varSetItem.variable_set;
2815 if(oldVarSetId !== varSetId) {
2816 this.deactivateVarSet(oldVarSetId);
2817 }
2818 }
2819 varSetItem.sc_cat_item = catalogItemId;
2820 varSetItem.variable_set = varSetId;
2821 // Create relation between variable set and catalog item by adding a record to SaraCommon.TABLE_NAME.SN_VARIABLE_SET_ITEM table
2822 LOGGER.info('Creating relation between variable set catalog item');
2823 this.saveOrUpdateVariableSetItem(varSetItem);
2824 LOGGER.info('Created relation between variable set catalog item');
2825
2826 // Creating Sara client scripts
2827 this.createSaraClientScripts(varSetId);
2828
2829 // Creating Sara hidden variable
2830 this.createSaraHiddenVariable(varSetId);
2831
2832 // process each variable in the set
2833 LOGGER.info('Importing {0} variables for variable set named "{1}"...', sapiService.variables.length, varSetName);
2834 for (var i = 0; i < sapiService.variables.length ; i++) {
2835 var variable = sapiService.variables[i];
2836 this.saveSapiServiceVariable(variable, null, varSetId);
2837 }
2838 LOGGER.info('Imported {0} variables for variable set (name = {1}, sys_id = {2})', sapiService.variables.length, varSetName, varSetId);
2839 } else {
2840 LOGGER.warn('There\' no variable found in catalog item (name = {0}). Skip syncLookup!', sapiService.getName());
2841 }
2842
2843 return varSetId;
2844 },
2845
2846 deactivateVarSet: function(varSetId) {
2847 var glideHelper = this.glideHelper;
2848 var LOGGER = this.LOGGER;
2849 LOGGER.info("Deactivating Variable Set: " + varSetId);
2850 SaraUtils.guardNotNullOrEmpty(varSetId, "varSetId must not be null or empty");
2851 var saraVariables = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_VARIABLE, {
2852 variable_set: varSetId
2853 }, true);
2854
2855 for(var i = 0; i < saraVariables.length; i++) {
2856 var saraVariable = saraVariables[i];
2857 saraVariable.active = false;
2858 LOGGER.info("Deactivate Sara Variable");
2859 this.saveOrUpdateVariable(saraVariable);
2860 }
2861 LOGGER.info("Deactivated Variable Set");
2862 },
2863
2864 /**
2865 * Save variable
2866 * @param {SaraModel.CatalogVariable} variable
2867 * @param {String} catalogItemId
2868 * @param {String} varSetId
2869 * @param {Object} optionals
2870 * @return {String} sys_id of saved variable
2871 */
2872 saveSapiServiceVariable: function(variable, catalogItemId, varSetId, optionals) {
2873 var glideHelper = this.glideHelper;
2874 var LOGGER = this.LOGGER;
2875
2876 LOGGER.info('Saving variable (name = {0}, type = {1}, isLookup = {2})...', variable.getName(), variable.getType(), variable.isLookup());
2877
2878 var variableData = {
2879 'name': variable.getName(),
2880 'type': variable.getType(),
2881 'u_is_lookup': variable.isLookup(),
2882 'u_hash': variable.getHash(),
2883 'order': variable.getOrder()
2884 };
2885
2886 if (catalogItemId) {
2887 variableData.cat_item = catalogItemId;
2888 } else if (varSetId) {
2889 variableData.variable_set = varSetId;
2890 }
2891
2892 if (variable.getDescription()) {
2893 variableData.help_text = variable.getDescription();
2894 variableData.show_help = true;
2895 }
2896
2897 // Include '-- None --' option if type is 'LOOKUP_SELECT_BOX' and there's no defaultValue
2898 if (variable.getType() === SaraCommon.VAR_TYPE.LOOKUP_SELECT_BOX && (!variable.getDefaultValue() || !variable.getDefaultValue()[0])) {
2899 variableData.include_none = true;
2900 }
2901
2902 // Add default value if have and default value is not array
2903 if (variable.getDefaultValue() && variable.getDefaultValue().length === 1 && variable.getType() !== SaraCommon.VAR_TYPE.LIST_COLLECTOR) {
2904 variableData.default_value = variable.getDefaultValue()[0];
2905 }
2906
2907 variableData.question_text = variable.getLabel();
2908 variableData.mandatory = variable.isRequired();
2909
2910 if (optionals) {
2911 for (var prop in optionals) {
2912 variableData[prop] = optionals[prop];
2913 }
2914 }
2915
2916 // Additional fields for Sara
2917 variableData.u_name = variable.getActualName();
2918 variableData.u_is_password = variable.isPassword();
2919
2920 // get 'catalog' user role
2921 var catalogRoleId = glideHelper.getSysId(SaraCommon.TABLE_NAME.SN_ROLE, {
2922 'name': 'catalog'
2923 });
2924
2925 LOGGER.info('Variable information: {0}', SaraJSON.stringify(variableData));
2926
2927 // Save variable to SaraCommon.TABLE_NAME.SARA_VARIABLE table
2928 var variableId = this.saveOrUpdateVariable(variableData).sys_id;
2929
2930 // Process variable range for all lookup controls
2931 if (variable.isLookup()) {
2932 LOGGER.info('Saving lookup table for lookup control (sys_id = {0})...', variableId);
2933
2934 // Default value for list collector is list of value id in range table
2935 var defaultValueForListCollector = [];
2936
2937 // Update data for lookup controls
2938 var updateData = {};
2939
2940 var ranges = variable.getRange();
2941 if (ranges) {
2942 updateData.u_is_lookup = "true";
2943 // Insert values to lookup table
2944 for (var i = 0; i < ranges.length; i++) {
2945 var rangeValue = ranges[i];
2946 var key = rangeValue.Value;
2947 var display = rangeValue.Key;
2948 if(!rangeValue.Value) {
2949 key = SaraCommon.EMPTY_VALUE.KEY;
2950 display = SaraCommon.EMPTY_VALUE.VALUE;
2951 }
2952
2953 var rangeId = this.saveOrUpdateSaraLookup({
2954 'u_key': key,
2955 'u_display_name': display,
2956 'u_control_id': variableId
2957 }).sys_id;
2958
2959 if (SaraUtils.inArray(variable.defaultValue, rangeValue.Key)) {
2960 defaultValueForListCollector.push(rangeId);
2961 }
2962 }
2963
2964 LOGGER.info('Insert {0} values to table "{1}" finished successfully.', ranges.length, SaraCommon.TABLE_NAME.SARA_LOOKUP);
2965 } else {
2966 LOGGER.info('Lookup values of {0} is null', variable.getName());
2967 }
2968
2969 if (variable.getType() === SaraCommon.VAR_TYPE.LIST_COLLECTOR) {
2970 updateData.list_table = SaraCommon.TABLE_NAME.SARA_LOOKUP;
2971 updateData.default_value = defaultValueForListCollector.join(',');
2972 updateData.attributes = 'no_filter=true';
2973 updateData.reference_qual = 'u_control_id=' + variableId;
2974 } else {
2975 updateData.lookup_table = SaraCommon.TABLE_NAME.SARA_LOOKUP;
2976 updateData.lookup_value = 'u_display_name';
2977 updateData.reference_qual = 'u_control_id=' + variableId;
2978 }
2979
2980 LOGGER.debug('Variable updated information: {0}', SaraJSON.stringify(updateData));
2981 updateData.id = variableId;
2982 updateData.name = variableData.name;
2983 updateData.variable_set = variableData.variable_set;
2984 this.saveOrUpdateVariable(updateData);
2985 LOGGER.info('Saved lookup table for lookup control (sys_id = {0})', variableId);
2986 }
2987
2988 LOGGER.info('Saved variable (name = {0}, type = {1}, isLookup = {2})', variable.getName(), variable.getType(), variable.isLookup());
2989
2990 return variableId;
2991 },
2992
2993 getVariableSet: function(name) {
2994 return this.glideHelper.getData(this.TABLES.SN_VARIABLE_SET, {name: name});
2995 },
2996
2997 /**
2998 * param varset
2999 * id: optional. Blank for insert
3000 * name: required
3001 * title:
3002 * description:
3003 * sys_name:
3004 */
3005 saveOrUpdateVariableSet: function(varset) {
3006 SaraUtils.guardNotNullOrEmpty(varset, "varset must not be null or empty");
3007 SaraUtils.guardNotNullOrEmpty(varset.name, "varset name must not be null or empty");
3008
3009 this.saveOrUpdateEntity(varset, "var_set");
3010
3011 var result = this.getVariableSet(varset.name);
3012 SaraUtils.guardNotNullOrEmpty(result, "variable set is not save or updated correctly: " + varset.name);
3013 return result;
3014 },
3015
3016 getVariableSetItem: function(sc_cat_item, variable_set) {
3017 return this.glideHelper.getData(this.TABLES.SN_VARIABLE_SET_ITEM, {sc_cat_item: sc_cat_item, variable_set: variable_set});
3018 },
3019
3020 saveOrUpdateVariableSetItem: function(varsetItem) {
3021 SaraUtils.guardNotNullOrEmpty(varsetItem, "varsetItem must not be null or empty");
3022 SaraUtils.guardNotNullOrEmpty(varsetItem.sc_cat_item, "varsetItem sc_cat_item must not be null or empty");
3023 SaraUtils.guardNotNullOrEmpty(varsetItem.variable_set, "varsetItem variable_set must not be null or empty");
3024
3025 this.saveOrUpdateEntity(varsetItem, "var_set_item");
3026
3027 var result = this.getVariableSetItem(varsetItem.sc_cat_item, varsetItem.variable_set);
3028 SaraUtils.guardNotNullOrEmpty(result, "variable set item is not save or updated correctly");
3029 return result;
3030 },
3031
3032 getVariable: function(variable_set, name) {
3033 return this.glideHelper.getData(this.TABLES.SARA_VARIABLE, {variable_set: variable_set, name: name});
3034 },
3035
3036 saveOrUpdateVariable: function(variable) {
3037 SaraUtils.guardNotNullOrEmpty(variable, "variable must not be null or empty");
3038 SaraUtils.guardNotNullOrEmpty(variable.variable_set, "variable variable_set must not be null or empty");
3039 SaraUtils.guardNotNullOrEmpty(variable.name, "variable name must not be null or empty");
3040
3041 this.saveOrUpdateEntity(variable, "sara_variable");
3042
3043 var result = this.getVariable(variable.variable_set, variable.name);
3044 SaraUtils.guardNotNullOrEmpty(result, "variable is not save or updated correctly");
3045 return result;
3046 },
3047
3048 getSaraLookup: function(u_control_id, u_key, u_display_name) {
3049 return this.glideHelper.getData(this.TABLES.SARA_LOOKUP, {u_control_id: u_control_id, u_key: u_key, u_display_name: u_display_name});
3050 },
3051
3052 saveOrUpdateSaraLookup: function(lookup) {
3053 SaraUtils.guardNotNullOrEmpty(lookup, "lookup must not be null or empty");
3054 SaraUtils.guardNotNullOrEmpty(lookup.u_key, "lookup u_key must not be null or empty");
3055
3056 this.saveOrUpdateEntity(lookup, "sara_lookup");
3057
3058 var controlId = lookup.u_control_id;
3059 if(controlId === "0") {
3060 controlId = "";
3061 }
3062 var result = this.getSaraLookup(lookup.u_control_id, lookup.u_key, lookup.u_display_name);
3063 SaraUtils.guardNotNullOrEmpty(result, "lookup is not save or updated correctly");
3064 return result;
3065 },
3066
3067 /**
3068 * Create Sara Client Scripts with type is Macro and using UI Macro name SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS. This control help us to
3069 * include all SNSC client scripts
3070 * @param {String} varSetId The sys_id of variable set
3071 */
3072 createSaraClientScripts: function (varSetId) {
3073 var glideHelper = this.glideHelper;
3074 var LOGGER = this.LOGGER;
3075
3076 var macroSaraClientScripts = glideHelper.getData(SaraCommon.TABLE_NAME.SN_UI_MACRO, {
3077 'name': SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS
3078 });
3079
3080 if (macroSaraClientScripts) {
3081 this.saveOrUpdateVariable({
3082 'name': SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS,
3083 'type': SaraCommon.VAR_TYPE.MACRO,
3084 'u_is_lookup': false,
3085 'macro': macroSaraClientScripts.sys_id,
3086 'variable_set': varSetId
3087 });
3088 } else {
3089 LOGGER.info('There\' no UI Macro named "{0}". Creating Sara client scripts skipped!', SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS);
3090 }
3091 },
3092
3093 /**
3094 * Create Sara Hidden Variable with type is Macro and using UI Macro name SaraCommon.CONTROL_NAME.HIDDEN_CONTROL. This control help us
3095 * to run x_ausgh_snsc.SaraVarSet.onLoad() method without creating Catalog Client Script for VariableSet
3096 * @param {String} varSetId The sys_id of variable set
3097 */
3098 createSaraHiddenVariable: function (varSetId) {
3099 var glideHelper = this.glideHelper;
3100 var LOGGER = this.LOGGER;
3101
3102 var macroSaraHiddenControl = glideHelper.getData(SaraCommon.TABLE_NAME.SN_UI_MACRO, {
3103 'name': SaraCommon.CONTROL_NAME.HIDDEN_CONTROL
3104 });
3105
3106 if (macroSaraHiddenControl) {
3107 this.saveOrUpdateVariable({
3108 'name': SaraCommon.CONTROL_NAME.HIDDEN_CONTROL,
3109 'type': SaraCommon.VAR_TYPE.MACRO,
3110 'u_is_lookup': false,
3111 'macro': macroSaraHiddenControl.sys_id,
3112 'variable_set': varSetId
3113 });
3114 } else {
3115 LOGGER.info('There\' no UI Macro named "{0}". Creating Sara hidden control skipped!', SaraCommon.CONTROL_NAME.HIDDEN_CONTROL);
3116 }
3117 },
3118
3119 //---------------------------
3120 //Sara Definition
3121 //---------------------------
3122 getSaraDefinition: function(name, parentCategoryId, type) {
3123 return this.glideHelper.getData(this.TABLES.SARA_DEFINITION, {
3124 'u_name': name,
3125 'u_parent': parentCategoryId,
3126 'u_type': type
3127 });
3128 },
3129
3130 /**
3131 * param saraDefinition
3132 * id:
3133 * u_name: required
3134 * u_consume_url:
3135 * u_sc_item:
3136 * u_service_catalog_category:
3137 * u_var_set:
3138 * u_parent: required
3139 * u_type: required
3140 * u_hash:
3141 * u_active
3142 */
3143 saveOrUpdateSaraDefinition: function(saraDefinition) {
3144 SaraUtils.guardNotNullOrEmpty(saraDefinition, "saraDefinition must not be null or empty");
3145 SaraUtils.guardNotNullOrEmpty(saraDefinition.u_name, "u_name must not be null or empty");
3146 SaraUtils.guardNotNullOrEmpty(saraDefinition.u_parent, "u_parent must not be null or empty");
3147 SaraUtils.guardNotNullOrEmpty(saraDefinition.u_type, "u_type must not be null or empty");
3148
3149 this.saveOrUpdateEntity(saraDefinition, "sara_definition");
3150
3151 var result = this.getSaraDefinition(saraDefinition.u_name, saraDefinition.u_parent, saraDefinition.u_type);
3152 SaraUtils.guardNotNullOrEmpty(result, "definition is not save or updated correctly");
3153 return result;
3154 },
3155
3156 /**
3157 * Save category into SaraCommon.TABLE_NAME.SARA_DEFINITION table
3158 * @param {String} categoryId
3159 */
3160 saveRootImportCategoryToSaraDefinition: function (categoryId) {
3161 var glideHelper = this.glideHelper;
3162 var LOGGER = this.LOGGER;
3163
3164 var targetCategory = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
3165 'sys_id': categoryId
3166 });
3167
3168 var importedDefinition = this.getSaraDefinition(targetCategory.title, targetCategory.sys_id, 'category');
3169
3170 if (importedDefinition) {
3171 LOGGER.info('Services have been imported in target category (name = {0})!', targetCategory.title);
3172 return importedDefinition;
3173 } else {
3174 return this.saveOrUpdateSaraDefinition({
3175 u_name: targetCategory.title,
3176 u_parent: targetCategory.sys_id,
3177 u_type: 'category',
3178 u_active: true
3179 });
3180 }
3181 },
3182
3183 /**
3184 * Save category into SaraCommon.TABLE_NAME.SARA_DEFINITION table
3185 * @param {String} categoryId
3186 */
3187 saveCategoryToSaraDefinition: function (sapiCatalog) {
3188 var glideHelper = this.glideHelper;
3189 var LOGGER = this.LOGGER;
3190
3191 // Assign default homepage renderer
3192 var defaultRendererSysId = glideHelper.getSysId(SaraCommon.TABLE_NAME.SN_HOMEPAGE_RENDERER, {
3193 'name': 'Category Items'
3194 });
3195
3196 var categoryToSave = {
3197 title: sapiCatalog.getTitle(),
3198 description: sapiCatalog.getDescription(),
3199 active: sapiCatalog.isActive(),
3200 homepage_renderer: defaultRendererSysId,
3201 parent: sapiCatalog.getParent(),
3202 };
3203 var category = this.saveOrUpdateCategory(categoryToSave);
3204 LOGGER.info('Created Catalog category {0} (sys_id = {1})...', sapiCatalog.getTitle(), category.sys_id);
3205
3206 return this.saveOrUpdateSaraDefinition({
3207 'u_service_catalog_category': category.sys_id,
3208 'u_name': sapiCatalog.getName(),
3209 'u_consume_url': sapiCatalog.getConsumeUrl() || '',
3210 'u_parent': sapiCatalog.getParent(),
3211 'u_type': 'catalog',
3212 'u_description': sapiCatalog.getDescription(),
3213 'u_active': true
3214 });
3215 },
3216
3217 /**
3218 * Deactivate item in SaraCommon.TABLE_NAME.SARA_DEFINITION via import set
3219 * @param {Object} saraDefinition The catalog item which will be deactivated
3220 */
3221 deactivateSaraDefinition: function (saraDefinition) {
3222 SaraUtils.guardNotNullOrEmpty(saraDefinition, "saraDefinition must not be null or empty");
3223 var id = saraDefinition.sys_id || saraDefinition.id;
3224 SaraUtils.guardNotNullOrEmpty(id, "definition id must not be null or empty");
3225
3226 var glideHelper = this.glideHelper;
3227 var LOGGER = this.LOGGER;
3228
3229 LOGGER.info('Deactivating sara definition and its child definitions... (sys_id = {0}, u_name= {1}) in table "{2}"',
3230 saraDefinition.sys_id, saraDefinition.u_name, SaraCommon.TABLE_NAME.SARA_DEFINITION);
3231
3232 var categoryId = saraDefinition.u_service_catalog_category;
3233 this.deactivateCategory(categoryId);
3234
3235 var catItemId = saraDefinition.u_sc_item;
3236 this.deactivateCatalogItem(catItemId);
3237
3238 // Deactivate definition in SaraCommon.TABLE_NAME.SARA_DEFINITION table
3239 LOGGER.info('Deactivating sara definition...');
3240 saraDefinition.u_active = false;
3241 this.saveOrUpdateSaraDefinition(saraDefinition);
3242 LOGGER.info('Deactivated sara definition');
3243
3244 LOGGER.info('Deactivating child definitions...');
3245 var parentCategoryId = saraDefinition.u_service_catalog_category;
3246 if(SaraUtils.isNullOrEmpty(parentCategoryId)) {
3247 parentCategoryId = saraDefinition.u_parent;
3248 }
3249
3250 if(saraDefinition.u_type === 'category' || saraDefinition.u_type === 'catalog') {
3251 var nextLevelType = saraDefinition.u_type === 'category' ? 'catalog' : 'service';
3252 // Deactive items which have parent is this category
3253 var childDefinitions = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
3254 'u_parent': parentCategoryId,
3255 'u_type': nextLevelType
3256 }, true);
3257
3258 if(childDefinitions.length === 0) {
3259 LOGGER.info("No child definition found");
3260 }
3261
3262 for (var i = 0; i < childDefinitions.length; i++) {
3263 var childDefinition = childDefinitions[i];
3264 this.deactivateSaraDefinition(childDefinition);
3265 }
3266 }
3267
3268 LOGGER.info('Deactivated sara definition and its child definitions');
3269 },
3270
3271 deactivateCatalogItem: function(catItemId) {
3272 var glideHelper = this.glideHelper;
3273 var LOGGER = this.LOGGER;
3274 if(!SaraUtils.isNullOrEmpty(catItemId)) {
3275 var catItem = glideHelper.getData(this.TABLES.SN_CATALOG_ITEM, {sys_id: catItemId});
3276 // Mark catalog item as deleted in SaraCommon.TABLE_NAME.SN_CATALOG_ITEM table
3277 LOGGER.info('Deactivating catalog item (sys_id = {0}, name = {1}) in table "{2}"', catItemId, catItem.name, SaraCommon.TABLE_NAME.SARA_CAT_ITEM);
3278 catItem.active = false;
3279 this.saveOrUpdateCatalogItem(catItem);
3280 LOGGER.info('Deactivated catalog item (sys_id = {0}, name = {1}) in table "{2}"', catItemId, catItem.name, SaraCommon.TABLE_NAME.SARA_CAT_ITEM);
3281 }
3282 },
3283
3284 saveOrUpdateEntity: function(entity, type) {
3285 SaraUtils.guardNotNullOrEmpty(entity, "entity cannot be null or empty");
3286 SaraUtils.guardNotNullOrEmpty(type, "type cannot be null or empty");
3287
3288 var LOGGER = this.LOGGER;
3289
3290 var mappingDefinition;
3291 for(var definedType in this.typeMaps) {
3292 if(type === definedType) {
3293 mappingDefinition = this.typeMaps[type];
3294 }
3295 }
3296
3297 if(mappingDefinition === undefined) {
3298 throw " Defined mapping for " + type + " not found.";
3299 }
3300
3301 //transfer properties to new data object
3302 var data = {};
3303
3304 for(var i = 0; i < mappingDefinition.fields.length; i++) {
3305 var fieldName = mappingDefinition.fields[i];
3306 if(entity[fieldName] !== undefined) {
3307 data[fieldName] = entity[fieldName];
3308 }
3309 else {
3310 if(fieldName === "active") {
3311 LOGGER.info("default active to true");
3312 data[fieldName] = true;
3313 }
3314 }
3315 }
3316
3317 if(!SaraUtils.isNullOrEmpty(entity.sys_id)) {
3318 data.id= entity.sys_id;
3319 }
3320
3321 this.LOGGER.info(" dal.saveOrUpdateEntity: Save or update entity: type = {0}, data = ({1}) -> staging table {2}", type, SaraJSON.stringify(data), mappingDefinition.stagingTable);
3322
3323 this.glideHelper.persistData(mappingDefinition.stagingTable, data);
3324
3325 this.LOGGER.info(" dal.saveOrUpdateEntity: done");
3326
3327 return data;
3328 },
3329
3330 getTypeMaps: function() {
3331 return {
3332 "catalog": {
3333 stagingTable: this.TABLES.SN_CATALOG_IST,
3334 table: this.TABLES.SN_CATALOG,
3335 fields: [
3336 "id",
3337 "title",
3338 "description",
3339 "active"]
3340 },
3341 "category": {
3342 stagingTable: this.TABLES.SN_CATEGORY_IST,
3343 table: this.TABLES.SN_CATEGORY,
3344 fields: [
3345 "id",
3346 "title",
3347 "homepage_renderer",
3348 "active",
3349 "description",
3350 "parent",
3351 "sc_catalog"]
3352 },
3353 "cat_item": {
3354 stagingTable: this.TABLES.SARA_CAT_ITEM_IST,
3355 table: this.TABLES.SARA_CAT_ITEM,
3356 fields: [
3357 "id",
3358 "name",
3359 "category",
3360 "active",
3361 "short_description",
3362 "description",
3363 "custom_cart",
3364 "use_sc_layout",
3365 "no_quantity",
3366 "workflow",
3367 "sc_catalogs"]
3368 },
3369 "var_set": {
3370 stagingTable: this.TABLES.SN_VARIABLE_SET_IST,
3371 table: this.TABLES.SN_VARIABLE_SET,
3372 fields: [
3373 "id",
3374 "name",
3375 "description",
3376 "title",
3377 "sys_name"
3378 ]
3379 },
3380 "var_set_item": {
3381 stagingTable: this.TABLES.SN_VARIABLE_SET_ITEM_IST,
3382 table: this.TABLES.SN_VARIABLE_SET_ITEM,
3383 fields: [
3384 "id",
3385 "sc_cat_item",
3386 "variable_set",
3387 ]
3388 },
3389 "sara_definition": {
3390 stagingTable: this.TABLES.SARA_DEFINITION_IST,
3391 table: this.TABLES.SARA_DEFINITION,
3392 fields: [
3393 "id",
3394 "u_name",
3395 "u_consume_url",
3396 "u_sc_item",
3397 "u_service_catalog_category",
3398 "u_var_set",
3399 "u_parent",
3400 "u_type",
3401 "u_hash",
3402 "u_active"]
3403 },
3404 "sara_variable": {
3405 stagingTable: this.TABLES.SARA_VARIABLE_IST,
3406 table: this.TABLES.SARA_VARIABLE,
3407 fields: [
3408 "id",
3409 "u_name",
3410 "u_readonly",
3411 "u_is_password",
3412 "u_is_lookup",
3413 "u_hash",
3414 "variable_set",
3415 "type",
3416 "macro",
3417 "name",
3418 "cat_item",
3419 "help_text",
3420 "show_help",
3421 "include_none",
3422 "default_value",
3423 "question_text",
3424 "mandatory",
3425 "list_table",
3426 "attributes",
3427 "lookup_table",
3428 "lookup_value",
3429 "reference_qual",
3430 "order",
3431 "active"]
3432 },
3433 "sara_lookup": {
3434 stagingTable: this.TABLES.SARA_LOOKUP_IST,
3435 table: this.TABLES.SARA_LOOKUP,
3436 fields: [
3437 "id",
3438 "u_key",
3439 "u_display_name",
3440 "u_control_id"]
3441 }
3442 };
3443 },
3444 type: 'SaraConsumerDAL'
3445};
3446]]></script>
3447 <description>Sara Consumer Data Access to read and import service definition to Service Catalog using staging tables</description>
3448 <active>true</active>
3449 <client_callable>false</client_callable>
3450 <access>public</access>
3451 </script_include>
3452
3453 <script_include>
3454 <name>SaraConsumerRunner</name>
3455 <script><![CDATA[/**
3456 * Runner for SaraConsumerImportSet
3457 */
3458var SaraConsumerRunner = Class.create();
3459SaraConsumerRunner.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
3460 start: function () {
3461 var LOGGER = new SaraLog(this);
3462
3463 var targetCatId = this.getParameter('sysparm_catid');
3464
3465 LOGGER.info('Starting SaraConsumerRunner for importing services into "{0}"...', targetCatId);
3466
3467 var worker = new GlideScriptedHierarchicalWorker();
3468 worker.setProgressName('Import Services');
3469 worker.setBackground(true);
3470 worker.setScriptIncludeName('x_ausgh_snsc.SaraConsumerWorker');
3471 worker.setScriptIncludeMethod('run');
3472 worker.putMethodArg('targetCatId', targetCatId);
3473 worker.start();
3474
3475 LOGGER.info('SaraConsumerWorker starts successfully!');
3476
3477 var progressID = worker.getProgressID();
3478
3479 LOGGER.info('ID of SaraConsumerWorker is {0}', progressID);
3480
3481 return progressID;
3482 },
3483
3484 type: 'SaraConsumerRunner'
3485
3486});
3487]]></script>
3488 <description>Worker for SaraConsumer</description>
3489 <active>true</active>
3490 <client_callable>true</client_callable>
3491 <access>public</access>
3492 </script_include>
3493
3494 <script_include>
3495 <name>SaraConsumerWorker</name>
3496 <script><![CDATA[/**
3497 * Worker for SaraConsumerImportSet
3498 */
3499var SaraConsumerWorker = Class.create();
3500SaraConsumerWorker.prototype = {
3501 initialize: function () {
3502 var LOGGER = this.LOGGER = new SaraLog(this);
3503 var tracker = null;
3504 try {
3505 tracker = GlideExecutionTracker.getLastRunning();
3506 } catch (e) {
3507 LOGGER.error('Error when getting tracker: {0}', e);
3508 }
3509
3510 this.tracker = tracker;
3511 },
3512
3513 run: function (targetCatId) {
3514 var LOGGER = this.LOGGER;
3515 if (targetCatId) {
3516 try {
3517 var consumer = new SaraConsumerImportSet(this.tracker);
3518 var result = consumer.discoverAndImport(targetCatId);
3519
3520 if (!result) {
3521 var statusCode = consumer.getStatusCode();
3522 var errorMessage = consumer.getErrorMessage();
3523
3524 if (statusCode != 200) {
3525 this.updateTrackerResult('Failed to import Automic services', true);
3526 this.tracker.fail('Got error: ' + statusCode + ' - ' + errorMessage);
3527 } else {
3528 this.updateTrackerResult('Got no service or catalog from server.', false);
3529 this.tracker.success('Got no service or catalog from server.');
3530 }
3531 } else {
3532 this.updateTrackerResult('Imported successfully', false, result);
3533 this.tracker.success('Imported successfully!');
3534 }
3535 } catch (err) {
3536 LOGGER.error('Failed to import Automic services', err);
3537 this.updateTrackerResult('Failed to import Automic services', true);
3538 this.tracker.fail(err);
3539 }
3540 } else {
3541 this.updateTrackerResult('Failed to import Automic services', true);
3542 this.tracker.fail('Target category id is null!');
3543 }
3544 },
3545
3546 /**
3547 * Update tracker result
3548 * @param {String} message The message content
3549 * @param {Boolean} error Error or not
3550 * @param {String} info The addition information
3551 */
3552 updateTrackerResult: function (message, error, info) {
3553 var LOGGER = this.LOGGER;
3554
3555 if (error) {
3556 LOGGER.error(message);
3557 } else {
3558 LOGGER.info(message);
3559 }
3560
3561 try {
3562 this.tracker.updateResult({
3563 msg: message,
3564 info: info
3565 });
3566 } catch (ex) {
3567 LOGGER.error('Error when updating result for tracker: {0}', ex);
3568 }
3569 },
3570
3571 type: 'SaraConsumerWorker'
3572
3573};
3574]]></script>
3575 <description>Runner for SaraConsumer</description>
3576 <active>true</active>
3577 <client_callable>false</client_callable>
3578 <access>public</access>
3579 </script_include>
3580
3581 <script_include>
3582 <name>SaraGlideHelper</name>
3583 <script><![CDATA[/**
3584 * Helper class provides convenient methods to work with ServiceNow data tables
3585 */
3586var SaraGlideHelper = Class.create();
3587SaraGlideHelper.prototype = {
3588 initialize: function () {},
3589
3590 /**
3591 * Common data persistent operation
3592 * @param {String} table The table name
3593 * @param {Object} entity Object represents the row to insert
3594 * @param {Boolean} referencing Insert with references or not
3595 * @return {String} sys_id of inserted row
3596 */
3597 persistData: function (table, entity, referencing) {
3598 var rec = this._getGlideRecord(table);
3599 rec.initialize();
3600
3601 for (key in entity) {
3602 var value = entity[key];
3603
3604 if (value === undefined || value === null) {
3605 value = '';
3606 }
3607
3608 // check if key contains 'sys_id'
3609 var idx = key.indexOf('.sys_id');
3610 if (idx > 0 && idx == key.length - 7) {
3611 var propName = key.substring(0, idx);
3612 rec[propName]['sys_id'] = value;
3613 } else {
3614 rec[key] = value;
3615 }
3616 }
3617
3618 if (referencing) {
3619 return rec.insertWithReferences();
3620 } else {
3621 return rec.insert();
3622 }
3623 },
3624
3625 /**
3626 * Updates record(s) in given table based on the query and entity object holds fields/values to update
3627 * @param {String} table Target table to update
3628 * @param {Object} queryObj Query object, property name is the field name to query, value is value to query
3629 * @param {Object} entity Entity holds fields and values to update
3630 * @param {Boolean} updateAll Update all matching record(s) or only the first one
3631 * @param {Boolean} referencing Update with references or not
3632 */
3633 updateData: function (table, queryObj, entity, updateAll, referencing) {
3634 var rec = this._getGlideRecord(table);
3635 this._buildQuery(rec, queryObj);
3636 rec.query();
3637
3638 while (rec.next()) {
3639 for (key in entity) {
3640 // check if key contains 'sys_id'
3641 var idx = key.indexOf('.sys_id');
3642 if (idx > 0 && idx == key.length - 7) {
3643 var propName = key.substring(0, idx);
3644 rec[propName]['sys_id'] = entity[key];
3645 } else {
3646 rec[key] = entity[key];
3647 }
3648 }
3649
3650 if (referencing) {
3651 rec.updateWithReferences();
3652 } else {
3653 rec.update();
3654 }
3655
3656 if (!updateAll) {
3657 break;
3658 }
3659 }
3660 },
3661
3662 /**
3663 * Retrieve sys_id of a record in given table by key=value query
3664 * @param {String} table The table name
3665 * @param {Object} queryObj The object holds the query, property name is the field name to query, value is value to query
3666 * @param {Boolean} getAll Get sys_id of all matching record(s) or only the first one
3667 * @return {String|Array<String>} sys_id that found, or null if no record found
3668 */
3669 getSysId: function (table, queryObj, getAll) {
3670 var rec = this._getGlideRecord(table);
3671 this._buildQuery(rec, queryObj);
3672 rec.query();
3673
3674 if (getAll) {
3675 var results = [];
3676 while (rec.next()) {
3677 results.push('' + rec['sys_id']);
3678 }
3679
3680 return results;
3681 } else {
3682 if (rec.next()) {
3683 return '' + rec['sys_id'];
3684 } else {
3685 return null;
3686 }
3687 }
3688 },
3689
3690 /**
3691 * Parse GlideRecordSecure into an object with same properties but value of properties will be converted to String. The
3692 * original properties will be store in '_origin' property
3693 * @param {GlideRecordSecure} rec The instance of GlideRecordSecure
3694 * @return {Object}
3695 */
3696 _parseRecord: function (rec) {
3697 var obj = {
3698 _origin: rec
3699 };
3700
3701 for (var key in rec) {
3702 try {
3703 obj[key] = '' + rec[key];
3704 } catch (e) {
3705 obj[key] = '' + rec[key].toString();
3706 }
3707 }
3708
3709 return obj;
3710 },
3711
3712 /**
3713 * Query data from given table and query condition, return objects contain information specified in list of key
3714 * @param {String} table The target table
3715 * @param {Object} queryObj The object holds the query, property name is the field name to query, value is value to query
3716 * @param {Boolean} getAll Get all matching record(s) or only the first one
3717 * @return {Array} Array of object
3718 */
3719 getData: function (table, queryObj, getAll) {
3720 var rec = this._getGlideRecord(table);
3721 this._buildQuery(rec, queryObj);
3722 rec.query();
3723
3724 if (getAll) {
3725 var result = [];
3726 while (rec.next()) {
3727 result.push(this._parseRecord(rec));
3728 }
3729
3730 return result;
3731 } else {
3732 if (rec.next()) {
3733 return this._parseRecord(rec);
3734 } else {
3735 return null;
3736 }
3737 }
3738 },
3739
3740 /**
3741 * Delete record(s) from given table based on a query condition
3742 * @param {String} table The target table
3743 * @param {Object} queryObj The object holds the query, property name is the field name to query, value is value to query
3744 * @param {Boolean} deleteAll Delete all matching record(s) or only the first one
3745 */
3746 deleteData: function (table, queryObj, deleteAll) {
3747 var rec = this._getGlideRecord(table);
3748 this._buildQuery(rec, queryObj);
3749
3750 if (deleteAll) {
3751 rec.deleteMultiple();
3752 } else {
3753 rec.query();
3754 if (rec.next()) {
3755 rec.deleteRecord();
3756 }
3757 }
3758 },
3759
3760 /**
3761 * Build query for GlideRecordSecure and also support Operators
3762 * @link http://wiki.servicenow.com/index.php?title=Using_GlideRecord_to_Query_Tables
3763 * @param {GlideRecordSecure} rec
3764 * @param {Object} queryObj
3765 * - @key {String} The field name
3766 * - @value {Array|String|Number} The field value. If array, value will be [Operator, Value]
3767 */
3768 _buildQuery: function (rec, queryObj) {
3769 for (var key in queryObj) {
3770 var value = queryObj[key];
3771
3772 if (typeof value === 'object' && value instanceof Array) {
3773 rec.addQuery(key, value[0], value[1]);
3774 } else {
3775 rec.addQuery(key, value);
3776 }
3777 }
3778 },
3779
3780 /**
3781 * Get instance of GlideRecordSecure
3782 * @param {String} table The target table
3783 * @return {GlideRecordSecure}
3784 */
3785 _getGlideRecord: function (table) {
3786 return new GlideRecordSecure(table);
3787 },
3788
3789 type: 'SaraGlideHelper'
3790};
3791]]></script>
3792 <description>Helper class provides convenient methods to work with ServiceNow data tables</description>
3793 <active>true</active>
3794 <client_callable>false</client_callable>
3795 <access>public</access>
3796 </script_include>
3797
3798 <script_include>
3799 <name>SaraJSON</name>
3800 <script><![CDATA[/**
3801 * Sara JSON Utilities
3802 */
3803var SaraJSON = Class.create();
3804SaraJSON.prototype = {
3805 initialize: function() {},
3806
3807 type: 'SaraJSON'
3808};
3809
3810/*
3811 JSON.js
3812 2013-05-26
3813
3814 Public Domain.
3815
3816 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
3817
3818 See http://www.JSON.org/js.html
3819
3820
3821 This code should be minified before deployment.
3822 See http://javascript.crockford.com/jsmin.html
3823
3824 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
3825 NOT CONTROL.
3826
3827
3828 This file creates a global JSON object containing two methods: stringify
3829 and parse.
3830
3831 JSON.stringify(value, replacer, space)
3832 value any JavaScript value, usually an object or array.
3833
3834 replacer an optional parameter that determines how object
3835 values are stringified for objects. It can be a
3836 function or an array of strings.
3837
3838 space an optional parameter that specifies the indentation
3839 of nested structures. If it is omitted, the text will
3840 be packed without extra whitespace. If it is a number,
3841 it will specify the number of spaces to indent at each
3842 level. If it is a string (such as '\t' or ' '),
3843 it contains the characters used to indent at each level.
3844
3845 This method produces a JSON text from a JavaScript value.
3846
3847 When an object value is found, if the object contains a toJSON
3848 method, its toJSON method will be called and the result will be
3849 stringified. A toJSON method does not serialize: it returns the
3850 value represented by the name/value pair that should be serialized,
3851 or undefined if nothing should be serialized. The toJSON method
3852 will be passed the key associated with the value, and this will be
3853 bound to the value
3854
3855 For example, this would serialize Dates as ISO strings.
3856
3857 Date.prototype.toJSON = function (key) {
3858 function f(n) {
3859 // Format integers to have at least two digits.
3860 return n < 10 ? '0' + n : n;
3861 }
3862
3863 return this.getUTCFullYear() + '-' +
3864 f(this.getUTCMonth() + 1) + '-' +
3865 f(this.getUTCDate()) + 'T' +
3866 f(this.getUTCHours()) + ':' +
3867 f(this.getUTCMinutes()) + ':' +
3868 f(this.getUTCSeconds()) + 'Z';
3869 };
3870
3871 You can provide an optional replacer method. It will be passed the
3872 key and value of each member, with this bound to the containing
3873 object. The value that is returned from your method will be
3874 serialized. If your method returns undefined, then the member will
3875 be excluded from the serialization.
3876
3877 If the replacer parameter is an array of strings, then it will be
3878 used to select the members to be serialized. It filters the results
3879 such that only members with keys listed in the replacer array are
3880 stringified.
3881
3882 Values that do not have JSON representations, such as undefined or
3883 functions, will not be serialized. Such values in objects will be
3884 dropped; in arrays they will be replaced with null. You can use
3885 a replacer function to replace those with JSON values.
3886 JSON.stringify(undefined) returns undefined.
3887
3888 The optional space parameter produces a stringification of the
3889 value that is filled with line breaks and indentation to make it
3890 easier to read.
3891
3892 If the space parameter is a non-empty string, then that string will
3893 be used for indentation. If the space parameter is a number, then
3894 the indentation will be that many spaces.
3895
3896 Example:
3897
3898 text = JSON.stringify(['e', {pluribus: 'unum'}]);
3899 // text is '["e",{"pluribus":"unum"}]'
3900
3901
3902 text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
3903 // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
3904
3905 text = JSON.stringify([new Date()], function (key, value) {
3906 return this[key] instanceof Date ?
3907 'Date(' + this[key] + ')' : value;
3908 });
3909 // text is '["Date(---current time---)"]'
3910
3911
3912 JSON.parse(text, reviver)
3913 This method parses a JSON text to produce an object or array.
3914 It can throw a SyntaxError exception.
3915
3916 The optional reviver parameter is a function that can filter and
3917 transform the results. It receives each of the keys and values,
3918 and its return value is used instead of the original value.
3919 If it returns what it received, then the structure is not modified.
3920 If it returns undefined then the member is deleted.
3921
3922 Example:
3923
3924 // Parse the text. Values that look like ISO date strings will
3925 // be converted to Date objects.
3926
3927 myData = JSON.parse(text, function (key, value) {
3928 var a;
3929 if (typeof value === 'string') {
3930 a =
3931 /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
3932 if (a) {
3933 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
3934 +a[5], +a[6]));
3935 }
3936 }
3937 return value;
3938 });
3939
3940 myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
3941 var d;
3942 if (typeof value === 'string' &&
3943 value.slice(0, 5) === 'Date(' &&
3944 value.slice(-1) === ')') {
3945 d = new Date(value.slice(5, -1));
3946 if (d) {
3947 return d;
3948 }
3949 }
3950 return value;
3951 });
3952
3953
3954 This is a reference implementation. You are free to copy, modify, or
3955 redistribute.
3956 */
3957
3958/*jslint evil: true, regexp: true */
3959
3960/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
3961 call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
3962 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
3963 lastIndex, length, parse, prototype, push, replace, slice, stringify,
3964 test, toJSON, toString, valueOf
3965 */
3966
3967(function(JSON) {
3968 'use strict';
3969
3970 function f(n) {
3971 // Format integers to have at least two digits.
3972 return n < 10 ? '0' + n : n;
3973 }
3974
3975 function toJSON(value) {
3976 if (value instanceof Date) {
3977 return isFinite(date.valueOf()) ? date.getUTCFullYear() + '-' +
3978 f(date.getUTCMonth() + 1) + '-' +
3979 f(date.getUTCDate()) + 'T' +
3980 f(date.getUTCHours()) + ':' +
3981 f(date.getUTCMinutes()) + ':' +
3982 f(date.getUTCSeconds()) + 'Z' : null;
3983 } else {
3984 switch (typeof value) {
3985 case 'string':
3986 case 'number':
3987 case 'boolean':
3988 return value.valueOf();
3989 }
3990 }
3991 }
3992
3993 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
3994 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
3995 gap,
3996 indent,
3997 meta = { // table of character substitutions
3998 '\b': '\\b',
3999 '\t': '\\t',
4000 '\n': '\\n',
4001 '\f': '\\f',
4002 '\r': '\\r',
4003 '"': '\\"',
4004 '\\': '\\\\'
4005 },
4006 rep;
4007
4008
4009 function quote(string) {
4010
4011 // If the string contains no control characters, no quote characters, and no
4012 // backslash characters, then we can safely slap some quotes around it.
4013 // Otherwise we must also replace the offending characters with safe escape
4014 // sequences.
4015
4016 escapable.lastIndex = 0;
4017 return escapable.test(string) ? '"' + string.replace(escapable, function(a) {
4018 var c = meta[a];
4019 return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
4020 }) + '"' : '"' + string + '"';
4021 }
4022
4023
4024 function str(key, holder) {
4025
4026 // Produce a string from holder[key].
4027
4028 var i, // The loop counter.
4029 k, // The member key.
4030 v, // The member value.
4031 length,
4032 mind = gap,
4033 partial,
4034 value = holder[key];
4035
4036 // If the value has a toJSON method, call it to obtain a replacement value.
4037
4038 if (value && typeof value === 'object' && typeof toJSON(value) === 'function') {
4039 value = toJSON(value, key);
4040 }
4041
4042 // If we were called with a replacer function, then call the replacer to
4043 // obtain a replacement value.
4044
4045 if (typeof rep === 'function') {
4046 value = rep.call(holder, key, value);
4047 }
4048
4049 // What happens next depends on the value's type.
4050
4051 switch (typeof value) {
4052 case 'string':
4053 return quote(value);
4054
4055 case 'number':
4056
4057 // JSON numbers must be finite. Encode non-finite numbers as null.
4058
4059 return isFinite(value) ? String(value) : 'null';
4060
4061 case 'boolean':
4062 case 'null':
4063
4064 // If the value is a boolean or null, convert it to a string. Note:
4065 // typeof null does not produce 'null'. The case is included here in
4066 // the remote chance that this gets fixed someday.
4067
4068 return String(value);
4069
4070 // If the type is 'object', we might be dealing with an object or an array or
4071 // null.
4072
4073 case 'object':
4074
4075 // Due to a specification blunder in ECMAScript, typeof null is 'object',
4076 // so watch out for that case.
4077
4078 /**
4079 * MUST to check the type of object is Array or not because if value = [''], !value always is true on Rhino
4080 * @modifiedBy: dhm@automic.com
4081 */
4082 if (!value && Object.prototype.toString.apply(value) !== '[object Array]') {
4083 return 'null';
4084 }
4085
4086 // Make an array to hold the partial results of stringifying this object value.
4087
4088 gap += indent;
4089 partial = [];
4090
4091 // Is the value an array?
4092
4093 if (Object.prototype.toString.apply(value) === '[object Array]') {
4094
4095 // The value is an array. Stringify every element. Use null as a placeholder
4096 // for non-JSON values.
4097
4098 length = value.length;
4099 for (i = 0; i < length; i += 1) {
4100 partial[i] = str(i, value) || 'null';
4101 }
4102
4103 // Join all of the elements together, separated with commas, and wrap them in
4104 // brackets.
4105
4106 v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
4107 gap = mind;
4108 return v;
4109 }
4110
4111 // If the replacer is an array, use it to select the members to be stringified.
4112
4113 if (rep && typeof rep === 'object') {
4114 length = rep.length;
4115 for (i = 0; i < length; i += 1) {
4116 if (typeof rep[i] === 'string') {
4117 k = rep[i];
4118 v = str(k, value);
4119 if (v) {
4120 partial.push(quote(k) + (gap ? ': ' : ':') + v);
4121 }
4122 }
4123 }
4124 } else {
4125
4126 // Otherwise, iterate through all of the keys in the object.
4127
4128 for (k in value) {
4129 if (Object.prototype.hasOwnProperty.call(value, k)) {
4130 v = str(k, value);
4131 if (v) {
4132 partial.push(quote(k) + (gap ? ': ' : ':') + v);
4133 }
4134 }
4135 }
4136 }
4137
4138 // Join all of the member texts together, separated with commas,
4139 // and wrap them in braces.
4140
4141 v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
4142 gap = mind;
4143 return v;
4144 }
4145 }
4146
4147 // If the JSON object does not yet have a stringify method, give it one.
4148
4149 if (typeof JSON.stringify !== 'function') {
4150 JSON.stringify = function(value, replacer, space) {
4151
4152 // The stringify method takes a value and an optional replacer, and an optional
4153 // space parameter, and returns a JSON text. The replacer can be a function
4154 // that can replace values, or an array of strings that will select the keys.
4155 // A default replacer method can be provided. Use of the space parameter can
4156 // produce text that is more easily readable.
4157
4158 var i;
4159 gap = '';
4160 indent = '';
4161
4162 // If the space parameter is a number, make an indent string containing that
4163 // many spaces.
4164
4165 if (typeof space === 'number') {
4166 for (i = 0; i < space; i += 1) {
4167 indent += ' ';
4168 }
4169
4170 // If the space parameter is a string, it will be used as the indent string.
4171
4172 } else if (typeof space === 'string') {
4173 indent = space;
4174 }
4175
4176 // If there is a replacer, it must be a function or an array.
4177 // Otherwise, throw an error.
4178
4179 rep = replacer;
4180 if (replacer && typeof replacer !== 'function' &&
4181 (typeof replacer !== 'object' ||
4182 typeof replacer.length !== 'number')) {
4183 throw new Error('JSON.stringify');
4184 }
4185
4186 // Make a fake root object containing our value under the key of ''.
4187 // Return the result of stringifying the value.
4188
4189 return str('', {
4190 '': value
4191 });
4192 };
4193 }
4194
4195 // Because with SCOPED_APP, we can't use 'eval' function as the original so we decided to use 'decode' function of
4196 // ServiceNow's JSON class for our 'SaraJSON.parse'
4197 if (typeof JSON.parse !== 'function') {
4198 JSON.parse = function(text, reviver) {
4199 return new global.JSON().decode(text, reviver);
4200 };
4201 }
4202
4203})(SaraJSON);
4204]]></script>
4205 <description>Sara JSON Utilities</description>
4206 <active>true</active>
4207 <client_callable>false</client_callable>
4208 <access>public</access>
4209 </script_include>
4210
4211 <script_include>
4212 <name>SaraLog</name>
4213 <script><![CDATA[/**
4214 * Log Utilities for Sara
4215 */
4216var SaraLog = Class.create();
4217SaraLog.prototype = {
4218 /**
4219 * Init logger
4220 * @param {Object|String} className The class name of object. Will be append after timestamp.
4221 * If is not String, will get the className from 'type' property of object
4222 */
4223 initialize: function (className) {
4224 this.className = typeof className === 'string' ? className : className.type;
4225 },
4226
4227 _log: function (message) {
4228 return SaraUtils.formatString('[{0}] [{1}] {2}', SaraUtils.getTimeStamp(), this.className, message.toString());
4229 },
4230
4231 info: function () {
4232 var message = SaraUtils.formatString.apply(this, arguments);
4233 message = this._log(message);
4234
4235 gs.info(message);
4236 },
4237
4238 debug: function () {
4239 var message = SaraUtils.formatString.apply(this, arguments);
4240 message = this._log(message);
4241
4242 gs.debug(message);
4243 },
4244
4245 error: function () {
4246 var message = SaraUtils.formatString.apply(this, arguments);
4247 message = this._log(message);
4248
4249 gs.error(message);
4250 },
4251
4252 warn: function () {
4253 var message = SaraUtils.formatString.apply(this, arguments);
4254 message = this._log(message);
4255
4256 gs.warn(message);
4257 },
4258
4259 type: 'SaraLog'
4260
4261};
4262]]></script>
4263 <description>Log Utilities for Sara</description>
4264 <active>true</active>
4265 <client_callable>false</client_callable>
4266 <access>public</access>
4267 </script_include>
4268
4269 <script_include>
4270 <name>SaraModel</name>
4271 <script><![CDATA[/**
4272 * SARA concepts modelling in Service Now
4273 */
4274var SaraModel = {}
4275
4276/**
4277 * CatalogItem object represents a SN service catalog item
4278 * @constructor
4279 */
4280SaraModel.CatalogItem = Class.create();
4281SaraModel.CatalogItem.prototype = {
4282 initialize: function () {},
4283
4284 setName: function (name) {
4285 this.name = name;
4286 },
4287
4288 getName: function () {
4289 return this.name;
4290 },
4291
4292 setCategory: function (category) {
4293 this.category = category;
4294 },
4295
4296 getCategory: function () {
4297 return this.category;
4298 },
4299
4300 unsetCategory: function () {
4301 delete this.category;
4302 },
4303
4304 setActive: function (active) {
4305 this.active = active;
4306 },
4307
4308 isActive: function () {
4309 return this.active;
4310 },
4311
4312 setWorkflow: function (workflow) {
4313 this.workflow = workflow;
4314 },
4315
4316 getWorkflow: function () {
4317 return this.workflow;
4318 },
4319
4320 setShortDesc: function (shortDesc) {
4321 this.shortDesc = shortDesc;
4322 },
4323
4324 getShortDesc: function (shortDesc) {
4325 return this.shortDesc;
4326 },
4327
4328 setDescription: function (description) {
4329 this.description = description;
4330 },
4331
4332 getDescription: function () {
4333 return this.description;
4334 },
4335
4336 setVariables: function (variables) {
4337 this.variables = variables;
4338 },
4339
4340 getVariables: function (variables) {
4341 return this.variables;
4342 },
4343
4344 setConsumeUrl: function (consumeUrl) {
4345 this.consumeUrl = consumeUrl;
4346 },
4347
4348 getConsumeUrl: function () {
4349 return this.consumeUrl;
4350 },
4351
4352 setServiceName: function (serviceName) {
4353 this.serviceName = serviceName;
4354 },
4355
4356 getServiceName: function () {
4357 return this.serviceName;
4358 },
4359
4360 setCustomCart: function (customCart) {
4361 this.customCart = customCart;
4362 },
4363
4364 getCustomCart: function () {
4365 return this.customCart;
4366 },
4367
4368 setSNCatalog: function(catalog) {
4369 this.sc_catalog = catalog;
4370 },
4371
4372 getSNCatalog: function() {
4373 return this.sc_catalog;
4374 },
4375
4376 setHash: function (hash) {
4377 this.hash = hash;
4378 },
4379
4380 getHash: function () {
4381 return this.hash;
4382 },
4383
4384 type: 'SaraModel.CatalogItem'
4385};
4386
4387/**
4388 * CatalogVariable object represents a SN service virable
4389 * @constructor
4390 */
4391SaraModel.CatalogVariable = Class.create();
4392SaraModel.CatalogVariable.prototype = {
4393 initialize: function () {},
4394
4395 setName: function (name) {
4396 this.name = name;
4397 },
4398
4399 getName: function () {
4400 return this.name;
4401 },
4402
4403 setType: function (type) {
4404 this.type = type;
4405 },
4406
4407 getType: function () {
4408 return this.type;
4409 },
4410
4411 setLabel: function (label) {
4412 this.label = label;
4413 },
4414
4415 getLabel: function () {
4416 return this.label;
4417 },
4418
4419 setDefaultValue: function (defaultValue) {
4420 this.defaultValue = defaultValue;
4421 },
4422
4423 getDefaultValue: function () {
4424 return this.defaultValue;
4425 },
4426
4427 setDescription: function (description) {
4428 this.description = description;
4429 },
4430
4431 getDescription: function () {
4432 return this.description;
4433 },
4434
4435 setRange: function (range) {
4436 this.range = range;
4437 },
4438
4439 getRange: function () {
4440 return this.range;
4441 },
4442
4443 setActualName: function (actualName) {
4444 this.actualName = actualName;
4445 },
4446
4447 getActualName: function () {
4448 return this.actualName;
4449 },
4450
4451 setAsPassword: function (asPassword) {
4452 this.asPassword = asPassword;
4453 },
4454
4455 isPassword: function (isPassword) {
4456 return this.asPassword;
4457 },
4458
4459 setRequired: function (required) {
4460 this.required = required;
4461 },
4462
4463 isRequired: function (required) {
4464 return this.required;
4465 },
4466
4467 setMultiSelect: function (multiSelect) {
4468 this.multiSelect = multiSelect;
4469 },
4470
4471 isMultiSelect: function (multiSelect) {
4472 return this.multiSelect;
4473 },
4474
4475 setAsLookup: function (asLookup) {
4476 this.asLookup = asLookup;
4477 },
4478
4479 isLookup: function () {
4480 return this.asLookup;
4481 },
4482
4483 setHash: function (hash) {
4484 this.hash = hash;
4485 },
4486
4487 getHash: function () {
4488 return this.hash;
4489 },
4490
4491 setOrder: function (order) {
4492 this.order = order;
4493 },
4494
4495 getOrder: function () {
4496 if(this.order)
4497 return this.order;
4498 return 0;
4499 },
4500
4501 type: 'SaraModel.CatalogVariable'
4502};
4503
4504/**
4505 * CatalogCategory object represents a SN service catalog category
4506 * @constructor
4507 */
4508SaraModel.CatalogCategory = Class.create();
4509SaraModel.CatalogCategory.prototype = {
4510 initialize: function () {},
4511
4512 setTitle: function (title) {
4513 this.title = title;
4514 },
4515
4516 getTitle: function () {
4517 return this.title;
4518 },
4519
4520 setName: function (name) {
4521 this.name = name;
4522 },
4523
4524 getName: function () {
4525 return this.name;
4526 },
4527
4528 setParent: function (parent) {
4529 this.parent = parent;
4530 },
4531
4532 getParent: function () {
4533 return this.parent;
4534 },
4535
4536 unsetParent: function () {
4537 delete this.parent;
4538 },
4539
4540 setActive: function (active) {
4541 this.active = active;
4542 },
4543
4544 isActive: function () {
4545 return this.active;
4546 },
4547
4548 setDescription: function (description) {
4549 this.description = description;
4550 },
4551
4552 getDescription: function () {
4553 return this.description;
4554 },
4555
4556 setConsumeUrl: function (consumeUrl) {
4557 this.consumeUrl = consumeUrl;
4558 },
4559
4560 getConsumeUrl: function () {
4561 return this.consumeUrl;
4562 },
4563
4564 setAsNew: function (asNew) {
4565 this.asNew = asNew;
4566 },
4567
4568 isNew: function () {
4569 return this.asNew;
4570 },
4571
4572 unsetAsNew: function () {
4573 delete this.asNew;
4574 },
4575
4576 setSysId: function (sysId) {
4577 this.sysId = sysId;
4578 },
4579
4580 getSysId: function () {
4581 return this.sysId;
4582 },
4583
4584 unsetSysId: function () {
4585 delete this.sysId;
4586 },
4587
4588 setSNCatalog: function(catalog) {
4589 this.sc_catalog = catalog;
4590 },
4591
4592 getSNCatalog: function() {
4593 return this.sc_catalog;
4594 },
4595
4596 type: 'SaraModel.CatalogCategory'
4597};
4598]]></script>
4599 <description>SARA concepts modelling in Service Now</description>
4600 <active>true</active>
4601 <client_callable>false</client_callable>
4602 <access>package_private</access>
4603 </script_include>
4604
4605 <script_include>
4606 <name>SaraOAuthAjax</name>
4607 <script><![CDATA[/**
4608 * AJAX facade for SaraOAuthClient
4609 */
4610var SaraOAuthAjax = Class.create();
4611SaraOAuthAjax.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
4612 /**
4613 * Get OAuth URL with redirection endpoint and client id in query string
4614 * @return {String}
4615 */
4616 getOAuthUrl: function () {
4617 var LOGGER = new SaraLog(this);
4618
4619 try {
4620 var clientId = this.getParameter('sysparm_client_id').toString();
4621 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4622 var authEndpoint = this.getParameter('sysparm_auth_endpoint').toString();
4623 var redirectionEndpoint = SaraUtils.getRedirectionUrl();
4624
4625 LOGGER.info('auth_endpoint={0}; redirect_uri={1}; client_id={2}; technical_user={3}', authEndpoint, redirectionEndpoint, clientId, technicalUser);
4626
4627 return authEndpoint
4628 + '?redirect_uri=' + escape(redirectionEndpoint)
4629 + '&client_id=' + escape(clientId)
4630 + '&user_info=' + escape(technicalUser)
4631 + '&user_info_editable=false'
4632 + '&response_type=code';
4633 } catch (e) {
4634 this.logError(e);
4635 }
4636
4637 return;
4638 },
4639
4640 /**
4641 * Request token by using Username and password
4642 * @return {String}
4643 */
4644 requestToken: function () {
4645 var LOGGER = new SaraLog(this);
4646
4647 try {
4648 var username = this.getParameter('sysparm_username').toString();
4649 var password = this.getParameter('sysparm_password').toString();
4650 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4651
4652 var oauthClient = new SaraOAuthClient();
4653 var tokens = oauthClient.requestToken(username, password);
4654
4655 LOGGER.info('Token: {0}', SaraJSON.stringify(tokens));
4656
4657 if (tokens && !tokens.error && tokens['access_token']) {
4658 oauthClient.storeUserTokens(technicalUser, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
4659 return 'ok';
4660 } else {
4661 return tokens.error ? tokens.error : (!tokens['access_token'] ? 'Empty result' : '');
4662 }
4663 } catch (e) {
4664 this.logError(e);
4665 }
4666
4667 return;
4668 },
4669
4670 /**
4671 * Request token by authorization code
4672 * @return {String}
4673 */
4674 requestTokenByCode: function () {
4675 var LOGGER = new SaraLog(this);
4676
4677 try {
4678 var code = this.getParameter('sysparm_code').toString();
4679 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4680 LOGGER.info('Request token for user "{0}" by using code {1}', technicalUser, code);
4681
4682
4683 var config = {};
4684 config[SaraCommon.CONFIG_NAME.CLIENT_ID] = this.getParameter('sysparm_client_id').toString();
4685 config[SaraCommon.CONFIG_NAME.CLIENT_SECERT] = this.getParameter('sysparm_client_secret').toString();
4686 config[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT] = this.getParameter('sysparm_token_endpoint').toString();
4687
4688 var oauthClient = new SaraOAuthClient();
4689 var tokens = oauthClient.requestTokenByCode(code, config);
4690
4691 LOGGER.info('Token info: {0}', SaraJSON.stringify(tokens));
4692
4693 if (tokens && !tokens.error && tokens['access_token']) {
4694 oauthClient.storeUserTokens(technicalUser, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
4695
4696 return 'ok';
4697 } else {
4698 return tokens.error ? tokens.error : (!tokens['access_token'] ? 'Empty result' : '');
4699 }
4700 } catch (e) {
4701 this.logError(e);
4702 }
4703
4704 return;
4705 },
4706
4707 /**
4708 * Get client configuration
4709 */
4710 getConfig: function () {
4711 var LOGGER = new SaraLog(this);
4712
4713 try {
4714 var configData = new SaraConfig().getClientConfig();
4715
4716 LOGGER.info('OAuth Configuration: \n'
4717 + ' - Client ID = {0} \n'
4718 + ' - Client Secret = *** \n'
4719 + ' - Technical User = {1} \n'
4720 + ' - SAPI Endpoint = {2} \n'
4721 + ' - Token Endpoint = {3} \n'
4722 + ' - Auth Endpoint = {4} \n',
4723 configData[SaraCommon.CONFIG_NAME.CLIENT_ID],
4724 configData[SaraCommon.CONFIG_NAME.TECHNICAL_USER],
4725 configData[SaraCommon.CONFIG_NAME.SAPI_ENDPOINT],
4726 configData[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT],
4727 configData[SaraCommon.CONFIG_NAME.AUTH_ENDPOINT]
4728 );
4729
4730 var config = this.newItem('config');
4731 for (var key in SaraCommon.CONFIG_NAME) {
4732 var name = SaraCommon.CONFIG_NAME[key];
4733
4734 config.setAttribute(name, configData[name]);
4735 }
4736 } catch (e) {
4737 this.logError(e);
4738 }
4739
4740 return;
4741 },
4742
4743 /**
4744 * Validate access token key
4745 */
4746 validateToken: function () {
4747 var LOGGER = new SaraLog(this);
4748
4749 try {
4750 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4751 var glideHelper = new SaraGlideHelper();
4752 var saraOAuth = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_OAUTH, {
4753 'u_user': technicalUser
4754 });
4755
4756 if (saraOAuth) {
4757 var token = saraOAuth['u_access_token'].toString();
4758 var sapiEndpoint = this.getParameter('sysparm_sapi_endpoint').toString();
4759 var oauthClient = new SaraOAuthClient();
4760 var result = oauthClient.validateToken(token, sapiEndpoint);
4761
4762 LOGGER.debug('Result of validating token: {0}', result.toString());
4763
4764 if (typeof result === 'boolean') {
4765 this.addItem('result', {
4766 isValid: result
4767 });
4768 } else {
4769 this.addItem('result', {
4770 message: result
4771 });
4772 }
4773 } else {
4774 LOGGER.info('Technical User "{1}" does not have tokens', technicalUser);
4775
4776 this.addItem('result', {
4777 isValid: false
4778 });
4779 }
4780
4781 } catch (e) {
4782 this.logError(e);
4783 }
4784
4785 return;
4786 },
4787
4788 /**
4789 * Log error
4790 * @param {Error} error
4791 * @param {SaraLog} LOGGER
4792 */
4793 logError: function (error, LOGGER) {
4794 LOGGER.error('{0}', error);
4795
4796 this.addItem('error', {
4797 message: error
4798 });
4799 },
4800
4801 /**
4802 * Add item in response
4803 * @param {String} itemName The name of item
4804 * @param {Object<String, String>} attributes The object contains item's attributes
4805 */
4806 addItem: function (itemName, attributes) {
4807 var item = this.newItem(itemName);
4808
4809 for (var name in attributes) {
4810 var value = attributes[name];
4811
4812 item.setAttribute(name, value);
4813 }
4814 },
4815
4816 type: 'SaraOAuthAjax'
4817});
4818]]></script>
4819 <description>AJAX facade for SaraOAuthClient</description>
4820 <active>true</active>
4821 <client_callable>true</client_callable>
4822 <access>package_private</access>
4823 </script_include>
4824
4825 <script_include>
4826 <name>SaraOAuthClient</name>
4827 <script><![CDATA[/**
4828 * This class contains all OAuth-relaled functions
4829 */
4830var SaraOAuthClient = Class.create();
4831SaraOAuthClient.prototype = {
4832 /**
4833 * Init new OAuth Client from SaraRESTClient object
4834 * @param {SaraRestCLient} restClient
4835 */
4836 initialize: function (restClient) {
4837 this.glideHelper = new SaraGlideHelper();
4838 this.saraConfig = new SaraConfig();
4839 this.LOGGER = new SaraLog(this);
4840
4841 if (!restClient) {
4842 this.restClient = new SaraRESTClient();
4843 this.restClient.setMIDServer(SaraUtils.getMIDServer());
4844 } else {
4845 this.restClient = restClient;
4846 }
4847 },
4848
4849 /**
4850 * Store user tokens into 'SaraCommon.TABLE_NAME.SARA_OAUTH' table
4851 * @param {String} username The username which owns tokens
4852 * @param {String} accessToken The access token of user
4853 * @param {String} refreshToken The refresh token of user
4854 * @param {String} tokenExpiry The expiry of token
4855 * @param {String} tokenType The type of token
4856 * @return {String} The sys_id of user tokens record
4857 */
4858 storeUserTokens: function (username, accessToken, refreshToken, tokenExpiry, tokenType) {
4859 var LOGGER = this.LOGGER;
4860
4861 if (!username) {
4862 LOGGER.info('Store user token: Username must not be empty!');
4863 return;
4864 }
4865
4866 if (!accessToken) {
4867 LOGGER.info('Error: Access token must be non-empty!');
4868 return;
4869 }
4870
4871 LOGGER.info('Preparing for storing user tokens...');
4872
4873 // Request tokens of user in 'SaraCommon.TABLE_NAME.SARA_OAUTH' table
4874 var saraOAuth = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4875 'u_user': username
4876 });
4877
4878 // If user's tokens are existed
4879 if (saraOAuth) {
4880 LOGGER.info('User\'s tokens are existed. Updating tokens...');
4881
4882 this.glideHelper.updateData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4883 'sys_id': saraOAuth['sys_id']
4884 }, {
4885 'u_access_token': accessToken,
4886 'u_refresh_token': refreshToken,
4887 'u_token_expiry': tokenExpiry,
4888 'u_token_type': tokenType
4889 });
4890
4891 return saraOAuth['sys_id'];
4892 } else {
4893 LOGGER.info('Storing user\'s tokens...');
4894
4895 return this.glideHelper.persistData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4896 'u_user': username,
4897 'u_access_token': accessToken,
4898 'u_refresh_token': refreshToken,
4899 'u_token_expiry': tokenExpiry,
4900 'u_token_type': tokenType
4901 });
4902 }
4903 },
4904
4905 /**
4906 * Get user tokens by username. The result will be [accessToken, refreshToken, tokenExpiry, tokenType, { createdAt, createdBy, updateAt, updateBy }]
4907 * @param {String} username
4908 * @return {Array<String|Object>}
4909 */
4910 getUserTokens: function (username) {
4911 var LOGGER = this.LOGGER;
4912
4913 if (!username) {
4914 return null;
4915 }
4916
4917 var saraOAuth = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4918 'u_user': username
4919 });
4920
4921 if (saraOAuth) {
4922 return [
4923 saraOAuth['u_access_token'],
4924 saraOAuth['u_refresh_token'],
4925 saraOAuth['u_token_expiry'],
4926 saraOAuth['u_token_type'], {
4927 'createdAt': saraOAuth['sys_created_on'],
4928 'createdBy': saraOAuth['sys_created_by'],
4929 'updatedAt': saraOAuth['sys_updated_on'],
4930 'updatedBy': saraOAuth['sys_updated_by']
4931 }
4932 ];
4933 } else {
4934 LOGGER.info('Tokens of "{0}" do not exist!', username);
4935 return null;
4936 }
4937 },
4938
4939 /**
4940 * Remove user tokens by username
4941 * @param {String} username
4942 * @return {String} The sys_id of deleted record
4943 */
4944 removeUserToken: function (username) {
4945 var LOGGER = this.LOGGER;
4946
4947 if (!username) {
4948 return null;
4949 }
4950
4951 var saraOAuth = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4952 'u_user': username
4953 });
4954
4955 if (saraOAuth) {
4956 saraOAuth = this.glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4957 'sys_id': saraOAuth['sys_id']
4958 });
4959
4960 return saraOAuth['sys_id'];
4961 } else {
4962 LOGGER.info('No token found for user "{0}"', username);
4963 return null;
4964 }
4965 },
4966
4967 /**
4968 * Requests user tokens, the request must use client_id/client_secret to authenticate (BASICally) against SARA server,
4969 * LDAP username/password and grant_type will be embedded in request's body
4970 * @param {String} username
4971 * @param {String} password
4972 * @return {Object} Object contains access token, refresh token, token expiry and token type
4973 */
4974 requestToken: function (username, password) {
4975 var LOGGER = this.LOGGER;
4976
4977 LOGGER.debug('Preparing for requesting tokens for SARA user {0}...', username);
4978
4979 var clientInfo = this.saraConfig.getClientConfig();
4980 var clientId = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_ID];
4981 var clientSecret = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_SECERT];
4982 var tokenEndpoint = clientInfo[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
4983
4984 var request = this.restClient.newOAuthRequest('post', tokenEndpoint);
4985 request.setBasicAuth(clientId, clientSecret);
4986
4987 // Add POST body, set Content-Type header
4988 request.setContentType('application/x-www-form-urlencoded');
4989 var formEntity = {
4990 'grant_type': 'password',
4991 'username': username,
4992 'password': password
4993 };
4994 request.setFormContent(formEntity);
4995
4996 LOGGER.info('Requesting tokens for SARA user {0}...', username);
4997 var response = this.restClient.execute(request);
4998 var responseObject = response.getResponseObject();
4999
5000 if (response.haveError()) {
5001 LOGGER.info('Failed to request token for user {0}', username);
5002
5003 return {
5004 'error': responseObject.errorMessage,
5005 'error_description': responseObject.errorDescription
5006 }
5007 }
5008
5009 LOGGER.info('Successfully obtain token for user {0}', username);
5010 return responseObject.bodyObject;
5011 },
5012
5013 /**
5014 * Requests user tokens, the request must use client_id/client_secret to authenticate (BASICally) against SARA server,
5015 * LDAP redirect_uri/authorization_code and grant_type will be embedded in request's body
5016 * @param {String} code The authorization code which get from OAuth after logged-in successfully in Auth Endpoint
5017 * @param {Object} config The config of OAuth Server
5018 * @return {Object} Object contains access token, refresh token, token expiry and token type
5019 */
5020 requestTokenByCode: function (code, config) {
5021 var LOGGER = this.LOGGER;
5022
5023 LOGGER.debug('Preparing for requesting tokens by code "{0}"...', code);
5024
5025 var clientId = config[SaraCommon.CONFIG_NAME.CLIENT_ID];
5026 var clientSecret = config[SaraCommon.CONFIG_NAME.CLIENT_SECERT];
5027 var tokenEndpoint = config[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
5028 var redirectionEndpoint = SaraUtils.getRedirectionUrl();
5029
5030 var request = this.restClient.newOAuthRequest('post', tokenEndpoint);
5031 request.setBasicAuth(clientId, clientSecret);
5032
5033 // Add POST body, set Content-Type header
5034 request.setContentType('application/x-www-form-urlencoded');
5035 var formEntity = {
5036 'grant_type': 'authorization_code',
5037 'redirect_uri': redirectionEndpoint,
5038 'code': code
5039 };
5040 request.setFormContent(formEntity);
5041
5042 LOGGER.info('Requesting tokens by code...');
5043 var response = this.restClient.execute(request);
5044 var responseObject = response.getResponseObject();
5045
5046 if (response.haveError()) {
5047 LOGGER.info('Failed to request token by code');
5048
5049 return {
5050 'error': responseObject.errorMessage,
5051 'error_description': responseObject.errorDescription
5052 }
5053 }
5054
5055 LOGGER.info('Successfully obtain token for user by code "{0}"', code);
5056 return responseObject.bodyObject;
5057 },
5058
5059 /**
5060 * Refresh user tokens
5061 * @param {String} username
5062 * @return {Object}
5063 */
5064 refreshToken: function (username) {
5065 var LOGGER = this.LOGGER;
5066
5067 // Get refresh tokens for this user from 'SaraCommon.TABLE_NAME.SARA_OAUTH' table
5068 var tokens = this.getUserTokens(username);
5069 if (!tokens || tokens.length < 1) {
5070 LOGGER.info('Tokens not found for user {0}', username);
5071 return null;
5072 }
5073
5074 LOGGER.info('Preparing for refreshing tokens for user {0}...', username);
5075
5076 // Use that refesh token to retrieve new tokens
5077 var clientInfo = this.saraConfig.getClientConfig();
5078 var clientId = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_ID];
5079 var clientSecret = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_SECRET];
5080 var tokenEndpoint = clientInfo[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
5081 var request = this.restClient.newOAuthRequest('post', tokenEndpoint);
5082 request.setBasicAuth(clientId, clientSecret);
5083
5084 // Add POST body, set Content-Type header
5085 request.setContentType('application/x-www-form-urlencoded');
5086 request.setFormContent({
5087 'grant_type': 'refresh_token',
5088 'refresh_token': tokens[1]
5089 });
5090
5091 LOGGER.info('Refreshing tokens for user {0}...', username);
5092 var response = this.restClient.execute(request);
5093 var responseObject = response.getResponseObject();
5094
5095 if (response.haveError()) {
5096 LOGGER.info('Failed to refresh token for code');
5097
5098 return {
5099 'error': responseObject.errorMessage,
5100 'error_description': responseObject.errorDescription
5101 }
5102 }
5103
5104 LOGGER.info('Successfully refresh token for user {0}', username);
5105 return responseObject.bodyObject;
5106 },
5107
5108 /**
5109 * Validate access token key of user is invalid or expired
5110 * @param {String} token The access token key of user
5111 * @param {String} sapiEndpoint The SAPI endpoint
5112 * @return {Boolean|String}
5113 */
5114 validateToken: function (token, sapiEndpoint) {
5115 var LOGGER = this.LOGGER;
5116
5117 LOGGER.info('Preparing for validating token "{0}"...', token.toString());
5118
5119 var configData = this.saraConfig.getClientConfig();
5120 var response = this.executeGetRequest(token, sapiEndpoint);
5121 var responseObject = response.getResponseObject();
5122
5123 if (response.haveError()) {
5124 if (responseObject.statusCode !== 401) {
5125 var message = SaraUtils.formatString('Error when validating token! Error code: {0} - Error message: {1}', responseObject.statusCode, responseObject.errorMessage);
5126 LOGGER.error(message);
5127 return message;
5128 } else {
5129 var username = this.saraConfig.getTechnicalUser();
5130 this.removeUserToken(username);
5131 return false;
5132 }
5133 } else {
5134 LOGGER.info('Preparing for validating services endpoint ...');
5135 response = this.executeGetRequest(token, SaraUtils.buildUrl('services', sapiEndpoint));
5136 responseObject = response.getResponseObject();
5137 LOGGER.debug('Response of validating services endpoint {0} ...', JSON.stringify(responseObject));
5138 if(responseObject.statusCode === 200) {
5139 return true;
5140 }
5141 LOGGER.error(responseObject.errorMessage);
5142 return SaraUtils.formatString('Error validating SAPI get services endpoint. Please check AE Password Exit configuration and make sure SAPI is accessible from ServiceNow!! Error code: {0} - Error message: {1}', responseObject.statusCode, responseObject.errorMessage);
5143 }
5144 },
5145
5146 /**
5147 * Execute get request
5148 * @param {String} token The access token key of user
5149 * @param {String} sapiEndpoint The SAPI endpoint
5150 * @return {SaraRESTResponse}
5151 */
5152 executeGetRequest: function (token, sapiEndpoint) {
5153 var request = this.restClient.newSAPIRequest('get', sapiEndpoint);
5154 request.addHeader('Authorization', 'bearer ' + token);
5155 return this.restClient.executeWithRefreshToken(request);
5156 },
5157
5158 type: 'SaraOAuthClient'
5159};
5160]]></script>
5161 <description>This class contains all OAuth-relaled functions</description>
5162 <active>true</active>
5163 <client_callable>false</client_callable>
5164 <access>public</access>
5165 </script_include>
5166
5167 <script_include>
5168 <name>SaraRESTClient</name>
5169 <script><![CDATA[/**
5170 * Wraps Service Now RESTMessage in a class to provide convenient methods interacting with SARA REST
5171 */
5172var SaraRESTClient = Class.create();
5173SaraRESTClient.prototype = {
5174 initialize: function () {
5175 this.LOGGER = new SaraLog(this);
5176 },
5177
5178 /**
5179 * Init new service request from SaraRESTMessage class
5180 * @param {String} name The name of the REST message record
5181 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5182 * @param {String} endpoint The endpoint for the REST message
5183 * @param {Array<String>} basicAuthCreds The basic authentication headers for the REST message
5184 * @param {Array<Object>} headers The object contains headers for the REST message
5185 * @param {Array<Object>} stringParameters The object contains string parameters for the REST message
5186 * @param {Array<Object>} stringParametersNoEscape The object contains string parameters which will be not escaped for the REST message
5187 * @return {SaraRESTMessage}
5188 */
5189 newServiceRequest: function (name, method, endpoint, basicAuthCreds, headers, stringParameters, stringParametersNoEscape) {
5190 var restMsg = new SaraRESTMessage(name, method);
5191
5192 if (endpoint) {
5193 restMsg.setEndpoint(endpoint);
5194 }
5195
5196 if (this.midServer) {
5197 restMsg.setMIDServer(this.midServer);
5198 }
5199
5200 if (basicAuthCreds && basicAuthCreds.length > 1) {
5201 restMsg.setBasicAuth(basicAuthCreds[0], basicAuthCreds[1]);
5202 }
5203
5204 if (headers) {
5205 for (var i = 0, header; header = headers[i]; i++) {
5206 if (header['name']) {
5207 restMsg.addHeader(header['name'], header['value']);
5208 }
5209 }
5210 }
5211
5212 if (stringParameters) {
5213 for (var i = 0, stringParameter; stringParameter = stringParameters[i]; i++) {
5214 if (stringParameter['name']) {
5215 restMsg.setStringParameter(stringParameter['name'], stringParameter['value']);
5216 }
5217 }
5218 }
5219
5220 if (stringParametersNoEscape) {
5221 for (var i = 0, stringParameter; stringParameter = stringParametersNoEscape[i]; i++) {
5222 if (stringParameter['name']) {
5223 restMsg.setStringParameterNoEscape(stringParameter['name'], stringParameter['value']);
5224 }
5225 }
5226 }
5227
5228 return restMsg;
5229 },
5230
5231 /**
5232 * Init new SAPI service request from SaraRESTMessage class
5233 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5234 * @param {String} endpoint The endpoint for the REST message
5235 * @param {Array<String>} basicAuthCreds The basic authentication headers for the REST message
5236 * @param {Array<Object>} headers The object contains headers for the REST message
5237 * @param {Array<Object>} stringParameters The object contains string parameters for the REST message
5238 * @param {Array<Object>} stringParametersNoEscape The object contains string parameters which will be not escaped for the REST message
5239 * @return {SaraRESTMessage}
5240 */
5241 newSAPIRequest: function (method, endpoint, basicAuthCreds, headers, stringParameters, stringParametersNoEscape) {
5242 return this.newServiceRequest(SaraCommon.REST_NAME.SAPI, method, endpoint, basicAuthCreds, headers)
5243 },
5244
5245 /**
5246 * Init new OAuth service request from SaraRESTMessage class
5247 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5248 * @param {String} endpoint The endpoint for the REST message
5249 * @param {Array<String>} basicAuthCreds The basic authentication headers for the REST message
5250 * @param {Array<Object>} headers The object contains headers for the REST message
5251 * @param {Array<Object>} stringParameters The object contains string parameters for the REST message
5252 * @param {Array<Object>} stringParametersNoEscape The object contains string parameters which will be not escaped for the REST message
5253 * @return {SaraRESTMessage}
5254 */
5255 newOAuthRequest: function (method, endpoint, basicAuthCreds, headers, stringParameters, stringParametersNoEscape) {
5256 return this.newServiceRequest(SaraCommon.REST_NAME.OAUTH, method, endpoint, basicAuthCreds, headers)
5257 },
5258
5259 /**
5260 * Execute REST Message request
5261 * @param {SaraRESTMessage} saraRest Sara REST Message object
5262 * @return {SaraRESTResponse}
5263 */
5264 execute: function (saraRest) {
5265 var LOGGER = this.LOGGER;
5266
5267 LOGGER.info('Making {0} request to {1}...', saraRest.getMethod(), saraRest.getEndpoint());
5268 LOGGER.debug(saraRest.dump());
5269
5270 var response;
5271 if (this.midServer) {
5272 response = saraRest.executeViaMIDServer(this.midServer);
5273 } else {
5274 response = saraRest.execute();
5275 }
5276
5277 return response;
5278 },
5279
5280 /**
5281 * Execute REST Message request with automatically get new token if token is expired
5282 * @param {SaraRESTMessage} saraRest Sara REST Message object
5283 * @return {SaraRESTResponse}
5284 */
5285 executeWithRefreshToken: function (saraRest) {
5286 var LOGGER = this.LOGGER;
5287
5288 // First time request
5289 var response = this.execute(saraRest);
5290 var responseObject = response.getResponseObject();
5291
5292 if (response.haveError()) {
5293 if (responseObject.statusCode === 401) {
5294 LOGGER.info('Access token of user is invalid or expired');
5295
5296 var oauthClient = new SaraOAuthClient(this);
5297 var username = new SaraConfig().getTechnicalUser();
5298
5299 LOGGER.info('Trying to refresh token for user "{0}"...', username);
5300 var tokens = oauthClient.refreshToken(username);
5301
5302 if (tokens && !tokens.error) {
5303 LOGGER.info('Refresh token finished successfully.');
5304 oauthClient.storeUserTokens(username, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
5305
5306 // Request again with new token
5307 saraRest.addHeader('Authorization', 'bearer ' + tokens['access_token']);
5308 response = this.execute(saraRest);
5309 } else {
5310 LOGGER.error('Error when refreshing token');
5311
5312 if (!tokens) {
5313 LOGGER.info('Error: {0} - Error description: {1}', tokens.error, tokens.errorDescription);
5314 oauthClient.removeUserToken(username);
5315 }
5316 }
5317 }
5318 }
5319
5320 return response;
5321 },
5322
5323 /**
5324 * Set MID Server
5325 * @param {String} midServer The MID Server name
5326 */
5327 setMIDServer: function (midServer) {
5328 this.midServer = midServer;
5329 },
5330
5331 type: 'SaraRESTClient'
5332};
5333]]></script>
5334 <description>Wraps Service Now RESTMessage in a class to provide convenient methods interacting with SARA REST</description>
5335 <active>true</active>
5336 <client_callable>false</client_callable>
5337 <access>public</access>
5338 </script_include>
5339
5340 <script_include>
5341 <name>SaraRESTMessage</name>
5342 <script><![CDATA[/**
5343 * Wrap original ServiceNow's RESTMessageV2 class to make HTTP request
5344 */
5345var SaraRESTMessage = Class.create();
5346SaraRESTMessage.prototype = {
5347 /**
5348 * Init Sara REST Message object
5349 * @param {String} name Name of REST message record
5350 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5351 */
5352 initialize: function (name, method) {
5353 method = method.toLowerCase();
5354 this.restMsg = new sn_ws.RESTMessageV2(name, method);
5355 this.restMsg.setEccParameter('skip_sensor', true);
5356 this.name = name;
5357 this.method = method;
5358
5359 this.LOGGER = new SaraLog(this);
5360 },
5361
5362 /**
5363 * Set the content of the REST message body
5364 * @param {String} content The content of REST Message
5365 */
5366 setContent: function (content) {
5367 this.restMsg.setRequestBody(content);
5368 },
5369
5370 /**
5371 * Set form content for REST Message
5372 * @param {Object} formData The object contains form data
5373 */
5374 setFormContent: function (formData) {
5375 if (!formData) {
5376 return;
5377 }
5378
5379 var content = '';
5380
5381 for (var propName in formData) {
5382 var value = formData[propName];
5383
5384 if (value instanceof Array) {
5385 for (var i = 0; i < value.length; i++) {
5386 var _value = value[i];
5387
5388 content += (encodeURIComponent(propName) + '=' + encodeURIComponent(_value) + '&');
5389 }
5390 } else {
5391 content += (encodeURIComponent(propName) + '=' + encodeURIComponent(value) + '&');
5392 }
5393 }
5394
5395 if (content.length > 0) {
5396 content = content.substring(0, content.length - 1);
5397 this.setContent(content);
5398 }
5399 },
5400
5401 /**
5402 * Get the content of the REST message body
5403 * @return {String}
5404 */
5405 getContent: function () {
5406 return this.restMsg.getRequestBody();
5407 },
5408
5409 /**
5410 * Add headers for REST Message
5411 * @param {String} key The key of header
5412 * @param {*} value The value of header
5413 */
5414 addHeader: function (key, value) {
5415 var LOGGER = this.LOGGER;
5416
5417 LOGGER.debug('addHeader: key = "{0}" and value = "{1}"', key, value);
5418
5419 this.restMsg.setRequestHeader(key, value);
5420 },
5421
5422 /**
5423 * Add type for header named 'content-type'
5424 * @param {String} type The content type of REST Message
5425 */
5426 setContentType: function (type) {
5427 var LOGGER = this.LOGGER;
5428
5429 LOGGER.debug('setContentType: type = "{0}"', type);
5430
5431 this.addHeader('content-type', type);
5432 },
5433
5434 /**
5435 * Set basic authentication headers for the REST message
5436 * @param {String} usename
5437 * @param {String} password
5438 */
5439 setBasicAuth: function (username, password) {
5440 var LOGGER = this.LOGGER;
5441
5442 LOGGER.debug('setBasicAuth: username = "{0}" and password = "{1}"', username, password);
5443
5444 this.restMsg.setBasicAuth(username, password);
5445 },
5446
5447 /**
5448 * Set a REST message function variable to the specified value
5449 * @param {String} name The name of parameter
5450 * @param {String} value The value of parameter
5451 */
5452 setStringParameter: function (name, value) {
5453 var LOGGER = this.LOGGER;
5454
5455 LOGGER.debug('setStringParameter: name = "{0}" and value = "{1}"', name, value);
5456
5457 this.restMsg.setStringParameter(name, value);
5458 },
5459
5460 /**
5461 * Set a REST message function variable to the specified value without escaping XML reserved characters
5462 * @param {String} name The name of parameter
5463 * @param {String} value The value of parameter
5464 */
5465 setStringParameterNoEscape: function (name, value) {
5466 var LOGGER = this.LOGGER;
5467
5468 LOGGER.debug('setStringParameterNoEscape: name = "{0}" and value = "{1}"', name, value);
5469
5470 this.restMsg.setStringParameterNoEscape(name, value);
5471 },
5472
5473 /**
5474 * Set the endpoint for the REST message
5475 * @param {String} endpoint
5476 */
5477 setEndpoint: function (endpoint) {
5478 var LOGGER = this.LOGGER;
5479
5480 LOGGER.debug('setEndpoint: endpoint = "{0}"', endpoint);
5481
5482 this.restMsg.setEndpoint(endpoint);
5483 },
5484
5485 /**
5486 * Get the URL of the endpoint for the REST message.
5487 * @return {String}
5488 */
5489 getEndpoint: function () {
5490 return this.restMsg.getEndpoint();
5491 },
5492
5493 /**
5494 * Configure the REST message to communicate through a MID Server.
5495 * @param {String} midServer The name of MID Server
5496 */
5497 setMIDServer: function (midServer) {
5498 var LOGGER = this.LOGGER;
5499
5500 LOGGER.debug('setMIDServer: midServer = "{0}"', midServer);
5501
5502 this.restMsg.setMIDServer(midServer);
5503 },
5504
5505 /**
5506 * Send REST Message to endpoint
5507 * @return {}
5508 */
5509 execute: function () {
5510 return new SaraRESTResponse(this.restMsg.execute());
5511 },
5512
5513 /**
5514 * Execute REST request via MID Server
5515 * @param {String} midServer The name of MID Server
5516 */
5517 executeViaMIDServer: function (midServer) {
5518 var LOGGER = this.LOGGER;
5519
5520 if (midServer) {
5521 this.restMsg.setMIDServer(midServer);
5522 this.midServer = midServer;
5523 LOGGER.info('Using MID Server {0}', this.midServer);
5524 }
5525
5526 if (!this.midServer) {
5527 LOGGER.info('No MID Server defined for the request. Request is aborted!');
5528 return null;
5529 }
5530
5531 return new SaraRESTResponse(this.restMsg.execute(), true);
5532 },
5533
5534 /**
5535 * Get method name of this REST Message
5536 * @return {String}
5537 */
5538 getMethod: function () {
5539 return this.method.toUpperCase();
5540 },
5541
5542 /**
5543 * Dump information of REST Message
5544 */
5545 dump: function () {
5546 var LOGGER = this.LOGGER;
5547
5548 try {
5549 var str = this.getMethod() + ' ' + this.getEndpoint() + ' HTTP/1.1';
5550
5551 var headers = this.restMsg.getRequestHeaders();
5552 if (headers) {
5553 for (key in headers) {
5554 var value = headers[key];
5555
5556 if (!gs.nil(value)) {
5557 if (key === 'Authorization') {
5558 value = '**********************';
5559 }
5560
5561 str += SaraUtils.formatString('\n {0}: {1}', key, value);
5562 }
5563 }
5564 }
5565
5566 var content = this.getContent();
5567
5568 if (!gs.nil(content) && content !== 'undefined' && content) {
5569 str += SaraUtils.formatString('\n\n', content);
5570 }
5571
5572 return str;
5573 } catch (error) {
5574 LOGGER.info('Error in SaraRESTMessage.dump(): ' + error);
5575 }
5576 },
5577
5578 type: 'SaraRESTMessage'
5579};
5580]]></script>
5581 <description>Class extend from original ServiceNow's RESTMessage class to make HTTP request</description>
5582 <active>true</active>
5583 <client_callable>false</client_callable>
5584 <access>package_private</access>
5585 </script_include>
5586
5587 <script_include>
5588 <name>SaraRESTResponse</name>
5589 <script><![CDATA[/**
5590 * Wrap original ServiceNow's RESTResponseV2 class to handle response of RESTMessageV2
5591 */
5592var SaraRESTResponse = Class.create();
5593SaraRESTResponse.prototype = {
5594 /**
5595 * Init Sara REST Response object
5596 * @param {sn_ws.RESTResponseV2} response The response object of RESTResponseV2
5597 * @param {Boolean} useMIDServer Get response via MID Server or not
5598 */
5599 initialize: function (response, useMIDServer) {
5600 this.response = response;
5601
5602 var LOGGER = this.LOGGER = new SaraLog(this);
5603
5604 if (useMIDServer) {
5605 var timeout = SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.REST_REQUEST_TIMEOUT);
5606 LOGGER.debug('Timeout for REST Message: {0}s', timeout);
5607 response.waitForResponse(timeout);
5608 }
5609
5610 if (response.haveError()) {
5611 LOGGER.info('Error when requesting REST Message: {0} - {1}', response.getErrorCode(), response.getErrorMessage());
5612 } else {
5613 LOGGER.info('Status code: {0}', response.getStatusCode());
5614 }
5615
5616 LOGGER.debug('Response body: {0}', response.getBody());
5617 },
5618
5619 /**
5620 * Set the amount of time the instance waits for the response
5621 * @param {Number} timeoutSecs The amount of time, in seconds, to wait for this response.
5622 */
5623 waitForResponse: function (timeoutSecs) {
5624 this.response.waitForResponse(timeoutSecs);
5625 },
5626
5627 /**
5628 * Get the numeric HTTP status code returned by the REST provider
5629 * @return {Number}
5630 */
5631 getStatusCode: function () {
5632 return this.response.getStatusCode();
5633 },
5634
5635 /**
5636 * Get the value for a specified header
5637 * @param {Number} timeoutSecs The name of the header that you want the value for, such as Set-Cookie.
5638 * @return {String}
5639 */
5640 getHeader: function (name) {
5641 return this.response.getHeader(name);
5642 },
5643
5644 /**
5645 * Get all headers returned in the REST response and the associated values
5646 * @return {Object}
5647 */
5648 getHeaders: function () {
5649 return this.response.getHeaders();
5650 },
5651
5652 /**
5653 * Get the content of the REST response body
5654 * @return {String}
5655 */
5656 getBody: function () {
5657 return this.response.getBody();
5658 },
5659
5660 /**
5661 * Indicate if there was an error during the REST transaction
5662 * @return {Boolean}
5663 */
5664 haveError: function () {
5665 return this.response.haveError();
5666 },
5667
5668 /**
5669 * Get the numeric error code if there was an error during the REST transaction. This error code is
5670 * specific to the ServiceNow platform, it is not an HTTP error code. Provide this error code if you
5671 * require assistance from ServiceNow Customer Support
5672 * @return {Number}
5673 */
5674 getErrorCode: function () {
5675 return this.response.getErrorCode();
5676 },
5677
5678 /**
5679 * Get the error message if there was an error during the REST transaction
5680 * @return {String}
5681 */
5682 getErrorMessage: function () {
5683 return this.response.getErrorMessage();
5684 },
5685
5686 /**
5687 * Get the fully-resolved query sent to the REST endpoint. This query contains the endpoint URL as well
5688 * as any values assigned to variables in the REST message
5689 */
5690 getQueryString: function () {
5691 return this, response.getQueryString();
5692 },
5693
5694 /**
5695 * Get response body with format is Object
5696 * @return {Object|Null}
5697 */
5698 getBodyObject: function () {
5699 var LOGGER = this.LOGGER;
5700
5701 var body = this.getBody();
5702 if (body) {
5703 try {
5704 body = SaraJSON.parse(body);
5705 } catch (ex) {
5706 LOGGER.error('Error when parsing response body to Object: {0}', ex);
5707 }
5708 }
5709
5710 return body;
5711 },
5712
5713 /**
5714 * Get response with format is Object. This response contains body object, status code, error message and
5715 * error description
5716 * @return {Object}
5717 */
5718 getResponseObject: function () {
5719 var bodyObject = this.getBodyObject();
5720 var statusCode = this.getStatusCode();
5721 var errorMessage = this.getErrorMessage();
5722 var errorDescription = this.getErrorMessage();
5723
5724 if (bodyObject) {
5725 if (bodyObject['error']) {
5726 errorMessage = bodyObject['error'];
5727 }
5728
5729 if (bodyObject['error_description']) {
5730 errorDescription = bodyObject['error_description'];
5731 }
5732 }
5733
5734 return {
5735 bodyObject: bodyObject,
5736 statusCode: statusCode,
5737 errorMessage: errorMessage,
5738 errorDescription: errorDescription
5739 }
5740 },
5741
5742 type: 'SaraRESTResponse'
5743};
5744]]></script>
5745 <description>Wrap original ServiceNow's RESTResponseV2 class to handle RESTMessageV2 response</description>
5746 <active>true</active>
5747 <client_callable>false</client_callable>
5748 <access>package_private</access>
5749 </script_include>
5750
5751 <script_include>
5752 <name>SaraSync</name>
5753 <script><![CDATA[/**
5754 * Sara Sync Utilities
5755 */
5756var SaraSync = Class.create();
5757SaraSync.prototype = {
5758 initialize: function () {
5759 this.glideHelper = new SaraGlideHelper();
5760 this.LOGGER = new SaraLog(this);
5761 this.dal = new SaraConsumerDAL();
5762 },
5763
5764 /**
5765 * Sync services and catalogs of all category which was imported services
5766 */
5767 syncServices: function () {
5768 var glideHelper = this.glideHelper;
5769 var LOGGER = this.LOGGER;
5770
5771 var importedCategories = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
5772 'u_type': 'category'
5773 }, true);
5774
5775 if (importedCategories.length > 0) {
5776 LOGGER.info('There are {0} target category(s) which were imported services\n', importedCategories.length);
5777
5778 var consumer = new SaraConsumerImportSet();
5779 var response = consumer.discover();
5780
5781 if (response.error) {
5782 LOGGER.error('Discover data from SAPI not successfully. Syncing services is aborted!');
5783 return;
5784 } else {
5785 for (var i = 0; i < importedCategories.length; i++) {
5786 var importedCategory = importedCategories[i];
5787 LOGGER.info('Syncing target category (name = {0}, sys_id = {1})', importedCategory.u_name, importedCategory.u_parent);
5788
5789 consumer.doImport(importedCategory.u_parent);
5790 consumer.refreshImportedData();
5791
5792 LOGGER.info('Target category (name = {0}, sys_id = {1}) is synced!', importedCategory.u_name, importedCategory.u_parent);
5793 }
5794 }
5795 } else {
5796 LOGGER.warn('No target category found. Skip syncServices!');
5797 }
5798 },
5799
5800 /**
5801 * Sync all lookup values of catalog item
5802 * @param {String} saraItem The catalog item in SaraCommon.TABLE_NAME.SARA_DEFINITION
5803 * @param {SaraModel.CatalogItem} catalogItem
5804 */
5805 //saraCatalogItem, catalogItem
5806 syncLookup: function (existDefinition, sapiService) {
5807 var glideHelper = this.glideHelper;
5808 var LOGGER = this.LOGGER;
5809
5810 LOGGER.info('Starting syncLookup... definition: {0}; sapiService: {1}',
5811 SaraJSON.stringify(existDefinition), SaraJSON.stringify(sapiService));
5812
5813 if (sapiService.getVariables()) {
5814 // Get variable set of catalog item
5815 var varSetId = existDefinition.u_var_set;
5816 LOGGER.info('Found sys_id of variable set of {0} is: {1}', existDefinition.u_name, varSetId);
5817
5818 // Get lookup variables of variable set
5819 var saraLookupVariables = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_VARIABLE, {
5820 'variable_set': varSetId,
5821 'u_is_lookup': true
5822 }, true);
5823
5824 if (saraLookupVariables.length > 0) {
5825 LOGGER.info('Found {0} lookup variable(s) in variable set (sys_id = {1})', saraLookupVariables.length, varSetId);
5826
5827 for (var i = 0; i < saraLookupVariables.length; i++) {
5828 var saraVariable = saraLookupVariables[i];
5829 LOGGER.info("Processing variable: " + saraVariable.name);
5830 var variable = this.getVariable(sapiService, saraVariable.name);
5831 if(variable !== null) {
5832 this.updateLookupVariable(saraVariable, variable);
5833 }
5834 }
5835 } else {
5836 LOGGER.warn('No lookup variable found in variable set (sys_id = {0}). Skip syncLookup!', varSetId);
5837 }
5838 } else {
5839 LOGGER.warn('There\' no variable found in catalog (item name = {0}). Skip syncLookup!', existDefinition.u_name);
5840 }
5841
5842 LOGGER.info('Ended syncLookup!');
5843 },
5844
5845 /**
5846 * Get variable from instance of SaraModel.CatalogItem
5847 * @param {SaraModel.CatalogItem} catalogItem
5848 * @param {String} saraVariableName
5849 * @return {SaraModel.CatalogVariable||Null}
5850 */
5851 getVariable: function (sapiService, saraVariableName) {
5852 for (var i = 0; i < sapiService.variables.length; i++) {
5853 if (sapiService.variables[i].name === saraVariableName) {
5854 return sapiService.variables[i];
5855 }
5856 }
5857
5858 return null;
5859 },
5860
5861 /**
5862 * Update lookup variable
5863 * @param {Object} saraVariable The variable from SaraCommon.TABLE_NAME.SARA_DEFINITION, has 'sys_id', 'type', 'name', 'u_hash', 'list_table', 'lookup_table' and 'default_value'
5864 * @param {SaraModel.CatalogVariable} variable
5865 */
5866 updateLookupVariable: function (saraVariable, variable) {
5867 var glideHelper = this.glideHelper;
5868 var LOGGER = this.LOGGER;
5869
5870 LOGGER.info('New and old hash of variable "{0}": {1} - {2}', saraVariable.name, variable.getHash(), saraVariable.u_hash);
5871
5872 if (variable.getHash() === saraVariable.u_hash) {
5873 LOGGER.info('Lookup value of variable "{0}" is not changed!', saraVariable.name);
5874 } else {
5875 LOGGER.info('Lookup value of variable "{0}" is changed!', saraVariable.name);
5876
5877 this.deactivateOldLookupValues(saraVariable);
5878
5879 var newDefaultValues = [];
5880 var ranges = variable.getRange();
5881
5882 // Insert new range values
5883 for (var i = 0; i < ranges.length; i++) {
5884 var range = ranges[i];
5885 var key = range.Value;
5886 var display = range.Key;
5887 if(!rangeValue.Value) {
5888 key = SaraCommon.EMPTY_VALUE.KEY;
5889 display = SaraCommon.EMPTY_VALUE.VALUE;
5890 }
5891
5892 var rangeId = this.dal.saveOrUpdateSaraLookup({
5893 'u_key': key,
5894 'u_display_name': display,
5895 'u_control_id': saraVariable.sys_id
5896 }).sys_id;
5897
5898 if (SaraUtils.inArray(variable.getDefaultValue(), range.Key)) {
5899 if(variable.getType() === SaraCommon.VAR_TYPE.LIST_COLLECTOR) {
5900 newDefaultValues.push(rangeId);
5901 }
5902 else {
5903 newDefaultValues.push(range.Key);
5904 }
5905 }
5906 }
5907 LOGGER.info('Inserted new data of {0} in {1}!', saraVariable.name, SaraCommon.TABLE_NAME.SARA_LOOKUP);
5908
5909 if (saraVariable.default_value) {
5910 newDefaultValues = newDefaultValues.join(',');
5911
5912 saraVariable.default_value = newDefaultValues;
5913 saraVariable.u_hash = variable.getHash();
5914 this.dal.saveOrUpdateVariable(saraVariable);
5915
5916 LOGGER.info('Updated default value for variable (name = {0}, sys_id = {1}) with new default_value = {2}',
5917 saraVariable.name, saraVariable.sys_id, newDefaultValues);
5918 }
5919 }
5920 },
5921
5922 deactivateOldLookupValues: function(saraVariable) {
5923 var glideHelper = this.glideHelper;
5924 var LOGGER = this.LOGGER;
5925 // Remove the old data of lookup table
5926 var lookups = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_LOOKUP, {
5927 'u_control_id': saraVariable.sys_id
5928 }, true);
5929
5930 for(var i = 0; i < lookups.length; i++) {
5931 var lookup = lookups[i];
5932 lookup.u_control_id = "";
5933 this.dal.saveOrUpdateSaraLookup(lookup);
5934 }
5935
5936 LOGGER.info('Deactivated old data of {0} in {1}!', saraVariable.name, SaraCommon.TABLE_NAME.SARA_LOOKUP);
5937 },
5938
5939 type: 'SaraSync'
5940};
5941]]></script>
5942 <description>Sara Sync Utilities</description>
5943 <active>true</active>
5944 <client_callable>false</client_callable>
5945 <access>public</access>
5946 </script_include>
5947
5948 <script_include>
5949 <name>SaraUtils</name>
5950 <script><![CDATA[/**
5951 * Sara Utilities
5952 */
5953var SaraUtils = Class.create();
5954SaraUtils.prototype = {
5955 initialize: function () {},
5956
5957 type: 'SaraUtils'
5958};
5959
5960/**
5961 * Format strings
5962 * @param {String} string The template string
5963 * @param {String[]} args Zero or more objects to format, supplied either in a comma-delimited list or as an array
5964 */
5965SaraUtils.formatString = function (string) {
5966 if(!string) {
5967 return "";
5968 }
5969 var args = Array.prototype.slice.call(arguments, 1);
5970
5971 return string.replace(/\{(\d+)\}/g, function (match, number) {
5972 return typeof args[number] != 'undefined' ? args[number] : match;
5973 });
5974};
5975
5976/**
5977 * Get Sara property
5978 * @param {String} name Name of sara property
5979 * @return {String}
5980 */
5981SaraUtils.getSaraProperty = function (name) {
5982 var property = gs.getProperty(SaraCommon.PROP_PREFIX + '.' + name);
5983 if(property == null) {
5984 property = gs.getProperty(name);
5985 }
5986
5987 return property;
5988};
5989
5990/**
5991 * Get mid servcer
5992 * @return {String}
5993 */
5994SaraUtils.getMIDServer = function () {
5995 return SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.MID_SERVER);
5996};
5997
5998/**
5999 * Get timestamp of current
6000 * @return {String}
6001 */
6002SaraUtils.getTimeStamp = function () {
6003 return new Date().valueOf();
6004};
6005
6006/**
6007 * Get random number
6008 * @return {String}
6009 */
6010SaraUtils.getRandom = function () {
6011 return Math.round(Math.random() * 987654321);
6012};
6013
6014/**
6015 * Diff time and return 'h, m, s'
6016 * @param {Number} time1 The first timestamp
6017 * @param {Number} time2 The second timestamp
6018 * @return {String}
6019 */
6020SaraUtils.diffTime = function (time1, time2) {
6021 var difference = time2 - time1;
6022
6023 var daysDifference = Math.floor(difference / 1000 / 60 / 60 / 24);
6024 difference -= daysDifference * 1000 * 60 * 60 * 24;
6025
6026 var hoursDifference = Math.floor(difference / 1000 / 60 / 60);
6027 difference -= hoursDifference * 1000 * 60 * 60;
6028
6029 var minutesDifference = Math.floor(difference / 1000 / 60);
6030 difference -= minutesDifference * 1000 * 60;
6031
6032 var secondsDifference = Math.floor(difference / 1000);
6033 difference -= secondsDifference * 1000;
6034
6035 var result = '';
6036
6037 if (daysDifference > 0) {
6038 result += daysDifference + 'd ';
6039 }
6040
6041 if (hoursDifference > 0) {
6042 result += hoursDifference + 'h ';
6043 }
6044
6045 if (minutesDifference > 0) {
6046 result += minutesDifference + 'm ';
6047 }
6048
6049 if (secondsDifference > 0) {
6050 result += secondsDifference + 's ';
6051 }
6052
6053 result += difference + 'ms';
6054
6055 return result;
6056};
6057
6058/**
6059 * Convert '\n' to '<br />' in string
6060 * @param {String} string
6061 * @return {String}
6062 */
6063SaraUtils.nl2br = function (string) {
6064 string = string || '';
6065
6066 return string.replace(/\n/g, '<br />');
6067};
6068
6069/**
6070 * Clean all data of SNSC
6071 */
6072SaraUtils.cleanup = function (filter) {
6073 if (!gs.hasRole(SaraCommon.ROLES.ADMIN)) {
6074 var message = 'You dont\'t have sufficient permission to do this action. Allowed role: ' + SaraCommon.ROLES.ADMIN;
6075 throw new Error(message);
6076 }
6077
6078 var glideHelper = new SaraGlideHelper();
6079 var LOGGER = new SaraLog('SaraUtils');
6080 var catItemIds = [];
6081 var varSetIds = [];
6082 var catCateIds = [];
6083 var targetCateIds = [];
6084
6085 filter = filter || {};
6086
6087 // Get list of catalog item from SaraCommon.TABLE_NAME.SARA_DEFINITION table
6088 var saraItems = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, filter, true);
6089
6090 if (saraItems.length > 0) {
6091 LOGGER.info('Found {0} item(s) in "{1}"', saraItems.length, SaraCommon.TABLE_NAME.SARA_DEFINITION);
6092
6093 for (var i = 0, saraItem; saraItem = saraItems[i]; i++) {
6094 if (saraItem['u_sc_item']) {
6095 catItemIds.push(saraItem['u_sc_item']);
6096 }
6097
6098 if (saraItem['u_var_set']) {
6099 varSetIds.push(saraItem['u_var_set']);
6100 }
6101
6102 if (saraItem['u_service_catalog_category']) {
6103 catCateIds.push(saraItem['u_service_catalog_category']);
6104 }
6105
6106 if (saraItem['u_type'] === 'category') {
6107 targetCateIds.push(saraItem['u_parent']);
6108 }
6109 }
6110
6111 var message = 'There are :';
6112 message += SaraUtils.formatString('\n - {0} catalog item(s)', catItemIds.length);
6113 message += SaraUtils.formatString('\n - {0} variable set(s)', varSetIds.length);
6114 message += SaraUtils.formatString('\n - {0} category(s)', catCateIds.length);
6115 message += SaraUtils.formatString('\n - {0} target category(s)', targetCateIds.length);
6116 LOGGER.info(message);
6117
6118 if (varSetIds.length > 0) {
6119 LOGGER.info('Removing {0} variable set(s)...', varSetIds.length);
6120
6121 for (var i = 0, varSetId; varSetId = varSetIds[i]; i++) {
6122 // Remove all variables belong to above variable sets
6123 LOGGER.info('Removing variables from variable set {0}...', varSetId);
6124 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_VARIABLE, {
6125 'variable_set': varSetId
6126 }, true);
6127
6128 // Remove all variable sets
6129 LOGGER.info('Removing variable set (sys_id = {0})...', varSetId);
6130 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_VARIABLE_SET, {
6131 'sys_id': varSetId
6132 }, true);
6133 }
6134 }
6135
6136 // Cleanup service catalog items
6137 if (catItemIds.length > 0) {
6138 LOGGER.info('Removing {0} catalog item(s)...', catItemIds.length);
6139
6140 for (var i = 0, catItemId; catItemId = catItemIds[i]; i++) {
6141 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_CAT_ITEM, {
6142 'sys_id': catItemId
6143 });
6144 }
6145 }
6146
6147 // Cleanup catalog categories
6148 if (catCateIds.length > 0) {
6149 LOGGER.info('Removing {0} catalog category(s)...', catCateIds.length);
6150
6151 for (var i = 0, catCateId; catCateId = catCateIds[i]; i++) {
6152 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
6153 'sys_id': catCateId
6154 });
6155 }
6156 }
6157
6158 // Refresh target categories
6159 if (targetCateIds.length > 0) {
6160 LOGGER.info('Refreshing {0} target category(s)...', catCateIds.length);
6161
6162 for (var i = 0, targetCateId; targetCateId = targetCateIds[i]; i++) {
6163 glideHelper.updateData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
6164 'sys_id': targetCateId
6165 }, {
6166 'active': false
6167 });
6168
6169 glideHelper.updateData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
6170 'sys_id': targetCateId
6171 }, {
6172 'active': true
6173 });
6174
6175 LOGGER.info('Target category (sys_id = {0}) is refreshed.', targetCateId);
6176 }
6177 }
6178
6179 LOGGER.info('Cleaning up {0} table ...', SaraCommon.TABLE_NAME.SARA_DEFINITION);
6180 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {}, true);
6181
6182 LOGGER.info('Cleaning up {0} table ...', SaraCommon.TABLE_NAME.SARA_VARIABLE);
6183 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_VARIABLE, {}, true);
6184 } else {
6185 LOGGER.warn('There is no items in "{0}". Skip cleanup!', SaraCommon.TABLE_NAME.SARA_DEFINITION);
6186 }
6187};
6188
6189/**
6190 * Create catalog variable from field information
6191 * @param {Object} field
6192 * @return {SaraModel.CatalogVariable}
6193 */
6194SaraUtils.createCatalogVariable = function (field) {
6195 var defaultValue = '';
6196 var varType;
6197 var isLookupControl = false;
6198 var LOGGER = new SaraLog('SaraUtils');
6199
6200 if (field['default'] && field['default'].length > 0) {
6201 defaultValue = field['default'];
6202 }
6203
6204 switch (field.type) {
6205 case 'Label':
6206 varType = SaraCommon.VAR_TYPE.LABEL;
6207 break;
6208 case 'Number':
6209 // SN only have NUM_SCALE variable type but not suitable, just use string
6210 varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
6211 break;
6212 case 'String':
6213 varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
6214 break;
6215 case 'List':
6216 varType = field.multiSelect ? SaraCommon.VAR_TYPE.LIST_COLLECTOR : SaraCommon.VAR_TYPE.LOOKUP_SELECT_BOX;
6217 isLookupControl = true;
6218 break;
6219 case 'Time':
6220 varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
6221 break;
6222 case 'Date':
6223 varType = SaraCommon.VAR_TYPE.DATE;
6224 break;
6225 case 'Timestamp':
6226 varType = SaraCommon.VAR_TYPE.DATE_TIME;
6227 break;
6228 default:
6229 break;
6230 }
6231
6232 var catalogVariable = new SaraModel.CatalogVariable();
6233 catalogVariable.setName(this.legitVarName(field.name));
6234 catalogVariable.setType(varType);
6235 catalogVariable.setLabel(field.caption);
6236 catalogVariable.setDefaultValue(defaultValue);
6237 catalogVariable.setDescription(field.description);
6238 catalogVariable.setRange([]);
6239 catalogVariable.setAsLookup(isLookupControl);
6240
6241 if(field.order != null && field.order != undefined) {
6242 catalogVariable.setOrder(field.order);
6243 }
6244
6245 if (field.maskAsPassword) {
6246 catalogVariable.setAsPassword(field.maskAsPassword);
6247 }
6248
6249 if (field.range && field.range[0].values) {
6250 var rangeValue = field.range[0].values;
6251 catalogVariable.setRange(rangeValue);
6252
6253 // Generate range hash for variable
6254 var hash = SaraUtils.md5(SaraJSON.stringify(rangeValue));
6255 catalogVariable.setHash(hash);
6256 }
6257
6258 if (field.name) {
6259 catalogVariable.setActualName(field.name);
6260 }
6261
6262 if (field.required) {
6263 catalogVariable.setRequired(field.required);
6264 }
6265
6266 if (field.multiSelect) {
6267 catalogVariable.setMultiSelect(field.multiSelect);
6268 }
6269
6270 return catalogVariable;
6271};
6272
6273/**
6274 * Legitimates variable name that is not qualified business rule validate_variable_name
6275 * @param {String} varName
6276 * @return {String}
6277 */
6278SaraUtils.legitVarName = function (varName) {
6279 var firstLegal = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
6280 var firstLetter = varName.charAt(0);
6281 if (firstLegal.indexOf(firstLetter) == -1) {
6282 varName = 'v_' + varName;
6283 }
6284
6285 var legal = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789';
6286 for (var i = 0; i < varName.length; i++) {
6287 var letter = varName.charAt(i);
6288 if (legal.indexOf(letter) == -1) {
6289 // replace illegal char with _
6290 varName = varName.substr(0, i) + '_' + varName.substr(i + 1);
6291 }
6292 }
6293
6294 return varName;
6295};
6296
6297SaraUtils.getImportTargetCatRefQual = function(){
6298 var gh = new SaraGlideHelper();
6299
6300 var catalogs = gh.getData('sc_catalog', {}, true);
6301 var catalogIds = [];
6302 for(var i = 0; i < catalogs.length; i++) {
6303 catalogIds.push(catalogs[i].sys_id);
6304 }
6305
6306 var catalogFilter = ['IN', catalogIds.join(',')];
6307 gs.info('catalogFilter = ' + catalogFilter);
6308
6309 var result = 'sys_idIN';
6310 var cats = gh.getData('sc_category', {sc_catalog: catalogFilter}, true);
6311 var categoryIds = [];
6312
6313 for(i = 0;i < cats.length; i++) {
6314 var cat = cats[i];
6315 gs.info(SaraJSON.stringify(cat));
6316 categoryIds.push(cat.sys_id);
6317 }
6318 result += categoryIds.join(',');
6319
6320 return result;
6321};
6322
6323/**
6324 * Build url
6325 * @param {String} url
6326 * @param {String} baseUrl
6327 * @return {String}
6328 */
6329SaraUtils.buildUrl = function (url, baseUrl) {
6330 if (!url) {
6331 url = '';
6332 }
6333
6334 var scheme;
6335 var pattern = /^https?:\/\//i;
6336 if (pattern.test(url)) {
6337 scheme = 'absolute';
6338 } else {
6339 scheme = 'relative';
6340 }
6341
6342 if (scheme === 'relative') {
6343 var basePath = new SaraConfig().getBasePath();
6344 if(baseUrl) {
6345 if(typeof baseUrl === 'string') {
6346 basePath = baseUrl;
6347 } else {
6348 basePath = String(baseUrl);
6349 }
6350 }
6351
6352 if (basePath.charAt(basePath.length - 1) == '/' && url.substring(0, 1) == '/') {
6353 return basePath + url.substring(1);
6354 }
6355
6356 if (basePath.charAt(basePath.length - 1) != '/' && url.substring(0, 1) != '/') {
6357 return basePath + '/' + url;
6358 }
6359
6360 return basePath + url;
6361 }
6362
6363 if (url == '/') {
6364 return new SaraConfig().getBasePath();
6365 }
6366
6367 return url;
6368};
6369
6370/**
6371 * Gets index of item in array
6372 * @param {Array} array
6373 * @param {*} item
6374 * @return {Number}
6375 */
6376SaraUtils.indexOf = function (array, item) {
6377 for (var i = 0; i < array.length; ++i) {
6378 if (array[i] === item) {
6379 return i;
6380 }
6381 }
6382
6383 return -1;
6384};
6385
6386/**
6387 * Detects the array item is in array or not
6388 * @param {Array} array
6389 * @param {*} item
6390 * @return {Boolean}
6391 */
6392SaraUtils.inArray = function (array, item) {
6393 return SaraUtils.indexOf(array, item) !== -1;
6394};
6395
6396/**
6397 * Get redirection endpoint of current instance
6398 * @return {String} The redirection endpoint
6399 */
6400SaraUtils.getRedirectionUrl = function () {
6401 return gs.getProperty('glide.servlet.uri') + SaraCommon.SCOPED_APP + '_sara_oauth_callback.do';
6402};
6403
6404SaraUtils.guardNotNullOrEmpty = function(param, msg) {
6405 if(!param || param === null || param === "") {
6406 throw msg;
6407 }
6408};
6409
6410SaraUtils.isNullOrEmpty = function(param) {
6411 if(!param || param === null || param === "") {
6412 return true;
6413 }
6414 return false;
6415};
6416
6417SaraUtils.md5 = function (string, key, raw) {
6418 /*
6419 * JavaScript MD5 1.0.1
6420 * https://github.com/blueimp/JavaScript-MD5
6421 *
6422 * Copyright 2011, Sebastian Tschan
6423 * https://blueimp.net
6424 *
6425 * Licensed under the MIT license:
6426 * http://www.opensource.org/licenses/MIT
6427 *
6428 * Based on
6429 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
6430 * Digest Algorithm, as defined in RFC 1321.
6431 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
6432 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6433 * Distributed under the BSD License
6434 * See http://pajhome.org.uk/crypt/md5 for more info.
6435 */
6436 /*jslint bitwise: true */
6437 /*global unescape, define */
6438
6439 'use strict';
6440 /*
6441 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
6442 * to work around bugs in some JS interpreters.
6443 */
6444 function safe_add(x, y) {
6445 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
6446 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
6447 return (msw << 16) | (lsw & 0xFFFF);
6448 }
6449 /*
6450 * Bitwise rotate a 32-bit number to the left.
6451 */
6452 function bit_rol(num, cnt) {
6453 return (num << cnt) | (num >>> (32 - cnt));
6454 }
6455 /*
6456 * These functions implement the four basic operations the algorithm uses.
6457 */
6458 function md5_cmn(q, a, b, x, s, t) {
6459 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
6460 }
6461
6462 function md5_ff(a, b, c, d, x, s, t) {
6463 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
6464 }
6465
6466 function md5_gg(a, b, c, d, x, s, t) {
6467 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
6468 }
6469
6470 function md5_hh(a, b, c, d, x, s, t) {
6471 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
6472 }
6473
6474 function md5_ii(a, b, c, d, x, s, t) {
6475 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
6476 }
6477 /*
6478 * Calculate the MD5 of an array of little-endian words, and a bit length.
6479 */
6480 function binl_md5(x, len) {
6481 /* append padding */
6482 x[len >> 5] |= 0x80 << (len % 32);
6483 x[(((len + 64) >>> 9) << 4) + 14] = len;
6484 var i, olda, oldb, oldc, oldd,
6485 a = 1732584193,
6486 b = -271733879,
6487 c = -1732584194,
6488 d = 271733878;
6489 for (i = 0; i < x.length; i += 16) {
6490 olda = a;
6491 oldb = b;
6492 oldc = c;
6493 oldd = d;
6494 a = md5_ff(a, b, c, d, x[i], 7, -680876936);
6495 d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
6496 c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
6497 b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
6498 a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
6499 d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
6500 c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
6501 b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
6502 a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
6503 d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
6504 c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
6505 b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
6506 a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
6507 d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
6508 c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
6509 b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
6510 a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
6511 d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
6512 c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
6513 b = md5_gg(b, c, d, a, x[i], 20, -373897302);
6514 a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
6515 d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
6516 c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
6517 b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
6518 a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
6519 d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
6520 c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
6521 b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
6522 a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
6523 d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
6524 c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
6525 b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
6526 a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
6527 d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
6528 c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
6529 b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
6530 a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
6531 d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
6532 c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
6533 b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
6534 a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
6535 d = md5_hh(d, a, b, c, x[i], 11, -358537222);
6536 c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
6537 b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
6538 a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
6539 d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
6540 c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
6541 b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
6542 a = md5_ii(a, b, c, d, x[i], 6, -198630844);
6543 d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
6544 c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
6545 b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
6546 a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
6547 d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
6548 c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
6549 b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
6550 a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
6551 d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
6552 c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
6553 b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
6554 a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
6555 d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
6556 c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
6557 b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
6558 a = safe_add(a, olda);
6559 b = safe_add(b, oldb);
6560 c = safe_add(c, oldc);
6561 d = safe_add(d, oldd);
6562 }
6563 return [a, b, c, d];
6564 }
6565 /*
6566 * Convert an array of little-endian words to a string
6567 */
6568 function binl2rstr(input) {
6569 var i,
6570 output = '';
6571 for (i = 0; i < input.length * 32; i += 8) {
6572 output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
6573 }
6574 return output;
6575 }
6576 /*
6577 * Convert a raw string to an array of little-endian words
6578 * Characters >255 have their high-byte silently ignored.
6579 */
6580 function rstr2binl(input) {
6581 var i,
6582 output = [];
6583 output[(input.length >> 2) - 1] = undefined;
6584 for (i = 0; i < output.length; i += 1) {
6585 output[i] = 0;
6586 }
6587 for (i = 0; i < input.length * 8; i += 8) {
6588 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
6589 }
6590 return output;
6591 }
6592 /*
6593 * Calculate the MD5 of a raw string
6594 */
6595 function rstr_md5(s) {
6596 return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
6597 }
6598 /*
6599 * Calculate the HMAC-MD5, of a key and some data (raw strings)
6600 */
6601 function rstr_hmac_md5(key, data) {
6602 var i,
6603 bkey = rstr2binl(key),
6604 ipad = [],
6605 opad = [],
6606 hash;
6607 ipad[15] = opad[15] = undefined;
6608 if (bkey.length > 16) {
6609 bkey = binl_md5(bkey, key.length * 8);
6610 }
6611 for (i = 0; i < 16; i += 1) {
6612 ipad[i] = bkey[i] ^ 0x36363636;
6613 opad[i] = bkey[i] ^ 0x5C5C5C5C;
6614 }
6615 hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
6616 return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
6617 }
6618 /*
6619 * Convert a raw string to a hex string
6620 */
6621 function rstr2hex(input) {
6622 var hex_tab = '0123456789abcdef',
6623 output = '',
6624 x,
6625 i;
6626 for (i = 0; i < input.length; i += 1) {
6627 x = input.charCodeAt(i);
6628 output += hex_tab.charAt((x >>> 4) & 0x0F) +
6629 hex_tab.charAt(x & 0x0F);
6630 }
6631 return output;
6632 }
6633 /*
6634 * Encode a string as utf-8
6635 */
6636 function str2rstr_utf8(input) {
6637 return unescape(encodeURIComponent(input));
6638 }
6639 /*
6640 * Take string arguments and return either raw or hex encoded strings
6641 */
6642 function raw_md5(s) {
6643 return rstr_md5(str2rstr_utf8(s));
6644 }
6645
6646 function hex_md5(s) {
6647 return rstr2hex(raw_md5(s));
6648 }
6649
6650 function raw_hmac_md5(k, d) {
6651 return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
6652 }
6653
6654 function hex_hmac_md5(k, d) {
6655 return rstr2hex(raw_hmac_md5(k, d));
6656 }
6657
6658 if (!key) {
6659 if (!raw) {
6660 return hex_md5(string);
6661 }
6662 return raw_md5(string);
6663 }
6664 if (!raw) {
6665 return hex_hmac_md5(key, string);
6666 }
6667
6668 return raw_hmac_md5(key, string);
6669};
6670]]></script>
6671 <description>Sara Utilities</description>
6672 <active>true</active>
6673 <client_callable>false</client_callable>
6674 <access>public</access>
6675 </script_include>
6676
6677 <script_include>
6678 <name>SaraTestBench</name>
6679 <script><![CDATA[/*
6680Test bench for Sara Scripts
6681Create manually in scope of Automic SNSC
6682Use background script to execute:
6683
6684var test = new SaraTestBench();
6685test.execute();
6686 */
6687var SaraTestBench = Class.create();
6688SaraTestBench.prototype = {
6689 initialize: function () {
6690 },
6691
6692 execute: function(){
6693 SaraTest.resetSummary();
6694
6695 SaraTransformMapTest.execute();
6696
6697 SaraConsumerDALTest.execute();
6698
6699 SaraConsumerImportTest.execute();
6700
6701 gs.info("=======================================================================================");
6702 gs.info("SUMMARY");
6703 gs.info("=======================================================================================");
6704 var summary = SaraTest.getSummary();
6705 gs.info("------ TOTAL: " + summary.total);
6706 gs.info("------ PASS: " + summary.pass);
6707 gs.info("------ FAIL: " + summary.fail);
6708 gs.info("------ IGNORE: " + summary.ignore);
6709 }
6710};
6711
6712var SaraConsumerDALTest = (function() {
6713 var gh = new SaraGlideHelper();
6714 var dal = new SaraConsumerDAL();
6715 return {
6716 execute: function() {
6717 gs.info("----------------------------------------------------------------------------");
6718 gs.info("Test SaraConsumerDAL");
6719 gs.info("----------------------------------------------------------------------------");
6720
6721 this.testGetCatalog();
6722 this.testSaveOrUpdateCatalog();
6723 this.testSaveOrUpdateCategory();
6724 this.testGetDefaultCategoryId();
6725 this.testSaveCategoryToSaraDefinition();
6726 this.testDeactivateSaraDefinition();
6727 },
6728
6729 testGetCatalog: function() {
6730 SaraTest.test("get catalog id by title", function() {
6731 var cat = dal.getCatalog("Service Catalog");
6732 SaraTest.assert(cat !== undefined, "catalog is get correctly");
6733 SaraTest.assert(cat.title === "Service Catalog", "title is get correctly");
6734 gs.info(SaraJSON.stringify(cat));
6735 });
6736 },
6737
6738 testSaveOrUpdateCatalog: function() {
6739 SaraTest.test("save or update catalog", function() {
6740 var catName = "snsc dal cat 1" + SaraUtils.getRandom();
6741 var desc = "test description";
6742
6743 var catId = dal.saveOrUpdateCatalog({
6744 title: catName,
6745 description: desc,
6746 active: true
6747 }).sys_id;
6748 SaraTest.assert(catId !== null, "catalog is persisted correctly");
6749
6750 var cat = gh.getData("sc_catalog", {sys_id: catId});
6751 gs.info(SaraJSON.stringify(cat));
6752 SaraTest.assert(cat !== null, "catalog is get correctly");
6753 SaraTest.assert(cat.title === catName, "title is set correctly");
6754 SaraTest.assert(cat.description === desc, "description is set correctly");
6755 SaraTest.assert(cat.active == "true", "active is set correctly");
6756
6757 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6758 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6759 });
6760 },
6761
6762 testSaveOrUpdateCategory: function() {
6763 SaraTest.test("save or update category", function() {
6764 var catName = "snsc dal cat 2" + SaraUtils.getRandom();
6765 var desc = "test description";
6766 var categoryName = "snsc dal category 2" + SaraUtils.getRandom();
6767 var categoryDescription = "category description";
6768 var categoryNewDescription = "category description new";
6769
6770 var catId = dal.saveOrUpdateCatalog({
6771 title: catName,
6772 description: desc,
6773 active: true
6774 }).sys_id;
6775
6776 var cat = {
6777 sc_catalog: catId,
6778 title: categoryName,
6779 description: categoryDescription,
6780 active: true};
6781 cat.description = categoryDescription;
6782 var category = dal.saveOrUpdateCategory(cat);
6783 gs.info("category: " + SaraJSON.stringify(category));
6784 SaraTest.assert(category !== null, "category is get correctly");
6785 SaraTest.assert(category.title === categoryName, "title is set correctly");
6786 SaraTest.assert(category.description === categoryDescription, "description is set correctly");
6787 SaraTest.assert(category.active == "true", "active is set correctly");
6788
6789 category.description = categoryNewDescription;
6790 category.active = false;
6791 dal.saveOrUpdateCategory(category);
6792
6793 var result = gh.getData("sc_category", {sys_id: category.sys_id});
6794 gs.info("result: " + SaraJSON.stringify(result));
6795
6796 SaraTest.assert(result.description === categoryNewDescription, "description is updated correctly");
6797 SaraTest.assert(result.active == "false", "active is updated correctly");
6798
6799 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6800 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6801 });
6802 },
6803
6804 testGetDefaultCategoryId: function() {
6805 SaraTest.test("get default category", function () {
6806 var catId = dal.getDefaultCategoryId();
6807 var category = gh.getData("sc_category", {sys_id: catId});
6808
6809 SaraTest.assert(category !== null, "getDetaultCategoryId return valid category id");
6810 gs.info(SaraJSON.stringify(category));
6811 });
6812 },
6813
6814 testSaveCategoryToSaraDefinition: function() {
6815 SaraTest.test("save category to sara definition", function() {
6816 var catName = "snsc dal cat 3" + SaraUtils.getRandom();
6817 var desc = "test description";
6818
6819 var categoryName = "snsc dal category 3" + SaraUtils.getRandom();
6820 var categoryDescription = "category description";
6821
6822 var catId = dal.saveOrUpdateCatalog({
6823 title: catName,
6824 description: desc,
6825 active: true
6826 }).sys_id;
6827
6828 var category = dal.saveOrUpdateCategory({
6829 sc_catalog: catId,
6830 title: categoryName,
6831 description: categoryDescription,
6832 active: true
6833 });
6834
6835 var definitionId = dal.saveRootImportCategoryToSaraDefinition(category.sys_id).sys_id;
6836 var definition = gh.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definitionId});
6837 gs.info(SaraJSON.stringify(definition));
6838
6839 SaraTest.assert(definition !== null, "definition is saved correctly");
6840 SaraTest.assert(definition.u_name === categoryName, "u_name is saved correctly");
6841 SaraTest.assert(definition.u_parent === category.sys_id, "u_parent is saved correctly");
6842 SaraTest.assert(definition.u_type === 'category', "u_type is saved correctly");
6843 SaraTest.assert(definition.u_active == 'true', "active is saved correctly");
6844
6845 gh.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definitionId}, true);
6846 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6847 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6848 });
6849 },
6850
6851 testDeactivateSaraDefinition: function() {
6852 SaraTest.test("deactivate sara definition", function() {
6853 var catName = "snsc dal cat 6" + SaraUtils.getRandom();
6854 var desc = "test description";
6855 var categoryName = "snsc dal category 6" + SaraUtils.getRandom();
6856 var categoryDescription = "category description";
6857 var catalogItemName = "snsc dal catalog item 6";
6858
6859 var parentDefinitionName = "snsc definition 6 parent" + SaraUtils.getRandom();
6860 var definitionName = "snsc definition 6" + SaraUtils.getRandom();
6861
6862 var catId = dal.saveOrUpdateCatalog({
6863 title: catName,
6864 description: desc,
6865 active: true
6866 }).sys_id;
6867 var category = dal.saveOrUpdateCategory({
6868 title: categoryName,
6869 description: categoryDescription,
6870 sc_catalog: catId
6871 });
6872 var catalogItem = dal.saveOrUpdateCatalogItem({
6873 category: category.sys_id,
6874 name: catalogItemName,
6875 active: true
6876 });
6877
6878 var parentDefinition = dal.saveOrUpdateSaraDefinition({
6879 u_name: parentDefinitionName,
6880 u_active: true,
6881 u_consume_url: "http://testurl.com",
6882 u_parent: category.sys_id,
6883 u_type: 'catalog'
6884 });
6885
6886 var definition = dal.saveOrUpdateSaraDefinition({
6887 u_name: definitionName,
6888 u_active: true,
6889 u_consume_url: "http://testurl.com",
6890 u_parent: category.sys_id,
6891 u_type: 'service',
6892 u_sc_item: catalogItem.sys_id,
6893 u_hash: '123'
6894 });
6895
6896 SaraTest.assert(parentDefinition.u_active == 'true', "parent definition is active");
6897 SaraTest.assert(definition.u_active == 'true', "definition is active");
6898
6899 gs.info("parent definition: " + SaraJSON.stringify(parentDefinition));
6900 gs.info("definition: " + SaraJSON.stringify(definition));
6901
6902 dal.deactivateSaraDefinition(parentDefinition);
6903
6904 definition = gh.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definition.sys_id});
6905 parentDefinition = gh.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: parentDefinition.sys_id});
6906
6907 category = gh.getData("sc_category", {sys_id: category.sys_id});
6908 gs.info("category: " + SaraJSON.stringify(category));
6909
6910 catalogItem = gh.getData("sc_cat_item", {sys_id: catalogItem.sys_id});
6911 gs.info("catalogItem: " + SaraJSON.stringify(catalogItem));
6912
6913 SaraTest.assert(catalogItem.name === catalogItemName,"get correct catalog item");
6914 SaraTest.assert(catalogItem.active == 'false',"catalog item is deactivated");
6915 SaraTest.assert(definition.u_name === definitionName,"get correct definition");
6916 SaraTest.assert(definition.u_active == 'false',"definition is deactivated");
6917 SaraTest.assert(parentDefinition.u_name === parentDefinitionName,"get correct parent definition");
6918 SaraTest.assert(parentDefinition.u_active == 'false',"parent definition is deactivated");
6919
6920
6921 gh.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definition.sys_id}, true);
6922 gh.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: parentDefinition.sys_id}, true);
6923 //gh.deleteData("sc_cat_item", {category: category.sys_id}, true);
6924 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6925 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6926 });
6927 }
6928 };
6929})();
6930
6931var SaraConsumerImportTest = (function() {
6932 var logger = new SaraLog("SaraGlideHelperTest");
6933 var glideHelper = new SaraGlideHelper();
6934 var categoryName = "snsc test import " + SaraUtils.getRandom();
6935 var consumer = new SaraConsumerImportSet();
6936 var categoryId = null;
6937 var catalogId;
6938 var category;
6939 var dal = new SaraConsumerDAL();
6940 var catItem1 = null;
6941
6942 return {
6943 execute: function() {
6944 gs.info("----------------------------------------------------------------------------");
6945 gs.info("Test SaraConsumerImportSet");
6946 gs.info("----------------------------------------------------------------------------");
6947
6948 this.initialize();
6949
6950 this.testImportCategory();
6951
6952 this.testImportItem();
6953
6954 this.testSyncLookup();
6955
6956 this.tearDown();
6957 },
6958
6959 initialize: function() {
6960 catalogId = glideHelper.getData("sc_catalog", { title: "Service Catalog" }).sys_id;
6961
6962 category = dal.saveOrUpdateCategory({
6963 title: categoryName,
6964 description: "test",
6965 sc_catalog: catalogId,
6966 active: true
6967 });
6968 gs.info("created category: " + category);
6969
6970 gs.info("category to be imported: " + categoryName);
6971
6972 categoryId = category.sys_id;
6973 },
6974
6975 getMockCatalogData: function() {
6976 var catalogsData = {
6977 "DEMO":{
6978 "title":"Automic Demo Services",
6979 "active":true,
6980 "description":"Automic Demo Services",
6981 "parent":"",
6982 "name":"DEMO"},
6983 "DEMO2":{
6984 "title":"DEMO2",
6985 "active":true,
6986 "description":"",
6987 "parent":"",
6988 "name":"DEMO2"}};
6989
6990 //mock catalog data for testing
6991 for(var ctgName in catalogsData) {
6992 this.wrapCategoryData(catalogsData[ctgName]);
6993 }
6994
6995 return catalogsData;
6996 },
6997
6998 getMockupServicesData: function() {
6999 var servicesData = {
7000 "DEMO": {
7001 "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.ACTIVATE_SNSC_SERVICE.NEW.1":
7002 {
7003 "variables": [
7004 { "description": "", "label": "Currency", "defaultValue": ["EUR"], "type": 18, "required": true, "range": [{ "Value": "EUR", "Key": "EUR" }, { "Value": "US$", "Key": "US$" }], "hash": "d4dcdddf0d7831ecaf23643ce1d4d4b7", "asLookup": true, "name": "EOM_CURRENCY_", "actualName": "EOM_CURRENCY#" },
7005 { "description": "", "label": "Previous Month(s) included", "defaultValue": ["3"], "type": 6, "required": true, "range": [], "asLookup": false, "name": "EOM_MONTHBACK_", "actualName": "EOM_MONTHBACK#" },
7006 { "description": "", "label": "Components", "defaultValue": ["Current Account"], "type": 21, "required": true, "range": [{ "Value": "Current Account", "Key": "Current Account" }, { "Value": "General Ledger", "Key": "General Ledger" }, { "Value": "Loans", "Key": "Loans" }, { "Value": "Mortgage", "Key": "Mortgage" }, { "Value": "Treasury", "Key": "Treasury" }], "hash": "2eb7e44c8b0b12acae8e8322f8b376d3", "asLookup": true, "multiSelect": true, "name": "EOM_COMPONENTS_", "actualName": "EOM_COMPONENTS#" },
7007 { "description": "", "label": "Region", "defaultValue": ["America"], "type": 18, "required": true, "range": [{ "Value": "Africa", "Key": "Africa" }, { "Value": "America", "Key": "America" }, { "Value": "Asia", "Key": "Asia" }, { "Value": "Australia", "Key": "Australia" }, { "Value": "Europe", "Key": "Europe" }], "hash": "a093352aac40b86d0245f2c14e3afc21", "asLookup": true, "name": "EOM_REGION_", "actualName": "EOM_REGION#" },
7008 { "description": "", "label": "Units", "defaultValue": ["Development"], "type": 21, "required": true, "range": [{ "Value": "Development", "Key": "Development" }, { "Value": "Headquarter", "Key": "Headquarter" }, { "Value": "Production", "Key": "Production" }, { "Value": "Research", "Key": "Research" }, { "Value": "Sales", "Key": "Sales" }], "hash": "e6b832d4aef3952cb8120e59d8e1eeaf", "asLookup": true, "multiSelect": true, "name": "EOM_UNITS_", "actualName": "EOM_UNITS#" }
7009 ], "description": "Moves the Demo Service to the /SERVICES/SNSC_DEMO folder (must be created beforehand) so that SAPI can publish it and Service Now can display it", "workflow": "Sara Service", "serviceName": "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.ACTIVATE_SNSC_SERVICE.NEW.1", "consumeUrl": "/services/PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.ACTIVATE_SNSC_SERVICE.NEW.1/consume", "hash": "34cb7f82e66c1829423e5e77a6356a5b", "active": true, "shortDesc": "Activate SNSC Service", "customCart": "", "name": "Activate SNSC Service" },
7010 "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEACTIVATE_SNSC_SERVICE.NEW.1":
7011 {
7012 "variables": [], "description": "Moves the SNSC Demo service back to the packages folder so that it is no longer visible by SAPI and Service Now", "workflow": "Sara Service", "serviceName": "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEACTIVATE_SNSC_SERVICE.NEW.1", "consumeUrl": "/services/PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEACTIVATE_SNSC_SERVICE.NEW.1/consume", "hash": "5d70dace54e578249482379fde08a8ef", "active": true, "shortDesc": "Deactivate SNSC Service", "customCart": "", "name": "Deactivate SNSC Service" }
7013 },
7014 "DEMO2": {
7015 "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEMO_SERVICE.NEW.1": {
7016 "variables": [
7017 { "description": "", "label": "Currency", "defaultValue": ["EUR"], "type": 18, "required": true, "range": [{ "Value": "EUR", "Key": "EUR" }, { "Value": "US$", "Key": "US$" }], "hash": "d4dcdddf0d7831ecaf23643ce1d4d4b7", "asLookup": true, "name": "EOM_CURRENCY_", "actualName": "EOM_CURRENCY#" },
7018 { "description": "", "label": "Previous Month(s) included", "defaultValue": ["3"], "type": 6, "required": true, "range": [], "asLookup": false, "name": "EOM_MONTHBACK_", "actualName": "EOM_MONTHBACK#" },
7019 { "description": "", "label": "Components", "defaultValue": ["Current Account"], "type": 21, "required": true, "range": [{ "Value": "Current Account", "Key": "Current Account" }, { "Value": "General Ledger", "Key": "General Ledger" }, { "Value": "Loans", "Key": "Loans" }, { "Value": "Mortgage", "Key": "Mortgage" }, { "Value": "Treasury", "Key": "Treasury" }], "hash": "2eb7e44c8b0b12acae8e8322f8b376d3", "asLookup": true, "multiSelect": true, "name": "EOM_COMPONENTS_", "actualName": "EOM_COMPONENTS#" },
7020 { "description": "", "label": "Region", "defaultValue": ["America"], "type": 18, "required": true, "range": [{ "Value": "Africa", "Key": "Africa" }, { "Value": "America", "Key": "America" }, { "Value": "Asia", "Key": "Asia" }, { "Value": "Australia", "Key": "Australia" }, { "Value": "Europe", "Key": "Europe" }], "hash": "a093352aac40b86d0245f2c14e3afc21", "asLookup": true, "name": "EOM_REGION_", "actualName": "EOM_REGION#" },
7021 { "description": "", "label": "Units", "defaultValue": ["Development"], "type": 21, "required": true, "range": [{ "Value": "Development", "Key": "Development" }, { "Value": "Headquarter", "Key": "Headquarter" }, { "Value": "Production", "Key": "Production" }, { "Value": "Research", "Key": "Research" }, { "Value": "Sales", "Key": "Sales" }], "hash": "e6b832d4aef3952cb8120e59d8e1eeaf", "asLookup": true, "multiSelect": true, "name": "EOM_UNITS_", "actualName": "EOM_UNITS#" }
7022 ], "description": "End of Month processing demo with various promptsets and elements", "workflow": "Sara Service", "serviceName": "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEMO_SERVICE.NEW.1", "consumeUrl": "/services/PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEMO_SERVICE.NEW.1/consume", "hash": "1258a64471bc8a44b9ce46f2b88a1145", "active": true, "shortDesc": "End of Month Demo", "customCart": "", "name": "End of Month Demo" }
7023 }};
7024
7025 //mock service data for testing
7026 for (var catalogName in servicesData) {
7027 var catalog = servicesData[catalogName];
7028 for(var serviceName in catalog) {
7029 this.wrapServiceData(catalog[serviceName]);
7030 }
7031 }
7032
7033 return servicesData;
7034 },
7035
7036 wrapCategoryData: function(dataObj) {
7037 dataObj.__proto__ = new SaraModel.CatalogCategory();
7038 },
7039
7040 wrapServiceData: function(dataObj) {
7041 dataObj.__proto__ = new SaraModel.CatalogItem();
7042 if(dataObj.variables && dataObj.variables instanceof Array) {
7043 for(var i = 0; i < dataObj.variables.length; i ++) {
7044 dataObj.variables[i].__proto__ = new SaraModel.CatalogVariable();
7045 }
7046 }
7047 },
7048
7049 testImportCategory: function () {
7050 consumer.catalogsData = this.getMockCatalogData();
7051 SaraTest.test("test import categories, de-activate definition removed from AE, update existing definition and create new definition", function () {
7052 var categoryName2 = "snsc test import " + SaraUtils.getRandom();
7053 var categoryName3 = "snsc test import " + SaraUtils.getRandom();
7054
7055 var definitionName = "snsc test import " + SaraUtils.getRandom();
7056 var categoryDescription = "testImportCategory category description";
7057
7058 var category2 = dal.saveOrUpdateCategory({
7059 title: categoryName2,
7060 description: categoryDescription,
7061 sc_catalog: catalogId,
7062 active: true
7063 });
7064
7065
7066 var definition = dal.saveOrUpdateSaraDefinition({
7067 u_name: definitionName,
7068 u_active: true,
7069 u_consume_url: "http://testurl.com",
7070 u_parent: category.sys_id,
7071 u_type: 'catalog',
7072 u_service_catalog_category: category2.sys_id
7073 });
7074
7075 var category3 = dal.saveOrUpdateCategory({
7076 title: categoryName3,
7077 description: categoryDescription,
7078 sc_catalog: catalogId,
7079 active: true
7080 });
7081
7082 var demoDefinition = dal.saveOrUpdateSaraDefinition({
7083 u_name: "DEMO",
7084 u_active: true,
7085 u_consume_url: "oldurl",
7086 u_parent: category.sys_id,
7087 u_type: 'catalog',
7088 u_service_catalog_category: category3.sys_id
7089 });
7090
7091 gs.info("done prepare test data");
7092 //create new definition and make sure that it will be de-activate during synchronization
7093 consumer.importCategory(categoryId);
7094
7095 var resultDefinition = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, { u_name: definitionName, u_parent: category.sys_id });
7096 SaraTest.assert(resultDefinition.u_active == "false", "Definition does not exist in AE should be de-activated");
7097
7098 category2 = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, { sys_id: category2.sys_id });
7099 SaraTest.assert(category2.active == "false", "Category linked to definition does not exist in AE should be de-activated");
7100
7101 category3 = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, { sys_id: category3.sys_id });
7102 SaraTest.assert(category3.parent == category.sys_id, "parent of category linked to definition exist is updated");
7103 SaraTest.assert(category3.title == "Automic Demo Services", "title of category linked to definition exist is updated");
7104 SaraTest.assert(category3.description == "Automic Demo Services", "description of category linked to definition exist is updated");
7105 });
7106 },
7107
7108 testImportItem: function() {
7109 consumer.servicesData = this.getMockupServicesData();
7110
7111 SaraTest.test("test import items", function() {
7112 consumer.importItem();
7113
7114 gs.info("get sub category of " + categoryId);
7115 //get catalog items under import category
7116 var subCategories = glideHelper.getData("sc_category", {parent: categoryId, active: true}, true);
7117 gs.info("sub categories: " + SaraJSON.stringify(subCategories));
7118 SaraTest.assertEqual(subCategories.length, 2, "2 categories are created");
7119 var category1 = subCategories[0].title === "DEMO2" ? subCategories[1] : subCategories[0];
7120 var catItemsOfCategory1 = glideHelper.getData("sc_cat_item", {category: category1.sys_id}, true);
7121
7122 SaraTest.assertEqual(catItemsOfCategory1.length, 2, "2 catalog item under category " + category1.title);
7123
7124 gs.info("catItemsOfCategory1: " + SaraJSON.stringify(catItemsOfCategory1));
7125 catItem1 = catItemsOfCategory1[0].name === "Activate SNSC Service" ? catItemsOfCategory1[0] : catItemsOfCategory1[1];
7126 var itemVarSet = glideHelper.getData("io_set_item", {sc_cat_item: catItem1.sys_id});
7127 var varSet = glideHelper.getData("item_option_new_set", {sys_id: itemVarSet.variable_set});
7128 gs.info(" varSet of the item: " + SaraJSON.stringify(varSet));
7129 var variables = glideHelper.getData("x_ausgh_snsc_sara_variable", {variable_set: varSet.sys_id}, true);
7130 gs.info(" variables of the item: " + SaraJSON.stringify(variables));
7131 SaraTest.assert(variables.length == 7, "5 + 2 variables are created");
7132 });
7133 },
7134
7135 testSyncLookup: function() {
7136 var newSapiService = {
7137 "variables": [
7138 { "description": "", "label": "Currency", "defaultValue": ["EUR"], "type": 18, "required": true, "range": [{ "Value": "EUR", "Key": "EUR" }, { "Value": "US$", "Key": "US$" }], "hash": "d4dcdddf0d7831ecaf23643ce1dd4b8", "asLookup": true, "name": "EOM_CURRENCY_", "actualName": "EOM_CURRENCY#" },
7139 { "description": "", "label": "CMB", "defaultValue": ["value1"], "type": 18, "required": true, "range": [{ "Value": "value1", "Key": "value1" }, { "Value": "value2", "Key": "value2" }], "hash": "d4dcdddf0d7831ecaf23643ce1d4g4b6", "asLookup": true, "name": "CMB_NEW_LOOKUP", "actualName": "CMB_NEW_LOOKUP#" },
7140 { "description": "", "label": "Previous Month(s) included", "defaultValue": ["3"], "type": 6, "required": true, "range": [], "asLookup": false, "name": "EOM_MONTHBACK_", "actualName": "EOM_MONTHBACK#" },
7141 { "description": "", "label": "Components", "defaultValue": ["Current Account"], "type": 21, "required": true, "range": [{ "Value": "Current Account", "Key": "Current Account" }, { "Value": "General Ledger", "Key": "General Ledger" }, { "Value": "Loans", "Key": "Loans" }, { "Value": "Mortgage", "Key": "Mortgage" }, { "Value": "Treasury", "Key": "Treasury" }], "hash": "2eb7e44c8b0b12acae8e8322f8b376d3", "asLookup": true, "multiSelect": true, "name": "EOM_COMPONENTS_", "actualName": "EOM_COMPONENTS#" },
7142 { "description": "", "label": "Region", "defaultValue": ["America"], "type": 18, "required": true, "range": [{ "Value": "Africa", "Key": "Africa" }, { "Value": "America", "Key": "America" }, { "Value": "Asia", "Key": "Asia" }, { "Value": "Australia", "Key": "Australia" }, { "Value": "Europe", "Key": "Europe" }], "hash": "a093ddd352aac40b86d0245f2c14e3afc21", "asLookup": true, "name": "EOM_REGION_", "actualName": "EOM_REGION#" },
7143 { "description": "", "label": "Units", "defaultValue": ["Development"], "type": 21, "required": true, "range": [{ "Value": "Development", "Key": "Development" }, { "Value": "Headquarter", "Key": "Headquarter" }, { "Value": "Production", "Key": "Production" }, { "Value": "Research", "Key": "Research" }, { "Value": "Sales", "Key": "Sales" }], "hash": "e6b832d4aef3952cb8120e59d8e1eeaf", "asLookup": true, "multiSelect": true, "name": "EOM_UNITS_", "actualName": "EOM_UNITS#" }
7144 ], "description": "Moves the Demo Service to the /SERVICES/SNSC_DEMO folder (must be created beforehand) so that SAPI can publish it and Service Now can display it", "workflow": "Sara Service", "serviceName": "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.ACTIVATE_SNSC_SERVICE.NEW.1", "consumeUrl": "/services/PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.ACTIVATE_SNSC_SERVICE.NEW.1/consume", "hash": "34cb7f82e66c1829423e5e77a6356a5b", "active": true, "shortDesc": "Activate SNSC Service", "customCart": "", "name": "Activate SNSC Service" };
7145 this.wrapServiceData(newSapiService);
7146
7147 SaraTest.test("test sync lookup", function() {
7148 var saraSync = new SaraSync();
7149 gs.info("catItem1: " + SaraJSON.stringify(catItem1));
7150 var definition = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {u_sc_item:catItem1.sys_id });
7151 gs.info("newSapiService: " + SaraJSON.stringify(newSapiService));
7152 saraSync.syncLookup(definition, newSapiService);
7153 });
7154 },
7155
7156 tearDown: function() {
7157 SaraUtils.cleanup( { u_parent: category.sys_id });
7158 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, { u_parent: category.sys_id }, true);
7159 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY, { parent: categoryId }, true);
7160 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY, { title: ["CONTAINS", "snsc test import"] }, true);
7161 }
7162 };
7163})();
7164
7165var SaraTransformMapTest = (function(){
7166 var logger = new SaraLog("SaraGlideHelperTest");
7167 var glideHelper = new SaraGlideHelper();
7168
7169 var catalogId = glideHelper.getSysId("sc_catalog", {title: "Service Catalog"});
7170 gs.info("catelog id: " + catalogId);
7171
7172 var getCategory = function(title) {
7173 return glideHelper.getData("sc_category", {title: title });
7174 };
7175
7176 var deleteCategory = function(title, deleteAll) {
7177 glideHelper.deleteData("sc_category", {title: title },deleteAll);
7178 glideHelper.deleteData("x_ausgh_snsc_sc_category_ist", {title: title },deleteAll);
7179 };
7180
7181 var createCategory = function(title, active, description, parent) {
7182 glideHelper.persistData("x_ausgh_snsc_sc_category_ist", {
7183 title: title,
7184 active: active,
7185 description: description,
7186 parent: parent,
7187 sc_catalog: catalogId
7188 });
7189 };
7190
7191 return {
7192 execute: function() {
7193 gs.info("----------------------------------------------------------------------------");
7194 gs.info("Test transform map definitions");
7195 gs.info("----------------------------------------------------------------------------");
7196
7197 this.testPersistCatalog();
7198 this.testPersistCategory();
7199 this.testPersistCatalogItem();
7200 this.testPersistVariableSet();
7201 this.testPersistCatelogVariableSet();
7202 this.testPersistSaraDefinition();
7203 },
7204
7205 testPersistCatalog: function() {
7206 var catalogName = "snsc test catalog";
7207 glideHelper.deleteData("sc_catalog", {"title": catalogName});
7208
7209 SaraTest.test("Persist catalog via Importset", function() {
7210 glideHelper.persistData("x_ausgh_snsc_sc_catalog_ist", {
7211 title: catalogName,
7212 description: "test description",
7213 active: "true"
7214 });
7215
7216 var catalog = glideHelper.getData("sc_catalog", {"title": catalogName});
7217
7218 SaraTest.assert(catalog !== null, "catalog is transformed correctly");
7219 SaraTest.assert(catalog.title === catalogName, "catalog title is transformed correctly");
7220 SaraTest.assert(catalog.description === "test description", "catalog description is transformed correctly");
7221 gs.info("active: " + catalog.active);
7222 SaraTest.assert(catalog.active, "catalog active is transformed correctly");
7223 });
7224
7225 SaraTest.test("Update catalog via Importset", function() {
7226 var catalog = glideHelper.getData("sc_catalog", {title: catalogName});
7227 var data = {
7228 id: catalog.sys_id,
7229 description: "new description 2",
7230 active: false
7231 };
7232 glideHelper.persistData("x_ausgh_snsc_sc_catalog_ist", data);
7233
7234 var newCatalog = glideHelper.getData("sc_catalog", {"title": catalogName});
7235 gs.info("new catalog: " + SaraJSON.stringify(newCatalog));
7236 SaraTest.assert(newCatalog !== null, "catalog is transformed correctly, title is not overrided");
7237 SaraTest.assert(newCatalog.description === "new description 2", "catalog description is updated correctly");
7238 gs.info("active: " + newCatalog.active);
7239 SaraTest.assert(newCatalog.active == "false", "catalog active is updated correctly");
7240 });
7241 },
7242
7243 testPersistCategory: function() {
7244 var categoryName1 = "snsc test catagory";
7245 var categoryName2 = "snsc test sub catagory";
7246 deleteCategory(categoryName1, true);
7247 deleteCategory(categoryName2, true);
7248
7249 SaraTest.test("Persist category via Importset", function() {
7250 var category = getCategory(categoryName1);
7251 SaraTest.assert(category === null, "category must not exists");
7252 var category2 = getCategory(categoryName2);
7253 SaraTest.assert(category2 === null, "sub category must not exists");
7254
7255 createCategory(categoryName1,true,"test description", null);
7256 category = getCategory(categoryName1);
7257 gs.info(SaraJSON.stringify(category));
7258 SaraTest.assert(category !== null, "Category ImportSet should be transform to category table");
7259 SaraTest.assert(category.title === categoryName1, "Assert title transform correctly");
7260
7261 //create via importset table
7262 createCategory(categoryName2,true,"test sub description", category.sys_id);
7263 //get real data
7264 category2 = getCategory(categoryName2);
7265 SaraTest.assert(category2 !== null, "Sub category ImportSet should be transform to category table");
7266 SaraTest.assert(category2.title === categoryName2, "Assert title transform correctly");
7267
7268 var parent = glideHelper.getData("sc_category", {sys_id:category2.parent});
7269 SaraTest.assert(parent !== null, "Assert parent transform correctly");
7270 SaraTest.assert(parent.title === categoryName1, "Assert parent transform correctly");
7271 });
7272
7273 SaraTest.test("Save category with same name but different parent should create new category", function() {
7274 //create another category with different parent and assert that new item is
7275 //inserted to target table
7276 gs.info("create another record with name " + categoryName2);
7277 createCategory(categoryName2,true,"test description 2");
7278 var records = glideHelper.getData("sc_category", {title:categoryName2}, true);
7279 SaraTest.assert(records.length === 2, "new category is created");
7280 });
7281 },
7282
7283 testPersistCatalogItem: function() {
7284 var gh = glideHelper;
7285 var name = "snsc sample catelog item" + SaraUtils.getRandom();
7286 gs.info("catelog item name: " + name);
7287 var description = "whatever";
7288 var short_description = "short descriprion";
7289 var categoryName = "snsc item category";
7290 var category = null;
7291
7292 SaraTest.test("Persist catalog item via Importset", function(){
7293 //prepare data
7294 deleteCategory(categoryName, true);
7295 createCategory(categoryName, true, "");
7296 category = getCategory(categoryName);
7297 gs.info("category id: " + category.sys_id);
7298 SaraTest.assert(category !== null, "category is created successfully");
7299
7300 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7301 name: name,
7302 description: description,
7303 short_description: short_description,
7304 use_sc_layout: true,
7305 no_quantity: true,
7306 category: category.sys_id,
7307 active: true
7308 });
7309 var item = gh.getData("sc_cat_item", {name: name});
7310 SaraTest.assert(item.name === name, "item is transformed correctly");
7311 SaraTest.assert(item.description === description, "description is transformed correctly");
7312 SaraTest.assert(item.short_description === short_description, "short_description is transformed correctly");
7313 SaraTest.assert(item.use_sc_layout == "true", "use_sc_layout is transformed correctly");
7314 SaraTest.assert(item.no_quantity == "true", "no_quantity is transformed correctly");
7315 SaraTest.assert(item.active == "true", "active is transformed correctly");
7316 SaraTest.assert(item.category === category.sys_id, "category is transformed correctly");
7317 });
7318
7319 SaraTest.test("Catalog item same name different category should create new", function() {
7320 var newCategoryName = categoryName + SaraUtils.getRandom();
7321 createCategory(newCategoryName, true, "");
7322 var newCat = getCategory(newCategoryName);
7323 gs.info("new category id: " + newCat.sys_id);
7324 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7325 name: name,
7326 description: "new description",
7327 short_description: "new short description",
7328 use_sc_layout: false,
7329 no_quantity: false,
7330 category: newCat.sys_id,
7331 active: false
7332 });
7333
7334 var records = gh.getData("sc_cat_item", {name: name}, true);
7335 SaraTest.assert(records.length === 2, "new item is created");
7336 });
7337
7338 SaraTest.test("Update catalog item via Importset", function(){
7339 var existingItem = gh.getData("sc_cat_item", {
7340 name: name,
7341 category: category.sys_id
7342 });
7343
7344 SaraTest.assert(existingItem !== undefined, "existing item is get correctly");
7345
7346 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7347 id: existingItem.sys_id,
7348 name: name,
7349 description: "new description",
7350 short_description: "new short description",
7351 use_sc_layout: false,
7352 no_quantity: false,
7353 category: category.sys_id,
7354 active: false
7355 });
7356 var items = gh.getData("sc_cat_item", {name: name, category: category.sys_id}, true);
7357 SaraTest.assert(items.length === 1, "no new item is created");
7358
7359 var item = items[0];
7360 SaraTest.assert(item.name === name, "item is transformed correctly");
7361 SaraTest.assert(item.description === "new description", "description is transformed correctly");
7362 SaraTest.assert(item.short_description === "new short description", "short_description is transformed correctly");
7363 SaraTest.assert(item.use_sc_layout == "false", "use_sc_layout is transformed correctly");
7364 SaraTest.assert(item.no_quantity == "false", "no_quantity is transformed correctly");
7365 SaraTest.assert(item.active == "false", "active is transformed correctly");
7366 SaraTest.assert(item.category === category.sys_id, "category is transformed correctly");
7367 });
7368 },
7369
7370 testPersistVariableSet: function() {
7371 var varSetName = "snsc test variable set " + SaraUtils.getRandom();
7372 var varSetTitle = "title";
7373 var varSetDescription = "test description";
7374 var varSetDisplayName = "display name";
7375
7376 var varSetTitleNew = "title new";
7377 var varSetDescriptionNew = "test description new";
7378 var varSetDisplayNameNew = "display name new";
7379
7380 glideHelper.deleteData("item_option_new_set", {"name": ["CONTAINS", "snsc test"]}, true);
7381
7382 SaraTest.test("Persist variable set via Importset", function() {
7383 glideHelper.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7384 name: varSetName,
7385 title: varSetTitle,
7386 description: varSetDescription,
7387 sys_name: varSetDisplayName
7388 });
7389
7390 var varSet = glideHelper.getData("item_option_new_set", {"name": varSetName});
7391
7392 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7393 SaraTest.assert(varSet.name === varSetName, "var set name is transformed correctly");
7394 SaraTest.assert(varSet.title === varSetTitle, "var set title is transformed correctly");
7395 SaraTest.assert(varSet.description === varSetDescription, "var set description is transformed correctly");
7396 SaraTest.assert(varSet.sys_name === varSetDisplayName, "var set display name is transformed correctly");
7397 });
7398
7399 SaraTest.test("Update var set via Importset", function() {
7400 var existingVarSet = glideHelper.getData("item_option_new_set", {name: varSetName});
7401 SaraTest.assert(existingVarSet !== undefined, "var set is get correctly");
7402
7403 glideHelper.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7404 id: existingVarSet.sys_id,
7405 name: varSetName,
7406 title: varSetTitleNew,
7407 description: varSetDescriptionNew
7408 });
7409
7410 var varSets = glideHelper.getData("item_option_new_set", {"name": varSetName}, true);
7411
7412 SaraTest.assert(varSets.length === 1, "no new item is get correctly");
7413 var varSet = varSets[0];
7414 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7415 SaraTest.assert(varSet.name === varSetName, "var set name is transformed correctly");
7416 SaraTest.assert(varSet.title === varSetTitleNew, "var set title is updated correctly");
7417 SaraTest.assert(varSet.description === varSetDescriptionNew, "var set description is updated correctly");
7418 });
7419 },
7420
7421 testPersistCatelogVariableSet : function() {
7422 var varSetName = "snsc test variable set " + SaraUtils.getRandom();
7423 var varSetTitle = "title";
7424 var varSetDescription = "test description";
7425 var varSetDisplayName = "display name";
7426
7427 var newCategoryName = "snsc category " + SaraUtils.getRandom();
7428
7429 var catItemName = "snsc cat item " + SaraUtils.getRandom();
7430
7431 var gh = glideHelper;
7432
7433 gh.deleteData("item_option_new_set", {"name": ["CONTAINS", "snsc test"]}, true);
7434
7435 SaraTest.test("Persist catalog variable set via Importset", function() {
7436 gh.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7437 name: varSetName,
7438 title: varSetTitle,
7439 description: varSetDescription,
7440 display_name: varSetDisplayName
7441 });
7442
7443 var varSet = glideHelper.getData("item_option_new_set", {"name": varSetName});
7444
7445 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7446
7447 createCategory(newCategoryName);
7448 var newCat = getCategory(newCategoryName);
7449
7450 gs.info("new category id: " + newCat.sys_id);
7451
7452 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7453 name: catItemName,
7454 description: "new description",
7455 short_description: "new short description",
7456 use_sc_layout: true,
7457 no_quantity: true,
7458 category: newCat.sys_id,
7459 active: true
7460 });
7461
7462 var catItem = gh.getData("sc_cat_item", {name: catItemName, category: newCat.sys_id});
7463 SaraTest.assert(catItem !== undefined, "cat item is transformed successfully");
7464
7465 //link item and varset via import set
7466 gh.persistData("x_ausgh_snsc_io_set_item_ist", {sc_cat_item: catItem.sys_id, variable_set: varSet.sys_id});
7467 //get real
7468 var catVarSet = gh.getData("io_set_item", {sc_cat_item: catItem.sys_id, variable_set: varSet.sys_id});
7469
7470 SaraTest.assert(catVarSet !== null, "catalog item variable is transformed correctly");
7471 SaraTest.assert(catVarSet.sc_cat_item === catItem.sys_id, "cat item is set correctly");
7472 SaraTest.assert(catVarSet.variable_set === varSet.sys_id, "var set is set correctly");
7473 });
7474 },
7475
7476 testPersistSaraDefinition : function() {
7477 var newCategoryName = "snsc test category " + SaraUtils.getRandom();
7478 var parentCategoryName = "snsc test parent category " + SaraUtils.getRandom();
7479
7480 var varSetName = "snsc test var set" + SaraUtils.getRandom();
7481
7482 var definitionName1 = "snsc test" + SaraUtils.getRandom();
7483 var definitionName2 = "snsc test" + SaraUtils.getRandom();
7484 var definitionName3 = "snsc test" + SaraUtils.getRandom();
7485
7486 var catItemName1 = "snsc test cat item" + SaraUtils.getRandom();
7487
7488 var consume_url1 = "http://automictest.com";
7489 var consume_url2 = "http://automictest2.com";
7490 var hash1 = "FDSGHERGGGGFGFGDGFS";
7491 var hash2 = "FDSFFSDHASAFGFGDGFS";
7492
7493 var gh = glideHelper;
7494
7495 gh.deleteData("x_ausgh_snsc_sara_definition", {"name": ["CONTAINS", "snsc test"]}, true);
7496
7497 SaraTest.test("Persist sara definition for catalog item via Importset", function() {
7498 createCategory(parentCategoryName);
7499 var parentCat = getCategory(parentCategoryName);
7500 SaraTest.assert(parentCat !== null, "parentCat is transformed correctly");
7501
7502 createCategory(newCategoryName);
7503 var newCat = getCategory(newCategoryName);
7504 SaraTest.assert(newCat !== null, "newCat is transformed correctly");
7505
7506 //create var set
7507 gh.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7508 name: varSetName,
7509 title: "title",
7510 description: "description",
7511 display_name: "whatever"
7512 });
7513
7514 var varSet = gh.getData("item_option_new_set", {"name": varSetName});
7515 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7516
7517 //create catalog item
7518 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7519 name: catItemName1,
7520 description: "new description",
7521 short_description: "new short description",
7522 use_sc_layout: true,
7523 no_quantity: true,
7524 category: newCat.sys_id,
7525 active: true
7526 });
7527
7528 var catItem = gh.getData("sc_cat_item", {name: catItemName1, category: newCat.sys_id});
7529 SaraTest.assert(catItem !== null, "catItem is transformed correctly");
7530
7531 gh.persistData("x_ausgh_snsc_sara_definition_ist", {
7532 u_name: definitionName1,
7533 u_consume_url: consume_url1,
7534 u_sc_item: catItem.sys_id,
7535 u_service_catalog_category: newCat.sys_id,
7536 u_var_set: varSet.sys_id,
7537 u_parent: parentCat.sys_id,
7538 u_type: "service",
7539 u_hash: hash1
7540 });
7541 var saraDefinition = gh.getData("x_ausgh_snsc_sara_definition_ist", {u_name: definitionName1, u_parent: parentCat.sys_id});
7542
7543 SaraTest.assert(saraDefinition !== null, "saraDefinition is transformed correctly");
7544 gs.info("saraDefinition: " + SaraJSON.stringify(saraDefinition));
7545 SaraTest.assert(saraDefinition.u_name === definitionName1, "u_name is transformed correctly");
7546 SaraTest.assert(saraDefinition.u_consume_url === consume_url1, "consume_url is transformed correctly");
7547 SaraTest.assert(saraDefinition.u_sc_item === catItem.sys_id, "u_sc_item is transformed correctly");
7548 SaraTest.assert(saraDefinition.u_service_catalog_category === newCat.sys_id, "u_service_catalog_category is transformed correctly");
7549 SaraTest.assert(saraDefinition.u_var_set === varSet.sys_id, "u_var_set is transformed correctly");
7550 SaraTest.assert(saraDefinition.u_parent === parentCat.sys_id, "u_parent is transformed correctly");
7551 SaraTest.assert(saraDefinition.u_type === "service", "u_type is transformed correctly");
7552 SaraTest.assert(saraDefinition.u_hash === hash1, "u_hash is transformed correctly");
7553 });
7554 }
7555 };
7556})();
7557
7558var SaraTest = (function() {
7559 var indent = "";
7560 var logger = new SaraLog("SaraTest");
7561 var pass = 0;
7562 var fail = 0;
7563 var isIgnore = false;
7564 var ignored = 0;
7565 var continueOnError = true;
7566
7567 var log = function() {
7568 logger.info.apply(logger,arguments);
7569 };
7570
7571 return {
7572 resetSummary: function() {
7573 pass = 0;
7574 fail = 0;
7575 ignored = 0;
7576 },
7577
7578 disableContinueOnError:function() {
7579 continueOnError = false;
7580 },
7581
7582 getSummary: function() {
7583 return {
7584 pass: pass,
7585 fail: fail,
7586 ignore: ignored,
7587 total: pass + fail + ignored
7588 };
7589 },
7590
7591 ignore: function() {
7592 isIgnore = true;
7593 },
7594
7595 assert: function(value, desc) {
7596 var prefix = ">>>PASS: ";
7597 if(!value) {
7598 prefix = "<<<FAIL: ";
7599 }
7600 logger.info("{0}{1}{2}", indent, prefix, desc);
7601 if(!value) {
7602 var exceptionMsg = prefix + desc;
7603 throw new Error(exceptionMsg);
7604 }
7605 },
7606 assertEqual: function(actual, expected, desc) {
7607 var failed = false;
7608 var prefix = ">>>PASS: ";
7609 if(actual != expected) {
7610 prefix = "<<<FAIL: ";
7611 failed = true;
7612 }
7613 logger.info("{0}{1}{2}", indent, prefix, desc);
7614 if(failed) {
7615 logger.info("Expected: {0}; Actual: {1}", expected, actual);
7616 }
7617 if(failed) {
7618 var exceptionMsg = prefix + desc + "; Expected:" + expected + "; Actual: " + actual
7619
7620 throw new Error(exceptionMsg);
7621 }
7622 },
7623 test: function(name, fn) {
7624 indent = "";
7625 logger.info("********************************");
7626 if(isIgnore) {
7627 logger.info("[IGNORE] {0}", name);
7628 isIgnore = false;
7629 ignored++;
7630 return;
7631 }
7632 logger.info("[TEST CASE] {0}", name);
7633 indent = " ";
7634
7635 if(continueOnError) {
7636 try {
7637 fn();
7638 pass++;
7639 }
7640 catch(err) {
7641 gs.error(err);
7642 fail++;
7643 }
7644 }
7645 else {
7646 fn();
7647 pass++;
7648 }
7649
7650 indent = "";
7651 },
7652 type: "SaraTest"
7653 };
7654})();
7655]]></script>
7656 <description>Sara Test Bench</description>
7657 <active>true</active>
7658 <client_callable>false</client_callable>
7659 <access>public</access>
7660 </script_include>
7661</script_includes>
7662
7663
7664 <ui_scripts>
7665 <ui_script>
7666 <script_name>SaraVarSet</script_name>
7667 <script><![CDATA[/**
7668 * Catalog client script for SaraVariableSet
7669 */
7670var x_ausgh_snsc = x_ausgh_snsc || {};
7671x_ausgh_snsc.SaraVarSet = x_ausgh_snsc.SaraVarSet || {};
7672
7673(function (SaraVarSet) {
7674 'use strict';
7675
7676 /**
7677 * OnLoad event handler for Sara variable set
7678 */
7679 SaraVarSet.onLoad = function () {
7680 SaraVarSet.initListCollector();
7681 SaraVarSet.setSelectBoxWidth();
7682 };
7683
7684 /**
7685 * Init collector filter
7686 */
7687 SaraVarSet.initListCollector = function () {
7688 x_ausgh_snsc.log('Start: SaraVarSet.initListCollector');
7689 var messageTables = $$('[id$=_select_0_add_remove_message_table]');
7690 var listWrappers = $$('.list_name');
7691
7692 for (var i = 0, table; table = messageTables[i]; i++) {
7693 var name = table.id.replace('_select_0_add_remove_message_table', '');
7694 var wrapper = listWrappers[i];
7695 var target;
7696 var id;
7697
7698 if (wrapper) {
7699 target = wrapper;
7700 } else {
7701 target = table;
7702 }
7703
7704 id = target.nextSibling.id.replace('IO:', '');
7705
7706 SaraVarSet.getListCollectorData(id, name);
7707 }
7708
7709 x_ausgh_snsc.log('End: SaraVarSet.initListCollector');
7710 };
7711
7712 /**
7713 * Get list collector data from lookup table
7714 * @param {String} id The sys_id of list collector
7715 * @param {String} name The name of list collector
7716 */
7717 SaraVarSet.getListCollectorData = function (id, name) {
7718 var filterFn = name + 'g_filter';
7719 var acRequestFn = name + 'acRequest';
7720
7721 if (window[filterFn] === undefined || window[acRequestFn] === undefined) {
7722 setTimeout(function () {
7723 SaraVarSet.getListCollectorData(id, name);
7724 }, 100);
7725 return;
7726 }
7727
7728 window[filterFn].reset();
7729 window[filterFn].setQuery('u_control_id=' + id);
7730 window[acRequestFn](null);
7731 };
7732
7733 /**
7734 * Make all selecbox's width is 250px for preventing the broken of layout when value of option is too long
7735 */
7736 SaraVarSet.setSelectBoxWidth = function () {
7737 x_ausgh_snsc.log('Start: SaraVarSet.setSelectBoxWidth');
7738 var selectboxes = $$('select.cat_item_option');
7739
7740 for (var i = 0, selectbox; selectbox = selectboxes[i]; i++) {
7741 selectbox.style.width = '250px';
7742 }
7743
7744 x_ausgh_snsc.log('End: SaraVarSet.setSelectBoxWidth');
7745 };
7746
7747})(x_ausgh_snsc.SaraVarSet);
7748]]></script>
7749 <description>Catalog client script for SaraVariableSet</description>
7750 <active>true</active>
7751 <global>false</global>
7752 </ui_script>
7753 <ui_script>
7754 <script_name>SaraCommon</script_name>
7755 <script><![CDATA[/**
7756 * Common client properties for Sara
7757 */
7758var SaraCommon = SaraCommon || {};
7759
7760var x_ausgh_snsc = x_ausgh_snsc || {};
7761x_ausgh_snsc.SaraCommon = x_ausgh_snsc.SaraCommon || {};
7762
7763x_ausgh_snsc.log = function () {
7764 if (typeof (console) !== 'undefined') {
7765 if (navigator.appName === 'Microsoft Internet Explorer') {
7766 if (arguments.length == 1) {
7767 console.log('[SARA]', arguments[0]);
7768 } else if (arguments.length === 2) {
7769 console.log('[SARA]', arguments[0], arguments[1]);
7770 } else if (arguments.length > 2) {
7771 console.log('[SARA]', arguments[0], arguments[1], arguments[2]);
7772 }
7773 } else {
7774 console.log('[SARA]', arguments);
7775 }
7776 }
7777};
7778
7779x_ausgh_snsc.config = x_ausgh_snsc.config || {};
7780
7781(function (SaraCommon) {
7782 'use strict';
7783
7784 SaraCommon.SCOPED_APP = 'x_ausgh_snsc';
7785
7786 SaraCommon.CONFIG_NAME = {
7787 CLIENT_ID: 'client_id',
7788 CLIENT_SECRET: 'client_secret',
7789 TECHNICAL_USER: 'technical_user',
7790 SAPI_ENDPOINT: 'sapi_endpoint',
7791 TOKEN_ENDPOINT: 'token_endpoint',
7792 AUTH_ENDPOINT: 'auth_endpoint'
7793 };
7794
7795 SaraCommon.CONTROL_NAME = {
7796 CLIENT_SCRIPTS: 'sara_client_scripts',
7797 HIDDEN_CONTROL: 'sara_hidden_control'
7798 };
7799
7800})(x_ausgh_snsc.SaraCommon);
7801]]></script>
7802 <description>Common client properties for Sara</description>
7803 <active>true</active>
7804 <global>false</global>
7805 </ui_script>
7806 <ui_script>
7807 <script_name>SaraOAuth</script_name>
7808 <script><![CDATA[/**
7809 * Client script for OAuth integration
7810 */
7811var x_ausgh_snsc = x_ausgh_snsc || {};
7812x_ausgh_snsc.SaraOAuth = x_ausgh_snsc.SaraOAuth || {};
7813
7814(function (SaraOAuth) {
7815 'use strict';
7816
7817 /**
7818 * Login to OAuth server for authentication
7819 * @param {String} clientId The client ID of OAuth Server
7820 * @param {String} technicalUser The tecnical user who owns the tokens
7821 * @param {String} authEndpoint The authorization endpoint of OAuth Server
7822 * @param {Object} callback The callback object contains onSuccess and onFail handler
7823 */
7824 SaraOAuth.login = function (clientId, technicalUser, authEndpoint, callback) {
7825 if (confirm('Technical User does not have tokens or Technical User\'s tokens are empty, invalid or expired. Do you want to open OAuth Authorization popup for getting new tokens?')) {
7826 SaraOAuth.processSuccess = null;
7827 SaraOAuth.processFail = null;
7828
7829 if (SaraOAuth.win) {
7830 SaraOAuth.win.close();
7831 }
7832 SaraOAuth.win = null;
7833
7834 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Getting OAuth url...');
7835 ga.addParam('sysparm_name', 'getOAuthUrl');
7836 ga.addParam('sysparm_client_id', clientId);
7837 ga.addParam('sysparm_technical_user', technicalUser);
7838 ga.addParam('sysparm_auth_endpoint', authEndpoint);
7839 ga.getXML(function (response) {
7840 if (callback && callback.onSuccess && typeof (callback.onSuccess) == 'function') {
7841 SaraOAuth.processSuccess = callback.onSuccess;
7842 }
7843
7844 if (callback && callback.onFail && typeof (callback.onFail) == 'function') {
7845 SaraOAuth.processFail = callback.onFail;
7846 }
7847
7848 var w = 500;
7849 var h = 600;
7850
7851 var left = (screen.width / 2) - (w / 2);
7852 var top = (screen.height / 2) - (h / 2);
7853
7854 var url = response.responseXML.documentElement.getAttribute('answer');
7855 SaraOAuth.win = window.open(url, 'aelogin', 'width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
7856 });
7857 }
7858 };
7859
7860 /**
7861 * Process response from OAuth server. If is 'ok', will call SaraOAuth.processSuccess callback.
7862 * If is not 'ok', will log the answer and alert message.
7863 * @param {*} response The response
7864 */
7865 SaraOAuth.processResponse = function (response) {
7866 if (SaraOAuth.win) {
7867 SaraOAuth.win.close();
7868 }
7869
7870 x_ausgh_snsc.log('Callback response is: ' + response);
7871
7872 if (response === 'ok') {
7873 if (SaraOAuth.processSuccess && typeof (SaraOAuth.processSuccess) == 'function') {
7874 SaraOAuth.processSuccess();
7875 }
7876 } else {
7877 var msg;
7878
7879 if (typeof (response) == 'string' && response.match('^function') != 'function') {
7880 msg = x_ausgh_snsc.SaraUtils.formatString('Token request finished unsuccessfully{0}. Please try again later or contact administrators.', response ? (', error: ' + response) : '');
7881 } else {
7882 msg = 'Token request finished unsuccessfully! Please try again later or contact administrators.';
7883 }
7884
7885 alert(msg);
7886
7887 if (SaraOAuth.processFail && typeof (SaraOAuth.processFail) == 'function') {
7888 SaraOAuth.processFail();
7889 }
7890
7891 x_ausgh_snsc.log(msg);
7892 }
7893 };
7894
7895 /**
7896 * Get configuration
7897 * @param {Function} callback The callback will be called when getting configuration
7898 * successfully with parametter is object with same keys with x_ausgh_snsc.SaraCommon.CONFIG_NAME
7899 */
7900 SaraOAuth.getConfig = function (callback) {
7901 var configData = {};
7902 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Getting OAuth configuration...');
7903 ga.addParam('sysparm_name', 'getConfig');
7904
7905 ga.getXML(function (resp) {
7906 var config = resp.responseXML.getElementsByTagName('config')[0];
7907
7908 for (var key in x_ausgh_snsc.SaraCommon.CONFIG_NAME) {
7909 var name = x_ausgh_snsc.SaraCommon.CONFIG_NAME[key];
7910
7911 configData[name] = config.getAttribute(name);
7912 }
7913
7914 callback.call(this, configData);
7915 });
7916 };
7917
7918 /**
7919 * Check OAuth Token of current technical user is invalid, expired or empty
7920 * @param {String} technicalUser The tecnical user who owns the tokens
7921 * @param {String} sapiEndpoint The SAPI endpoint
7922 * @param {Boolean} hideWizardSubmit Hide submit button of wizard or not when token is empty, expired
7923 * or invalid
7924 * @param {Object<String, Function>} callback The callback object contains callbacks when valid,
7925 * invalid, error:
7926 * - onValid(); // Will be called when tokens are existed and valid.
7927 * - onInvalid(); // Will be called when tokens are existed but invalid.
7928 * - onError(errorMessage); // Will be called when have any error. 'errorMessage' is error message
7929 * - onExisted(); // Will be called if current technical user has tokens but not validate the token yet.
7930 * SaraCommon.TABLE_NAME.SARA_OAUTH table
7931 */
7932 SaraOAuth.checkOAuthToken = function (technicalUser, sapiEndpoint, hideWizardSubmit, callback) {
7933 x_ausgh_snsc.log('checkOAuthToken', technicalUser, sapiEndpoint, hideWizardSubmit, callback);
7934
7935 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Validating token...');
7936 ga.addParam('sysparm_name', 'validateToken');
7937 ga.addParam('sysparm_technical_user', technicalUser);
7938 ga.addParam('sysparm_sapi_endpoint', sapiEndpoint);
7939
7940 ga.getXML(function (resp) {
7941 var result = resp.responseXML.getElementsByTagName('result')[0];
7942
7943 if (result) {
7944 var isValid = result.getAttribute('isValid');
7945
7946 // Valid
7947 if (isValid === 'true') {
7948 if (hideWizardSubmit) {
7949 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(true);
7950 }
7951
7952 x_ausgh_snsc.log('Access token is valid');
7953
7954 if (typeof callback.onValid === 'function') {
7955 callback.onValid.call(this);
7956 }
7957
7958 // Invalid
7959 } else if (isValid === 'false') {
7960 if (hideWizardSubmit) {
7961 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(false);
7962 }
7963
7964 x_ausgh_snsc.log('Access token is invalid');
7965
7966 if (typeof callback.onInvalid === 'function') {
7967 callback.onInvalid.call(this);
7968 }
7969
7970 // Error
7971 } else {
7972 var errorMessage = result.getAttribute('message');
7973 x_ausgh_snsc.log(errorMessage);
7974
7975
7976 if (typeof callback.onError === 'function') {
7977 callback.onError.call(this, errorMessage);
7978 }
7979 }
7980 } else {
7981 var error = resp.responseXML.getElementsByTagName('error')[0];
7982 var errorMessage;
7983
7984 if (error) {
7985 errorMessage = error.getAttribute('message');
7986 }
7987
7988 if (typeof callback.onError === 'function') {
7989 callback.onError.call(this, errorMessage);
7990 }
7991 }
7992 });
7993 };
7994
7995})(x_ausgh_snsc.SaraOAuth);
7996]]></script>
7997 <description>Client script for OAuth integration</description>
7998 <active>true</active>
7999 <global>false</global>
8000 </ui_script>
8001 <ui_script>
8002 <script_name>SaraUtils</script_name>
8003 <script><![CDATA[/**
8004 * Sara Utilities
8005 */
8006var x_ausgh_snsc = x_ausgh_snsc || {};
8007x_ausgh_snsc.SaraUtils = x_ausgh_snsc.SaraUtils || {};
8008
8009(function (SaraUtils) {
8010 'use strict';
8011
8012 /**
8013 * Format strings
8014 * @method format
8015 * @param {String} string The template string
8016 * @param {String[]} args Zero or more objects to format, supplied either in a comma-delimited list or as an array
8017 */
8018 SaraUtils.formatString = function (string) {
8019 var args = Array.prototype.slice.call(arguments, 1);
8020
8021 return string.replace(/{(\d+)}/g, function (match, number) {
8022 return typeof args[number] != 'undefined' ? args[number] : match;
8023 });
8024 };
8025
8026 /**
8027 * Get parameter value in current URL
8028 * @param {String} name The name of parameter
8029 * @return {String}
8030 */
8031 SaraUtils.getParmVal = function (name) {
8032 name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
8033 var regexS = '[\\?&]' + name + '=([^&#]*)';
8034 var regex = new RegExp(regexS);
8035 var results = regex.exec(window.location.href);
8036
8037 if (results == null) {
8038 return '';
8039 } else {
8040 return unescape(results[1]);
8041 }
8042 };
8043
8044 /**
8045 * Hide/show submit button of wizard
8046 * @param {Boolean} isVisible Submit button is visible or not
8047 */
8048 SaraUtils.setWizardSubmitVisible = function (isVisible) {
8049 document.getElementById('expert_next').style.display = isVisible ? '' : 'none';
8050 };
8051
8052 /**
8053 * Set visible of a form control
8054 * @param {String} name Name of control
8055 * @param {Boolean} isVisible Control is hidden or visible
8056 */
8057 SaraUtils.setFormControlVisible = function (name, isVisible) {
8058 if (g_form) {
8059 g_form.setDisplay(name, isVisible);
8060 }
8061 }
8062
8063})(x_ausgh_snsc.SaraUtils);
8064]]></script>
8065 <description>Sara Utilities</description>
8066 <active>true</active>
8067 <global>false</global>
8068 </ui_script>
8069 <ui_script>
8070 <script_name>SaraGlideAjax</script_name>
8071 <script><![CDATA[/**
8072 * Helper class wraps GlideAjax class of ServiceNow and provide Loading Dialog with custom title
8073 */
8074var x_ausgh_snsc = x_ausgh_snsc || {};
8075x_ausgh_snsc.SaraGlideAjax = x_ausgh_snsc.SaraGlideAjax || Class.create();
8076
8077(function (SaraGlideAjax) {
8078 'use strict';
8079
8080 SaraGlideAjax.prototype = {
8081 /**
8082 * Initialize SaraGlideAjax
8083 * @param {String} className The class name of callable Script Include
8084 * @param {String} title The title of loading dialog
8085 */
8086 initialize: function (className, title) {
8087 this.title = title;
8088 this.ga = new GlideAjax(className);
8089 this.ga.addParam('sysparm_scope', x_ausgh_snsc.SaraCommon.SCOPED_APP);
8090 this.className = className;
8091 },
8092
8093 /**
8094 * Add parameter for GlideAjax
8095 * @param {String} key The key of parameter
8096 * @param {String} value The value of parameter
8097 */
8098 addParam: function (key, value) {
8099 this.ga.addParam(key, value);
8100 },
8101
8102 /**
8103 * Get XML response from server
8104 * @param {Function} callback The callback will be call after getting response from server
8105 */
8106 getXML: function (callback) {
8107 var loadingDialog = new GlideDialogWindow('hierarchical_progress_viewer');
8108 loadingDialog.hideCloseButton();
8109 loadingDialog.setTitle(this.title);
8110
8111 var className = this.className;
8112 x_ausgh_snsc.log('Sending request to ' + className + '...');
8113
8114 this.ga.getXML(function (response) {
8115 loadingDialog.destroy();
8116 x_ausgh_snsc.log('Got response from ' + className, response);
8117
8118 if (typeof callback === 'function') {
8119 callback.apply(this, arguments);
8120 }
8121 });
8122 },
8123
8124 type: 'SaraGlideAjax'
8125 };
8126
8127})(x_ausgh_snsc.SaraGlideAjax);
8128]]></script>
8129 <description>Helper class wraps GlideAjax class of ServiceNow and provide Loading Dialog with custom title</description>
8130 <active>true</active>
8131 <global>false</global>
8132 </ui_script>
8133</ui_scripts>
8134
8135
8136 <ui_pages>
8137 <ui_page>
8138 <name>sara_oauth_callback</name>
8139 <description>OAuth Redirection Endpoint</description>
8140 <category>general</category>
8141 <html><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
8142<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
8143 <g:requires name="x_ausgh_snsc.SaraCommon.jsdbx" params="cache=$[jvar_stamp]" />
8144 <g:requires name="x_ausgh_snsc.SaraGlideHelper.jsdbx" params="cache=$[jvar_stamp]" />
8145 <g:requires name="x_ausgh_snsc.SaraGlideAjax.jsdbx" params="cache=$[jvar_stamp]" />
8146 <g:requires name="x_ausgh_snsc.SaraOAuth.jsdbx" params="cache=$[jvar_stamp]" />
8147 <g:requires name="x_ausgh_snsc.SaraUtils.jsdbx" params="cache=$[jvar_stamp]" />
8148 <g:requires name="x_ausgh_snsc.SaraVarSet.jsdbx" params="cache=$[jvar_stamp]" />
8149
8150 <g:ui_form>
8151 <p>
8152 <label>Please wait, processing...</label>
8153 </p>
8154 </g:ui_form>
8155</j:jelly>
8156]]></html>
8157 <client_script><![CDATA[var parentWin = (window.opener && window.opener.x_ausgh_snsc.SaraOAuth) ? window.opener : window.parent;
8158
8159if (!parentWin || !parentWin.x_ausgh_snsc || !parentWin.x_ausgh_snsc.SaraOAuth || !parentWin.x_ausgh_snsc.SaraOAuth.processResponse || typeof(parentWin.x_ausgh_snsc.SaraOAuth.processResponse) !== 'function') {
8160 window.location.href = '/home.do';
8161} else {
8162 var code = x_ausgh_snsc.SaraUtils.getParmVal('code');
8163 x_ausgh_snsc.log('Code: ' + code);
8164
8165 if (code) {
8166 var clientId = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID];
8167 var clientSecret = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_SECRET];
8168 var technicalUser = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER];
8169 var tokenEndpoint = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
8170
8171 x_ausgh_snsc.log('Client ID: ' + clientId, 'Client Secret: ' + clientSecret, 'Token Endpoint: ' + tokenEndpoint)
8172
8173 // Invoke x_ausgh_snsc.SaraOAuthAjax to exchange code for tokens
8174 x_ausgh_snsc.log('Init GlideAjax for requesting token by code...');
8175 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Requesting token by code...');
8176 ga.addParam('sysparm_name', 'requestTokenByCode');
8177 ga.addParam('sysparm_code', code);
8178 ga.addParam('sysparm_client_id', clientId);
8179 ga.addParam('sysparm_client_secret', clientSecret);
8180 ga.addParam('sysparm_technical_user', technicalUser);
8181 ga.addParam('sysparm_token_endpoint', tokenEndpoint);
8182
8183 ga.getXML(function (response) {
8184 var answer = response.responseXML.documentElement.getAttribute('answer');
8185 parentWin.x_ausgh_snsc.SaraOAuth.processResponse(answer);
8186 });
8187 } else {
8188 x_ausgh_snsc.log('Code is empty!');
8189 parentWin.x_ausgh_snsc.SaraOAuth.processResponse();
8190 }
8191}
8192]]></client_script>
8193 <processing_script/>
8194 </ui_page>
8195</ui_pages>
8196
8197
8198 <ui_macros>
8199 <ui_macro>
8200 <name>sara_hidden_control</name>
8201 <description>UI Marco for Sara Hidden Control</description>
8202 <category>catalog</category>
8203 <active>true</active>
8204 <media_type/>
8205 <xml><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
8206<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
8207 <script type="text/javascript">
8208 $j(function () {
8209 x_ausgh_snsc.SaraUtils.setFormControlVisible(x_ausgh_snsc.SaraCommon.CONTROL_NAME.HIDDEN_CONTROL, false);
8210 x_ausgh_snsc.SaraVarSet.onLoad();
8211 });
8212 </script>
8213</j:jelly>
8214]]></xml>
8215 </ui_macro>
8216 <ui_macro>
8217 <name>sara_client_scripts</name>
8218 <description/>
8219 <category>catalog</category>
8220 <active>true</active>
8221 <media_type/>
8222 <xml><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
8223<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
8224 <g:requires name="x_ausgh_snsc.SaraCommon.jsdbx" params="cache=$[jvar_stamp]" />
8225 <g:requires name="x_ausgh_snsc.SaraGlideAjax.jsdbx" params="cache=$[jvar_stamp]" />
8226 <g:requires name="x_ausgh_snsc.SaraOAuth.jsdbx" params="cache=$[jvar_stamp]" />
8227 <g:requires name="x_ausgh_snsc.SaraUtils.jsdbx" params="cache=$[jvar_stamp]" />
8228 <g:requires name="x_ausgh_snsc.SaraVarSet.jsdbx" params="cache=$[jvar_stamp]" />
8229
8230 <script type="text/javascript">
8231 $j(function () {
8232 x_ausgh_snsc.SaraUtils.setFormControlVisible(x_ausgh_snsc.SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS, false);
8233 });
8234 </script>
8235</j:jelly>
8236]]></xml>
8237 </ui_macro>
8238</ui_macros>
8239
8240
8241 <workflows>
8242 <workflow>
8243 <name>Sara Service</name>
8244 <description>Sara Service workflow</description>
8245 <start>begin</start>
8246 <table>sc_req_item</table>
8247 <active>true</active>
8248 <published>true</published>
8249 <max_activity_count>1000000</max_activity_count>
8250
8251
8252 <stages>
8253 <stage>
8254 <name>Initializing</name>
8255 <order>100</order>
8256 <value>initializing</value>
8257 <ola/>
8258 </stage>
8259 <stage>
8260 <name>Transferring</name>
8261 <order>200</order>
8262 <value>transferring</value>
8263 <ola/>
8264 </stage>
8265 <stage>
8266 <name>Transferred</name>
8267 <order>300</order>
8268 <value>transferred</value>
8269 <ola/>
8270 </stage>
8271 <stage>
8272 <name>Transfer Failed</name>
8273 <order>300</order>
8274 <value>transfer_failed</value>
8275 <ola/>
8276 </stage>
8277 <stage>
8278 <name>Consume Failed</name>
8279 <order>400</order>
8280 <value>consume_failed</value>
8281 <ola/>
8282 </stage>
8283 <stage>
8284 <name>Running</name>
8285 <order>500</order>
8286 <value>running</value>
8287 <ola/>
8288 </stage>
8289 <stage>
8290 <name>Ended OK</name>
8291 <order>900</order>
8292 <value>ended_ok</value>
8293 <ola/>
8294 </stage>
8295 <stage>
8296 <name>Ended Failed</name>
8297 <order>900</order>
8298 <value>ended_failed</value>
8299 <ola/>
8300 </stage>
8301 <stage>
8302 <name>Completed</name>
8303 <order>1000</order>
8304 <value>completed</value>
8305 <ola/>
8306 </stage>
8307</stages>
8308
8309
8310
8311 <activities>
8312 <activity>
8313 <name>Begin</name>
8314 <activity_definition>Begin</activity_definition>
8315 <stage/>
8316 <width/>
8317 <height/>
8318 <x>1</x>
8319 <y>1</y>
8320 <snsc_name>begin</snsc_name>
8321 </activity>
8322
8323 <activity>
8324 <name>Check item's price is 0 or not?</name>
8325 <activity_definition>If</activity_definition>
8326 <stage/>
8327 <width/>
8328 <height/>
8329 <x>1</x>
8330 <y>2</y>
8331 <snsc_name>check_price</snsc_name>
8332 <variables>
8333 <variable>
8334 <name>script</name>
8335 <value><![CDATA[function ifScript() {
8336 var item = (new x_ausgh_snsc.SaraGlideHelper()).getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_CATALOG_ITEM, {
8337 'sys_id': current.cat_item.sys_id
8338 });
8339
8340 if ((item.price.toString()) === '0') {
8341 return 'yes';
8342 }
8343
8344 return 'no';
8345}
8346
8347answer = ifScript();
8348]]></value>
8349 </variable>
8350 <variable>
8351 <name>advanced</name>
8352 <value>1</value>
8353 </variable>
8354 </variables>
8355 </activity>
8356
8357 <activity>
8358 <name>Waiting for approval</name>
8359 <activity_definition>Approval - Group</activity_definition>
8360 <stage/>
8361 <width/>
8362 <height/>
8363 <x>1</x>
8364 <y>3</y>
8365 <snsc_name>waiting_for_approval</snsc_name>
8366 <variables>
8367 <variable>
8368 <name>wait_for</name>
8369 <value>first_any</value>
8370 </variable>
8371 <variable>
8372 <name>reject_handling</name>
8373 <value>reject</value>
8374 </variable>
8375 </variables>
8376 </activity>
8377
8378 <activity>
8379 <name>Approved</name>
8380 <activity_definition>Approval Action</activity_definition>
8381 <stage/>
8382 <width/>
8383 <height/>
8384 <x>2</x>
8385 <y>3</y>
8386 <snsc_name>approved</snsc_name>
8387 <variables>
8388 <variable>
8389 <name>action</name>
8390 <value>approved</value>
8391 </variable>
8392 </variables>
8393 </activity>
8394
8395 <activity>
8396 <name>Rejected</name>
8397 <activity_definition>Approval Action</activity_definition>
8398 <stage/>
8399 <width/>
8400 <height/>
8401 <x>1</x>
8402 <y>4</y>
8403 <snsc_name>rejected</snsc_name>
8404 <variables>
8405 <variable>
8406 <name>action</name>
8407 <value>rejected</value>
8408 </variable>
8409 </variables>
8410 </activity>
8411
8412 <activity>
8413 <name>Initializing</name>
8414 <activity_definition>Timer</activity_definition>
8415 <stage>initializing</stage>
8416 <width/>
8417 <height/>
8418 <x>3</x>
8419 <y>3</y>
8420 <snsc_name>initializing</snsc_name>
8421 <variables>
8422 <variable>
8423 <name>timer_type</name>
8424 <value>script</value>
8425 </variable>
8426 <variable>
8427 <name>script</name>
8428 <value><![CDATA[workflow.info('Initializing ...');
8429var currentUser = current.opened_by.user_name.toString();
8430workflow.info('Workflow started by {0}', currentUser);
8431workflow.scratchpad.openedBy = currentUser;
8432
8433var technicalUser = new x_ausgh_snsc.SaraConfig().getTechnicalUser();
8434workflow.info('Technical user: {0}', technicalUser);
8435workflow.scratchpad.technicalUser = technicalUser;
8436
8437// Set 'answer' to the number of seconds this timer should wait
8438answer = 2;
8439]]></value>
8440 </variable>
8441 </variables>
8442 </activity>
8443
8444 <activity>
8445 <name>Invoke Consume URL</name>
8446 <activity_definition>Run Script</activity_definition>
8447 <stage>transferring</stage>
8448 <width/>
8449 <height/>
8450 <x>4</x>
8451 <y>3</y>
8452 <snsc_name>invoke_consume</snsc_name>
8453 <variables>
8454 <variable>
8455 <name>script</name>
8456 <value><![CDATA[var restClient = new x_ausgh_snsc.SaraRESTClient();
8457restClient.setMIDServer(x_ausgh_snsc.SaraUtils.getMIDServer());
8458var oauthClient = new x_ausgh_snsc.SaraOAuthClient(restClient);
8459var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
8460
8461// Get tokens, store tokens in workflow scratchpad
8462var tokens = oauthClient.getUserTokens(workflow.scratchpad.technicalUser);
8463
8464if (!tokens) {
8465 workflow.info('Cannot find access tokens for this user "{0}". Order will be skipped', workflow.scratchpad.technicalUser);
8466} else {
8467 workflow.scratchpad.executionHref = null;
8468 workflow.scratchpad.isTransfered = false;
8469
8470 // get service name & consume URL
8471 var serviceName, consumeUrl, varSetId;
8472 var catId = current.cat_item.sys_id;
8473 var saraItem = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_DEFINITION, {
8474 'u_sc_item': catId
8475 });
8476
8477 if (saraItem) {
8478 serviceName = saraItem['u_name'];
8479 consumeUrl = saraItem['u_consume_url'];
8480 varSetId = saraItem['u_var_set'];
8481
8482 consumeUrl = x_ausgh_snsc.SaraUtils.buildUrl(consumeUrl);
8483
8484 workflow.info('Service name = {0}', serviceName);
8485 workflow.info('Consume URL = {0}', consumeUrl);
8486 workflow.info('Cat item = {0}', current.cat_item.name);
8487
8488 var payload = {};
8489 var payloadFields = {};
8490 payload.fieldvalues = payloadFields;
8491
8492 if (varSetId) {
8493 var saraVariables = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_VARIABLE, {
8494 'variable_set': varSetId
8495 }, true);
8496
8497 for (var i = 0, variable; variable = saraVariables[i]; i++) {
8498 var variableName = variable['name'];
8499
8500 if (variableName !== x_ausgh_snsc.SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS
8501 && variableName !== x_ausgh_snsc.SaraCommon.CONTROL_NAME.HIDDEN_CONTROL
8502 && variable['u_name']) {
8503
8504 var currentVariable = current.variables[variableName];
8505 var currentValue;
8506
8507 if (variable['type'] === x_ausgh_snsc.SaraCommon.VAR_TYPE.LIST_COLLECTOR.toString()) {
8508 var values = currentVariable.toString().split(',');
8509 currentValue = [];
8510
8511 for (var j = 0, value; value = values[j]; j++) {
8512 var realValue = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_LOOKUP, {
8513 'sys_id': value
8514 });
8515
8516 currentValue.push(realValue['u_display_name']);
8517 }
8518 } else {
8519 currentValue = [currentVariable.getDisplayValue()];
8520 }
8521
8522 payloadFields[variable['u_name']] = currentValue;
8523 }
8524 }
8525 } else {
8526 workflow.info('There is no variables in catalog item (sys_id = {0})', catId);
8527 }
8528
8529 //---------------- audit information ---------------
8530 workflow.info('Add audit information');
8531
8532 var payloadParams = {};
8533 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.ORDER_ID] = current.request.number.toString();
8534 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.ORDER_TIMESTAMP] = current.sys_created_on.toString();
8535 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.ORDER_NAME] = current.sys_created_by.toString();
8536
8537 var approvalHistory = '<<Auto Approval>>';
8538
8539 if(current.approval_history != null) {
8540 var journal = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_JOURNAL_FIELD, {
8541 'element_id' : current.sys_id
8542 });
8543 if(journal != null) {
8544 approvalHistory = journal.value.toString();
8545 }
8546 }
8547
8548 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.APPROVAL_HISTORY] = approvalHistory;
8549 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.APPROVAL_TIMESTAMP] = current.approval_set.toString();
8550
8551 payload.parametervalues = payloadParams;
8552 //--------------- /audit information ---------------
8553
8554 var payloadStr = x_ausgh_snsc.SaraJSON.stringify(payload);
8555 workflow.info(payloadStr);
8556
8557 // Make request
8558 if (serviceName) {
8559 workflow.info('Invoking consume URL...');
8560
8561 var request = restClient.newSAPIRequest('post', consumeUrl);
8562 request.setContent('${payload}');
8563 request.addHeader('content-type', 'application/json;charset=UTF-8');
8564 request.setStringParameterNoEscape('payload', payloadStr);
8565
8566 // Add Authorization header
8567 request.addHeader('Authorization', tokens[3] + ' ' + tokens[0]);
8568
8569 var response = restClient.executeWithRefreshToken(request);
8570 var responseObject = response.getResponseObject();
8571
8572 if (response.haveError()) {
8573 workflow.info('Order process FAILED.');
8574 } else {
8575 workflow.info('Successfully transfered.');
8576 workflow.info('Response: {0}', response.getBody());
8577 var resObj = x_ausgh_snsc.SaraJSON.parse(response.getBody());
8578 var runId = resObj['runID'];
8579
8580 workflow.scratchpad.isTransfered = true;
8581
8582 if (runId !== undefined) {
8583 var executionHref = resObj['_links']['self']['href'];
8584 workflow.info('Got runId: {0}', runId.toString());
8585 workflow.info('Got execution href: {0}', executionHref);
8586 workflow.scratchpad.runId = runId;
8587 workflow.scratchpad.executionHref = executionHref;
8588
8589 // save runId to the 'correlation_id' column of current record in 'sc_req_item' table
8590 current['correlation_id'] = '' + runId;
8591 current.update();
8592 } else {
8593 workflow.info(resObj.message);
8594 }
8595 }
8596
8597 } else {
8598 workflow.info('Failed to make consume request as no service definition was defined.');
8599 }
8600 } else {
8601 workflow.info('Catalog item (sys_id = {0}) doesn\'t existed any more in {1}!', [catId, x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_DEFINITION]);
8602 }
8603}
8604]]></value>
8605 </variable>
8606 </variables>
8607 </activity>
8608
8609 <activity>
8610 <name>Check transfer result</name>
8611 <activity_definition>If</activity_definition>
8612 <stage>transferred</stage>
8613 <width/>
8614 <height/>
8615 <x>5</x>
8616 <y>3</y>
8617 <snsc_name>check_transfer</snsc_name>
8618 <variables>
8619 <variable>
8620 <name>script</name>
8621 <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
8622//
8623// For example,
8624//
8625answer = ifScript();
8626
8627function ifScript() {
8628 return (workflow.scratchpad.isTransfered == true ? 'yes' : 'no');
8629}
8630]]></value>
8631 </variable>
8632 <variable>
8633 <name>advanced</name>
8634 <value>1</value>
8635 </variable>
8636 </variables>
8637 </activity>
8638
8639 <activity>
8640 <name>Transfer Request Failed</name>
8641 <activity_definition>Log Message</activity_definition>
8642 <stage>transfer_failed</stage>
8643 <width/>
8644 <height/>
8645 <x>5</x>
8646 <y>4</y>
8647 <snsc_name>transfer_failed</snsc_name>
8648 <variables>
8649 <variable>
8650 <name>message</name>
8651 <value>Transfer request failed, order skipped.</value>
8652 </variable>
8653 </variables>
8654 </activity>
8655
8656 <activity>
8657 <name>Check consume result</name>
8658 <activity_definition>If</activity_definition>
8659 <stage>transferred</stage>
8660 <width/>
8661 <height/>
8662 <x>6</x>
8663 <y>4</y>
8664 <snsc_name>check_consume</snsc_name>
8665 <variables>
8666 <variable>
8667 <name>script</name>
8668 <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
8669//
8670// For example,
8671//
8672answer = ifScript();
8673
8674function ifScript() {
8675 return (workflow.scratchpad.executionHref != null ? 'yes' : 'no');
8676}
8677]]></value>
8678 </variable>
8679 <variable>
8680 <name>advanced</name>
8681 <value>1</value>
8682 </variable>
8683 </variables>
8684 </activity>
8685
8686 <activity>
8687 <name>Consume Request Failed</name>
8688 <activity_definition>Log Message</activity_definition>
8689 <stage>consume_failed</stage>
8690 <width/>
8691 <height/>
8692 <x>6</x>
8693 <y>5</y>
8694 <snsc_name>consume_failed</snsc_name>
8695 <variables>
8696 <variable>
8697 <name>message</name>
8698 <value>Consume request failed, order skipped.</value>
8699 </variable>
8700 </variables>
8701 </activity>
8702
8703 <activity>
8704 <name>Workflow Timer</name>
8705 <activity_definition>Timer</activity_definition>
8706 <stage>running</stage>
8707 <width/>
8708 <height/>
8709 <x>7</x>
8710 <y>5</y>
8711 <snsc_name>workflow_timer</snsc_name>
8712 <variables>
8713 <variable>
8714 <name>timer_type</name>
8715 <value>script</value>
8716 </variable>
8717 <variable>
8718 <name>script</name>
8719 <value><![CDATA[if (workflow.scratchpad.delay === undefined) {
8720 var delay = +x_ausgh_snsc.SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.WORKFLOW_DELAY);
8721 var timeout = +x_ausgh_snsc.SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.WORKFLOW_TIMEOUT);
8722
8723 // If delay time in config is equal or lesser than 0, let make it '60'
8724 if (delay <= 0) {
8725 delay = 60;
8726 }
8727
8728 // Make sure that timeout minimum always be '0'
8729 if (timeout < 0) {
8730 timeout = 0;
8731 }
8732
8733 workflow.scratchpad.counter = 1;
8734 workflow.scratchpad.maxCount = (timeout / delay) + 1;
8735 workflow.scratchpad.delay = delay;
8736 workflow.scratchpad.timeout = timeout;
8737}
8738
8739answer = workflow.scratchpad.delay;
8740]]></value>
8741 </variable>
8742 </variables>
8743 </activity>
8744
8745 <activity>
8746 <name>Retrieve Execution Status</name>
8747 <activity_definition>Run Script</activity_definition>
8748 <stage>running</stage>
8749 <width/>
8750 <height/>
8751 <x>8</x>
8752 <y>5</y>
8753 <snsc_name>retrieve_status</snsc_name>
8754 <variables>
8755 <variable>
8756 <name>script</name>
8757 <value><![CDATA[var restClient = new x_ausgh_snsc.SaraRESTClient();
8758restClient.setMIDServer(x_ausgh_snsc.SaraUtils.getMIDServer());
8759var oauthClient = new x_ausgh_snsc.SaraOAuthClient(restClient);
8760var executionHref = x_ausgh_snsc.SaraUtils.buildUrl(workflow.scratchpad.executionHref);
8761
8762workflow.scratchpad.ended = 'unknown';
8763
8764// Get tokens, store tokens in workflow scratchpad
8765var tokens = oauthClient.getUserTokens(workflow.scratchpad.technicalUser);
8766var request = restClient.newSAPIRequest('get', executionHref);
8767request.addHeader('Authorization', tokens[3] + ' ' + tokens[0]);
8768
8769workflow.info('[{0}] Waiting for execution checking response ...', workflow.scratchpad.counter);
8770var response = restClient.executeWithRefreshToken(request);
8771var responseObject = response.getResponseObject();
8772
8773if (response.haveError()) {
8774 workflow.warn('Status code: {0}, error message: {1}', [responseObject.statusCode, responseObject.errorMessage]);
8775
8776 workflow.info('Stop retrieving execution status now.');
8777} else {
8778 workflow.info('Response received: {0}', response.getBody());
8779 var resObj = responseObject.bodyObject;
8780 var statusCode = resObj.statusCode;
8781 workflow.info('Status code: {0}, statusText: {1}', [statusCode.toString(), resObj.statusText]);
8782
8783 if (statusCode >= 1800) {
8784 if (statusCode === x_ausgh_snsc.SaraCommon.WORKFLOW_STATUS_CODE.ENDED_OK) {
8785 workflow.info('Execution finished successfully!');
8786 workflow.scratchpad.ended = 'ENDED_OK';
8787 } else {
8788 workflow.scratchpad.ended = statusCode + ' - ' + resObj.statusText;
8789 }
8790 }
8791}
8792
8793workflow.scratchpad.counter++;
8794]]></value>
8795 </variable>
8796 </variables>
8797 </activity>
8798
8799 <activity>
8800 <name>Check Timeout</name>
8801 <activity_definition>If</activity_definition>
8802 <stage>running</stage>
8803 <width/>
8804 <height/>
8805 <x>9</x>
8806 <y>5</y>
8807 <snsc_name>check_timeout</snsc_name>
8808 <variables>
8809 <variable>
8810 <name>script</name>
8811 <value><![CDATA[function ifScript() {
8812 var counter = workflow.scratchpad.counter;
8813 var maxCount = workflow.scratchpad.maxCount;
8814 var timeout = workflow.scratchpad.timeout;
8815
8816 if (timeout === 0) {
8817 if (workflow.scratchpad.ended !== 'unknown') {
8818 return 'yes';
8819 }
8820 } else {
8821 if (counter <= maxCount) {
8822 if (workflow.scratchpad.ended !== 'unknown') {
8823 return 'yes';
8824 }
8825 } else {
8826 return 'yes';
8827 }
8828 }
8829
8830 return 'no';
8831}
8832
8833answer = ifScript();
8834]]></value>
8835 </variable>
8836 <variable>
8837 <name>advanced</name>
8838 <value>1</value>
8839 </variable>
8840 </variables>
8841 </activity>
8842
8843 <activity>
8844 <name>Check Execution Result</name>
8845 <activity_definition>If</activity_definition>
8846 <stage>running</stage>
8847 <width/>
8848 <height/>
8849 <x>10</x>
8850 <y>6</y>
8851 <snsc_name>check_result</snsc_name>
8852 <variables>
8853 <variable>
8854 <name>script</name>
8855 <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
8856
8857answer = ifScript();
8858
8859function ifScript() {
8860 return (workflow.scratchpad.ended == 'ENDED_OK' ? 'yes' : 'no');
8861}
8862]]></value>
8863 </variable>
8864 <variable>
8865 <name>advanced</name>
8866 <value>1</value>
8867 </variable>
8868 </variables>
8869 </activity>
8870
8871 <activity>
8872 <name>Ended Failed</name>
8873 <activity_definition>Log Message</activity_definition>
8874 <stage>ended_failed</stage>
8875 <width/>
8876 <height/>
8877 <x>10</x>
8878 <y>7</y>
8879 <snsc_name>ended_failed</snsc_name>
8880 <variables>
8881 <variable>
8882 <name>message</name>
8883 <value>Workflow finished NOT OK.</value>
8884 </variable>
8885 </variables>
8886 </activity>
8887
8888 <activity>
8889 <name>Ended OK</name>
8890 <activity_definition>Log Message</activity_definition>
8891 <stage>ended_ok</stage>
8892 <width/>
8893 <height/>
8894 <x>11</x>
8895 <y>7</y>
8896 <snsc_name>ended_ok</snsc_name>
8897 <variables>
8898 <variable>
8899 <name>message</name>
8900 <value>Workflow finished successfully.</value>
8901 </variable>
8902 </variables>
8903 </activity>
8904
8905 <activity>
8906 <name>End</name>
8907 <activity_definition>End</activity_definition>
8908 <stage>completed</stage>
8909 <width/>
8910 <height/>
8911 <x>2</x>
8912 <y>8</y>
8913 <snsc_name>end</snsc_name>
8914 </activity>
8915</activities>
8916
8917
8918
8919 <transitions>
8920
8921 <transition>
8922 <from>begin</from>
8923 <to>check_price</to>
8924 <condition>
8925 <name>Always</name>
8926 <condition>true</condition>
8927 <order>1</order>
8928 <description/>
8929 </condition>
8930 </transition>
8931
8932
8933 <transition>
8934 <from>check_price</from>
8935 <to>waiting_for_approval</to>
8936 <condition>
8937 <name>No</name>
8938 <condition>activity.result == 'no'</condition>
8939 <order>1</order>
8940 <description/>
8941 </condition>
8942 </transition>
8943
8944
8945 <transition>
8946 <from>check_price</from>
8947 <to>approved</to>
8948 <condition>
8949 <name>Yes</name>
8950 <condition>activity.result == 'yes'</condition>
8951 <order>1</order>
8952 <description/>
8953 </condition>
8954 </transition>
8955
8956
8957 <transition>
8958 <from>waiting_for_approval</from>
8959 <to>rejected</to>
8960 <condition>
8961 <name>Rejected</name>
8962 <condition>activity.result == 'rejected'</condition>
8963 <order>1</order>
8964 <description/>
8965 </condition>
8966 </transition>
8967
8968
8969 <transition>
8970 <from>rejected</from>
8971 <to>end</to>
8972 <condition>
8973 <name>Always</name>
8974 <condition>true</condition>
8975 <order>1</order>
8976 <description/>
8977 </condition>
8978 </transition>
8979
8980
8981 <transition>
8982 <from>waiting_for_approval</from>
8983 <to>approved</to>
8984 <condition>
8985 <name>Approved</name>
8986 <condition>activity.result == 'approved' || activity.result == 'skipped'</condition>
8987 <order>1</order>
8988 <description/>
8989 </condition>
8990 </transition>
8991
8992
8993 <transition>
8994 <from>approved</from>
8995 <to>initializing</to>
8996 <condition>
8997 <name>Always</name>
8998 <condition>true</condition>
8999 <order>1</order>
9000 <description/>
9001 </condition>
9002 </transition>
9003
9004
9005 <transition>
9006 <from>initializing</from>
9007 <to>invoke_consume</to>
9008 <condition>
9009 <name>Always</name>
9010 <condition>true</condition>
9011 <order>1</order>
9012 <description/>
9013 </condition>
9014 </transition>
9015
9016
9017 <transition>
9018 <from>invoke_consume</from>
9019 <to>check_transfer</to>
9020 <condition>
9021 <name>Always</name>
9022 <condition>true</condition>
9023 <order>1</order>
9024 <description/>
9025 </condition>
9026 </transition>
9027
9028
9029 <transition>
9030 <from>check_transfer</from>
9031 <to>transfer_failed</to>
9032 <condition>
9033 <name>No</name>
9034 <condition>activity.result == 'no'</condition>
9035 <order>1</order>
9036 <description/>
9037 </condition>
9038 </transition>
9039
9040
9041 <transition>
9042 <from>transfer_failed</from>
9043 <to>end</to>
9044 <condition>
9045 <name>Always</name>
9046 <condition>true</condition>
9047 <order>1</order>
9048 <description/>
9049 </condition>
9050 </transition>
9051
9052
9053 <transition>
9054 <from>check_transfer</from>
9055 <to>check_consume</to>
9056 <condition>
9057 <name>Yes</name>
9058 <condition>activity.result == 'yes'</condition>
9059 <order>1</order>
9060 <description/>
9061 </condition>
9062 </transition>
9063
9064
9065 <transition>
9066 <from>check_consume</from>
9067 <to>consume_failed</to>
9068 <condition>
9069 <name>No</name>
9070 <condition>activity.result == 'no'</condition>
9071 <order>1</order>
9072 <description/>
9073 </condition>
9074 </transition>
9075
9076
9077 <transition>
9078 <from>consume_failed</from>
9079 <to>end</to>
9080 <condition>
9081 <name>Always</name>
9082 <condition>true</condition>
9083 <order>1</order>
9084 <description/>
9085 </condition>
9086 </transition>
9087
9088
9089 <transition>
9090 <from>check_consume</from>
9091 <to>workflow_timer</to>
9092 <condition>
9093 <name>Yes</name>
9094 <condition>activity.result == 'yes'</condition>
9095 <order>1</order>
9096 <description/>
9097 </condition>
9098 </transition>
9099
9100
9101 <transition>
9102 <from>workflow_timer</from>
9103 <to>retrieve_status</to>
9104 <condition>
9105 <name>Always</name>
9106 <condition>true</condition>
9107 <order>1</order>
9108 <description/>
9109 </condition>
9110 </transition>
9111
9112
9113 <transition>
9114 <from>retrieve_status</from>
9115 <to>check_timeout</to>
9116 <condition>
9117 <name>Always</name>
9118 <condition>true</condition>
9119 <order>1</order>
9120 <description/>
9121 </condition>
9122 </transition>
9123
9124
9125 <transition>
9126 <from>check_timeout</from>
9127 <to>workflow_timer</to>
9128 <condition>
9129 <name>No</name>
9130 <condition>activity.result == 'no'</condition>
9131 <order>2</order>
9132 <description/>
9133 </condition>
9134 </transition>
9135
9136
9137 <transition>
9138 <from>check_timeout</from>
9139 <to>check_result</to>
9140 <condition>
9141 <name>Yes</name>
9142 <condition>activity.result == 'yes'</condition>
9143 <order>1</order>
9144 <description/>
9145 </condition>
9146 </transition>
9147
9148
9149 <transition>
9150 <from>check_result</from>
9151 <to>ended_failed</to>
9152 <condition>
9153 <name>No</name>
9154 <condition>activity.result == 'no'</condition>
9155 <order>2</order>
9156 <description/>
9157 </condition>
9158 </transition>
9159
9160
9161 <transition>
9162 <from>ended_failed</from>
9163 <to>end</to>
9164 <condition>
9165 <name>Always</name>
9166 <condition>true</condition>
9167 <order>1</order>
9168 <description/>
9169 </condition>
9170 </transition>
9171
9172
9173 <transition>
9174 <from>check_result</from>
9175 <to>ended_ok</to>
9176 <condition>
9177 <name>Yes</name>
9178 <condition>activity.result == 'yes'</condition>
9179 <order>1</order>
9180 <description/>
9181 </condition>
9182 </transition>
9183
9184
9185 <transition>
9186 <from>ended_ok</from>
9187 <to>end</to>
9188 <condition>
9189 <name>Always</name>
9190 <condition>true</condition>
9191 <order>1</order>
9192 <description/>
9193 </condition>
9194 </transition>
9195</transitions>
9196
9197 </workflow>
9198</workflows>
9199
9200
9201 <fix_scripts>
9202 <fix_script>
9203 <name>Sara - Create Scheduler for auto-sync</name>
9204 <description>Create Scheduler for auto-sync service and lookup value</description>
9205 <active>true</active>
9206 <run_once>true</run_once>
9207 <script><![CDATA[var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
9208
9209glideHelper.persistData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_AUTO_SCRIPT, {
9210 'name': 'SaraAutoSync',
9211 'script': 'new x_ausgh_snsc.SaraSync().syncServices();',
9212 'active': true,
9213 'run_type': 'periodically',
9214 'run_period': '02:00:00',
9215 'sys_class_name': 'sysauto_script',
9216 'run_dayofweek': 1
9217});
9218]]></script>
9219 </fix_script>
9220 <fix_script>
9221 <name>Sara - Remove Scheduler for auto-sync</name>
9222 <description>Remove Scheduler for auto-sync service and lookup value</description>
9223 <active>true</active>
9224 <run_once>true</run_once>
9225 <script><![CDATA[var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
9226
9227glideHelper.deleteData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_AUTO_SCRIPT, {
9228 'name': 'SaraAutoSync'
9229}, true);
9230]]></script>
9231 </fix_script>
9232</fix_scripts>
9233
9234
9235 <schedulers>
9236 <scheduler>
9237 <name>SaraAutoSync</name>
9238 <active>false</active>
9239 <run_type>periodically</run_type>
9240 <run_period>02:00:00</run_period>
9241 <sys_class_name>sysauto_script</sys_class_name>
9242 <run_dayofweek>1</run_dayofweek>
9243 <script>new x_ausgh_snsc.SaraSync().syncServices();</script>
9244 </scheduler>
9245</schedulers>
9246
9247
9248 <wizards>
9249 <wizard>
9250 <name>Automic OAuth Configuration</name>
9251 <type>expert</type>
9252 <banner_type>fixed</banner_type>
9253 <roles>x_ausgh_snsc.admin</roles>
9254 <first_panel>OAuth Client</first_panel>
9255 <variables>
9256 <variable>
9257 <name>sara_client_scripts</name>
9258 <type>14</type>
9259 <class>expert_variable</class>
9260 <question>Sara Client Scripts</question>
9261 <order>0</order>
9262 <mandatory>false</mandatory>
9263 <active>true</active>
9264 <panel>Config OAuth Client</panel>
9265 <macro>sara_client_scripts</macro>
9266 </variable>
9267 <variable>
9268 <name>client_id</name>
9269 <type>6</type>
9270 <class>expert_variable</class>
9271 <question>Client ID</question>
9272 <order>100</order>
9273 <mandatory>true</mandatory>
9274 <active>true</active>
9275 <panel>Config OAuth Client</panel>
9276 <show_help>true</show_help>
9277 <help_tag>More information</help_tag>
9278 <help_text>Identity of OAuth client (AE system name / client number / user name). Example: AE/777/SERVICE_NOW. Typically the ID of the ServiceNow instance registered with OAuth server.</help_text>
9279 </variable>
9280 <variable>
9281 <name>client_secret</name>
9282 <type>6</type>
9283 <class>expert_variable</class>
9284 <question>Client Secret</question>
9285 <order>200</order>
9286 <mandatory>true</mandatory>
9287 <active>true</active>
9288 <panel>Config OAuth Client</panel>
9289 <show_help>true</show_help>
9290 <help_tag>More information</help_tag>
9291 <help_text>Secret phrase of OAuth client user. Example: AES_12345, the value will be encrypted in ServiceNow.</help_text>
9292 </variable>
9293 <variable>
9294 <name>technical_user</name>
9295 <type>6</type>
9296 <class>expert_variable</class>
9297 <question>Technical User</question>
9298 <order>300</order>
9299 <mandatory>true</mandatory>
9300 <active>true</active>
9301 <panel>Config OAuth Client</panel>
9302 <show_help>true</show_help>
9303 <help_tag>More information</help_tag>
9304 <help_text>User Name/Department. Example: TECHSYNC/AUTOMIC</help_text>
9305 </variable>
9306 <variable>
9307 <name>sapi_endpoint</name>
9308 <type>6</type>
9309 <class>expert_variable</class>
9310 <question>SAPI Endpoint</question>
9311 <order>400</order>
9312 <mandatory>true</mandatory>
9313 <active>true</active>
9314 <panel>Config OAuth Client</panel>
9315 <show_help>true</show_help>
9316 <help_tag>More information</help_tag>
9317 <help_text>Root endpoint URL of SAPI, the URL from which SNSC will start discovering services. Example: http://mycompany.com/sapi. Protocol indication (http/https) is required. If SAPI is not public accessible, mid_server must be specified under Sara System Properties > x_ausgh_snsc.mid_server</help_text>
9318 </variable>
9319 <variable>
9320 <name>token_endpoint</name>
9321 <type>6</type>
9322 <class>expert_variable</class>
9323 <question>Token Endpoint</question>
9324 <order>500</order>
9325 <mandatory>true</mandatory>
9326 <active>true</active>
9327 <panel>Config OAuth Client</panel>
9328 <show_help>true</show_help>
9329 <help_tag>More information</help_tag>
9330 <help_text>Endpoint for token requesting/refreshing URL. Example: http://mycompany.com/oauth2/token. Protocol indication (http/https) is required. If OAuth Server is not public accessible, mid_server must be specified under Sara System Properties > x_ausgh_snsc.mid_server</help_text>
9331 </variable>
9332 <variable>
9333 <name>auth_endpoint</name>
9334 <type>6</type>
9335 <class>expert_variable</class>
9336 <question>Authorization Endpoint</question>
9337 <order>600</order>
9338 <mandatory>true</mandatory>
9339 <active>true</active>
9340 <panel>Config OAuth Client</panel>
9341 <show_help>true</show_help>
9342 <help_tag>More information</help_tag>
9343 <help_text>Authorization endpoint URL. Example: http://mycompany.com/oauth2/auth. Protocol indication (http/https) is required.. If OAuth Server is not public accessible, mid_server must be specified under Sara System Properties > x_ausgh_snsc.mid_server</help_text>
9344 </variable>
9345 </variables>
9346
9347 <panels>
9348 <panel>
9349 <name>Config OAuth Client</name>
9350 <title>Config OAuth Client</title>
9351 <class>expert_panel</class>
9352 <description>Config OAuth Server Endpoints, Client ID, Client Secret, SAPI Endpoint and Technical User for SNSC. OAuth login popup will be shown in case Technical User doesn't have tokens or Technical User's tokens are empty, invalid or expired.</description>
9353 <previous_message>Previous</previous_message>
9354 <next_message>Store OAuth Client Settings</next_message>
9355 <complete_message>Done</complete_message>
9356 <client_script>
9357 <name>SARA OAuth Client OnLoad</name>
9358 <active>true</active>
9359 <type>onLoad</type>
9360 <script><![CDATA[function onLoad() {
9361 g_form.getControl(x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_SECRET).type = 'password';
9362 x_ausgh_snsc.oldConfig = {};
9363
9364 x_ausgh_snsc.SaraOAuth.getConfig(function (configData) {
9365 for (var name in configData) {
9366 var value = configData[name];
9367
9368 g_form.setValue(name, value);
9369 x_ausgh_snsc.oldConfig[name] = value;
9370 }
9371 });
9372}
9373]]></script>
9374 </client_script>
9375 <client_script>
9376 <name>SARA OAuth Client OnSubmit</name>
9377 <active>true</active>
9378 <type>onSubmit</type>
9379 <script><![CDATA[function onSubmit() {
9380 if (x_ausgh_snsc.isTokenValid) {
9381 return true;
9382 } else {
9383 var isChange = false;
9384 for (var name in x_ausgh_snsc.oldConfig) {
9385 if (x_ausgh_snsc.oldConfig[name] !== g_form.getValue(name).toString() && name !== x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT) {
9386 isChange = true;
9387 break;
9388 }
9389 }
9390
9391 if (isChange && !x_ausgh_snsc.notChange) {
9392 getToken();
9393 } else {
9394 // Clean all existing messages
9395 g_form.clearMessages();
9396
9397 // Check if Sara tokens exist for Technical User
9398 var technicalUser = g_form.getValue(x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER).toString();
9399 var sapiEndpoint = g_form.getValue(x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT).toString();
9400 x_ausgh_snsc.SaraOAuth.checkOAuthToken(technicalUser, sapiEndpoint, false, {
9401 onValid: function () {
9402 x_ausgh_snsc.isTokenValid = true;
9403 g_expert.next();
9404 },
9405 onInvalid: function () {
9406 x_ausgh_snsc.isTokenValid = false;
9407 getToken();
9408 },
9409 onError: function (errorMessage) {
9410 x_ausgh_snsc.isTokenValid = false;
9411 g_form.addErrorMessage(errorMessage);
9412 }
9413 });
9414 }
9415 }
9416
9417 return false;
9418}
9419
9420function getToken() {
9421 x_ausgh_snsc.log('Preparing for openning OAuth login popup...');
9422
9423 for (var key in x_ausgh_snsc.SaraCommon.CONFIG_NAME) {
9424 var name = x_ausgh_snsc.SaraCommon.CONFIG_NAME[key];
9425
9426 x_ausgh_snsc.config[name] = g_form.getValue(name).toString();
9427 }
9428
9429 x_ausgh_snsc.SaraOAuth.login(
9430 x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID],
9431 x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER],
9432 x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.AUTH_ENDPOINT], {
9433 onSuccess: function () {
9434 x_ausgh_snsc.notChange = true;
9435 g_expert.next();
9436 }
9437 }
9438 );
9439}
9440]]></script>
9441 </client_script>
9442 </panel>
9443 <panel>
9444 <name>Config OAuth Client Completed</name>
9445 <title>Config OAuth Client Completed</title>
9446 <class>expert_panel</class>
9447 <description/>
9448 <previous_message>Previous</previous_message>
9449 <next_message>Next</next_message>
9450 <complete_message>Done</complete_message>
9451 </panel>
9452 </panels>
9453
9454 <transitions>
9455 <transition>
9456 <from>Config OAuth Client</from>
9457 <to>Config OAuth Client Completed</to>
9458 <order>100</order>
9459 <condition/>
9460 <transition_script><![CDATA[var LOGGER = new x_ausgh_snsc.SaraLog('sara_oauth_client_transition');
9461
9462gs.addInfoMessage('Client ID = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID]
9463 + ', Client Secret = ***'
9464 + ', Technical User = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER]
9465 + ', SAPI Endpoint = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT]
9466 + ', Token Endpoint = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT]
9467 + ', Authorization Endpoint = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.AUTH_ENDPOINT]);
9468
9469var saraConfig = new x_ausgh_snsc.SaraConfig();
9470try {
9471 var configData = {};
9472 for (var key in x_ausgh_snsc.SaraCommon.CONFIG_NAME) {
9473 var name = x_ausgh_snsc.SaraCommon.CONFIG_NAME[key];
9474
9475 configData[name] = wizard[name];
9476 }
9477
9478 saraConfig.storeClientConfig(configData);
9479 LOGGER.info('OAuth Configuration updated:\n'
9480 + ' - Client ID = {0}, \n'
9481 + ' - Client Secret = ***, \n'
9482 + ' - Technical User = {1} \n'
9483 + ' - SAPI Endpoint = {2}, \n'
9484 + ' - Token Endpoint = {3}, \n'
9485 + ' - Authorization Endpoint = {4}',
9486 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID],
9487 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER],
9488 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT],
9489 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT],
9490 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.AUTH_ENDPOINT]
9491 );
9492
9493 gs.addInfoMessage('Successfully update Automic OAuth client settings');
9494} catch (err) {
9495 LOGGER.info('Error on update Automic OAuth client settings: {0}', err);
9496
9497 gs.addInfoMessage('Failed to update Automic OAuth client settings');
9498}
9499]]></transition_script>
9500 </transition>
9501 </transitions>
9502 </wizard>
9503
9504 <wizard>
9505 <name>Automic Import Services</name>
9506 <type>expert</type>
9507 <banner_type>fixed</banner_type>
9508 <roles>x_ausgh_snsc.admin</roles>
9509 <first_panel>Import Services</first_panel>
9510 <variables>
9511 <variable>
9512 <name>sara_client_scripts</name>
9513 <type>14</type>
9514 <class>expert_variable</class>
9515 <question>Sara Client Scripts</question>
9516 <order>0</order>
9517 <mandatory>false</mandatory>
9518 <active>true</active>
9519 <panel>Import Services</panel>
9520 <macro>sara_client_scripts</macro>
9521 </variable>
9522 <variable>
9523 <name>sara_message</name>
9524 <type>6</type>
9525 <class>expert_variable</class>
9526 <question>Sara Message</question>
9527 <order>100</order>
9528 <mandatory>false</mandatory>
9529 <active>true</active>
9530 <panel>Import Services</panel>
9531 </variable>
9532 <variable>
9533 <name>sara_target_category</name>
9534 <type>18</type>
9535 <class>expert_variable</class>
9536 <question>Select Target Category</question>
9537 <order>200</order>
9538 <mandatory>true</mandatory>
9539 <active>true</active>
9540 <lookup_table>sc_category</lookup_table>
9541 <lookup_value>sys_id</lookup_value>
9542 <lookup_label>title</lookup_label>
9543 <panel>Import Services</panel>
9544 <reference_qual>javascript:x_ausgh_snsc.SaraUtils.getImportTargetCatRefQual()</reference_qual>
9545 </variable>
9546 </variables>
9547
9548 <panels>
9549 <panel>
9550 <name>Import Services</name>
9551 <title>Import Services</title>
9552 <class>expert_panel</class>
9553 <description>Import SARA services to Service Catalog. Error messages will be shown in case Technical User doesn't have tokens or Technical User's tokens empty, invalid or expired.</description>
9554 <previous_message>Previous</previous_message>
9555 <next_message>Import Services</next_message>
9556 <complete_message>Done</complete_message>
9557 <client_script>
9558 <name>Import Services OnLoad</name>
9559 <active>true</active>
9560 <type>onLoad</type>
9561 <script><![CDATA[function onLoad() {
9562 x_ausgh_snsc.SaraUtils.setFormControlVisible('sara_message', false);
9563 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(false);
9564
9565 x_ausgh_snsc.SaraOAuth.getConfig(function (configData) {
9566 for (var key in configData) {
9567 var value = configData[key];
9568
9569 x_ausgh_snsc.config[key] = value;
9570
9571 if (!value) {
9572 g_form.addErrorMessage('OAuth Configuration "' + key + '" is empty. Please check the current OAuth configuration.');
9573 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(false);
9574 break;
9575 }
9576 }
9577
9578 setTimeout(function () {
9579 checkToken();
9580 }, 100);
9581 });
9582}
9583
9584function checkToken() {
9585 var technicalUser = x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER];
9586 var sapiEndpoint = x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT];
9587 x_ausgh_snsc.SaraOAuth.checkOAuthToken(technicalUser, sapiEndpoint, true, {
9588 onValid: function () {
9589 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(true);
9590 },
9591 onInvalid: function () {
9592 g_form.addErrorMessage('Tokens are empty, invalid or expired! Please contact your administrator for resolving this problem.');
9593 },
9594 onError: function (errorMessage) {
9595 g_form.addErrorMessage(errorMessage);
9596 }
9597 });
9598}
9599]]></script>
9600 </client_script>
9601 <client_script>
9602 <name>Import Services OnSubmit</name>
9603 <active>true</active>
9604 <type>onSubmit</type>
9605 <script><![CDATA[function onSubmit() {
9606 if (x_ausgh_snsc.isOk) {
9607 return true;
9608 }
9609
9610 var importDialog = new GlideDialogWindow('hierarchical_progress_viewer');
9611 importDialog.setPreference('sysparm_ajax_processor', 'x_ausgh_snsc.SaraConsumerRunner');
9612 importDialog.setPreference('sysparm_catid', g_form.getValue('sara_target_category').toString());
9613 importDialog.setSize(400, 300);
9614 importDialog.setTitle('Importing service...');
9615
9616 importDialog.on('executionComplete', function (trackerObj) {
9617 x_ausgh_snsc.log('executionComplete', trackerObj);
9618 if (trackerObj.result && trackerObj.result.info) {
9619 importDialog.setTitle(trackerObj.result.msg);
9620 g_form.setValue('sara_message', trackerObj.result.info);
9621
9622 x_ausgh_snsc.isOk = true;
9623 x_ausgh_snsc.log('Go to next panel', x_ausgh_snsc.isOk);
9624 g_expert.next();
9625
9626
9627 x_ausgh_snsc.log('Destroy diablog', importDialog);
9628 importDialog.destroy();
9629 }
9630 });
9631
9632 importDialog.on("renderStatus", function (trackerObj) {
9633 x_ausgh_snsc.log('renderStatus', trackerObj);
9634
9635 if (trackerObj && trackerObj.result && trackerObj.result.msg) {
9636 importDialog.setTitle(trackerObj.result.msg);
9637 }
9638 });
9639
9640 // Render the viewer
9641 importDialog.render();
9642
9643 return false;
9644}
9645]]></script>
9646 </client_script>
9647 </panel>
9648 <panel>
9649 <name>Import Services Completed</name>
9650 <title>Import Services Completed</title>
9651 <class>expert_panel</class>
9652 <description/>
9653 <previous_message>Previous</previous_message>
9654 <next_message>Next</next_message>
9655 <complete_message>Done</complete_message>
9656 </panel>
9657 </panels>
9658
9659 <transitions>
9660 <transition>
9661 <from>Import Services</from>
9662 <to>Import Services Completed</to>
9663 <order>100</order>
9664 <condition>[sara_target_category]!=^EQ</condition>
9665 <transition_script><![CDATA[gs.addInfoMessage(wizard.sara_message.toString());
9666]]></transition_script>
9667 </transition>
9668 </transitions>
9669 </wizard>
9670
9671 <wizard>
9672 <name>Automic Clean-up</name>
9673 <type>expert</type>
9674 <banner_type>fixed</banner_type>
9675 <roles>x_ausgh_snsc.admin</roles>
9676 <first_panel>Automic Cleanup</first_panel>
9677 <variables>
9678 <variable/>
9679 </variables>
9680
9681 <panels>
9682 <panel>
9683 <name>Cleanup Catalog Items</name>
9684 <title>Cleanup Catalog Items</title>
9685 <class>expert_panel</class>
9686 <description>Cleanup all Automic SARA stuffs. This will delete all subcategories and service items.</description>
9687 <previous_message>Previous</previous_message>
9688 <next_message>Cleanup</next_message>
9689 <complete_message>Done</complete_message>
9690 </panel>
9691 <panel>
9692 <name>Cleanup Catalog Items Completed</name>
9693 <title>Cleanup Catalog Items Completed</title>
9694 <class>expert_panel</class>
9695 <description>Cleanup successfully!</description>
9696 <previous_message>Previous</previous_message>
9697 <next_message>Next</next_message>
9698 <complete_message>Done</complete_message>
9699 </panel>
9700 </panels>
9701
9702 <transitions>
9703 <transition>
9704 <from>Cleanup Catalog Items</from>
9705 <to>Cleanup Catalog Items Completed</to>
9706 <order>100</order>
9707 <condition/>
9708 <transition_script>
9709 <![CDATA[x_ausgh_snsc.SaraUtils.cleanup();]]>
9710 </transition_script>
9711 </transition>
9712 </transitions>
9713 </wizard>
9714</wizards>
9715
9716
9717 <processors>
9718 <processor>
9719 <name>SaraUpdateStatus</name>
9720 <type>script</type>
9721 <active>true</active>
9722 <description>Sara REST api for updating status of worflow remotely</description>
9723 <path>sara_update_status</path>
9724 <script><![CDATA[var LOGGER = new x_ausgh_snsc.SaraLog('SaraUpdateStatus');
9725var runId = g_request.getParameter('runId');
9726var status = g_request.getParameter('status');
9727var error = 0;
9728var result = {};
9729
9730LOGGER.info('SaraUpdateStatus: RunId = {0}, Status = {1}', runId, status);
9731LOGGER.info('SaraUpdateStatus: Request user = ' + gs.getUserName());
9732
9733if (!runId) {
9734 error += 1;
9735}
9736
9737if (!status) {
9738 error += 1;
9739}
9740
9741if (error === 0) {
9742 runId = +runId;
9743
9744 if (isNaN(runId)) {
9745 result = {
9746 code: 99,
9747 message: 'The runId must be digits!'
9748 };
9749 } else {
9750 var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
9751 var reqItem = glideHelper.getData('sc_req_item', {
9752 'correlation_id': runId.toString()
9753 });
9754
9755 if (reqItem) {
9756 LOGGER.info('Found current request item (correlation_id = {0}, sys_id = {1})', runId, reqItem['sys_id']);
9757
9758 try {
9759 glideHelper.updateData('sc_req_item', {
9760 'sys_id': reqItem['sys_id']
9761 }, {
9762 'comments': status,
9763 'display_state': status
9764 });
9765
9766 result = {
9767 code: 200,
9768 message: 'Update OK!',
9769 sysId: reqItem['sys_id']
9770 };
9771 } catch (e) {
9772 result = {
9773 code: 99,
9774 message: err
9775 };
9776 }
9777 } else {
9778 var message = x_ausgh_snsc.SaraUtils.formatString('No request item (correlation_id = {0}) found! Update status failed.', runId);
9779 LOGGER.info(message);
9780
9781 result = {
9782 code: 99,
9783 message: message
9784 };
9785 }
9786 }
9787} else {
9788 result = {
9789 code: 99,
9790 message: 'The runId and status must be not null!'
9791 }
9792}
9793
9794var response = x_ausgh_snsc.SaraJSON.stringify(result);
9795
9796LOGGER.debug('SaraUpdateStatus: {0}', response);
9797
9798g_processor.writeOutput('application/json', response);
9799]]></script>
9800 </processor>
9801</processors>
9802
9803
9804 <snsc_application>
9805 <application>
9806 <name>Automic SNSC</name>
9807 <short_description>Automic ServiceNow Service Connector Application</short_description>
9808 <active>true</active>
9809 <user_role>x_ausgh_snsc.user</user_role>
9810 <version>1.0.2</version>
9811 <menu>u_ausgh_snsc_menu</menu>
9812 <scope>x_ausgh_snsc</scope>
9813 </application>
9814 <application_menu>
9815 <name>u_ausgh_snsc_menu</name>
9816 <active>true</active>
9817 <category>Custom Applications</category>
9818 <title>Automic SNSC</title>
9819 <roles>x_ausgh_snsc.user,x_ausgh_snsc.admin</roles>
9820 <hint>Automic ServiceNow Service Connector Application</hint>
9821 </application_menu>
9822 <user_roles>
9823 <user_role>
9824 <name>x_ausgh_snsc.user</name>
9825 <description>User role for SNSC application</description>
9826 </user_role>
9827 <user_role>
9828 <name>x_ausgh_snsc.admin</name>
9829 <description>Admin role for SNSC application</description>
9830 <includes_roles>x_ausgh_snsc.user</includes_roles>
9831 </user_role>
9832 </user_roles>
9833</snsc_application>
9834
9835
9836 <modules>
9837 <module>
9838 <title>Automic Configuration</title>
9839 <order>0</order>
9840 <active>true</active>
9841 <link_type>SEPARATOR</link_type>
9842 <roles>x_ausgh_snsc.admin</roles>
9843 </module>
9844 <module>
9845 <title>Automic Clean-up</title>
9846 <reference>wizard</reference>
9847 <reference_name>Automic Clean-up</reference_name>
9848 <order>10</order>
9849 <active>true</active>
9850 <link_type>DIRECT</link_type>
9851 <query>/expert_shell.do?sysparm_sys_id=@{sys_id}&sysparm_initial=true</query>
9852 <roles>x_ausgh_snsc.admin</roles>
9853 </module>
9854 <module>
9855 <title>Automic Import Services</title>
9856 <reference>wizard</reference>
9857 <reference_name>Automic Import Services</reference_name>
9858 <order>20</order>
9859 <active>true</active>
9860 <link_type>DIRECT</link_type>
9861 <query>/expert_shell.do?sysparm_sys_id=@{sys_id}&sysparm_initial=true</query>
9862 <roles>x_ausgh_snsc.admin</roles>
9863 </module>
9864 <module>
9865 <title>Automic OAuth Configuration</title>
9866 <reference>wizard</reference>
9867 <reference_name>Automic OAuth Configuration</reference_name>
9868 <order>30</order>
9869 <active>true</active>
9870 <link_type>DIRECT</link_type>
9871 <query>/expert_shell.do?sysparm_sys_id=@{sys_id}&sysparm_initial=true</query>
9872 <roles>x_ausgh_snsc.admin</roles>
9873 </module>
9874 <module>
9875 <title>Automic SNSC Components</title>
9876 <order>100</order>
9877 <active>true</active>
9878 <link_type>SEPARATOR</link_type>
9879 </module>
9880 <module>
9881 <title>Sara Tables</title>
9882 <order>110</order>
9883 <active>true</active>
9884 <link_type>LIST</link_type>
9885 <table_name>sys_db_object</table_name>
9886 <filter>nameSTARTSWITHx_ausgh_snsc_</filter>
9887 </module>
9888 <module>
9889 <title>Sara Transform Maps</title>
9890 <order>115</order>
9891 <active>true</active>
9892 <link_type>LIST</link_type>
9893 <table_name>sys_transform_map</table_name>
9894 <filter>nameSTARTSWITHx_ausgh_snsc_</filter>
9895 </module>
9896 <module>
9897 <title>Sara System Properties</title>
9898 <reference>system_property</reference>
9899 <reference_name>Automic</reference_name>
9900 <order>120</order>
9901 <active>true</active>
9902 <link_type>DIRECT</link_type>
9903 <query>/sys_properties_category.do?sys_id=@{sys_id}</query>
9904 </module>
9905 <module>
9906 <title>Sara Script Includes</title>
9907 <order>130</order>
9908 <active>true</active>
9909 <link_type>LIST</link_type>
9910 <table_name>sys_script_include</table_name>
9911 <filter>nameSTARTSWITHSara</filter>
9912 </module>
9913 <module>
9914 <title>Sara UI Scripts</title>
9915 <order>140</order>
9916 <active>true</active>
9917 <link_type>LIST</link_type>
9918 <table_name>sys_ui_script</table_name>
9919 <filter>nameSTARTSWITHx_ausgh_snsc.Sara</filter>
9920 </module>
9921 <module>
9922 <title>Sara UI Pages</title>
9923 <order>150</order>
9924 <active>true</active>
9925 <link_type>LIST</link_type>
9926 <table_name>sys_ui_page</table_name>
9927 <filter>nameSTARTSWITHsara_</filter>
9928 </module>
9929 <module>
9930 <title>Sara UI Macros</title>
9931 <order>160</order>
9932 <active>true</active>
9933 <link_type>LIST</link_type>
9934 <table_name>sys_ui_macro</table_name>
9935 <filter>nameSTARTSWITHsara_</filter>
9936 </module>
9937 <module>
9938 <title>Sara Processors</title>
9939 <order>170</order>
9940 <active>true</active>
9941 <link_type>LIST</link_type>
9942 <table_name>sys_processor</table_name>
9943 <filter>nameSTARTSWITHSara</filter>
9944 </module>
9945 <module>
9946 <title>Sara Wizards</title>
9947 <order>180</order>
9948 <active>true</active>
9949 <link_type>LIST</link_type>
9950 <table_name>expert</table_name>
9951 <filter>nameSTARTSWITHAutomic</filter>
9952 </module>
9953 <module>
9954 <title>Sara Schedulers</title>
9955 <order>190</order>
9956 <active>true</active>
9957 <link_type>LIST</link_type>
9958 <table_name>sysauto</table_name>
9959 <filter>nameSTARTSWITHSara</filter>
9960 </module>
9961 <module>
9962 <title>Sara REST Messages</title>
9963 <order>200</order>
9964 <active>true</active>
9965 <link_type>LIST</link_type>
9966 <table_name>sys_rest_message</table_name>
9967 <filter>nameSTARTSWITHSara</filter>
9968 </module>
9969 <module>
9970 <title>Support</title>
9971 <order>900</order>
9972 <active>true</active>
9973 <link_type>SEPARATOR</link_type>
9974 </module>
9975 <module>
9976 <title>Used ServiceNow's Tables</title>
9977 <order>910</order>
9978 <active>true</active>
9979 <link_type>LIST</link_type>
9980 <table_name>sys_db_object</table_name>
9981 <query>name=sc_category^ORname=item_option_new_set^ORname=io_set_item^ORname=sysauto_script^ORname=item_option_new</query>
9982 </module>
9983 <module>
9984 <title>Sara Transform History</title>
9985 <order>915</order>
9986 <active>true</active>
9987 <link_type>LIST</link_type>
9988 <table_name>sys_import_set_run</table_name>
9989 <query>sys_transform_mapSTARTSWITHx_ausgh_snsc</query>
9990 </module>
9991 <module>
9992 <title>Contact Us</title>
9993 <order>920</order>
9994 <active>true</active>
9995 <link_type>DIRECT</link_type>
9996 <query>https://automic.com/contact-us</query>
9997 </module>
9998 <module>
9999 <title>Support</title>
10000 <order>930</order>
10001 <active>true</active>
10002 <link_type>DIRECT</link_type>
10003 <query>https://automic.force.com/support</query>
10004 </module>
10005</modules>
10006
10007
10008 <rest_messages>
10009 <rest_message>
10010 <name>Sara - SAPI Services</name>
10011 <description>Sara Outbound Web Service for SAPI</description>
10012 <rest_endpoint>${sapiEndpoint}</rest_endpoint>
10013 <methods>
10014 <method>
10015 <function_name>GET</function_name>
10016 <http_method>GET</http_method>
10017 </method>
10018 <method>
10019 <function_name>POST</function_name>
10020 <http_method>POST</http_method>
10021 </method>
10022 <method>
10023 <function_name>PUT</function_name>
10024 <http_method>PUT</http_method>
10025 </method>
10026 <method>
10027 <function_name>DELETE</function_name>
10028 <http_method>DELETE</http_method>
10029 </method>
10030 </methods>
10031 </rest_message>
10032 <rest_message>
10033 <name>Sara - OAuth Services</name>
10034 <description>Sara Outbound Web Service for OAuth</description>
10035 <rest_endpoint>${oauthEndpoint}</rest_endpoint>
10036 <methods>
10037 <method>
10038 <function_name>GET</function_name>
10039 <http_method>GET</http_method>
10040 </method>
10041 <method>
10042 <function_name>POST</function_name>
10043 <http_method>POST</http_method>
10044 </method>
10045 <method>
10046 <function_name>PUT</function_name>
10047 <http_method>PUT</http_method>
10048 </method>
10049 <method>
10050 <function_name>DELETE</function_name>
10051 <http_method>DELETE</http_method>
10052 </method>
10053 </methods>
10054 </rest_message>
10055</rest_messages>
10056
10057 </package>
10058</sara>