跳到主要內容

發表文章

目前顯示的是有「Apps Script」標籤的文章

Detached Apps Script

通常Apps Script會Binding在一份文件上,但是使用的情境上,如果永遠讓文件與Script做Binding,就缺少了些操縱的快感.... 例如,需要動態產生表單,並且讓表單自動的Binding onFormSubmit的Event…. 下面就是這段範例,執行createFormTrigger之後,ID為 '1hCg1vS…..Qm5-Q'的文件(必須要是Form啦,這個Trigger是針對Form動作的),就會附加上onFormSubmit的Event,而Event的內容,則是同一份Script中的runCommand function,也就是由ScriptApp所new的Trigger名稱: function createFormTrigger() {  var fid = '1hCg1vS…..Qm5-Q';  // Create onEdit trigger using sheet ID  ScriptApp.newTrigger("runCommand").forForm(fid).onFormSubmit().create(); } function runCommand(){  Logger.log('TEST......' + new Date()); } 上面的Script可以搭配Driver來使用,例如指定某個Forder下的文件都要附加上某個Trigger,這樣以後Create在那個Folder下的文件,就都會具備同樣的Event...

Apps Script取出Calendar API中的htmlLink

不死心的過客,一定覺得Apps Script怎麼可能做不到呢... 既然是加密的eid...那可能可以解密 透過Apps Script的Utilities類別,我們將上篇的htmlLink後面的eid欄位取出來分析 因為比較像Base64...我們採用Base64來做解密...(可以參考: https://developers.google.com/apps-script/reference/utilities/utilities#base64Decode(String,Charset) ) 下面試測試function... function test123(){   var o = 'ZTc0Mjk4OHVicHRrdHNjM.....RhYy5jb20udHc';   Logger.log(o);   var e = Utilities.base64Decode(o, Utilities.Charset.UTF_8);   Logger.log(Utilities.newBlob(e).getDataAsString()); } 執行後,果如預期... 分析如下: 透過分析,我們可以新增build htmlLink的function如下: function getHtmlLink(id, user) {   var ori = id.split('@')[0] + ' ' + user;   var enc = Utilities.base64Encode(ori, Utilities.Charset.UTF_8);   return ' https://www.google.com/calendar/render?action=VIEW&eid='+enc.replace('= ',''); } 然後call法可以向下面這樣... function getEvents(calId, startTime, endTime) {   if(!calId || !startTime || !endTime)     return...

透過Calendar API取得Calendar URI進入Calendar Event頁面

Google的Calendar API搭配Apps Script的使用如先前所介紹,非常方便... 但是如果想要透過Apps Script來建置可以提供點選後重導到特定Google Event的功能則有先天上的限制... 這是由於Google的Calendar頁面在點選Event時候,會在同一個視窗中動作 開啟Event是透過javascript的方式使用ajax非同步load Event資訊到頁面上呈現 而load這個資訊的重要關鍵資訊就是Calendar Event中的"htmlLink"欄位 如果透過之前介紹的Apps Script取出event物件來做應用的話 目前無法取出"htmlLink"欄位... 但是Google所發送的Calendar Remind信件中 卻使用了一個快速進入特定Event的方式的鏈結 下面文章在解密這個鏈結的資訊... 相信下面的信件不陌生吧 是Google Calendar提醒開會的資訊... 注意到框起來的地方了嘛... 他是一個這樣格式的URL: https://www.google.com/calendar/event?action=VIEW&eid= ZTc0Mjk4OHV...zdUBtaXRhYy5jb20udHc 而其中紅色的地方就是目前Apps Script取不到的欄位... 如何得到htmlLink呢?可以透過 Google API Explore 來查詢 在API Explore中,Calendar API提供了一個event list的function 填入您的calendar id就可以查得該calendar的所有行事曆事項 而calendar id可以在calendar的設定中找到 如果是account的預設行事曆,則會是使用account email作為calendar id... 送出查詢之後會得到下面的結果... 其中可以看到items中有所有的event列表 而event中有個htmlLink可以作為行事曆事件的代表網頁 點選該Link則可以直接轉址到該行事曆事件頁面 如下所示: 至於Apps Script無法取出htmlLink部分...只好提供意見給Google參考啦...

批次匯入Google行事曆

在Google Apps的架構中,要透過App Script做到行事曆的批次匯入是相當簡單的事情 尤其以Admin帳號作批次import不同user的行事曆資訊 通常在第一次轉入時後相當重要... 下面展是透過Google Sheet統計好需要匯入的行事曆資訊 然後透過建立Sheet binding的Apps Script開發匯入的程式... 程式碼大約如下: /* 主程式,將會讀取sheet的資料,然後進行建立行事曆動作 */ function main() {   var sheet = SpreadsheetApp.getActiveSheet();   var rows = sheet.getDataRange();   var numRows = rows.getNumRows();   var values = rows.getValues();   for (var i = 1; i <= numRows - 1; i++) {     var row = values[i];     Logger.log(row);     createEvent(row[0], new Date(row[1]), new Date(row[2]), row[3], row[4], row[5])   } }; /* 建立行事曆'主程式,需要針對行事曆作subscribe,避免新進人員資訊無法閱讀出錯 */ function createEvent(calendarId, start, end, title, desc, loc) {   CalendarApp.subscribeToCalendar(calendarId);   var cal = CalendarApp.getCalendarById(calendarId);   var event = cal.createEvent(title, start, end, {       descri...

Apps Script中使用其他Apps Script的程式碼

Apps Script雖然語法相似於JavaScript,但是畢竟不是JavaScript 有許多js的特性他沒有... 其中像Node.js的module import的方式,在這邊是不能用的 需要透過library的設定方可以使用其他Script作為library... 下面說明設定的方式: 首先,需要找出要被import的library的project key 位置在File > Project properties中 打開後,畫面如下: 提取Project key的部份...先記下來 然後,在需要import的目的Script中,點選Resources > Manage libraries 打開後畫面如下: 這邊的"Find a Library"中,填寫入欲import的Script的Project key 然後點選select,上面欄位就會出現該library 並且有version與deployment mode部分可以選擇 其中version部分,需要在來源端的Script中指定Script的版本號碼 以便讓目的端可以調用不同版本的操作... 另外,Identifier欄位是到時候目的端Script會使用到的instance name 讓Web IDE可以支援"."的操作來叫出可以執行的function... 這樣,就可以直接從一個Script File去呼叫另一個Script File來做操作了∼趕快去定義自己的Apps Script Libraries吧! 最後,操作Library時候需要小心,因為一個Script可以開多個Script File,如上圖,列表在最左邊部分的 但是當Script被當做Library被呼叫時候,只有第一個Script的內容可以被正常執行(我猜是Bug...G大神還沒時間解...)

Apps Script for Google Calendar with SMS notify

Calendar是Google旗下一門重要的產品 而不少G-Fans都有發現Calendar擁有免費的SMS通知功能( 參考:https://developers.google.com/apps-script/articles/gmail_filter_sms ) 既然如此,透過Apps Script來觸發這個Event是在好不過 因為Apps Script完美的整合Google旗下許許多多的產品 讓你可以透過簡單的SDK使用該服務... 下面展示使用Apps Script建立一個Calendar Event 並且透過Calendar的一些設定,就可以讓Apps Script做到SMS通知... Step1: 建立一個Google Calendar 建立行事曆的過程頗簡單,這邊不介紹... 當行事曆建立完成,在行事曆旁邊的下拉三角形點一下,就可以進入行事曆的詳細設定頁面(如下) 在這個頁面中,有三個頁籤,第一個頁籤往下拉會看到Calendar ID的值 這邊需要把它記錄下來,之後寫程式會用到... Step2: 設定通知,並啟用簡訊通知 在日曆詳細頁面的第三個是提醒與通知中,在最下面的可以設定啟用簡訊通知的目的電話號碼(日後有分享給其他使用者時,需要請該使用者也註冊電話號碼,否則就無法收到訊息),然後再第一欄"New Event"的部份勾取SMS,這樣只要有新的Calendar Event進來,就會發出通知... Step3: 建立Apps Script 來到最後一個步驟...如果曾經試過Apps Script去開過Calendar Project的話,會發現建立Calendar Event如此簡單.... 下面function就是實際建立Calendar Event的程式碼,而其中加上了幾個部分 calendarId: 日曆ID,就是上面詳細頁面中顯示的那個ID值 addSmsReminder(0): 表示直接發送SMS通知 function createEvent() {   var calendarId = ' 9s...1c@group.calendar.google.com ';   var cal = CalendarApp.getCalenda...

Apps Script REST再一篇 - doPost request

通常操作REST服務時,除了GET方式操作之外 POST跟其他method的操作也少不了 這邊介紹POST的操作function:doPost() doPost function同樣會在參數部分帶入request object用來包裝傳入的參數 下面是一個範例,簡單的組一個response回覆前端的呼叫: function doPost(request){   var data = {"name": request.parameters.form };   return ContentService.createTextOutput(JSON.stringify(data))     .setMimeType(ContentService.MimeType.JSON); } 上面程式同樣使用request.parameters.[parameter name]來帶回傳入參數的值 後續可以有更複雜的操作,例如利用這個值做資料庫的查詢或是Google文件的查詢之類的... 程式完成後的deploy & publish部分則與之前方式相同。 Client操作的部份,為了應付比較複雜的POST操作,這邊使用Node.js的request模組來操作POST的呼叫,其中因為Apps Script執行url的redirect特性,必須加入 followAllRedirects 這個參數,指定request模組往下做redirect page的查詢動作,而form欄位所帶入的JOSN物件中,key值(form)所對應的value(123)則會實際反應在Apps Script中的request.parameters.[key]中 var request = require('request'); request({     url: ' https://script.google.com/macros/s/AKfycbxjC58GE1r...R5SA2nNb3Lsc/exec ',     method: 'POST',     followAllRedirects: tr...

細看Apps Script的呼叫

上篇參考 Google Apps Script Doc 的部分,已經可以正常呼叫該url帶出的json資源 但是Google在Serving JSONP in Web Pages片段中提到的JSONP(可參考 Wiki定義的JSONP )的方式...個人不太喜歡這個作法 雖然JSONP也是個滿普遍的作法... 但是正常來說,CORS(這邊有一篇 Node.js實作CORS Server Side的文章 )應該是比較正確的作法吧! 而且,上一篇實際也是用了ajax來呼叫資源成功 因此這次加上一些參數來實際了解Apps Script的Header包裝了些什麼東西... # curl -i -L https://script.google.com/macros/s/AKfycbxjC58GErPi54eAZvhxIgaX2xSLGu38K4YfR0R5SA2nNb3Lsc/exec?start=test1234 HTTP/1.1 302 Moved Temporarily Content-Type: text/html; charset=UTF-8 Access-Control-Allow-Origin: * Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Date: Sat, 20 Jul 2013 02:24:13 GMT Location: https://script.googleusercontent.com/macros/echo?user_content_key=xdISd1kOLMcsy2Q....A&lib=MfUByQ3tUD4fXYfP6AIUJuMmwZ9lE5h1H Set-Cookie: NID=67=R7b_RUOMh-I59....L6A8QpSgyAV;Domain=. google.com ;Path=/;Expires=Sun, 19-Jan-2014 02:24:13 GMT;HttpOnly Set-Cookie: S=maestro=inV...

Apps Script with RESTful

RESTful的幾個重點,其中一個就是從url定義資源所需的參數,而在Apps Script中的doGet function中,可以透過request物件來取出request過程中的query等參數... function doGet(request) {   var out = {name: request.parameters.start};   return ContentService.createTextOutput(JSON.stringify(out))     .setMimeType(ContentService.MimeType.JSON); } 要把doGet做publish時,首先要指定版本,原則上在"File > Manage Versions"裡面可以指定版本 然後再透過Deploy頁面設定Project version,就可以發佈該版本的Apps Script到Web上... 而Apps Script的執行部分有幾個重點供參考: 取出current web app url欄位的url時,url格式大概如下: https://script.google.com/macros/s/AKfycbxjC58GE1rPi54eAZvhxIgaX2xSLGu38K4YfR0R5SA2nNb3Lsc/exec url看起來是: https://script.google.com/macros/s/:id/exec 的組合 當點選下方的lastest code鏈結時候,或開啟測試模式,則會跑到: https://script.google.com/a/macros/mitac.com.tw/s/AKfycbzCUJIWgpo6yVnL4JG_4qSSAQlg99bwJ3EdE6J4lTh/dev 然後馬上被redirect到: https://script.googleusercontent.com/a/macros/mitac.com.tw/echo?user_content_key=j-9iX4odzmJRZKijrZ0e_5jqowDZT1uCy8d6Jx5x_FkOvWHMXj78CEgdU8n3oqyObjSjU2wmuTE8Fmd...

改寫Form Commit通知中Table的成列方式...

承 「 透過Google Apps Script結合Google Form做即時郵件通知 」來賓所提及Form的呈現方式改用直式的呈現,可以透過下面兩個部分修改來呈現... 1. 先改寫getLastRowTable(): function getLastRowTable(arr){   return jsonObjToTableWithTitle(arr[0], arr[arr.length-1]); } 2. 增加jsonObjToTableWithTitle實作部分: function jsonObjToTableWithTitle(title, row){   var TRs = '';   var keys = Object.keys(row);   for(var j = 0 ; j < keys.length ; j++) {     var TR = '<tr>';     var rowvalue = row[keys[j]];     TR += ('<td>' + title[keys[j]] + '</td><td>' + rowvalue + '</td>' );     TR+= '</tr>';     TRs += TR;   }   var table = '<table>' + TRs +'</table>';   return table; } 測試後收到的信件就會這樣呈現拉: 以上,可以參考拉∼需要更漂亮的Layout...可以再加工一下!

透過Google Apps Script設定Form Commit Trigger

延伸 「 透過Google Apps Script結合Google Form做即時郵件通知 」,有朋友問到掛載form commit trigger部分 實際實作上如下: 1. 點選工具列上的啟動氣按扭...就是那個小時鐘 2. 在出現的啟動程序點選"ˋ建立"鏈結 3. 這時候如果是一般的script的話,可以透過選擇要執行的function以及時間設定來完成排程執行的動作 如果是Form/SpreadSheet的Script則可以在活動下拉中見到"來自試算表"的選項,選擇後,右邊會出現"開啟時", "編輯時", "提交表單時"等選項的下拉,選擇"提交表單時"則可以把該Function設定為每次提交表單就會觸動,此時,裡面的Function就可以做到通知的效果了 最後,如果您的表單是同時公布給大量User使用時,有可能會有同時存入表單的狀況 此時,抓取最後一筆的邏輯就會比較不適用... 這時,可以參考: http://gappsnews.blogspot.tw/2013/03/fwd-google-apps-script-event-object.html 直接聽取commit時候的event,就萬無一失拉!

Google Apps Script Event Object

Google Apps Script的Event系統有別於一般程式語言的Event寫法 Apps Script在"資源>您現有的觸發程序"中,可以註冊您的function到某個Event 例如下面就是把onOrderFormCommit()註冊到表單提交時候執行 而根據Apps Event的說明文件( https://developers.google.com/apps-script/understanding_events )指出 以Form的Event部分,將會接收到三個參數: 而這三個參數都會包在第一個傳入變數中,因此在onOrderFormCommit()中加入Logger檢視接收參數的內容... function onOrderFormCommit(e){   Logger.log('----------------->');   Logger.log(JSON.stringify(e));   Logger.log('----------------->'); ...(skip) } 透過"檢視 > 記錄",則可以看到表單送出的內容如下: 把它丟給JSON parser格式化一下,比較清楚... 如此,就可以比較明確的抓出Form的送出值來做處理(之前都笨笨的抓最後一筆...可以修改程式拉!)

透過Google Apps Script結合Google Form做即時郵件通知

體驗過Google Apps Script的功能後,也發現他結合GmailApps的模組 GmailApps的應用可以用在表單填寫完成後,做發信的通知 例如您開立了一個訂購的表單,為了要在第一時間通知商家有訂單進入 就可以直接呼叫Gmail做發信的通知,讓手持Smart Phone的我們可以很快的知道生意上門了! 下面規劃三個function,其中: onCommit():為form commit時候觸發的function,需要掛載於form commit trigger上 jsonArrToTable():目的將json array解析成為一個Table getLastRowTable():目的將整個table的回傳過濾為剩下第一筆(表頭,含有Form的欄位說明)與最後一筆(原則上就是剛剛送出的那一筆表單) 完整程式碼如下: function onCommit(){   var sheet = SpreadsheetApp.getActiveSheet();   var rows = sheet.getDataRange();   var numRows = rows.getNumRows();   var values = rows.getValues();   var content = getLastRowTable(values);   var htmlBody = "Hi Admin: <br/><br/>有訂單拉,檢查一下吧! <br/><br/>" + content + '<br/><br/>Send by Google Apps';   GmailApp.sendEmail(     " your-email-address@gmail.com ",      "Order Confirm Notice",      htmlBody,      {from: ' from-email-...

透過Google指令碼,存取Google Cloud SQL

既然Cloud SQL提供了MySQL的Feature 那麼透過指令碼(Apps Script)來存取Cloud SQL應該也是OK的拉! 這邊介紹一下在指令碼中操作的方式 首先要確認一下您在Cloud SQL中申請的DB Instance名稱 而名稱可以在API Console中找到 此範例是屬於手動執行的部份,因此這邊建一個test function來收容db query的code... function test(){   var conn = Jdbc.getCloudSqlConnection("jdbc:google:rdbms://[db instance name]/[db name]");   var stmt = conn.createStatement();   stmt.setMaxRows(100);   var start = new Date();   var sql = "select * from member_info";   var rs = stmt.executeQuery(sql);   Logger.log('SQL:' + sql);   while(rs.next()){     Logger.log('['+new Date().toString() + ']' + rs.getString(1) + '::' + rs.getString(2) );   } } Project看起來像這樣: 此時,在工具列選擇要執行的Function後,點選執行按鈕,就可以執行撈取Cloud SQL的動作了... 執行時候會發現Google會跟您要求受權,請user同意讓Script Editor來執行這部份程式,同意後才可以執行... 這部份是說,如果將來把這段程式碼放到Web Service中時候,該Web Service App也需要經過授權才能使用...

Google指令碼基本操作介紹 - Web Server篇

Google的指令碼是什麼東西呢?!原則上他就是Google的一份靜態檔案,但是透過Google的雲端服務平台的一些能力,將靜態檔案內的scriptlet片段拉到Google的後端作運算,寫起來就像在寫JavaScript(這邊說Node.js可能比較貼切,因為同為server side language)或JSP,而在scriptlet片段中,則可以操作許多Google的API服務,甚至他提供你連接JDBC的能力、URL呼叫的能力...等,宛如就是一套完整的雲端程式語言(這樣說應該不為過拉,這真是個創新!),有並駕於App Engine的氣勢喔! Google指令碼的範圍很廣,筆者也仍在摸索中,之前介紹過透過Sheet+指令碼做一個簡單的URL監控( 這裡 ),而本篇簡單介紹一下指令碼如何製作一個Web Server(嚴格說起來是Web Page拉,但是具備Server端運作功能喔!)。您將可以體驗到No-Hosting Web Server的威力! 指令碼是Google Drive的一個服務,Google將指令碼(Code)以檔案方式寄存在Drive中,類似的靜態檔案服務的應用,最近滿火紅的! 首先開啟指令碼時候,選擇"作為網路應用程式的指令碼",檔案開啟後,會有愈設定程式碼片段供編輯 程式碼片段大致上如下,是一個doGet function,Web base的指令碼需要認得doGet()作為server的進入點 如果選擇到空白專案的話,只要把doGet function建上即可 作為一個Cloud IDE,Google當然也有把Code Hint擺上來,透過簡單的提示,寫啟程是來就更容易拉! 而Web部分物件的建立主要是透過 HtmlService 這個模組來進行操作,我們利用他來output html, load static html page, load template html page..等,範例如下: Output HTML: // Script-as-app template. function doGet(e) {   return HtmlService. createHtmlOutput ("<h1>HELLO!</h1>...

Google Apps Script - HTTP Monitor

這邊是一個利用Google的SpreadSheet(試算表)服務,加上Apps Script(指令碼)服務,來做HTTP URL的監控,並且記錄每次Request的回應時間值,應用層面,可以作為監控或是網路回應時間的統計(當然,這邊是以Google的網路來做Request,比較不客觀一點,僅供參考拉 :D),未來可以搭配Mail Service使用或是再發揮更多想像力吧∼ (PS: 不要拿來攻擊阿@@) Step1: 開立一個Google Spreadsheet 為了美觀,這邊先輸入title,如下: Step2: 建立Sheet Apps Script,選擇視窗中,可以看到Spreadsheet項目,選這個就對了∼ 在上面的視窗中,可以看到網址列有個sheet id,先記錄下這個,之後會用到... Step3: 撰寫指令碼... 清掉預先產生的內容(因為用不到),貼上下面的code,並改寫sites裡面的內容成為你要監控的HTTP URL,最後儲存起來... /**  * 透過UrlFetch的服務來進行網站Response Time的監控  */ function emitRequestAndRecord() {   var sites = [ //定義要監控的HTTP點     " http://www.google.com ",     " http://micloud.tw "   ];       var sheet = SpreadsheetApp.openById(' 0Aq-z....RVkE ').getActiveSheet(); //id即為開啟sheet時候,網址列的key參數值   var rows = sheet.getDataRange();   var numRows = rows.getNumRows();   var values = rows.getValues();   sites.forEach(function(v,i){     v...

Advance Google Form - 使用Google Form搭配Web Server做即時資料處理

Google Form提供了一個強大的線上編輯功能 並且結合Google Sheet可以做到分析與後製圖表等動作 而不斷"長大"的Google推出Apps Script之後 許多的應用不斷的在衍生... 這邊介紹如何透過Apps Script結合Form的服務,並直接後送後端的HTTP伺服器做即時的後續處理動作(這邊不規範後續處理,範圍太大了@@)... 1. 建置屬於你的Form表單 2. 完成Form建置後,可以發現從Drive點選Form會以Sheet的方式打開,此時點選插入,選擇"指令碼" 3. 選擇指令碼後,Google會開立一個Apps Script的編輯畫面,此時可以幫你的Script命名... 4. 這邊我們直接採用readRows(),可以直接把下面這段code加到for loop下面   Logger.log('Call url...');   var response = UrlFetchApp.fetch(" http://hello.my.micloud.tw:1337/test ", {     method:"POST",     payload:{       row_a:row[0],row_b:row[1],row_c:row[2]     }   });   Browser.msgBox(response.getContentText()); 上面程式中,主要是針對 http://hello.my.micloud.tw:1337/test 做POST的動作 因此在UrlFetchApp.fetch的第二個參數中加入option參數,告知要用POST method以及表單的內容(payload欄位) 最後透過getContentText()來trigger整個http request的動作 5. 然後,接下來要把function attach到form的event裡面,點選工具列的啟動程序(小時中按鈕) 6. 啟動程序視窗中增加readRows()的執行,...