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