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