daily pastebin goal
30%
SHARE
TWEET

Untitled

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