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