Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <sara xmlns="http://www.automic.com/sara/snsc">
- <references>
- <variable_types>
- <var_type value="1">Yes / No</var_type>
- <var_type value="2">Multi Line Text</var_type>
- <var_type value="3">Multiple Choice</var_type>
- <var_type value="4">Numeric Scale</var_type>
- <var_type value="18">Lookup Select Box</var_type>
- <var_type value="5">Select Box</var_type>
- <var_type value="6">Single Line Text</var_type>
- <var_type value="7">CheckBox</var_type>
- <var_type value="8">Reference</var_type>
- <var_type value="9">Date</var_type>
- <var_type value="10">Date/Time</var_type>
- <var_type value="11">Label</var_type>
- <var_type value="12">Break</var_type>
- <var_type value="14">Macro</var_type>
- <var_type value="15">UI Page</var_type>
- <var_type value="16">Wide Single Line Text</var_type>
- <var_type value="17">Macro with Label</var_type>
- <var_type value="21">List Collector</var_type>
- <var_type value="22">Lookup Multiple Choice</var_type>
- <var_type value="23">HTML</var_type>
- </variable_types>
- </references>
- <package name="snsc" version="1.0-SNAPSHOT">
- <description/>
- <system_properties>
- <category>
- <name>SARA</name>
- <title>This category consists of all SARA OAuth client settings</title>
- <properties>
- <property>
- <name>com.automic.sara.sapi_endpoint</name>
- <description/>
- <type>string</type>
- <value>http://vvnarasara01:8686/</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- <property>
- <name>com.automic.sara.client_secret</name>
- <description/>
- <type>password2</type>
- <value>AES_12345</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- <property>
- <name>com.automic.sara.client_id</name>
- <description/>
- <type>string</type>
- <value>SERVICE_NOW</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- <property>
- <name>com.automic.sara.auth_endpoint</name>
- <description/>
- <type>string</type>
- <value>http://172.16.36.40:8080/oauth-server</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- <property>
- <name>com.automic.sara.token_endpoint</name>
- <description/>
- <type>string</type>
- <value>http://vvnarasara01:8080/oauth-server/oauth2/token</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- <property>
- <name>com.automic.sara.mid_server</name>
- <description/>
- <type>string</type>
- <value>VVNARAWIN01</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- <property>
- <name>com.automic.sara.ref_scheme</name>
- <description/>
- <type>string</type>
- <value>relative</value>
- <ignore_cache>false</ignore_cache>
- <private>false</private>
- </property>
- </properties>
- </category>
- </system_properties>
- <tables>
- <table>
- <name>u_sara_oauth</name>
- <label>Sara OAuth</label>
- <extends_table/>
- <user_role>admin</user_role>
- <is_extendable>false</is_extendable>
- <dictionary_entries>
- <column>
- <name>u_access_token</name>
- <type>string</type>
- <label>Access Token</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_refresh_token</name>
- <type>string</type>
- <label>Refresh Token</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_token_expiry</name>
- <type>string</type>
- <label>Access Token</label>
- <max_length>40</max_length>
- </column>
- <column>
- <name>u_token_type</name>
- <type>string</type>
- <label>Token Type</label>
- <max_length>40</max_length>
- </column>
- <column>
- <name>u_user</name>
- <type>reference</type>
- <label>User</label>
- <max_length>32</max_length>
- <reference>sys_user</reference>
- </column>
- </dictionary_entries>
- </table>
- <table>
- <name>u_sara_variable</name>
- <label>Sara Variable</label>
- <extends_table>item_option_new</extends_table>
- <user_role>admin</user_role>
- <is_extendable>false</is_extendable>
- <dictionary_entries>
- <column>
- <name>u_name</name>
- <type>string</type>
- <label>Actual Name</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_url</name>
- <type>string</type>
- <label>URL</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_tooltip</name>
- <type>string</type>
- <label>Tooltip</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_readonly</name>
- <type>boolean</type>
- <label>Read only</label>
- <max_length>40</max_length>
- </column>
- <column>
- <name>u_is_password</name>
- <type>boolean</type>
- <label>Is password</label>
- <max_length>40</max_length>
- </column>
- </dictionary_entries>
- </table>
- <table>
- <name>u_sara_definition</name>
- <label>Sara Definition</label>
- <extends_table/>
- <user_role>admin</user_role>
- <is_extendable>false</is_extendable>
- <dictionary_entries>
- <column>
- <name>u_name</name>
- <type>string</type>
- <label>Name</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_links</name>
- <type>string</type>
- <label>Links</label>
- <max_length>2000</max_length>
- </column>
- <column>
- <name>u_consume_url</name>
- <type>string</type>
- <label>Consume URL</label>
- <max_length>1000</max_length>
- </column>
- <column>
- <name>u_sc_item</name>
- <type>reference</type>
- <label>Service Catalog Item</label>
- <max_length>32</max_length>
- <reference>sc_cat_item</reference>
- </column>
- <column>
- <name>u_sara_var_set</name>
- <type>reference</type>
- <label>Sara Variable Set</label>
- <max_length>32</max_length>
- <reference>item_option_new_set</reference>
- </column>
- <column>
- <name>u_parent</name>
- <type>reference</type>
- <label>Parent Category</label>
- <max_length>32</max_length>
- <reference>sc_category</reference>
- </column>
- <column>
- <name>u_type</name>
- <type>string</type>
- <label>Sara Type</label>
- <max_length>40</max_length>
- </column>
- </dictionary_entries>
- </table>
- </tables>
- <script_includes>
- <script_include>
- <name>SaraRestClient</name>
- <content><![CDATA[gs.include('SaraCommon');
- gs.include('SaraOAuthClient');
- var SaraRestClient = Class.create();
- SaraRestClient.prototype = {
- initialize: function() {
- this.basePath = SaraCommon.getBasePath();
- if (!this.basePath) { gs.log('No SAPI Endpoint was defined, the REST client may not act correctly!', 'SARA') }
- },
- newServiceRequest: function(name, method, endpoint) {
- // construct new service definition request
- var restMsg = new SaraRESTMessage(name, method);
- if (endpoint) restMsg.setRestEndPoint(endpoint);
- if (this.midServer) {
- restMsg.setMIDServer(this.midServer);
- }
- return restMsg;
- },
- newServiceRequest: function(name, method, endpoint, basicAuthCreds, headers) {
- // construct new service definition request
- var restMsg = new SaraRESTMessage(name, method);
- if (endpoint) restMsg.setRestEndPoint(endpoint);
- if (this.midServer) {
- restMsg.setMIDServer(this.midServer);
- }
- if (basicAuthCreds && basicAuthCreds.length > 1) {
- restMsg.setBasicAuth(basicAuthCreds[0], basicAuthCreds[1]);
- }
- if (headers) {
- for (index in headers) {
- var header = headers[index];
- if (header['name']) restMsg.addHeader(header['name'], header['value']);
- }
- }
- return restMsg;
- },
- newEntryRequest: function() {
- return this.newServiceRequest('Entry', 'get', this.basePath);
- },
- newSapiGetRequest: function(relPath) {
- return this.newServiceRequest('Sapi', 'get', this.basePath + relPath);
- },
- execute: function(saraRest) {
- if (this.midServer) return saraRest.executeViaMidServer();
- else return saraRest.execute();
- },
- executeRequest: function(saraRest){
- // var request = saraRest;
- // firstime request.
- var response = this.execute(saraRest);
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- // handle ERROR
- if (response && response.getStatusCode() == 401) {
- var resObj = new JSONParser().parse(response.getBody());
- var error = resObj['error'];
- var oauthClient = new SaraOAuthClient(this);
- if (error == 'expired_token') {
- // issue a refresh request
- var username = gs.getUserName();
- var tokens = oauthClient.refreshToken(username);
- if (tokens && !tokens.error) {
- oauthClient.storeUserTokens(username, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
- gs.log('Refresh token finished successfully.','SARA');
- // request again with new token
- // var request = this.newServiceRequest('SAPI','get',saraRest.getEndpoint());
- saraRest.addHeader('Authorization', 'Bearer '+tokens['access_token']);
- gs.log('Request = '+'','SARA');
- response = null;
- response = this.execute(saraRest);
- } else {
- gs.log('Refresh token finished unsuccessfully.');
- if (tokens != null) {
- gs.log('Error: ' + tokens.error);
- oauthClient.removeUserToken(username);
- }
- response = null;
- }
- } else {
- gs.log('You\'ve got invalid tokens, please try again or contact administrator to solve this problem');
- // invalidate token
- oauthClient.removeUserToken(username);
- response = null;
- }
- }
- }
- return response;
- },
- executeWithRefreshToken: function(saraRest){
- //var request = saraRest;
- // firstime request.
- var response = this.execute(saraRest);
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- // handle ERROR
- if (response && response.getStatusCode() == 401) {
- var resObj = new JSONParser().parse(response.getBody());
- var error = resObj['error'];
- var oauthClient = new SaraOAuthClient(this);
- var username = gs.getUserName();
- if (error == 'expired_token') {
- // issue a refresh request
- var tokens = oauthClient.refreshToken(username);
- if (tokens && !tokens.error) {
- oauthClient.storeUserTokens(username, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
- gs.log('Refresh token finished successfully.','SARA');
- // request again with new token
- var request = this.newServiceRequest('SAPI','get',saraRest.getEndpoint());
- request .addHeader('Authorization', 'bearer '+tokens['access_token']);
- response = this.execute(request );
- } else {
- gs.log('Refresh token finished unsuccessfully.');
- if (tokens != null) {
- gs.log('Error: ' + tokens.error);
- oauthClient.removeUserToken(username);
- }
- }
- } else {
- gs.log('You\'ve got invalid tokens, please try again or contact administrator to solve this problem');
- // invalidate token
- oauthClient.removeUserToken(username);
- }
- }
- }
- return response;
- },
- setBasePath: function(basePath) {
- this.basePath = basePath;
- },
- getBasePath: function() {
- return this.basePath;
- },
- setMIDServer: function(midServer) {
- this.midServer = midServer;
- },
- midServer: '',
- basePath: '',
- type: 'SaraRestClient'
- }
- var SaraRESTMessage = Class.create();
- SaraRESTMessage.prototype = Object.extendsObject(RESTMessage, {
- setContent: function(content) {
- this.content = content;
- },
- encodeUrl: function(value) {
- if (value) return Packages.java.net.URLEncoder.encode(value, 'utf-8');
- else return '';
- },
- setFormContent: function(entity) {
- if (!entity) return;
- var content = '';
- for (prop in entity) {
- var value = entity[prop];
- if (value instanceof Array) {
- for (idx in value) content += (this.encodeUrl(prop) + '=' + this.encodeUrl(value[idx]) + '&');
- } else {
- content += (this.encodeUrl(prop) + '=' + this.encodeUrl(value) + '&');
- }
- }
- if (content.length > 0) {
- content = content.substring(0, content.length - 1);
- this.setContent(content);
- }
- },
- addHeader: function(key, value) {
- if (!this.headers) this.headers = {};
- this.headers[key] = value;
- },
- setContentType: function(type) {
- this.addHeader('content-type', type);
- },
- setStringParameterWithoutEscaping: function (name, value) {
- this.props.put(name, value);
- },
- executeViaMidServer: function(midServer) {
- gs.log("Making " + this.funcName.toUpperCase() + " request to " + this.getEndpoint() + " ...", 'SARA');
- if (midServer) this.setMIDServer(midServer)
- if(!this.midServer) {
- gs.log('No MID Server defined for the request, abort now.', 'SARA');
- return null;
- }
- this.execute();
- var k = 1;
- var response = this.getResponse();
- gs.log('Waiting for result from ' + this.getEndpoint(), 'SARA');
- while (response == null) {
- //gs.log("Waiting ... " + k + " seconds", 'SARA');
- response = this.getResponse(1000);
- k++;
- if (k > 30) break;
- }
- if (response != null) {
- if (response.getStatusCode()) gs.log('Status code: ' + response.getStatusCode(), 'SARA');
- else {
- gs.log('No returned code from server, error message: ' + response.errorMessage, 'SARA');
- }
- } else gs.log('No response from server', 'SARA');
- return response;
- },
- _handleContent: function() {
- var content;
- if (this.content) content = this.content;
- else content = '' + this.functionGr.content;
- if (this._shouldSubstitute(content))
- content = this._substituteVariable(content, this.props);
- return content;
- },
- _handleHeaders: function() {
- var headers = {};
- var headersToReturn = [];
- // Grab all the headers from the main message body first, then the function and replace any duplicates with the one
- // from the function because it takes precedent by being more specific
- var hgr = new GlideRecord('sys_rest_message_headers');
- hgr.addQuery('rest_message', this.restMessageGR.sys_id);
- hgr.query();
- while (hgr.next())
- headers['' + hgr.name] = '' + hgr.value;
- hgr = new GlideRecord('sys_rest_message_fn_headers');
- hgr.addQuery('rest_message_function', '' + this.functionGr.sys_id);
- hgr.query();
- while (hgr.next())
- headers['' + hgr.name] = '' + hgr.value;
- if (this.headers) {
- for (var key in this.headers) {
- headers['' + key] = this.headers[key];
- }
- }
- for (var key in headers) {
- var value = headers[key];
- if (this._shouldSubstitute(value))
- value = this._substituteVariable(value, this.props);
- var header = {};
- header.name = key;
- header.value = value;
- headersToReturn.push(header);
- }
- //gs.log("HEADERS:");
- //for (index in headersToReturn) {
- // gs.log(headersToReturn[index].name + " = " + headersToReturn[index].value);
- // }
- return headersToReturn;
- },
- _getEccResponse: function() {
- var eccResponse = null;
- var ieccgr = new GlideRecord('ecc_queue');
- ieccgr.addQuery('response_to', this.outputq);
- ieccgr.query();
- if (ieccgr.next()) {
- eccResponse = new SaraRESTECCResponse(ieccgr);
- eccResponse.setEndpoint(this.endPoint);
- }
- return eccResponse;
- },
- execute : function () {
- var httpResponse = null;
- var response = 'error';
- this.httpStatus = null;
- if (this.restMessageGR.sys_id) {
- this.functionGr = new GlideRecord('sys_rest_message_fn');
- this.functionGr.addQuery('rest_message', this.restMessageGR.sys_id);
- this.functionGr.addQuery('function_name', this.funcName);
- this.functionGr.query();
- } else this.functionGr = {};
- if ((this.restMessageGR.sys_id && this.functionGr.next()) || !this.restMessageGR.sys_id) {
- this._handleEndpoint();
- var headers = this._handleHeaders();
- var params = this._handleParameters();
- if (this.functionGr.use_mid_server && !this.functionGr.use_mid_server.nil()) {
- this.use_ecc = true;
- if (!this.midServer)
- this.midServer = this.functionGr.use_mid_server.name;
- }
- var creds = this._handleBasicAuth();
- if (this.use_ecc) {
- // Build ECC queue payload
- var payload = new GlideXMLDocument('parameters');
- this._addParameterToPayload(payload, 'message_headers', this._getMessageFields(headers));
- this._addParameterToPayload(payload, 'message_parameters', this._getMessageFields(params));
- for (var name in this.eccParameters)
- this._addParameterToPayload(payload, name, this.eccParameters[name]);
- if (this.useBasicAuth) {
- if (creds) {
- var encrypter = new GlideEncrypter();
- this._addParameterToPayload(payload, 'rest_user', creds.user);
- this._addParameterToPayload(payload, 'rest_password', 'enc:' + encrypter.reencryptForAutomation(creds.password));
- }
- }
- // if the function takes content
- if (this.funcName == 'post' || this.funcName == 'put')
- this._addParameterToPayload(payload, 'content', this._handleContent());
- this._createECCQueueEntry(payload.toString());
- } else {
- var httpRequest = new GlideHTTPRequest(this.endPoint);
- if (this.useBasicAuth) {
- if (creds) {
- var Encrypter = new GlideEncrypter();
- var userpassword = Encrypter.decrypt(creds.password);
- httpRequest.setBasicAuth(creds.user, userpassword);
- }
- }
- // Pass the headers through
- for (var h = 0; h < headers.length; h++)
- httpRequest.addHeader(headers[h].name, headers[h].value);
- // Pass the parameters through
- for (var i = 0; i < params.length; i++)
- httpRequest.addParameter(params[i].name, params[i].value);
- if (this.funcName == 'get')
- httpResponse = this._handleGetRequest(httpRequest);
- else if (this.funcName == 'post')
- httpResponse = this._handlePostRequest(httpRequest, this._handleContent());
- else if (this.funcName == 'put')
- httpResponse = this._handlePutRequest(httpRequest, this._handleContent());
- else if (this.funcName == 'delete')
- httpResponse = this._handleDeleteRequest(httpRequest);
- }
- }
- return httpResponse;
- },
- type: 'SaraRESTMessage'
- });
- var SaraRESTECCResponse = Class.create();
- SaraRESTECCResponse.prototype = Object.extendsObject(RESTECCResponse, {
- _processEccQueueInput: function(input) {
- var xml = new XMLHelper();
- var record = xml.toObject('' + input.payload);
- this.params = record.parameters.parameter;
- this.statusCode = this._getParameter('http_status_code');
- this.content = this._getParameter('content');
- /*
- this.hasError = false;
- this.errorCode = 0;
- this.errorMessage = '';
- */
- var error = record['@error'];
- if (error) {
- this.hasError = true;
- this.errorMessage = error;
- }
- if (record.result) {
- var error = record.result['@error'];
- if (error) {
- this.hasError = true;
- this.errorMessage = error;
- }
- error = record.result.error;
- if (error){
- this.hasError = true;
- this.errorMessage = error;
- }
- this.body = record.result.output;
- }
- },
- type: 'SaraRESTECCResponse'
- });
- SaraRESTECCResponse.prototype.toString = Object.prototype.toString;
- ]]></content>
- <description>Wraps and extends Service Now RESTMessage in a class to provide convenient methods interacting with SARA REST</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SaraOAuthClient</name>
- <content><![CDATA[gs.include('SaraCommon');
- var SaraOAuthClient = Class.create();
- SaraOAuthClient.prototype = {
- initialize: function(restClient) {
- if (!restClient) {
- this.restClient = new SaraRestClient();
- this.restClient.setMIDServer(SaraCommon.getMidServer());
- } else this.restClient = restClient;
- },
- /**
- * Store SARA OAuth client settings to System Properties
- */
- storeClientSettings: function(clientId, clientSecret, sapiEndpoint, tokenEndpoint, authEndpoint) {
- // check for SARA category
- var catId = null;
- var catRec = new GlideRecord('sys_properties_category');
- catRec.addQuery('name', 'SARA');
- catRec.query();
- if (catRec.next()) catId = catRec.sys_id;
- else {
- catRec = new GlideRecord('sys_properties_category');
- catRec.initialize();
- catRec.name = 'SARA';
- catRec.title = 'This category consists of all SARA OAuth client settings';
- catId = catRec.insert();
- }
- // save properties to 'sys_properties' table
- var props = ['client_id', 'client_secret', 'sapi_endpoint', 'token_endpoint', 'auth_endpoint'];
- var values = [clientId, clientSecret, sapiEndpoint, tokenEndpoint, authEndpoint];
- var propRec = null;
- var order = 50;
- for (index = 0; index < props.length; index++) {
- var propId = null;
- propRec = new GlideRecord('sys_properties');
- var propName = SaraCommon.PROP_PREFIX + '.' + props[index];
- propRec.addQuery('name', propName);
- propRec.query();
- if (propRec.next()) {
- propRec.value = values[index];
- propId = propRec.update();
- } else {
- propRec = new GlideRecord('sys_properties');
- propRec.initialize();
- propRec.name = propName;
- propRec.value = values[index];
- propId = propRec.insert();
- }
- // ensure relationship between properties and 'SARA' category
- var catPropRec = new GlideRecord('sys_properties_category_m2m');
- catPropRec.addQuery('property', propId);
- catPropRec.addQuery('category', catId);
- catPropRec.query();
- if (!catPropRec.next()) {
- catPropRec = new GlideRecord('sys_properties_category_m2m');
- catPropRec.initialize();
- catPropRec.property = propId;
- catPropRec.category = catId;
- catPropRec.order = order;
- catPropRec.insert();
- order += 10;
- }
- }
- },
- /**
- * Gets the array of SARA client settings in following order: Client Id, Client Secret, SAPI Endpoint,
- * Token Endpoint, Authorization Endpoint
- */
- getClientSettings: function() {
- return [SaraCommon.getSaraProperty('client_id'), SaraCommon.getSaraProperty('client_secret'), SaraCommon.getSaraProperty('sapi_endpoint'),
- SaraCommon.getSaraProperty('token_endpoint'), SaraCommon.getSaraProperty('auth_endpoint')]
- },
- getSaraProperty: function(name) {
- return gs.getProperty(SaraCommon.PROP_PREFIX + '.' + name);
- },
- type: 'SaraOAuthClient'
- }
- SaraOAuthClient.prototype.storeUserTokens = function(username, accessToken, refreshToken, tokenExpiry, tokenType) {
- if (!username) {
- gs.log('Store user token: Username must not be empty', 'SARA');
- return;
- }
- if (!accessToken) {
- gs.log('Error: Access token must be non-empty', 'SARA');
- return;
- }
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', username);
- rec.query();
- if (rec.next()) {
- rec.u_access_token = accessToken;
- rec.u_refresh_token = refreshToken;
- rec.u_token_expiry = tokenExpiry;
- rec.u_token_type = tokenType;
- return rec.update();
- } else {
- rec = new GlideRecord('u_sara_oauth');
- rec.initialize();
- var uRec = new GlideRecord('sys_user');
- uRec.addQuery('user_name', username);
- uRec.query();
- if (uRec.next()) rec.u_user = uRec.sys_id;
- else {
- gs.log('User \'' + username + '\' does not exist, skipped.', 'SARA');
- return;
- }
- rec.u_access_token = accessToken;
- rec.u_refresh_token = refreshToken;
- rec.u_token_expiry = tokenExpiry;
- rec.u_token_type = tokenType;
- return rec.insert();
- }
- }
- SaraOAuthClient.prototype.getUserTokens = function(username) {
- if (!username) return null;
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', username);
- rec.query();
- if (rec.next()) {
- return [rec.u_access_token, rec.u_refresh_token, rec.u_token_expiry, rec.u_token_type,
- { 'createdAt': rec.sys_created_on, 'createdBy': rec.sys_created_by, 'updatedAt': rec.sys_updated_on, 'updatedBy': rec.sys_updated_by }];
- } else return null;
- }
- SaraOAuthClient.prototype.removeUserToken = function(username) {
- if (!username) return null;
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', username);
- rec.query();
- if (rec.next()) {
- return rec.deleteRecord();
- } else {
- gs.log('No token found for user \'' + username, 'SARA');
- return null;
- }
- }
- /**
- * Requests user tokens, the request must use client_id/client_secret to authenticate (BASICally) against SARA server,
- * LDAP username/password and grant_type will be embedded in request's body
- * @return array of access token, refresh token and token expiry
- */
- SaraOAuthClient.prototype.requestToken = function(username, password) {
- var clientInfo = this.getClientSettings();
- var tokenEndpoint = clientInfo[3];
- var request = this.restClient.newServiceRequest('Request Token', 'post', tokenEndpoint);
- request.setBasicAuth(clientInfo[0], clientInfo[1]);
- // add POST body, set Content-Type header
- request.setContentType('application/x-www-form-urlencoded');
- var formEntity = {'grant_type' : 'password', 'username' : username, 'password': password};
- //request.setContent('grant_type=password&username=' + username + '&password=' + password);
- request.setFormContent(formEntity);
- gs.log('Requesting tokens for SARA user ' + username + ' ...', 'SARA');
- var response = this.restClient.execute(request);
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- gs.log('Failed to request token for user ' + username, 'SARA');
- if (response && response.getStatusCode()) {
- gs.log("Status code: " + response.getStatusCode() + ", error message: " + response.getBody(), 'SARA');
- var resObj = new JSONParser().parse(response.getBody());
- if (!resObj.error) resObj = {'error': 'unknown_error', 'error_description': 'Status code: ' + response.getStatusCode()};
- return {'error': resObj.error, 'error_description': resObj.error_description};
- } else {
- gs.log('No response from server', 'SARA');
- if (response && response.errorMessage) return {'error': 'no_response', 'error_description': response.errorMessage};
- else return null;
- }
- }
- gs.log('Successfully obtain token for user ' + username, 'SARA');
- return (new JSONParser()).parse(response.getBody());
- }
- SaraOAuthClient.prototype.refreshToken = function(username) {
- // get refresh token for this user from 'sara_oauth' table
- var tokens = this.getUserTokens(username);
- if (!tokens || tokens.length < 1) {
- gs.log('Tokens not found for user ' + username, 'SARA');
- return null;
- }
- // use that refesh token to retrieve new tokens
- var clientInfo = this.getClientSettings();
- var tokenEndpoint = clientInfo[3];
- var request = this.restClient.newServiceRequest('Refresh Token', 'post', tokenEndpoint);
- request.setBasicAuth(clientInfo[0], clientInfo[1]);
- // add POST body, set Content-Type header
- //request.addHeader('content-type', 'application/x-www-form-urlencoded');
- request.setContentType('application/x-www-form-urlencoded');
- //request.setContent('grant_type=refresh_token&refresh_token=' + tokens[1]);
- request.setFormContent({'grant_type': 'refresh_token', 'refresh_token': tokens[1]});
- gs.log('Refreshing tokens for user ' + username + ' ...', 'SARA');
- var response = this.restClient.execute(request);
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- gs.log('Failed to refresh token for user ' + username, 'SARA');
- if (response && response.getStatusCode()) {
- gs.log("Status code: " + response.getStatusCode() + ", error message: " + response.getBody(), 'SARA');
- var resObj = new JSONParser().parse(response.getBody());
- if (!resObj.error) resObj = {'error': 'unknown_error', 'error_description': 'Status code: ' + response.getStatusCode()};
- return {'error': resObj.error, 'error_description': resObj.error_description};
- } else {
- gs.log('No response from server', 'SARA');
- if (response && response.errorMessage) return {'error': 'no_response', 'error_description': response.errorMessage};
- else return null;
- }
- }
- gs.log('Successfully refresh token for user ' + username, 'SARA');
- return (new JSONParser()).parse(response.getBody());
- }
- ]]></content>
- <description>This class contains all OAuth-relaled functions</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SaraCommon</name>
- <content><![CDATA[var SaraCommon = Class.create();
- SaraCommon.prototype = {
- initialize: function() {
- },
- type: 'SaraCommon'
- }
- SaraCommon.PROP_PREFIX = 'com.automic.sara';
- SaraCommon.OAUTH_IMPORT_SUCCESS = 0;
- SaraCommon.OAUTH_AUTHENTICATION_FAILED = 1;
- SaraCommon.OAUTH_INVALID_TOKEN = 2;
- SaraCommon.OAUTH_TOKEN_EXPIRED = 3;
- SaraCommon.VAR_TYPE = {};
- SaraCommon.VAR_TYPE.YES_NO = 1;
- SaraCommon.VAR_TYPE.MULTI_LINE_TEXT = 2;
- SaraCommon.VAR_TYPE.MULTI_CHOICE = 3;
- SaraCommon.VAR_TYPE.NUM_SCALE = 4;
- SaraCommon.VAR_TYPE.LOOKUP_SELECT_BOX = 18;
- SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT = 6;
- SaraCommon.VAR_TYPE.CHECK_BOX = 7;
- SaraCommon.VAR_TYPE.REFERENCE = 8;
- SaraCommon.VAR_TYPE.DATE = 9;
- SaraCommon.VAR_TYPE.DATE_TIME = 10;
- SaraCommon.VAR_TYPE.LABEL = 11;
- SaraCommon.VAR_TYPE.BREAK = 12;
- SaraCommon.VAR_TYPE.MACRO = 14;
- SaraCommon.VAR_TYPE.UI_PAGE = 15;
- SaraCommon.VAR_TYPE.WIDE_SINGLE_LINE_TEXT = 16;
- SaraCommon.VAR_TYPE.MACRO_WITH_LABEL = 17;
- SaraCommon.VAR_TYPE.CONTAINER_START = 19;
- SaraCommon.VAR_TYPE.CONTAINER_END = 20;
- SaraCommon.VAR_TYPE.LIST_COLLECTOR = 21;
- SaraCommon.VAR_TYPE.LOOKUP_MULTI_CHOICE = 22;
- SaraCommon.VAR_TYPE.HTML = 23;
- SaraCommon.getSaraProperty = function(name) {
- return gs.getProperty(SaraCommon.PROP_PREFIX + '.' + name);
- };
- SaraCommon.getBasePath = function() {
- return SaraCommon.getSaraProperty('sapi_endpoint');
- };
- SaraCommon.getMidServer = function() {
- return SaraCommon.getSaraProperty('mid_server');
- };
- SaraCommon.getRefScheme = function() {
- var scheme = SaraCommon.getSaraProperty('ref_scheme');
- return scheme?scheme:'relative';
- }
- ]]></content>
- <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>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SaraCommonAjax</name>
- <content><![CDATA[var SaraCommonAjax = Class.create();
- SaraCommonAjax.prototype = Object.extendsObject(AbstractAjaxProcessor,{
- getSysProperty: function() {
- var propName = this.getParameter('sysparm_property_name');
- return gs.getProperty(propName);
- },
- type : "SaraCommonAjax"
- });
- ]]></content>
- <description>Get Sara common property on server side. This will be called from client side by using GlideAjax</description>
- <active>true</active>
- <client_callable>true</client_callable>
- </script_include>
- <script_include>
- <name>SaraModel</name>
- <content><![CDATA[var SaraModel = Class.create();
- SaraModel.prototype = {
- initialize: function() {
- },
- type: 'SaraModel'
- }
- /**
- * CatalogItem object represents a SN service catalog item
- * @constructor
- */
- function CatalogItem(name, category, active, workflow, shortDesc, description, variables, additionalFields) {
- this.name = name;
- this.category = category;
- this.active = active;
- this.workflow = workflow;
- this.shortDescription = shortDesc;
- this.description = description;
- this.variables = variables;
- this.additionalFields = additionalFields;
- }
- CatalogItem.prototype.setVariables = function(variables) {
- this.variables = variables;
- }
- CatalogItem.prototype.getCategory = function() {
- return this.category;
- }
- CatalogItem.prototype.getName = function() {
- return this.name;
- }
- CatalogItem.prototype.setConsumeUrl = function(consumeUrl) {
- this.consumeUrl = consumeUrl;
- }
- CatalogItem.prototype.getConsumeUrl = function() {
- return this.consumeUrl;
- }
- CatalogItem.prototype.setLinks = function(links) {
- this.links = links;
- }
- CatalogItem.prototype.getLinks = function() {
- return this.links;
- }
- CatalogItem.prototype.setServiceName = function(serviceName) {
- this.serviceName = serviceName;
- }
- CatalogItem.prototype.getServiceName = function() {
- return this.serviceName;
- }
- CatalogItem.prototype.setCustomCart = function(customCart) {
- this.customCart = customCart;
- }
- /**
- * Checks if a given link name contained in catalog item definition
- * @return true if catalog item contains given link name
- */
- CatalogItem.prototype.containLink = function(link) {
- return this.links[link]?true:false;
- }
- /**
- * Gets link object for given name
- */
- CatalogItem.prototype.getLink = function(link) {
- return this.links[link];
- }
- function CatalogVariable(name, type, label, defaultValue, description, range) {
- this.name = name;
- this.type = type;
- this.label = label;
- this.defaultValue = defaultValue;
- this.description = description;
- this.range = range;
- }
- CatalogVariable.prototype.setRange = function(range) {
- this.range = range;
- }
- CatalogVariable.prototype.setActualName = function(actualName) {
- this.actualName = actualName;
- }
- CatalogVariable.prototype.setUrl = function(url) {
- this.url = url;
- }
- CatalogVariable.prototype.isPassword = function(isPassword) {
- this.isPassword = isPassword;
- }
- CatalogVariable.prototype.isRequired = function(required) {
- this.required = required;
- }
- /**
- * CatalogCategory object represents a SN service catalog category
- * @constructor
- */
- function CatalogCategory(title, name, parent,active, description){
- this.title = title;
- this.name = name;
- this.parent = parent;
- this.active = active;
- this.description = description;
- }
- CatalogCategory.prototype.setName = function(name){
- this.name = name;
- }
- CatalogCategory.prototype.getName = function() {
- return this.name;
- }
- CatalogCategory.prototype.setConsumeUrl = function(consumeUrl) {
- this.consumeUrl = consumeUrl;
- }
- CatalogCategory.prototype.getConsumeUrl = function() {
- return this.consumeUrl;
- }
- ]]></content>
- <description>SARA concepts modelling in Service Now</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SaraCatalogGenerator</name>
- <content><![CDATA[gs.include('SaraUtils');
- var SaraCatalogGenerator = Class.create();
- SaraCatalogGenerator.prototype = {
- initialize: function() {
- this.glideHelper = new SaraGlideHelper();
- },
- save: function(itemObj) {
- // creates new service catalog item
- var rec = new GlideRecord('sc_cat_item');
- rec.initialize();
- rec.name = itemObj.name;
- if (itemObj.category) {
- rec.category = itemObj.category;
- }
- rec.active = itemObj.active;
- if (itemObj.workflow) {
- var workflowRec = new GlideRecord('wf_workflow');
- workflowRec.addQuery('name', itemObj.workflow);
- workflowRec.query();
- if (workflowRec.next()) rec.workflow = workflowRec.sys_id;
- }
- if (itemObj.customCart) {
- var cartRec = new GlideRecord('sys_ui_macro');
- cartRec.addQuery('name', itemObj.customCart);
- cartRec.query();
- if (cartRec.next()) rec.custom_cart = cartRec.sys_id;
- }
- rec.short_description = itemObj.shortDescription;
- rec.description = itemObj.description;
- // TODO: process additional fields
- var catId = rec.insertWithReferences();
- var varSetId = null;
- // process catalog variables
- if (itemObj.variables.length > 0) {
- // create a variable set containing all variables
- var varSetRec = new GlideRecord('item_option_new_set');
- varSetRec.initialize();
- varSetRec.name = itemObj.name + '_VarSet';
- varSetRec.description = 'Variable Set containing all variables belong to \'' + itemObj.name + '\' catalog item';
- varSetRec.title = itemObj.name + ' Variable Set';
- varSetRec.display_title = true;
- // save variable set to 'item_option_new_set' table
- var varSetId = varSetRec.insert();
- // create relation between variable set and catalog item by adding a record to 'io_set_item' table
- var varSetItemRec = new GlideRecord('io_set_item');
- varSetItemRec.initialize();
- varSetItemRec.sc_cat_item = catId;
- varSetItemRec.variable_set = varSetId;
- varSetItemRec.insertWithReferences();
- // process each variable in the set
- var order = 50;
- for (i in itemObj.variables) {
- this.saveVariable(itemObj.variables[i], null, varSetId, { 'order': order });
- order += 10;
- }
- }
- // add new row to 'u_sara_definition' table, holding additional info. about this services like consume URL, links
- // and reference to the variable set that contains Sara fields
- rec = new GlideRecord('u_sara_definition');
- rec.initialize();
- rec.u_sc_item = catId;
- gs.log('SAVING SERVICE \'' + itemObj.getServiceName() + '\' ...', 'SARA');
- rec.u_name = itemObj.getServiceName();
- if (itemObj.consumeUrl) rec.u_consume_url = itemObj.consumeUrl;
- if (itemObj.links) rec.u_links = itemObj.links;
- if (varSetId) rec.u_sara_var_set = varSetId;
- rec.u_parent = itemObj.category;
- rec.u_type = 'service';
- rec.insert();
- },
- /**
- *
- */
- saveVariable: function(variableObj, catalogItemId, variableSetId, optionals) {
- var varRec = new GlideRecord('u_sara_variable');
- varRec.initialize();
- varRec.name = variableObj.name;
- varRec.type = variableObj.type;
- if (catalogItemId) varRec.cat_item = catalogItemId;
- else if (variableSetId) varRec.variable_set = variableSetId;
- if (variableObj.description){
- varRec.help_text = variableObj.description;
- varRec.show_help = true;
- }
- varRec.default_value = variableObj.defaultValue;
- varRec.question_text = variableObj.label;
- varRec.mandatory = variableObj.required;
- if (optionals) {
- for (prop in optionals) varRec[prop] = optionals[prop];
- }
- // additional fields for Sara
- varRec.u_name = variableObj.actualName;
- varRec.u_url = variableObj.url;
- varRec.u_is_password = variableObj.isPassword;
- if (variableObj.range) {
- // process variable range
- // create a new table contain variable range
- var tblName = 'u_sara_' + SaraUtils.randomNum() + '_' + variableObj.name.toLowerCase();
- if (tblName.length > 30) tblName = tblName.substring(0, 30);
- var lookupTableRec = new GlideRecord('sys_db_object');
- if (!lookupTableRec.get('name', tblName)) {
- lookupTableRec.initialize();
- lookupTableRec.name = tblName;
- var tblId = lookupTableRec.insert();
- gs.print('Create table name \'' + tblName + '\' finished successfully.');
- gs.print('Creating schema for table \'' + tblName + '\'..');
- // create schema for table by inserting to table 'sys_dictionary'
- var columns = ['u_key', 'u_display_name', 'u_description', 'u_icon'];
- var columnLabels = ['Key', 'Display Name', 'Description', 'Icon'];
- for (index in columns) {
- var col = columns[index];
- var dictRec = new GlideRecord('sys_dictionary');
- dictRec.initialize();
- dictRec.element = col;
- dictRec.type = 'string';
- dictRec.name = tblName;
- dictRec.column_label = columnLabels[index];
- dictRec.insert();
- }
- gs.print('Create schema for table \'' + tblName + '\' finished successfully.','SARA');
- gs.print('Inserting values to table \'' + tblName + '\'..','SARA');
- // insert values to lookup table
- for (index in variableObj.range) {
- var varValue = variableObj.range[index];
- var lookupRowRec = new GlideRecord(tblName);
- lookupRowRec.initialize();
- ////lookupRowRec.u_key = varValue.key;
- gs.print('Insert key: ' + varValue.Key ,'SARA');
- lookupRowRec.u_key = varValue.Value;
- lookupRowRec.u_display_name = varValue.Key;
- //lookupRowRec.u_display_name = varValue.displayName;
- //lookupRowRec.u_description = varValue.description;
- //lookupRowRec.u_icon = varValue.icon;
- lookupRowRec.insert();
- }
- gs.print('Insert value to table \'' + tblName + '\' finished successfully.');
- varRec.lookup_table = tblName;
- varRec.lookup_value = 'u_display_name';
- }
- gs.print('Updating variable..','SARA');
- // update variable
- ////varRec = new GlideRecord('u_sara_variable');
- // varRec.addQuery('sys_id', varId);
- // varRec.query();
- //while(varRec.next()) {
- // varRec.type = 18; // Lookup Select Box
- // varRec.lookup_table = tblName;
- // varRec.lookup_value = 'u_display_name';
- // varRec.update();
- // gs.print('Done!');
- // }
- }
- // save variable to 'u_sara_variable' table
- varRec.insertWithReferences();
- },
- /**
- * Create catalog category
- * @return Category ID from tbale sc_category
- */
- saveCategory: function(categoryEntity) {
- var categoryRec = new GlideRecord('sc_category');
- categoryRec.initialize();
- categoryRec.title = categoryEntity.title;
- if (categoryEntity.parent){
- // Parent is reference type, need to query sys_id from the given parent_name
- var parentRec = new GlideRecord('sc_category');
- parentRec.addQuery('title',categoryEntity.parent);
- parentRec.query();
- if (parentRec.next()) categoryRec.parent = parentRec.sys_id;
- }else{
- // TODO: default root category is : 'Automic Integration Demo'
- // if root category is not provided, then use the default.
- var parentRec = new GlideRecord('sc_category');
- var targetCategoryId;
- parentRec.addQuery('title','Automic Integration Demo');
- parentRec.query();
- if (parentRec.next()) targetCategoryId = parentRec.sys_id;
- if (typeof wizard != 'undefined' && wizard && wizard.sara_target_category){
- gs.log("Importing SAPI catalogs into category "+wizard.sara_target_category+" ...");
- targetCategoryId = wizard.sara_target_category;
- }
- categoryRec.parent = targetCategoryId;
- }
- // Assign default homepage renderer
- var rendererRec = new GlideRecord('sc_homepage_renderer');
- rendererRec.addQuery('Name', 'Default');
- if (rendererRec.next()) categoryRec.homepage_renderer = rendererRec.sys_id;
- // Active this category
- categoryRec.active = categoryEntity.active;
- // Add description
- categoryRec.description = categoryEntity.description;
- var catId = categoryRec.insertWithReferences();
- gs.log("Created Catalog category "+categoryRec.title+" with sys_id = "+catId);
- // add new row to 'u_sara_definition' table, holding additional info. about this category
- var rec = new GlideRecord('u_sara_definition');
- rec.initialize();
- rec.u_service_catalog_category = catId;
- rec.u_name = categoryEntity.name;
- if (categoryRec.getConsumeUrl()) rec.u_consume_url = categoryRec.getConsumeUrl();
- rec.u_parent = categoryRec.parent;
- rec.u_type = 'catalog';
- rec.insert();
- return catId;
- },
- /**
- *
- */
- updateItem: function(item) {
- if (!item.sysId) return null;
- gs.log('Updating item , name = ' + item.name + ', short description = ' + item.shortDescription, 'SARA');
- // update item info
- this.glideHelper.updateData('sc_cat_item', {'sys_id': item.sysId}, {
- 'name': item.name,
- 'short_description': item.shortDescription,
- 'description': item.description,
- });
- // update corresponding record in 'u_sara_definition' table
- var saraDef = this.glideHelper.getData('u_sara_definition', {'u_sc_item': item.sysId}, ['sys_id', 'u_sara_var_set']);
- if (saraDef && saraDef.length > 0) {
- saraDef = saraDef[0];
- var varSetId = saraDef['u_sara_var_set'];
- // process catalog variables
- if (item.variables.length > 0) {
- // delete all existing variables in current set
- this.glideHelper.deleteData('u_sara_variable', {'variable_set': varSetId}, true);
- // process new variables in the set
- var order = 50;
- for (i in item.variables) {
- this.saveVariable(item.variables[i], null, varSetId, {
- 'order' : order
- });
- order += 10;
- }
- }
- this.glideHelper.updateData('u_sara_definition', {'u_sc_item': saraDef['sys_id']}, {'u_consume_url': item.getConsumeUrl(), 'u_sara_var_set': varSetId});
- }
- // update item variables/variable set
- // delete old variable set and all related variableSetId
- // create new variables, variable set and wire with item
- },
- /**
- *
- */
- updateCategory: function(category) {
- if (!category.sysId) return null;
- gs.log('Updating category, title = ' + category.title + ', description = ' + category.description, 'SARA');
- return this.glideHelper.updateData('sc_category', {'sys_id': category.sysId}, {
- 'title': category.title,
- 'description': category.description
- });
- },
- type: 'SaraCatalogGenerator'
- };
- ]]></content>
- <description>Service Catalog Generator to import service definition to Service Catalog</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SaraOAuthAjax</name>
- <content><![CDATA[var SaraOAuthAjax = Class.create();
- SaraOAuthAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
- requestToken: function() {
- var username = this.getParameter('sysparm_username');
- var password = this.getParameter('sysparm_password');
- var oauthClient = new SaraOAuthClient();
- var tokens = oauthClient.requestToken(username, password);
- if (tokens && !tokens.error && tokens['access_token']) {
- oauthClient.storeUserTokens(gs.getUserName(), tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
- return 'ok';
- } else return tokens.error ? tokens.error : (!tokens['access_token']?'Empty result':'');
- },
- helloWorld: function() {
- gs.sleep(5000);
- return "Hello " + this.getParameter('sysparm_username') + "!";
- },
- });
- ]]></content>
- <description>AJAX facade for SaraOAuthClient</description>
- <active>true</active>
- <client_callable>true</client_callable>
- </script_include>
- <script_include>
- <name>SaraUtils</name>
- <content><![CDATA[gs.include('SaraModel');
- gs.include('SaraCommon');
- var SaraUtils = Class.create();
- SaraUtils.prototype = {
- initialize: function() {
-      }, 
- type: 'SaraUtils'
- }
- SaraUtils.randomNum = function() {
- return new Date().valueOf();
- }
- SaraUtils.cleanup = function() {
- // get list of catalog item from 'u_sara_definiton' table
- var rec = new GlideRecord('u_sara_definition');
- rec.query();
- var catItemIds = [];
- var varSetIds = [];
- var catCateIds = [];
- while (rec.next()) {
- if (rec.u_sc_item) catItemIds.push(rec.u_sc_item.sys_id);
- if (rec.u_sara_var_set) varSetIds.push(rec.u_sara_var_set.sys_id);
- if (rec.u_service_catalog_category) catCateIds.push(rec.u_service_catalog_category.sys_id);
- }
- var index;
- // remove all variables belong to above variable sets
- for (index = 0; index < varSetIds.length; index++) {
- //
- gs.log('Removing variables from variable set ' + varSetIds[index] + ' ...','SARA');
- rec = new GlideRecord('item_option_new');
- rec.addQuery('variable_set', varSetIds[index]);
- rec.deleteMultiple();
- }
- // if a variable has lookup table, remove the table (skip now)
- // remove all variable sets
- if (varSetIds.length > 0) {
- gs.log('Removing ' + varSetIds.length + ' variable sets ...','SARA');
- for (index = 0; index < varSetIds.length; index++) {
- rec = new GlideRecord('item_option_new_set');
- rec.addQuery('sys_id', varSetIds[index]);
- rec.query();
- if (rec.next()) rec.deleteRecord();
- }
- rec.deleteMultiple();
- }
- // cleanup service catalog items
- if (catItemIds.length > 0) {
- gs.log('Removing ' + catItemIds.length + ' catalog items ...','SARA');
- for (index = 0; index < catItemIds.length; index++) {
- rec = new GlideRecord('sc_cat_item');
- rec.addQuery('sys_id', catItemIds[index]);
- rec.query();
- if (rec.next()) rec.deleteRecord();
- }
- }
- // cleanup catalog categories
- if (catCateIds.length > 0) {
- gs.log('Removing ' + catCateIds.length + ' catalog categories ...','SARA');
- for (index = 0; index < catCateIds.length; index++) {
- rec = new GlideRecord('sc_category');
- rec.addQuery('sys_id', catCateIds[index]);
- rec.query();
- if (rec.next()) rec.deleteRecord();
- }
- }
- gs.log('Cleaning up u_sara_definition table ...','SARA');
- rec = new GlideRecord('u_sara_definition');
- rec.deleteMultiple();
- gs.log('Cleaning up u_sara_variable table ...','SARA');
- rec = new GlideRecord('u_sara_variable');
- rec.deleteMultiple();
- }
- SaraUtils.dropSaraRangeTables = function() {
- // query all table entries from 'sys_db_object' that begins with 'u_sara_'
- var rec = new GlideRecord('sys_db_object');
- rec.addQuery('name', 'STARTSWITH', 'u_sara_');
- rec.addQuery('name', 'NOT IN', 'u_sara_variable,u_sara_oauth,u_sara_definition');
- rec.query();
- var count = 1;
- var tables = [];
- while (rec.next()) {
- var index;
- // for each table, retrieve all related entries from 'sys_dictionary' and 'sys_documentation' to delete
- var sys_id = rec.sys_id;
- var tblName = rec.name;
- gs.log(count++ + ': table = ' + tblName)
- // query 'sys_dictionary'
- var rec1 = new GlideRecord('sys_dictionary');
- rec1.addQuery('name', tblName);
- rec1.query();
- //rec.deleteMultiple();
- //rec.query();
- while (rec1.next()) {
- gs.log(' - ' + rec1.column_label + ' ' + rec1.element);
- rec1.deleteRecord();
- }
- var rec2 = new GlideRecord('sys_documentation');
- rec2.addQuery('name', tblName);
- rec2.query();
- //rec.deleteMultiple();
- while(rec2.next()) {
- gs.log(' + ' + rec2.element);
- rec2.deleteRecord();
- }
- rec.deleteRecord();
- }
- }
- SaraUtils.createCatalogVariable = function(str) {
- var field =str;
- var variable;
- var defaultValue = '';
- if ( field.detault.length > 0 ) {
- defaultValue = field.detault;
- }
- switch (field.type) {
- case 'Label':
- gs.log("Create Label Field: "+this.legitVarName(field.name),'SARA');
- var varType = SaraCommon.VAR_TYPE.LABEL;
- break;
- case 'Number':
- gs.log("Create Number Field: "+this.legitVarName(field.name),'SARA');
- // SN only have NUM_SCALE variable type but not suitable, just use string
- var varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
- break;
- case 'String':
- gs.log("Create String Field: "+this.legitVarName(field.name),'SARA');
- var varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
- break;
- case 'List':
- gs.log("Create List Field: "+this.legitVarName(field.name),'SARA');
- var varType = SaraCommon.VAR_TYPE.LOOKUP_SELECT_BOX;
- break;
- case 'Time':
- gs.log("Create Time Field: "+this.legitVarName(field.name),'SARA');
- var varType = SaraCommon.VAR_TYPE.SINGLE_LINE_TEXT;
- break;
- case 'Date':
- gs.log("Create Date Field: "+this.legitVarName(field.name),'SARA');
- var varType = SaraCommon.VAR_TYPE.DATE;
- break;
- case 'Timestamp':
- gs.log("Create Timestamp Field: "+this.legitVarName(field.name),'SARA');
- var varType = SaraCommon.VAR_TYPE.DATE_TIME;
- break;
- default:
- break;
- }
- variable = new CatalogVariable(this.legitVarName(field.name), varType, field.caption, defaultValue, field.description, []);
- if (field.maskAsPassword) variable.isPassword(field.maskAsPassword);
- if (field.range && field.range.values) {
- if (!(field.range.values instanceof Array)) field.range.values = [field.range.values];
- variable.setRange(field.range.values);
- }
- if (field.name) variable.setActualName(field.name);
- if (field.required) variable.isRequired(field.required);
- return variable;
- }
- /**
- * Contructs a CatalogItem object from its definition
- * @return CatalogItem object
- */
- SaraUtils.fromDef = function(defStr) {
- // TODO: parses the definition using JSONParser
- var parser = new JSONParser();
- var catObj = parser.parse(defStr);
- gs.log("TQT: Form length "+ catObj.forms.length );
- var i;
- for( i=0; i < catObj.forms.length;i++ ) {
- gs.log("TQT: Form length"+ i );
- }
- var obj = catObj.forms[0];
- for( i=0; i < obj.fields.length;i++ ) {
- gs.log("TQT: Form length "+ obj.fields[i].type );
- }
- //if (!catObj['shortDescription']) catObj['shortDescription'] = 'This is auto-generated shortDescription for service ' + catObj['name'];
- var catItem = new CatalogItem(catObj['name'], 'SARA Integration Demo', true, 'Sara Service', catObj['shortDescription'], catObj['shortDescription'], [], '');
- //catItem.setLinks(catObj['_links']);
- catItem.setServiceName(catObj['name']);
- // set SARA item to use 'sara_cart' cart
- catItem.setCustomCart('sara_cart');
- gs.log("TQT:"+ catObj.forms.length );
- var variables = [];
- var field = catObj.forms[0].fields[0];
- var variable = SaraUtils.createCatalogVariable(field);
- gs.log("TQT:"+ field.name );
- //new CatalogVariable(this.legitVarName(field.name), '9', 'why', '' , field.description, []);
- variables.push(variable);
- catItem.setVariables(variables);
- return catItem;
- }
- /**
- * Legitimates variable name that is not qualified business rule validate_variable_name
- */
- SaraUtils.legitVarName = function(varName) {
- var firstLegal = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- var firstLetter = varName.charAt(0);
- if (firstLegal.indexOf(firstLetter) == -1) {
- varName = "v_" + varName;
- }
- var legal = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789';
- for (var i = 0; i < varName.length; i++) {
- var letter = varName.charAt(i);
- if (legal.indexOf(letter) == -1) {
- // replace illegal char with _
- varName = varName.substr(0, i) + '_' + varName.substr(i + 1);
- }
- }
- return varName;
- }
- /**
- * Builds url with respect to configurable 'ref_scheme' property that might be 'relative' or 'absolute'
- */
- SaraUtils.buildUrl = function(url) {
- if (!url) url = '';
- if (SaraCommon.getRefScheme() === 'relative') {
- var basePath = SaraCommon.getBasePath();
- if (basePath.charAt(basePath.length - 1) == '/' && url.substring(0,1) == '/') {
- return basePath + url.substring(1);
- }
- if (basePath.charAt(basePath.length - 1) != '/' && url.substring(0,1) != '/') {
- return basePath + '/' + url;
- }
- return basePath + url;
- }
- if (url == '/') return SaraCommon.getBasePath();
- return url;
- }
- ]]></content>
- <description>Sara Utilities</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SAPIConsumer</name>
- <content><![CDATA[gs.include('SaraModel');
- gs.include('SaraCatalogGenerator');
- gs.include('SaraRestClient');
- gs.include('SaraUtils');
- gs.include('SaraCommon');
- var SAPIConsumer= Class.create();
- SAPIConsumer.prototype = {
- initialize: function() {
- // initialize dependencies
- var midserver = SaraCommon.getMidServer();
- this.restClient = new SaraRestClient();
- this.restClient.setMIDServer(midserver);
- this.username = gs.getUserName();
- this.statusCode = '';
- this.errorMessage = '';
- // inject restClient to the OAuth client instance
- this.oauthClient = new SaraOAuthClient(this.restClient);
- this.tokens = this.oauthClient.getUserTokens(this.username);
- this.generator = new SaraCatalogGenerator();
- // list of catalog category
- this.catalogCategoryEntities = [];
- // list of catalog item
- this.catalogItemEntities = [];
- // item category table;
- this.categorySysId = {};
- },
- restClient: null,
- // private method to check user permission.
- _checkPermission: function(){
- if (!gs.hasRole("admin") && !gs.hasRole("groups_admin")) {
- gs.log("You don't have sufficient permission to do this action. Allowed roles: admin, groups_admin",'SARA');
- return null;
- }
- // check user tokens
- if (!this.tokens) {
- gs.log('No tokens found for user ' + this.username + '. Skip import','SARA');
- return null;
- }
- gs.log('Tokens found for user ' + this.username,'SARA');
- if (!this.tokens[3]) this.tokens[3] = 'bearer';
- },
- /**
- * discover SAPI consumer URL, create corresponding list of Catalog Category and Catalog Item
- */
- discover: function() {
- this._checkPermission();
- /*************************************************************************************************
- * Block request Sapi REST API: Root URL *
- **************************************************************************************************/
- // Make request
- this.tokens = this.oauthClient.getUserTokens(this.username);
- var requestUrl = SaraUtils.buildUrl('/');
- //var request = this.restClient.newEntryRequest();
- var request = this.restClient.newServiceRequest('Entry','get',requestUrl);
- request.addHeader('Authorization', this.tokens[3] + ' ' + this.tokens[0]);
- // Get response
- var response = this.restClient.executeWithRefreshToken(request);
- if (!response || !response.getStatusCode() || response.getStatusCode() < 200 || response.getStatusCode() > 299) return response;
- // Parsing return Objects
- var resObj = (new JSONParser()).parse(response.getBody());
- /*************************************************************************************************/
- if (!resObj["_links"] || !resObj["_links"]["catalogs"]){
- gs.log('No catalog consumer URL found, skip discover!','SARA');
- return null;
- }
- /*************************************************************************************************
- * Block request Sapi REST API: /catalogs URL *
- **************************************************************************************************/
- // Make request
- this.tokens = this.oauthClient.getUserTokens(this.username);
- var requestUrl = SaraUtils.buildUrl(resObj["_links"]["catalogs"]["href"]);
- request = this.restClient.newServiceRequest('Sapi','get',requestUrl);
- request.addHeader('Authorization', this.tokens[3] + ' ' + this.tokens[0]);
- // Get response
- response = this.restClient.executeWithRefreshToken(request);
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) return response;
- // Parsing return Objects
- var catalogsObj = (new JSONParser()).parse(response.getBody());
- /*************************************************************************************************/
- // TODO: Should change to catalogsObj["_links"]["catalog"]
- if (!catalogsObj["_links"] || !catalogsObj["_links"]["catalog"]){
- gs.log('No SAPI catalog found, skip discover!','SARA')
- return null;
- }
- // discover SAPI Catalogs
- // TODO: Only for case: there is 1 item in list catalog, the JSON list will return as an object, not an array.
- // Should remove when all return are in array type.
- gs.log('Found '+catalogsObj["count"]+' SAPI Catalogs, start discover each catalog.', 'SARA');
- // In case there is only 1 catalog, convert catalogsObj["_links"]["catalog"] object to array with 1 element.
- if (catalogsObj["count"]==1 || catalogsObj["count"]=="1"){
- catalogsObj["_links"]["catalog"]=[catalogsObj["_links"]["catalog"]];
- }
- // TODO: For common case: there are more than 1 item in list catalog, JSON list return an array of catalog.
- for (var i in catalogsObj["_links"]["catalog"]){
- var catalogEntity = catalogsObj["_links"]["catalog"][i];
- if (!catalogEntity.href){
- break;
- }
- gs.log('Found catalog "'+catalogEntity.title+'" : ' + catalogEntity.href ,'SARA');
- this.tokens = this.oauthClient.getUserTokens(this.username);
- requestUrl = SaraUtils.buildUrl(catalogEntity.href);
- request = this.restClient.newServiceRequest('Sapi','get',requestUrl);
- request.addHeader('Authorization', this.tokens[3] + ' ' + this.tokens[0]);
- response = this.restClient.executeWithRefreshToken(request);
- if (!response || !response.getStatusCode() || response.getStatusCode() < 200 || response.getStatusCode() > 299) return response;
- var catObj = (new JSONParser()).parse(response.getBody());
- // store CatalogCategoryEntity to create later.
- var catName = (catalogEntity.title?catalogEntity.title:catObj.name);
- var catalogCategoryEntity = new CatalogCategory(catName,catObj.name, '', true, catObj.shortDescription);
- gs.log('Found catalog category at: '+catObj["_links"]["self"]["href"],'SARA');
- if (catObj["_links"]["self"]["href"])
- catalogCategoryEntity.setConsumeUrl(catObj["_links"]["self"]["href"]);
- this.catalogCategoryEntities.push(catalogCategoryEntity);
- if (catObj["_links"] && catObj["_links"]["service"]){
- // In case there is only 1 service, convert catObj["_links"]["service"] object to array with 1 element.
- if (catObj.count==1 || catObj.count=="1"){
- catObj["_links"]["service"] = [catObj["_links"]["service"]];
- }
- // discover Services inside each SAPI Catalog
- for (var j in catObj["_links"]["service"]){
- var serviceObj = catObj["_links"]["service"][j];
- if (serviceObj.href){
- var catalogItemEntity = new CatalogItem(serviceObj.title,catObj.name,true,'','','',null,null);
- catalogItemEntity.setConsumeUrl(serviceObj.href);
- gs.log('Found service "'+serviceObj.title+'" inside catalog "'+catObj.name+'"','SARA');
- this.catalogItemEntities.push(catalogItemEntity);
- }
- }
- }
- }
- return response;
- },
- /** Imports with regard to update behaviour */
- discoverItem : function (catalogItemEntities) {
- var catalogItems = [];
- var response = null;
- for (var i in catalogItemEntities) {
- var item = catalogItemEntities[i];
- // Make request to catalog item details
- this.tokens = this.oauthClient.getUserTokens(this.username);
- var requestUrl = SaraUtils.buildUrl(item.getConsumeUrl());
- var request = this.restClient.newServiceRequest('Sapi', 'get', requestUrl);
- request.addHeader('Authorization', this.tokens[3] + ' ' + this.tokens[0]);
- response = this.restClient.executeWithRefreshToken(request);
- if (!response || !response.getStatusCode() || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- gs.log('Request to ' + requestUrl + ' failed', 'SARA');
- if (response) {
- gs.log("Status code: " + response.getStatusCode() + ", error message: " + response.getBody(), 'SARA');
- }
- return;
- }
- var service = (new JSONParser()).parse(response.getBody());
- var variables = [];
- //
- var itemName = (item.name ? item.name : service.name);
- gs.log('Set category for Item ' + item.getCategory() + ' to ' + this.categorySysId[item.getCategory()].sysId, 'SARA');
- var catItem = new CatalogItem(itemName, this.categorySysId[item.getCategory()].sysId, true, 'Sara Service', service.shortDescription, service.shortDescription, [], '');
- gs.log('SERVICE NAME = ' + service.name, 'SARA');
- catItem.setServiceName(service.name);
- catItem.setConsumeUrl(service._links.consume.href);
- catItem.isNew = this.categorySysId[item.getCategory()].isNew;
- // In case there is only 1 form, convert service.forms object to array with 1 element.
- if (service.forms.name) {
- service.forms = [service.forms];
- }
- for (var i = 0; i < service.forms.length; i++) {
- var j = 0;
- var form = service.forms[i];
- // set SARA item to use 'sara_cart' cart
- catItem.setCustomCart('sara_cart');
- // In case there is only 1 field, convert form.fields object to array with 1 element.
- if (form.fields.type) {
- form.fields = [form.fields];
- }
- for (j = 0; j < form.fields.length; j++) {
- var field = form.fields[j];
- var variable = SaraUtils.createCatalogVariable(field);
- variables.push(variable);
- }
- }
- catItem.setVariables(variables);
- catalogItems.push(catItem);
- }
- this.catalogItemEntities = catalogItems.slice(0);
- return response;
- },
- importItem: function(catalogItemEntities){
- var glideHelper = new SaraGlideHelper();
- for(var i in catalogItemEntities) {
- var item = catalogItemEntities[i];
- if (item.isNew) {
- this.generator.save(item);
- gs.log('Imported new item, name = ' + item.name + ', service name = ' + item.getServiceName(), 'SARA');
- continue;
- }
- // check existing item with same name and same parent category id = item.category
- var saraItems = glideHelper.getData('u_sara_definition', {'u_name': item.getServiceName(), 'u_parent': item.category, 'u_type': 'service'}, ['u_sc_item']);
- if (saraItems && saraItems.length > 0) {
- // update sc item with sys_id = saraItems[0].u_sc_item
- item.sysId = saraItems[0].u_sc_item;
- this.generator.updateItem(item);
- gs.log('Updated catalog item sys_id = ' + item.sysId + ', name = ' + item.name + ', service name = ' + item.getServiceName(), 'SARA');
- } else {
- // insert new as normal
- this.generator.save(item);
- gs.log('Imported new item, name = ' + item.name + ', service name = ' + item.getServiceName(), 'SARA');
- }
- }
- },
- importCategory: function(catalogs){
- var targetCatId; // = '506d3e5a600a5980e73c9affd8c630e0';
- var glideHelper = new SaraGlideHelper();
- if (typeof wizard != 'undefined' && wizard && wizard.sara_target_category){
- gs.log('Target category = \'' + wizard.sara_target_category + '\' ...', 'SARA');
- targetCatId = wizard.sara_target_category;
- }
- // if there's no target category specified, all catalogs will be imported as new ones
- if (!targetCatId) {
- for (i in catalogs){
- var catId = this.generator.saveCategory(catalogs[i]);
- this.categorySysId[catalogs[i].name] = {'sysId': catId, 'isNew': true};
- gs.log('Imported new category ' + catalogs[i].name + ' with sys_id = ' + catId, 'SARA');
- }
- return;
- }
- // otherwise, check if there's same name category existing under target category
- for (i in catalogs) {
- var catId, isNew = true;
- var catalog = catalogs[i];
- gs.log('Catalog ' + i + ': ' + new JSON().encode(catalog), 'SARA');
- // check if there's same name category existing under target category
- var saraCats = glideHelper.getData('u_sara_definition', {'u_name': catalog.name, 'u_parent': targetCatId, 'u_type': 'catalog'}, ['u_service_catalog_category']);
- if (saraCats && saraCats.length > 0) {
- isNew = false;
- catId = saraCats[0]['u_service_catalog_category'];
- }
- catalog.isNew = isNew;
- if (isNew) {
- catId = this.generator.saveCategory(catalog);
- this.categorySysId[catalogs[i].name] = {'sysId': catId, 'isNew': true};
- gs.log('Imported new category ' + catalog.name + ' with sys_id = ' + catId, 'SARA');
- } else {
- // update category with sys_id = catId
- catalog.sysId = catId;
- this.generator.updateCategory(catalog);
- this.categorySysId[catalogs[i].name] = {'sysId': catId, 'isNew': false};
- gs.log('Updated category ' + catalog.name + ' with sys_id = ' + catId, 'SARA');
- }
- }
- },
- /**
- * discover then import the data.
- */
- discoverAndImport: function(){
- var response = this.discover();
- if(response){
- if (response.getStatusCode() && response.getBody() ){
- if (response.getStatusCode()<200 || response.getStatusCode()>299){
- this.statusCode = response.getStatusCode();
- var resObj = new JSONParser().parse(response.getBody());
- this.errorMessage = resObj.error + ' - ' + resObj.error_description;
- return null;
- }
- } else {
- this.statusCode = response.errorCode;
- this.errorMessage = response.errorMessage;
- gs.log('ERROR with statusCode = '+this.statusCode+' - ErrorMessage = '+this.errorMessage,'SARA');
- return null;
- }
- }else{
- this.statusCode = 0;
- this.errorMessage = 'No response from server '+SaraCommon.getMidServer();
- return null;
- }
- var logMsg = '';
- if (this.catalogCategoryEntities){
- this.importCategory(this.catalogCategoryEntities);
- logMsg = logMsg.concat('\nImported '+this.catalogCategoryEntities.length+' Catalog categories!');
- }
- else gs.log('Cannot found any Catalog category!','SARA');
- // Import service and finalize logMsg.
- response = this.discoverItem(this.catalogItemEntities);
- if(response){
- if (response.getStatusCode() && response.getBody() ){
- if (response.getStatusCode()<200 || response.getStatusCode()>299){
- this.statusCode = response.getStatusCode();
- var resObj = new JSONParser().parse(response.getBody());
- this.errorMessage = resObj.error + ' - ' + resObj.error_description;
- return null;
- }
- } else {
- this.statusCode = response.errorCode;
- this.errorMessage = response.errorMessage;
- gs.log('ERROR with statusCode = '+this.statusCode+' - ErrorMessage = '+this.errorMessage,'SARA');
- return null;
- }
- }else{
- this.statusCode = 0;
- this.errorMessage = 'No response from server '+SaraCommon.getMidServer();
- return null;
- }
- this.importItem(this.catalogItemEntities);
- logMsg = logMsg.concat('\nImported '+this.catalogItemEntities.length+' Catalog items!');
- if (!this.catalogCategoryEntities && !this.catalogItemEntities)
- return null;
- else return logMsg;
- },
- getCatalogCategoryEntities: function(){
- return this.catalogCategoryEntities;
- },
- getCatalogItemEntities: function(){
- return this.catalogItemEntities;
- },
- getStatusCode: function(){
- return this.statusCode;
- },
- getErrorMessage: function(){
- return this.errorMessage;
- },
- type: 'SAPIConsumer'
- }
- ]]></content>
- <description>SAPI consumer class to discover all SAPI catalogs, services and import them into SN as the corresponding catalog categories and items</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- <script_include>
- <name>SaraGlideHelper</name>
- <content><![CDATA[/**
- * Helper class provides convenient methods to work with ServiceNow data tables
- */
- var SaraGlideHelper = Class.create();
- SaraGlideHelper.prototype = {
- initialize : function () {},
- /**
- * Common data persistent operation
- * @param table the table name
- * @param entity object represents the row to insert
- * @param referencing insert with references or not
- * @return sys_id of inserted row
- */
- persistData : function (table, entity, referencing) {
- var rec = new GlideRecord(table);
- rec.initialize();
- for (key in entity) {
- // check if key contains 'sys_id'
- var idx = key.indexOf('.sys_id');
- if (idx > 0 && idx == key.length - 7) {
- var propName = key.substring(0, idx);
- rec[propName]['sys_id'] = entity[key];
- } else rec[key] = entity[key];
- }
- if (referencing) {
- return rec.insertWithReferences();
- }
- else {
- return rec.insert();
- }
- },
- /**
- * Updates record(s) in given table based on the query and entity object holds fields/values to update
- * @param table target table to update
- * @param queryObj query object, property name is the field name to query, value is value to query
- * @param entity holds fields and values to update
- * @param updateAll update all matching record(s) or only the first one
- * @param referencing update with references or not
- */
- updateData: function(table, queryObj, entity, updateAll, referencing) {
- var rec = new GlideRecord(table);
- if (queryObj) {
- for (key in queryObj) {
- rec.addQuery(key, queryObj[key]);
- }
- }
- rec.query();
- while (rec.next()) {
- for (key in entity) {
- // check if key contains 'sys_id'
- var idx = key.indexOf('.sys_id');
- if (idx > 0 && idx == key.length - 7) {
- var propName = key.substring(0, idx);
- rec[propName]['sys_id'] = entity[key];
- } else rec[key] = entity[key];
- }
- if (referencing) {
- rec.updateWithReferences();
- } else {
- rec.update();
- }
- if (!updateAll) break;
- }
- },
- /**
- * Retrieve sys_id of a record in given table by key=value query
- * @param table the table name
- * @param queryObj the object holds the query, property name is the field name to query, value is value to query
- * @return sys_id that found, or null if no record found
- */
- getSysId : function (table, queryObj) {
- var rec = new GlideRecord(table);
- if (queryObj) {
- for (key in queryObj) {
- rec.addQuery(key, queryObj[key]);
- }
- }
- rec.query();
- if (rec.next()) {
- return rec.sys_id;
- }
- else {
- return null;
- }
- },
- /**
- * Query data from given table and query condition, return objects contain information specified in list of key
- * @param table the target table
- * @param queryObj the object holds the query, property name is the field name to query, value is value to query
- * @param keys list of field members that will be included in result
- * @return array of object with key from <code>keys</code>
- */
- getData: function(table, queryObj, keys) {
- var rec = new GlideRecord(table);
- var k;
- if (queryObj) {
- for (k in queryObj) {
- rec.addQuery(k, queryObj[k]);
- }
- }
- rec.query();
- var result = [];
- if (!keys) keys = ['sys_id'];
- while (rec.next()) {
- var obj = {};
- for (idx in keys) {
- obj[keys[idx]] = rec[keys[idx]].toString();
- }
- result.push(obj);
- }
- return result;
- },
- /**
- * Delete record(s) from given table based on a query condition
- * @param table the target table
- * @param queryObj the object holds the query, property name is the field name to query, value is value to query
- */
- deleteData: function(table, queryObj, deleteAll) {
- var rec = new GlideRecord(table);
- if (queryObj) {
- for (key in queryObj) {
- rec.addQuery(key, queryObj[key]);
- }
- }
- if (deleteAll) {
- rec.deleteMultiple();
- } else {
- rec.query();
- if (rec.next()) {
- rec.deleteRecord();
- }
- }
- },
- type : 'SaraGlideHelper'
- };
- ]]></content>
- <description>Helper class provides convenient methods to work with ServiceNow data tables</description>
- <active>true</active>
- <client_callable>false</client_callable>
- </script_include>
- </script_includes>
- <ui_pages>
- <ui_page>
- <name>sara_oauth_authentication</name>
- <description/>
- <category>catalog</category>
- <html><![CDATA[<g:ui_form>
- <g:evaluate var="jvar_sysparm_id" expression="RP.getWindowProperties().get('sysparm_id')" />
- <g:evaluate var="jvar_quantity" expression="RP.getWindowProperties().get('quantity')" />
- <g:evaluate var="jvar_item_guid" expression="RP.getWindowProperties().get('item_guid')" />
- <g:evaluate var="jvar_cart_action" expression="RP.getWindowProperties().get('cart_action')" />
- <div class="sara_cart_hidden" style="display:none">
- <input type="hidden" name="sara_order_sysparm_id" id="sara_order_sysparm_id" value="${jvar_sysparm_id}" />
- <input type="hidden" name="sara_order_quantity" id="sara_order_quantity" value="${jvar_quantity}" />
- <input type="hidden" name="sara_order_item_guid" id="sara_order_item_guid" value="${jvar_item_guid}" />
- <input type="hidden" name="sara_cart_action" id="sara_cart_action" value="${jvar_cart_action}" />
- </div>
- <p><label>Username</label><input type="text" name="sara_oauth_username" id="sara_oauth_username" /></p>
- <p><label>Password</label><input type="password" name="sara_oauth_password" id="sara_oauth_password" /></p>
- <g:dialog_buttons_ok_cancel ok="validate(); return false;" cancel="processCancel(); return false;" />
- <p id="sara_oauth_processing" style="display:none;"><label>Please wait, processing...</label></p>
- </g:ui_form>
- ]]></html>
- <client_script><![CDATA[function validate() {
- var username = trim(gel('sara_oauth_username').value);
- var password = trim(gel('sara_oauth_password').value);
- if (!username || !password) {
- alert('Please provide username/password to authenticate against Automic OAuth Server.');
- return false;
- }
- gel('sara_oauth_processing').style.display='block';
- var sysparmId = gel('sara_order_sysparm_id').value;
- var quantity = gel('sara_order_quantity').value;
- var itemGuid = gel('sara_order_item_guid').value;
- var cartAction = gel('sara_cart_action').value;
- // invoke SaraOAuthAjax
- var ga = new GlideAjax("SaraOAuthAjax");
- ga.addParam('sysparm_name', 'requestToken');
- ga.addParam('sysparm_username', username);
- ga.addParam('sysparm_password', password);
- //ga.getXMLWait();
- //var answer = ga.getAnswer();
- //console.log('Answer = ' + answer);
- //if (answer == 'ok') {
- // if (cartAction == "order") {
- // var g_cart = new SCCart();
- // g_cart.order(sysparmId, quantity, itemGuid);
- // } else if (cartAction == "checkout") {
- // // go to 'Order Status' page
- // window.location='service_catalog.do?sysparm_action=checkout';
- // }
- //} else alert('Token request finished unsuccessfully' + answer?', error: ' + answer:'' + '. Please try again later or contact administrators.');
- ga.getXML(function(response) {
- var answer = response.responseXML.documentElement.getAttribute("answer");
- console.log('Answer = ' + answer);
- if (answer == 'ok') {
- gel('sara_oauth_processing').childNodes[0].innerHTML = 'Token request successfully, redirecting to Order Status page...';
- if (cartAction == "order") {
- var g_cart = new SCCart();
- g_cart.order(sysparmId, quantity, itemGuid);
- } else if (cartAction == "checkout") {
- // go to 'Order Status' page
- window.location='service_catalog.do?sysparm_action=checkout';
- }
- } else {
- alert('Token request finished unsuccessfully' + (answer?(', error: ' + answer):'') + '. Please try again later or contact administrators.');
- GlideDialogWindow.get().destroy(); //Close the dialog window
- }
- });
- return false;
- }
- function processCancel(){
- GlideDialogWindow.get().destroy(); //Close the dialog window
- //alert('Your order has been skipped.');
- console.log('Order is skipped');
- }
- ]]></client_script>
- <processing_script/>
- </ui_page>
- <ui_page>
- <name>sara_servicecatalog_cart_view</name>
- <description/>
- <category>catalog</category>
- <html><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
- <j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
- <j:set var="jvar_two_step" value="false" />
- <g:macro_invoke macro="sara_servicecatalog_cart_template" />
- <g:catalog_notify_cart_empty />
- </j:jelly>
- ]]></html>
- </ui_page>
- </ui_pages>
- <ui_macros>
- <ui_macro>
- <name>sara_cart</name>
- <description/>
- <category>catalog</category>
- <active>true</active>
- <media_type/>
- <xml><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
- <j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
- <g:set_if test="${sysparm_cartless}" var="jvar_cart_style" true="display:none" />
- <table style="float: right">
- <tr>
- <td id="cart" style="${jvar_cart_style}"></td>
- </tr>
- </table>
- <input type="hidden" id="sara_cart_indicator" value="This is the custom cart for SARA catalog items" />
- <input type="hidden" id="sysparm_id" value="${sysparm_id}"/>
- <table id="qty" style="display:none; width:100%" border="0">
- <g:sc_cart_main />
- <j:if test="${sysparm_cart_edit == null}">
- <j:if test="${sc_cat_item.no_order != true}">
- <j:if test="${sysparm_no_checkout != true}">
- <j:if test="${sc_cat_item.no_order_now != true}">
- <tr>
- <td colspan="2" class="order_buttons">
- <a class="request_catalog_button_with_icon" href="#" id="order_now" onclick="orderNow(); return false;" title="${gs.getMessage('Order Now')}">
- <table>
- <tr><td><img src="images/button_cursor.gifx" /></td><td class="text_cell">${gs.getMessage('Order Now')}</td></tr>
- </table>
- </a>
- </td>
- </tr>
- </j:if>
- </j:if>
- <j:if test="${sc_cat_item.no_cart != true}">
- <tr>
- <td colspan="2" class="order_buttons">
- <a class="request_catalog_button_with_icon" href="#" onclick="addToCart(); return false;" title="${gs.getMessage('Add to Cart')}">
- <table><tr><td><img src="images/button_cart.gifx"/></td><td class="text_cell">${gs.getMessage('Add to Cart')}</td></tr></table>
- </a>
- </td>
- </tr>
- </j:if>
- </j:if>
- </j:if>
- <j:if test="${sysparm_cart_edit != null}">
- <tr>
- <td colspan="2" class="order_buttons">
- <a class="request_catalog_button_with_icon" href="#" onclick="orderEdit(); return false;" title="${gs.getMessage('Update Cart')}">
- <table><tr><td><img src="images/button_cart.gifx"/></td><td class="text_cell">${gs.getMessage('Update Cart')}</td></tr></table>
- </a>
- </td>
- </tr>
- </j:if>
- </table>
- <script language="javascript">
- var g_cart = null;
- function scCartOnRender() {
- g_cart = new SCCart();
- <j:if test="${sc_cat_item.no_order != true}">
- g_cart.attachWindow('qty', 'cart', "${gs.getMessage('Order this Item')}");
- </j:if>
- <j:if test="${sc_cat_item.no_cart == true}">
- g_cart.setCartVisible(false);
- </j:if>
- g_cart.addCartContent();
- g_cart.editID = '${sysparm_cart_edit}';
- //g_cart.getWithBackButton();
- var i = new CartItemList(g_cart);
- i._afterChange = function() {
- if (this.cart)
- this.cart._changed();
- _frameChanged();
- modifyCartActions();
- }
- i.create();
- i.get();
- }
- addRenderEvent(scCartOnRender);
- function addToCart() {
- var m = g_form.catalogOnSubmit();
- if (!m) return;
- var guid;
- var item_guid = gel("sysparm_item_guid");
- if (item_guid) guid = item_guid.value
- // To prevent duplicate key violations due to multiple rapid clicks
- // clear the item_guid if not empty and continue with the addToCart
- // else return until a new item_guid is returned from the server
- if (guid == "") return;
- item_guid.value = "";
- // hide the attachment header and delete out attachment name spans
- var attachmentList = gel("header_attachment_list");
- if (attachmentList) {
- var count = attachmentList.childNodes.length;
- while (count > 1) {
- count--;
- var node = attachmentList.childNodes[count];
- rel(node);
- }
- var listLabel = gel("header_attachment_list_label");
- listLabel.style.display = "none";
- var spanNodes = $(listLabel).select("span");
- if (spanNodes $[AMP]$[AMP] spanNodes.length != 0) spanNodes[0].update("");
- }
- g_cart.add(gel("sysparm_id").value, getQuantity(), guid);
- }
- function modifyCartActions() {
- var edit = gel('catalog_cart_edit_button');
- if (edit) {
- edit.onclick = function() {
- window.location='sara_servicecatalog_cart_view.do';
- return false;
- };
- }
- var checkout = gel('catalog_cart_proceed_checkout');
- if (checkout) {
- checkout.onclick = null;
- checkout.onclick = function() { saraCheckout(); }
- }
- gel('sara_cart_indicator').value = gel('sara_cart_indicator').value + ', modified actions = true';
- }
- function saraCheckout() {
- //gel("catalog_cart_proceed_checkout").onclick = "";
- var currentUser = g_user.userName;
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', currentUser);
- rec.query(function(rec) {
- if (rec.next()) {
- console.log('Token found: ' + rec.u_access_token);
- // go to 'Order Status' page
- window.location='service_catalog.do?sysparm_action=checkout';
- } else {
- console.log('Token not found, please provide your credentials to request tokens');
- // pop out username/password dialog
- var dialog = new GlideDialogWindow("sara_oauth_authentication");
- dialog.setPreference("cart_action", "checkout");
- dialog.setTitle("SARA OAuth Credentials");
- dialog.removeCloseDecoration();
- dialog.render();
- return;
- }
- });
- }
- function orderNow() {
- var m = g_form.catalogOnSubmit();
- if (!m) return;
- // Disable the Order Now button to prevent muliple item order
- // as a result of muliple clicks before navigating away
- //gel("order_now").onclick = "";
- var item_guid = gel("sysparm_item_guid");
- if (item_guid) item_guid = item_guid.value;
- // check if current user has token or not
- var currentUser = g_user.userName;
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', currentUser);
- rec.query(function(rec) {
- if (rec.next()) {
- console.log('Token found: ' + rec.u_access_token);
- g_cart.order(gel("sysparm_id").value, getQuantity(), item_guid);
- } else {
- console.log('Token not found, please provide your credentials to request tokens');
- // pop out username/password dialog
- var dialog = new GlideDialogWindow("sara_oauth_authentication");
- dialog.setPreference("sysparm_id", gel("sysparm_id").value);
- dialog.setPreference("quantity", getQuantity());
- dialog.setPreference("item_guid", item_guid);
- dialog.setPreference("cart_action", "order");
- dialog.setTitle("SARA OAuth Credentials");
- dialog.removeCloseDecoration();
- dialog.render();
- return;
- }
- });
- }
- function calcPrice() {
- g_cart.recalcPrice(gel("sysparm_id").value, getQuantity());
- }
- function orderEdit(target) {
- if (!target) target = '${sysparm_cart_edit}';
- var m = g_form.catalogOnSubmit();
- if (!m) return;
- g_cart.edit(target, getQuantity());
- }
- // unused atm
- function proceedCheckout(target) {
- // check if current user has token or not
- alert('In proceedCheckout');
- var currentUser = g_user.userName;
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', currentUser);
- rec.query(function(rec) {
- if (rec.next()) {
- alert('Token found: ' + rec.u_access_token);
- var m = g_form.catalogOnSubmit();
- if (!m) return;
- g_cart.orderUpdate(target, getQuantity());
- } else {
- alert('Token not found');
- var dialog = new GlideDialogWindow("sara_oauth_authentication"); //Render the dialog containing the UI Page 'task_comments_dialog'
- dialog.setTitle("Request OAuth tokens"); //Set the dialog title
- dialog.render(); //Open the dialog
- return;
- }
- });
- }
- function getQuantity() {
- var quantity = 1;
- var quan_widget = gel("quantity");
- if (quan_widget) quantity = quan_widget.value;
- return quantity;
- }
- </script>
- </j:jelly>
- ]]></xml>
- </ui_macro>
- <ui_macro>
- <name>sara_servicecatalog_cart_template</name>
- <description/>
- <category>catalog</category>
- <active>true</active>
- <media_type/>
- <xml><![CDATA[<?xml version="1.0" encoding="utf-8" ?>
- <j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
- <g:include_script src="CartCheckoutFunctions.jsdbx"/>
- <g:catalog_notify_cart_empty />
- <!-- assumption is that a cart exists -->
- <g2:evaluate var="jvar_item" expression="sc_cart = new GlideRecord('sc_cart'); sc_cart.get('user', system.getUserID()); var sc_cat_item = new GlideRecord('sc_cat_item'); sc_cat_item.initialize();"/>
- <j:set var="jvar_checkout" value="checkout" />
- <j:if test="${jvar_two_step == true}">
- <j:set var="jvar_checkout" value="checkouttwo" />
- </j:if>
- <j:if test="${sysparm_guide == 'true'}">
- <g:inline template="com.glideapp.servicecatalog_guide_banner.xml" />
- </j:if>
- <form method="POST" name="service_catalog.do" id="sc_cart.do">
- <input type="HIDDEN" name="sysparm_view" value="${sysparm_view}" />
- <input type="HIDDEN" name="sysparm_action" value="${jvar_checkout}" />
- <input type="HIDDEN" name="sys_action" />
- <table class="request_table" style="border-collapse: collapse;">
- <tr class="header" border="0" cellspacing="0">
- <td style="width: 22px;">
- <img name="not_important" value="sysverb_back" id="sysverb_back" onClick="gel('sc_cart.do').sysparm_action.value ='sysverb_back';gel('sc_cart.do').submit();" src="images/green_back.gifx" title="${gs.getMessage('Back')}" alt="${gs.getMessage('Back')}" style="cursor:hand; margin-left: 4px;"/>
- </td>
- <td class="column_head" colspan="1">
- <div class="caption">${gs.getMessage('Shopping Cart')}</div>
- </td>
- <td></td>
- <td class="column_head" align="right" colspan="99">
- <j:if test="${jvar_two_step != true}">
- <button class="header" type="submit">
- ${gs.getMessage('Check out')}
- </button>
- </j:if>
- </td>
- </tr>
- </table>
- <p class="order_details">
- ${gs.getMessage('Are the contents of your cart correct? Please double check the items and remove and edit where appropriate')}
- </p>
- <table class="request_table" style="border-collapse: collapse;" border="0">
- <j2:set var="jvar_never_show_price" value="$[gs.getProperty('glide.sc.price.display') == 'never']" />
- <j2:set var="jvar_show_price" value="false" />
- <j2:set var="jvar_got_one" value="false" />
- <j2:set var="jvar_freq_list" value="$[SNC.CartBatcher.getFrequencyList(sc_cart.sys_id)]"/>
- <j2:forEach var="jvar_freq" items="$[jvar_freq_list]">
- <g2:evaluate var="freq_name" jelly="true">
- var freq_name = jelly.jvar_freq;
- freq_name;
- </g2:evaluate>
- <j2:set var="jvar_show_recurring_price_block" value="false" />
- <j2:set var="jvar_show_price_block" value="false" />
- <j2:set var="jvar_item_list" value="$[SNC.CartBatcher.getFrequencyItems(sc_cart.sys_id, freq_name)]"/>
- <j2:set var="jvar_subtotal_block" value="$[0]" />
- <j2:set var="jvar_recurring_subtotal_block" value="$[0]" />
- <g2:evaluate var="jvar_line_num" expression="0" />
- <j2:forEach var="jvar_item" items="$[jvar_item_list]">
- <g2:evaluate var="sc_cart_item" jelly="true">
- var sc_cart_item = new GlideRecord("sc_cart_item");
- sc_cart_item.addQuery("sys_id", ""+jelly.jvar_item);
- sc_cart_item.query();
- sc_cart_item.next();
- sc_cart_item;
- </g2:evaluate>
- <!-- jvar_freq = current_item.cat_item.name -->
- <j2:set var="jvar_got_one" value="true" />
- <g2:evaluate var="jvar_cat_item" expression="sc_cat_item = new GlideRecord('sc_cat_item'); sc_cat_item.addQuery('sys_id','$[sc_cart_item.cat_item]'); sc_cat_item.query(); sc_cat_item.next();"/>
- <g2:evaluate var="cart_item_price">
- var helper = new GlideappScriptHelper();
- cart_item_price = helper.getCartItemPrice($[sc_cart_item]);
- </g2:evaluate>
- <g2:evaluate var="cart_item_recurring_price">
- var helper = new GlideappScriptHelper();
- cart_item_recurring_price = helper.getCartItemRecurringPrice($[sc_cart_item]);
- </g2:evaluate>
- <j2:if test="$[jvar_line_num == 0]">
- <thead class="checkout_title">
- <th class="checkout_left"/>
- <j2:if test="$[freq_name != 'none']">
- <th class="checkout_left">${gs.getMessage('Item')} (${gs.getMessage("Includes")} $[sc_cat_item.recurring_frequency.getDisplayValue()] ${gs.getMessage("Charges")})</th>
- </j2:if>
- <j2:if test="$[freq_name == 'none']">
- <th class="checkout_left">${gs.getMessage('Item')}</th>
- </j2:if>
- <th class="checkout_left">${gs.getMessage('Delivery Time')}</th>
- <j2:if test="$[!jvar_never_show_price]">
- <th class="checkout_price">$[sc_cat_item.price.sys_meta.label] (ea.)</th>
- </j2:if>
- <th class="checkout_quantity">${gs.getMessage('Quantity')}</th>
- <j2:if test="$[!jvar_never_show_price]">
- <th class="checkout_total">${gs.getMessage('Total')}</th>
- </j2:if>
- </thead>
- </j2:if>
- <g2:inline template="com.glideapp.servicecatalog_show_price_function.xml" />
- <j2:if test="$[show_price]">
- <j2:set var="jvar_show_price" value="true" />
- <j2:set var="jvar_show_price_block" value="true" />
- </j2:if>
- <j2:if test="$[show_recurring_price]">
- <j2:set var="jvar_show_recurring_price_block" value="true" />
- </j2:if>
- <g2:evaluate var="jvar_line_num" expression="$[jvar_line_num] + 1" />
- <g2:evaluate var="jvar_price">
- this_price = '--';
- if ($[show_price])
- this_price = cart_item_price;
- </g2:evaluate>
- <g2:evaluate var="jvar_recurring_price">
- this_recurring_price = '--';
- if ($[show_recurring_price])
- this_recurring_price = cart_item_recurring_price;
- </g2:evaluate>
- <g2:evaluate var="jvar_subtotal">
- subtotal = 0;
- if($[show_price]) {
- if ($[this_price == '--'])
- subtotal = 0;
- else
- subtotal = this_price * $[sc_cart_item.quantity];
- } else
- this_price;
- </g2:evaluate>
- <g2:evaluate var="jvar_recurring_subtotal">
- recurring_subtotal = 0;
- if($[show_recurring_price])
- if ($[this_recurring_price == '--'])
- recurring_subtotal = 0;
- else
- recurring_subtotal = this_recurring_price * $[sc_cart_item.quantity];
- else
- this_recurring_price;
- </g2:evaluate>
- <j2:if test="$[jvar_subtotal != '--']" >
- <j2:set var="jvar_subtotal_block" value="$[jvar_subtotal_block + jvar_subtotal]" />
- </j2:if>
- <j2:if test="$[jvar_recurring_subtotal != '--']" >
- <j2:set var="jvar_recurring_subtotal_block" value="$[jvar_recurring_subtotal_block + jvar_recurring_subtotal]" />
- </j2:if>
- <g2:evaluate var="jvar_total_price" expression="$[jvar_total_price] + subtotal"/>
- <j2:set var="jvar_line_color" value="odd" />
- <j2:if test="$[jvar_line_num % 2 == 0]" >
- <j2:set var="jvar_line_color" value="even" />
- </j2:if>
- <tr class="$[jvar_line_color]">
- <td class="checkout_left">
- <a class="request_catalog_button" href="service_catalog.do?sysparm_action=cart_remove&sysparm_id=$[sc_cart_item.sys_id]&sysparm_ck=$[gs.getSessionToken()]">
- ${gs.getMessage('Delete')}
- </a>
- <a class="request_catalog_button" href="com.glideapp.servicecatalog_cat_item_view.do?sysparm_view=${sysparm_view}&sysparm_id=$[sc_cart_item.cat_item]&sysparm_cart_edit=$[sc_cart_item.sys_id]&sysparm_ck=$[gs.getSessionToken()]">
- ${gs.getMessage('Edit')}
- </a>
- </td>
- <td class="checkout_left" style="width: 40%;">
- <table cellspacing="0" cellpadding="0" width="100%" class="background_transparent">
- <g2:evaluate var="sc_cart_item_labels">
- var sc_cart_item_labels = new CatalogLabelEvaluator(sc_cart_item).getLabels();
- </g2:evaluate>
- <g2:inline template="help_text.xml"
- question_show_help="true"
- question_help_tag="$[sc_cat_item.name.getDisplayValue() + ' - ' +sc_cat_item.short_description.getDisplayValue()]"
- question_name="$[sc_cart_item.sys_id]"
- help_class="$[jvar_line_color]">
- <g:cart_variable_summary sc_cart_item_labels="$[sc_cart_item_labels]" />
- </g2:inline>
- </table>
- </td>
- <td class="checkout_left">
- <j2:set var="jvar_wf" value="$[sc_cat_item.workflow]"/>
- <j2:if test="$[!empty(jvar_wf)]">
- <g2:evaluate var="jvar_wf_delivery_time" expression="new Workflow().getEstimatedDeliveryTime('$[jvar_wf]');" />
- <j2:if test="$[!empty(jvar_wf_delivery_time)]">
- $[jvar_wf_delivery_time]
- </j2:if>
- <j2:if test="$[empty(jvar_wf_delivery_time)]">
- 0 $[gs.getMessage("Days")]
- </j2:if>
- </j2:if>
- <j2:if test="$[empty(jvar_wf)]">
- <j2:set var="jvar_dt" value="$[sc_cat_item.delivery_plan.total_delivery_time.getDisplayValue()]"/>
- <j2:if test="$[!empty(jvar_dt)]">
- $[jvar_dt]
- </j2:if>
- <j2:if test="$[empty(jvar_dt)]">
- <g2:evaluate var="jvar_dt" jelly="true">
- var jvar_dt = "";
- var pgr = new GlideRecord("sc_cat_item_delivery_plan");
- pgr.addQuery("name", "DEFAULT");
- pgr.query();
- if (pgr.next())
- jvar_dt = pgr.total_delivery_time.getDisplayValue();
- jvar_dt;
- </g2:evaluate>
- <j2:if test="$[!empty(jvar_dt)]">
- $[jvar_dt]
- </j2:if>
- <j2:if test="$[empty(jvar_dt)]">
- 0 $[gs.getMessage("Days")]
- </j2:if>
- </j2:if>
- </j2:if>
- </td>
- <j2:if test="$[!jvar_never_show_price]">
- <td class="checkout_price">
- <j2:if test="$[show_price]">
- <div><g2:currency_format double="$[this_price]"/></div>
- </j2:if>
- <j2:if test="$[!show_price]">
- <div>-</div>
- </j2:if>
- <j2:if test="$[show_recurring_price]">
- <j2:if test="$[!sc_cat_item.recurring_frequency.nil()]">
- <div class="checkout_recurring_price">
- + <g2:currency_format double="$[this_recurring_price]"/> $[sc_cat_item.recurring_frequency.getDisplayValue()]
- </div>
- </j2:if>
- </j2:if>
- </td>
- </j2:if>
- <td class="checkout_quantity">$[sc_cart_item.quantity]</td>
- <j2:if test="$[!jvar_never_show_price]">
- <td class="checkout_total">
- <j2:if test="$[show_price]">
- <div><g2:currency_format double="$[jvar_subtotal]"/></div>
- </j2:if>
- <j2:if test="$[!show_price]">
- <div>-</div>
- </j2:if>
- <j2:if test="$[show_recurring_price]">
- <j2:if test="$[!sc_cat_item.recurring_frequency.nil()]">
- <div class="checkout_recurring_price_total">+ <g2:currency_format double="$[jvar_recurring_subtotal]"/> $[sc_cat_item.recurring_frequency.getDisplayValue()]</div>
- </j2:if>
- </j2:if>
- </td>
- </j2:if>
- </tr>
- </j2:forEach>
- <j2:if test="$[!jvar_never_show_price]">
- <thead class="checkout_title">
- <j2:if test="$[jvar_never_show_price]">
- <th style="font-size: 0px;" colspan="4">$[AMP]nbsp;</th>
- </j2:if>
- <j2:if test="$[!jvar_never_show_price]">
- <th style="font-size: 0px;" colspan="6">$[AMP]nbsp;</th>
- </j2:if>
- </thead>
- <tr style="border-bottom: 0px;">
- <td/>
- <td/>
- <td/>
- <td/>
- <td class="checkoutTotalLabel">
- <j2:if test="$[jvar_freq_list.length == 1]">
- ${gs.getMessage('Total')}
- </j2:if>
- <j2:if test="$[jvar_freq_list.length != 1]">
- ${gs.getMessage('Subtotal')}
- </j2:if>
- </td>
- <td class="checkoutTotalSum" style="border-bottom: 1px solid #E0E0E0;">
- <j2:if test="$[jvar_show_price_block]">
- <div><g2:currency_format double="$[jvar_subtotal_block]"/></div>
- </j2:if>
- <j2:if test="$[!jvar_show_price_block]">
- <div>-</div>
- </j2:if>
- <j2:if test="$[freq_name != 'none']">
- <div class="checkout_recurring_price_subtotal">+ <g2:currency_format double="$[jvar_recurring_subtotal_block]"/> $[sc_cat_item.recurring_frequency.getDisplayValue()]</div>
- </j2:if>
- </td>
- </tr>
- </j2:if>
- <tr>
- <td colspan="4">$[AMP]nbsp;<br/></td>
- <j2:if test="$[!jvar_never_show_price]">
- <td colspan="2"/>
- </j2:if>
- </tr>
- </j2:forEach>
- <j2:if test="$[!jvar_never_show_price and jvar_freq_list.length != 1]">
- <thead class="checkout_title">
- <j2:if test="$[jvar_never_show_price]">
- <th style="font-size: 0px;" colspan="4">$[AMP]nbsp;</th>
- </j2:if>
- <j2:if test="$[!jvar_never_show_price]">
- <th style="font-size: 0px;" colspan="6">$[AMP]nbsp;</th>
- </j2:if>
- </thead>
- <tr style="border-bottom: 0px;">
- <td/>
- <td/>
- <td/>
- <td/>
- <td class="checkoutTotalLabel">${gs.getMessage('Total')}</td>
- <td class="checkoutTotalSum" style="border-bottom: 1px solid #E0E0E0;">
- <j2:if test="$[jvar_show_price]">
- <div><g2:currency_format double="$[jvar_total_price]"/></div>
- </j2:if>
- <j2:if test="$[!jvar_show_price]">
- <div>-</div>
- </j2:if>
- </td>
- </tr>
- <tr style="border-bottom: 0px;">
- <td colspan="4">$[AMP]nbsp;<br/></td>
- <j2:if test="$[!jvar_never_show_price]">
- <td colspan="2"/>
- </j2:if>
- </tr>
- </j2:if>
- <j2:if test="$[jvar_got_one == false]">
- <tr>
- <td>
- <p class="order_details">${gs.getMessage('Cart is empty')}</p>
- </td>
- </tr>
- </j2:if>
- </table>
- <j:if test="${jvar_two_step == true}">
- <p class="order_details">
- ${gs.getMessage('If this request is for someone other than yourself please provide detailed information in the fields provided below.')}
- </p>
- <table class="wide" cellspacing="0" cellpadding="3">
- <j:set var="ref" value="sc_cart" />
- <j:set var="jvar_skip_attachment_footer" value="true" />
- <j2:set var="jvar_ref" value="$[sc_cart.requested_for]"/>
- <j2:set var="jvar_ref_display" value="$[sc_cart.requested_for.getDisplayValue()]" />
- <g2:evaluate var="jvar_can_delta_rf" expression="var helper = new GlideappCalculationHelper(); helper.canViewRF();"/>
- <tr class="header">
- <td width="30%" >
- ${gs.getMessage('Requested for')}:
- </td>
- <td width="70%">
- <label for="requestor_location">${gs.getMessage('Deliver to')}:</label>
- </td>
- </tr>
- <tr>
- <td>
- $[SP]
- </td>
- </tr>
- <tr>
- <td valign="top">
- <j2:if test="$[jvar_can_delta_rf == false]">
- $[sc_cart.requested_for.getDisplayValue()]
- </j2:if>
- <j2:if test="$[jvar_can_delta_rf != false]">
- <g2:catalog_requested_for />
- </j2:if>
- </td>
- <td>
- <g2:evaluate var="jvar_set_address" jelly="true">
- var jvar_set_address = jelly.jvar_can_delta_rf == "false" $[AMP]$[AMP] (sc_cart.delivery_address == null || sc_cart.delivery_address == "");
- jvar_set_address;
- </g2:evaluate>
- <j2:if test="$[jvar_set_address]">
- <g2:evaluate var="calculated_address">
- function addValue(value, extra, cond) {
- var returnValue = '';
- if (value != '') {
- returnValue += value;
- if (cond)
- returnValue += extra;
- }
- return returnValue;
- }
- function generateLocation(loc) {
- var address = '';
- var streetOK = loc.street != null $[AMP]$[AMP] loc.street != '';
- var cityOK = loc.city != null $[AMP]$[AMP] loc.city != '';
- var stateOK = loc.state != null $[AMP]$[AMP] loc.state != '';
- var zipOK = loc.zip != null $[AMP]$[AMP] loc.zip != '';
- if (streetOK || cityOK || stateOK || zipOK) {
- address += addValue(loc.street, '\n', cityOK || stateOK || zipOK);
- address += addValue(loc.city, ', ', stateOK || zipOK);
- address += addValue(loc.state, ', ', zipOK);
- address += addValue(loc.zip, ', ', true);
- }
- return address;
- }
- var calculated_address = '';
- var gr = new GlideRecord('sys_user');
- gr.addQuery('sys_id', sc_cart.requested_for);
- gr.query();
- if (gr.next()) {
- calculated_address = generateLocation(gr);
- if (calculated_address == null || calculated_address == '') {
- var loc = new GlideRecord('cmn_location');
- loc.addQuery('sys_id', gr.location);
- loc.query();
- if (loc.next())
- calculated_address = generateLocation(loc);
- }
- }
- calculated_address;
- </g2:evaluate>
- </j2:if>
- <textarea id="requestor_location" style="width: 100%" rows="4" name="requestor_location" wrap="soft" onChange="catDeliveryAddress('$[sc_cart.sys_id]', 'requestor_location');">
- <j2:if test="$[jvar_set_address]">
- $[calculated_address]
- </j2:if>
- <j2:if test="$[!jvar_set_address]">
- $[sc_cart.delivery_address]
- </j2:if>
- </textarea>
- </td>
- </tr>
- <tr>
- <td>$[SP]</td>
- </tr>
- <tr class="header" >
- <td>
- <label for="special_instructions">${gs.getMessage('Special instructions')}</label>
- </td>
- <td align="right">${gs.getMessage('Add attachment...')}
- <a onclick="saveCartAttachment('$[sc_cart.sys_id]');">
- <img src="images/icons/attachment.gifx" width="16" height="16"
- border="0" alt="${gs.getMessage('Attachments')}" title="${gs.getMessage('Attachments')}"/>
- </a>
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <g:inline template="attachment_list.xml" />
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <textarea id="special_instructions" style="width: 100%" rows="6"
- name="special_instructions" wrap="soft"
- onChange="catSpecialInstructions('$[sc_cart.sys_id]', 'special_instructions');" >
- $[sc_cart.special_instructions]
- </textarea>
- </td>
- </tr>
- </table>
- <table class="wide" cellspacing="0">
- <j:if test="${jvar_suppress_buttonbar != 'true'}">
- <tr>
- <td align="left">
- <j2:set var="jvar_show_back" value="$[gs.getProperty('glide.sc.checkout.twostep.back')]" />
- <j2:if test="$[jvar_show_back == 'true']">
- <j2:if test="$[sysparm_guide != 'true']">
- <a href="#" class="request_catalog_button" onclick="window.location='catalog_home.do?sysparm_view=catalog_default'; return false;">
- ${gs.getMessage('Back to Catalog');}
- </a>
- </j2:if>
- <j2:if test="$[sysparm_guide == 'true']">
- <a href="#" class="request_catalog_button" onclick="window.location='service_catalog.do?sysparm_action=restart_guide&sysparm_ck=$[gs.getSessionToken()]'; return false;">
- ${gs.getMessage('Choose Options');}
- </a>
- </j2:if>
- </j2:if>
- </td>
- <j2:if test="$[sysparm_guide != 'true']">
- <td style="width: 100%">
- </td>
- </j2:if>
- <j2:if test="$[sysparm_guide == 'true']">
- <g2:evaluate var="not_important" expression="
- var returnToCatalogHome = 'false';
- var guide = '$[sysparm_order_guide]';
- var og = new GlideappOrderGuide(guide);
- if (og.isOrderToCart())
- returnToCatalogHome = 'true';
- "/>
- <j2:if test="$[returnToCatalogHome != 'true']">
- <td style="width: 100%">
- </td>
- </j2:if>
- <j2:if test="$[returnToCatalogHome == 'true']">
- <td style="width: 50%">
- </td>
- <td align="center">
- <a href="#" class="request_catalog_button"
- onclick="window.location='catalog_home.do?sysparm_view=catalog_default'; return false;">
- ${gs.getMessage('Back to Catalog');}
- </a>
- </td>
- <td style="width: 50%">
- </td>
- </j2:if>
- </j2:if>
- <td align="right">
- <a href="#" class="request_catalog_button" type="submit" value="sysverb_insert" onClick="return gsftSubmit(this);" id="sysverb_insert">
- ${gs.getMessage('Submit Order');}
- </a>
- </td>
- </tr>
- </j:if>
- </table>
- <j2:set var="jvar_address" value="$[sc_cart.delivery_address]"/>
- <j2:set var="jvar_p2flow_all_visible_fields" value="requested_for" />
- <g:client_script tableName="sc_cart" type="phase1"/>
- <g2:client_script tableName="sc_cart" file="$[sc_cart]"/>
- </j:if>
- </form>
- <script language="javascript">
- gel('sc_cart.do').onsubmit = function(e) {
- saraCheckout();
- e.preventDefault();
- return false;
- };
- function saraCheckout() {
- //
- var currentUser = "${gs.getUserName()}";
- console.log('Current user is ' + currentUser);
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', currentUser);
- rec.query(function(rec) {
- if (rec.next()) {
- console.log('Token found: ' + rec.u_access_token);
- // go to 'Order Status' page
- window.location='service_catalog.do?sysparm_action=checkout';
- } else {
- console.log('Token not found, please provide your credentials to request tokens');
- // pop out username/password dialog
- var dialog = new GlideDialogWindow("sara_oauth_authentication");
- dialog.setPreference("cart_action", "checkout");
- dialog.setTitle("SARA OAuth Credentials");
- dialog.removeCloseDecoration();
- dialog.render();
- return;
- }
- });
- return false;
- }
- </script>
- </j:jelly>
- ]]></xml>
- </ui_macro>
- </ui_macros>
- <workflows>
- <workflow>
- <name>SaraService</name>
- <description>Sara Service workflow</description>
- <start/>
- <table>sc_req_item</table>
- <active>true</active>
- <published>true</published>
- <stages>
- <stage>
- <name>Initializing</name>
- <order>50</order>
- <value>initializing</value>
- <ola/>
- </stage>
- <stage>
- <name>Transfered</name>
- <order>100</order>
- <value>transfered</value>
- <ola/>
- </stage>
- <stage>
- <name>Active</name>
- <order>200</order>
- <value>active</value>
- <ola/>
- </stage>
- <stage>
- <name>Transfer Failed</name>
- <order>300</order>
- <value>transfer_failed</value>
- <ola/>
- </stage>
- <stage>
- <name>Ended OK</name>
- <order>300</order>
- <value>ended_ok</value>
- <ola/>
- </stage>
- <stage>
- <name>Ended Failed</name>
- <order>300</order>
- <value>ended_failed</value>
- <ola/>
- </stage>
- <stage>
- <name>Completed</name>
- <order>1000</order>
- <value>completed</value>
- <ola/>
- </stage>
- </stages>
- <activities>
- <activity>
- <name>Begin</name>
- <activity_definition>Begin</activity_definition>
- <stage/>
- <width>80</width>
- <height/>
- <x>20</x>
- <y>20</y>
- <snsc_name>begin</snsc_name>
- </activity>
- <activity>
- <name>Initialize</name>
- <activity_definition>Timer</activity_definition>
- <stage>Initializing</stage>
- <width/>
- <height/>
- <x>70</x>
- <y>170</y>
- <snsc_name>initialize</snsc_name>
- <variables>
- <variable>
- <name>timer_type</name>
- <value>script</value>
- </variable>
- <variable>
- <name>script</name>
- <value><![CDATA[workflow.debug('Initializing ...');
- workflow.debug('Workflow started by ' + current.opened_by.user_name);
- workflow.scratchpad.openedBy = current.opened_by.user_name;
- // Set 'answer' to the number of seconds this timer should wait
- answer = 2;
- ]]></value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Invoke Consume URL</name>
- <activity_definition>Run Script</activity_definition>
- <stage>Transfered</stage>
- <width/>
- <height/>
- <x>200</x>
- <y>310</y>
- <snsc_name>invoke_consume</snsc_name>
- <variables>
- <variable>
- <name>script</name>
- <value><![CDATA[var restClient = new SaraRestClient();
- restClient.setMIDServer(SaraCommon.getMidServer());
- var oauthClient = new SaraOAuthClient(restClient);
- // get tokens, store tokens in workflow scratchpad
- var tokens = oauthClient.getUserTokens(workflow.scratchpad.openedBy);
- if (!tokens) {
- workflow.debug("Cannot find access tokens for this user '" + workflow.scratchpad.openedBy + "'. Order will be skipped");
- workflow.cancel(current);
- }
- workflow.scratchpad.tokens = { 'accessToken': tokens[0], 'refreshToken': tokens[1], 'tokenType': tokens[3] };
- // get service name & consume URL
- var serviceName, consumeUrl, varSetId;
- var catId = current.cat_item.sys_id;
- var rec = new GlideRecord('u_sara_definition');
- rec.addQuery('u_sc_item', catId);
- rec.query();
- if (rec.next()) {
- serviceName = rec.u_name;
- consumeUrl = rec.u_consume_url;
- varSetId = rec.u_sara_var_set.sys_id;
- }
- consumeUrl = SaraUtils.buildUrl(consumeUrl);
- workflow.debug('Service name = ' + serviceName);
- workflow.debug('Consume URL = ' + consumeUrl);
- workflow.debug('Cat item: ' + current.cat_item.name);
- var payload = {};
- var payloadFields = {};
- payload.fieldvalues = payloadFields;
- // looping over Sara variable set to build the payload
- rec = new GlideRecord('u_sara_variable');
- //rec.addQuery('name', i);
- rec.addQuery('variable_set.sys_id', varSetId);
- rec.query();
- while (rec.next()) {
- var varName = rec.name;
- var v = current.variables[varName];
- payloadFields[rec.u_name] = [v.getDisplayValue()];
- workflow.debug(varName + " = " + [v.getDisplayValue()]);
- }
- var json = new JSON();
- var payloadStr = json.encode(payload);
- workflow.debug(payloadStr);
- workflow.scratchpad.executionHref = null;
- // make request
- if (serviceName) {
- workflow.debug('Invoking consume URL...');
- var request = restClient.newServiceRequest('Consume Request', 'post', consumeUrl);
- request.setContent('${payload}');
- request.addHeader('content-type', 'application/json;charset=UTF-8');
- request.setStringParameterWithoutEscaping('payload', payloadStr);
- // add Authorization header
- request.addHeader('Authorization', tokens[3] + ' ' + tokens[0]);
- var response = restClient.execute(request);
- //
- if (response && response.getStatusCode() == 401) {
- var resObj = new JSONParser().parse(response.getBody());
- var error = resObj['error'];
- if (error == 'expired_token') {
- workflow.debug('User token is expired, issuing request to refresh token ...');
- // issue a refresh request
- var tokens = oauthClient.refreshToken(workflow.scratchpad.openedBy);
- if (tokens && !tokens.error) {
- workflow.debug('Token refresh finished successfully');
- workflow.debug('Got new tokens: ' + new JSON().encode(tokens));
- oauthClient.storeUserTokens(workflow.scratchpad.openedBy, tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
- workflow.scratchpad.tokens = { 'accessToken': tokens['access_token'], 'refreshToken': tokens['refresh_token'], 'tokenType': tokens['token_type'] };
- workflow.debug('Making new consume request...');
- // re-initiate consume request with new token
- request = restClient.newServiceRequest('Consume Request', 'post', consumeUrl);
- request.setContent('${payload}');
- request.addHeader('content-type', 'application/json');
- request.setStringParameterWithoutEscaping('payload', payloadStr);
- request.addHeader('Authorization', tokens['token_type'] + ' ' + tokens['access_token']);
- response = restClient.execute(request);
- } else {
- workflow.debug('Refresh token finished unsuccessfully.');
- if (tokens != null) {
- workflow.debug('Error: ' + tokens.error);
- oauthClient.removeUserToken(workflow.scratchpad.openedBy);
- }
- workflow.cancel(current);
- }
- } else if (error = 'invalid_token') {
- workflow.debug('You\'ve got invalid tokens, please try again or contact administrator to solve this problem');
- // invalidate token
- oauthClient.removeUserToken(workflow.scratchpad.openedBy);
- workflow.cancel(current);
- }
- }
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- workflow.debug('Request failed.');
- workflow.debug(new JSON().encode(response));
- if (response && response.getStatusCode()) {
- workflow.debug("Status code: " + response.getStatusCode() + ", error message: " + response.getBody());
- } else if (response) {
- workflow.debug('No response from server, error message: ' + response.errorMessage);
- } else workflow.debug('Response Null');
- workflow.debug("Order process FAILED.");
- } else {
- workflow.debug('Successfully transfered.');
- workflow.debug('Response: ' + response.getBody());
- var resObj = json.decode(response.getBody());
- var runId = resObj['runID'];
- var executionHref = resObj['_links']['self']['href'];
- workflow.debug('Got runId: ' + runId);
- workflow.debug('Got execution href: ' + executionHref);
- workflow.scratchpad.runId = runId;
- workflow.scratchpad.executionHref = executionHref;
- }
- } else {
- workflow.debug("Failed to make consume request as no service definition was defined.");
- }
- ]]></value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Check consume result</name>
- <activity_definition>If</activity_definition>
- <stage>Transfered</stage>
- <width/>
- <height/>
- <x>310</x>
- <y>450</y>
- <snsc_name>check_consume</snsc_name>
- <variables>
- <variable>
- <name>script</name>
- <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
- //
- // For example,
- //
- answer = ifScript();
- function ifScript() {
- return (workflow.scratchpad.executionHref != null ? 'yes' : 'no');
- }
- ]]></value>
- </variable>
- <variable>
- <name>advanced</name>
- <value>1</value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Wait for 5 seconds</name>
- <activity_definition>Timer</activity_definition>
- <stage>Active</stage>
- <width/>
- <height/>
- <x>490</x>
- <y>280</y>
- <snsc_name>wait_for_5</snsc_name>
- <variables>
- <variable>
- <name>timer_type</name>
- <value>script</value>
- </variable>
- <variable>
- <name>script</name>
- <value><![CDATA[// Set 'answer' to the number of seconds this timer should wait
- answer = 5;
- ]]></value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Retrieve Execution Status</name>
- <activity_definition>Run Script</activity_definition>
- <stage>Active</stage>
- <width/>
- <height/>
- <x>730</x>
- <y>320</y>
- <snsc_name>retrieve_status</snsc_name>
- <variables>
- <variable>
- <name>script</name>
- <value><![CDATA[// input: response object from consume request
- var restClient = new SaraRestClient();
- restClient.setMIDServer(SaraCommon.getMidServer());
- var executionHref = SaraUtils.buildUrl(workflow.scratchpad.executionHref);
- var request = restClient.newServiceRequest('Sara Check Execution Status', 'get', executionHref);
- request.addHeader('Authorization', workflow.scratchpad.tokens['tokenType'] + ' ' + workflow.scratchpad.tokens['accessToken']);
- workflow.scratchpad.ended = 'unknown';
- var counter = 1;
- while (counter <= 300) {
- workflow.debug(counter + ': Waiting for execution checking response ...');
- //var response = restClient.execute(request);
- var response = restClient.executeWithRefreshToken(request);
- if (!response || response.getStatusCode() < 200 || response.getStatusCode() > 299) {
- if (response && response.getStatusCode()) {
- workflow.debug("Status code: " + response.getStatusCode() + ", error message: " + response.getBody());
- } else if (response) workflow.debug('No response from server, error message: ' + response.errorMessage);
- else workflow.debug('Response Null');
- workflow.debug('Stop retrieving execution status now.');
- break;
- } else {
- workflow.debug('Response received: ' + response.getBody());
- var parser = new JSONParser();
- var resObj = parser.parse(response.getBody());
- var status = resObj.statusCode;
- workflow.debug('Status code: ' + status + ', statusText: ' + resObj.statusText);
- // Status code >= 1800 -> Task ended with ended code, otherwise, it is running
- if (status >= 1800) {
- if (status == '1900' || status == 1900) {
- workflow.debug('Execution finished successfully!');
- workflow.scratchpad.ended = 'ENDED_OK';
- } else {
- workflow.scratchpad.ended = status +' - '+resObj.statusText;
- }
- break;
- } else {
- // Status code < 1800 -> Task is active or running...
- //workflow.debug('');
- }
- }
- counter++;
- gs.sleep(2000);
- }
- ]]></value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Check Execution Result</name>
- <activity_definition>If</activity_definition>
- <stage>Active</stage>
- <width/>
- <height/>
- <x>970</x>
- <y>310</y>
- <snsc_name>check_result</snsc_name>
- <variables>
- <variable>
- <name>script</name>
- <value><![CDATA[// This script needs to set answer to 'yes' or 'no' to indicate the state of the activity.
- answer = ifScript();
- function ifScript() {
- return (workflow.scratchpad.ended == 'ENDED_OK'?'yes':'no');
- }
- ]]></value>
- </variable>
- <variable>
- <name>advanced</name>
- <value>1</value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Consume Request Failed</name>
- <activity_definition>Log Message</activity_definition>
- <stage>Transfer Failed</stage>
- <width/>
- <height/>
- <x>985</x>
- <y>505</y>
- <snsc_name>consume_failed</snsc_name>
- <variables>
- <variable>
- <name>message</name>
- <value>Consume request failed, order skipped.</value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Successfully Ended</name>
- <activity_definition>Log Message</activity_definition>
- <stage>Ended OK</stage>
- <width/>
- <height/>
- <x>1200</x>
- <y>280</y>
- <snsc_name>ended_ok</snsc_name>
- <variables>
- <variable>
- <name>message</name>
- <value>Workflow finished successfully.</value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>Ended NOT OK</name>
- <activity_definition>Log Message</activity_definition>
- <stage>Ended Failed</stage>
- <width/>
- <height/>
- <x>1280</x>
- <y>410</y>
- <snsc_name>ended_not_ok</snsc_name>
- <variables>
- <variable>
- <name>message</name>
- <value>Workflow finished NOT OK.</value>
- </variable>
- </variables>
- </activity>
- <activity>
- <name>End</name>
- <activity_definition>End</activity_definition>
- <stage/>
- <width/>
- <height/>
- <x>1500</x>
- <y>520</y>
- <snsc_name>end</snsc_name>
- </activity>
- </activities>
- <transitions>
- <transition>
- <from>begin</from>
- <to>initialize</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>initialize</from>
- <to>invoke_consume</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>invoke_consume</from>
- <to>check_consume</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>check_consume</from>
- <to>wait_for_5</to>
- <condition>
- <name>Yes</name>
- <condition>activity.result == 'yes'</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>check_consume</from>
- <to>consume_failed</to>
- <condition>
- <name>No</name>
- <condition>activity.result == 'no'</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>consume_failed</from>
- <to>end</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>wait_for_5</from>
- <to>retrieve_status</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>retrieve_status</from>
- <to>check_result</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>check_result</from>
- <to>ended_ok</to>
- <condition>
- <name>Yes</name>
- <condition>activity.result == 'yes'</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>check_result</from>
- <to>ended_not_ok</to>
- <condition>
- <name>No</name>
- <condition>activity.result == 'no'</condition>
- <order>2</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>ended_ok</from>
- <to>end</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- <transition>
- <from>ended_not_ok</from>
- <to>end</to>
- <condition>
- <name>Always</name>
- <condition>true</condition>
- <order>1</order>
- <description/>
- </condition>
- </transition>
- </transitions>
- </workflow>
- </workflows>
- <wizards>
- <wizard>
- <name>Automic OAuth Configuration</name>
- <type>expert</type>
- <roles>admin</roles>
- <first_panel>OAuth Client</first_panel>
- <variables>
- <variable>
- <name>client_id</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>Client ID</question>
- <order>100</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>OAuth Client</panel>
- </variable>
- <variable>
- <name>client_secret</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>Client Secret</question>
- <order>200</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>OAuth Client</panel>
- </variable>
- <variable>
- <name>sapi_endpoint</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>SAPI Endpoint</question>
- <order>300</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>OAuth Client</panel>
- </variable>
- <variable>
- <name>token_endpoint</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>Token Endpoint</question>
- <order>400</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>OAuth Client</panel>
- </variable>
- <variable>
- <name>auth_endpoint</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>Authorization Endpoint</question>
- <order>500</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>OAuth Client</panel>
- </variable>
- </variables>
- <panels>
- <panel>
- <name>OAuth Client</name>
- <title>OAuth Client</title>
- <class>expert_panel</class>
- <description>Prepare Service Now OAuth Client for SARA</description>
- <previous_message>Previous</previous_message>
- <next_message>Store OAuth Client Settings</next_message>
- <complete_message>Done</complete_message>
- <client_script>
- <name>SARA OAuth Client OnLoad</name>
- <active>true</active>
- <type>onLoad</type>
- <script><![CDATA[function onLoad() {
- // load existing properties if available to form
- var props = ['client_id', 'client_secret', 'sapi_endpoint', 'token_endpoint', 'auth_endpoint'];
- for (i = 0; i < props.length; i++) {
- var name = props[i];
- g_form.setMandatory(name, true);
- if (name == "client_secret"){
- g_form.getControl('client_secret').type="password";
- }
- var rec = new GlideRecord('sys_properties');
- var propName = 'com.automic.sara.' + name;
- var ga = new GlideAjax("SaraCommonAjax");
- ga.addParam("sysparm_name","getSysProperty");
- ga.addParam("sysparm_property_name",propName);
- ga.getXMLWait();
- g_form.setValue(name , ga.getAnswer());
- }
- }
- ]]></script>
- </client_script>
- </panel>
- <panel>
- <name>Completed</name>
- <title>Complete</title>
- <class>expert_panel</class>
- <description>Complete</description>
- <previous_message>Previous</previous_message>
- <next_message>Next</next_message>
- <complete_message>Done</complete_message>
- </panel>
- </panels>
- <transitions>
- <transition>
- <from>OAuth Client</from>
- <to>Completed</to>
- <order>100</order>
- <condition/>
- <transition_script><![CDATA[gs.addInfoMessage('Storing OAuth client information into System Properties table ..');
- gs.addInfoMessage('Client ID = ' + wizard.client_id + ', Client Secret = ***, SAPI Endpoint = ' + wizard.sapi_endpoint
- + ', Token Endpoint = ' + wizard.token_endpoint + ', Authorization Endpoint = ' + wizard.auth_endpoint);
- var oauthClient = new SaraOAuthClient();
- try {
- oauthClient.storeClientSettings(wizard.client_id, wizard.client_secret, wizard.sapi_endpoint, wizard.token_endpoint, wizard.auth_endpoint);
- gs.addInfoMessage('Successfully update Automic OAuth client settings');
- } catch (err) {
- gs.addInfoMessage('Failed to update Automic OAuth client settings');
- gs.log('Error on update Automic OAuth client settings: '+err,'SARA');
- }
- ]]></transition_script>
- </transition>
- </transitions>
- </wizard>
- <wizard>
- <name>Automic Import Services</name>
- <type>expert</type>
- <roles>admin</roles>
- <first_panel>Import Services</first_panel>
- <variables>
- <variable>
- <name>sara_oauth_sysid</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>Sara OAuth SysId</question>
- <order>400</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>Import Services</panel>
- </variable>
- <variable>
- <name>sara_username</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>SARA Username</question>
- <order>100</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>Import Services</panel>
- </variable>
- <variable>
- <name>sara_password</name>
- <type>6</type>
- <class>expert_variable</class>
- <question>SARA Password</question>
- <order>200</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <panel>Import Services</panel>
- </variable>
- <variable>
- <name>sara_target_category</name>
- <type>18</type>
- <class>expert_variable</class>
- <question>Target Category</question>
- <order>300</order>
- <mandatory>false</mandatory>
- <active>true</active>
- <lookup_table>sc_category</lookup_table>
- <lookup_value>sys_id</lookup_value>
- <lookup_label>title</lookup_label>
- <panel>Import Services</panel>
- </variable>
- </variables>
- <panels>
- <panel>
- <name>Import Services</name>
- <title>Import Services</title>
- <class>expert_panel</class>
- <description>Import SARA services to Service Catalog. Username/password are mandatory in cyou don't have tokens or your tokens invalid or expired.</description>
- <previous_message>Previous</previous_message>
- <next_message>Import Services</next_message>
- <complete_message>Done</complete_message>
- <client_script>
- <name>SARA Import Service OnLoad</name>
- <active>true</active>
- <type>onLoad</type>
- <script><![CDATA[function onLoad() {
- // check if system properties are existed;
- var props = ['client_id', 'client_secret', 'sapi_endpoint', 'token_endpoint', 'auth_endpoint'];
- for (i = 0; i < props.length; i++) {
- var name = props[i];
- var rec = new GlideRecord('sys_properties');
- var propName = 'com.automic.sara.' + name;
- var ga = new GlideAjax("SaraCommonAjax");
- ga.addParam("sysparm_name","getSysProperty");
- ga.addParam("sysparm_property_name",propName);
- ga.getXMLWait();
- if (!ga.getAnswer()){
- g_form.addErrorMessage("OAuth Configuration '"+props[i]+"' is empty. Please check the current OAuth configuration.");
- document.getElementById('expert_next').style.display = 'none';
- break;
- }
- }
- g_form.setVisible('sara_oauth_sysid', false);
- g_form.getControl('sara_password').type="password";
- // check if Sara tokens exist for current user
- var currentUser = g_user.userName;
- var rec = new GlideRecord('u_sara_oauth');
- rec.addQuery('u_user.user_name', currentUser);
- rec.query(function(rec) {
- if (rec.next()) {
- g_form.setValue('sara_oauth_sysid', rec.u_access_token);
- // hide username and password textbox
- //g_form.setDisplay('sara_oauth_sysid',false);
- g_form.setDisplay('sara_username', false);
- g_form.setDisplay('sara_password', false);
- } else {
- g_form.setMandatory('sara_username', true);
- g_form.showFieldMsg('sara_username','Username must be formatted as: <SYSTEM_NAME>/<CLIENT>/<USER>/<DEPARTMENT>. E.g. AE10/1/BOND/BOND');
- g_form.setMandatory('sara_password', true);
- }
- });
- }
- ]]></script>
- </client_script>
- </panel>
- <panel>
- <name>Completed</name>
- <title>Complete</title>
- <class>expert_panel</class>
- <description>Complete</description>
- <previous_message>Previous</previous_message>
- <next_message>Next</next_message>
- <complete_message>Done</complete_message>
- </panel>
- </panels>
- <transitions>
- <transition>
- <from>Import Services</from>
- <to>Completed</to>
- <order>100</order>
- <condition>[sara_oauth_sysid]ISEMPTY^[sara_username]ISNOTEMPTY^EQ</condition>
- <transition_script><![CDATA[gs.addInfoMessage('Requesting tokens for user \'' + gs.getUserName() + '\' with provided credentials ... ');
- var oauthClient = new SaraOAuthClient();
- // request new tokens for this user, store in 'u_sara_oauth' table
- try {
- tokens = oauthClient.requestToken(wizard.sara_username, wizard.sara_password);
- } catch (err) {
- gs.addErrorMessage('Failed to request user tokens');
- gs.addErrorMessage('Error: ' + err);
- }
- if (!tokens || tokens['error'] || !tokens['access_token']) {
- gs.addErrorMessage('Failed to request user tokens');
- if (tokens['error']) gs.addErrorMessage('Error: ' + tokens['error'] + ', error description: ' + tokens['error_description']);
- gs.addInfoMessage('Import finished unsuccessfully');
- } else {
- gs.addInfoMessage('Obtained tokens for \'' + gs.getUserName() + '\'');
- oauthClient.storeUserTokens(gs.getUserName(), tokens['access_token'], tokens['refresh_token'], tokens['expires_in'], tokens['token_type']);
- // process import
- var tokens = oauthClient.getUserTokens(gs.getUserName());
- if (tokens.length > 0 && tokens[0]) {
- gs.addInfoMessage('Access Token = ' + tokens[0] + ', Secret Token = ' + tokens[1] + ', Token Expiry = ' + tokens[2] + ', Token Type = ' + tokens[3]);
- gs.addInfoMessage('Importing services with provided tokens ...');
- //var demo = new SaraDemo();
- var consumer = new SAPIConsumer();
- try {
- var result = consumer.discoverAndImport();
- if (!result) gs.addInfoMessage('Got no service or catalog from server');
- else gs.addInfoMessage('Imported successfully : ' + result);
- } catch (err) {
- gs.addErrorMessage('Failed to import SARA services');
- gs.addErrorMessage(err);
- }
- } else {
- gs.addErrorMessage('No token found, skip import');
- }
- }
- ]]></transition_script>
- </transition>
- <transition>
- <from>Import Services</from>
- <to>Completed</to>
- <order>100</order>
- <condition>[sara_oauth_sysid]ISNOTEMPTY^EQ</condition>
- <transition_script><![CDATA[// tokens exist, just process import
- var tokens = new SaraOAuthClient().getUserTokens(gs.getUserName());
- if (tokens.length > 0) {
- gs.addInfoMessage('Access Token = ' + tokens[0] + ', Secret Token = ' + tokens[1] + ', Token Expiry = ' + tokens[2]);
- gs.addInfoMessage('Importing services with provided tokens ...');
- //var demo = new SaraDemo();
- var consumer = new SAPIConsumer();
- try {
- //var result = demo.discoverAndImport();
- var result = consumer.discoverAndImport();
- if (!result){
- var statusCode = consumer.getStatusCode();
- var errorMessage = consumer.getErrorMessage();
- if (statusCode != 200){
- gs.addErrorMessage('Failed to import Automic services');
- gs.addErrorMessage('Got error: ' + statusCode +' - '+errorMessage );
- } else gs.addInfoMessage('Got no service or catalog from server.');
- } else gs.addInfoMessage('Imported successfully : ' + result);
- } catch (err) {
- gs.addErrorMessage('Failed to import Automic services');
- gs.addErrorMessage('Error on processing data from server');
- gs.log('Got error from import service wizard panel for case oauth_sysid is not empty: ' + err,'SARA');
- }
- } else {
- gs.addErrorMessage('No token found, skip import');
- }
- ]]></transition_script>
- </transition>
- <transition>
- <from>Import Services</from>
- <to>Completed</to>
- <order>100</order>
- <condition>[sara_oauth_sysid]ISEMPTY^[sara_username]ISEMPTY^EQ</condition>
- <transition_script><![CDATA[
- // with mandatory username/password enforced, this case actually couldn't happen
- gs.addInfoMessage('No tokens found for current user. You have to provide credentials to get tokens!');
- ]]></transition_script>
- </transition>
- </transitions>
- </wizard>
- <wizard>
- <name>Automic Clean-up</name>
- <type>expert</type>
- <roles>admin</roles>
- <first_panel>Automic Cleanup</first_panel>
- <variables>
- <variable/>
- </variables>
- <panels>
- <panel>
- <name>Automic Cleanup</name>
- <title>Cleanup Automic catalog items</title>
- <class>expert_panel</class>
- <description>Cleanup all Automic SARA stuffs. This will delete all subcategories and service items.</description>
- <previous_message>Previous</previous_message>
- <next_message>Cleanup</next_message>
- <complete_message>Done</complete_message>
- </panel>
- <panel>
- <name>Completed</name>
- <title>Cleanup Completed</title>
- <class>expert_panel</class>
- <description>Cleanup successfully!</description>
- <previous_message>Previous</previous_message>
- <next_message>Next</next_message>
- <complete_message>Done</complete_message>
- </panel>
- </panels>
- <transitions>
- <transition>
- <from>Automic Cleanup</from>
- <to>Completed</to>
- <order>100</order>
- <condition/>
- <transition_script><![CDATA[SaraUtils.cleanup();]]></transition_script>
- </transition>
- </transitions>
- </wizard>
- </wizards>
- </package>
- </sara>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement