Created
September 5, 2011 04:32
-
-
Save aishfenton/1194096 to your computer and use it in GitHub Desktop.
vWorkApp Javascript Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------------------------------------------------// | |
// vWorkApp Core Library | |
// ------------------------------------------------------------------------------------------------------------------// | |
var vWorkAppScript = vWorkAppScript || {}; | |
vWorkAppScript.host = "api.vworkapp.com"; | |
vWorkAppScript.apiToken = "PUT YOUR API KEY HERE" | |
(function() { | |
// CONFIGURATION | |
// ------------------------------------------------------------------------------------------------------------------// | |
//required fields | |
var _spreadsheet; | |
var apiToken; | |
var host; | |
//optional fields | |
var recordsPerPage = 100; | |
var dataDecorator = null; | |
// API HELPER | |
// ------------------------------------------------------------------------------------------------------------------// | |
this.loadData = function(url){ | |
var result = this.loadDataPage(url,1); | |
return [Xml.parse(result, true)]; | |
} | |
this.loadPagedData = function(url){ | |
var page = 1; | |
var results = []; | |
var result = this.loadDataPage(url,1); | |
var xmlDoc = Xml.parse(result, true); | |
var pages = parseInt(xmlDoc.getElement().getAttribute("total_pages").getValue()); | |
results.push(xmlDoc); | |
for(var i = 2; i <= pages; i++) { | |
results.push(Xml.parse(this.loadDataPage(url,i), true)); | |
} | |
return results; | |
} | |
this.loadDataPage = function(url, page) { | |
var parameters = this.generateRequestHeader("get"); | |
var requestURL = url + "&per_page="+recordsPerPage+"&page=" + page; | |
var result; | |
try { | |
result = UrlFetchApp.fetch(requestURL, parameters).getContentText(); | |
} catch(e){ | |
Logger.log("I/O Failure: "+e); | |
Browser.msgBox("We are sorry but we are unable to process your request at this time. Please try again later."); | |
} | |
return result; | |
} | |
this.postAsJSON = function(url, payload, method) { | |
if (method == null) | |
method = 'post'; | |
var args = this.generateRequestHeader( | |
method, { | |
payload: JSON.stringify(payload), | |
contentType: "application/json; charset=UTF-8" | |
} | |
); | |
UrlFetchApp.fetch(url, args); | |
}; | |
// URL HELPER | |
// ------------------------------------------------------------------------------------------------------------------// | |
this.buildURL = function(resource, ext, identifier, useThirdParty){ | |
var str = resource + ((identifier == null) ? "" : "/"+identifier) + ((ext == null) ? "" : ext); | |
return "https://" + this.host + "/2.0/"+ str + "?api_key=" + this.apiToken + ((useThirdParty) ? "&use_third_party_id=true" : ''); | |
} | |
this.explodeURLParameters = function(params){ | |
var s = ''; | |
var value; | |
for(var key in params){ | |
value = params[key]; | |
key = escape(key); value = escape(value); | |
var kvp = key+"="+value; | |
var r = new RegExp("(&|\\?)"+key+"=[^\&]*"); | |
s = s.replace(r,"$1"+kvp); | |
if(!RegExp.$1) {s += '&' + kvp;}; | |
} | |
return s; | |
} | |
this.generateRequestHeader = function(method, arguments){ | |
if (arguments == null) arguments = {}; | |
arguments['method'] = method; | |
arguments['headers'] = { "Accept-Encoding": "gzip,deflate" } | |
return arguments; | |
} | |
// JOBS | |
// ------------------------------------------------------------------------------------------------------------------// | |
this.loadJobByIdentifier = function(jobId, isThirdParty){ | |
var url = this.buildURL("jobs",".xml",jobId,isThirdParty); | |
return this.loadData(url); | |
}; | |
this.loadJobsForParameters = function(params){ | |
var url = this.buildURL("jobs",".xml") + this.explodeURLParameters(params); | |
return this.loadData(url); | |
} | |
this.loadJobsForList = function(list,useThirdParty){ | |
var jobsAsXML = []; | |
for (var idIterator = 0; idIterator < list.length; idIterator++) { | |
jobsAsXML.push(this.loadJobByIdentifier(list[idIterator].trim(),useThirdParty)); | |
} | |
return jobsAsXML; | |
} | |
this.createJob = function(customerName, templateName, duration, steps, custom_fields) { | |
var payload = { | |
job: { | |
customer_name: customerName, | |
template_name: templateName, | |
planned_duration: duration, | |
steps: steps, | |
custom_fields: custom_fields | |
} | |
}; | |
var url = this.buildURL('jobs'); | |
this.postAsJSON(url, payload); | |
} | |
this.updateJob = function(jobAsJSON){ | |
var job = {}; | |
for (var property in jobAsJSON){ | |
job[vWorkAppUtils.toUnderscore(property)] = jobAsJSON[property]; | |
} | |
var payload = { job: job }; | |
var url = this.buildURL('jobs','.xml',job.id); | |
this.postAsJSON(url, payload, 'put'); | |
} | |
this.jobFlattenCustomFields = function(job){ | |
// WARNING - this method will clone job and return all custom fields as root elements keyed on name | |
var jobClone = {}; var property; | |
for(property in job){ | |
jobClone[property] = job[property]; | |
} | |
for(property in job.customFields){ | |
jobClone[this.normalizeHeader(job.customFields[property].name)] = job.customFields[property].value; | |
} | |
return jobClone; | |
} | |
this.jobRebuildCustomFields = function(job,stdHeaders,cfHeaders){ | |
// WARNING - this method assumes that anything not in stdHeaders is a custom field keyed on name | |
var normalizedStdHeaders = vWorkAppScript.normalizeHeaders(stdHeaders); | |
var normalizedCfHeaders = vWorkAppScript.normalizeHeaders(cfHeaders); | |
var jobClone = {}; var customFields = []; var property; | |
for(property in job){ | |
if (normalizedStdHeaders.indexOf(property) == -1){ | |
if (normalizedCfHeaders.indexOf(property) == -1) | |
continue; | |
customFields.push({ | |
name:cfHeaders[normalizedCfHeaders.indexOf(property)], | |
value:job[property] | |
}); | |
continue; | |
} | |
jobClone[property] = job[property]; | |
} | |
jobClone.customFields = customFields; | |
return jobClone; | |
} | |
// PROOF OF DELIVERY | |
// ------------------------------------------------------------------------------------------------------------------// | |
this.getProofOfDeliveryURL = function(jobId){ | |
return "https://" + this.host + "/2.0/jobs/" + jobId + "/proof_of_delivery.png?api_key=" + this.apiToken; | |
} | |
// CUSTOM FIELDS | |
// ------------------------------------------------------------------------------------------------------------------// | |
// DATA PARSERS | |
// ------------------------------------------------------------------------------------------------------------------// | |
this.jobsXMLtoJSON = function(jobsXML){ | |
var jobXMLArray = jobsXML.jobs.getElements("job"); | |
if (jobXMLArray.length == 0) return {}; | |
var jobsData = []; var jobData; | |
for(var i = 0; i < jobXMLArray.length; i++) { | |
jobXML = jobXMLArray[i]; | |
jobsData.push(this.jobXMLtoJSON(jobXML)); | |
} | |
return jobsData; | |
} | |
this.jobXMLtoJSON = function(jobXML){ | |
if(jobXML.getElement('id') == null) | |
return {}; | |
var jobData = { | |
id: jobXML.getElement('id').getText(), | |
jobName: jobXML.getElement('template_name').getText(), | |
customerName: jobXML.getElement('customer_name').getText(), | |
workerName: jobXML.getElement('worker_name').getText(), | |
proofOfDelivery: (jobXML.getElement('has_pod').getText() == "true") ? this.getProofOfDeliveryURL(jobXML.getElement('id').getText()) : "", | |
steps: this.stepsXMLtoJSON(jobXML.getElement('steps')), | |
customFields: this.customFieldXMLtoJSON(jobXML.getElement('custom_fields')), | |
progressState: jobXML.getElement('progress_state').getText(), | |
actualDuration: jobXML.getElement('actual_duration').getText(), | |
plannedDuration: jobXML.getElement('planned_duration').getText(), | |
plannedStartAt: jobXML.getElement('planned_start_at').getText(), | |
plannedEndAt: jobXML.getElement('planned_end_at').getText(), | |
actualStartAt: jobXML.getElement('actual_start_at').getText() | |
} | |
if (this.dataDecorator != null) | |
this.dataDecorator.run("job", jobData); | |
return jobData; | |
} | |
this.customFieldXMLtoJSON = function(customFieldNode){ | |
var cfXMLArray = customFieldNode.getElements("custom_field"); | |
var customFieldsData = []; var customFieldData; | |
for(var c = 0; c < cfXMLArray.length; c++) { | |
var cfXML = cfXMLArray[c]; | |
customFieldData = { | |
name: cfXML.name.getText(), | |
value: cfXML.value.getText(), | |
type: cfXML.type.getText() | |
} | |
customFieldsData.push(customFieldData); | |
} | |
return customFieldsData; | |
} | |
this.stepsXMLtoJSON = function(stepNode){ | |
var stepsXMLArray = stepNode.getElements("step"); | |
var stepsData = []; var stepData; | |
for(var s = 0; s < stepsXMLArray.length; s++) { | |
var stepXML = stepsXMLArray[s]; | |
stepData = { | |
id: stepXML.id.getText(), | |
name: stepXML.name.getText(), | |
completedAt: stepXML.completed_at.getText(), | |
location: this.locationXMLtoJSON(stepXML.location) | |
} | |
stepsData.push(stepData); | |
} | |
return stepsData; | |
} | |
this.locationXMLtoJSON = function(locationNode){ | |
return { | |
id: locationNode.id.getText(), | |
formattedAddress: locationNode.formatted_address.getText(), | |
lat: locationNode.lat.getText(), | |
lng: locationNode.lng.getText() | |
} | |
} | |
// GEOUTILS | |
// ------------------------------------------------------------------------------------------------------------------// | |
this.geocodeAddress = function(address) { | |
var geocoder = Maps.newGeocoder(); | |
try { | |
var geoJSON = geocoder.geocode(address); | |
return geoJSON.results[0].geometry.location; | |
} catch(e) { | |
Logger.log("Geocoding Failed: Address is " + address); | |
return { lat: '', lng: '' }; | |
} | |
} | |
}).apply(vWorkAppScript); | |
// vWorkAppUitls - vWorkApp utility library | |
// ------------------------------------------------------------------------------------------------------------------// | |
// ------------------------------------------------------------------------------------------------------------------// | |
var vWorkAppUtils = vWorkAppUtils || {}; | |
(function() { | |
this.ISODateString = function(d){ | |
function pad(n){ return n < 10 ? '0'+ n : n } | |
return d.getUTCFullYear()+'-' | |
+ pad(d.getUTCMonth()+1)+'-' | |
+ pad(d.getUTCDate())+'T' | |
+ pad(d.getUTCHours())+':' | |
+ pad(d.getUTCMinutes())+':' | |
+ pad(d.getUTCSeconds())+'Z' | |
} | |
this.xmlDateToJavascriptDate = function(xmlDate) { | |
var re = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(Z|([+-])([0-9]{2}):([0-9]{2}))?$/; | |
var match = xmlDate.match(re); | |
if (!match) | |
return null; | |
var all = match[0]; | |
var year = match[1]; var month = match[2] - 1; var day = match[3]; | |
var hour = match[4]; var minute = match[5]; var second = match[6]; | |
var milli = match[7]; | |
var z_or_offset = match[8]; var offset_sign = match[9]; | |
var offset_hour = match[10]; var offset_minute = match[11]; | |
if (offset_sign) { | |
var direction = (offset_sign == "+" ? 1 : -1); | |
hour = parseInt(hour) + parseInt(offset_hour) * direction; | |
minute = parseInt(minute) + parseInt(offset_minute) * direction; | |
} | |
var utcDate = Date.UTC(year, month, day, hour, minute, second, (milli || 0)); | |
return new Date(utcDate); | |
} | |
this.toUnderscore = function(str){ | |
str = str.substr(0,1).toLowerCase() + str.substr(1,str.length); | |
return str.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();}); | |
} | |
this.secondsToTime = function(seconds){ | |
var h = Math.floor(seconds / (60 * 60)); | |
var divisor_for_minutes = seconds % (60 * 60); | |
var m = Math.floor(divisor_for_minutes / 60); | |
var divisor_for_seconds = divisor_for_minutes % 60; | |
var s = Math.ceil(divisor_for_seconds); | |
return h + "h "+m+"m "+s+"s"; | |
} | |
}).apply(vWorkAppUtils); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment