Thursday, March 12, 2015
Enhanced object properties in the PHP and Ruby libraries
While creating and modifying hashes is straightforward, sometimes you want a true object and the benefits that come with using one, such as type checking or introspection. To enable this, the PHP and Ruby client libraries can now provide objects as the results of API calls, in addition to supporting hash responses.
Ruby gets this for free with the latest version of the gem. For PHP, you have to enable support in the client instance:
$apiClient = new apiClient();The following examples for PHP and Ruby retrieve an event via the Calendar API, and use data from the new resulting object:
$apiClient->setUseObjects(true);
PHP:
$event = $service->events->get("primary", "eventId");
echo $event->getSummary();Ruby:result = client.execute(If you have general questions about the client libraries, be sure to check out the client library forums (PHP and Ruby). For questions on specific Apps APIs come find us in the respective Apps API forum.
:api_method => service.events.get,
:parameters => {calendarId => primary,
eventId => eventId})
print result.data.summary
| Dan Holevoet profile Dan joined the Google Developer Relations team in 2007. When not playing Starcraft, he works on Google Apps, with a focus on the Calendar and Contacts APIs. Hes previously worked on iGoogle, OpenSocial, Gmail contextual gadgets, and the Google Apps Marketplace. |
Google Drawings Support added to Documents List API
Currently, we allow importing Drawings from WMF files. Drawings can be exported as PDF, JPEG, PNG, and SVG images.
This has been a feature requested by many users, so we’re happy to fulfil those requests. The release of this feature has been done in stages. You may have noticed that Drawings started showing up in list feeds a few months ago, but our most recent release marks full support for Drawings.
These features are only available in version 3.0 of the Documents List API. Users can read the updated documentation and the release notes for information on using these new features of the API. As always, if you have any questions, please visit the Documents List API support forum.
Posted by Vic Fryzel, Google Apps Team
Want to weigh in on this topic? Discuss on Buzz
5 things you didnt know you could do with the Google Drive API
Have you tried using the Google Drive API? If so, you’re aware that it allows you to programmatically manage a user’s Google Drive and build applications to manipulate files stored in the user’s account. However, the API might still be capable of doing a few things you didn’t know about. Here is a list of five specific use cases and how each of them can be addressed with the API.
1) Sharing a file with the world
When a file in Google Drive is shared publicly, it can be downloaded without authentication at the URL provided by the API in the webContentLink field of the Files resource. To retrieve that value, send a GET request to retrieve the file metadata and look for the webContentLink element in the JSON response, as in the following example:
{
"kind": "drive#file",
"id": "0B8E...",
"etag": "WtRjAP...",
"selfLink": "https://www.googleapis.com/drive/v2/files/0B8E...",
"webContentLink": "https://docs.google.com/a/google.com/uc?id=0B8E...",
...
}
2) Granting comment-only access to a user
When setting permissions for a file with the Drive API, you can choose one of owner, writer and reader as the value for the role parameter. The Drive UI also lists another role, commenter, which is not allowed for that parameter.
In order to grant comment-only access to a user with the Drive API, you have to set the role parameter to reader and include the value commenter in the list of additionalRoles, as in the following example:
{
"kind": "drive#permission",
...
"role": "reader",
"additionalRoles": [
"commenter"
],
...
}
3) Listing all files in the root folder
It is possible to restrict the list of files (and folders) returned by the Drive API by specifying some search criteria in the q query parameter. Each file has a parents collection listing all folders containing it, and the root folder in Google Drive can be conveniently addressed with the alias ‘root’. All you need to do to retrieve all files in that folder is add a search query for element with ‘root’ in their parents collection, as in the following example:
GET https://www.googleapis.com/drive/v2/files?q=root in parents
Remember to URL-encode the search query for transmission unless you are using one of the available client libraries.
4) Finding how much quota is available in the user’s account
Your application might need to know if users have enough available quota to save a file, in order to handle the case when they don’t. Quota information is available in the About feed of the Drive API:
{
"kind": "drive#about",
...
"quotaBytesTotal": "59055800320",
"quotaBytesUsed": "14547272",
"quotaBytesUsedInTrash": "511494",
...
}
The feed includes three values related to quota management: quotaBytesTotal, quotaBytesUsed and quotaBytesUsedInTrash. The first value indicates the total amount of bytes available to the user (new accounts currently get 5GB for free) while the second one tells how many of those bytes are in use. In case you need to get more free space, you can use the last value to know how many bytes are used by files that have been trashed. An application might use this value to recommend emptying the trash bin before suggesting to get additional storage.
5) Discovering if one of the user’s apps can open a file
Google Drive allows users to store any kind of file and to install applications to open file types that are not directly supported by the native Google applications. In case you need to know what applications are installed and what file types each of them can open, you can retrieve the Apps feed and look for the primaryMimeTypes and secondaryMimeTypes elements for supported MIME types or primaryFileExtensions and secondaryFileExtensions for file extensions:
{
"kind": "drive#app",
"name": "Pixlr Editor",
...
"primaryMimeTypes": [
"image/psd",
"image/pxd",
"application/vnd.google-apps.drive-sdk.419782477519"
],
"secondaryMimeTypes": [
"image/png",
"image/jpeg",
"image/gif",
"image/bmp"
],
"primaryFileExtensions": [
"pxd",
"psd"
],
"secondaryFileExtensions": [
"jpg",
"png",
"jpeg",
"bmp",
"gif"
],
…
}
Note: to access the Apps feed you have to request access to the https://www.googleapis.com/auth/drive.apps.readonly OAuth scope.
![]() | Claudio Cherubino profile | twitter | blog Claudio is an engineer in the Google Drive Developer Relations team. Prior to Google, he worked as software developer, technology evangelist, community manager, consultant, technical translator and has contributed to many open-source projects. His current interests include Google APIs, new technologies and coffee. |
Wednesday, March 11, 2015
Agile scope completion techniques
Whether you are using story cards, features or other techniques to capture your requirements, you need to answer this question: "How do I know when Ive done enough requirements gathering?" In waterfall this is ‘easy’ – gather all the detail and sign-off (ok – I’m simplifying). In agile, we depend on features or stories, but many are concerned that major scope elements will be left out which will either cause many items to grow exponentially in size or that feature X is really feature X, Y and Z. For example, when the registration screen has 50 fields instead of the 10-15 that we might have assumed, but didn’t write down. It is hard to understand how this can be done in 1 or 2 days using feature or story cards that contain only one line of description, a few lines of acceptance and a few assumptions.
Three things for you to consider to help you solve this dilemna:
1. In waterfall techniques, although we hold some comfort in our massive requirements documents, we know from experience that even then things will change and things will be missed.
2. My teams estimate using planning poker with the full team including the client and we have found this has helped to uncover hidden or unknown scope. We discuss each item together before estimating and talk about the number of screens, inputs, outputs, services etc involved. This discussion itself often uncovers additional scope, but so does the estimating that follows each discussion. For example, when most of us say ‘2’ and one person says ‘8’, the person who said ‘8’ enlightens the team on the complex caching required to meet the performance requirements listed as an Acceptance test. This is especially important if your client is the one with the highest estimate. Dont ignore it.
3. Lastly, I attended a virtual class on agile estimating that suggested another technique. For every feature or story, categorize the requirements certainty as high, medium and low. Keep challenging your client until the requirements certainty on each story is low.
Id be interested in other techniques you may be using to keep the initial requirements gathering phase light weight, yet complete. I think as an industry we are getting better at embracing the changes that are inevitable on all projects, but our clients still require us to have a good understanding of the known scope and the resulting estimate before starting the project.
Tuesday, March 10, 2015
Create a Spreadsheet User Directory with Apps Script
What is the Google Spreadsheet User Directory?
The “Google Spreadsheet User Directory” is a solution I’m frequently asked about. Google Apps Domain administrators can use a simple Apps Script that can be saved into a Google Spreadsheet and then set to run on a schedule, via a “time-driven” trigger. By using the Google Profiles API (available only for domain administrators), domain administrators can create a Google Spreadsheet which contains Google Apps domain user information.The user profile data can then be consumed and used by other business logic code, either in the spreadsheet itself or elsewhere.Using Apps Script to provide this kind of solution was an obvious choice for the following reasons.
- Apps Script makes the Google Spreadsheet User Directory a simple, flexible solution that the customer can quickly understand and extend. The JavaScript syntax is easy to learn and program in, and there is no need to compile and deploy code.
- The Apps Script code is conveniently integrated into Google Spreadsheets, so there is no need to use any other software. Advanced functions can be exposed to end users for data manipulation through the spreadsheet menu, and scheduling an Apps Script to run at a regular interval is trivial via the Spreadsheet “Triggers” mechanism.
- Google Apps Script provides services for accessing Google Profiles, Contact Info, and Google Groups plus Google Docs, Google Sites, Google Charts, and more. The Google Spreadsheet User Directory script makes use of both the new Apps Script Domain Services API and the GData Profiles API, via the “UrlFetch” service.
- The Apps Script code can be easily shared through Google Spreadsheet templates and through the Google Script gallery.
Using the Google Spreadsheet User Directory
The Google Spreadsheet User Directory code consists of a primary scanUserProfiles() function and some supporting “utility” functions. The three steps for setting up the code to run are: 1. Set up the “Consumer_Key” and “Consumer_Secret” ScriptProperties and run the scanUserProfiles() function in the Apps Script integrated development environment to get the first “Authorization Required” screen. (I’ve included an illustration below... Choose “Authorize.”).
| 2. Since scanUserProfiles() uses OAuth with UrlFetch to get User Profile information via the GData API, it needs to be run at least one more time inside of the Apps Script IDE, so that the OAuth “Authorize” prompt can be shown to the programmer and accepted. | ![]() |
Design of the Google Spreadsheet User Directory
The following snippets show the OAuth setup, the user profiles Url setup, and the initial UrlFetch.var oAuthConfig1 = UrlFetchApp.addOAuthService("googleProfiles");
oAuthConfig1.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope=https:// www.google.com/m8/feeds/profiles");
oAuthConfig1.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig1.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken?oauth_callback=https:// spreadsheets.google.com/macros");
oAuthConfig1.setConsumerKey(ScriptProperties.getProperty("Consumer_Key"));
oAuthConfig1.setConsumerSecret(ScriptProperties.getProperty("Consumer_Secret"));
var options1 = {
oAuthServiceName : "googleProfiles",
oAuthUseToken : "always",
method : "GET",
headers : {
"GData-Version" : "3.0"
},
contentType : "application/x-www-form-urlencoded"
};
var theUrl = "";
if (nextUrl == "") {
theUrl =
"https://www.google.com/m8/feeds/profiles/domain/" + domain +
"/full?v=3&max-results=" + profilesPerPass + "&alt=json";
} else {
theUrl = nextUrl;
}
if (theUrl != "DONE") {
var largeString = "";
try {
var response = UrlFetchApp.fetch(theUrl, options1);
largeString = response.getContentText();
} catch (problem) {
recordEvent_(problem.message, largeString, ss);
}
}
var provisioningJSONObj = null;The "nextUrl" variable above (line 74) is being pulled from a cell in the spreadsheet, where Im saving the "next" link from the fetched data. (If there’s no “next” link, I save "DONE" to the same spreadsheet cell.) To fetch JSON, I’m appending the parameter &;alt=json on lines 75 and 76. After I’ve got my JSON object, I create an array to store the data that I will be writing out to the spreadsheet. I set the array default values and make liberal use of try-catch blocks in this code, since there’s no telling which of these fields will be populated, and which will not.
var jsonObj = JSON.parse(largeString);
var entryArray = jsonObj.feed.entry;
for (var i=0; i<entryArray.length; i++) {
var rowArray = new Array();
rowArray[0] = "";
rowArray[1] = "";
rowArray[2] = "";
try { rowArray[0] = entryArray[i].gd$name.gd$fullName.$t; } catch (ex) {} //fullname
try { rowArray[1] = entryArray[i].gd$name.gd$givenName.$t; } catch (ex) {} //firstname
try { rowArray[2] = entryArray[i].gd$name.gd$familyName.$t; } catch (ex) {} //lastname
At the end of the data collection process for a single record/row, I add the rowArray to another single-element array called valueArray (line 207), to create a 2-D array that I can use with range.setValues to commit my data to the spreadsheet in one shot (line 209). var updateRow = getNextRowIndexByUNID_(rowArray[3],4,stageSheet);The function getNextRowIndexByUNID (line 205) just finds the next available row on the “staging” sheet of the spreadsheet, so I can write data to it. The code is inside of a “for” loop (starting on line 106) that executes once for each entry in the current JSON object (created lines 96 and 97).
var valueArray = new Array();
valueArray.push(rowArray);
var outputRange = stageSheet.getRange(updateRow, 1, 1, 12);
outputRange.setValues(valueArray);
} else {
// COPY CHANGES TO "PRODUCTION" TAB OF SPREADSHEET
var endTime = new Date();
setSettingFromArray_("LastPassEnded",getZeroPaddedDateTime_(endTime),settingsArray,setSheet);
if (parseInt(getSettingFromArray_("StagingCopiedToProduction",settingsArray)) == 0) {
// THIS DOES A TEST-WRITE, THEN A "WIPE," THEN COPIES STAGING TO
// PRODUCTION
var copied = copySheet_(ss,"Staging","Employees");
if (copied == "SUCCESS") {
var sortRange = empSheet.getRange(2,1,empSheet.getLastRow(),empSheet.getLastColumn());
sortRange.sort([3,2]); // SORT BY COLUMN C, THEN B
// RESET SETTINGS
setSettingFromArray_("NextProfileLink","",settingsArray,setSheet);
setSettingFromArray_("LastRowUpdated",0,settingsArray,setSheet);
setSettingFromArray_("StagingCopiedToProduction",1,settingsArray,setSheet);
}
}
} // end if "DONE"
If the script finds “DONE” in the “NextProfileLink” cell of the spreadsheet, it will skip doing another UrlFetch to the next feed link (line 81). Instead, it will copy all records from the “staging” sheet of the spreadsheet to the “production” one, via a utility function called “copySheet” (line 273). Then it will sort the range, reset the copy settings, and it will mark another designated cell, “StagingCopiedToProduction” as “1” in the spreadsheet, to stop any further runs that day. Scheduling the Google Spreadsheet User Directory Script to Run
Below are the triggers I typically set up for the Spreadsheet User Directory. I recommend setting scanUserProfiles() to run on an interval of less than 30 minutes, since the Google-provided token in each “NextProfileLink” url lasts about that long. I also recommend running the WipeEventLog() utility function at the end of each day, just to clear data from prior runs from the EventLog tab of the spreadsheet.
Conclusion

Using Apps Script made this solution quick and easy to produce and flexible enough to be extended and used in many different ways. The code is easy to share as well. If you’d like to give the Google Spreadsheet User Directory a try, then please copy this spreadsheet template, and modify and re-authorize it to run in your own domain. Enjoy!
![]() | Shel Davis Guest author Shel Davis is a senior consultant with Cloud Sherpas, a company recently named the Google Enterprise 2011 Partner of the Year. When Shel is not working on solutions for customers, he’s either teaching classes on Google Apps and Apps Script (Google Apps Script Training), or he’s at home, playing with his kids. |
Private Member Variables in Javascript Objects
The programming language of Google Apps Script is JavaScript (ECMAScript). JavaScript is a very flexible and forgiving language which suits us perfectly, and theres also a surprising amount of depth and power in the language. To help users get into some of the more useful power features were starting a series of articles introducing some more advanced topics.
Lets say we want to create an object that counts the number of occurrences of some event. To ensure correctness, we want to guarantee the counter cant be tampered with, like the odometer on your car. It needs to be "monotonically increasing". In other words, it starts at 0, only counts up, and never loses any previously counted events.
Heres a sample implementation:
Counter = function() {
this.value = 0;
};
Counter.prototype = {
get: function() {
return this.value;
},
increment: function() {
this.value++;
}
};
This defines a constructor called Counter which can be used to build new counter objects, initialized to a value of zero. To construct a new object, the user scripts counter = new Counter(). The constructor has a prototype object, providing every counter object with the methods counter.increment() and counter.get(). These methods count an event, and check the value of the counter, respectively. However, there is nothing to stop the script from erroneously writing to counter.value. We would like to guarantee that the counters value is monotonically increasing, but lines of code such as counter.value-- or counter.value = 0 roll the counter back, breaking our guarantee.
Most programming languages have mechanisms to limit the visibility of variables. Object-oriented languages often feature a private keyword, which limits a variables visibility to the code within the class. Such a mechanism would be ideal here, ensuring that only the methods counter.increment() and counter.get() could access value. Assuming that these two methods are correctly implemented, we can be sure that our counter cant get rolled back.
Javascript has this private variable capability as well, despite not having an actual keyword for it. Lets examine the following code:
Counter = function() {
var value = 0;
this.get = function() {
return value;
};
this.increment = function() {
value++;
};
};
This constructor gives you objects that are indistinguishable from those built with the first constructor, except that value is private. The variable value here is not the same variable as counter.value used above. In fact, the latter is undefined for all objects built with this constructor.
How does this work? Instead of making value a member variable of the object, it is a local variable of the constructor function, by use of the var keyword. The get and increment functions are the only functions that can see value because they are defined within the same code block. Only code inside this block can see value; outside code does not have access to it. However, these methods are publicly visible by having been assigned to the this object.
Limiting visibility of variables is considered a good practice, because it rules out many buggy states of your program. Make sure to use this technique wherever possible.
Cross-posted from Google Apps Script Blog
by: Jason Ganetsky, Software Engineer, Google Apps Script
Integrating Google Docs with Salesforce com using Apps Script
Editors Note: Ferris Argyle is going to present Salesforce Workflow Automation with Google Spreadsheet and Apps Script at Cloudforce. Do not miss Ferriss talk - Saurabh Gupta
As part of Googles Real Estate and Workplace Services (REWS) Green Team, the Healthy Materials program is charged with ensuring Google has the healthiest workplaces possible. We collect and review information for thousands of building materials to make sure that our offices are free of formaldehyde, heavy metals, PBDEs and other toxins that threaten human health and reduce our productivity.
A Case for using Google Docs and Salesforce.com
My team, as you might imagine, has a great deal of data to collect and manage. We recently implemented Salesforce.com to manage that data, as it can record attributes of an object in a dynamic way, is good at tracking correspondence activity and allows for robust reports on the data, among many other functions.
We needed Saleforce.com to integrate with our processes in Google Apps. We wanted to continue collecting data using a Google Docs form but needed it integrated with Salesforce.com because we:
- Liked the way the form looked and functioned
- Wanted to retain continuity for our users, including keeping the same URL
- Wanted a backup of submissions
And this is where Google Apps Script came to our rescue. We found that we could use Google Apps Script to create a new Case or Lead in Salesforce.com when a form is submitted through our Google Docs form. This allowed us to continue using our existing form and get our data directly and automatically into Salesforce.com.
Google Docs + Apps Script + Salesforce.com = Integrated Goodness!
Salesforce.com has two built-in options for capturing data online - Cases and Leads. Google Docs Forms can capture data for both of them. Set up your Case or Lead object with the desired fields in Salesforce.com. The next step is to generate the HTML for a form. You will use the IDs in the Salesforce.com-generated HTML when writing your Google Apps script.
A) Getting the HTML in Salesforce.com:
1. Login to Salesforce.com and go to Your Name > Setup > Customize > Leads or Self-Service (for Cases) > Web-to-Lead or Web-to-Case
2. Make sure Web-to-Lead/Web-to-Case is enabled. Click on Edit (Leads) or Modify (Cases) and enable if it is not.
3. Click on the Create Web to Lead Form button (for Leads) or the Generate the HTML link (for Cases)
4. Select the fields you want to capture and click Generate. Save the HTML in a text file. You can leave Return URL blank

B) Setting up Google Apps Form/Spreadsheet:
Create your form and spreadsheet (or open up the one you already have and want to keep using). This is very easy to do. Go to your Docs and click on Create to open a new form. Use the form editor to add the desired fields to your form- theyll show up as column headings in the corresponding spreadsheet. When someone fills out your form, their answers will show up in the right columns under those headings.
C) Writing the Google Apps Script:
The script is set up to take the data in specified cells from the form/spreadsheet and send it into designated fields in your Salesforce.com instance (identified by the org id in the HTML generated above). For example, the form submitters email is recorded through the form in one cell, and sent into the email field in either the Lead or Case object in Salesforce.com.
1. Create a new script (Tools > Script Manager > New).
2. Write the script below using the pertinent information from your Salesforce.com-generated code (shown further down).
function SendtoSalesforce() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var row = sheet.getLastRow();
var firstname = sheet.getRange(row, 2).getValue();
var lastname = sheet.getRange(row, 3).getValue();
var email = sheet.getRange(row, 4).getValue();
var company = sheet.getRange(row, 5).getValue();
var custom = sheet.getRange(row, 6).getValue();
var resp = UrlFetchApp
.fetch(
https://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8,
{
method: post,
payload: {
orgid : 00XXXXXXXX,
first_name : firstname,
last_name : lastname,
email : email,
company : company,
00YYYYYYYY : custom,
external : 1
}
});
Logger.log(resp.getContentText());
}
Define your variables by directing the script to the correct cell (row, column number). Then in the payload section, match the field id from your Salesforce.com HTML (red) to the variable you defined (blue). For example, the email address of the submitter is defined as variable email, can be found in the 4th column of the last row submitted, and the id for that field in Salesforce.com is email.

Note that any custom fields youve created will have an alpha-numeric id.
3. Save your script and do a test run.
D) Wiring Script to a Form Submission.
To send your data automatically into Salesforce.com, you need to set a trigger that will run the script every time a form is submitted. To do this, go to your script and click Resources>Current scripts triggers.
1. Create a Trigger for your function so that it runs when a form is submitted.

2. Post the link to your form on your website, send it in an email, link to it on G+, etc. Get it out there!
Thats it! Now when someone submits a form, the information will come into your spreadsheet, and then immediately be sent into Salesforce.com. You can adjust your Salesforce.com settings to create tasks when the information comes in, send out an auto-response to the person filling out the form and set up rules for who is assigned as owner to the record. Youll also have the information backed up in your spreadsheet.
This has been a great solution for our team, and we hope others find it useful as well!
![]() | Beth Sturgeon Beth Sturgeon is a member of Googles Green Team in Mountain View, which makes sure that Googles offices are the healthiest, most sustainable workplaces around. Prior to Google, she had a past life as a wildlife researcher. |



