Collaboration Store, Part LX

“Failure is simply the opportunity to begin again, this time more intelligently.”
Henry Ford

Last time, I had to confess that the code that I put out didn’t actually work. At the time, I had tried several things to make it work, but none of those were successful. Since then, I have tried quite a few other things, but none of those were successful, either. Eventually, I had to actually read the documentation, which helps quite a bit, but for some reason, always seems to be my tactic of last resort. Anyway, as it turns out, I only had to make one small change to get the logo image to actually appear on the other side intact. This line from my original attempt:

request.setRequestBody(gsa.getContentBase64(attachmentGR));

… just had to be changed to this:

request.setRequestBodyFromAttachment(attachmentGR.getUniqueValue());

The setRequestBodyFromAttachment method of the sn_ws.RESTMessageV2 object accepts the sys_id of the attachment as an argument and does all of the heavy lifting of building the request body from the attachment file. Once I replaced the setRequestBody method with the setRequestBodyFromAttachment method, everything worked great. So that takes care of that little problem. Now, where were we?

Now that we have a working function to push over the images for both instances and applications, we need to go into the functions that push over the instances and applications and add a call to this function. Here is the common function created to push over an instance.

pushInstance: function(instanceGR, targetGR) {
	var result = {};

	var payload = {};
	payload.instance = instanceGR.getDisplayValue('instance');
	payload.name = instanceGR.getDisplayValue('name');
	payload.description = instanceGR.getDisplayValue('description');
	payload.email = instanceGR.getDisplayValue('email');
	payload.accepted = instanceGR.getDisplayValue('accepted');
	payload.active = instanceGR.getDisplayValue('active');
	payload.host = instanceGR.getDisplayValue('host');
	result.url = 'https://' + targetGR.getDisplayValue('instance') + '.service-now.com/api/now/table/x_11556_col_store_member_organization';
	result.method = 'POST';
	var request = new sn_ws.RESTMessageV2();
	request.setEndpoint(result.url);
	request.setHttpMethod(result.method);
	request.setBasicAuth(this.WORKER_ROOT + targetGR.getDisplayValue('instance'), targetGR.getDisplayValue('token'));
	request.setRequestHeader('Content-Type', 'application/json');
	request.setRequestHeader('Accept', 'application/json');
	request.setRequestBody(JSON.stringify(payload, null, '\t'));
	var response = request.execute();
	result.status = response.getStatusCode();
	result.body = response.getBody();
	if (result.body) {
		try {
			result.obj = JSON.parse(result.body);
		} catch (e) {
			result.parse_error = e.toString();
		}
	}
	result.error = response.haveError();
	if (result.error) {
		result.error_code = response.getErrorCode();
		result.error_message = response.getErrorMessage();
	}
	this.logRESTCall(targetGR, result, payload);

	return result;
}

As we did within the pushImageAttachment function, we can add an else to the if (result.error) condition and check to see if we need to send over the image. In this instance, not only do we need to make sure that the instance record was successfully sent over to the target instance, we also need to check if the instance record actually has a logo image. If it does, then we need to grab the image attachment record so that we can use it to make the call to the pushImageAttachment function.

result.error = response.haveError();
if (result.error) {
	result.error_code = response.getErrorCode();
	result.error_message = response.getErrorMessage();
} else {
	if (instanceGR.getValue('logo')) {
		if (result.status == '201' && result.obj) {
			var attachmentGR = new GlideRecord('sys_attachment');
			attachmentGR.get(instanceGR.getValue('logo'));
			this.pushImageAttachment(attachmentGR, targetGR, 'x_11556_col_store_member_organization', result.obj.result.sys_id);
		}
	}
}

For an application record, things get a little more complicated, as that can be either an insert or an update. Since the application record might already exist on the target system, not only do we need to make sure that the application has a logo image on the source instance, but we also need to check to make sure that the image doesn’t already exist on the target instance. Here is the code that I came up with to add to the pushApplication function.

result.error = response.haveError();
if (result.error) {
	result.error_code = response.getErrorCode();
	result.error_message = response.getErrorMessage();
} else {
	if (applicationGR.getValue('logo') > '') {
		if ((result.status == '200' || result.status == '201') && result.obj) {
			if (!result.obj.result.logo) {
				var attachmentGR = new GlideRecord('sys_attachment');
				attachmentGR.get(applicationGR.getValue('logo'));
				this.pushImageAttachment(attachmentGR, targetGR, 'x_11556_col_store_member_application', result.obj.result.sys_id);
			}
		}
	}
}

With those changes, pushing an instance record will also push over the instance’s logo image and pushing an application record will also push over that application’s logo image. At least, that will happen if you are using the shared functions built for that purpose. We are not yet using those everywhere, though, so now might be a good time to fix that. We built those functions so that they could be called from various places as needed, but we never went back and refactored the code to actually do that in all places. That sounds like a good project for our next installment.