{"id":256,"date":"2014-01-19T20:11:05","date_gmt":"2014-01-19T20:11:05","guid":{"rendered":"http:\/\/blogs.nd.edu\/devops\/?p=256"},"modified":"2014-01-19T20:11:05","modified_gmt":"2014-01-19T20:11:05","slug":"google-apps-scripts-ldap-and-wookiee-steak","status":"publish","type":"post","link":"https:\/\/sites.nd.edu\/devops\/2014\/01\/19\/google-apps-scripts-ldap-and-wookiee-steak\/","title":{"rendered":"Google Apps Scripts, LDAP, and Wookiee Steak"},"content":{"rendered":"<p>I&#8217;ve been a Google Apps user for as long as I could score an invite code to Gmail. Then came Google Calendar, Google Docs and Spreadsheets, and a whole slew of other stuff. But as I moved from coder to whatever-I-am-now, I stopped following along with the new stuff Google and others kept putting out there. I mean, I&#8217;m vaguely aware of Google Apps Engine and something called Google Apps Script, but I hadn&#8217;t spent any real time looking at them.<\/p>\n<p>But as any good IT professional should, I&#8217;m not afraid to do a little scripting here any there to accomplish a task. It&#8217;s fairly common to get a CSV export that needs a little massaging or find a perfect API to mash up with some other data.<\/p>\n<p>The other day, I found myself working with some data in a Google Spreadsheet and thinking about one of my most common scripting tasks &#8211; appending data to existing data. For instance, I start with something like a list of users and want to know whether they are faculty, staff, or student.<\/p>\n<table>\n<tbody>\n<tr>\n<th style=\"color: #fff\">netid<\/th>\n<th style=\"color: #fff\">name<\/th>\n<th style=\"color: #fff\">Affiliation<\/th>\n<\/tr>\n<tr>\n<td>cgrundy1<\/td>\n<td>Chas Grundy<\/td>\n<td>???<\/td>\n<\/tr>\n<tr>\n<td>katie<\/td>\n<td>Katie Rose<\/td>\n<td>???<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Aside: Could I get this easily by searching <a href=\"http:\/\/eds.nd.edu\">EDS<\/a>? Sure. Unfortunately, my data set might be thousands of records long and while I could certainly ask our friends in identity management to get me the bulk data I want, they&#8217;re busy and I might need it right away. Or at least, I&#8217;m impatient and don&#8217;t want to wait. Oh, and I need something like this probably once or twice a week so I&#8217;d just get on their nerves. Moving on&#8230;<\/p>\n<p>So that&#8217;s when I began to explore <a href=\"https:\/\/developers.google.com\/apps-script\/\">Google Apps Script<\/a>. It&#8217;s a Javascript-based environment to interact with various Google Apps, perform custom operations, or <em>access external APIs<\/em>. This last part is what got my attention.<\/p>\n<p>First, let&#8217;s think about how we might use a feature like this. Imagine the following function:<\/p>\n<p><code>=getLDAPAttribute(\"cgrundy1\",\"ndPrimaryAffiliation\")<\/code><\/p>\n<p>If I passed it the NetID and attribute I wanted, perhaps this function would be so kind as to go fetch it for me. Sounds cool to me.<\/p>\n<p>Now the data I want to append lives in LDAP, but Javascript (and GA Script) can&#8217;t talk to LDAP directly. But Google Apps Script can interpret JSON (as well as SOAP or XML), so I needed a little LDAP web service. Let&#8217;s begin <a href=\"http:\/\/sethgodin.typepad.com\/seths_blog\/2005\/03\/dont_shave_that.html\">shaving the yak<\/a>. Or we could <a href=\"http:\/\/www.shavenwookie.com\/\">shave a wookiee<\/a>.<\/p>\n<p><img decoding=\"async\" alt=\"Google Apps Script and LDAP API flowchart\" src=\"http:\/\/blogs.nd.edu\/devops\/files\/2014\/01\/apps-scripts-api-flowchart.png\" \/><\/p>\n<p>First, I cobbled together a quick PHP microapp and threw it into my Notre Dame web space. All it does is take two parameters, <code>q<\/code> and <code>attribute<\/code>, query LDAP, and return the requested attribute in JSON format.<\/p>\n<p>Here&#8217;s an example:<\/p>\n<p><code>index.php?q=cgrundy1&amp;attribute=ndPrimaryAffiliation<\/code><\/p>\n<p>And this returns:<\/p>\n<p><code>{<br \/>\n  \"title\": \"LDAP\",<br \/>\n    \"attributes\": {<br \/>\n      \"netid\": \"cgrundy1\",<br \/>\n      \"ndprimaryaffiliation\": \"Staff\"<br \/>\n    }<br \/>\n}<\/code><\/p>\n<p><a href=\"http:\/\/pastebin.com\/Gt3sdpQW\">View the full PHP script here<\/a><\/p>\n<p>For a little extra convenience, the script allows <code>q<\/code> to be a NetID or email address. Inputs are sanitized to avoid LDAP injections, but there&#8217;s no throttling at the script level so for now it&#8217;s up to the LDAP server to enforce any protections against abuse.<\/p>\n<p>Next, the Google Apps Script needs to actually make the request. Let&#8217;s create the custom function. In Spreadsheets, this is found under Tools &gt; Script Editor.<\/p>\n<p><code><br \/>\nfunction getLDAPAttribute(search,attribute) {<br \/>\nsearch = search.toLowerCase();<br \/>\nattribute = attribute.toLowerCase();<br \/>\nvar attr_value = \"\";<br \/>\nvar url = 'https:\/\/www3.nd.edu\/~cgrundy1\/gapps-ldap-test\/?'<br \/>\n+ 'q=' + search<br \/>\n+ '&amp;attribute=' + attribute;<br \/>\nvar response = UrlFetchApp.fetch(url);<br \/>\nvar json = response.getContentText();<br \/>\nvar data = JSON.parse(json);<br \/>\nattr_value = data.attributes[attribute];<br \/>\nreturn attr_value;<br \/>\n};<br \/>\n<\/code><\/p>\n<p>This accepts our parameters, passes them along to the PHP web service in a GET request, parses the response as JSON, and returns the attribute value.<\/p>\n<p>Nota bene: <a href=\"https:\/\/developers.google.com\/apps-script\/guides\/services\/quotas\">Google enforces quotas<\/a> on various operations including URL Fetch. The PHP script and the Google Apps Script function could be optimized, cache results, etc. I didn&#8217;t do those things. You are welcome to.<\/p>\n<p>Anyway, let&#8217;s put it all together and see how it works:<\/p>\n<p><img decoding=\"async\" alt=\"Screenshot of custom formula in action\" src=\"http:\/\/blogs.nd.edu\/devops\/files\/2014\/01\/apps-script-formula-example.png\" \/><\/p>\n<p>Well, there you have it. A quick little PHP microapp, a simple custom Javascript function, and now a bunch of cool things I can imagine doing with Google Apps. And just in case you only clicked through to this article because of the title:<\/p>\n<p>&lt;joke&gt;I tried the Wookiee Steak, but it was a little chewy.&lt;\/joke&gt;<\/p>\n<p><a href=\"http:\/\/www.shavenwookie.com\/\"><img decoding=\"async\" alt=\"\" src=\"http:\/\/blogs.nd.edu\/devops\/files\/2014\/01\/shaven-wookiee.jpg\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been a Google Apps user for as long as I could score an invite code to Gmail. Then came Google Calendar, Google Docs and Spreadsheets, and a whole slew of other stuff. But as I moved from coder to &hellip; <a href=\"https:\/\/sites.nd.edu\/devops\/2014\/01\/19\/google-apps-scripts-ldap-and-wookiee-steak\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[65095],"tags":[66,65112,65110,65113,65111],"class_list":["post-256","post","type-post","status-publish","format-standard","hentry","category-cloud-infrastructure","tag-google","tag-javascript","tag-ldap","tag-php","tag-script"],"_links":{"self":[{"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/posts\/256","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/comments?post=256"}],"version-history":[{"count":4,"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/posts\/256\/revisions"}],"predecessor-version":[{"id":264,"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/posts\/256\/revisions\/264"}],"wp:attachment":[{"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/media?parent=256"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/categories?post=256"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sites.nd.edu\/devops\/wp-json\/wp\/v2\/tags?post=256"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}