· 8 years ago · Feb 02, 2018, 03:26 PM
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 ranges = SaraUtils.removeDuplicatedLookup(ranges);
2943 updateData.u_is_lookup = "true";
2944 // Insert values to lookup table
2945 for (var i = 0; i < ranges.length; i++) {
2946 var rangeValue = ranges[i];
2947 var key = rangeValue.Value;
2948 var display = rangeValue.Key;
2949 if(!rangeValue.Value) {
2950 key = SaraCommon.EMPTY_VALUE.KEY;
2951 display = SaraCommon.EMPTY_VALUE.VALUE;
2952 }
2953
2954 var rangeId = this.saveOrUpdateSaraLookup({
2955 'u_key': key,
2956 'u_display_name': display,
2957 'u_control_id': variableId
2958 }).sys_id;
2959
2960 if (SaraUtils.inArray(variable.defaultValue, display)) {
2961 defaultValueForListCollector.push(rangeId);
2962 }
2963 }
2964
2965 LOGGER.info('Insert {0} values to table "{1}" finished successfully.', ranges.length, SaraCommon.TABLE_NAME.SARA_LOOKUP);
2966 } else {
2967 LOGGER.info('Lookup values of {0} is null', variable.getName());
2968 }
2969
2970 if (variable.getType() === SaraCommon.VAR_TYPE.LIST_COLLECTOR) {
2971 updateData.list_table = SaraCommon.TABLE_NAME.SARA_LOOKUP;
2972 updateData.default_value = defaultValueForListCollector.join(',');
2973 updateData.attributes = 'no_filter=true';
2974 updateData.reference_qual = 'u_control_id=' + variableId;
2975 } else {
2976 updateData.lookup_table = SaraCommon.TABLE_NAME.SARA_LOOKUP;
2977 updateData.lookup_value = 'u_display_name';
2978 updateData.reference_qual = 'u_control_id=' + variableId;
2979 }
2980
2981 LOGGER.debug('Variable updated information: {0}', SaraJSON.stringify(updateData));
2982 updateData.id = variableId;
2983 updateData.name = variableData.name;
2984 updateData.variable_set = variableData.variable_set;
2985 this.saveOrUpdateVariable(updateData);
2986 LOGGER.info('Saved lookup table for lookup control (sys_id = {0})', variableId);
2987 }
2988
2989 LOGGER.info('Saved variable (name = {0}, type = {1}, isLookup = {2})', variable.getName(), variable.getType(), variable.isLookup());
2990
2991 return variableId;
2992 },
2993
2994 getVariableSet: function(name) {
2995 return this.glideHelper.getData(this.TABLES.SN_VARIABLE_SET, {name: name});
2996 },
2997
2998 /**
2999 * param varset
3000 * id: optional. Blank for insert
3001 * name: required
3002 * title:
3003 * description:
3004 * sys_name:
3005 */
3006 saveOrUpdateVariableSet: function(varset) {
3007 SaraUtils.guardNotNullOrEmpty(varset, "varset must not be null or empty");
3008 SaraUtils.guardNotNullOrEmpty(varset.name, "varset name must not be null or empty");
3009
3010 this.saveOrUpdateEntity(varset, "var_set");
3011
3012 var result = this.getVariableSet(varset.name);
3013 SaraUtils.guardNotNullOrEmpty(result, "variable set is not save or updated correctly: " + varset.name);
3014 return result;
3015 },
3016
3017 getVariableSetItem: function(sc_cat_item, variable_set) {
3018 return this.glideHelper.getData(this.TABLES.SN_VARIABLE_SET_ITEM, {sc_cat_item: sc_cat_item, variable_set: variable_set});
3019 },
3020
3021 saveOrUpdateVariableSetItem: function(varsetItem) {
3022 SaraUtils.guardNotNullOrEmpty(varsetItem, "varsetItem must not be null or empty");
3023 SaraUtils.guardNotNullOrEmpty(varsetItem.sc_cat_item, "varsetItem sc_cat_item must not be null or empty");
3024 SaraUtils.guardNotNullOrEmpty(varsetItem.variable_set, "varsetItem variable_set must not be null or empty");
3025
3026 this.saveOrUpdateEntity(varsetItem, "var_set_item");
3027
3028 var result = this.getVariableSetItem(varsetItem.sc_cat_item, varsetItem.variable_set);
3029 SaraUtils.guardNotNullOrEmpty(result, "variable set item is not save or updated correctly");
3030 return result;
3031 },
3032
3033 getVariable: function(variable_set, name) {
3034 return this.glideHelper.getData(this.TABLES.SARA_VARIABLE, {variable_set: variable_set, name: name});
3035 },
3036
3037 saveOrUpdateVariable: function(variable) {
3038 SaraUtils.guardNotNullOrEmpty(variable, "variable must not be null or empty");
3039 SaraUtils.guardNotNullOrEmpty(variable.variable_set, "variable variable_set must not be null or empty");
3040 SaraUtils.guardNotNullOrEmpty(variable.name, "variable name must not be null or empty");
3041
3042 this.saveOrUpdateEntity(variable, "sara_variable");
3043
3044 var result = this.getVariable(variable.variable_set, variable.name);
3045 SaraUtils.guardNotNullOrEmpty(result, "variable is not save or updated correctly");
3046 return result;
3047 },
3048
3049 getSaraLookup: function(u_control_id, u_key, u_display_name) {
3050 return this.glideHelper.getData(this.TABLES.SARA_LOOKUP, {u_control_id: u_control_id, u_key: u_key, u_display_name: u_display_name});
3051 },
3052
3053 saveOrUpdateSaraLookup: function(lookup) {
3054 SaraUtils.guardNotNullOrEmpty(lookup, "lookup must not be null or empty");
3055 SaraUtils.guardNotNullOrEmpty(lookup.u_key, "lookup u_key must not be null or empty");
3056
3057 this.saveOrUpdateEntity(lookup, "sara_lookup");
3058
3059 var controlId = lookup.u_control_id;
3060 if(controlId === "0") {
3061 controlId = "";
3062 }
3063 var result = this.getSaraLookup(lookup.u_control_id, lookup.u_key, lookup.u_display_name);
3064 SaraUtils.guardNotNullOrEmpty(result, "lookup is not save or updated correctly");
3065 return result;
3066 },
3067
3068 /**
3069 * Create Sara Client Scripts with type is Macro and using UI Macro name SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS. This control help us to
3070 * include all SNSC client scripts
3071 * @param {String} varSetId The sys_id of variable set
3072 */
3073 createSaraClientScripts: function (varSetId) {
3074 var glideHelper = this.glideHelper;
3075 var LOGGER = this.LOGGER;
3076
3077 var macroSaraClientScripts = glideHelper.getData(SaraCommon.TABLE_NAME.SN_UI_MACRO, {
3078 'name': SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS
3079 });
3080
3081 if (macroSaraClientScripts) {
3082 this.saveOrUpdateVariable({
3083 'name': SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS,
3084 'type': SaraCommon.VAR_TYPE.MACRO,
3085 'u_is_lookup': false,
3086 'macro': macroSaraClientScripts.sys_id,
3087 'variable_set': varSetId
3088 });
3089 } else {
3090 LOGGER.info('There\' no UI Macro named "{0}". Creating Sara client scripts skipped!', SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS);
3091 }
3092 },
3093
3094 /**
3095 * Create Sara Hidden Variable with type is Macro and using UI Macro name SaraCommon.CONTROL_NAME.HIDDEN_CONTROL. This control help us
3096 * to run x_ausgh_snsc.SaraVarSet.onLoad() method without creating Catalog Client Script for VariableSet
3097 * @param {String} varSetId The sys_id of variable set
3098 */
3099 createSaraHiddenVariable: function (varSetId) {
3100 var glideHelper = this.glideHelper;
3101 var LOGGER = this.LOGGER;
3102
3103 var macroSaraHiddenControl = glideHelper.getData(SaraCommon.TABLE_NAME.SN_UI_MACRO, {
3104 'name': SaraCommon.CONTROL_NAME.HIDDEN_CONTROL
3105 });
3106
3107 if (macroSaraHiddenControl) {
3108 this.saveOrUpdateVariable({
3109 'name': SaraCommon.CONTROL_NAME.HIDDEN_CONTROL,
3110 'type': SaraCommon.VAR_TYPE.MACRO,
3111 'u_is_lookup': false,
3112 'macro': macroSaraHiddenControl.sys_id,
3113 'variable_set': varSetId
3114 });
3115 } else {
3116 LOGGER.info('There\' no UI Macro named "{0}". Creating Sara hidden control skipped!', SaraCommon.CONTROL_NAME.HIDDEN_CONTROL);
3117 }
3118 },
3119
3120 //---------------------------
3121 //Sara Definition
3122 //---------------------------
3123 getSaraDefinition: function(name, parentCategoryId, type) {
3124 return this.glideHelper.getData(this.TABLES.SARA_DEFINITION, {
3125 'u_name': name,
3126 'u_parent': parentCategoryId,
3127 'u_type': type
3128 });
3129 },
3130
3131 /**
3132 * param saraDefinition
3133 * id:
3134 * u_name: required
3135 * u_consume_url:
3136 * u_sc_item:
3137 * u_service_catalog_category:
3138 * u_var_set:
3139 * u_parent: required
3140 * u_type: required
3141 * u_hash:
3142 * u_active
3143 */
3144 saveOrUpdateSaraDefinition: function(saraDefinition) {
3145 SaraUtils.guardNotNullOrEmpty(saraDefinition, "saraDefinition must not be null or empty");
3146 SaraUtils.guardNotNullOrEmpty(saraDefinition.u_name, "u_name must not be null or empty");
3147 SaraUtils.guardNotNullOrEmpty(saraDefinition.u_parent, "u_parent must not be null or empty");
3148 SaraUtils.guardNotNullOrEmpty(saraDefinition.u_type, "u_type must not be null or empty");
3149
3150 this.saveOrUpdateEntity(saraDefinition, "sara_definition");
3151
3152 var result = this.getSaraDefinition(saraDefinition.u_name, saraDefinition.u_parent, saraDefinition.u_type);
3153 SaraUtils.guardNotNullOrEmpty(result, "definition is not save or updated correctly");
3154 return result;
3155 },
3156
3157 /**
3158 * Save category into SaraCommon.TABLE_NAME.SARA_DEFINITION table
3159 * @param {String} categoryId
3160 */
3161 saveRootImportCategoryToSaraDefinition: function (categoryId) {
3162 var glideHelper = this.glideHelper;
3163 var LOGGER = this.LOGGER;
3164
3165 var targetCategory = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
3166 'sys_id': categoryId
3167 });
3168
3169 var importedDefinition = this.getSaraDefinition(targetCategory.title, targetCategory.sys_id, 'category');
3170
3171 if (importedDefinition) {
3172 LOGGER.info('Services have been imported in target category (name = {0})!', targetCategory.title);
3173 return importedDefinition;
3174 } else {
3175 return this.saveOrUpdateSaraDefinition({
3176 u_name: targetCategory.title,
3177 u_parent: targetCategory.sys_id,
3178 u_type: 'category',
3179 u_active: true
3180 });
3181 }
3182 },
3183
3184 /**
3185 * Save category into SaraCommon.TABLE_NAME.SARA_DEFINITION table
3186 * @param {String} categoryId
3187 */
3188 saveCategoryToSaraDefinition: function (sapiCatalog) {
3189 var glideHelper = this.glideHelper;
3190 var LOGGER = this.LOGGER;
3191
3192 // Assign default homepage renderer
3193 var defaultRendererSysId = glideHelper.getSysId(SaraCommon.TABLE_NAME.SN_HOMEPAGE_RENDERER, {
3194 'name': 'Category Items'
3195 });
3196
3197 var categoryToSave = {
3198 title: sapiCatalog.getTitle(),
3199 description: sapiCatalog.getDescription(),
3200 active: sapiCatalog.isActive(),
3201 homepage_renderer: defaultRendererSysId,
3202 parent: sapiCatalog.getParent(),
3203 };
3204 var category = this.saveOrUpdateCategory(categoryToSave);
3205 LOGGER.info('Created Catalog category {0} (sys_id = {1})...', sapiCatalog.getTitle(), category.sys_id);
3206
3207 return this.saveOrUpdateSaraDefinition({
3208 'u_service_catalog_category': category.sys_id,
3209 'u_name': sapiCatalog.getName(),
3210 'u_consume_url': sapiCatalog.getConsumeUrl() || '',
3211 'u_parent': sapiCatalog.getParent(),
3212 'u_type': 'catalog',
3213 'u_description': sapiCatalog.getDescription(),
3214 'u_active': true
3215 });
3216 },
3217
3218 /**
3219 * Deactivate item in SaraCommon.TABLE_NAME.SARA_DEFINITION via import set
3220 * @param {Object} saraDefinition The catalog item which will be deactivated
3221 */
3222 deactivateSaraDefinition: function (saraDefinition) {
3223 SaraUtils.guardNotNullOrEmpty(saraDefinition, "saraDefinition must not be null or empty");
3224 var id = saraDefinition.sys_id || saraDefinition.id;
3225 SaraUtils.guardNotNullOrEmpty(id, "definition id must not be null or empty");
3226
3227 var glideHelper = this.glideHelper;
3228 var LOGGER = this.LOGGER;
3229
3230 LOGGER.info('Deactivating sara definition and its child definitions... (sys_id = {0}, u_name= {1}) in table "{2}"',
3231 saraDefinition.sys_id, saraDefinition.u_name, SaraCommon.TABLE_NAME.SARA_DEFINITION);
3232
3233 var categoryId = saraDefinition.u_service_catalog_category;
3234 this.deactivateCategory(categoryId);
3235
3236 var catItemId = saraDefinition.u_sc_item;
3237 this.deactivateCatalogItem(catItemId);
3238
3239 // Deactivate definition in SaraCommon.TABLE_NAME.SARA_DEFINITION table
3240 LOGGER.info('Deactivating sara definition...');
3241 saraDefinition.u_active = false;
3242 this.saveOrUpdateSaraDefinition(saraDefinition);
3243 LOGGER.info('Deactivated sara definition');
3244
3245 LOGGER.info('Deactivating child definitions...');
3246 var parentCategoryId = saraDefinition.u_service_catalog_category;
3247 if(SaraUtils.isNullOrEmpty(parentCategoryId)) {
3248 parentCategoryId = saraDefinition.u_parent;
3249 }
3250
3251 if(saraDefinition.u_type === 'category' || saraDefinition.u_type === 'catalog') {
3252 var nextLevelType = saraDefinition.u_type === 'category' ? 'catalog' : 'service';
3253 // Deactive items which have parent is this category
3254 var childDefinitions = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
3255 'u_parent': parentCategoryId,
3256 'u_type': nextLevelType
3257 }, true);
3258
3259 if(childDefinitions.length === 0) {
3260 LOGGER.info("No child definition found");
3261 }
3262
3263 for (var i = 0; i < childDefinitions.length; i++) {
3264 var childDefinition = childDefinitions[i];
3265 this.deactivateSaraDefinition(childDefinition);
3266 }
3267 }
3268
3269 LOGGER.info('Deactivated sara definition and its child definitions');
3270 },
3271
3272 deactivateCatalogItem: function(catItemId) {
3273 var glideHelper = this.glideHelper;
3274 var LOGGER = this.LOGGER;
3275 if(!SaraUtils.isNullOrEmpty(catItemId)) {
3276 var catItem = glideHelper.getData(this.TABLES.SN_CATALOG_ITEM, {sys_id: catItemId});
3277 // Mark catalog item as deleted in SaraCommon.TABLE_NAME.SN_CATALOG_ITEM table
3278 LOGGER.info('Deactivating catalog item (sys_id = {0}, name = {1}) in table "{2}"', catItemId, catItem.name, SaraCommon.TABLE_NAME.SARA_CAT_ITEM);
3279 catItem.active = false;
3280 this.saveOrUpdateCatalogItem(catItem);
3281 LOGGER.info('Deactivated catalog item (sys_id = {0}, name = {1}) in table "{2}"', catItemId, catItem.name, SaraCommon.TABLE_NAME.SARA_CAT_ITEM);
3282 }
3283 },
3284
3285 saveOrUpdateEntity: function(entity, type) {
3286 SaraUtils.guardNotNullOrEmpty(entity, "entity cannot be null or empty");
3287 SaraUtils.guardNotNullOrEmpty(type, "type cannot be null or empty");
3288
3289 var LOGGER = this.LOGGER;
3290
3291 var mappingDefinition;
3292 for(var definedType in this.typeMaps) {
3293 if(type === definedType) {
3294 mappingDefinition = this.typeMaps[type];
3295 }
3296 }
3297
3298 if(mappingDefinition === undefined) {
3299 throw " Defined mapping for " + type + " not found.";
3300 }
3301
3302 //transfer properties to new data object
3303 var data = {};
3304
3305 for(var i = 0; i < mappingDefinition.fields.length; i++) {
3306 var fieldName = mappingDefinition.fields[i];
3307 if(entity[fieldName] !== undefined) {
3308 data[fieldName] = entity[fieldName];
3309 }
3310 else {
3311 if(fieldName === "active") {
3312 LOGGER.info("default active to true");
3313 data[fieldName] = true;
3314 }
3315 }
3316 }
3317
3318 if(!SaraUtils.isNullOrEmpty(entity.sys_id)) {
3319 data.id= entity.sys_id;
3320 }
3321
3322 this.LOGGER.info(" dal.saveOrUpdateEntity: Save or update entity: type = {0}, data = ({1}) -> staging table {2}", type, SaraJSON.stringify(data), mappingDefinition.stagingTable);
3323
3324 this.glideHelper.persistData(mappingDefinition.stagingTable, data);
3325
3326 this.LOGGER.info(" dal.saveOrUpdateEntity: done");
3327
3328 return data;
3329 },
3330
3331 getTypeMaps: function() {
3332 return {
3333 "catalog": {
3334 stagingTable: this.TABLES.SN_CATALOG_IST,
3335 table: this.TABLES.SN_CATALOG,
3336 fields: [
3337 "id",
3338 "title",
3339 "description",
3340 "active"]
3341 },
3342 "category": {
3343 stagingTable: this.TABLES.SN_CATEGORY_IST,
3344 table: this.TABLES.SN_CATEGORY,
3345 fields: [
3346 "id",
3347 "title",
3348 "homepage_renderer",
3349 "active",
3350 "description",
3351 "parent",
3352 "sc_catalog"]
3353 },
3354 "cat_item": {
3355 stagingTable: this.TABLES.SARA_CAT_ITEM_IST,
3356 table: this.TABLES.SARA_CAT_ITEM,
3357 fields: [
3358 "id",
3359 "name",
3360 "category",
3361 "active",
3362 "short_description",
3363 "description",
3364 "custom_cart",
3365 "use_sc_layout",
3366 "no_quantity",
3367 "workflow",
3368 "sc_catalogs"]
3369 },
3370 "var_set": {
3371 stagingTable: this.TABLES.SN_VARIABLE_SET_IST,
3372 table: this.TABLES.SN_VARIABLE_SET,
3373 fields: [
3374 "id",
3375 "name",
3376 "description",
3377 "title",
3378 "sys_name"
3379 ]
3380 },
3381 "var_set_item": {
3382 stagingTable: this.TABLES.SN_VARIABLE_SET_ITEM_IST,
3383 table: this.TABLES.SN_VARIABLE_SET_ITEM,
3384 fields: [
3385 "id",
3386 "sc_cat_item",
3387 "variable_set",
3388 ]
3389 },
3390 "sara_definition": {
3391 stagingTable: this.TABLES.SARA_DEFINITION_IST,
3392 table: this.TABLES.SARA_DEFINITION,
3393 fields: [
3394 "id",
3395 "u_name",
3396 "u_consume_url",
3397 "u_sc_item",
3398 "u_service_catalog_category",
3399 "u_var_set",
3400 "u_parent",
3401 "u_type",
3402 "u_hash",
3403 "u_active"]
3404 },
3405 "sara_variable": {
3406 stagingTable: this.TABLES.SARA_VARIABLE_IST,
3407 table: this.TABLES.SARA_VARIABLE,
3408 fields: [
3409 "id",
3410 "u_name",
3411 "u_readonly",
3412 "u_is_password",
3413 "u_is_lookup",
3414 "u_hash",
3415 "variable_set",
3416 "type",
3417 "macro",
3418 "name",
3419 "cat_item",
3420 "help_text",
3421 "show_help",
3422 "include_none",
3423 "default_value",
3424 "question_text",
3425 "mandatory",
3426 "list_table",
3427 "attributes",
3428 "lookup_table",
3429 "lookup_value",
3430 "reference_qual",
3431 "order",
3432 "active"]
3433 },
3434 "sara_lookup": {
3435 stagingTable: this.TABLES.SARA_LOOKUP_IST,
3436 table: this.TABLES.SARA_LOOKUP,
3437 fields: [
3438 "id",
3439 "u_key",
3440 "u_display_name",
3441 "u_control_id"]
3442 }
3443 };
3444 },
3445 type: 'SaraConsumerDAL'
3446};
3447]]></script>
3448 <description>Sara Consumer Data Access to read and import service definition to Service Catalog using staging tables</description>
3449 <active>true</active>
3450 <client_callable>false</client_callable>
3451 <access>public</access>
3452 </script_include>
3453
3454 <script_include>
3455 <name>SaraConsumerRunner</name>
3456 <script><![CDATA[/**
3457 * Runner for SaraConsumerImportSet
3458 */
3459var SaraConsumerRunner = Class.create();
3460SaraConsumerRunner.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
3461 start: function () {
3462 var LOGGER = new SaraLog(this);
3463
3464 var targetCatId = this.getParameter('sysparm_catid');
3465
3466 LOGGER.info('Starting SaraConsumerRunner for importing services into "{0}"...', targetCatId);
3467
3468 var worker = new GlideScriptedHierarchicalWorker();
3469 worker.setProgressName('Import Services');
3470 worker.setBackground(true);
3471 worker.setScriptIncludeName('x_ausgh_snsc.SaraConsumerWorker');
3472 worker.setScriptIncludeMethod('run');
3473 worker.putMethodArg('targetCatId', targetCatId);
3474 worker.start();
3475
3476 LOGGER.info('SaraConsumerWorker starts successfully!');
3477
3478 var progressID = worker.getProgressID();
3479
3480 LOGGER.info('ID of SaraConsumerWorker is {0}', progressID);
3481
3482 return progressID;
3483 },
3484
3485 type: 'SaraConsumerRunner'
3486
3487});
3488]]></script>
3489 <description>Worker for SaraConsumer</description>
3490 <active>true</active>
3491 <client_callable>true</client_callable>
3492 <access>public</access>
3493 </script_include>
3494
3495 <script_include>
3496 <name>SaraConsumerWorker</name>
3497 <script><![CDATA[/**
3498 * Worker for SaraConsumerImportSet
3499 */
3500var SaraConsumerWorker = Class.create();
3501SaraConsumerWorker.prototype = {
3502 initialize: function () {
3503 var LOGGER = this.LOGGER = new SaraLog(this);
3504 var tracker = null;
3505 try {
3506 tracker = GlideExecutionTracker.getLastRunning();
3507 } catch (e) {
3508 LOGGER.error('Error when getting tracker: {0}', e);
3509 }
3510
3511 this.tracker = tracker;
3512 },
3513
3514 run: function (targetCatId) {
3515 var LOGGER = this.LOGGER;
3516 if (targetCatId) {
3517 try {
3518 var consumer = new SaraConsumerImportSet(this.tracker);
3519 var result = consumer.discoverAndImport(targetCatId);
3520
3521 if (!result) {
3522 var statusCode = consumer.getStatusCode();
3523 var errorMessage = consumer.getErrorMessage();
3524
3525 if (statusCode != 200) {
3526 this.updateTrackerResult('Failed to import Automic services', true);
3527 this.tracker.fail('Got error: ' + statusCode + ' - ' + errorMessage);
3528 } else {
3529 this.updateTrackerResult('Got no service or catalog from server.', false);
3530 this.tracker.success('Got no service or catalog from server.');
3531 }
3532 } else {
3533 this.updateTrackerResult('Imported successfully', false, result);
3534 this.tracker.success('Imported successfully!');
3535 }
3536 } catch (err) {
3537 LOGGER.error('Failed to import Automic services', err);
3538 this.updateTrackerResult('Failed to import Automic services', true);
3539 this.tracker.fail(err);
3540 }
3541 } else {
3542 this.updateTrackerResult('Failed to import Automic services', true);
3543 this.tracker.fail('Target category id is null!');
3544 }
3545 },
3546
3547 /**
3548 * Update tracker result
3549 * @param {String} message The message content
3550 * @param {Boolean} error Error or not
3551 * @param {String} info The addition information
3552 */
3553 updateTrackerResult: function (message, error, info) {
3554 var LOGGER = this.LOGGER;
3555
3556 if (error) {
3557 LOGGER.error(message);
3558 } else {
3559 LOGGER.info(message);
3560 }
3561
3562 try {
3563 this.tracker.updateResult({
3564 msg: message,
3565 info: info
3566 });
3567 } catch (ex) {
3568 LOGGER.error('Error when updating result for tracker: {0}', ex);
3569 }
3570 },
3571
3572 type: 'SaraConsumerWorker'
3573
3574};
3575]]></script>
3576 <description>Runner for SaraConsumer</description>
3577 <active>true</active>
3578 <client_callable>false</client_callable>
3579 <access>public</access>
3580 </script_include>
3581
3582 <script_include>
3583 <name>SaraGlideHelper</name>
3584 <script><![CDATA[/**
3585 * Helper class provides convenient methods to work with ServiceNow data tables
3586 */
3587var SaraGlideHelper = Class.create();
3588SaraGlideHelper.prototype = {
3589 initialize: function () {},
3590
3591 /**
3592 * Common data persistent operation
3593 * @param {String} table The table name
3594 * @param {Object} entity Object represents the row to insert
3595 * @param {Boolean} referencing Insert with references or not
3596 * @return {String} sys_id of inserted row
3597 */
3598 persistData: function (table, entity, referencing) {
3599 try {
3600 var rec = this._getGlideRecord(table);
3601 rec.initialize();
3602
3603 for (key in entity) {
3604 var value = entity[key];
3605
3606 if (value === undefined || value === null) {
3607 value = '';
3608 }
3609
3610 // check if key contains 'sys_id'
3611 var idx = key.indexOf('.sys_id');
3612 if (idx > 0 && idx == key.length - 7) {
3613 var propName = key.substring(0, idx);
3614 rec[propName]['sys_id'] = value;
3615 } else {
3616 rec[key] = value;
3617 }
3618 }
3619
3620 if (referencing) {
3621 return rec.insertWithReferences();
3622 } else {
3623 return rec.insert();
3624 }
3625 } catch (e) {
3626 log('Cannot persistData: {0}' + JSON.stringify(e), 'INFO');
3627 }
3628 return null;
3629 },
3630
3631 /**
3632 * Updates record(s) in given table based on the query and entity object holds fields/values to update
3633 * @param {String} table Target table to update
3634 * @param {Object} queryObj Query object, property name is the field name to query, value is value to query
3635 * @param {Object} entity Entity holds fields and values to update
3636 * @param {Boolean} updateAll Update all matching record(s) or only the first one
3637 * @param {Boolean} referencing Update with references or not
3638 */
3639 updateData: function (table, queryObj, entity, updateAll, referencing) {
3640 var rec = this._getGlideRecord(table);
3641 this._buildQuery(rec, queryObj);
3642 rec.query();
3643
3644 while (rec.next()) {
3645 for (key in entity) {
3646 // check if key contains 'sys_id'
3647 var idx = key.indexOf('.sys_id');
3648 if (idx > 0 && idx == key.length - 7) {
3649 var propName = key.substring(0, idx);
3650 rec[propName]['sys_id'] = entity[key];
3651 } else {
3652 rec[key] = entity[key];
3653 }
3654 }
3655
3656 if (referencing) {
3657 rec.updateWithReferences();
3658 } else {
3659 rec.update();
3660 }
3661
3662 if (!updateAll) {
3663 break;
3664 }
3665 }
3666 },
3667
3668 /**
3669 * Retrieve sys_id of a record in given table by key=value query
3670 * @param {String} table The table name
3671 * @param {Object} queryObj The object holds the query, property name is the field name to query, value is value to query
3672 * @param {Boolean} getAll Get sys_id of all matching record(s) or only the first one
3673 * @return {String|Array<String>} sys_id that found, or null if no record found
3674 */
3675 getSysId: function (table, queryObj, getAll) {
3676 var rec = this._getGlideRecord(table);
3677 this._buildQuery(rec, queryObj);
3678 rec.query();
3679
3680 if (getAll) {
3681 var results = [];
3682 while (rec.next()) {
3683 results.push('' + rec['sys_id']);
3684 }
3685
3686 return results;
3687 } else {
3688 if (rec.next()) {
3689 return '' + rec['sys_id'];
3690 } else {
3691 return null;
3692 }
3693 }
3694 },
3695
3696 /**
3697 * Parse GlideRecordSecure into an object with same properties but value of properties will be converted to String. The
3698 * original properties will be store in '_origin' property
3699 * @param {GlideRecordSecure} rec The instance of GlideRecordSecure
3700 * @return {Object}
3701 */
3702 _parseRecord: function (rec) {
3703 var obj = {
3704 _origin: rec
3705 };
3706
3707 for (var key in rec) {
3708 try {
3709 obj[key] = '' + rec[key];
3710 } catch (e) {
3711 obj[key] = '' + rec[key].toString();
3712 }
3713 }
3714
3715 return obj;
3716 },
3717
3718 /**
3719 * Query data from given table and query condition, return objects contain information specified in list of key
3720 * @param {String} table The target table
3721 * @param {Object} queryObj The object holds the query, property name is the field name to query, value is value to query
3722 * @param {Boolean} getAll Get all matching record(s) or only the first one
3723 * @return {Array} Array of object
3724 */
3725 getData: function (table, queryObj, getAll) {
3726 var rec = this._getGlideRecord(table);
3727 this._buildQuery(rec, queryObj);
3728 rec.query();
3729
3730 if (getAll) {
3731 var result = [];
3732 while (rec.next()) {
3733 result.push(this._parseRecord(rec));
3734 }
3735
3736 return result;
3737 } else {
3738 if (rec.next()) {
3739 return this._parseRecord(rec);
3740 } else {
3741 return null;
3742 }
3743 }
3744 },
3745
3746 /**
3747 * Delete record(s) from given table based on a query condition
3748 * @param {String} table The target table
3749 * @param {Object} queryObj The object holds the query, property name is the field name to query, value is value to query
3750 * @param {Boolean} deleteAll Delete all matching record(s) or only the first one
3751 */
3752 deleteData: function (table, queryObj, deleteAll) {
3753 var rec = this._getGlideRecord(table);
3754 this._buildQuery(rec, queryObj);
3755
3756 if (deleteAll) {
3757 rec.deleteMultiple();
3758 } else {
3759 rec.query();
3760 if (rec.next()) {
3761 rec.deleteRecord();
3762 }
3763 }
3764 },
3765
3766 /**
3767 * Build query for GlideRecordSecure and also support Operators
3768 * @link http://wiki.servicenow.com/index.php?title=Using_GlideRecord_to_Query_Tables
3769 * @param {GlideRecordSecure} rec
3770 * @param {Object} queryObj
3771 * - @key {String} The field name
3772 * - @value {Array|String|Number} The field value. If array, value will be [Operator, Value]
3773 */
3774 _buildQuery: function (rec, queryObj) {
3775 for (var key in queryObj) {
3776 var value = queryObj[key];
3777
3778 if (typeof value === 'object' && value instanceof Array) {
3779 rec.addQuery(key, value[0], value[1]);
3780 } else {
3781 rec.addQuery(key, value);
3782 }
3783 }
3784 },
3785
3786 /**
3787 * Get instance of GlideRecordSecure
3788 * @param {String} table The target table
3789 * @return {GlideRecordSecure}
3790 */
3791 _getGlideRecord: function (table) {
3792 return new GlideRecordSecure(table);
3793 },
3794
3795 type: 'SaraGlideHelper'
3796};
3797]]></script>
3798 <description>Helper class provides convenient methods to work with ServiceNow data tables</description>
3799 <active>true</active>
3800 <client_callable>false</client_callable>
3801 <access>public</access>
3802 </script_include>
3803
3804 <script_include>
3805 <name>SaraJSON</name>
3806 <script><![CDATA[/**
3807 * Sara JSON Utilities
3808 */
3809var SaraJSON = Class.create();
3810SaraJSON.prototype = {
3811 initialize: function() {},
3812
3813 type: 'SaraJSON'
3814};
3815
3816/*
3817 JSON.js
3818 2013-05-26
3819
3820 Public Domain.
3821
3822 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
3823
3824 See http://www.JSON.org/js.html
3825
3826
3827 This code should be minified before deployment.
3828 See http://javascript.crockford.com/jsmin.html
3829
3830 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
3831 NOT CONTROL.
3832
3833
3834 This file creates a global JSON object containing two methods: stringify
3835 and parse.
3836
3837 JSON.stringify(value, replacer, space)
3838 value any JavaScript value, usually an object or array.
3839
3840 replacer an optional parameter that determines how object
3841 values are stringified for objects. It can be a
3842 function or an array of strings.
3843
3844 space an optional parameter that specifies the indentation
3845 of nested structures. If it is omitted, the text will
3846 be packed without extra whitespace. If it is a number,
3847 it will specify the number of spaces to indent at each
3848 level. If it is a string (such as '\t' or ' '),
3849 it contains the characters used to indent at each level.
3850
3851 This method produces a JSON text from a JavaScript value.
3852
3853 When an object value is found, if the object contains a toJSON
3854 method, its toJSON method will be called and the result will be
3855 stringified. A toJSON method does not serialize: it returns the
3856 value represented by the name/value pair that should be serialized,
3857 or undefined if nothing should be serialized. The toJSON method
3858 will be passed the key associated with the value, and this will be
3859 bound to the value
3860
3861 For example, this would serialize Dates as ISO strings.
3862
3863 Date.prototype.toJSON = function (key) {
3864 function f(n) {
3865 // Format integers to have at least two digits.
3866 return n < 10 ? '0' + n : n;
3867 }
3868
3869 return this.getUTCFullYear() + '-' +
3870 f(this.getUTCMonth() + 1) + '-' +
3871 f(this.getUTCDate()) + 'T' +
3872 f(this.getUTCHours()) + ':' +
3873 f(this.getUTCMinutes()) + ':' +
3874 f(this.getUTCSeconds()) + 'Z';
3875 };
3876
3877 You can provide an optional replacer method. It will be passed the
3878 key and value of each member, with this bound to the containing
3879 object. The value that is returned from your method will be
3880 serialized. If your method returns undefined, then the member will
3881 be excluded from the serialization.
3882
3883 If the replacer parameter is an array of strings, then it will be
3884 used to select the members to be serialized. It filters the results
3885 such that only members with keys listed in the replacer array are
3886 stringified.
3887
3888 Values that do not have JSON representations, such as undefined or
3889 functions, will not be serialized. Such values in objects will be
3890 dropped; in arrays they will be replaced with null. You can use
3891 a replacer function to replace those with JSON values.
3892 JSON.stringify(undefined) returns undefined.
3893
3894 The optional space parameter produces a stringification of the
3895 value that is filled with line breaks and indentation to make it
3896 easier to read.
3897
3898 If the space parameter is a non-empty string, then that string will
3899 be used for indentation. If the space parameter is a number, then
3900 the indentation will be that many spaces.
3901
3902 Example:
3903
3904 text = JSON.stringify(['e', {pluribus: 'unum'}]);
3905 // text is '["e",{"pluribus":"unum"}]'
3906
3907
3908 text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
3909 // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
3910
3911 text = JSON.stringify([new Date()], function (key, value) {
3912 return this[key] instanceof Date ?
3913 'Date(' + this[key] + ')' : value;
3914 });
3915 // text is '["Date(---current time---)"]'
3916
3917
3918 JSON.parse(text, reviver)
3919 This method parses a JSON text to produce an object or array.
3920 It can throw a SyntaxError exception.
3921
3922 The optional reviver parameter is a function that can filter and
3923 transform the results. It receives each of the keys and values,
3924 and its return value is used instead of the original value.
3925 If it returns what it received, then the structure is not modified.
3926 If it returns undefined then the member is deleted.
3927
3928 Example:
3929
3930 // Parse the text. Values that look like ISO date strings will
3931 // be converted to Date objects.
3932
3933 myData = JSON.parse(text, function (key, value) {
3934 var a;
3935 if (typeof value === 'string') {
3936 a =
3937 /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
3938 if (a) {
3939 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
3940 +a[5], +a[6]));
3941 }
3942 }
3943 return value;
3944 });
3945
3946 myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
3947 var d;
3948 if (typeof value === 'string' &&
3949 value.slice(0, 5) === 'Date(' &&
3950 value.slice(-1) === ')') {
3951 d = new Date(value.slice(5, -1));
3952 if (d) {
3953 return d;
3954 }
3955 }
3956 return value;
3957 });
3958
3959
3960 This is a reference implementation. You are free to copy, modify, or
3961 redistribute.
3962 */
3963
3964/*jslint evil: true, regexp: true */
3965
3966/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
3967 call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
3968 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
3969 lastIndex, length, parse, prototype, push, replace, slice, stringify,
3970 test, toJSON, toString, valueOf
3971 */
3972
3973(function(JSON) {
3974 'use strict';
3975
3976 function f(n) {
3977 // Format integers to have at least two digits.
3978 return n < 10 ? '0' + n : n;
3979 }
3980
3981 function toJSON(value) {
3982 if (value instanceof Date) {
3983 return isFinite(date.valueOf()) ? date.getUTCFullYear() + '-' +
3984 f(date.getUTCMonth() + 1) + '-' +
3985 f(date.getUTCDate()) + 'T' +
3986 f(date.getUTCHours()) + ':' +
3987 f(date.getUTCMinutes()) + ':' +
3988 f(date.getUTCSeconds()) + 'Z' : null;
3989 } else {
3990 switch (typeof value) {
3991 case 'string':
3992 case 'number':
3993 case 'boolean':
3994 return value.valueOf();
3995 }
3996 }
3997 }
3998
3999 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
4000 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
4001 gap,
4002 indent,
4003 meta = { // table of character substitutions
4004 '\b': '\\b',
4005 '\t': '\\t',
4006 '\n': '\\n',
4007 '\f': '\\f',
4008 '\r': '\\r',
4009 '"': '\\"',
4010 '\\': '\\\\'
4011 },
4012 rep;
4013
4014
4015 function quote(string) {
4016
4017 // If the string contains no control characters, no quote characters, and no
4018 // backslash characters, then we can safely slap some quotes around it.
4019 // Otherwise we must also replace the offending characters with safe escape
4020 // sequences.
4021
4022 escapable.lastIndex = 0;
4023 return escapable.test(string) ? '"' + string.replace(escapable, function(a) {
4024 var c = meta[a];
4025 return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
4026 }) + '"' : '"' + string + '"';
4027 }
4028
4029
4030 function str(key, holder) {
4031
4032 // Produce a string from holder[key].
4033
4034 var i, // The loop counter.
4035 k, // The member key.
4036 v, // The member value.
4037 length,
4038 mind = gap,
4039 partial,
4040 value = holder[key];
4041
4042 // If the value has a toJSON method, call it to obtain a replacement value.
4043
4044 if (value && typeof value === 'object' && typeof toJSON(value) === 'function') {
4045 value = toJSON(value, key);
4046 }
4047
4048 // If we were called with a replacer function, then call the replacer to
4049 // obtain a replacement value.
4050
4051 if (typeof rep === 'function') {
4052 value = rep.call(holder, key, value);
4053 }
4054
4055 // What happens next depends on the value's type.
4056
4057 switch (typeof value) {
4058 case 'string':
4059 return quote(value);
4060
4061 case 'number':
4062
4063 // JSON numbers must be finite. Encode non-finite numbers as null.
4064
4065 return isFinite(value) ? String(value) : 'null';
4066
4067 case 'boolean':
4068 case 'null':
4069
4070 // If the value is a boolean or null, convert it to a string. Note:
4071 // typeof null does not produce 'null'. The case is included here in
4072 // the remote chance that this gets fixed someday.
4073
4074 return String(value);
4075
4076 // If the type is 'object', we might be dealing with an object or an array or
4077 // null.
4078
4079 case 'object':
4080
4081 // Due to a specification blunder in ECMAScript, typeof null is 'object',
4082 // so watch out for that case.
4083
4084 /**
4085 * MUST to check the type of object is Array or not because if value = [''], !value always is true on Rhino
4086 * @modifiedBy: dhm@automic.com
4087 */
4088 if (!value && Object.prototype.toString.apply(value) !== '[object Array]') {
4089 return 'null';
4090 }
4091
4092 // Make an array to hold the partial results of stringifying this object value.
4093
4094 gap += indent;
4095 partial = [];
4096
4097 // Is the value an array?
4098
4099 if (Object.prototype.toString.apply(value) === '[object Array]') {
4100
4101 // The value is an array. Stringify every element. Use null as a placeholder
4102 // for non-JSON values.
4103
4104 length = value.length;
4105 for (i = 0; i < length; i += 1) {
4106 partial[i] = str(i, value) || 'null';
4107 }
4108
4109 // Join all of the elements together, separated with commas, and wrap them in
4110 // brackets.
4111
4112 v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
4113 gap = mind;
4114 return v;
4115 }
4116
4117 // If the replacer is an array, use it to select the members to be stringified.
4118
4119 if (rep && typeof rep === 'object') {
4120 length = rep.length;
4121 for (i = 0; i < length; i += 1) {
4122 if (typeof rep[i] === 'string') {
4123 k = rep[i];
4124 v = str(k, value);
4125 if (v) {
4126 partial.push(quote(k) + (gap ? ': ' : ':') + v);
4127 }
4128 }
4129 }
4130 } else {
4131
4132 // Otherwise, iterate through all of the keys in the object.
4133
4134 for (k in value) {
4135 if (Object.prototype.hasOwnProperty.call(value, k)) {
4136 v = str(k, value);
4137 if (v) {
4138 partial.push(quote(k) + (gap ? ': ' : ':') + v);
4139 }
4140 }
4141 }
4142 }
4143
4144 // Join all of the member texts together, separated with commas,
4145 // and wrap them in braces.
4146
4147 v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
4148 gap = mind;
4149 return v;
4150 }
4151 }
4152
4153 // If the JSON object does not yet have a stringify method, give it one.
4154
4155 if (typeof JSON.stringify !== 'function') {
4156 JSON.stringify = function(value, replacer, space) {
4157
4158 // The stringify method takes a value and an optional replacer, and an optional
4159 // space parameter, and returns a JSON text. The replacer can be a function
4160 // that can replace values, or an array of strings that will select the keys.
4161 // A default replacer method can be provided. Use of the space parameter can
4162 // produce text that is more easily readable.
4163
4164 var i;
4165 gap = '';
4166 indent = '';
4167
4168 // If the space parameter is a number, make an indent string containing that
4169 // many spaces.
4170
4171 if (typeof space === 'number') {
4172 for (i = 0; i < space; i += 1) {
4173 indent += ' ';
4174 }
4175
4176 // If the space parameter is a string, it will be used as the indent string.
4177
4178 } else if (typeof space === 'string') {
4179 indent = space;
4180 }
4181
4182 // If there is a replacer, it must be a function or an array.
4183 // Otherwise, throw an error.
4184
4185 rep = replacer;
4186 if (replacer && typeof replacer !== 'function' &&
4187 (typeof replacer !== 'object' ||
4188 typeof replacer.length !== 'number')) {
4189 throw new Error('JSON.stringify');
4190 }
4191
4192 // Make a fake root object containing our value under the key of ''.
4193 // Return the result of stringifying the value.
4194
4195 return str('', {
4196 '': value
4197 });
4198 };
4199 }
4200
4201 // Because with SCOPED_APP, we can't use 'eval' function as the original so we decided to use 'decode' function of
4202 // ServiceNow's JSON class for our 'SaraJSON.parse'
4203 if (typeof JSON.parse !== 'function') {
4204 JSON.parse = function(text, reviver) {
4205 return new global.JSON().decode(text, reviver);
4206 };
4207 }
4208
4209})(SaraJSON);
4210]]></script>
4211 <description>Sara JSON Utilities</description>
4212 <active>true</active>
4213 <client_callable>false</client_callable>
4214 <access>public</access>
4215 </script_include>
4216
4217 <script_include>
4218 <name>SaraLog</name>
4219 <script><![CDATA[/**
4220 * Log Utilities for Sara
4221 */
4222var SaraLog = Class.create();
4223SaraLog.prototype = {
4224 /**
4225 * Init logger
4226 * @param {Object|String} className The class name of object. Will be append after timestamp.
4227 * If is not String, will get the className from 'type' property of object
4228 */
4229 initialize: function (className) {
4230 this.className = typeof className === 'string' ? className : className.type;
4231 },
4232
4233 _log: function (message) {
4234 return SaraUtils.formatString('[{0}] [{1}] {2}', SaraUtils.getTimeStamp(), this.className, message.toString());
4235 },
4236
4237 info: function () {
4238 var message = SaraUtils.formatString.apply(this, arguments);
4239 message = this._log(message);
4240
4241 gs.info(message);
4242 },
4243
4244 debug: function () {
4245 var message = SaraUtils.formatString.apply(this, arguments);
4246 message = this._log(message);
4247
4248 gs.debug(message);
4249 },
4250
4251 error: function () {
4252 var message = SaraUtils.formatString.apply(this, arguments);
4253 message = this._log(message);
4254
4255 gs.error(message);
4256 },
4257
4258 warn: function () {
4259 var message = SaraUtils.formatString.apply(this, arguments);
4260 message = this._log(message);
4261
4262 gs.warn(message);
4263 },
4264
4265 type: 'SaraLog'
4266
4267};
4268]]></script>
4269 <description>Log Utilities for Sara</description>
4270 <active>true</active>
4271 <client_callable>false</client_callable>
4272 <access>public</access>
4273 </script_include>
4274
4275 <script_include>
4276 <name>SaraModel</name>
4277 <script><![CDATA[/**
4278 * SARA concepts modelling in Service Now
4279 */
4280var SaraModel = {}
4281
4282/**
4283 * CatalogItem object represents a SN service catalog item
4284 * @constructor
4285 */
4286SaraModel.CatalogItem = Class.create();
4287SaraModel.CatalogItem.prototype = {
4288 initialize: function () {},
4289
4290 setName: function (name) {
4291 this.name = name;
4292 },
4293
4294 getName: function () {
4295 return this.name;
4296 },
4297
4298 setCategory: function (category) {
4299 this.category = category;
4300 },
4301
4302 getCategory: function () {
4303 return this.category;
4304 },
4305
4306 unsetCategory: function () {
4307 delete this.category;
4308 },
4309
4310 setActive: function (active) {
4311 this.active = active;
4312 },
4313
4314 isActive: function () {
4315 return this.active;
4316 },
4317
4318 setWorkflow: function (workflow) {
4319 this.workflow = workflow;
4320 },
4321
4322 getWorkflow: function () {
4323 return this.workflow;
4324 },
4325
4326 setShortDesc: function (shortDesc) {
4327 this.shortDesc = shortDesc;
4328 },
4329
4330 getShortDesc: function (shortDesc) {
4331 return this.shortDesc;
4332 },
4333
4334 setDescription: function (description) {
4335 this.description = description;
4336 },
4337
4338 getDescription: function () {
4339 return this.description;
4340 },
4341
4342 setVariables: function (variables) {
4343 this.variables = variables;
4344 },
4345
4346 getVariables: function (variables) {
4347 return this.variables;
4348 },
4349
4350 setConsumeUrl: function (consumeUrl) {
4351 this.consumeUrl = consumeUrl;
4352 },
4353
4354 getConsumeUrl: function () {
4355 return this.consumeUrl;
4356 },
4357
4358 setServiceName: function (serviceName) {
4359 this.serviceName = serviceName;
4360 },
4361
4362 getServiceName: function () {
4363 return this.serviceName;
4364 },
4365
4366 setCustomCart: function (customCart) {
4367 this.customCart = customCart;
4368 },
4369
4370 getCustomCart: function () {
4371 return this.customCart;
4372 },
4373
4374 setSNCatalog: function(catalog) {
4375 this.sc_catalog = catalog;
4376 },
4377
4378 getSNCatalog: function() {
4379 return this.sc_catalog;
4380 },
4381
4382 setHash: function (hash) {
4383 this.hash = hash;
4384 },
4385
4386 getHash: function () {
4387 return this.hash;
4388 },
4389
4390 type: 'SaraModel.CatalogItem'
4391};
4392
4393/**
4394 * CatalogVariable object represents a SN service virable
4395 * @constructor
4396 */
4397SaraModel.CatalogVariable = Class.create();
4398SaraModel.CatalogVariable.prototype = {
4399 initialize: function () {},
4400
4401 setName: function (name) {
4402 this.name = name;
4403 },
4404
4405 getName: function () {
4406 return this.name;
4407 },
4408
4409 setType: function (type) {
4410 this.type = type;
4411 },
4412
4413 getType: function () {
4414 return this.type;
4415 },
4416
4417 setLabel: function (label) {
4418 this.label = label;
4419 },
4420
4421 getLabel: function () {
4422 return this.label;
4423 },
4424
4425 setDefaultValue: function (defaultValue) {
4426 this.defaultValue = defaultValue;
4427 },
4428
4429 getDefaultValue: function () {
4430 return this.defaultValue;
4431 },
4432
4433 setDescription: function (description) {
4434 this.description = description;
4435 },
4436
4437 getDescription: function () {
4438 return this.description;
4439 },
4440
4441 setRange: function (range) {
4442 this.range = range;
4443 },
4444
4445 getRange: function () {
4446 return this.range;
4447 },
4448
4449 setActualName: function (actualName) {
4450 this.actualName = actualName;
4451 },
4452
4453 getActualName: function () {
4454 return this.actualName;
4455 },
4456
4457 setAsPassword: function (asPassword) {
4458 this.asPassword = asPassword;
4459 },
4460
4461 isPassword: function (isPassword) {
4462 return this.asPassword;
4463 },
4464
4465 setRequired: function (required) {
4466 this.required = required;
4467 },
4468
4469 isRequired: function (required) {
4470 return this.required;
4471 },
4472
4473 setMultiSelect: function (multiSelect) {
4474 this.multiSelect = multiSelect;
4475 },
4476
4477 isMultiSelect: function (multiSelect) {
4478 return this.multiSelect;
4479 },
4480
4481 setAsLookup: function (asLookup) {
4482 this.asLookup = asLookup;
4483 },
4484
4485 isLookup: function () {
4486 return this.asLookup;
4487 },
4488
4489 setHash: function (hash) {
4490 this.hash = hash;
4491 },
4492
4493 getHash: function () {
4494 return this.hash;
4495 },
4496
4497 setOrder: function (order) {
4498 this.order = order;
4499 },
4500
4501 getOrder: function () {
4502 if(this.order)
4503 return this.order;
4504 return 0;
4505 },
4506
4507 type: 'SaraModel.CatalogVariable'
4508};
4509
4510/**
4511 * CatalogCategory object represents a SN service catalog category
4512 * @constructor
4513 */
4514SaraModel.CatalogCategory = Class.create();
4515SaraModel.CatalogCategory.prototype = {
4516 initialize: function () {},
4517
4518 setTitle: function (title) {
4519 this.title = title;
4520 },
4521
4522 getTitle: function () {
4523 return this.title;
4524 },
4525
4526 setName: function (name) {
4527 this.name = name;
4528 },
4529
4530 getName: function () {
4531 return this.name;
4532 },
4533
4534 setParent: function (parent) {
4535 this.parent = parent;
4536 },
4537
4538 getParent: function () {
4539 return this.parent;
4540 },
4541
4542 unsetParent: function () {
4543 delete this.parent;
4544 },
4545
4546 setActive: function (active) {
4547 this.active = active;
4548 },
4549
4550 isActive: function () {
4551 return this.active;
4552 },
4553
4554 setDescription: function (description) {
4555 this.description = description;
4556 },
4557
4558 getDescription: function () {
4559 return this.description;
4560 },
4561
4562 setConsumeUrl: function (consumeUrl) {
4563 this.consumeUrl = consumeUrl;
4564 },
4565
4566 getConsumeUrl: function () {
4567 return this.consumeUrl;
4568 },
4569
4570 setAsNew: function (asNew) {
4571 this.asNew = asNew;
4572 },
4573
4574 isNew: function () {
4575 return this.asNew;
4576 },
4577
4578 unsetAsNew: function () {
4579 delete this.asNew;
4580 },
4581
4582 setSysId: function (sysId) {
4583 this.sysId = sysId;
4584 },
4585
4586 getSysId: function () {
4587 return this.sysId;
4588 },
4589
4590 unsetSysId: function () {
4591 delete this.sysId;
4592 },
4593
4594 setSNCatalog: function(catalog) {
4595 this.sc_catalog = catalog;
4596 },
4597
4598 getSNCatalog: function() {
4599 return this.sc_catalog;
4600 },
4601
4602 type: 'SaraModel.CatalogCategory'
4603};
4604]]></script>
4605 <description>SARA concepts modelling in Service Now</description>
4606 <active>true</active>
4607 <client_callable>false</client_callable>
4608 <access>package_private</access>
4609 </script_include>
4610
4611 <script_include>
4612 <name>SaraOAuthAjax</name>
4613 <script><![CDATA[/**
4614 * AJAX facade for SaraOAuthClient
4615 */
4616var SaraOAuthAjax = Class.create();
4617SaraOAuthAjax.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {
4618 /**
4619 * Get OAuth URL with redirection endpoint and client id in query string
4620 * @return {String}
4621 */
4622 getOAuthUrl: function () {
4623 var LOGGER = new SaraLog(this);
4624
4625 try {
4626 var clientId = this.getParameter('sysparm_client_id').toString();
4627 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4628 var authEndpoint = this.getParameter('sysparm_auth_endpoint').toString();
4629 var redirectionEndpoint = SaraUtils.getRedirectionUrl();
4630
4631 LOGGER.info('auth_endpoint={0}; redirect_uri={1}; client_id={2}; technical_user={3}', authEndpoint, redirectionEndpoint, clientId, technicalUser);
4632
4633 return authEndpoint
4634 + '?redirect_uri=' + escape(redirectionEndpoint)
4635 + '&client_id=' + escape(clientId)
4636 + '&user_info=' + escape(technicalUser)
4637 + '&user_info_editable=false'
4638 + '&response_type=code';
4639 } catch (e) {
4640 this.logError(e);
4641 }
4642
4643 return;
4644 },
4645
4646 /**
4647 * Request token by using Username and password
4648 * @return {String}
4649 */
4650 requestToken: function () {
4651 var LOGGER = new SaraLog(this);
4652
4653 try {
4654 var username = this.getParameter('sysparm_username').toString();
4655 var password = this.getParameter('sysparm_password').toString();
4656 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4657
4658 var oauthClient = new SaraOAuthClient();
4659 var tokens = oauthClient.requestToken(username, password);
4660
4661 LOGGER.info('Token: {0}', SaraJSON.stringify(tokens));
4662
4663 if (tokens && !tokens.error && tokens['access_token']) {
4664 oauthClient.storeUserTokens(technicalUser, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
4665 return 'ok';
4666 } else {
4667 return tokens.error ? tokens.error : (!tokens['access_token'] ? 'Empty result' : '');
4668 }
4669 } catch (e) {
4670 this.logError(e);
4671 }
4672
4673 return;
4674 },
4675
4676 /**
4677 * Request token by authorization code
4678 * @return {String}
4679 */
4680 requestTokenByCode: function () {
4681 var LOGGER = new SaraLog(this);
4682
4683 try {
4684 var code = this.getParameter('sysparm_code').toString();
4685 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4686 LOGGER.info('Request token for user "{0}" by using code {1}', technicalUser, code);
4687
4688
4689 var config = {};
4690 config[SaraCommon.CONFIG_NAME.CLIENT_ID] = this.getParameter('sysparm_client_id').toString();
4691 config[SaraCommon.CONFIG_NAME.CLIENT_SECERT] = this.getParameter('sysparm_client_secret').toString();
4692 config[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT] = this.getParameter('sysparm_token_endpoint').toString();
4693
4694 var oauthClient = new SaraOAuthClient();
4695 var tokens = oauthClient.requestTokenByCode(code, config);
4696
4697 LOGGER.info('Token info: {0}', SaraJSON.stringify(tokens));
4698
4699 if (tokens && !tokens.error && tokens['access_token']) {
4700 oauthClient.storeUserTokens(technicalUser, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
4701
4702 return 'ok';
4703 } else {
4704 return tokens.error ? tokens.error : (!tokens['access_token'] ? 'Empty result' : '');
4705 }
4706 } catch (e) {
4707 this.logError(e);
4708 }
4709
4710 return;
4711 },
4712
4713 /**
4714 * Get client configuration
4715 */
4716 getConfig: function () {
4717 var LOGGER = new SaraLog(this);
4718
4719 try {
4720 var configData = new SaraConfig().getClientConfig();
4721
4722 LOGGER.info('OAuth Configuration: \n'
4723 + ' - Client ID = {0} \n'
4724 + ' - Client Secret = *** \n'
4725 + ' - Technical User = {1} \n'
4726 + ' - SAPI Endpoint = {2} \n'
4727 + ' - Token Endpoint = {3} \n'
4728 + ' - Auth Endpoint = {4} \n',
4729 configData[SaraCommon.CONFIG_NAME.CLIENT_ID],
4730 configData[SaraCommon.CONFIG_NAME.TECHNICAL_USER],
4731 configData[SaraCommon.CONFIG_NAME.SAPI_ENDPOINT],
4732 configData[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT],
4733 configData[SaraCommon.CONFIG_NAME.AUTH_ENDPOINT]
4734 );
4735
4736 var config = this.newItem('config');
4737 for (var key in SaraCommon.CONFIG_NAME) {
4738 var name = SaraCommon.CONFIG_NAME[key];
4739
4740 config.setAttribute(name, configData[name]);
4741 }
4742 } catch (e) {
4743 this.logError(e);
4744 }
4745
4746 return;
4747 },
4748
4749 /**
4750 * Validate access token key
4751 */
4752 validateToken: function () {
4753 var LOGGER = new SaraLog(this);
4754
4755 try {
4756 var technicalUser = this.getParameter('sysparm_technical_user').toString();
4757 var glideHelper = new SaraGlideHelper();
4758 var saraOAuth = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_OAUTH, {
4759 'u_user': technicalUser
4760 });
4761
4762 if (saraOAuth) {
4763 var token = saraOAuth['u_access_token'].toString();
4764 var sapiEndpoint = this.getParameter('sysparm_sapi_endpoint').toString();
4765 var oauthClient = new SaraOAuthClient();
4766 var result = oauthClient.validateToken(token, sapiEndpoint);
4767
4768 LOGGER.debug('Result of validating token: {0}', result.toString());
4769
4770 if (typeof result === 'boolean') {
4771 this.addItem('result', {
4772 isValid: result
4773 });
4774 } else {
4775 this.addItem('result', {
4776 message: result
4777 });
4778 }
4779 } else {
4780 LOGGER.info('Technical User "{1}" does not have tokens', technicalUser);
4781
4782 this.addItem('result', {
4783 isValid: false
4784 });
4785 }
4786
4787 } catch (e) {
4788 this.logError(e);
4789 }
4790
4791 return;
4792 },
4793
4794 /**
4795 * Log error
4796 * @param {Error} error
4797 * @param {SaraLog} LOGGER
4798 */
4799 logError: function (error, LOGGER) {
4800 LOGGER.error('{0}', error);
4801
4802 this.addItem('error', {
4803 message: error
4804 });
4805 },
4806
4807 /**
4808 * Add item in response
4809 * @param {String} itemName The name of item
4810 * @param {Object<String, String>} attributes The object contains item's attributes
4811 */
4812 addItem: function (itemName, attributes) {
4813 var item = this.newItem(itemName);
4814
4815 for (var name in attributes) {
4816 var value = attributes[name];
4817
4818 item.setAttribute(name, value);
4819 }
4820 },
4821
4822 type: 'SaraOAuthAjax'
4823});
4824]]></script>
4825 <description>AJAX facade for SaraOAuthClient</description>
4826 <active>true</active>
4827 <client_callable>true</client_callable>
4828 <access>package_private</access>
4829 </script_include>
4830
4831 <script_include>
4832 <name>SaraOAuthClient</name>
4833 <script><![CDATA[/**
4834 * This class contains all OAuth-relaled functions
4835 */
4836var SaraOAuthClient = Class.create();
4837SaraOAuthClient.prototype = {
4838 /**
4839 * Init new OAuth Client from SaraRESTClient object
4840 * @param {SaraRestCLient} restClient
4841 */
4842 initialize: function (restClient) {
4843 this.glideHelper = new SaraGlideHelper();
4844 this.saraConfig = new SaraConfig();
4845 this.LOGGER = new SaraLog(this);
4846
4847 if (!restClient) {
4848 this.restClient = new SaraRESTClient();
4849 this.restClient.setMIDServer(SaraUtils.getMIDServer());
4850 } else {
4851 this.restClient = restClient;
4852 }
4853 },
4854
4855 /**
4856 * Store user tokens into 'SaraCommon.TABLE_NAME.SARA_OAUTH' table
4857 * @param {String} username The username which owns tokens
4858 * @param {String} accessToken The access token of user
4859 * @param {String} refreshToken The refresh token of user
4860 * @param {String} tokenExpiry The expiry of token
4861 * @param {String} tokenType The type of token
4862 * @return {String} The sys_id of user tokens record
4863 */
4864 storeUserTokens: function (username, accessToken, refreshToken, tokenExpiry, tokenType) {
4865 var LOGGER = this.LOGGER;
4866
4867 if (!username) {
4868 LOGGER.info('Store user token: Username must not be empty!');
4869 return;
4870 }
4871
4872 if (!accessToken) {
4873 LOGGER.info('Error: Access token must be non-empty!');
4874 return;
4875 }
4876
4877 LOGGER.info('Preparing for storing user tokens...');
4878
4879 // Request tokens of user in 'SaraCommon.TABLE_NAME.SARA_OAUTH' table
4880 var saraOAuth = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4881 'u_user': username
4882 });
4883
4884 // If user's tokens are existed
4885 if (saraOAuth) {
4886 LOGGER.info('User\'s tokens are existed. Updating tokens...');
4887
4888 this.glideHelper.updateData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4889 'sys_id': saraOAuth['sys_id']
4890 }, {
4891 'u_access_token': accessToken,
4892 'u_refresh_token': refreshToken,
4893 'u_token_expiry': tokenExpiry,
4894 'u_token_type': tokenType
4895 });
4896
4897 return saraOAuth['sys_id'];
4898 } else {
4899 LOGGER.info('Storing user\'s tokens...');
4900
4901 return this.glideHelper.persistData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4902 'u_user': username,
4903 'u_access_token': accessToken,
4904 'u_refresh_token': refreshToken,
4905 'u_token_expiry': tokenExpiry,
4906 'u_token_type': tokenType
4907 });
4908 }
4909 },
4910
4911 /**
4912 * Get user tokens by username. The result will be [accessToken, refreshToken, tokenExpiry, tokenType, { createdAt, createdBy, updateAt, updateBy }]
4913 * @param {String} username
4914 * @return {Array<String|Object>}
4915 */
4916 getUserTokens: function (username) {
4917 var LOGGER = this.LOGGER;
4918
4919 if (!username) {
4920 return null;
4921 }
4922
4923 var saraOAuth = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4924 'u_user': username
4925 });
4926
4927 if (saraOAuth) {
4928 return [
4929 saraOAuth['u_access_token'],
4930 saraOAuth['u_refresh_token'],
4931 saraOAuth['u_token_expiry'],
4932 saraOAuth['u_token_type'], {
4933 'createdAt': saraOAuth['sys_created_on'],
4934 'createdBy': saraOAuth['sys_created_by'],
4935 'updatedAt': saraOAuth['sys_updated_on'],
4936 'updatedBy': saraOAuth['sys_updated_by']
4937 }
4938 ];
4939 } else {
4940 LOGGER.info('Tokens of "{0}" do not exist!', username);
4941 return null;
4942 }
4943 },
4944
4945 /**
4946 * Remove user tokens by username
4947 * @param {String} username
4948 * @return {String} The sys_id of deleted record
4949 */
4950 removeUserToken: function (username) {
4951 var LOGGER = this.LOGGER;
4952
4953 if (!username) {
4954 return null;
4955 }
4956
4957 var saraOAuth = this.glideHelper.getData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4958 'u_user': username
4959 });
4960
4961 if (saraOAuth) {
4962 saraOAuth = this.glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_OAUTH, {
4963 'sys_id': saraOAuth['sys_id']
4964 });
4965
4966 return saraOAuth['sys_id'];
4967 } else {
4968 LOGGER.info('No token found for user "{0}"', username);
4969 return null;
4970 }
4971 },
4972
4973 /**
4974 * Requests user tokens, the request must use client_id/client_secret to authenticate (BASICally) against SARA server,
4975 * LDAP username/password and grant_type will be embedded in request's body
4976 * @param {String} username
4977 * @param {String} password
4978 * @return {Object} Object contains access token, refresh token, token expiry and token type
4979 */
4980 requestToken: function (username, password) {
4981 var LOGGER = this.LOGGER;
4982
4983 LOGGER.debug('Preparing for requesting tokens for SARA user {0}...', username);
4984
4985 var clientInfo = this.saraConfig.getClientConfig();
4986 var clientId = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_ID];
4987 var clientSecret = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_SECERT];
4988 var tokenEndpoint = clientInfo[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
4989
4990 var request = this.restClient.newOAuthRequest('post', tokenEndpoint);
4991 request.setBasicAuth(clientId, clientSecret);
4992
4993 // Add POST body, set Content-Type header
4994 request.setContentType('application/x-www-form-urlencoded');
4995 var formEntity = {
4996 'grant_type': 'password',
4997 'username': username,
4998 'password': password
4999 };
5000 request.setFormContent(formEntity);
5001
5002 LOGGER.info('Requesting tokens for SARA user {0}...', username);
5003 var response = this.restClient.execute(request);
5004 var responseObject = response.getResponseObject();
5005
5006 if (response.haveError()) {
5007 LOGGER.info('Failed to request token for user {0}', username);
5008
5009 return {
5010 'error': responseObject.errorMessage,
5011 'error_description': responseObject.errorDescription
5012 }
5013 }
5014
5015 LOGGER.info('Successfully obtain token for user {0}', username);
5016 return responseObject.bodyObject;
5017 },
5018
5019 /**
5020 * Requests user tokens, the request must use client_id/client_secret to authenticate (BASICally) against SARA server,
5021 * LDAP redirect_uri/authorization_code and grant_type will be embedded in request's body
5022 * @param {String} code The authorization code which get from OAuth after logged-in successfully in Auth Endpoint
5023 * @param {Object} config The config of OAuth Server
5024 * @return {Object} Object contains access token, refresh token, token expiry and token type
5025 */
5026 requestTokenByCode: function (code, config) {
5027 var LOGGER = this.LOGGER;
5028
5029 LOGGER.debug('Preparing for requesting tokens by code "{0}"...', code);
5030
5031 var clientId = config[SaraCommon.CONFIG_NAME.CLIENT_ID];
5032 var clientSecret = config[SaraCommon.CONFIG_NAME.CLIENT_SECERT];
5033 var tokenEndpoint = config[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
5034 var redirectionEndpoint = SaraUtils.getRedirectionUrl();
5035
5036 var request = this.restClient.newOAuthRequest('post', tokenEndpoint);
5037 request.setBasicAuth(clientId, clientSecret);
5038
5039 // Add POST body, set Content-Type header
5040 request.setContentType('application/x-www-form-urlencoded');
5041 var formEntity = {
5042 'grant_type': 'authorization_code',
5043 'redirect_uri': redirectionEndpoint,
5044 'code': code
5045 };
5046 request.setFormContent(formEntity);
5047
5048 LOGGER.info('Requesting tokens by code...');
5049 var response = this.restClient.execute(request);
5050 var responseObject = response.getResponseObject();
5051
5052 if (response.haveError()) {
5053 LOGGER.info('Failed to request token by code');
5054
5055 return {
5056 'error': responseObject.errorMessage,
5057 'error_description': responseObject.errorDescription
5058 }
5059 }
5060
5061 LOGGER.info('Successfully obtain token for user by code "{0}"', code);
5062 return responseObject.bodyObject;
5063 },
5064
5065 /**
5066 * Refresh user tokens
5067 * @param {String} username
5068 * @return {Object}
5069 */
5070 refreshToken: function (username) {
5071 var LOGGER = this.LOGGER;
5072
5073 // Get refresh tokens for this user from 'SaraCommon.TABLE_NAME.SARA_OAUTH' table
5074 var tokens = this.getUserTokens(username);
5075 if (!tokens || tokens.length < 1) {
5076 LOGGER.info('Tokens not found for user {0}', username);
5077 return null;
5078 }
5079
5080 LOGGER.info('Preparing for refreshing tokens for user {0}...', username);
5081
5082 // Use that refesh token to retrieve new tokens
5083 var clientInfo = this.saraConfig.getClientConfig();
5084 var clientId = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_ID];
5085 var clientSecret = clientInfo[SaraCommon.CONFIG_NAME.CLIENT_SECRET];
5086 var tokenEndpoint = clientInfo[SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
5087 var request = this.restClient.newOAuthRequest('post', tokenEndpoint);
5088 request.setBasicAuth(clientId, clientSecret);
5089
5090 // Add POST body, set Content-Type header
5091 request.setContentType('application/x-www-form-urlencoded');
5092 request.setFormContent({
5093 'grant_type': 'refresh_token',
5094 'refresh_token': tokens[1]
5095 });
5096
5097 LOGGER.info('Refreshing tokens for user {0}...', username);
5098 var response = this.restClient.execute(request);
5099 var responseObject = response.getResponseObject();
5100
5101 if (response.haveError()) {
5102 LOGGER.info('Failed to refresh token for code');
5103
5104 return {
5105 'error': responseObject.errorMessage,
5106 'error_description': responseObject.errorDescription
5107 }
5108 }
5109
5110 LOGGER.info('Successfully refresh token for user {0}', username);
5111 return responseObject.bodyObject;
5112 },
5113
5114 /**
5115 * Validate access token key of user is invalid or expired
5116 * @param {String} token The access token key of user
5117 * @param {String} sapiEndpoint The SAPI endpoint
5118 * @return {Boolean|String}
5119 */
5120 validateToken: function (token, sapiEndpoint) {
5121 var LOGGER = this.LOGGER;
5122
5123 LOGGER.info('Preparing for validating token "{0}"...', token.toString());
5124
5125 var configData = this.saraConfig.getClientConfig();
5126 var response = this.executeGetRequest(token, sapiEndpoint);
5127 var responseObject = response.getResponseObject();
5128
5129 if (response.haveError()) {
5130 if (responseObject.statusCode !== 401) {
5131 var message = SaraUtils.formatString('Error when validating token! Error code: {0} - Error message: {1}', responseObject.statusCode, responseObject.errorMessage);
5132 LOGGER.error(message);
5133 return message;
5134 } else {
5135 var username = this.saraConfig.getTechnicalUser();
5136 this.removeUserToken(username);
5137 return false;
5138 }
5139 } else {
5140 LOGGER.info('Preparing for validating services endpoint ...');
5141 response = this.executeGetRequest(token, SaraUtils.buildUrl('services', sapiEndpoint));
5142 responseObject = response.getResponseObject();
5143 LOGGER.debug('Response of validating services endpoint {0} ...', JSON.stringify(responseObject));
5144 if(responseObject.statusCode === 200) {
5145 return true;
5146 }
5147 LOGGER.error(responseObject.errorMessage);
5148 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);
5149 }
5150 },
5151
5152 /**
5153 * Execute get request
5154 * @param {String} token The access token key of user
5155 * @param {String} sapiEndpoint The SAPI endpoint
5156 * @return {SaraRESTResponse}
5157 */
5158 executeGetRequest: function (token, sapiEndpoint) {
5159 var request = this.restClient.newSAPIRequest('get', sapiEndpoint);
5160 request.addHeader('Authorization', 'bearer ' + token);
5161 return this.restClient.executeWithRefreshToken(request);
5162 },
5163
5164 type: 'SaraOAuthClient'
5165};
5166]]></script>
5167 <description>This class contains all OAuth-relaled functions</description>
5168 <active>true</active>
5169 <client_callable>false</client_callable>
5170 <access>public</access>
5171 </script_include>
5172
5173 <script_include>
5174 <name>SaraRESTClient</name>
5175 <script><![CDATA[/**
5176 * Wraps Service Now RESTMessage in a class to provide convenient methods interacting with SARA REST
5177 */
5178var SaraRESTClient = Class.create();
5179SaraRESTClient.prototype = {
5180 initialize: function () {
5181 this.LOGGER = new SaraLog(this);
5182 },
5183
5184 /**
5185 * Init new service request from SaraRESTMessage class
5186 * @param {String} name The name of the REST message record
5187 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5188 * @param {String} endpoint The endpoint for the REST message
5189 * @param {Array<String>} basicAuthCreds The basic authentication headers for the REST message
5190 * @param {Array<Object>} headers The object contains headers for the REST message
5191 * @param {Array<Object>} stringParameters The object contains string parameters for the REST message
5192 * @param {Array<Object>} stringParametersNoEscape The object contains string parameters which will be not escaped for the REST message
5193 * @return {SaraRESTMessage}
5194 */
5195 newServiceRequest: function (name, method, endpoint, basicAuthCreds, headers, stringParameters, stringParametersNoEscape) {
5196 var restMsg = new SaraRESTMessage(name, method);
5197
5198 if (endpoint) {
5199 restMsg.setEndpoint(endpoint);
5200 }
5201
5202 if (this.midServer) {
5203 restMsg.setMIDServer(this.midServer);
5204 }
5205
5206 if (basicAuthCreds && basicAuthCreds.length > 1) {
5207 restMsg.setBasicAuth(basicAuthCreds[0], basicAuthCreds[1]);
5208 }
5209
5210 if (headers) {
5211 for (var i = 0, header; header = headers[i]; i++) {
5212 if (header['name']) {
5213 restMsg.addHeader(header['name'], header['value']);
5214 }
5215 }
5216 }
5217
5218 if (stringParameters) {
5219 for (var i = 0, stringParameter; stringParameter = stringParameters[i]; i++) {
5220 if (stringParameter['name']) {
5221 restMsg.setStringParameter(stringParameter['name'], stringParameter['value']);
5222 }
5223 }
5224 }
5225
5226 if (stringParametersNoEscape) {
5227 for (var i = 0, stringParameter; stringParameter = stringParametersNoEscape[i]; i++) {
5228 if (stringParameter['name']) {
5229 restMsg.setStringParameterNoEscape(stringParameter['name'], stringParameter['value']);
5230 }
5231 }
5232 }
5233
5234 return restMsg;
5235 },
5236
5237 /**
5238 * Init new SAPI service request from SaraRESTMessage class
5239 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5240 * @param {String} endpoint The endpoint for the REST message
5241 * @param {Array<String>} basicAuthCreds The basic authentication headers for the REST message
5242 * @param {Array<Object>} headers The object contains headers for the REST message
5243 * @param {Array<Object>} stringParameters The object contains string parameters for the REST message
5244 * @param {Array<Object>} stringParametersNoEscape The object contains string parameters which will be not escaped for the REST message
5245 * @return {SaraRESTMessage}
5246 */
5247 newSAPIRequest: function (method, endpoint, basicAuthCreds, headers, stringParameters, stringParametersNoEscape) {
5248 return this.newServiceRequest(SaraCommon.REST_NAME.SAPI, method, endpoint, basicAuthCreds, headers)
5249 },
5250
5251 /**
5252 * Init new OAuth service request from SaraRESTMessage class
5253 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5254 * @param {String} endpoint The endpoint for the REST message
5255 * @param {Array<String>} basicAuthCreds The basic authentication headers for the REST message
5256 * @param {Array<Object>} headers The object contains headers for the REST message
5257 * @param {Array<Object>} stringParameters The object contains string parameters for the REST message
5258 * @param {Array<Object>} stringParametersNoEscape The object contains string parameters which will be not escaped for the REST message
5259 * @return {SaraRESTMessage}
5260 */
5261 newOAuthRequest: function (method, endpoint, basicAuthCreds, headers, stringParameters, stringParametersNoEscape) {
5262 return this.newServiceRequest(SaraCommon.REST_NAME.OAUTH, method, endpoint, basicAuthCreds, headers)
5263 },
5264
5265 /**
5266 * Execute REST Message request
5267 * @param {SaraRESTMessage} saraRest Sara REST Message object
5268 * @return {SaraRESTResponse}
5269 */
5270 execute: function (saraRest) {
5271 var LOGGER = this.LOGGER;
5272
5273 LOGGER.info('Making {0} request to {1}...', saraRest.getMethod(), saraRest.getEndpoint());
5274 LOGGER.debug(saraRest.dump());
5275
5276 var response;
5277 if (this.midServer) {
5278 response = saraRest.executeViaMIDServer(this.midServer);
5279 } else {
5280 response = saraRest.execute();
5281 }
5282
5283 return response;
5284 },
5285
5286 /**
5287 * Execute REST Message request with automatically get new token if token is expired
5288 * @param {SaraRESTMessage} saraRest Sara REST Message object
5289 * @return {SaraRESTResponse}
5290 */
5291 executeWithRefreshToken: function (saraRest) {
5292 var LOGGER = this.LOGGER;
5293
5294 // First time request
5295 var response = this.execute(saraRest);
5296 var responseObject = response.getResponseObject();
5297
5298 if (response.haveError()) {
5299 if (responseObject.statusCode === 401) {
5300 LOGGER.info('Access token of user is invalid or expired');
5301
5302 var oauthClient = new SaraOAuthClient(this);
5303 var username = new SaraConfig().getTechnicalUser();
5304
5305 LOGGER.info('Trying to refresh token for user "{0}"...', username);
5306 var tokens = oauthClient.refreshToken(username);
5307
5308 if (tokens && !tokens.error) {
5309 LOGGER.info('Refresh token finished successfully.');
5310 oauthClient.storeUserTokens(username, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
5311
5312 // Request again with new token
5313 saraRest.addHeader('Authorization', 'bearer ' + tokens['access_token']);
5314 response = this.execute(saraRest);
5315 } else {
5316 LOGGER.error('Error when refreshing token');
5317
5318 if (!tokens) {
5319 LOGGER.info('Error: {0} - Error description: {1}', tokens.error, tokens.errorDescription);
5320 oauthClient.removeUserToken(username);
5321 }
5322 }
5323 }
5324 }
5325
5326 return response;
5327 },
5328
5329 /**
5330 * Set MID Server
5331 * @param {String} midServer The MID Server name
5332 */
5333 setMIDServer: function (midServer) {
5334 this.midServer = midServer;
5335 },
5336
5337 type: 'SaraRESTClient'
5338};
5339]]></script>
5340 <description>Wraps Service Now RESTMessage in a class to provide convenient methods interacting with SARA REST</description>
5341 <active>true</active>
5342 <client_callable>false</client_callable>
5343 <access>public</access>
5344 </script_include>
5345
5346 <script_include>
5347 <name>SaraRESTMessage</name>
5348 <script><![CDATA[/**
5349 * Wrap original ServiceNow's RESTMessageV2 class to make HTTP request
5350 */
5351var SaraRESTMessage = Class.create();
5352SaraRESTMessage.prototype = {
5353 /**
5354 * Init Sara REST Message object
5355 * @param {String} name Name of REST message record
5356 * @param {String} method The name of the HTTP method to use, such as GET or PUT
5357 */
5358 initialize: function (name, method) {
5359 method = method.toLowerCase();
5360 this.restMsg = new sn_ws.RESTMessageV2(name, method);
5361 this.restMsg.setEccParameter('skip_sensor', true);
5362 this.name = name;
5363 this.method = method;
5364
5365 this.LOGGER = new SaraLog(this);
5366 },
5367
5368 /**
5369 * Set the content of the REST message body
5370 * @param {String} content The content of REST Message
5371 */
5372 setContent: function (content) {
5373 this.restMsg.setRequestBody(content);
5374 },
5375
5376 /**
5377 * Set form content for REST Message
5378 * @param {Object} formData The object contains form data
5379 */
5380 setFormContent: function (formData) {
5381 if (!formData) {
5382 return;
5383 }
5384
5385 var content = '';
5386
5387 for (var propName in formData) {
5388 var value = formData[propName];
5389
5390 if (value instanceof Array) {
5391 for (var i = 0; i < value.length; i++) {
5392 var _value = value[i];
5393
5394 content += (encodeURIComponent(propName) + '=' + encodeURIComponent(_value) + '&');
5395 }
5396 } else {
5397 content += (encodeURIComponent(propName) + '=' + encodeURIComponent(value) + '&');
5398 }
5399 }
5400
5401 if (content.length > 0) {
5402 content = content.substring(0, content.length - 1);
5403 this.setContent(content);
5404 }
5405 },
5406
5407 /**
5408 * Get the content of the REST message body
5409 * @return {String}
5410 */
5411 getContent: function () {
5412 return this.restMsg.getRequestBody();
5413 },
5414
5415 /**
5416 * Add headers for REST Message
5417 * @param {String} key The key of header
5418 * @param {*} value The value of header
5419 */
5420 addHeader: function (key, value) {
5421 var LOGGER = this.LOGGER;
5422
5423 LOGGER.debug('addHeader: key = "{0}" and value = "{1}"', key, value);
5424
5425 this.restMsg.setRequestHeader(key, value);
5426 },
5427
5428 /**
5429 * Add type for header named 'content-type'
5430 * @param {String} type The content type of REST Message
5431 */
5432 setContentType: function (type) {
5433 var LOGGER = this.LOGGER;
5434
5435 LOGGER.debug('setContentType: type = "{0}"', type);
5436
5437 this.addHeader('content-type', type);
5438 },
5439
5440 /**
5441 * Set basic authentication headers for the REST message
5442 * @param {String} usename
5443 * @param {String} password
5444 */
5445 setBasicAuth: function (username, password) {
5446 var LOGGER = this.LOGGER;
5447
5448 LOGGER.debug('setBasicAuth: username = "{0}" and password = "{1}"', username, password);
5449
5450 this.restMsg.setBasicAuth(username, password);
5451 },
5452
5453 /**
5454 * Set a REST message function variable to the specified value
5455 * @param {String} name The name of parameter
5456 * @param {String} value The value of parameter
5457 */
5458 setStringParameter: function (name, value) {
5459 var LOGGER = this.LOGGER;
5460
5461 LOGGER.debug('setStringParameter: name = "{0}" and value = "{1}"', name, value);
5462
5463 this.restMsg.setStringParameter(name, value);
5464 },
5465
5466 /**
5467 * Set a REST message function variable to the specified value without escaping XML reserved characters
5468 * @param {String} name The name of parameter
5469 * @param {String} value The value of parameter
5470 */
5471 setStringParameterNoEscape: function (name, value) {
5472 var LOGGER = this.LOGGER;
5473
5474 LOGGER.debug('setStringParameterNoEscape: name = "{0}" and value = "{1}"', name, value);
5475
5476 this.restMsg.setStringParameterNoEscape(name, value);
5477 },
5478
5479 /**
5480 * Set the endpoint for the REST message
5481 * @param {String} endpoint
5482 */
5483 setEndpoint: function (endpoint) {
5484 var LOGGER = this.LOGGER;
5485
5486 LOGGER.debug('setEndpoint: endpoint = "{0}"', endpoint);
5487
5488 this.restMsg.setEndpoint(endpoint);
5489 },
5490
5491 /**
5492 * Get the URL of the endpoint for the REST message.
5493 * @return {String}
5494 */
5495 getEndpoint: function () {
5496 return this.restMsg.getEndpoint();
5497 },
5498
5499 /**
5500 * Configure the REST message to communicate through a MID Server.
5501 * @param {String} midServer The name of MID Server
5502 */
5503 setMIDServer: function (midServer) {
5504 var LOGGER = this.LOGGER;
5505
5506 LOGGER.debug('setMIDServer: midServer = "{0}"', midServer);
5507
5508 this.restMsg.setMIDServer(midServer);
5509 },
5510
5511 /**
5512 * Send REST Message to endpoint
5513 * @return {}
5514 */
5515 execute: function () {
5516 return new SaraRESTResponse(this.restMsg.execute());
5517 },
5518
5519 /**
5520 * Execute REST request via MID Server
5521 * @param {String} midServer The name of MID Server
5522 */
5523 executeViaMIDServer: function (midServer) {
5524 var LOGGER = this.LOGGER;
5525
5526 if (midServer) {
5527 this.restMsg.setMIDServer(midServer);
5528 this.midServer = midServer;
5529 LOGGER.info('Using MID Server {0}', this.midServer);
5530 }
5531
5532 if (!this.midServer) {
5533 LOGGER.info('No MID Server defined for the request. Request is aborted!');
5534 return null;
5535 }
5536
5537 return new SaraRESTResponse(this.restMsg.execute(), true);
5538 },
5539
5540 /**
5541 * Get method name of this REST Message
5542 * @return {String}
5543 */
5544 getMethod: function () {
5545 return this.method.toUpperCase();
5546 },
5547
5548 /**
5549 * Dump information of REST Message
5550 */
5551 dump: function () {
5552 var LOGGER = this.LOGGER;
5553
5554 try {
5555 var str = this.getMethod() + ' ' + this.getEndpoint() + ' HTTP/1.1';
5556
5557 var headers = this.restMsg.getRequestHeaders();
5558 if (headers) {
5559 for (key in headers) {
5560 var value = headers[key];
5561
5562 if (!gs.nil(value)) {
5563 if (key === 'Authorization') {
5564 value = '**********************';
5565 }
5566
5567 str += SaraUtils.formatString('\n {0}: {1}', key, value);
5568 }
5569 }
5570 }
5571
5572 var content = this.getContent();
5573
5574 if (!gs.nil(content) && content !== 'undefined' && content) {
5575 str += SaraUtils.formatString('\n\n', content);
5576 }
5577
5578 return str;
5579 } catch (error) {
5580 LOGGER.info('Error in SaraRESTMessage.dump(): ' + error);
5581 }
5582 },
5583
5584 type: 'SaraRESTMessage'
5585};
5586]]></script>
5587 <description>Class extend from original ServiceNow's RESTMessage class to make HTTP request</description>
5588 <active>true</active>
5589 <client_callable>false</client_callable>
5590 <access>package_private</access>
5591 </script_include>
5592
5593 <script_include>
5594 <name>SaraRESTResponse</name>
5595 <script><![CDATA[/**
5596 * Wrap original ServiceNow's RESTResponseV2 class to handle response of RESTMessageV2
5597 */
5598var SaraRESTResponse = Class.create();
5599SaraRESTResponse.prototype = {
5600 /**
5601 * Init Sara REST Response object
5602 * @param {sn_ws.RESTResponseV2} response The response object of RESTResponseV2
5603 * @param {Boolean} useMIDServer Get response via MID Server or not
5604 */
5605 initialize: function (response, useMIDServer) {
5606 this.response = response;
5607
5608 var LOGGER = this.LOGGER = new SaraLog(this);
5609
5610 if (useMIDServer) {
5611 var timeout = SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.REST_REQUEST_TIMEOUT);
5612 LOGGER.debug('Timeout for REST Message: {0}s', timeout);
5613 response.waitForResponse(timeout);
5614 }
5615
5616 if (response.haveError()) {
5617 LOGGER.info('Error when requesting REST Message: {0} - {1}', response.getErrorCode(), response.getErrorMessage());
5618 } else {
5619 LOGGER.info('Status code: {0}', response.getStatusCode());
5620 }
5621
5622 LOGGER.debug('Response body: {0}', response.getBody());
5623 },
5624
5625 /**
5626 * Set the amount of time the instance waits for the response
5627 * @param {Number} timeoutSecs The amount of time, in seconds, to wait for this response.
5628 */
5629 waitForResponse: function (timeoutSecs) {
5630 this.response.waitForResponse(timeoutSecs);
5631 },
5632
5633 /**
5634 * Get the numeric HTTP status code returned by the REST provider
5635 * @return {Number}
5636 */
5637 getStatusCode: function () {
5638 return this.response.getStatusCode();
5639 },
5640
5641 /**
5642 * Get the value for a specified header
5643 * @param {Number} timeoutSecs The name of the header that you want the value for, such as Set-Cookie.
5644 * @return {String}
5645 */
5646 getHeader: function (name) {
5647 return this.response.getHeader(name);
5648 },
5649
5650 /**
5651 * Get all headers returned in the REST response and the associated values
5652 * @return {Object}
5653 */
5654 getHeaders: function () {
5655 return this.response.getHeaders();
5656 },
5657
5658 /**
5659 * Get the content of the REST response body
5660 * @return {String}
5661 */
5662 getBody: function () {
5663 return this.response.getBody();
5664 },
5665
5666 /**
5667 * Indicate if there was an error during the REST transaction
5668 * @return {Boolean}
5669 */
5670 haveError: function () {
5671 return this.response.haveError();
5672 },
5673
5674 /**
5675 * Get the numeric error code if there was an error during the REST transaction. This error code is
5676 * specific to the ServiceNow platform, it is not an HTTP error code. Provide this error code if you
5677 * require assistance from ServiceNow Customer Support
5678 * @return {Number}
5679 */
5680 getErrorCode: function () {
5681 return this.response.getErrorCode();
5682 },
5683
5684 /**
5685 * Get the error message if there was an error during the REST transaction
5686 * @return {String}
5687 */
5688 getErrorMessage: function () {
5689 return this.response.getErrorMessage();
5690 },
5691
5692 /**
5693 * Get the fully-resolved query sent to the REST endpoint. This query contains the endpoint URL as well
5694 * as any values assigned to variables in the REST message
5695 */
5696 getQueryString: function () {
5697 return this, response.getQueryString();
5698 },
5699
5700 /**
5701 * Get response body with format is Object
5702 * @return {Object|Null}
5703 */
5704 getBodyObject: function () {
5705 var LOGGER = this.LOGGER;
5706
5707 var body = this.getBody();
5708 if (body) {
5709 try {
5710 body = SaraJSON.parse(body);
5711 } catch (ex) {
5712 LOGGER.error('Error when parsing response body to Object: {0}', ex);
5713 }
5714 }
5715
5716 return body;
5717 },
5718
5719 /**
5720 * Get response with format is Object. This response contains body object, status code, error message and
5721 * error description
5722 * @return {Object}
5723 */
5724 getResponseObject: function () {
5725 var bodyObject = this.getBodyObject();
5726 var statusCode = this.getStatusCode();
5727 var errorMessage = this.getErrorMessage();
5728 var errorDescription = this.getErrorMessage();
5729
5730 if (bodyObject) {
5731 if (bodyObject['error']) {
5732 errorMessage = bodyObject['error'];
5733 }
5734
5735 if (bodyObject['error_description']) {
5736 errorDescription = bodyObject['error_description'];
5737 }
5738 }
5739
5740 return {
5741 bodyObject: bodyObject,
5742 statusCode: statusCode,
5743 errorMessage: errorMessage,
5744 errorDescription: errorDescription
5745 }
5746 },
5747
5748 type: 'SaraRESTResponse'
5749};
5750]]></script>
5751 <description>Wrap original ServiceNow's RESTResponseV2 class to handle RESTMessageV2 response</description>
5752 <active>true</active>
5753 <client_callable>false</client_callable>
5754 <access>package_private</access>
5755 </script_include>
5756
5757 <script_include>
5758 <name>SaraSync</name>
5759 <script><![CDATA[/**
5760 * Sara Sync Utilities
5761 */
5762var SaraSync = Class.create();
5763SaraSync.prototype = {
5764 initialize: function () {
5765 this.glideHelper = new SaraGlideHelper();
5766 this.LOGGER = new SaraLog(this);
5767 this.dal = new SaraConsumerDAL();
5768 },
5769
5770 /**
5771 * Sync services and catalogs of all category which was imported services
5772 */
5773 syncServices: function () {
5774 var glideHelper = this.glideHelper;
5775 var LOGGER = this.LOGGER;
5776
5777 var importedCategories = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {
5778 'u_type': 'category'
5779 }, true);
5780
5781 if (importedCategories.length > 0) {
5782 LOGGER.info('There are {0} target category(s) which were imported services\n', importedCategories.length);
5783
5784 var consumer = new SaraConsumerImportSet();
5785 var response = consumer.discover();
5786
5787 if (response.error) {
5788 LOGGER.error('Discover data from SAPI not successfully. Syncing services is aborted!');
5789 return;
5790 } else {
5791 for (var i = 0; i < importedCategories.length; i++) {
5792 var importedCategory = importedCategories[i];
5793 LOGGER.info('Syncing target category (name = {0}, sys_id = {1})', importedCategory.u_name, importedCategory.u_parent);
5794
5795 consumer.doImport(importedCategory.u_parent);
5796 consumer.refreshImportedData();
5797
5798 LOGGER.info('Target category (name = {0}, sys_id = {1}) is synced!', importedCategory.u_name, importedCategory.u_parent);
5799 }
5800 }
5801 } else {
5802 LOGGER.warn('No target category found. Skip syncServices!');
5803 }
5804 },
5805
5806 /**
5807 * Sync all lookup values of catalog item
5808 * @param {String} saraItem The catalog item in SaraCommon.TABLE_NAME.SARA_DEFINITION
5809 * @param {SaraModel.CatalogItem} catalogItem
5810 */
5811 //saraCatalogItem, catalogItem
5812 syncLookup: function (existDefinition, sapiService) {
5813 var glideHelper = this.glideHelper;
5814 var LOGGER = this.LOGGER;
5815
5816 LOGGER.info('Starting syncLookup... definition: {0}; sapiService: {1}',
5817 SaraJSON.stringify(existDefinition), SaraJSON.stringify(sapiService));
5818
5819 if (sapiService.getVariables()) {
5820 // Get variable set of catalog item
5821 var varSetId = existDefinition.u_var_set;
5822 LOGGER.info('Found sys_id of variable set of {0} is: {1}', existDefinition.u_name, varSetId);
5823
5824 // Get lookup variables of variable set
5825 var saraLookupVariables = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_VARIABLE, {
5826 'variable_set': varSetId,
5827 'u_is_lookup': true
5828 }, true);
5829
5830 if (saraLookupVariables.length > 0) {
5831 LOGGER.info('Found {0} lookup variable(s) in variable set (sys_id = {1})', saraLookupVariables.length, varSetId);
5832
5833 for (var i = 0; i < saraLookupVariables.length; i++) {
5834 var saraVariable = saraLookupVariables[i];
5835 LOGGER.info("Processing variable: " + saraVariable.name);
5836 var variable = this.getVariable(sapiService, saraVariable.name);
5837 if(variable !== null) {
5838 this.updateLookupVariable(saraVariable, variable);
5839 }
5840 }
5841 } else {
5842 LOGGER.warn('No lookup variable found in variable set (sys_id = {0}). Skip syncLookup!', varSetId);
5843 }
5844 } else {
5845 LOGGER.warn('There\' no variable found in catalog (item name = {0}). Skip syncLookup!', existDefinition.u_name);
5846 }
5847
5848 LOGGER.info('Ended syncLookup!');
5849 },
5850
5851 /**
5852 * Get variable from instance of SaraModel.CatalogItem
5853 * @param {SaraModel.CatalogItem} catalogItem
5854 * @param {String} saraVariableName
5855 * @return {SaraModel.CatalogVariable||Null}
5856 */
5857 getVariable: function (sapiService, saraVariableName) {
5858 for (var i = 0; i < sapiService.variables.length; i++) {
5859 if (sapiService.variables[i].name === saraVariableName) {
5860 return sapiService.variables[i];
5861 }
5862 }
5863
5864 return null;
5865 },
5866
5867 /**
5868 * Update lookup variable
5869 * @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'
5870 * @param {SaraModel.CatalogVariable} variable
5871 */
5872 updateLookupVariable: function (saraVariable, variable) {
5873 var glideHelper = this.glideHelper;
5874 var LOGGER = this.LOGGER;
5875
5876 LOGGER.info('New and old hash of variable "{0}": {1} - {2}', saraVariable.name, variable.getHash(), saraVariable.u_hash);
5877
5878 if (variable.getHash() === saraVariable.u_hash) {
5879 LOGGER.info('Lookup value of variable "{0}" is not changed!', saraVariable.name);
5880 } else {
5881 LOGGER.info('Lookup value of variable "{0}" is changed!', saraVariable.name);
5882
5883 this.deactivateOldLookupValues(saraVariable);
5884
5885 var newDefaultValues = [];
5886 var ranges = SaraUtils.removeDuplicatedLookup(variable.getRange());
5887
5888 // Insert new range values
5889 for (var i = 0; i < ranges.length; i++) {
5890 var range = ranges[i];
5891 var key = range.Value;
5892 var display = range.Key;
5893 if(!range.Value) {
5894 key = SaraCommon.EMPTY_VALUE.KEY;
5895 display = SaraCommon.EMPTY_VALUE.VALUE;
5896 }
5897
5898 var rangeId = this.dal.saveOrUpdateSaraLookup({
5899 'u_key': key,
5900 'u_display_name': display,
5901 'u_control_id': saraVariable.sys_id
5902 }).sys_id;
5903
5904 if (SaraUtils.inArray(variable.getDefaultValue(), display)) {
5905 if(variable.getType() === SaraCommon.VAR_TYPE.LIST_COLLECTOR) {
5906 newDefaultValues.push(rangeId);
5907 }
5908 else {
5909 newDefaultValues.push(display);
5910 }
5911 }
5912 }
5913 LOGGER.info('Inserted new data of {0} in {1}!', saraVariable.name, SaraCommon.TABLE_NAME.SARA_LOOKUP);
5914
5915 if (saraVariable.default_value) {
5916 newDefaultValues = newDefaultValues.join(',');
5917
5918 saraVariable.default_value = newDefaultValues;
5919 saraVariable.u_hash = variable.getHash();
5920 this.dal.saveOrUpdateVariable(saraVariable);
5921
5922 LOGGER.info('Updated default value for variable (name = {0}, sys_id = {1}) with new default_value = {2}',
5923 saraVariable.name, saraVariable.sys_id, newDefaultValues);
5924 }
5925 }
5926 },
5927
5928 deactivateOldLookupValues: function(saraVariable) {
5929 var glideHelper = this.glideHelper;
5930 var LOGGER = this.LOGGER;
5931 // Remove the old data of lookup table
5932 var lookups = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_LOOKUP, {
5933 'u_control_id': saraVariable.sys_id
5934 }, true);
5935
5936 for(var i = 0; i < lookups.length; i++) {
5937 var lookup = lookups[i];
5938 lookup.u_control_id = "";
5939 this.dal.saveOrUpdateSaraLookup(lookup);
5940 }
5941
5942 LOGGER.info('Deactivated old data of {0} in {1}!', saraVariable.name, SaraCommon.TABLE_NAME.SARA_LOOKUP);
5943 },
5944
5945 type: 'SaraSync'
5946};
5947]]></script>
5948 <description>Sara Sync Utilities</description>
5949 <active>true</active>
5950 <client_callable>false</client_callable>
5951 <access>public</access>
5952 </script_include>
5953
5954 <script_include>
5955 <name>SaraUtils</name>
5956 <script><![CDATA[/**
5957 * Sara Utilities
5958 */
5959var SaraUtils = Class.create();
5960SaraUtils.prototype = {
5961 initialize: function () {},
5962
5963 type: 'SaraUtils'
5964};
5965
5966/**
5967 * Format strings
5968 * @param {String} string The template string
5969 * @param {String[]} args Zero or more objects to format, supplied either in a comma-delimited list or as an array
5970 */
5971SaraUtils.formatString = function (string) {
5972 if(!string) {
5973 return "";
5974 }
5975 var args = Array.prototype.slice.call(arguments, 1);
5976
5977 return string.replace(/\{(\d+)\}/g, function (match, number) {
5978 return typeof args[number] != 'undefined' ? args[number] : match;
5979 });
5980};
5981
5982/**
5983 * Get Sara property
5984 * @param {String} name Name of sara property
5985 * @return {String}
5986 */
5987SaraUtils.getSaraProperty = function (name) {
5988 var property = gs.getProperty(SaraCommon.PROP_PREFIX + '.' + name);
5989 if(property == null) {
5990 property = gs.getProperty(name);
5991 }
5992
5993 return property;
5994};
5995
5996/**
5997 * Get mid servcer
5998 * @return {String}
5999 */
6000SaraUtils.getMIDServer = function () {
6001 return SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.MID_SERVER);
6002};
6003
6004/**
6005 * Get timestamp of current
6006 * @return {String}
6007 */
6008SaraUtils.getTimeStamp = function () {
6009 return new Date().valueOf();
6010};
6011
6012/**
6013 * Get random number
6014 * @return {String}
6015 */
6016SaraUtils.getRandom = function () {
6017 return Math.round(Math.random() * 987654321);
6018};
6019
6020/**
6021 * Diff time and return 'h, m, s'
6022 * @param {Number} time1 The first timestamp
6023 * @param {Number} time2 The second timestamp
6024 * @return {String}
6025 */
6026SaraUtils.diffTime = function (time1, time2) {
6027 var difference = time2 - time1;
6028
6029 var daysDifference = Math.floor(difference / 1000 / 60 / 60 / 24);
6030 difference -= daysDifference * 1000 * 60 * 60 * 24;
6031
6032 var hoursDifference = Math.floor(difference / 1000 / 60 / 60);
6033 difference -= hoursDifference * 1000 * 60 * 60;
6034
6035 var minutesDifference = Math.floor(difference / 1000 / 60);
6036 difference -= minutesDifference * 1000 * 60;
6037
6038 var secondsDifference = Math.floor(difference / 1000);
6039 difference -= secondsDifference * 1000;
6040
6041 var result = '';
6042
6043 if (daysDifference > 0) {
6044 result += daysDifference + 'd ';
6045 }
6046
6047 if (hoursDifference > 0) {
6048 result += hoursDifference + 'h ';
6049 }
6050
6051 if (minutesDifference > 0) {
6052 result += minutesDifference + 'm ';
6053 }
6054
6055 if (secondsDifference > 0) {
6056 result += secondsDifference + 's ';
6057 }
6058
6059 result += difference + 'ms';
6060
6061 return result;
6062};
6063
6064/**
6065 * Convert '\n' to '<br />' in string
6066 * @param {String} string
6067 * @return {String}
6068 */
6069SaraUtils.nl2br = function (string) {
6070 string = string || '';
6071
6072 return string.replace(/\n/g, '<br />');
6073};
6074
6075/**
6076 * Clean all data of SNSC
6077 */
6078SaraUtils.cleanup = function (filter) {
6079 if (!gs.hasRole(SaraCommon.ROLES.ADMIN)) {
6080 var message = 'You dont\'t have sufficient permission to do this action. Allowed role: ' + SaraCommon.ROLES.ADMIN;
6081 throw new Error(message);
6082 }
6083
6084 var glideHelper = new SaraGlideHelper();
6085 var LOGGER = new SaraLog('SaraUtils');
6086 var catItemIds = [];
6087 var varSetIds = [];
6088 var catCateIds = [];
6089 var targetCateIds = [];
6090
6091 filter = filter || {};
6092
6093 // Get list of catalog item from SaraCommon.TABLE_NAME.SARA_DEFINITION table
6094 var saraItems = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, filter, true);
6095
6096 if (saraItems.length > 0) {
6097 LOGGER.info('Found {0} item(s) in "{1}"', saraItems.length, SaraCommon.TABLE_NAME.SARA_DEFINITION);
6098
6099 for (var i = 0, saraItem; saraItem = saraItems[i]; i++) {
6100 if (saraItem['u_sc_item']) {
6101 catItemIds.push(saraItem['u_sc_item']);
6102 }
6103
6104 if (saraItem['u_var_set']) {
6105 varSetIds.push(saraItem['u_var_set']);
6106 }
6107
6108 if (saraItem['u_service_catalog_category']) {
6109 catCateIds.push(saraItem['u_service_catalog_category']);
6110 }
6111
6112 if (saraItem['u_type'] === 'category') {
6113 targetCateIds.push(saraItem['u_parent']);
6114 }
6115 }
6116
6117 var message = 'There are :';
6118 message += SaraUtils.formatString('\n - {0} catalog item(s)', catItemIds.length);
6119 message += SaraUtils.formatString('\n - {0} variable set(s)', varSetIds.length);
6120 message += SaraUtils.formatString('\n - {0} category(s)', catCateIds.length);
6121 message += SaraUtils.formatString('\n - {0} target category(s)', targetCateIds.length);
6122 LOGGER.info(message);
6123
6124 if (varSetIds.length > 0) {
6125 LOGGER.info('Removing {0} variable set(s)...', varSetIds.length);
6126
6127 for (var i = 0, varSetId; varSetId = varSetIds[i]; i++) {
6128 // Remove all variables belong to above variable sets
6129 LOGGER.info('Removing variables from variable set {0}...', varSetId);
6130 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_VARIABLE, {
6131 'variable_set': varSetId
6132 }, true);
6133
6134 // Remove all variable sets
6135 LOGGER.info('Removing variable set (sys_id = {0})...', varSetId);
6136 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_VARIABLE_SET, {
6137 'sys_id': varSetId
6138 }, true);
6139 }
6140 }
6141
6142 // Cleanup service catalog items
6143 if (catItemIds.length > 0) {
6144 LOGGER.info('Removing {0} catalog item(s)...', catItemIds.length);
6145
6146 for (var i = 0, catItemId; catItemId = catItemIds[i]; i++) {
6147 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_CAT_ITEM, {
6148 'sys_id': catItemId
6149 });
6150 }
6151 }
6152
6153 // Cleanup catalog categories
6154 if (catCateIds.length > 0) {
6155 LOGGER.info('Removing {0} catalog category(s)...', catCateIds.length);
6156
6157 for (var i = 0, catCateId; catCateId = catCateIds[i]; i++) {
6158 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
6159 'sys_id': catCateId
6160 });
6161 }
6162 }
6163
6164 // Refresh target categories
6165 if (targetCateIds.length > 0) {
6166 LOGGER.info('Refreshing {0} target category(s)...', catCateIds.length);
6167
6168 for (var i = 0, targetCateId; targetCateId = targetCateIds[i]; i++) {
6169 glideHelper.updateData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
6170 'sys_id': targetCateId
6171 }, {
6172 'active': false
6173 });
6174
6175 glideHelper.updateData(SaraCommon.TABLE_NAME.SN_CATEGORY, {
6176 'sys_id': targetCateId
6177 }, {
6178 'active': true
6179 });
6180
6181 LOGGER.info('Target category (sys_id = {0}) is refreshed.', targetCateId);
6182 }
6183 }
6184
6185 LOGGER.info('Cleaning up {0} table ...', SaraCommon.TABLE_NAME.SARA_DEFINITION);
6186 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {}, true);
6187
6188 LOGGER.info('Cleaning up {0} table ...', SaraCommon.TABLE_NAME.SARA_VARIABLE);
6189 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_VARIABLE, {}, true);
6190 } else {
6191 LOGGER.warn('There is no items in "{0}". Skip cleanup!', SaraCommon.TABLE_NAME.SARA_DEFINITION);
6192 }
6193};
6194
6195/**
6196 * Create catalog variable from field information
6197 * @param {Object} field
6198 * @return {SaraModel.CatalogVariable}
6199 */
6200SaraUtils.createCatalogVariable = function (field) {
6201 var defaultValue = '';
6202 var varType;
6203 var isLookupControl = false;
6204 var LOGGER = new SaraLog('SaraUtils');
6205
6206 if (field['default'] && field['default'].length > 0) {
6207 defaultValue = field['default'];
6208 }
6209
6210 switch (field.type) {
6211 case 'Label':
6212 varType = SaraCommon.VAR_TYPE.LABEL;
6213 break;
6214 case 'Number':
6215 // SN only have NUM_SCALE variable type but not suitable, just use string
6216 varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
6217 break;
6218 case 'String':
6219 varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
6220 break;
6221 case 'List':
6222 varType = field.multiSelect ? SaraCommon.VAR_TYPE.LIST_COLLECTOR : SaraCommon.VAR_TYPE.LOOKUP_SELECT_BOX;
6223 isLookupControl = true;
6224 break;
6225 case 'Time':
6226 varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
6227 break;
6228 case 'Date':
6229 varType = SaraCommon.VAR_TYPE.DATE;
6230 break;
6231 case 'Timestamp':
6232 varType = SaraCommon.VAR_TYPE.DATE_TIME;
6233 break;
6234 default:
6235 break;
6236 }
6237
6238 var catalogVariable = new SaraModel.CatalogVariable();
6239 catalogVariable.setName(this.legitVarName(field.name));
6240 catalogVariable.setType(varType);
6241 catalogVariable.setLabel(field.caption);
6242 catalogVariable.setDefaultValue(defaultValue);
6243 catalogVariable.setDescription(field.description);
6244 catalogVariable.setRange([]);
6245 catalogVariable.setAsLookup(isLookupControl);
6246
6247 if(field.order != null && field.order != undefined) {
6248 catalogVariable.setOrder(field.order);
6249 }
6250
6251 if (field.maskAsPassword) {
6252 catalogVariable.setAsPassword(field.maskAsPassword);
6253 }
6254
6255 if (field.range && field.range[0].values) {
6256 var rangeValue = field.range[0].values;
6257 catalogVariable.setRange(rangeValue);
6258
6259 // Generate range hash for variable
6260 var hash = SaraUtils.md5(SaraJSON.stringify(rangeValue));
6261 catalogVariable.setHash(hash);
6262 }
6263
6264 if (field.name) {
6265 catalogVariable.setActualName(field.name);
6266 }
6267
6268 if (field.required) {
6269 catalogVariable.setRequired(field.required);
6270 }
6271
6272 if (field.multiSelect) {
6273 catalogVariable.setMultiSelect(field.multiSelect);
6274 }
6275
6276 return catalogVariable;
6277};
6278
6279/**
6280 * Legitimates variable name that is not qualified business rule validate_variable_name
6281 * @param {String} varName
6282 * @return {String}
6283 */
6284SaraUtils.legitVarName = function (varName) {
6285 var firstLegal = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
6286 var firstLetter = varName.charAt(0);
6287 if (firstLegal.indexOf(firstLetter) == -1) {
6288 varName = 'v_' + varName;
6289 }
6290
6291 var legal = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789';
6292 for (var i = 0; i < varName.length; i++) {
6293 var letter = varName.charAt(i);
6294 if (legal.indexOf(letter) == -1) {
6295 // replace illegal char with _
6296 varName = varName.substr(0, i) + '_' + varName.substr(i + 1);
6297 }
6298 }
6299
6300 return varName;
6301};
6302
6303SaraUtils.getImportTargetCatRefQual = function(){
6304 var gh = new SaraGlideHelper();
6305
6306 var catalogs = gh.getData('sc_catalog', {}, true);
6307 var catalogIds = [];
6308 for(var i = 0; i < catalogs.length; i++) {
6309 catalogIds.push(catalogs[i].sys_id);
6310 }
6311
6312 var catalogFilter = ['IN', catalogIds.join(',')];
6313 gs.info('catalogFilter = ' + catalogFilter);
6314
6315 var result = 'sys_idIN';
6316 var cats = gh.getData('sc_category', {sc_catalog: catalogFilter}, true);
6317 var categoryIds = [];
6318
6319 for(i = 0;i < cats.length; i++) {
6320 var cat = cats[i];
6321 gs.info(SaraJSON.stringify(cat));
6322 categoryIds.push(cat.sys_id);
6323 }
6324 result += categoryIds.join(',');
6325
6326 return result;
6327};
6328
6329/**
6330 * Build url
6331 * @param {String} url
6332 * @param {String} baseUrl
6333 * @return {String}
6334 */
6335SaraUtils.buildUrl = function (url, baseUrl) {
6336 if (!url) {
6337 url = '';
6338 }
6339
6340 var scheme;
6341 var pattern = /^https?:\/\//i;
6342 if (pattern.test(url)) {
6343 scheme = 'absolute';
6344 } else {
6345 scheme = 'relative';
6346 }
6347
6348 if (scheme === 'relative') {
6349 var basePath = new SaraConfig().getBasePath();
6350 if(baseUrl) {
6351 if(typeof baseUrl === 'string') {
6352 basePath = baseUrl;
6353 } else {
6354 basePath = String(baseUrl);
6355 }
6356 }
6357
6358 if (basePath.charAt(basePath.length - 1) == '/' && url.substring(0, 1) == '/') {
6359 return basePath + url.substring(1);
6360 }
6361
6362 if (basePath.charAt(basePath.length - 1) != '/' && url.substring(0, 1) != '/') {
6363 return basePath + '/' + url;
6364 }
6365
6366 return basePath + url;
6367 }
6368
6369 if (url == '/') {
6370 return new SaraConfig().getBasePath();
6371 }
6372
6373 return url;
6374};
6375
6376/**
6377 * Gets index of item in array
6378 * @param {Array} array
6379 * @param {*} item
6380 * @return {Number}
6381 */
6382SaraUtils.indexOf = function (array, item) {
6383 for (var i = 0; i < array.length; ++i) {
6384 if (array[i] === item) {
6385 return i;
6386 }
6387 }
6388
6389 return -1;
6390};
6391
6392/**
6393 * Detects the array item is in array or not
6394 * @param {Array} array
6395 * @param {*} item
6396 * @return {Boolean}
6397 */
6398SaraUtils.inArray = function (array, item) {
6399 return SaraUtils.indexOf(array, item) !== -1;
6400};
6401
6402/**
6403 * Get redirection endpoint of current instance
6404 * @return {String} The redirection endpoint
6405 */
6406SaraUtils.getRedirectionUrl = function () {
6407 return gs.getProperty('glide.servlet.uri') + SaraCommon.SCOPED_APP + '_sara_oauth_callback.do';
6408};
6409
6410SaraUtils.guardNotNullOrEmpty = function(param, msg) {
6411 if(!param || param === null || param === "") {
6412 throw msg;
6413 }
6414};
6415
6416SaraUtils.isNullOrEmpty = function(param) {
6417 if(!param || param === null || param === "") {
6418 return true;
6419 }
6420 return false;
6421};
6422
6423/**
6424 * Find the existing lookup object by given lookup object
6425 * @param {Lookup} lookup
6426 * @param {Lookup[]} array
6427 * @return {Boolean}
6428 */
6429SaraUtils.hasExistingLookupInArray = function (lookup, array) {
6430 if(!lookup || !array) {
6431 return false;
6432 }
6433 return array.filter(function(e) {
6434 return lookup.Key === e.Key;
6435 }).length > 0;
6436};
6437
6438/**
6439 * Remove duplicated lookup
6440 * @param {Lookup[]} ranges
6441 * @return {Lookup[]}
6442 */
6443SaraUtils.removeDuplicatedLookup = function (ranges) {
6444 if(ranges) {
6445 var result = [];
6446 for(var i = 0; i < ranges.length; i++) {
6447 var e = ranges[i];
6448 var key = e.Key;
6449 if(key === '' || key.trim() === '') {
6450 e.Key = key.trim();
6451 }
6452
6453 if(SaraUtils.hasExistingLookupInArray(e, result)) {
6454 continue;
6455 }
6456 result.push(e);
6457 }
6458 return result;
6459 }
6460 return [];
6461};
6462
6463SaraUtils.md5 = function (string, key, raw) {
6464 /*
6465 * JavaScript MD5 1.0.1
6466 * https://github.com/blueimp/JavaScript-MD5
6467 *
6468 * Copyright 2011, Sebastian Tschan
6469 * https://blueimp.net
6470 *
6471 * Licensed under the MIT license:
6472 * http://www.opensource.org/licenses/MIT
6473 *
6474 * Based on
6475 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
6476 * Digest Algorithm, as defined in RFC 1321.
6477 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
6478 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6479 * Distributed under the BSD License
6480 * See http://pajhome.org.uk/crypt/md5 for more info.
6481 */
6482 /*jslint bitwise: true */
6483 /*global unescape, define */
6484
6485 'use strict';
6486 /*
6487 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
6488 * to work around bugs in some JS interpreters.
6489 */
6490 function safe_add(x, y) {
6491 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
6492 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
6493 return (msw << 16) | (lsw & 0xFFFF);
6494 }
6495 /*
6496 * Bitwise rotate a 32-bit number to the left.
6497 */
6498 function bit_rol(num, cnt) {
6499 return (num << cnt) | (num >>> (32 - cnt));
6500 }
6501 /*
6502 * These functions implement the four basic operations the algorithm uses.
6503 */
6504 function md5_cmn(q, a, b, x, s, t) {
6505 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
6506 }
6507
6508 function md5_ff(a, b, c, d, x, s, t) {
6509 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
6510 }
6511
6512 function md5_gg(a, b, c, d, x, s, t) {
6513 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
6514 }
6515
6516 function md5_hh(a, b, c, d, x, s, t) {
6517 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
6518 }
6519
6520 function md5_ii(a, b, c, d, x, s, t) {
6521 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
6522 }
6523 /*
6524 * Calculate the MD5 of an array of little-endian words, and a bit length.
6525 */
6526 function binl_md5(x, len) {
6527 /* append padding */
6528 x[len >> 5] |= 0x80 << (len % 32);
6529 x[(((len + 64) >>> 9) << 4) + 14] = len;
6530 var i, olda, oldb, oldc, oldd,
6531 a = 1732584193,
6532 b = -271733879,
6533 c = -1732584194,
6534 d = 271733878;
6535 for (i = 0; i < x.length; i += 16) {
6536 olda = a;
6537 oldb = b;
6538 oldc = c;
6539 oldd = d;
6540 a = md5_ff(a, b, c, d, x[i], 7, -680876936);
6541 d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
6542 c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
6543 b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
6544 a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
6545 d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
6546 c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
6547 b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
6548 a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
6549 d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
6550 c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
6551 b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
6552 a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
6553 d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
6554 c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
6555 b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
6556 a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
6557 d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
6558 c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
6559 b = md5_gg(b, c, d, a, x[i], 20, -373897302);
6560 a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
6561 d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
6562 c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
6563 b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
6564 a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
6565 d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
6566 c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
6567 b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
6568 a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
6569 d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
6570 c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
6571 b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
6572 a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
6573 d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
6574 c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
6575 b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
6576 a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
6577 d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
6578 c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
6579 b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
6580 a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
6581 d = md5_hh(d, a, b, c, x[i], 11, -358537222);
6582 c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
6583 b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
6584 a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
6585 d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
6586 c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
6587 b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
6588 a = md5_ii(a, b, c, d, x[i], 6, -198630844);
6589 d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
6590 c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
6591 b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
6592 a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
6593 d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
6594 c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
6595 b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
6596 a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
6597 d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
6598 c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
6599 b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
6600 a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
6601 d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
6602 c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
6603 b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
6604 a = safe_add(a, olda);
6605 b = safe_add(b, oldb);
6606 c = safe_add(c, oldc);
6607 d = safe_add(d, oldd);
6608 }
6609 return [a, b, c, d];
6610 }
6611 /*
6612 * Convert an array of little-endian words to a string
6613 */
6614 function binl2rstr(input) {
6615 var i,
6616 output = '';
6617 for (i = 0; i < input.length * 32; i += 8) {
6618 output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
6619 }
6620 return output;
6621 }
6622 /*
6623 * Convert a raw string to an array of little-endian words
6624 * Characters >255 have their high-byte silently ignored.
6625 */
6626 function rstr2binl(input) {
6627 var i,
6628 output = [];
6629 output[(input.length >> 2) - 1] = undefined;
6630 for (i = 0; i < output.length; i += 1) {
6631 output[i] = 0;
6632 }
6633 for (i = 0; i < input.length * 8; i += 8) {
6634 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
6635 }
6636 return output;
6637 }
6638 /*
6639 * Calculate the MD5 of a raw string
6640 */
6641 function rstr_md5(s) {
6642 return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
6643 }
6644 /*
6645 * Calculate the HMAC-MD5, of a key and some data (raw strings)
6646 */
6647 function rstr_hmac_md5(key, data) {
6648 var i,
6649 bkey = rstr2binl(key),
6650 ipad = [],
6651 opad = [],
6652 hash;
6653 ipad[15] = opad[15] = undefined;
6654 if (bkey.length > 16) {
6655 bkey = binl_md5(bkey, key.length * 8);
6656 }
6657 for (i = 0; i < 16; i += 1) {
6658 ipad[i] = bkey[i] ^ 0x36363636;
6659 opad[i] = bkey[i] ^ 0x5C5C5C5C;
6660 }
6661 hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
6662 return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
6663 }
6664 /*
6665 * Convert a raw string to a hex string
6666 */
6667 function rstr2hex(input) {
6668 var hex_tab = '0123456789abcdef',
6669 output = '',
6670 x,
6671 i;
6672 for (i = 0; i < input.length; i += 1) {
6673 x = input.charCodeAt(i);
6674 output += hex_tab.charAt((x >>> 4) & 0x0F) +
6675 hex_tab.charAt(x & 0x0F);
6676 }
6677 return output;
6678 }
6679 /*
6680 * Encode a string as utf-8
6681 */
6682 function str2rstr_utf8(input) {
6683 return unescape(encodeURIComponent(input));
6684 }
6685 /*
6686 * Take string arguments and return either raw or hex encoded strings
6687 */
6688 function raw_md5(s) {
6689 return rstr_md5(str2rstr_utf8(s));
6690 }
6691
6692 function hex_md5(s) {
6693 return rstr2hex(raw_md5(s));
6694 }
6695
6696 function raw_hmac_md5(k, d) {
6697 return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
6698 }
6699
6700 function hex_hmac_md5(k, d) {
6701 return rstr2hex(raw_hmac_md5(k, d));
6702 }
6703
6704 if (!key) {
6705 if (!raw) {
6706 return hex_md5(string);
6707 }
6708 return raw_md5(string);
6709 }
6710 if (!raw) {
6711 return hex_hmac_md5(key, string);
6712 }
6713
6714 return raw_hmac_md5(key, string);
6715};
6716]]></script>
6717 <description>Sara Utilities</description>
6718 <active>true</active>
6719 <client_callable>false</client_callable>
6720 <access>public</access>
6721 </script_include>
6722
6723 <script_include>
6724 <name>SaraTestBench</name>
6725 <script><![CDATA[/*
6726Test bench for Sara Scripts
6727Create manually in scope of Automic SNSC
6728Use background script to execute:
6729
6730var test = new SaraTestBench();
6731test.execute();
6732 */
6733var SaraTestBench = Class.create();
6734SaraTestBench.prototype = {
6735 initialize: function () {
6736 },
6737
6738 execute: function(){
6739 SaraTest.resetSummary();
6740
6741 SaraTransformMapTest.execute();
6742
6743 SaraConsumerDALTest.execute();
6744
6745 SaraConsumerImportTest.execute();
6746
6747 gs.info("=======================================================================================");
6748 gs.info("SUMMARY");
6749 gs.info("=======================================================================================");
6750 var summary = SaraTest.getSummary();
6751 gs.info("------ TOTAL: " + summary.total);
6752 gs.info("------ PASS: " + summary.pass);
6753 gs.info("------ FAIL: " + summary.fail);
6754 gs.info("------ IGNORE: " + summary.ignore);
6755 }
6756};
6757
6758var SaraConsumerDALTest = (function() {
6759 var gh = new SaraGlideHelper();
6760 var dal = new SaraConsumerDAL();
6761 return {
6762 execute: function() {
6763 gs.info("----------------------------------------------------------------------------");
6764 gs.info("Test SaraConsumerDAL");
6765 gs.info("----------------------------------------------------------------------------");
6766
6767 this.testGetCatalog();
6768 this.testSaveOrUpdateCatalog();
6769 this.testSaveOrUpdateCategory();
6770 this.testGetDefaultCategoryId();
6771 this.testSaveCategoryToSaraDefinition();
6772 this.testDeactivateSaraDefinition();
6773 },
6774
6775 testGetCatalog: function() {
6776 SaraTest.test("get catalog id by title", function() {
6777 var cat = dal.getCatalog("Service Catalog");
6778 SaraTest.assert(cat !== undefined, "catalog is get correctly");
6779 SaraTest.assert(cat.title === "Service Catalog", "title is get correctly");
6780 gs.info(SaraJSON.stringify(cat));
6781 });
6782 },
6783
6784 testSaveOrUpdateCatalog: function() {
6785 SaraTest.test("save or update catalog", function() {
6786 var catName = "snsc dal cat 1" + SaraUtils.getRandom();
6787 var desc = "test description";
6788
6789 var catId = dal.saveOrUpdateCatalog({
6790 title: catName,
6791 description: desc,
6792 active: true
6793 }).sys_id;
6794 SaraTest.assert(catId !== null, "catalog is persisted correctly");
6795
6796 var cat = gh.getData("sc_catalog", {sys_id: catId});
6797 gs.info(SaraJSON.stringify(cat));
6798 SaraTest.assert(cat !== null, "catalog is get correctly");
6799 SaraTest.assert(cat.title === catName, "title is set correctly");
6800 SaraTest.assert(cat.description === desc, "description is set correctly");
6801 SaraTest.assert(cat.active == "true", "active is set correctly");
6802
6803 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6804 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6805 });
6806 },
6807
6808 testSaveOrUpdateCategory: function() {
6809 SaraTest.test("save or update category", function() {
6810 var catName = "snsc dal cat 2" + SaraUtils.getRandom();
6811 var desc = "test description";
6812 var categoryName = "snsc dal category 2" + SaraUtils.getRandom();
6813 var categoryDescription = "category description";
6814 var categoryNewDescription = "category description new";
6815
6816 var catId = dal.saveOrUpdateCatalog({
6817 title: catName,
6818 description: desc,
6819 active: true
6820 }).sys_id;
6821
6822 var cat = {
6823 sc_catalog: catId,
6824 title: categoryName,
6825 description: categoryDescription,
6826 active: true};
6827 cat.description = categoryDescription;
6828 var category = dal.saveOrUpdateCategory(cat);
6829 gs.info("category: " + SaraJSON.stringify(category));
6830 SaraTest.assert(category !== null, "category is get correctly");
6831 SaraTest.assert(category.title === categoryName, "title is set correctly");
6832 SaraTest.assert(category.description === categoryDescription, "description is set correctly");
6833 SaraTest.assert(category.active == "true", "active is set correctly");
6834
6835 category.description = categoryNewDescription;
6836 category.active = false;
6837 dal.saveOrUpdateCategory(category);
6838
6839 var result = gh.getData("sc_category", {sys_id: category.sys_id});
6840 gs.info("result: " + SaraJSON.stringify(result));
6841
6842 SaraTest.assert(result.description === categoryNewDescription, "description is updated correctly");
6843 SaraTest.assert(result.active == "false", "active is updated correctly");
6844
6845 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6846 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6847 });
6848 },
6849
6850 testGetDefaultCategoryId: function() {
6851 SaraTest.test("get default category", function () {
6852 var catId = dal.getDefaultCategoryId();
6853 var category = gh.getData("sc_category", {sys_id: catId});
6854
6855 SaraTest.assert(category !== null, "getDetaultCategoryId return valid category id");
6856 gs.info(SaraJSON.stringify(category));
6857 });
6858 },
6859
6860 testSaveCategoryToSaraDefinition: function() {
6861 SaraTest.test("save category to sara definition", function() {
6862 var catName = "snsc dal cat 3" + SaraUtils.getRandom();
6863 var desc = "test description";
6864
6865 var categoryName = "snsc dal category 3" + SaraUtils.getRandom();
6866 var categoryDescription = "category description";
6867
6868 var catId = dal.saveOrUpdateCatalog({
6869 title: catName,
6870 description: desc,
6871 active: true
6872 }).sys_id;
6873
6874 var category = dal.saveOrUpdateCategory({
6875 sc_catalog: catId,
6876 title: categoryName,
6877 description: categoryDescription,
6878 active: true
6879 });
6880
6881 var definitionId = dal.saveRootImportCategoryToSaraDefinition(category.sys_id).sys_id;
6882 var definition = gh.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definitionId});
6883 gs.info(SaraJSON.stringify(definition));
6884
6885 SaraTest.assert(definition !== null, "definition is saved correctly");
6886 SaraTest.assert(definition.u_name === categoryName, "u_name is saved correctly");
6887 SaraTest.assert(definition.u_parent === category.sys_id, "u_parent is saved correctly");
6888 SaraTest.assert(definition.u_type === 'category', "u_type is saved correctly");
6889 SaraTest.assert(definition.u_active == 'true', "active is saved correctly");
6890
6891 gh.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definitionId}, true);
6892 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6893 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6894 });
6895 },
6896
6897 testDeactivateSaraDefinition: function() {
6898 SaraTest.test("deactivate sara definition", function() {
6899 var catName = "snsc dal cat 6" + SaraUtils.getRandom();
6900 var desc = "test description";
6901 var categoryName = "snsc dal category 6" + SaraUtils.getRandom();
6902 var categoryDescription = "category description";
6903 var catalogItemName = "snsc dal catalog item 6";
6904
6905 var parentDefinitionName = "snsc definition 6 parent" + SaraUtils.getRandom();
6906 var definitionName = "snsc definition 6" + SaraUtils.getRandom();
6907
6908 var catId = dal.saveOrUpdateCatalog({
6909 title: catName,
6910 description: desc,
6911 active: true
6912 }).sys_id;
6913 var category = dal.saveOrUpdateCategory({
6914 title: categoryName,
6915 description: categoryDescription,
6916 sc_catalog: catId
6917 });
6918 var catalogItem = dal.saveOrUpdateCatalogItem({
6919 category: category.sys_id,
6920 name: catalogItemName,
6921 active: true
6922 });
6923
6924 var parentDefinition = dal.saveOrUpdateSaraDefinition({
6925 u_name: parentDefinitionName,
6926 u_active: true,
6927 u_consume_url: "http://testurl.com",
6928 u_parent: category.sys_id,
6929 u_type: 'catalog'
6930 });
6931
6932 var definition = dal.saveOrUpdateSaraDefinition({
6933 u_name: definitionName,
6934 u_active: true,
6935 u_consume_url: "http://testurl.com",
6936 u_parent: category.sys_id,
6937 u_type: 'service',
6938 u_sc_item: catalogItem.sys_id,
6939 u_hash: '123'
6940 });
6941
6942 SaraTest.assert(parentDefinition.u_active == 'true', "parent definition is active");
6943 SaraTest.assert(definition.u_active == 'true', "definition is active");
6944
6945 gs.info("parent definition: " + SaraJSON.stringify(parentDefinition));
6946 gs.info("definition: " + SaraJSON.stringify(definition));
6947
6948 dal.deactivateSaraDefinition(parentDefinition);
6949
6950 definition = gh.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definition.sys_id});
6951 parentDefinition = gh.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: parentDefinition.sys_id});
6952
6953 category = gh.getData("sc_category", {sys_id: category.sys_id});
6954 gs.info("category: " + SaraJSON.stringify(category));
6955
6956 catalogItem = gh.getData("sc_cat_item", {sys_id: catalogItem.sys_id});
6957 gs.info("catalogItem: " + SaraJSON.stringify(catalogItem));
6958
6959 SaraTest.assert(catalogItem.name === catalogItemName,"get correct catalog item");
6960 SaraTest.assert(catalogItem.active == 'false',"catalog item is deactivated");
6961 SaraTest.assert(definition.u_name === definitionName,"get correct definition");
6962 SaraTest.assert(definition.u_active == 'false',"definition is deactivated");
6963 SaraTest.assert(parentDefinition.u_name === parentDefinitionName,"get correct parent definition");
6964 SaraTest.assert(parentDefinition.u_active == 'false',"parent definition is deactivated");
6965
6966
6967 gh.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: definition.sys_id}, true);
6968 gh.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {sys_id: parentDefinition.sys_id}, true);
6969 //gh.deleteData("sc_cat_item", {category: category.sys_id}, true);
6970 gh.deleteData("sc_category", {sc_catalog: catId}, true);
6971 gh.deleteData("sc_catalog", {sys_id: catId}, true);
6972 });
6973 }
6974 };
6975})();
6976
6977var SaraConsumerImportTest = (function() {
6978 var logger = new SaraLog("SaraGlideHelperTest");
6979 var glideHelper = new SaraGlideHelper();
6980 var categoryName = "snsc test import " + SaraUtils.getRandom();
6981 var consumer = new SaraConsumerImportSet();
6982 var categoryId = null;
6983 var catalogId;
6984 var category;
6985 var dal = new SaraConsumerDAL();
6986 var catItem1 = null;
6987
6988 return {
6989 execute: function() {
6990 gs.info("----------------------------------------------------------------------------");
6991 gs.info("Test SaraConsumerImportSet");
6992 gs.info("----------------------------------------------------------------------------");
6993
6994 this.initialize();
6995
6996 this.testImportCategory();
6997
6998 this.testImportItem();
6999
7000 this.testSyncLookup();
7001
7002 this.tearDown();
7003 },
7004
7005 initialize: function() {
7006 catalogId = glideHelper.getData("sc_catalog", { title: "Service Catalog" }).sys_id;
7007
7008 category = dal.saveOrUpdateCategory({
7009 title: categoryName,
7010 description: "test",
7011 sc_catalog: catalogId,
7012 active: true
7013 });
7014 gs.info("created category: " + category);
7015
7016 gs.info("category to be imported: " + categoryName);
7017
7018 categoryId = category.sys_id;
7019 },
7020
7021 getMockCatalogData: function() {
7022 var catalogsData = {
7023 "DEMO":{
7024 "title":"Automic Demo Services",
7025 "active":true,
7026 "description":"Automic Demo Services",
7027 "parent":"",
7028 "name":"DEMO"},
7029 "DEMO2":{
7030 "title":"DEMO2",
7031 "active":true,
7032 "description":"",
7033 "parent":"",
7034 "name":"DEMO2"}};
7035
7036 //mock catalog data for testing
7037 for(var ctgName in catalogsData) {
7038 this.wrapCategoryData(catalogsData[ctgName]);
7039 }
7040
7041 return catalogsData;
7042 },
7043
7044 getMockupServicesData: function() {
7045 var servicesData = {
7046 "DEMO": {
7047 "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.ACTIVATE_SNSC_SERVICE.NEW.1":
7048 {
7049 "variables": [
7050 { "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#" },
7051 { "description": "", "label": "Previous Month(s) included", "defaultValue": ["3"], "type": 6, "required": true, "range": [], "asLookup": false, "name": "EOM_MONTHBACK_", "actualName": "EOM_MONTHBACK#" },
7052 { "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#" },
7053 { "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#" },
7054 { "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#" }
7055 ], "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" },
7056 "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEACTIVATE_SNSC_SERVICE.NEW.1":
7057 {
7058 "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" }
7059 },
7060 "DEMO2": {
7061 "PCK.AUTOMIC_SNSC_CERTIFICATION.PUB.ACTION.DEMO_SERVICE.NEW.1": {
7062 "variables": [
7063 { "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#" },
7064 { "description": "", "label": "Previous Month(s) included", "defaultValue": ["3"], "type": 6, "required": true, "range": [], "asLookup": false, "name": "EOM_MONTHBACK_", "actualName": "EOM_MONTHBACK#" },
7065 { "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#" },
7066 { "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#" },
7067 { "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#" }
7068 ], "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" }
7069 }};
7070
7071 //mock service data for testing
7072 for (var catalogName in servicesData) {
7073 var catalog = servicesData[catalogName];
7074 for(var serviceName in catalog) {
7075 this.wrapServiceData(catalog[serviceName]);
7076 }
7077 }
7078
7079 return servicesData;
7080 },
7081
7082 wrapCategoryData: function(dataObj) {
7083 dataObj.__proto__ = new SaraModel.CatalogCategory();
7084 },
7085
7086 wrapServiceData: function(dataObj) {
7087 dataObj.__proto__ = new SaraModel.CatalogItem();
7088 if(dataObj.variables && dataObj.variables instanceof Array) {
7089 for(var i = 0; i < dataObj.variables.length; i ++) {
7090 dataObj.variables[i].__proto__ = new SaraModel.CatalogVariable();
7091 }
7092 }
7093 },
7094
7095 testImportCategory: function () {
7096 consumer.catalogsData = this.getMockCatalogData();
7097 SaraTest.test("test import categories, de-activate definition removed from AE, update existing definition and create new definition", function () {
7098 var categoryName2 = "snsc test import " + SaraUtils.getRandom();
7099 var categoryName3 = "snsc test import " + SaraUtils.getRandom();
7100
7101 var definitionName = "snsc test import " + SaraUtils.getRandom();
7102 var categoryDescription = "testImportCategory category description";
7103
7104 var category2 = dal.saveOrUpdateCategory({
7105 title: categoryName2,
7106 description: categoryDescription,
7107 sc_catalog: catalogId,
7108 active: true
7109 });
7110
7111
7112 var definition = dal.saveOrUpdateSaraDefinition({
7113 u_name: definitionName,
7114 u_active: true,
7115 u_consume_url: "http://testurl.com",
7116 u_parent: category.sys_id,
7117 u_type: 'catalog',
7118 u_service_catalog_category: category2.sys_id
7119 });
7120
7121 var category3 = dal.saveOrUpdateCategory({
7122 title: categoryName3,
7123 description: categoryDescription,
7124 sc_catalog: catalogId,
7125 active: true
7126 });
7127
7128 var demoDefinition = dal.saveOrUpdateSaraDefinition({
7129 u_name: "DEMO",
7130 u_active: true,
7131 u_consume_url: "oldurl",
7132 u_parent: category.sys_id,
7133 u_type: 'catalog',
7134 u_service_catalog_category: category3.sys_id
7135 });
7136
7137 gs.info("done prepare test data");
7138 //create new definition and make sure that it will be de-activate during synchronization
7139 consumer.importCategory(categoryId);
7140
7141 var resultDefinition = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, { u_name: definitionName, u_parent: category.sys_id });
7142 SaraTest.assert(resultDefinition.u_active == "false", "Definition does not exist in AE should be de-activated");
7143
7144 category2 = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, { sys_id: category2.sys_id });
7145 SaraTest.assert(category2.active == "false", "Category linked to definition does not exist in AE should be de-activated");
7146
7147 category3 = glideHelper.getData(SaraCommon.TABLE_NAME.SN_CATEGORY, { sys_id: category3.sys_id });
7148 SaraTest.assert(category3.parent == category.sys_id, "parent of category linked to definition exist is updated");
7149 SaraTest.assert(category3.title == "Automic Demo Services", "title of category linked to definition exist is updated");
7150 SaraTest.assert(category3.description == "Automic Demo Services", "description of category linked to definition exist is updated");
7151 });
7152 },
7153
7154 testImportItem: function() {
7155 consumer.servicesData = this.getMockupServicesData();
7156
7157 SaraTest.test("test import items", function() {
7158 consumer.importItem();
7159
7160 gs.info("get sub category of " + categoryId);
7161 //get catalog items under import category
7162 var subCategories = glideHelper.getData("sc_category", {parent: categoryId, active: true}, true);
7163 gs.info("sub categories: " + SaraJSON.stringify(subCategories));
7164 SaraTest.assertEqual(subCategories.length, 2, "2 categories are created");
7165 var category1 = subCategories[0].title === "DEMO2" ? subCategories[1] : subCategories[0];
7166 var catItemsOfCategory1 = glideHelper.getData("sc_cat_item", {category: category1.sys_id}, true);
7167
7168 SaraTest.assertEqual(catItemsOfCategory1.length, 2, "2 catalog item under category " + category1.title);
7169
7170 gs.info("catItemsOfCategory1: " + SaraJSON.stringify(catItemsOfCategory1));
7171 catItem1 = catItemsOfCategory1[0].name === "Activate SNSC Service" ? catItemsOfCategory1[0] : catItemsOfCategory1[1];
7172 var itemVarSet = glideHelper.getData("io_set_item", {sc_cat_item: catItem1.sys_id});
7173 var varSet = glideHelper.getData("item_option_new_set", {sys_id: itemVarSet.variable_set});
7174 gs.info(" varSet of the item: " + SaraJSON.stringify(varSet));
7175 var variables = glideHelper.getData("x_ausgh_snsc_sara_variable", {variable_set: varSet.sys_id}, true);
7176 gs.info(" variables of the item: " + SaraJSON.stringify(variables));
7177 SaraTest.assert(variables.length == 7, "5 + 2 variables are created");
7178 });
7179 },
7180
7181 testSyncLookup: function() {
7182 var newSapiService = {
7183 "variables": [
7184 { "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#" },
7185 { "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#" },
7186 { "description": "", "label": "Previous Month(s) included", "defaultValue": ["3"], "type": 6, "required": true, "range": [], "asLookup": false, "name": "EOM_MONTHBACK_", "actualName": "EOM_MONTHBACK#" },
7187 { "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#" },
7188 { "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#" },
7189 { "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#" }
7190 ], "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" };
7191 this.wrapServiceData(newSapiService);
7192
7193 SaraTest.test("test sync lookup", function() {
7194 var saraSync = new SaraSync();
7195 gs.info("catItem1: " + SaraJSON.stringify(catItem1));
7196 var definition = glideHelper.getData(SaraCommon.TABLE_NAME.SARA_DEFINITION, {u_sc_item:catItem1.sys_id });
7197 gs.info("newSapiService: " + SaraJSON.stringify(newSapiService));
7198 saraSync.syncLookup(definition, newSapiService);
7199 });
7200 },
7201
7202 tearDown: function() {
7203 SaraUtils.cleanup( { u_parent: category.sys_id });
7204 glideHelper.deleteData(SaraCommon.TABLE_NAME.SARA_DEFINITION, { u_parent: category.sys_id }, true);
7205 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY, { parent: categoryId }, true);
7206 glideHelper.deleteData(SaraCommon.TABLE_NAME.SN_CATEGORY, { title: ["CONTAINS", "snsc test import"] }, true);
7207 }
7208 };
7209})();
7210
7211var SaraTransformMapTest = (function(){
7212 var logger = new SaraLog("SaraGlideHelperTest");
7213 var glideHelper = new SaraGlideHelper();
7214
7215 var catalogId = glideHelper.getSysId("sc_catalog", {title: "Service Catalog"});
7216 gs.info("catelog id: " + catalogId);
7217
7218 var getCategory = function(title) {
7219 return glideHelper.getData("sc_category", {title: title });
7220 };
7221
7222 var deleteCategory = function(title, deleteAll) {
7223 glideHelper.deleteData("sc_category", {title: title },deleteAll);
7224 glideHelper.deleteData("x_ausgh_snsc_sc_category_ist", {title: title },deleteAll);
7225 };
7226
7227 var createCategory = function(title, active, description, parent) {
7228 glideHelper.persistData("x_ausgh_snsc_sc_category_ist", {
7229 title: title,
7230 active: active,
7231 description: description,
7232 parent: parent,
7233 sc_catalog: catalogId
7234 });
7235 };
7236
7237 return {
7238 execute: function() {
7239 gs.info("----------------------------------------------------------------------------");
7240 gs.info("Test transform map definitions");
7241 gs.info("----------------------------------------------------------------------------");
7242
7243 this.testPersistCatalog();
7244 this.testPersistCategory();
7245 this.testPersistCatalogItem();
7246 this.testPersistVariableSet();
7247 this.testPersistCatelogVariableSet();
7248 this.testPersistSaraDefinition();
7249 },
7250
7251 testPersistCatalog: function() {
7252 var catalogName = "snsc test catalog";
7253 glideHelper.deleteData("sc_catalog", {"title": catalogName});
7254
7255 SaraTest.test("Persist catalog via Importset", function() {
7256 glideHelper.persistData("x_ausgh_snsc_sc_catalog_ist", {
7257 title: catalogName,
7258 description: "test description",
7259 active: "true"
7260 });
7261
7262 var catalog = glideHelper.getData("sc_catalog", {"title": catalogName});
7263
7264 SaraTest.assert(catalog !== null, "catalog is transformed correctly");
7265 SaraTest.assert(catalog.title === catalogName, "catalog title is transformed correctly");
7266 SaraTest.assert(catalog.description === "test description", "catalog description is transformed correctly");
7267 gs.info("active: " + catalog.active);
7268 SaraTest.assert(catalog.active, "catalog active is transformed correctly");
7269 });
7270
7271 SaraTest.test("Update catalog via Importset", function() {
7272 var catalog = glideHelper.getData("sc_catalog", {title: catalogName});
7273 var data = {
7274 id: catalog.sys_id,
7275 description: "new description 2",
7276 active: false
7277 };
7278 glideHelper.persistData("x_ausgh_snsc_sc_catalog_ist", data);
7279
7280 var newCatalog = glideHelper.getData("sc_catalog", {"title": catalogName});
7281 gs.info("new catalog: " + SaraJSON.stringify(newCatalog));
7282 SaraTest.assert(newCatalog !== null, "catalog is transformed correctly, title is not overrided");
7283 SaraTest.assert(newCatalog.description === "new description 2", "catalog description is updated correctly");
7284 gs.info("active: " + newCatalog.active);
7285 SaraTest.assert(newCatalog.active == "false", "catalog active is updated correctly");
7286 });
7287 },
7288
7289 testPersistCategory: function() {
7290 var categoryName1 = "snsc test catagory";
7291 var categoryName2 = "snsc test sub catagory";
7292 deleteCategory(categoryName1, true);
7293 deleteCategory(categoryName2, true);
7294
7295 SaraTest.test("Persist category via Importset", function() {
7296 var category = getCategory(categoryName1);
7297 SaraTest.assert(category === null, "category must not exists");
7298 var category2 = getCategory(categoryName2);
7299 SaraTest.assert(category2 === null, "sub category must not exists");
7300
7301 createCategory(categoryName1,true,"test description", null);
7302 category = getCategory(categoryName1);
7303 gs.info(SaraJSON.stringify(category));
7304 SaraTest.assert(category !== null, "Category ImportSet should be transform to category table");
7305 SaraTest.assert(category.title === categoryName1, "Assert title transform correctly");
7306
7307 //create via importset table
7308 createCategory(categoryName2,true,"test sub description", category.sys_id);
7309 //get real data
7310 category2 = getCategory(categoryName2);
7311 SaraTest.assert(category2 !== null, "Sub category ImportSet should be transform to category table");
7312 SaraTest.assert(category2.title === categoryName2, "Assert title transform correctly");
7313
7314 var parent = glideHelper.getData("sc_category", {sys_id:category2.parent});
7315 SaraTest.assert(parent !== null, "Assert parent transform correctly");
7316 SaraTest.assert(parent.title === categoryName1, "Assert parent transform correctly");
7317 });
7318
7319 SaraTest.test("Save category with same name but different parent should create new category", function() {
7320 //create another category with different parent and assert that new item is
7321 //inserted to target table
7322 gs.info("create another record with name " + categoryName2);
7323 createCategory(categoryName2,true,"test description 2");
7324 var records = glideHelper.getData("sc_category", {title:categoryName2}, true);
7325 SaraTest.assert(records.length === 2, "new category is created");
7326 });
7327 },
7328
7329 testPersistCatalogItem: function() {
7330 var gh = glideHelper;
7331 var name = "snsc sample catelog item" + SaraUtils.getRandom();
7332 gs.info("catelog item name: " + name);
7333 var description = "whatever";
7334 var short_description = "short descriprion";
7335 var categoryName = "snsc item category";
7336 var category = null;
7337
7338 SaraTest.test("Persist catalog item via Importset", function(){
7339 //prepare data
7340 deleteCategory(categoryName, true);
7341 createCategory(categoryName, true, "");
7342 category = getCategory(categoryName);
7343 gs.info("category id: " + category.sys_id);
7344 SaraTest.assert(category !== null, "category is created successfully");
7345
7346 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7347 name: name,
7348 description: description,
7349 short_description: short_description,
7350 use_sc_layout: true,
7351 no_quantity: true,
7352 category: category.sys_id,
7353 active: true
7354 });
7355 var item = gh.getData("sc_cat_item", {name: name});
7356 SaraTest.assert(item.name === name, "item is transformed correctly");
7357 SaraTest.assert(item.description === description, "description is transformed correctly");
7358 SaraTest.assert(item.short_description === short_description, "short_description is transformed correctly");
7359 SaraTest.assert(item.use_sc_layout == "true", "use_sc_layout is transformed correctly");
7360 SaraTest.assert(item.no_quantity == "true", "no_quantity is transformed correctly");
7361 SaraTest.assert(item.active == "true", "active is transformed correctly");
7362 SaraTest.assert(item.category === category.sys_id, "category is transformed correctly");
7363 });
7364
7365 SaraTest.test("Catalog item same name different category should create new", function() {
7366 var newCategoryName = categoryName + SaraUtils.getRandom();
7367 createCategory(newCategoryName, true, "");
7368 var newCat = getCategory(newCategoryName);
7369 gs.info("new category id: " + newCat.sys_id);
7370 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7371 name: name,
7372 description: "new description",
7373 short_description: "new short description",
7374 use_sc_layout: false,
7375 no_quantity: false,
7376 category: newCat.sys_id,
7377 active: false
7378 });
7379
7380 var records = gh.getData("sc_cat_item", {name: name}, true);
7381 SaraTest.assert(records.length === 2, "new item is created");
7382 });
7383
7384 SaraTest.test("Update catalog item via Importset", function(){
7385 var existingItem = gh.getData("sc_cat_item", {
7386 name: name,
7387 category: category.sys_id
7388 });
7389
7390 SaraTest.assert(existingItem !== undefined, "existing item is get correctly");
7391
7392 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7393 id: existingItem.sys_id,
7394 name: name,
7395 description: "new description",
7396 short_description: "new short description",
7397 use_sc_layout: false,
7398 no_quantity: false,
7399 category: category.sys_id,
7400 active: false
7401 });
7402 var items = gh.getData("sc_cat_item", {name: name, category: category.sys_id}, true);
7403 SaraTest.assert(items.length === 1, "no new item is created");
7404
7405 var item = items[0];
7406 SaraTest.assert(item.name === name, "item is transformed correctly");
7407 SaraTest.assert(item.description === "new description", "description is transformed correctly");
7408 SaraTest.assert(item.short_description === "new short description", "short_description is transformed correctly");
7409 SaraTest.assert(item.use_sc_layout == "false", "use_sc_layout is transformed correctly");
7410 SaraTest.assert(item.no_quantity == "false", "no_quantity is transformed correctly");
7411 SaraTest.assert(item.active == "false", "active is transformed correctly");
7412 SaraTest.assert(item.category === category.sys_id, "category is transformed correctly");
7413 });
7414 },
7415
7416 testPersistVariableSet: function() {
7417 var varSetName = "snsc test variable set " + SaraUtils.getRandom();
7418 var varSetTitle = "title";
7419 var varSetDescription = "test description";
7420 var varSetDisplayName = "display name";
7421
7422 var varSetTitleNew = "title new";
7423 var varSetDescriptionNew = "test description new";
7424 var varSetDisplayNameNew = "display name new";
7425
7426 glideHelper.deleteData("item_option_new_set", {"name": ["CONTAINS", "snsc test"]}, true);
7427
7428 SaraTest.test("Persist variable set via Importset", function() {
7429 glideHelper.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7430 name: varSetName,
7431 title: varSetTitle,
7432 description: varSetDescription,
7433 sys_name: varSetDisplayName
7434 });
7435
7436 var varSet = glideHelper.getData("item_option_new_set", {"name": varSetName});
7437
7438 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7439 SaraTest.assert(varSet.name === varSetName, "var set name is transformed correctly");
7440 SaraTest.assert(varSet.title === varSetTitle, "var set title is transformed correctly");
7441 SaraTest.assert(varSet.description === varSetDescription, "var set description is transformed correctly");
7442 SaraTest.assert(varSet.sys_name === varSetDisplayName, "var set display name is transformed correctly");
7443 });
7444
7445 SaraTest.test("Update var set via Importset", function() {
7446 var existingVarSet = glideHelper.getData("item_option_new_set", {name: varSetName});
7447 SaraTest.assert(existingVarSet !== undefined, "var set is get correctly");
7448
7449 glideHelper.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7450 id: existingVarSet.sys_id,
7451 name: varSetName,
7452 title: varSetTitleNew,
7453 description: varSetDescriptionNew
7454 });
7455
7456 var varSets = glideHelper.getData("item_option_new_set", {"name": varSetName}, true);
7457
7458 SaraTest.assert(varSets.length === 1, "no new item is get correctly");
7459 var varSet = varSets[0];
7460 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7461 SaraTest.assert(varSet.name === varSetName, "var set name is transformed correctly");
7462 SaraTest.assert(varSet.title === varSetTitleNew, "var set title is updated correctly");
7463 SaraTest.assert(varSet.description === varSetDescriptionNew, "var set description is updated correctly");
7464 });
7465 },
7466
7467 testPersistCatelogVariableSet : function() {
7468 var varSetName = "snsc test variable set " + SaraUtils.getRandom();
7469 var varSetTitle = "title";
7470 var varSetDescription = "test description";
7471 var varSetDisplayName = "display name";
7472
7473 var newCategoryName = "snsc category " + SaraUtils.getRandom();
7474
7475 var catItemName = "snsc cat item " + SaraUtils.getRandom();
7476
7477 var gh = glideHelper;
7478
7479 gh.deleteData("item_option_new_set", {"name": ["CONTAINS", "snsc test"]}, true);
7480
7481 SaraTest.test("Persist catalog variable set via Importset", function() {
7482 gh.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7483 name: varSetName,
7484 title: varSetTitle,
7485 description: varSetDescription,
7486 display_name: varSetDisplayName
7487 });
7488
7489 var varSet = glideHelper.getData("item_option_new_set", {"name": varSetName});
7490
7491 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7492
7493 createCategory(newCategoryName);
7494 var newCat = getCategory(newCategoryName);
7495
7496 gs.info("new category id: " + newCat.sys_id);
7497
7498 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7499 name: catItemName,
7500 description: "new description",
7501 short_description: "new short description",
7502 use_sc_layout: true,
7503 no_quantity: true,
7504 category: newCat.sys_id,
7505 active: true
7506 });
7507
7508 var catItem = gh.getData("sc_cat_item", {name: catItemName, category: newCat.sys_id});
7509 SaraTest.assert(catItem !== undefined, "cat item is transformed successfully");
7510
7511 //link item and varset via import set
7512 gh.persistData("x_ausgh_snsc_io_set_item_ist", {sc_cat_item: catItem.sys_id, variable_set: varSet.sys_id});
7513 //get real
7514 var catVarSet = gh.getData("io_set_item", {sc_cat_item: catItem.sys_id, variable_set: varSet.sys_id});
7515
7516 SaraTest.assert(catVarSet !== null, "catalog item variable is transformed correctly");
7517 SaraTest.assert(catVarSet.sc_cat_item === catItem.sys_id, "cat item is set correctly");
7518 SaraTest.assert(catVarSet.variable_set === varSet.sys_id, "var set is set correctly");
7519 });
7520 },
7521
7522 testPersistSaraDefinition : function() {
7523 var newCategoryName = "snsc test category " + SaraUtils.getRandom();
7524 var parentCategoryName = "snsc test parent category " + SaraUtils.getRandom();
7525
7526 var varSetName = "snsc test var set" + SaraUtils.getRandom();
7527
7528 var definitionName1 = "snsc test" + SaraUtils.getRandom();
7529 var definitionName2 = "snsc test" + SaraUtils.getRandom();
7530 var definitionName3 = "snsc test" + SaraUtils.getRandom();
7531
7532 var catItemName1 = "snsc test cat item" + SaraUtils.getRandom();
7533
7534 var consume_url1 = "http://automictest.com";
7535 var consume_url2 = "http://automictest2.com";
7536 var hash1 = "FDSGHERGGGGFGFGDGFS";
7537 var hash2 = "FDSFFSDHASAFGFGDGFS";
7538
7539 var gh = glideHelper;
7540
7541 gh.deleteData("x_ausgh_snsc_sara_definition", {"name": ["CONTAINS", "snsc test"]}, true);
7542
7543 SaraTest.test("Persist sara definition for catalog item via Importset", function() {
7544 createCategory(parentCategoryName);
7545 var parentCat = getCategory(parentCategoryName);
7546 SaraTest.assert(parentCat !== null, "parentCat is transformed correctly");
7547
7548 createCategory(newCategoryName);
7549 var newCat = getCategory(newCategoryName);
7550 SaraTest.assert(newCat !== null, "newCat is transformed correctly");
7551
7552 //create var set
7553 gh.persistData("x_ausgh_snsc_item_option_new_set_ist", {
7554 name: varSetName,
7555 title: "title",
7556 description: "description",
7557 display_name: "whatever"
7558 });
7559
7560 var varSet = gh.getData("item_option_new_set", {"name": varSetName});
7561 SaraTest.assert(varSet !== null, "varSet is transformed correctly");
7562
7563 //create catalog item
7564 gh.persistData("x_ausgh_snsc_sara_cat_item_ist", {
7565 name: catItemName1,
7566 description: "new description",
7567 short_description: "new short description",
7568 use_sc_layout: true,
7569 no_quantity: true,
7570 category: newCat.sys_id,
7571 active: true
7572 });
7573
7574 var catItem = gh.getData("sc_cat_item", {name: catItemName1, category: newCat.sys_id});
7575 SaraTest.assert(catItem !== null, "catItem is transformed correctly");
7576
7577 gh.persistData("x_ausgh_snsc_sara_definition_ist", {
7578 u_name: definitionName1,
7579 u_consume_url: consume_url1,
7580 u_sc_item: catItem.sys_id,
7581 u_service_catalog_category: newCat.sys_id,
7582 u_var_set: varSet.sys_id,
7583 u_parent: parentCat.sys_id,
7584 u_type: "service",
7585 u_hash: hash1
7586 });
7587 var saraDefinition = gh.getData("x_ausgh_snsc_sara_definition_ist", {u_name: definitionName1, u_parent: parentCat.sys_id});
7588
7589 SaraTest.assert(saraDefinition !== null, "saraDefinition is transformed correctly");
7590 gs.info("saraDefinition: " + SaraJSON.stringify(saraDefinition));
7591 SaraTest.assert(saraDefinition.u_name === definitionName1, "u_name is transformed correctly");
7592 SaraTest.assert(saraDefinition.u_consume_url === consume_url1, "consume_url is transformed correctly");
7593 SaraTest.assert(saraDefinition.u_sc_item === catItem.sys_id, "u_sc_item is transformed correctly");
7594 SaraTest.assert(saraDefinition.u_service_catalog_category === newCat.sys_id, "u_service_catalog_category is transformed correctly");
7595 SaraTest.assert(saraDefinition.u_var_set === varSet.sys_id, "u_var_set is transformed correctly");
7596 SaraTest.assert(saraDefinition.u_parent === parentCat.sys_id, "u_parent is transformed correctly");
7597 SaraTest.assert(saraDefinition.u_type === "service", "u_type is transformed correctly");
7598 SaraTest.assert(saraDefinition.u_hash === hash1, "u_hash is transformed correctly");
7599 });
7600 }
7601 };
7602})();
7603
7604var SaraTest = (function() {
7605 var indent = "";
7606 var logger = new SaraLog("SaraTest");
7607 var pass = 0;
7608 var fail = 0;
7609 var isIgnore = false;
7610 var ignored = 0;
7611 var continueOnError = true;
7612
7613 var log = function() {
7614 logger.info.apply(logger,arguments);
7615 };
7616
7617 return {
7618 resetSummary: function() {
7619 pass = 0;
7620 fail = 0;
7621 ignored = 0;
7622 },
7623
7624 disableContinueOnError:function() {
7625 continueOnError = false;
7626 },
7627
7628 getSummary: function() {
7629 return {
7630 pass: pass,
7631 fail: fail,
7632 ignore: ignored,
7633 total: pass + fail + ignored
7634 };
7635 },
7636
7637 ignore: function() {
7638 isIgnore = true;
7639 },
7640
7641 assert: function(value, desc) {
7642 var prefix = ">>>PASS: ";
7643 if(!value) {
7644 prefix = "<<<FAIL: ";
7645 }
7646 logger.info("{0}{1}{2}", indent, prefix, desc);
7647 if(!value) {
7648 var exceptionMsg = prefix + desc;
7649 throw new Error(exceptionMsg);
7650 }
7651 },
7652 assertEqual: function(actual, expected, desc) {
7653 var failed = false;
7654 var prefix = ">>>PASS: ";
7655 if(actual != expected) {
7656 prefix = "<<<FAIL: ";
7657 failed = true;
7658 }
7659 logger.info("{0}{1}{2}", indent, prefix, desc);
7660 if(failed) {
7661 logger.info("Expected: {0}; Actual: {1}", expected, actual);
7662 }
7663 if(failed) {
7664 var exceptionMsg = prefix + desc + "; Expected:" + expected + "; Actual: " + actual
7665
7666 throw new Error(exceptionMsg);
7667 }
7668 },
7669 test: function(name, fn) {
7670 indent = "";
7671 logger.info("********************************");
7672 if(isIgnore) {
7673 logger.info("[IGNORE] {0}", name);
7674 isIgnore = false;
7675 ignored++;
7676 return;
7677 }
7678 logger.info("[TEST CASE] {0}", name);
7679 indent = " ";
7680
7681 if(continueOnError) {
7682 try {
7683 fn();
7684 pass++;
7685 }
7686 catch(err) {
7687 gs.error(err);
7688 fail++;
7689 }
7690 }
7691 else {
7692 fn();
7693 pass++;
7694 }
7695
7696 indent = "";
7697 },
7698 type: "SaraTest"
7699 };
7700})();
7701]]></script>
7702 <description>Sara Test Bench</description>
7703 <active>true</active>
7704 <client_callable>false</client_callable>
7705 <access>public</access>
7706 </script_include>
7707</script_includes>
7708
7709
7710 <ui_scripts>
7711 <ui_script>
7712 <script_name>SaraVarSet</script_name>
7713 <script><![CDATA[/**
7714 * Catalog client script for SaraVariableSet
7715 */
7716var x_ausgh_snsc = x_ausgh_snsc || {};
7717x_ausgh_snsc.SaraVarSet = x_ausgh_snsc.SaraVarSet || {};
7718
7719(function (SaraVarSet) {
7720 'use strict';
7721
7722 /**
7723 * OnLoad event handler for Sara variable set
7724 */
7725 SaraVarSet.onLoad = function () {
7726 SaraVarSet.initListCollector();
7727 SaraVarSet.setSelectBoxWidth();
7728 };
7729
7730 /**
7731 * Init collector filter
7732 */
7733 SaraVarSet.initListCollector = function () {
7734 x_ausgh_snsc.log('Start: SaraVarSet.initListCollector');
7735 var messageTables = $$('[id$=_select_0_add_remove_message_table]');
7736 var listWrappers = $$('.list_name');
7737
7738 for (var i = 0, table; table = messageTables[i]; i++) {
7739 var name = table.id.replace('_select_0_add_remove_message_table', '');
7740 var wrapper = listWrappers[i];
7741 var target;
7742 var id;
7743
7744 if (wrapper) {
7745 target = wrapper;
7746 } else {
7747 target = table;
7748 }
7749
7750 id = target.nextSibling.id.replace('IO:', '');
7751
7752 SaraVarSet.getListCollectorData(id, name);
7753 }
7754
7755 x_ausgh_snsc.log('End: SaraVarSet.initListCollector');
7756 };
7757
7758 /**
7759 * Get list collector data from lookup table
7760 * @param {String} id The sys_id of list collector
7761 * @param {String} name The name of list collector
7762 */
7763 SaraVarSet.getListCollectorData = function (id, name) {
7764 var filterFn = name + 'g_filter';
7765 var acRequestFn = name + 'acRequest';
7766
7767 if (window[filterFn] === undefined || window[acRequestFn] === undefined) {
7768 setTimeout(function () {
7769 SaraVarSet.getListCollectorData(id, name);
7770 }, 100);
7771 return;
7772 }
7773
7774 window[filterFn].reset();
7775 window[filterFn].setQuery('u_control_id=' + id);
7776 window[acRequestFn](null);
7777 };
7778
7779 /**
7780 * Make all selecbox's width is 250px for preventing the broken of layout when value of option is too long
7781 */
7782 SaraVarSet.setSelectBoxWidth = function () {
7783 x_ausgh_snsc.log('Start: SaraVarSet.setSelectBoxWidth');
7784 var selectboxes = $$('select.cat_item_option');
7785
7786 for (var i = 0, selectbox; selectbox = selectboxes[i]; i++) {
7787 selectbox.style.width = '250px';
7788 }
7789
7790 x_ausgh_snsc.log('End: SaraVarSet.setSelectBoxWidth');
7791 };
7792
7793})(x_ausgh_snsc.SaraVarSet);
7794]]></script>
7795 <description>Catalog client script for SaraVariableSet</description>
7796 <active>true</active>
7797 <global>false</global>
7798 </ui_script>
7799 <ui_script>
7800 <script_name>SaraCommon</script_name>
7801 <script><![CDATA[/**
7802 * Common client properties for Sara
7803 */
7804var SaraCommon = SaraCommon || {};
7805
7806var x_ausgh_snsc = x_ausgh_snsc || {};
7807x_ausgh_snsc.SaraCommon = x_ausgh_snsc.SaraCommon || {};
7808
7809x_ausgh_snsc.log = function () {
7810 if (typeof (console) !== 'undefined') {
7811 if (navigator.appName === 'Microsoft Internet Explorer') {
7812 if (arguments.length == 1) {
7813 console.log('[SARA]', arguments[0]);
7814 } else if (arguments.length === 2) {
7815 console.log('[SARA]', arguments[0], arguments[1]);
7816 } else if (arguments.length > 2) {
7817 console.log('[SARA]', arguments[0], arguments[1], arguments[2]);
7818 }
7819 } else {
7820 console.log('[SARA]', arguments);
7821 }
7822 }
7823};
7824
7825x_ausgh_snsc.config = x_ausgh_snsc.config || {};
7826
7827(function (SaraCommon) {
7828 'use strict';
7829
7830 SaraCommon.SCOPED_APP = 'x_ausgh_snsc';
7831
7832 SaraCommon.CONFIG_NAME = {
7833 CLIENT_ID: 'client_id',
7834 CLIENT_SECRET: 'client_secret',
7835 TECHNICAL_USER: 'technical_user',
7836 SAPI_ENDPOINT: 'sapi_endpoint',
7837 TOKEN_ENDPOINT: 'token_endpoint',
7838 AUTH_ENDPOINT: 'auth_endpoint'
7839 };
7840
7841 SaraCommon.CONTROL_NAME = {
7842 CLIENT_SCRIPTS: 'sara_client_scripts',
7843 HIDDEN_CONTROL: 'sara_hidden_control'
7844 };
7845
7846})(x_ausgh_snsc.SaraCommon);
7847]]></script>
7848 <description>Common client properties for Sara</description>
7849 <active>true</active>
7850 <global>false</global>
7851 </ui_script>
7852 <ui_script>
7853 <script_name>SaraOAuth</script_name>
7854 <script><![CDATA[/**
7855 * Client script for OAuth integration
7856 */
7857var x_ausgh_snsc = x_ausgh_snsc || {};
7858x_ausgh_snsc.SaraOAuth = x_ausgh_snsc.SaraOAuth || {};
7859
7860(function (SaraOAuth) {
7861 'use strict';
7862
7863 /**
7864 * Login to OAuth server for authentication
7865 * @param {String} clientId The client ID of OAuth Server
7866 * @param {String} technicalUser The tecnical user who owns the tokens
7867 * @param {String} authEndpoint The authorization endpoint of OAuth Server
7868 * @param {Object} callback The callback object contains onSuccess and onFail handler
7869 */
7870 SaraOAuth.login = function (clientId, technicalUser, authEndpoint, callback) {
7871 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?')) {
7872 SaraOAuth.processSuccess = null;
7873 SaraOAuth.processFail = null;
7874
7875 if (SaraOAuth.win) {
7876 SaraOAuth.win.close();
7877 }
7878 SaraOAuth.win = null;
7879
7880 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Getting OAuth url...');
7881 ga.addParam('sysparm_name', 'getOAuthUrl');
7882 ga.addParam('sysparm_client_id', clientId);
7883 ga.addParam('sysparm_technical_user', technicalUser);
7884 ga.addParam('sysparm_auth_endpoint', authEndpoint);
7885 ga.getXML(function (response) {
7886 if (callback && callback.onSuccess && typeof (callback.onSuccess) == 'function') {
7887 SaraOAuth.processSuccess = callback.onSuccess;
7888 }
7889
7890 if (callback && callback.onFail && typeof (callback.onFail) == 'function') {
7891 SaraOAuth.processFail = callback.onFail;
7892 }
7893
7894 var w = 500;
7895 var h = 600;
7896
7897 var left = (screen.width / 2) - (w / 2);
7898 var top = (screen.height / 2) - (h / 2);
7899
7900 var url = response.responseXML.documentElement.getAttribute('answer');
7901 SaraOAuth.win = window.open(url, 'aelogin', 'width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
7902 });
7903 }
7904 };
7905
7906 /**
7907 * Process response from OAuth server. If is 'ok', will call SaraOAuth.processSuccess callback.
7908 * If is not 'ok', will log the answer and alert message.
7909 * @param {*} response The response
7910 */
7911 SaraOAuth.processResponse = function (response) {
7912 if (SaraOAuth.win) {
7913 SaraOAuth.win.close();
7914 }
7915
7916 x_ausgh_snsc.log('Callback response is: ' + response);
7917
7918 if (response === 'ok') {
7919 if (SaraOAuth.processSuccess && typeof (SaraOAuth.processSuccess) == 'function') {
7920 SaraOAuth.processSuccess();
7921 }
7922 } else {
7923 var msg;
7924
7925 if (typeof (response) == 'string' && response.match('^function') != 'function') {
7926 msg = x_ausgh_snsc.SaraUtils.formatString('Token request finished unsuccessfully{0}. Please try again later or contact administrators.', response ? (', error: ' + response) : '');
7927 } else {
7928 msg = 'Token request finished unsuccessfully! Please try again later or contact administrators.';
7929 }
7930
7931 alert(msg);
7932
7933 if (SaraOAuth.processFail && typeof (SaraOAuth.processFail) == 'function') {
7934 SaraOAuth.processFail();
7935 }
7936
7937 x_ausgh_snsc.log(msg);
7938 }
7939 };
7940
7941 /**
7942 * Get configuration
7943 * @param {Function} callback The callback will be called when getting configuration
7944 * successfully with parametter is object with same keys with x_ausgh_snsc.SaraCommon.CONFIG_NAME
7945 */
7946 SaraOAuth.getConfig = function (callback) {
7947 var configData = {};
7948 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Getting OAuth configuration...');
7949 ga.addParam('sysparm_name', 'getConfig');
7950
7951 ga.getXML(function (resp) {
7952 var config = resp.responseXML.getElementsByTagName('config')[0];
7953
7954 for (var key in x_ausgh_snsc.SaraCommon.CONFIG_NAME) {
7955 var name = x_ausgh_snsc.SaraCommon.CONFIG_NAME[key];
7956
7957 configData[name] = config.getAttribute(name);
7958 }
7959
7960 callback.call(this, configData);
7961 });
7962 };
7963
7964 /**
7965 * Check OAuth Token of current technical user is invalid, expired or empty
7966 * @param {String} technicalUser The tecnical user who owns the tokens
7967 * @param {String} sapiEndpoint The SAPI endpoint
7968 * @param {Boolean} hideWizardSubmit Hide submit button of wizard or not when token is empty, expired
7969 * or invalid
7970 * @param {Object<String, Function>} callback The callback object contains callbacks when valid,
7971 * invalid, error:
7972 * - onValid(); // Will be called when tokens are existed and valid.
7973 * - onInvalid(); // Will be called when tokens are existed but invalid.
7974 * - onError(errorMessage); // Will be called when have any error. 'errorMessage' is error message
7975 * - onExisted(); // Will be called if current technical user has tokens but not validate the token yet.
7976 * SaraCommon.TABLE_NAME.SARA_OAUTH table
7977 */
7978 SaraOAuth.checkOAuthToken = function (technicalUser, sapiEndpoint, hideWizardSubmit, callback) {
7979 x_ausgh_snsc.log('checkOAuthToken', technicalUser, sapiEndpoint, hideWizardSubmit, callback);
7980
7981 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Validating token...');
7982 ga.addParam('sysparm_name', 'validateToken');
7983 ga.addParam('sysparm_technical_user', technicalUser);
7984 ga.addParam('sysparm_sapi_endpoint', sapiEndpoint);
7985
7986 ga.getXML(function (resp) {
7987 var result = resp.responseXML.getElementsByTagName('result')[0];
7988
7989 if (result) {
7990 var isValid = result.getAttribute('isValid');
7991
7992 // Valid
7993 if (isValid === 'true') {
7994 if (hideWizardSubmit) {
7995 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(true);
7996 }
7997
7998 x_ausgh_snsc.log('Access token is valid');
7999
8000 if (typeof callback.onValid === 'function') {
8001 callback.onValid.call(this);
8002 }
8003
8004 // Invalid
8005 } else if (isValid === 'false') {
8006 if (hideWizardSubmit) {
8007 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(false);
8008 }
8009
8010 x_ausgh_snsc.log('Access token is invalid');
8011
8012 if (typeof callback.onInvalid === 'function') {
8013 callback.onInvalid.call(this);
8014 }
8015
8016 // Error
8017 } else {
8018 var errorMessage = result.getAttribute('message');
8019 x_ausgh_snsc.log(errorMessage);
8020
8021
8022 if (typeof callback.onError === 'function') {
8023 callback.onError.call(this, errorMessage);
8024 }
8025 }
8026 } else {
8027 var error = resp.responseXML.getElementsByTagName('error')[0];
8028 var errorMessage;
8029
8030 if (error) {
8031 errorMessage = error.getAttribute('message');
8032 }
8033
8034 if (typeof callback.onError === 'function') {
8035 callback.onError.call(this, errorMessage);
8036 }
8037 }
8038 });
8039 };
8040
8041})(x_ausgh_snsc.SaraOAuth);
8042]]></script>
8043 <description>Client script for OAuth integration</description>
8044 <active>true</active>
8045 <global>false</global>
8046 </ui_script>
8047 <ui_script>
8048 <script_name>SaraUtils</script_name>
8049 <script><![CDATA[/**
8050 * Sara Utilities
8051 */
8052var x_ausgh_snsc = x_ausgh_snsc || {};
8053x_ausgh_snsc.SaraUtils = x_ausgh_snsc.SaraUtils || {};
8054
8055(function (SaraUtils) {
8056 'use strict';
8057
8058 /**
8059 * Format strings
8060 * @method format
8061 * @param {String} string The template string
8062 * @param {String[]} args Zero or more objects to format, supplied either in a comma-delimited list or as an array
8063 */
8064 SaraUtils.formatString = function (string) {
8065 var args = Array.prototype.slice.call(arguments, 1);
8066
8067 return string.replace(/{(\d+)}/g, function (match, number) {
8068 return typeof args[number] != 'undefined' ? args[number] : match;
8069 });
8070 };
8071
8072 /**
8073 * Get parameter value in current URL
8074 * @param {String} name The name of parameter
8075 * @return {String}
8076 */
8077 SaraUtils.getParmVal = function (name) {
8078 name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
8079 var regexS = '[\\?&]' + name + '=([^&#]*)';
8080 var regex = new RegExp(regexS);
8081 var results = regex.exec(window.location.href);
8082
8083 if (results == null) {
8084 return '';
8085 } else {
8086 return unescape(results[1]);
8087 }
8088 };
8089
8090 /**
8091 * Hide/show submit button of wizard
8092 * @param {Boolean} isVisible Submit button is visible or not
8093 */
8094 SaraUtils.setWizardSubmitVisible = function (isVisible) {
8095 document.getElementById('expert_next').style.display = isVisible ? '' : 'none';
8096 };
8097
8098 /**
8099 * Set visible of a form control
8100 * @param {String} name Name of control
8101 * @param {Boolean} isVisible Control is hidden or visible
8102 */
8103 SaraUtils.setFormControlVisible = function (name, isVisible) {
8104 if (g_form) {
8105 g_form.setDisplay(name, isVisible);
8106 }
8107 }
8108
8109})(x_ausgh_snsc.SaraUtils);
8110]]></script>
8111 <description>Sara Utilities</description>
8112 <active>true</active>
8113 <global>false</global>
8114 </ui_script>
8115 <ui_script>
8116 <script_name>SaraGlideAjax</script_name>
8117 <script><![CDATA[/**
8118 * Helper class wraps GlideAjax class of ServiceNow and provide Loading Dialog with custom title
8119 */
8120var x_ausgh_snsc = x_ausgh_snsc || {};
8121x_ausgh_snsc.SaraGlideAjax = x_ausgh_snsc.SaraGlideAjax || Class.create();
8122
8123(function (SaraGlideAjax) {
8124 'use strict';
8125
8126 SaraGlideAjax.prototype = {
8127 /**
8128 * Initialize SaraGlideAjax
8129 * @param {String} className The class name of callable Script Include
8130 * @param {String} title The title of loading dialog
8131 */
8132 initialize: function (className, title) {
8133 this.title = title;
8134 this.ga = new GlideAjax(className);
8135 this.ga.addParam('sysparm_scope', x_ausgh_snsc.SaraCommon.SCOPED_APP);
8136 this.className = className;
8137 },
8138
8139 /**
8140 * Add parameter for GlideAjax
8141 * @param {String} key The key of parameter
8142 * @param {String} value The value of parameter
8143 */
8144 addParam: function (key, value) {
8145 this.ga.addParam(key, value);
8146 },
8147
8148 /**
8149 * Get XML response from server
8150 * @param {Function} callback The callback will be call after getting response from server
8151 */
8152 getXML: function (callback) {
8153 var loadingDialog = new GlideDialogWindow('hierarchical_progress_viewer');
8154 loadingDialog.hideCloseButton();
8155 loadingDialog.setTitle(this.title);
8156
8157 var className = this.className;
8158 x_ausgh_snsc.log('Sending request to ' + className + '...');
8159
8160 this.ga.getXML(function (response) {
8161 loadingDialog.destroy();
8162 x_ausgh_snsc.log('Got response from ' + className, response);
8163
8164 if (typeof callback === 'function') {
8165 callback.apply(this, arguments);
8166 }
8167 });
8168 },
8169
8170 type: 'SaraGlideAjax'
8171 };
8172
8173})(x_ausgh_snsc.SaraGlideAjax);
8174]]></script>
8175 <description>Helper class wraps GlideAjax class of ServiceNow and provide Loading Dialog with custom title</description>
8176 <active>true</active>
8177 <global>false</global>
8178 </ui_script>
8179</ui_scripts>
8180
8181
8182 <ui_pages>
8183 <ui_page>
8184 <name>sara_oauth_callback</name>
8185 <description>OAuth Redirection Endpoint</description>
8186 <category>general</category>
8187 <html><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
8188<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
8189 <g:requires name="x_ausgh_snsc.SaraCommon.jsdbx" params="cache=$[jvar_stamp]" />
8190 <g:requires name="x_ausgh_snsc.SaraGlideHelper.jsdbx" params="cache=$[jvar_stamp]" />
8191 <g:requires name="x_ausgh_snsc.SaraGlideAjax.jsdbx" params="cache=$[jvar_stamp]" />
8192 <g:requires name="x_ausgh_snsc.SaraOAuth.jsdbx" params="cache=$[jvar_stamp]" />
8193 <g:requires name="x_ausgh_snsc.SaraUtils.jsdbx" params="cache=$[jvar_stamp]" />
8194 <g:requires name="x_ausgh_snsc.SaraVarSet.jsdbx" params="cache=$[jvar_stamp]" />
8195
8196 <g:ui_form>
8197 <p>
8198 <label>Please wait, processing...</label>
8199 </p>
8200 </g:ui_form>
8201</j:jelly>
8202]]></html>
8203 <client_script><![CDATA[var parentWin = (window.opener && window.opener.x_ausgh_snsc.SaraOAuth) ? window.opener : window.parent;
8204
8205if (!parentWin || !parentWin.x_ausgh_snsc || !parentWin.x_ausgh_snsc.SaraOAuth || !parentWin.x_ausgh_snsc.SaraOAuth.processResponse || typeof(parentWin.x_ausgh_snsc.SaraOAuth.processResponse) !== 'function') {
8206 window.location.href = '/home.do';
8207} else {
8208 var code = x_ausgh_snsc.SaraUtils.getParmVal('code');
8209 x_ausgh_snsc.log('Code: ' + code);
8210
8211 if (code) {
8212 var clientId = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID];
8213 var clientSecret = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_SECRET];
8214 var technicalUser = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER];
8215 var tokenEndpoint = parentWin.x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT];
8216
8217 x_ausgh_snsc.log('Client ID: ' + clientId, 'Client Secret: ' + clientSecret, 'Token Endpoint: ' + tokenEndpoint)
8218
8219 // Invoke x_ausgh_snsc.SaraOAuthAjax to exchange code for tokens
8220 x_ausgh_snsc.log('Init GlideAjax for requesting token by code...');
8221 var ga = new x_ausgh_snsc.SaraGlideAjax('SaraOAuthAjax', 'Requesting token by code...');
8222 ga.addParam('sysparm_name', 'requestTokenByCode');
8223 ga.addParam('sysparm_code', code);
8224 ga.addParam('sysparm_client_id', clientId);
8225 ga.addParam('sysparm_client_secret', clientSecret);
8226 ga.addParam('sysparm_technical_user', technicalUser);
8227 ga.addParam('sysparm_token_endpoint', tokenEndpoint);
8228
8229 ga.getXML(function (response) {
8230 var answer = response.responseXML.documentElement.getAttribute('answer');
8231 parentWin.x_ausgh_snsc.SaraOAuth.processResponse(answer);
8232 });
8233 } else {
8234 x_ausgh_snsc.log('Code is empty!');
8235 parentWin.x_ausgh_snsc.SaraOAuth.processResponse();
8236 }
8237}
8238]]></client_script>
8239 <processing_script/>
8240 </ui_page>
8241</ui_pages>
8242
8243
8244 <ui_macros>
8245 <ui_macro>
8246 <name>sara_hidden_control</name>
8247 <description>UI Marco for Sara Hidden Control</description>
8248 <category>catalog</category>
8249 <active>true</active>
8250 <media_type/>
8251 <xml><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
8252<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
8253 <script type="text/javascript">
8254 $j(function () {
8255 x_ausgh_snsc.SaraUtils.setFormControlVisible(x_ausgh_snsc.SaraCommon.CONTROL_NAME.HIDDEN_CONTROL, false);
8256 x_ausgh_snsc.SaraVarSet.onLoad();
8257 });
8258 </script>
8259</j:jelly>
8260]]></xml>
8261 </ui_macro>
8262 <ui_macro>
8263 <name>sara_client_scripts</name>
8264 <description/>
8265 <category>catalog</category>
8266 <active>true</active>
8267 <media_type/>
8268 <xml><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
8269<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
8270 <g:requires name="x_ausgh_snsc.SaraCommon.jsdbx" params="cache=$[jvar_stamp]" />
8271 <g:requires name="x_ausgh_snsc.SaraGlideAjax.jsdbx" params="cache=$[jvar_stamp]" />
8272 <g:requires name="x_ausgh_snsc.SaraOAuth.jsdbx" params="cache=$[jvar_stamp]" />
8273 <g:requires name="x_ausgh_snsc.SaraUtils.jsdbx" params="cache=$[jvar_stamp]" />
8274 <g:requires name="x_ausgh_snsc.SaraVarSet.jsdbx" params="cache=$[jvar_stamp]" />
8275
8276 <script type="text/javascript">
8277 $j(function () {
8278 x_ausgh_snsc.SaraUtils.setFormControlVisible(x_ausgh_snsc.SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS, false);
8279 });
8280 </script>
8281</j:jelly>
8282]]></xml>
8283 </ui_macro>
8284</ui_macros>
8285
8286
8287 <workflows>
8288 <workflow>
8289 <name>Sara Service</name>
8290 <description>Sara Service workflow</description>
8291 <start>begin</start>
8292 <table>sc_req_item</table>
8293 <active>true</active>
8294 <published>true</published>
8295 <max_activity_count>1000000</max_activity_count>
8296
8297
8298 <stages>
8299 <stage>
8300 <name>Initializing</name>
8301 <order>100</order>
8302 <value>initializing</value>
8303 <ola/>
8304 </stage>
8305 <stage>
8306 <name>Transferring</name>
8307 <order>200</order>
8308 <value>transferring</value>
8309 <ola/>
8310 </stage>
8311 <stage>
8312 <name>Transferred</name>
8313 <order>300</order>
8314 <value>transferred</value>
8315 <ola/>
8316 </stage>
8317 <stage>
8318 <name>Transfer Failed</name>
8319 <order>300</order>
8320 <value>transfer_failed</value>
8321 <ola/>
8322 </stage>
8323 <stage>
8324 <name>Consume Failed</name>
8325 <order>400</order>
8326 <value>consume_failed</value>
8327 <ola/>
8328 </stage>
8329 <stage>
8330 <name>Running</name>
8331 <order>500</order>
8332 <value>running</value>
8333 <ola/>
8334 </stage>
8335 <stage>
8336 <name>Ended OK</name>
8337 <order>900</order>
8338 <value>ended_ok</value>
8339 <ola/>
8340 </stage>
8341 <stage>
8342 <name>Ended Failed</name>
8343 <order>900</order>
8344 <value>ended_failed</value>
8345 <ola/>
8346 </stage>
8347 <stage>
8348 <name>Completed</name>
8349 <order>1000</order>
8350 <value>completed</value>
8351 <ola/>
8352 </stage>
8353</stages>
8354
8355
8356
8357 <activities>
8358 <activity>
8359 <name>Begin</name>
8360 <activity_definition>Begin</activity_definition>
8361 <stage/>
8362 <width/>
8363 <height/>
8364 <x>1</x>
8365 <y>1</y>
8366 <snsc_name>begin</snsc_name>
8367 </activity>
8368
8369 <activity>
8370 <name>Check item's price is 0 or not?</name>
8371 <activity_definition>If</activity_definition>
8372 <stage/>
8373 <width/>
8374 <height/>
8375 <x>1</x>
8376 <y>2</y>
8377 <snsc_name>check_price</snsc_name>
8378 <variables>
8379 <variable>
8380 <name>script</name>
8381 <value><![CDATA[function ifScript() {
8382 var item = (new x_ausgh_snsc.SaraGlideHelper()).getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_CATALOG_ITEM, {
8383 'sys_id': current.cat_item.sys_id
8384 });
8385
8386 if ((item.price.toString()) === '0') {
8387 return 'yes';
8388 }
8389
8390 return 'no';
8391}
8392
8393answer = ifScript();
8394]]></value>
8395 </variable>
8396 <variable>
8397 <name>advanced</name>
8398 <value>1</value>
8399 </variable>
8400 </variables>
8401 </activity>
8402
8403 <activity>
8404 <name>Waiting for approval</name>
8405 <activity_definition>Approval - Group</activity_definition>
8406 <stage/>
8407 <width/>
8408 <height/>
8409 <x>1</x>
8410 <y>3</y>
8411 <snsc_name>waiting_for_approval</snsc_name>
8412 <variables>
8413 <variable>
8414 <name>wait_for</name>
8415 <value>first_any</value>
8416 </variable>
8417 <variable>
8418 <name>reject_handling</name>
8419 <value>reject</value>
8420 </variable>
8421 </variables>
8422 </activity>
8423
8424 <activity>
8425 <name>Approved</name>
8426 <activity_definition>Approval Action</activity_definition>
8427 <stage/>
8428 <width/>
8429 <height/>
8430 <x>2</x>
8431 <y>3</y>
8432 <snsc_name>approved</snsc_name>
8433 <variables>
8434 <variable>
8435 <name>action</name>
8436 <value>approved</value>
8437 </variable>
8438 </variables>
8439 </activity>
8440
8441 <activity>
8442 <name>Rejected</name>
8443 <activity_definition>Approval Action</activity_definition>
8444 <stage/>
8445 <width/>
8446 <height/>
8447 <x>1</x>
8448 <y>4</y>
8449 <snsc_name>rejected</snsc_name>
8450 <variables>
8451 <variable>
8452 <name>action</name>
8453 <value>rejected</value>
8454 </variable>
8455 </variables>
8456 </activity>
8457
8458 <activity>
8459 <name>Initializing</name>
8460 <activity_definition>Timer</activity_definition>
8461 <stage>initializing</stage>
8462 <width/>
8463 <height/>
8464 <x>3</x>
8465 <y>3</y>
8466 <snsc_name>initializing</snsc_name>
8467 <variables>
8468 <variable>
8469 <name>timer_type</name>
8470 <value>script</value>
8471 </variable>
8472 <variable>
8473 <name>script</name>
8474 <value><![CDATA[workflow.info('Initializing ...');
8475var currentUser = current.opened_by.user_name.toString();
8476workflow.info('Workflow started by {0}', currentUser);
8477workflow.scratchpad.openedBy = currentUser;
8478
8479var technicalUser = new x_ausgh_snsc.SaraConfig().getTechnicalUser();
8480workflow.info('Technical user: {0}', technicalUser);
8481workflow.scratchpad.technicalUser = technicalUser;
8482
8483// Set 'answer' to the number of seconds this timer should wait
8484answer = 2;
8485]]></value>
8486 </variable>
8487 </variables>
8488 </activity>
8489
8490 <activity>
8491 <name>Invoke Consume URL</name>
8492 <activity_definition>Run Script</activity_definition>
8493 <stage>transferring</stage>
8494 <width/>
8495 <height/>
8496 <x>4</x>
8497 <y>3</y>
8498 <snsc_name>invoke_consume</snsc_name>
8499 <variables>
8500 <variable>
8501 <name>script</name>
8502 <value><![CDATA[var restClient = new x_ausgh_snsc.SaraRESTClient();
8503restClient.setMIDServer(x_ausgh_snsc.SaraUtils.getMIDServer());
8504var oauthClient = new x_ausgh_snsc.SaraOAuthClient(restClient);
8505var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
8506
8507// Get tokens, store tokens in workflow scratchpad
8508var tokens = oauthClient.getUserTokens(workflow.scratchpad.technicalUser);
8509
8510if (!tokens) {
8511 workflow.info('Cannot find access tokens for this user "{0}". Order will be skipped', workflow.scratchpad.technicalUser);
8512} else {
8513 workflow.scratchpad.executionHref = null;
8514 workflow.scratchpad.isTransfered = false;
8515
8516 // get service name & consume URL
8517 var serviceName, consumeUrl, varSetId;
8518 var catId = current.cat_item.sys_id;
8519 var saraItem = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_DEFINITION, {
8520 'u_sc_item': catId
8521 });
8522
8523 if (saraItem) {
8524 serviceName = saraItem['u_name'];
8525 consumeUrl = saraItem['u_consume_url'];
8526 varSetId = saraItem['u_var_set'];
8527
8528 consumeUrl = x_ausgh_snsc.SaraUtils.buildUrl(consumeUrl);
8529
8530 workflow.info('Service name = {0}', serviceName);
8531 workflow.info('Consume URL = {0}', consumeUrl);
8532 workflow.info('Cat item = {0}', current.cat_item.name);
8533
8534 var payload = {};
8535 var payloadFields = {};
8536 payload.fieldvalues = payloadFields;
8537
8538 if (varSetId) {
8539 var saraVariables = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_VARIABLE, {
8540 'variable_set': varSetId
8541 }, true);
8542
8543 for (var i = 0, variable; variable = saraVariables[i]; i++) {
8544 var variableName = variable['name'];
8545
8546 if (variableName !== x_ausgh_snsc.SaraCommon.CONTROL_NAME.CLIENT_SCRIPTS
8547 && variableName !== x_ausgh_snsc.SaraCommon.CONTROL_NAME.HIDDEN_CONTROL
8548 && variable['u_name']) {
8549
8550 var currentVariable = current.variables[variableName];
8551 var currentValue;
8552
8553 if (variable['type'] === x_ausgh_snsc.SaraCommon.VAR_TYPE.LIST_COLLECTOR.toString()) {
8554 var values = currentVariable.toString().split(',');
8555 currentValue = [];
8556
8557 for (var j = 0, value; value = values[j]; j++) {
8558 var realValue = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_LOOKUP, {
8559 'sys_id': value
8560 });
8561
8562 currentValue.push(realValue['u_display_name']);
8563 }
8564 } else {
8565 currentValue = [currentVariable.getDisplayValue()];
8566 }
8567
8568 payloadFields[variable['u_name']] = currentValue;
8569 }
8570 }
8571 } else {
8572 workflow.info('There is no variables in catalog item (sys_id = {0})', catId);
8573 }
8574
8575 //---------------- audit information ---------------
8576 workflow.info('Add audit information');
8577
8578 var payloadParams = {};
8579 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.ORDER_ID] = current.request.number.toString();
8580 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.ORDER_TIMESTAMP] = current.sys_created_on.toString();
8581 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.ORDER_NAME] = current.sys_created_by.toString();
8582
8583 var approvalHistory = '<<Auto Approval>>';
8584
8585 if(current.approval_history != null) {
8586 var journal = glideHelper.getData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_JOURNAL_FIELD, {
8587 'element_id' : current.sys_id
8588 });
8589 if(journal != null) {
8590 approvalHistory = journal.value.toString();
8591 }
8592 }
8593
8594 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.APPROVAL_HISTORY] = approvalHistory;
8595 payloadParams[x_ausgh_snsc.SaraCommon.AUDIT.APPROVAL_TIMESTAMP] = current.approval_set.toString();
8596
8597 payload.parametervalues = payloadParams;
8598 //--------------- /audit information ---------------
8599
8600 var payloadStr = x_ausgh_snsc.SaraJSON.stringify(payload);
8601 workflow.info(payloadStr);
8602
8603 // Make request
8604 if (serviceName) {
8605 workflow.info('Invoking consume URL...');
8606
8607 var request = restClient.newSAPIRequest('post', consumeUrl);
8608 request.setContent('${payload}');
8609 request.addHeader('content-type', 'application/json;charset=UTF-8');
8610 request.setStringParameterNoEscape('payload', payloadStr);
8611
8612 // Add Authorization header
8613 request.addHeader('Authorization', tokens[3] + ' ' + tokens[0]);
8614
8615 var response = restClient.executeWithRefreshToken(request);
8616 var responseObject = response.getResponseObject();
8617
8618 if (response.haveError()) {
8619 workflow.info('Order process FAILED.');
8620 } else {
8621 workflow.info('Successfully transfered.');
8622 workflow.info('Response: {0}', response.getBody());
8623 var resObj = x_ausgh_snsc.SaraJSON.parse(response.getBody());
8624 var runId = resObj['runID'];
8625
8626 workflow.scratchpad.isTransfered = true;
8627
8628 if (runId !== undefined) {
8629 var executionHref = resObj['_links']['self']['href'];
8630 workflow.info('Got runId: {0}', runId.toString());
8631 workflow.info('Got execution href: {0}', executionHref);
8632 workflow.scratchpad.runId = runId;
8633 workflow.scratchpad.executionHref = executionHref;
8634
8635 // save runId to the 'correlation_id' column of current record in 'sc_req_item' table
8636 current['correlation_id'] = '' + runId;
8637 current.update();
8638 } else {
8639 workflow.info(resObj.message);
8640 }
8641 }
8642
8643 } else {
8644 workflow.info('Failed to make consume request as no service definition was defined.');
8645 }
8646 } else {
8647 workflow.info('Catalog item (sys_id = {0}) doesn\'t existed any more in {1}!', [catId, x_ausgh_snsc.SaraCommon.TABLE_NAME.SARA_DEFINITION]);
8648 }
8649}
8650]]></value>
8651 </variable>
8652 </variables>
8653 </activity>
8654
8655 <activity>
8656 <name>Check transfer result</name>
8657 <activity_definition>If</activity_definition>
8658 <stage>transferred</stage>
8659 <width/>
8660 <height/>
8661 <x>5</x>
8662 <y>3</y>
8663 <snsc_name>check_transfer</snsc_name>
8664 <variables>
8665 <variable>
8666 <name>script</name>
8667 <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
8668//
8669// For example,
8670//
8671answer = ifScript();
8672
8673function ifScript() {
8674 return (workflow.scratchpad.isTransfered == true ? 'yes' : 'no');
8675}
8676]]></value>
8677 </variable>
8678 <variable>
8679 <name>advanced</name>
8680 <value>1</value>
8681 </variable>
8682 </variables>
8683 </activity>
8684
8685 <activity>
8686 <name>Transfer Request Failed</name>
8687 <activity_definition>Log Message</activity_definition>
8688 <stage>transfer_failed</stage>
8689 <width/>
8690 <height/>
8691 <x>5</x>
8692 <y>4</y>
8693 <snsc_name>transfer_failed</snsc_name>
8694 <variables>
8695 <variable>
8696 <name>message</name>
8697 <value>Transfer request failed, order skipped.</value>
8698 </variable>
8699 </variables>
8700 </activity>
8701
8702 <activity>
8703 <name>Check consume result</name>
8704 <activity_definition>If</activity_definition>
8705 <stage>transferred</stage>
8706 <width/>
8707 <height/>
8708 <x>6</x>
8709 <y>4</y>
8710 <snsc_name>check_consume</snsc_name>
8711 <variables>
8712 <variable>
8713 <name>script</name>
8714 <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
8715//
8716// For example,
8717//
8718answer = ifScript();
8719
8720function ifScript() {
8721 return (workflow.scratchpad.executionHref != null ? 'yes' : 'no');
8722}
8723]]></value>
8724 </variable>
8725 <variable>
8726 <name>advanced</name>
8727 <value>1</value>
8728 </variable>
8729 </variables>
8730 </activity>
8731
8732 <activity>
8733 <name>Consume Request Failed</name>
8734 <activity_definition>Log Message</activity_definition>
8735 <stage>consume_failed</stage>
8736 <width/>
8737 <height/>
8738 <x>6</x>
8739 <y>5</y>
8740 <snsc_name>consume_failed</snsc_name>
8741 <variables>
8742 <variable>
8743 <name>message</name>
8744 <value>Consume request failed, order skipped.</value>
8745 </variable>
8746 </variables>
8747 </activity>
8748
8749 <activity>
8750 <name>Workflow Timer</name>
8751 <activity_definition>Timer</activity_definition>
8752 <stage>running</stage>
8753 <width/>
8754 <height/>
8755 <x>7</x>
8756 <y>5</y>
8757 <snsc_name>workflow_timer</snsc_name>
8758 <variables>
8759 <variable>
8760 <name>timer_type</name>
8761 <value>script</value>
8762 </variable>
8763 <variable>
8764 <name>script</name>
8765 <value><![CDATA[if (workflow.scratchpad.delay === undefined) {
8766 var delay = +x_ausgh_snsc.SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.WORKFLOW_DELAY);
8767 var timeout = +x_ausgh_snsc.SaraUtils.getSaraProperty(SaraCommon.SYSTEM_PROPERTY_NAME.WORKFLOW_TIMEOUT);
8768
8769 // If delay time in config is equal or lesser than 0, let make it '60'
8770 if (delay <= 0) {
8771 delay = 60;
8772 }
8773
8774 // Make sure that timeout minimum always be '0'
8775 if (timeout < 0) {
8776 timeout = 0;
8777 }
8778
8779 workflow.scratchpad.counter = 1;
8780 workflow.scratchpad.maxCount = (timeout / delay) + 1;
8781 workflow.scratchpad.delay = delay;
8782 workflow.scratchpad.timeout = timeout;
8783}
8784
8785answer = workflow.scratchpad.delay;
8786]]></value>
8787 </variable>
8788 </variables>
8789 </activity>
8790
8791 <activity>
8792 <name>Retrieve Execution Status</name>
8793 <activity_definition>Run Script</activity_definition>
8794 <stage>running</stage>
8795 <width/>
8796 <height/>
8797 <x>8</x>
8798 <y>5</y>
8799 <snsc_name>retrieve_status</snsc_name>
8800 <variables>
8801 <variable>
8802 <name>script</name>
8803 <value><![CDATA[var restClient = new x_ausgh_snsc.SaraRESTClient();
8804restClient.setMIDServer(x_ausgh_snsc.SaraUtils.getMIDServer());
8805var oauthClient = new x_ausgh_snsc.SaraOAuthClient(restClient);
8806var executionHref = x_ausgh_snsc.SaraUtils.buildUrl(workflow.scratchpad.executionHref);
8807
8808workflow.scratchpad.ended = 'unknown';
8809
8810// Get tokens, store tokens in workflow scratchpad
8811var tokens = oauthClient.getUserTokens(workflow.scratchpad.technicalUser);
8812var request = restClient.newSAPIRequest('get', executionHref);
8813request.addHeader('Authorization', tokens[3] + ' ' + tokens[0]);
8814
8815workflow.info('[{0}] Waiting for execution checking response ...', workflow.scratchpad.counter);
8816var response = restClient.executeWithRefreshToken(request);
8817var responseObject = response.getResponseObject();
8818
8819if (response.haveError()) {
8820 workflow.warn('Status code: {0}, error message: {1}', [responseObject.statusCode, responseObject.errorMessage]);
8821
8822 workflow.info('Stop retrieving execution status now.');
8823} else {
8824 workflow.info('Response received: {0}', response.getBody());
8825 var resObj = responseObject.bodyObject;
8826 var statusCode = resObj.statusCode;
8827 workflow.info('Status code: {0}, statusText: {1}', [statusCode.toString(), resObj.statusText]);
8828
8829 if (statusCode >= 1800) {
8830 if (statusCode === x_ausgh_snsc.SaraCommon.WORKFLOW_STATUS_CODE.ENDED_OK) {
8831 workflow.info('Execution finished successfully!');
8832 workflow.scratchpad.ended = 'ENDED_OK';
8833 } else {
8834 workflow.scratchpad.ended = statusCode + ' - ' + resObj.statusText;
8835 }
8836 }
8837}
8838
8839workflow.scratchpad.counter++;
8840]]></value>
8841 </variable>
8842 </variables>
8843 </activity>
8844
8845 <activity>
8846 <name>Check Timeout</name>
8847 <activity_definition>If</activity_definition>
8848 <stage>running</stage>
8849 <width/>
8850 <height/>
8851 <x>9</x>
8852 <y>5</y>
8853 <snsc_name>check_timeout</snsc_name>
8854 <variables>
8855 <variable>
8856 <name>script</name>
8857 <value><![CDATA[function ifScript() {
8858 var counter = workflow.scratchpad.counter;
8859 var maxCount = workflow.scratchpad.maxCount;
8860 var timeout = workflow.scratchpad.timeout;
8861
8862 if (timeout === 0) {
8863 if (workflow.scratchpad.ended !== 'unknown') {
8864 return 'yes';
8865 }
8866 } else {
8867 if (counter <= maxCount) {
8868 if (workflow.scratchpad.ended !== 'unknown') {
8869 return 'yes';
8870 }
8871 } else {
8872 return 'yes';
8873 }
8874 }
8875
8876 return 'no';
8877}
8878
8879answer = ifScript();
8880]]></value>
8881 </variable>
8882 <variable>
8883 <name>advanced</name>
8884 <value>1</value>
8885 </variable>
8886 </variables>
8887 </activity>
8888
8889 <activity>
8890 <name>Check Execution Result</name>
8891 <activity_definition>If</activity_definition>
8892 <stage>running</stage>
8893 <width/>
8894 <height/>
8895 <x>10</x>
8896 <y>6</y>
8897 <snsc_name>check_result</snsc_name>
8898 <variables>
8899 <variable>
8900 <name>script</name>
8901 <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
8902
8903answer = ifScript();
8904
8905function ifScript() {
8906 return (workflow.scratchpad.ended == 'ENDED_OK' ? 'yes' : 'no');
8907}
8908]]></value>
8909 </variable>
8910 <variable>
8911 <name>advanced</name>
8912 <value>1</value>
8913 </variable>
8914 </variables>
8915 </activity>
8916
8917 <activity>
8918 <name>Ended Failed</name>
8919 <activity_definition>Log Message</activity_definition>
8920 <stage>ended_failed</stage>
8921 <width/>
8922 <height/>
8923 <x>10</x>
8924 <y>7</y>
8925 <snsc_name>ended_failed</snsc_name>
8926 <variables>
8927 <variable>
8928 <name>message</name>
8929 <value>Workflow finished NOT OK.</value>
8930 </variable>
8931 </variables>
8932 </activity>
8933
8934 <activity>
8935 <name>Ended OK</name>
8936 <activity_definition>Log Message</activity_definition>
8937 <stage>ended_ok</stage>
8938 <width/>
8939 <height/>
8940 <x>11</x>
8941 <y>7</y>
8942 <snsc_name>ended_ok</snsc_name>
8943 <variables>
8944 <variable>
8945 <name>message</name>
8946 <value>Workflow finished successfully.</value>
8947 </variable>
8948 </variables>
8949 </activity>
8950
8951 <activity>
8952 <name>End</name>
8953 <activity_definition>End</activity_definition>
8954 <stage>completed</stage>
8955 <width/>
8956 <height/>
8957 <x>2</x>
8958 <y>8</y>
8959 <snsc_name>end</snsc_name>
8960 </activity>
8961</activities>
8962
8963
8964
8965 <transitions>
8966
8967 <transition>
8968 <from>begin</from>
8969 <to>check_price</to>
8970 <condition>
8971 <name>Always</name>
8972 <condition>true</condition>
8973 <order>1</order>
8974 <description/>
8975 </condition>
8976 </transition>
8977
8978
8979 <transition>
8980 <from>check_price</from>
8981 <to>waiting_for_approval</to>
8982 <condition>
8983 <name>No</name>
8984 <condition>activity.result == 'no'</condition>
8985 <order>1</order>
8986 <description/>
8987 </condition>
8988 </transition>
8989
8990
8991 <transition>
8992 <from>check_price</from>
8993 <to>approved</to>
8994 <condition>
8995 <name>Yes</name>
8996 <condition>activity.result == 'yes'</condition>
8997 <order>1</order>
8998 <description/>
8999 </condition>
9000 </transition>
9001
9002
9003 <transition>
9004 <from>waiting_for_approval</from>
9005 <to>rejected</to>
9006 <condition>
9007 <name>Rejected</name>
9008 <condition>activity.result == 'rejected'</condition>
9009 <order>1</order>
9010 <description/>
9011 </condition>
9012 </transition>
9013
9014
9015 <transition>
9016 <from>rejected</from>
9017 <to>end</to>
9018 <condition>
9019 <name>Always</name>
9020 <condition>true</condition>
9021 <order>1</order>
9022 <description/>
9023 </condition>
9024 </transition>
9025
9026
9027 <transition>
9028 <from>waiting_for_approval</from>
9029 <to>approved</to>
9030 <condition>
9031 <name>Approved</name>
9032 <condition>activity.result == 'approved' || activity.result == 'skipped'</condition>
9033 <order>1</order>
9034 <description/>
9035 </condition>
9036 </transition>
9037
9038
9039 <transition>
9040 <from>approved</from>
9041 <to>initializing</to>
9042 <condition>
9043 <name>Always</name>
9044 <condition>true</condition>
9045 <order>1</order>
9046 <description/>
9047 </condition>
9048 </transition>
9049
9050
9051 <transition>
9052 <from>initializing</from>
9053 <to>invoke_consume</to>
9054 <condition>
9055 <name>Always</name>
9056 <condition>true</condition>
9057 <order>1</order>
9058 <description/>
9059 </condition>
9060 </transition>
9061
9062
9063 <transition>
9064 <from>invoke_consume</from>
9065 <to>check_transfer</to>
9066 <condition>
9067 <name>Always</name>
9068 <condition>true</condition>
9069 <order>1</order>
9070 <description/>
9071 </condition>
9072 </transition>
9073
9074
9075 <transition>
9076 <from>check_transfer</from>
9077 <to>transfer_failed</to>
9078 <condition>
9079 <name>No</name>
9080 <condition>activity.result == 'no'</condition>
9081 <order>1</order>
9082 <description/>
9083 </condition>
9084 </transition>
9085
9086
9087 <transition>
9088 <from>transfer_failed</from>
9089 <to>end</to>
9090 <condition>
9091 <name>Always</name>
9092 <condition>true</condition>
9093 <order>1</order>
9094 <description/>
9095 </condition>
9096 </transition>
9097
9098
9099 <transition>
9100 <from>check_transfer</from>
9101 <to>check_consume</to>
9102 <condition>
9103 <name>Yes</name>
9104 <condition>activity.result == 'yes'</condition>
9105 <order>1</order>
9106 <description/>
9107 </condition>
9108 </transition>
9109
9110
9111 <transition>
9112 <from>check_consume</from>
9113 <to>consume_failed</to>
9114 <condition>
9115 <name>No</name>
9116 <condition>activity.result == 'no'</condition>
9117 <order>1</order>
9118 <description/>
9119 </condition>
9120 </transition>
9121
9122
9123 <transition>
9124 <from>consume_failed</from>
9125 <to>end</to>
9126 <condition>
9127 <name>Always</name>
9128 <condition>true</condition>
9129 <order>1</order>
9130 <description/>
9131 </condition>
9132 </transition>
9133
9134
9135 <transition>
9136 <from>check_consume</from>
9137 <to>workflow_timer</to>
9138 <condition>
9139 <name>Yes</name>
9140 <condition>activity.result == 'yes'</condition>
9141 <order>1</order>
9142 <description/>
9143 </condition>
9144 </transition>
9145
9146
9147 <transition>
9148 <from>workflow_timer</from>
9149 <to>retrieve_status</to>
9150 <condition>
9151 <name>Always</name>
9152 <condition>true</condition>
9153 <order>1</order>
9154 <description/>
9155 </condition>
9156 </transition>
9157
9158
9159 <transition>
9160 <from>retrieve_status</from>
9161 <to>check_timeout</to>
9162 <condition>
9163 <name>Always</name>
9164 <condition>true</condition>
9165 <order>1</order>
9166 <description/>
9167 </condition>
9168 </transition>
9169
9170
9171 <transition>
9172 <from>check_timeout</from>
9173 <to>workflow_timer</to>
9174 <condition>
9175 <name>No</name>
9176 <condition>activity.result == 'no'</condition>
9177 <order>2</order>
9178 <description/>
9179 </condition>
9180 </transition>
9181
9182
9183 <transition>
9184 <from>check_timeout</from>
9185 <to>check_result</to>
9186 <condition>
9187 <name>Yes</name>
9188 <condition>activity.result == 'yes'</condition>
9189 <order>1</order>
9190 <description/>
9191 </condition>
9192 </transition>
9193
9194
9195 <transition>
9196 <from>check_result</from>
9197 <to>ended_failed</to>
9198 <condition>
9199 <name>No</name>
9200 <condition>activity.result == 'no'</condition>
9201 <order>2</order>
9202 <description/>
9203 </condition>
9204 </transition>
9205
9206
9207 <transition>
9208 <from>ended_failed</from>
9209 <to>end</to>
9210 <condition>
9211 <name>Always</name>
9212 <condition>true</condition>
9213 <order>1</order>
9214 <description/>
9215 </condition>
9216 </transition>
9217
9218
9219 <transition>
9220 <from>check_result</from>
9221 <to>ended_ok</to>
9222 <condition>
9223 <name>Yes</name>
9224 <condition>activity.result == 'yes'</condition>
9225 <order>1</order>
9226 <description/>
9227 </condition>
9228 </transition>
9229
9230
9231 <transition>
9232 <from>ended_ok</from>
9233 <to>end</to>
9234 <condition>
9235 <name>Always</name>
9236 <condition>true</condition>
9237 <order>1</order>
9238 <description/>
9239 </condition>
9240 </transition>
9241</transitions>
9242
9243 </workflow>
9244</workflows>
9245
9246
9247 <fix_scripts>
9248 <fix_script>
9249 <name>Sara - Create Scheduler for auto-sync</name>
9250 <description>Create Scheduler for auto-sync service and lookup value</description>
9251 <active>true</active>
9252 <run_once>true</run_once>
9253 <script><![CDATA[var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
9254
9255glideHelper.persistData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_AUTO_SCRIPT, {
9256 'name': 'SaraAutoSync',
9257 'script': 'new x_ausgh_snsc.SaraSync().syncServices();',
9258 'active': true,
9259 'run_type': 'periodically',
9260 'run_period': '02:00:00',
9261 'sys_class_name': 'sysauto_script',
9262 'run_dayofweek': 1
9263});
9264]]></script>
9265 </fix_script>
9266 <fix_script>
9267 <name>Sara - Remove Scheduler for auto-sync</name>
9268 <description>Remove Scheduler for auto-sync service and lookup value</description>
9269 <active>true</active>
9270 <run_once>true</run_once>
9271 <script><![CDATA[var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
9272
9273glideHelper.deleteData(x_ausgh_snsc.SaraCommon.TABLE_NAME.SN_AUTO_SCRIPT, {
9274 'name': 'SaraAutoSync'
9275}, true);
9276]]></script>
9277 </fix_script>
9278</fix_scripts>
9279
9280
9281 <schedulers>
9282 <scheduler>
9283 <name>SaraAutoSync</name>
9284 <active>false</active>
9285 <run_type>periodically</run_type>
9286 <run_period>02:00:00</run_period>
9287 <sys_class_name>sysauto_script</sys_class_name>
9288 <run_dayofweek>1</run_dayofweek>
9289 <script>new x_ausgh_snsc.SaraSync().syncServices();</script>
9290 </scheduler>
9291</schedulers>
9292
9293
9294 <wizards>
9295 <wizard>
9296 <name>Automic OAuth Configuration</name>
9297 <type>expert</type>
9298 <banner_type>fixed</banner_type>
9299 <roles>x_ausgh_snsc.admin</roles>
9300 <first_panel>OAuth Client</first_panel>
9301 <variables>
9302 <variable>
9303 <name>sara_client_scripts</name>
9304 <type>14</type>
9305 <class>expert_variable</class>
9306 <question>Sara Client Scripts</question>
9307 <order>0</order>
9308 <mandatory>false</mandatory>
9309 <active>true</active>
9310 <panel>Config OAuth Client</panel>
9311 <macro>sara_client_scripts</macro>
9312 </variable>
9313 <variable>
9314 <name>client_id</name>
9315 <type>6</type>
9316 <class>expert_variable</class>
9317 <question>Client ID</question>
9318 <order>100</order>
9319 <mandatory>true</mandatory>
9320 <active>true</active>
9321 <panel>Config OAuth Client</panel>
9322 <show_help>true</show_help>
9323 <help_tag>More information</help_tag>
9324 <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>
9325 </variable>
9326 <variable>
9327 <name>client_secret</name>
9328 <type>6</type>
9329 <class>expert_variable</class>
9330 <question>Client Secret</question>
9331 <order>200</order>
9332 <mandatory>true</mandatory>
9333 <active>true</active>
9334 <panel>Config OAuth Client</panel>
9335 <show_help>true</show_help>
9336 <help_tag>More information</help_tag>
9337 <help_text>Secret phrase of OAuth client user. Example: AES_12345, the value will be encrypted in ServiceNow.</help_text>
9338 </variable>
9339 <variable>
9340 <name>technical_user</name>
9341 <type>6</type>
9342 <class>expert_variable</class>
9343 <question>Technical User</question>
9344 <order>300</order>
9345 <mandatory>true</mandatory>
9346 <active>true</active>
9347 <panel>Config OAuth Client</panel>
9348 <show_help>true</show_help>
9349 <help_tag>More information</help_tag>
9350 <help_text>User Name/Department. Example: TECHSYNC/AUTOMIC</help_text>
9351 </variable>
9352 <variable>
9353 <name>sapi_endpoint</name>
9354 <type>6</type>
9355 <class>expert_variable</class>
9356 <question>SAPI Endpoint</question>
9357 <order>400</order>
9358 <mandatory>true</mandatory>
9359 <active>true</active>
9360 <panel>Config OAuth Client</panel>
9361 <show_help>true</show_help>
9362 <help_tag>More information</help_tag>
9363 <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>
9364 </variable>
9365 <variable>
9366 <name>token_endpoint</name>
9367 <type>6</type>
9368 <class>expert_variable</class>
9369 <question>Token Endpoint</question>
9370 <order>500</order>
9371 <mandatory>true</mandatory>
9372 <active>true</active>
9373 <panel>Config OAuth Client</panel>
9374 <show_help>true</show_help>
9375 <help_tag>More information</help_tag>
9376 <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>
9377 </variable>
9378 <variable>
9379 <name>auth_endpoint</name>
9380 <type>6</type>
9381 <class>expert_variable</class>
9382 <question>Authorization Endpoint</question>
9383 <order>600</order>
9384 <mandatory>true</mandatory>
9385 <active>true</active>
9386 <panel>Config OAuth Client</panel>
9387 <show_help>true</show_help>
9388 <help_tag>More information</help_tag>
9389 <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>
9390 </variable>
9391 </variables>
9392
9393 <panels>
9394 <panel>
9395 <name>Config OAuth Client</name>
9396 <title>Config OAuth Client</title>
9397 <class>expert_panel</class>
9398 <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>
9399 <previous_message>Previous</previous_message>
9400 <next_message>Store OAuth Client Settings</next_message>
9401 <complete_message>Done</complete_message>
9402 <client_script>
9403 <name>SARA OAuth Client OnLoad</name>
9404 <active>true</active>
9405 <type>onLoad</type>
9406 <script><![CDATA[function onLoad() {
9407 g_form.getControl(x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_SECRET).type = 'password';
9408 x_ausgh_snsc.oldConfig = {};
9409
9410 x_ausgh_snsc.SaraOAuth.getConfig(function (configData) {
9411 for (var name in configData) {
9412 var value = configData[name];
9413
9414 g_form.setValue(name, value);
9415 x_ausgh_snsc.oldConfig[name] = value;
9416 }
9417 });
9418}
9419]]></script>
9420 </client_script>
9421 <client_script>
9422 <name>SARA OAuth Client OnSubmit</name>
9423 <active>true</active>
9424 <type>onSubmit</type>
9425 <script><![CDATA[function onSubmit() {
9426 if (x_ausgh_snsc.isTokenValid) {
9427 return true;
9428 } else {
9429 var isChange = false;
9430 for (var name in x_ausgh_snsc.oldConfig) {
9431 if (x_ausgh_snsc.oldConfig[name] !== g_form.getValue(name).toString() && name !== x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT) {
9432 isChange = true;
9433 break;
9434 }
9435 }
9436
9437 if (isChange && !x_ausgh_snsc.notChange) {
9438 getToken();
9439 } else {
9440 // Clean all existing messages
9441 g_form.clearMessages();
9442
9443 // Check if Sara tokens exist for Technical User
9444 var technicalUser = g_form.getValue(x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER).toString();
9445 var sapiEndpoint = g_form.getValue(x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT).toString();
9446 x_ausgh_snsc.SaraOAuth.checkOAuthToken(technicalUser, sapiEndpoint, false, {
9447 onValid: function () {
9448 x_ausgh_snsc.isTokenValid = true;
9449 g_expert.next();
9450 },
9451 onInvalid: function () {
9452 x_ausgh_snsc.isTokenValid = false;
9453 getToken();
9454 },
9455 onError: function (errorMessage) {
9456 x_ausgh_snsc.isTokenValid = false;
9457 g_form.addErrorMessage(errorMessage);
9458 }
9459 });
9460 }
9461 }
9462
9463 return false;
9464}
9465
9466function getToken() {
9467 x_ausgh_snsc.log('Preparing for openning OAuth login popup...');
9468
9469 for (var key in x_ausgh_snsc.SaraCommon.CONFIG_NAME) {
9470 var name = x_ausgh_snsc.SaraCommon.CONFIG_NAME[key];
9471
9472 x_ausgh_snsc.config[name] = g_form.getValue(name).toString();
9473 }
9474
9475 x_ausgh_snsc.SaraOAuth.login(
9476 x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID],
9477 x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER],
9478 x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.AUTH_ENDPOINT], {
9479 onSuccess: function () {
9480 x_ausgh_snsc.notChange = true;
9481 g_expert.next();
9482 }
9483 }
9484 );
9485}
9486]]></script>
9487 </client_script>
9488 </panel>
9489 <panel>
9490 <name>Config OAuth Client Completed</name>
9491 <title>Config OAuth Client Completed</title>
9492 <class>expert_panel</class>
9493 <description/>
9494 <previous_message>Previous</previous_message>
9495 <next_message>Next</next_message>
9496 <complete_message>Done</complete_message>
9497 </panel>
9498 </panels>
9499
9500 <transitions>
9501 <transition>
9502 <from>Config OAuth Client</from>
9503 <to>Config OAuth Client Completed</to>
9504 <order>100</order>
9505 <condition/>
9506 <transition_script><![CDATA[var LOGGER = new x_ausgh_snsc.SaraLog('sara_oauth_client_transition');
9507
9508gs.addInfoMessage('Client ID = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID]
9509 + ', Client Secret = ***'
9510 + ', Technical User = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER]
9511 + ', SAPI Endpoint = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT]
9512 + ', Token Endpoint = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT]
9513 + ', Authorization Endpoint = ' + wizard[x_ausgh_snsc.SaraCommon.CONFIG_NAME.AUTH_ENDPOINT]);
9514
9515var saraConfig = new x_ausgh_snsc.SaraConfig();
9516try {
9517 var configData = {};
9518 for (var key in x_ausgh_snsc.SaraCommon.CONFIG_NAME) {
9519 var name = x_ausgh_snsc.SaraCommon.CONFIG_NAME[key];
9520
9521 configData[name] = wizard[name];
9522 }
9523
9524 saraConfig.storeClientConfig(configData);
9525 LOGGER.info('OAuth Configuration updated:\n'
9526 + ' - Client ID = {0}, \n'
9527 + ' - Client Secret = ***, \n'
9528 + ' - Technical User = {1} \n'
9529 + ' - SAPI Endpoint = {2}, \n'
9530 + ' - Token Endpoint = {3}, \n'
9531 + ' - Authorization Endpoint = {4}',
9532 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.CLIENT_ID],
9533 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER],
9534 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT],
9535 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TOKEN_ENDPOINT],
9536 configData[x_ausgh_snsc.SaraCommon.CONFIG_NAME.AUTH_ENDPOINT]
9537 );
9538
9539 gs.addInfoMessage('Successfully update Automic OAuth client settings');
9540} catch (err) {
9541 LOGGER.info('Error on update Automic OAuth client settings: {0}', err);
9542
9543 gs.addInfoMessage('Failed to update Automic OAuth client settings');
9544}
9545]]></transition_script>
9546 </transition>
9547 </transitions>
9548 </wizard>
9549
9550 <wizard>
9551 <name>Automic Import Services</name>
9552 <type>expert</type>
9553 <banner_type>fixed</banner_type>
9554 <roles>x_ausgh_snsc.admin</roles>
9555 <first_panel>Import Services</first_panel>
9556 <variables>
9557 <variable>
9558 <name>sara_client_scripts</name>
9559 <type>14</type>
9560 <class>expert_variable</class>
9561 <question>Sara Client Scripts</question>
9562 <order>0</order>
9563 <mandatory>false</mandatory>
9564 <active>true</active>
9565 <panel>Import Services</panel>
9566 <macro>sara_client_scripts</macro>
9567 </variable>
9568 <variable>
9569 <name>sara_message</name>
9570 <type>6</type>
9571 <class>expert_variable</class>
9572 <question>Sara Message</question>
9573 <order>100</order>
9574 <mandatory>false</mandatory>
9575 <active>true</active>
9576 <panel>Import Services</panel>
9577 </variable>
9578 <variable>
9579 <name>sara_target_category</name>
9580 <type>18</type>
9581 <class>expert_variable</class>
9582 <question>Select Target Category</question>
9583 <order>200</order>
9584 <mandatory>true</mandatory>
9585 <active>true</active>
9586 <lookup_table>sc_category</lookup_table>
9587 <lookup_value>sys_id</lookup_value>
9588 <lookup_label>title</lookup_label>
9589 <panel>Import Services</panel>
9590 <reference_qual>javascript:x_ausgh_snsc.SaraUtils.getImportTargetCatRefQual()</reference_qual>
9591 </variable>
9592 </variables>
9593
9594 <panels>
9595 <panel>
9596 <name>Import Services</name>
9597 <title>Import Services</title>
9598 <class>expert_panel</class>
9599 <description><![CDATA[<p>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.</p>
9600 <p>The following roles are required to import services: x_ausgh_snsc.admin, catalog_admin, import_admin, soap, workflow_admin.</p>]]></description>
9601
9602 <previous_message>Previous</previous_message>
9603 <next_message>Import Services</next_message>
9604 <complete_message>Done</complete_message>
9605 <client_script>
9606 <name>Import Services OnLoad</name>
9607 <active>true</active>
9608 <type>onLoad</type>
9609 <script><![CDATA[function onLoad() {
9610 x_ausgh_snsc.SaraUtils.setFormControlVisible('sara_message', false);
9611 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(false);
9612
9613 x_ausgh_snsc.SaraOAuth.getConfig(function (configData) {
9614 for (var key in configData) {
9615 var value = configData[key];
9616
9617 x_ausgh_snsc.config[key] = value;
9618
9619 if (!value) {
9620 g_form.addErrorMessage('OAuth Configuration "' + key + '" is empty. Please check the current OAuth configuration.');
9621 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(false);
9622 break;
9623 }
9624 }
9625
9626 setTimeout(function () {
9627 checkToken();
9628 }, 100);
9629 });
9630}
9631
9632function checkToken() {
9633 var technicalUser = x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.TECHNICAL_USER];
9634 var sapiEndpoint = x_ausgh_snsc.config[x_ausgh_snsc.SaraCommon.CONFIG_NAME.SAPI_ENDPOINT];
9635 x_ausgh_snsc.SaraOAuth.checkOAuthToken(technicalUser, sapiEndpoint, true, {
9636 onValid: function () {
9637 x_ausgh_snsc.SaraUtils.setWizardSubmitVisible(true);
9638 },
9639 onInvalid: function () {
9640 g_form.addErrorMessage('Tokens are empty, invalid or expired! Please contact your administrator for resolving this problem.');
9641 },
9642 onError: function (errorMessage) {
9643 g_form.addErrorMessage(errorMessage);
9644 }
9645 });
9646}
9647]]></script>
9648 </client_script>
9649 <client_script>
9650 <name>Import Services OnSubmit</name>
9651 <active>true</active>
9652 <type>onSubmit</type>
9653 <script><![CDATA[function onSubmit() {
9654 if (x_ausgh_snsc.isOk) {
9655 return true;
9656 }
9657
9658 var importDialog = new GlideDialogWindow('hierarchical_progress_viewer');
9659 importDialog.setPreference('sysparm_ajax_processor', 'x_ausgh_snsc.SaraConsumerRunner');
9660 importDialog.setPreference('sysparm_catid', g_form.getValue('sara_target_category').toString());
9661 importDialog.setSize(400, 300);
9662 importDialog.setTitle('Importing service...');
9663
9664 importDialog.on('executionComplete', function (trackerObj) {
9665 x_ausgh_snsc.log('executionComplete', trackerObj);
9666 if (trackerObj.result && trackerObj.result.info) {
9667 importDialog.setTitle(trackerObj.result.msg);
9668 g_form.setValue('sara_message', trackerObj.result.info);
9669
9670 x_ausgh_snsc.isOk = true;
9671 x_ausgh_snsc.log('Go to next panel', x_ausgh_snsc.isOk);
9672 g_expert.next();
9673
9674
9675 x_ausgh_snsc.log('Destroy diablog', importDialog);
9676 importDialog.destroy();
9677 }
9678 });
9679
9680 importDialog.on("renderStatus", function (trackerObj) {
9681 x_ausgh_snsc.log('renderStatus', trackerObj);
9682
9683 if (trackerObj && trackerObj.result && trackerObj.result.msg) {
9684 importDialog.setTitle(trackerObj.result.msg);
9685 }
9686 });
9687
9688 // Render the viewer
9689 importDialog.render();
9690
9691 return false;
9692}
9693]]></script>
9694 </client_script>
9695 </panel>
9696 <panel>
9697 <name>Import Services Completed</name>
9698 <title>Import Services Completed</title>
9699 <class>expert_panel</class>
9700 <description/>
9701 <previous_message>Previous</previous_message>
9702 <next_message>Next</next_message>
9703 <complete_message>Done</complete_message>
9704 </panel>
9705 </panels>
9706
9707 <transitions>
9708 <transition>
9709 <from>Import Services</from>
9710 <to>Import Services Completed</to>
9711 <order>100</order>
9712 <condition>[sara_target_category]!=^EQ</condition>
9713 <transition_script><![CDATA[gs.addInfoMessage(wizard.sara_message.toString());
9714]]></transition_script>
9715 </transition>
9716 </transitions>
9717 </wizard>
9718
9719 <wizard>
9720 <name>Automic Clean-up</name>
9721 <type>expert</type>
9722 <banner_type>fixed</banner_type>
9723 <roles>x_ausgh_snsc.admin</roles>
9724 <first_panel>Automic Cleanup</first_panel>
9725 <variables>
9726 <variable/>
9727 </variables>
9728
9729 <panels>
9730 <panel>
9731 <name>Cleanup Catalog Items</name>
9732 <title>Cleanup Catalog Items</title>
9733 <class>expert_panel</class>
9734 <description>Cleanup all Automic SARA stuffs. This will delete all subcategories and service items.</description>
9735 <previous_message>Previous</previous_message>
9736 <next_message>Cleanup</next_message>
9737 <complete_message>Done</complete_message>
9738 </panel>
9739 <panel>
9740 <name>Cleanup Catalog Items Completed</name>
9741 <title>Cleanup Catalog Items Completed</title>
9742 <class>expert_panel</class>
9743 <description>Cleanup successfully!</description>
9744 <previous_message>Previous</previous_message>
9745 <next_message>Next</next_message>
9746 <complete_message>Done</complete_message>
9747 </panel>
9748 </panels>
9749
9750 <transitions>
9751 <transition>
9752 <from>Cleanup Catalog Items</from>
9753 <to>Cleanup Catalog Items Completed</to>
9754 <order>100</order>
9755 <condition/>
9756 <transition_script>
9757 <![CDATA[x_ausgh_snsc.SaraUtils.cleanup();]]>
9758 </transition_script>
9759 </transition>
9760 </transitions>
9761 </wizard>
9762</wizards>
9763
9764
9765 <processors>
9766 <processor>
9767 <name>SaraUpdateStatus</name>
9768 <type>script</type>
9769 <active>true</active>
9770 <description>Sara REST api for updating status of worflow remotely</description>
9771 <path>sara_update_status</path>
9772 <script><![CDATA[var LOGGER = new x_ausgh_snsc.SaraLog('SaraUpdateStatus');
9773var runId = g_request.getParameter('runId');
9774var status = g_request.getParameter('status');
9775var error = 0;
9776var result = {};
9777
9778LOGGER.info('SaraUpdateStatus: RunId = {0}, Status = {1}', runId, status);
9779LOGGER.info('SaraUpdateStatus: Request user = ' + gs.getUserName());
9780
9781if (!runId) {
9782 error += 1;
9783}
9784
9785if (!status) {
9786 error += 1;
9787}
9788
9789if (error === 0) {
9790 runId = +runId;
9791
9792 if (isNaN(runId)) {
9793 result = {
9794 code: 99,
9795 message: 'The runId must be digits!'
9796 };
9797 } else {
9798 var glideHelper = new x_ausgh_snsc.SaraGlideHelper();
9799 var reqItem = glideHelper.getData('sc_req_item', {
9800 'correlation_id': runId.toString()
9801 });
9802
9803 if (reqItem) {
9804 LOGGER.info('Found current request item (correlation_id = {0}, sys_id = {1})', runId, reqItem['sys_id']);
9805
9806 try {
9807 glideHelper.updateData('sc_req_item', {
9808 'sys_id': reqItem['sys_id']
9809 }, {
9810 'comments': status,
9811 'display_state': status
9812 });
9813
9814 result = {
9815 code: 200,
9816 message: 'Update OK!',
9817 sysId: reqItem['sys_id']
9818 };
9819 } catch (e) {
9820 result = {
9821 code: 99,
9822 message: err
9823 };
9824 }
9825 } else {
9826 var message = x_ausgh_snsc.SaraUtils.formatString('No request item (correlation_id = {0}) found! Update status failed.', runId);
9827 LOGGER.info(message);
9828
9829 result = {
9830 code: 99,
9831 message: message
9832 };
9833 }
9834 }
9835} else {
9836 result = {
9837 code: 99,
9838 message: 'The runId and status must be not null!'
9839 }
9840}
9841
9842var response = x_ausgh_snsc.SaraJSON.stringify(result);
9843
9844LOGGER.debug('SaraUpdateStatus: {0}', response);
9845
9846g_processor.writeOutput('application/json', response);
9847]]></script>
9848 </processor>
9849</processors>
9850
9851
9852 <snsc_application>
9853 <application>
9854 <name>Automic SNSC</name>
9855 <short_description>Automic ServiceNow Service Connector Application</short_description>
9856 <active>true</active>
9857 <user_role>x_ausgh_snsc.user</user_role>
9858 <version>1.0.2</version>
9859 <menu>u_ausgh_snsc_menu</menu>
9860 <scope>x_ausgh_snsc</scope>
9861 </application>
9862 <application_menu>
9863 <name>u_ausgh_snsc_menu</name>
9864 <active>true</active>
9865 <category>Custom Applications</category>
9866 <title>Automic SNSC</title>
9867 <roles>x_ausgh_snsc.user,x_ausgh_snsc.admin</roles>
9868 <hint>Automic ServiceNow Service Connector Application</hint>
9869 </application_menu>
9870 <user_roles>
9871 <user_role>
9872 <name>x_ausgh_snsc.user</name>
9873 <description>User role for SNSC application</description>
9874 </user_role>
9875 <user_role>
9876 <name>x_ausgh_snsc.admin</name>
9877 <description>Admin role for SNSC application</description>
9878 <includes_roles>x_ausgh_snsc.user</includes_roles>
9879 </user_role>
9880 </user_roles>
9881</snsc_application>
9882
9883
9884 <modules>
9885 <module>
9886 <title>Automic Configuration</title>
9887 <order>0</order>
9888 <active>true</active>
9889 <link_type>SEPARATOR</link_type>
9890 <roles>x_ausgh_snsc.admin</roles>
9891 </module>
9892 <module>
9893 <title>Automic Clean-up</title>
9894 <reference>wizard</reference>
9895 <reference_name>Automic Clean-up</reference_name>
9896 <order>10</order>
9897 <active>true</active>
9898 <link_type>DIRECT</link_type>
9899 <query>/expert_shell.do?sysparm_sys_id=@{sys_id}&sysparm_initial=true</query>
9900 <roles>x_ausgh_snsc.admin</roles>
9901 </module>
9902 <module>
9903 <title>Automic Import Services</title>
9904 <reference>wizard</reference>
9905 <reference_name>Automic Import Services</reference_name>
9906 <order>20</order>
9907 <active>true</active>
9908 <link_type>DIRECT</link_type>
9909 <query>/expert_shell.do?sysparm_sys_id=@{sys_id}&sysparm_initial=true</query>
9910 <roles>x_ausgh_snsc.admin</roles>
9911 </module>
9912 <module>
9913 <title>Automic OAuth Configuration</title>
9914 <reference>wizard</reference>
9915 <reference_name>Automic OAuth Configuration</reference_name>
9916 <order>30</order>
9917 <active>true</active>
9918 <link_type>DIRECT</link_type>
9919 <query>/expert_shell.do?sysparm_sys_id=@{sys_id}&sysparm_initial=true</query>
9920 <roles>x_ausgh_snsc.admin</roles>
9921 </module>
9922 <module>
9923 <title>Automic SNSC Components</title>
9924 <order>100</order>
9925 <active>true</active>
9926 <link_type>SEPARATOR</link_type>
9927 </module>
9928 <module>
9929 <title>Sara Tables</title>
9930 <order>110</order>
9931 <active>true</active>
9932 <link_type>LIST</link_type>
9933 <table_name>sys_db_object</table_name>
9934 <filter>nameSTARTSWITHx_ausgh_snsc_</filter>
9935 </module>
9936 <module>
9937 <title>Sara Transform Maps</title>
9938 <order>115</order>
9939 <active>true</active>
9940 <link_type>LIST</link_type>
9941 <table_name>sys_transform_map</table_name>
9942 <filter>nameSTARTSWITHx_ausgh_snsc_</filter>
9943 </module>
9944 <module>
9945 <title>Sara System Properties</title>
9946 <reference>system_property</reference>
9947 <reference_name>Automic</reference_name>
9948 <order>120</order>
9949 <active>true</active>
9950 <link_type>DIRECT</link_type>
9951 <query>/sys_properties_category.do?sys_id=@{sys_id}</query>
9952 </module>
9953 <module>
9954 <title>Sara Script Includes</title>
9955 <order>130</order>
9956 <active>true</active>
9957 <link_type>LIST</link_type>
9958 <table_name>sys_script_include</table_name>
9959 <filter>nameSTARTSWITHSara</filter>
9960 </module>
9961 <module>
9962 <title>Sara UI Scripts</title>
9963 <order>140</order>
9964 <active>true</active>
9965 <link_type>LIST</link_type>
9966 <table_name>sys_ui_script</table_name>
9967 <filter>nameSTARTSWITHx_ausgh_snsc.Sara</filter>
9968 </module>
9969 <module>
9970 <title>Sara UI Pages</title>
9971 <order>150</order>
9972 <active>true</active>
9973 <link_type>LIST</link_type>
9974 <table_name>sys_ui_page</table_name>
9975 <filter>nameSTARTSWITHsara_</filter>
9976 </module>
9977 <module>
9978 <title>Sara UI Macros</title>
9979 <order>160</order>
9980 <active>true</active>
9981 <link_type>LIST</link_type>
9982 <table_name>sys_ui_macro</table_name>
9983 <filter>nameSTARTSWITHsara_</filter>
9984 </module>
9985 <module>
9986 <title>Sara Processors</title>
9987 <order>170</order>
9988 <active>true</active>
9989 <link_type>LIST</link_type>
9990 <table_name>sys_processor</table_name>
9991 <filter>nameSTARTSWITHSara</filter>
9992 </module>
9993 <module>
9994 <title>Sara Wizards</title>
9995 <order>180</order>
9996 <active>true</active>
9997 <link_type>LIST</link_type>
9998 <table_name>expert</table_name>
9999 <filter>nameSTARTSWITHAutomic</filter>
10000 </module>
10001 <module>
10002 <title>Sara Schedulers</title>
10003 <order>190</order>
10004 <active>true</active>
10005 <link_type>LIST</link_type>
10006 <table_name>sysauto</table_name>
10007 <filter>nameSTARTSWITHSara</filter>
10008 </module>
10009 <module>
10010 <title>Sara REST Messages</title>
10011 <order>200</order>
10012 <active>true</active>
10013 <link_type>LIST</link_type>
10014 <table_name>sys_rest_message</table_name>
10015 <filter>nameSTARTSWITHSara</filter>
10016 </module>
10017 <module>
10018 <title>Support</title>
10019 <order>900</order>
10020 <active>true</active>
10021 <link_type>SEPARATOR</link_type>
10022 </module>
10023 <module>
10024 <title>Used ServiceNow's Tables</title>
10025 <order>910</order>
10026 <active>true</active>
10027 <link_type>LIST</link_type>
10028 <table_name>sys_db_object</table_name>
10029 <query>name=sc_category^ORname=item_option_new_set^ORname=io_set_item^ORname=sysauto_script^ORname=item_option_new</query>
10030 </module>
10031 <module>
10032 <title>Sara Transform History</title>
10033 <order>915</order>
10034 <active>true</active>
10035 <link_type>LIST</link_type>
10036 <table_name>sys_import_set_run</table_name>
10037 <query>sys_transform_mapSTARTSWITHx_ausgh_snsc</query>
10038 </module>
10039 <module>
10040 <title>Contact Us</title>
10041 <order>920</order>
10042 <active>true</active>
10043 <link_type>DIRECT</link_type>
10044 <query>https://automic.com/contact-us</query>
10045 </module>
10046 <module>
10047 <title>Support</title>
10048 <order>930</order>
10049 <active>true</active>
10050 <link_type>DIRECT</link_type>
10051 <query>https://automic.force.com/support</query>
10052 </module>
10053</modules>
10054
10055
10056 <rest_messages>
10057 <rest_message>
10058 <name>Sara - SAPI Services</name>
10059 <description>Sara Outbound Web Service for SAPI</description>
10060 <rest_endpoint>${sapiEndpoint}</rest_endpoint>
10061 <methods>
10062 <method>
10063 <function_name>GET</function_name>
10064 <http_method>GET</http_method>
10065 </method>
10066 <method>
10067 <function_name>POST</function_name>
10068 <http_method>POST</http_method>
10069 </method>
10070 <method>
10071 <function_name>PUT</function_name>
10072 <http_method>PUT</http_method>
10073 </method>
10074 <method>
10075 <function_name>DELETE</function_name>
10076 <http_method>DELETE</http_method>
10077 </method>
10078 </methods>
10079 </rest_message>
10080 <rest_message>
10081 <name>Sara - OAuth Services</name>
10082 <description>Sara Outbound Web Service for OAuth</description>
10083 <rest_endpoint>${oauthEndpoint}</rest_endpoint>
10084 <methods>
10085 <method>
10086 <function_name>GET</function_name>
10087 <http_method>GET</http_method>
10088 </method>
10089 <method>
10090 <function_name>POST</function_name>
10091 <http_method>POST</http_method>
10092 </method>
10093 <method>
10094 <function_name>PUT</function_name>
10095 <http_method>PUT</http_method>
10096 </method>
10097 <method>
10098 <function_name>DELETE</function_name>
10099 <http_method>DELETE</http_method>
10100 </method>
10101 </methods>
10102 </rest_message>
10103</rest_messages>
10104
10105 </package>
10106</sara>