Try it out
Apps
Blog
About
Contact
Developers
Docs
Login
Developers
gdrive@obindo.com
Written by
Alex
Store all file attachments within an email message to Google Drive.
/************************** Documentation Links/Description: API References: https://developers.google.com/drive/v2/reference/ : https://developers.google.com/drive/v2/reference/#Files MetaData URI : https://www.googleapis.com/drive/v2/files Upload URI : https://www.googleapis.com/upload/drive/v2/files Manage Uploads: https://developers.google.com/drive/manage-uploads Example Maker : https://developers.google.com/drive/v2/reference/files/insert#try-it OAuth2 Agent : https://developers.google.com/accounts/docs/OAuth2UserAgent Must obtain the API Key from creating a Server Key on the Google API Console and inputting IP address 0.0.0.0/0 as the allowed IP address. Make sure to activate the DriveSDK and the DriveAPI on the Google API Console. OAuth Playground: https://developers.google.com/oauthplayground/ **************************/ var oauth2Credentials = {}; //#region PRIVATE set my oauth2 credentials var requestUrl = 'https://accounts.google.com/o/oauth2/auth?'; var scopeUrl = 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata'; var tokenUrl = 'https://accounts.google.com/o/oauth2/token'; var apiRoot = 'https://www.googleapis.com/drive/v2/files/'; var uploadUri = 'https://www.googleapis.com/upload/drive/v2/files'; var maxFolders= 200; //max 1000, 100 is their default var g_folders= []; //global var of all user folders var regBrackets= /\[([^\]]+?)\]/g; var defaultTitle= '(no subject)'; oauth2.getAuthRedirectUrl= function(q) { if (q) tokens.requestToken= util.getObjectFromQueryArgs(q); //create the query object to request for our "code" var args= { scope: scopeUrl, state: tokens.getId(), response_type: 'code', client_id: oauth2Credentials.clientID, redirect_uri: oauth2.getCallbackUrl(true), access_type: 'offline', approval_prompt: 'auto' }; return requestUrl + util.getQueryArgsFromObject(args); } oauth2.onAuthResponse= function(q) { var qArgs= util.getObjectFromQueryArgs(q); //exchange the code for access token var args= { grant_type: 'authorization_code', client_id: oauth2Credentials.clientID, client_secret: oauth2Credentials.clientSecret, redirect_uri: oauth2.getCallbackUrl(true), code: qArgs.code }; var response = post({url: tokenUrl, args: args}); tokens.loadFromId(qArgs.state); tokens.accessToken= util.jsonify(response.text); if (tokens.requestToken && tokens.requestToken.redirect_uri) return tokens.requestToken.redirect_uri; } oauth2.refreshAccessToken= function() { var rt= tokens.accessToken.refresh_token; //refresh our access token if it expired var args= { grant_type: "refresh_token", refresh_token: rt, client_id: oauth2Credentials.clientID, client_secret: oauth2Credentials.clientSecret }; var response= post({url: tokenUrl, args: args}); var newToken= util.jsonify(response.text); newToken.refresh_token = rt; tokens.accessToken = newToken; } function getAuthHeader() { return { "Authorization": 'Bearer ' + tokens.accessToken.access_token }; } //get tags in a string (just bracketed phrases) function getTags(m) { if (m.selections && m.selections.folderName) { //from selections! var fname= util.trim(m.selections.folderName); return (fname.length > 0) ? [fname] : []; } var s= m.subject; var arr= []; if (!s) return arr; var r= /\[([^\]]+?)\]/g; var match; while (match= regBrackets.exec(s)) { var tag= match[1].replace(/^\s+|\s+$/g,''); if (tag.length > 0) arr.push(tag); } return arr; } //if tag is like [kingdom/phylum/class], turn into array function getSearches(query) { var qs= query.replace(/\\/g,'/').split('/'); //convert forward slashes var arr= []; for (var i=0; i < qs.length; i++) { var folder= qs[i].replace(/^\s+|\s+$/g,''); if (folder.length > 0) arr.push(folder); } return arr; } function createFolder(name, folderId) { var metadata = util.stringify({title: name, mimeType: 'application/vnd.google-apps.folder', parents: [{id: folderId}]}); var header = getAuthHeader(); header["Content-Type"] = 'application/json'; var response = post({url: apiRoot, header: header, body: metadata}); return util.jsonify(response.text); } function getRootFolder() { var response = get({url: apiRoot + 'root?&key=' + oauth2Credentials.apiKey, header: getAuthHeader()}); return util.jsonify(response.text); } function getAllFolders() { var args= { q: "mimeType = 'application/vnd.google-apps.folder' and trashed = false", fields: "items(alternateLink,title,parents,id)", key: oauth2Credentials.apiKey, maxResults: maxFolders }; var response = get({url: apiRoot, args: args, header: getAuthHeader()}); return util.jsonify(response.text).items; } function createPath(folder, parentPath) { return { id: folder.id, name: folder.title, url: getFolderUrl(folder.alternateLink, folder.id), path: (parentPath) ? parentPath.path + ' > ' + folder.title : folder.title, depth: (parentPath) ? parentPath.depth + 1: 0 }; } function getFolderUrl(altUrl, id) { var i= altUrl.indexOf('folderview'); if (i < 0) return altUrl; var baseUrl= altUrl.slice(0, i).replace('docs.google.com', 'drive.google.com'); return baseUrl + '#folders/' + id; } function getChildren(paths) { var arr= []; for (var i=0; i < g_folders.length; i++) { var folder= g_folders[i]; var matches= []; for (var j=0; j < paths.length; j++) if (isChild(paths[j], folder)) matches.push(paths[j]); if (matches.length == 0) continue; var best= getBestPath(matches); arr.push(createPath(folder, best)); } return arr; function isChild(path, folder) { for (var i=0; i < folder.parents.length; i++) if (folder.parents[i].id == path.id) return true; return false; } } function getBestPath(paths) { if (!paths || paths.length == 0) return null; if (paths.length == 1) return paths[0]; var best; for (var i=0; i < paths.length; i++) { //alphabetical if on the same depth if (i == 0 || paths[i].depth < best.depth || (paths[i].depth == best.depth && paths[i].path < best.path)) { best= paths[i]; } } return best; } function getPath(tags) { var root= createPath(getRootFolder()); if (tags.length == 0) return root; var searches= getSearches(tags[0]); if (searches.length == 0) return root; g_folders= getAllFolders(); //set global var of all folders var paths= [ root ]; var bSearch= true; //search folders for match for (var i=0; i < searches.length; i++) { if (bSearch) { var children= getChildren(paths); //children all matches var matches= getMatchingPaths(searches[i], children); if (matches.length > 0) paths= matches; else bSearch= false; } if (!bSearch) { var best= getBestPath(paths); var folder= createFolder(searches[i], best.id); paths= [ createPath(folder, best) ]; } } return getBestPath(paths); } function isPathMatch(search, path) { return (search.toLowerCase() == path.name.toLowerCase()); } function getMatchingPaths(search, paths) { //return all matches of a search if (paths.length == 0) return []; var matching= []; var nextSearch= []; //don't have to search children of matches for (var i=0; i < paths.length; i++) { if (isPathMatch(search, paths[i])) matching.push(paths[i]); else nextSearch.push(paths[i]); } if (nextSearch.length == 0) return matching; var children= getChildren(nextSearch); return matching.concat(getMatchingPaths(search, children)); } function getTextBytesLength(str) { var bytes = []; for(var i = 0; i < str.length; i++) { var c = str.charCodeAt(i); bytes.push(c >>> 8); bytes.push(c & 0xFF); } return bytes.length; } function getUploadMetadata(title, folderId) { var metadata= {'title': title, 'parents': [{id: folderId }] }; return util.stringify(metadata); } function getUploadHeader(type, length){ var header = getAuthHeader(); header['Content-Type'] = type; header['Content-Length'] = length; return header; } function uploadToGdrive(file, folderID) { var metadata = getUploadMetadata(file.name, folderID); var contentLength = file.contentLength + getTextBytesLength(metadata); var header = getUploadHeader('multipart/related', contentLength); post({url: uploadUri + '?uploadType=multipart&key=' + oauth2Credentials.apiKey, header: header, args:[{contentType: 'application/json', value: metadata}, {contentType: file.contentType, value: file}]}); } //gdoc functionality function getTitle(subject) { if (!subject || subject.length == 0) return defaultTitle; var title= subject.replace(regBrackets, ' '); title= title.replace(/^\s+|\s+$/g,''); //trim title= title.replace(/\s{2,}/g,' '); //consecutive spaces return (title.length > 0) ? title : defaultTitle; } function backupEmail(content, title, type, folderId) { var metadata = getUploadMetadata(title, folderId); var contentLength = getTextBytesLength(content) + getTextBytesLength(metadata); var header = getUploadHeader('multipart/related', contentLength); post({url: uploadUri + '?uploadType=multipart&convert=true&key=' + oauth2Credentials.apiKey, header: header, args: [{contentType: 'application/json', value: metadata }, {contentType: type, value: content }] }); } function saveDocument(path, title, html, text) { if (!text) return false; if (html) backupEmail(html, title, 'text/html', path.id); else backupEmail(text, title, 'text/plain', path.id); return true; } function sendDocEmail(email, success, title, path) { var text= ''; var emailArgs= { to: email, templateFields: { recipientName: message.from.name } }; if (success) { emailArgs.subject= 'Obindo upload to Google Drive complete'; emailArgs.templateFields.buttonText= 'View in Google Drive'; emailArgs.templateFields.buttonLink= path.url; text= 'We created the document "' + title + '" and saved it to your Google Drive account.'; text+= '\n\nIt was uploaded to: ' + path.path; text+= '\n\nThanks for using Obindo!'; text+= '\n\nP.S. We currently have two email addresses for Google Drive: '; text+= 'gdoc for backing up email text and attachments, and gdrive which just backs up the files.'; text+= ' We didn\'t see any files in your email, so we just created the text document for you.'; text+= 'We\'re constantly working to make Obindo easier to use, so we\'ll let you know when '; text+= 'these email addresses get even simpler.'; } else { var src= message.source; if (src && src.type && src.type == 'getstarted') //no empty message from other source return; emailArgs.subject= 'Obindo didn\'t know what to do with that one'; text= 'Sorry we didn\'t see any attachments or email body, so didn\'t know what you wanted to save.'; text+= '\n\nPlease try again the next time you\'d like to save something to Google Drive.'; text+= '\n\nThanks for using Obindo!'; } emailArgs.text= text; sendEmail(emailArgs); } //end gdoc stuff $(function () { var count= (message.files) ? message.files.length : 0; var tags= getTags(message); var path= getPath(tags); if (count == 0) { //no files; do gdoc functionality var title= getTitle(message.subject); var success= saveDocument(path, title, message.html, message.fullText); if (success) message.appUrl= path.url; sendDocEmail(message.from.emailAddress, success, title, path); return; } var txt= 'We uploaded ' + count + ' file'; txt+= (count > 1) ? 's' : ''; txt+= ' to your Google Drive account:'; for (var i = 0; i < message.files.length; i++) { uploadToGdrive(message.files[i], path.id); txt+= '\n' + message.files[i].name; } txt+= '\n\n'+((count > 1) ? 'They were' : 'It was') + ' uploaded to: ' + path.path; txt+= '\n\nThanks for using Obindo!'; message.appUrl= path.url; sendEmail({ to: message.from.emailAddress, text: txt, subject: 'Obindo upload to Google Drive complete!', templateFields: { recipientName: message.from.name, buttonText: 'View in Google Drive', buttonLink: message.appUrl } }); });