Cookbook Recipes

Here are a few helpful scripts to get you started.

Hiding a section of your script
We encourage your scripts to be as open as possible so that others can benefit from the work you've done. However there are some things you'd like to keep to yourself, especially a consumer key and secret when connecting with other sites. To hide a section of script, simply wrap it with //#region PRIVATE and //#endregion
  var oauth2Credentials= {};

  //#region PRIVATE set my oauth2 credentials
  oauth2Credentials.consumerKey= "<your key>";
  oauth2Credentials.consumerSecret= "<your secret>";
  //#endregion

  oauth2.onAuthResponse= function(q) {  
     var args= { grant_type: "authorization_code",
                client_id: oauth2Credentials.consumerKey,
                client_secret: oauth2Credentials.consumerSecret};
     ....
  }
Every other user will see your logic but not your credentials.
  var oauth2Credentials= {};

  //#region PRIVATE set my oauth2 credentials

  oauth2.onAuthResponse= function(q) {  
     var args= { grant_type: "authorization_code",
                client_id: oauth2Credentials.consumerKey,
                client_secret: oauth2Credentials.consumerSecret};
     ....
  }

Posting a file
Apps handle file uploads in many different ways. The nice thing about Obindo is that you can use the simple json object in the message.files array. Most file uploads are done using an HTTP post (see methods):
post({url: url, header: header, args: args})
post({url: url, header: header, body: body})
For some clients, posting a file is just a matter of setting the full body of a post to the file contents. For this, you just have to set the post body to the file object.
var fileUploadUrl= "http://api.site.com/uploadFile";

function uploadFile(file) {
  var contentType = file.contentType;
  var contentLength = file.contentLength;
  var filename = file.name;
  
  var header = { "Content-Type": file.contentType,
                 "Content-Length": file.contentLength                
               };
  
  post({url: fileUploadUrl, header: header,  body: file});
}

if (message.files) {
   for (var i=0; i < message.files.length; i++)
        uploadFile(message.files[i]);
}
For other sites, uploading files is a matter of adding the file as an argument to the post. Simple posts use a simple key/value object:
var args= { title: "Lunch meeting", description: "Meeting with Gene over lunch tomorrow" };
post({url: postUrl; args: args });
There are a number of ways to set the args to upload a file based on what the site you're connecting to requires.

1. Simple file upload: setting an arg key/value to the file object.
var postUrl; "http://api.site.com/uploadFile";

//post the first file if any found
if (message.files && message.files.length > 0) {
  var  args: { 'caption': message.text, 'media[]': message.files[0] } };
  post({ url: postUrl, args: args);
}
2. Overriding file properties. In the previous example, we automatically set additional properties of the file post argument. You can override those if you would like.
var postUrl; "http://api.site.com/uploadFile";

//post the first file if any found
if (message.files && message.files.length > 0) {
  var file= message.files[0];
  var attachmentArg= { contentType: "image/png", fileName: "a.png", value: file };
  var  args: { 'caption': message.text, attachment1: attachmentArg };
  post({ url: postUrl, args: args);
}
3. An array of arguments. Some sites' documentation will show the raw post, not in any name/value format. We handle that too by setting the args property to an array objects where the name can be set, but isn't necessary.
var fileUploadUrl= "http://api.site.com/uploadFile";

function uploadFile(file, title, description) {
  var fileDetails= { title: title, description: description; }
  var args= [];
  args.push({ value: util.stringify(fileDetails), contentType: "application/json" });

  args.push({ value: file });
  //or
  args.push({ value: file, name: "attachment" })
  //or
  args.push({ value: file, name: "attachment", fileName: file.name, contentType: file.contentType })
  
  post({url: fileUploadUrl, args: args});
}

if (message.files) {
   for (var i=0; i < message.files.length; i++)
        uploadFile(message.files[i], message.subject, message.text);
}
With the args array, it's also possible to upload multiple files at once if the site allows.
var albumUrl= "http://api.site.com/albums";

function createAlbum(files, albumName) {
  var args= [{ name: "albumName", value: albumName }];

  for (var i=0; i < files.length; i++)
       args.push({ name: "attachment" + (i+1), value: files[i] });
  
  post({url: albumUrl, args: args});
}

if (message.files)
   createAlbum(message.files, message.subject);
Note: With file posts, you usually don't have to worry about the post "Content-Type" header or boundary. We take care of that, and notice whether or not you've added a file as an argument. We use "multipart/form-data" by default. If you would like to override that (or override the multipart boundary), you can manually set the "Content-Type" header.

OAuth 2 with a fixed url
When registering for OAuth 2 access on a site (step 1 of OAuth 2), some sites require that you enter in one (or several) domains to which the user will be redirected after granting authorization on their site. For these sites, you will have to enter in http://www.obindo.com. Other sites don't require this configuration at all.

Finally there are ones that require not just the domain but the exact url to which the user will be redirected. This requires a bit more configuration. The reason: We like to keep the authorization process as stateless as possible. This means that:
  1. we don't store a session variable or anything on our site for use before and after the remote authorization
  2. we include an identifier for the user and your script in the url returned by the oauth2.getCallbackUrl() method. This is typically passed to the remote site in the querystring when redirecting for authorization. They redirect back to this url and we can load the user's information.

To accommodate sites with this requirement, you must add a few steps to your script.

1. When filling out the initial configuration on the site, use the following redirect url:
http://www.obindo.com/auth/<your-script-name>/response

2. If the redirect url is needed in the script at all (sometimes it must be passed for further authententication), you can use oauth2.getCallbackUrl(true). This returns the url listed above.

3. In the oauth2.onAuthResponse method (called after the user has granted authorization on the remote site and is now back at Obindo), the tokens object must be initialized to point to the current user before the access token can be saved. This can be done with the methods tokens.loadFromId(id) or tokens.loadFromEmailAddress(email).

Most sites out there allow you to pass an identifier in the querystring which they will pass right back in the redirect querystring (the argument is usually named state). If this is offered, you can pass the user's token id to the remote site, then use it to initiate the tokens object after they've granted authorization:
var authorizeUrl, tokenUrl;

oauth2.getAuthRedirectUrl= function() {
  var args= { state: tokens.getId(), 
              redirect_uri: oauth2.getCallbackUrl(true), 
              //other args
            };  
  return authorizeUrl + '?' + util.getQueryArgsFromObject(args);
}

oauth2.onAuthResponse= function(q) {
  var authResponse= util.getObjectFromQueryArgs(q);
  
  var args= { //access token args 
            };
  
  var url= tokenUrl + '?' + util.getQueryArgsFromObject(args);
  var accessResponse= post({ url: url });
  
  tokens.loadFromId(authResponse.state);
  tokens.accessToken= util.jsonify(accessResponse.text);
}
If this is not available, the other option is to make a subsequent call to the remote site inside oauth2.onAuthResponse, retrieve user information (including email address), then load the tokens object using tokens.loadFromEmailAddress(email).

If you are attempting to write a script and find that neither of these options work for you, please let us know. Thanks.