Google App Scriptの APIって微妙に使いづらいこと多いので、
自分で、ラッパー作ることが多いです。
以下は個人のアカウントごとにオブジェクトを作成する
Google Calendarのプロトタイプデザインパターンっぽい実装。
function createDefaultEvents_(){
var now = Now();
now.month--;
return [
{
title: EVENT_LABEL.READY,
start: new Date(now.year,now.month,now.date,10,30),
end:new Date(now.year,now.month,now.date,11,00)
},
{
title: EVENT_LABEL.DONE,
start: new Date(now.year,now.month,now.date,13,00),
end:new Date(now.year,now.month,now.date,14,00)
}
];
}
function Event_(title,start,end){
return {
title: title,
start: start,
end: end
}
}
function getCalendarManger(id){
var _id = id || "hogecalender"
return CalendarManager_(_id)
}
function registerEvent_(calendar){
return function(address,event){
Logger.log(event);
return calendar.createEvent(event.title,event.start,event.end,{guests:address,sendInvites:false});
};
}
function getEvent_(calendar){
return function(title,start,end){
var calEvents = calendar.getEvents(start,end);
var intMaxIndex = calEvents.length;
for (var i = 0;i<intMaxIndex;i++){
if(calEvents[i].getTitle()===title){
return calEvents[i];
}
}
};
}
function deleteGuest_(address,event){
if(existGuest_(address,event)) event.removeGuest(address);
}
function existGuest_(address,event){
var eventGuests = event.getGuestList();
eventGuest.forEach(function(v,i){
if(address == v.getEmail()){
return true;
}
});
}
function addGuest_(address,event) {
event.addGuest(address);
}
function CalendarManager_(id){
var _calendar = CalendarApp.getCalendarById(id);
var registerEvent = registerEvent_(_calendar);
var getEvent = getEvent_(_calendar);
return {
"calendar":_calendar,
"getEvents":function(startDate,endDate){
return _calendar.getEvents(startDate, endDate);
},
"Event":Event_,
"registerEventsAssignees":function(addresses,events) {
var _events = events || DEFAULT_GC_EVENT_;
_events.forEach(function(event){
registerEvent(addresses.join(","),event);
});
},
"registerEvents":function(address,events) {
var _events = events || DEFAULT_GC_EVENT_;
_events.forEach(function(event){
registerEvent(address,event)
});
},
"registerEvent":registerEvent,
"deleteAllEventsForDay":function(date){
var calEvents = _calendar.getEventsForDay(date);
var intMaxIndex = calEvents.length;
for (var i = 0;i<intMaxIndex;i++){
calEvents[i].deleteEvent();
}
},
"getEvent":getEvent,
"deleteEvents":function(events){
var _events = events || DEFAULT_GC_EVENT_;
_events.forEach(function(_event){
getEvent(_event.title,_event.start,_event.end).deleteEvent();
});
},
"deleteEvent":function(event){
var _event = getEvent(event.title,event.start,event.end);
_event.deleteEvent();
},
"changeGuests":function(origin,newer,event){
var _event = getEvent(event.title,event.start,event.end);
origin.forEach(function(v){deleteGuest(v,_event)});
newer.forEach(function(v){addGuest(v,_event)});
},
"addGuest":function(address,event){
var _event = getEvent(event.title,event.start,event.end);
addGuest_(address,_event);
},
"deleteGuest":function(address,event){
var _event = getEvent(event.title,event.start,event.end);
deleteGuest_(address,_event);
},
};
}
function Now(){
var _date = new Date();
return {
instance:_date,
year: _date.getYear(),
month: _date.getMonth()+1,
date: _date.getDate(),
hour: _date.getHours(),
day: _date.getDay(),
}
}
Google Spread Sheetをurlで指定するときもwrapper作ると便利です。
url指定で欲しいスプレッドシートのプロトタイプオブジェクトを手に入れます。
スプレッドシート内の参照したいsheetをaddSheetメソッドでニョキニョキ生や
します。以下はそのまま使えないですが例として
function getSheet1_(){
var now = Now();
var _sheet = getSheetByUrlOrDefault_();
_sheet.addSheet("sheet1","one");
_sheet.currentSheet = _sheet.addSheet(String(now.year)+'/'+String(now.month));
return _sheet;
}
function getSheet2_(){
var _sheet = getSheetByUrlOrDefault_("https://docs.google.com/spreadsheets/d/hogehogeurl");
_sheet.addSheet("sheet2","two");
var now = Now();
_sheet.targetRow = 8;
_sheet.targetColumn = 2 + 4*(now.day - 1);
_sheet.getProtectionRange = (function(now){
return function (sheet){
return sheet.getRange( _sheet.targetRow, _sheet.targetColumn , 100, 4);
};
})(Now());
return _sheet;
}
function getSheetByUrlOrDefault_(url){
var _target = url ? SpreadsheetApp.openByUrl(url):
SpreadsheetApp.getActiveSpreadsheet();
var _sheets={};
return{
main: _target,
sheet: _sheets,
addSheet:function(dateStr,alias){
if(!alias) alias=dateStr;
_sheets[alias] = _target.getSheetByName(dateStr);
this[alias] = _sheets[alias];
return _sheets[alias];
}
};
}
var a = getSheet1_();
var b = getSheet2_();
a.one
b.two
とかやると、スプレッドシートaのsheet1,スプレッドシートbのsheet2,など
にアクセスできて、使いたいシートだけobjectに生やしとけば便利に使えます。
** ただ後に普通にprototypeでclass宣言できることを知りました。**
以下はGmailのパラメータを監視して、正規表現マッチする
メールがあれば、slackに通知するようなスクリプトsendSlackChannel
の実装はincoming webhookでメッセージ投げる簡単な関数なので割愛。
色々なことを想定して設計したけど、結局本文中のパラメータマッチしか
使わなかったので、雑な実装になっているのは多めに見てください。
(function(global){
function GmailBoxWatcher(watch_box_label,params){
this._watchLabel = this.setWatchLabel(watch_box_label);
this._keyWords = {
or:params.or,
and:params.and
};
this._textType = params.textType;
this._recentlyThreads = this._watchLabel.getThreads(0, GmailBoxWatcher.LIMIT_THREADS);
this._slackChannel = params.slackChannel;
this.newMessagesCache = [];
}
GmailBoxWatcher.prototype.setWatchLabel = function(watch_box_label){
var count = GmailBoxWatcher.USER_LABELS.length;
for(var i = 0; i < count; i++){
var _label = GmailBoxWatcher.USER_LABELS[i];
if(_label.getName() === watch_box_label)
return _label;
}
return false;
}
GmailBoxWatcher.prototype.getNewMessages = function(){
if(this.newMessagesCache.length>0) return this.newMessagesCache;
return GmailBoxWatcher.prototype._setNewMessages();
}
GmailBoxWatcher.prototype.notifyMessageToSlack = function(message){
var sendText = this._getNotifyMessage(message);
if(sendText){
sendText = "hogehoge";
Logger.log(sendText);
Logger.log(this._slackChannel);
sendSlackChannel(this._slackChannel,sendText)
}
}
GmailBoxWatcher.prototype._getNotifyMessage = function(message){
if(!message.isUnread()) return;
this.newMessagesCache.push(message);
var _text = this._textForCondition(message);
if(!this._satisfyAllMatchConditions(_text)) return;
if(this._satisfyArbitaryMatchConditions(_text)){
return this._makeNotifyMessage(message);
}
return;
}
GmailBoxWatcher.prototype._makeNotifyMessage = function(message){
//ToDo:送るテキストのフォーマットを設定する。
return message.getPlainBody();
}
GmailBoxWatcher.prototype._textForCondition = function(message){
switch(this._textType){
case "title":
case "body":
case "to":
case "from":
case "cc":
case "attachment":
case "id":
default:
return message.getPlainBody();
}
}
GmailBoxWatcher.prototype._setNewMessages = function(){
var count_i = this._recentlyThreads.length;
for(var i = 0; i < count_i; i++){
var _messages = this._recentlyThreads[i].getMessages();
var count_j = _messages.length;
for(var j = 0; j < count_j; j++){
this.notifyMessageToSlack(_messages[j]);
}
}
return this.newMessagesCache;
}
GmailBoxWatcher.prototype._satisfyArbitaryMatchConditions = function (message){
var keyWords = this._keyWords.or;
var re = new RegExp(keyWords.join("|"),"g");
return re.test(message);
}
GmailBoxWatcher.prototype._satisfyAllMatchConditions = function (message){
var keyWords = this._keyWords.and;
var count = keyWords.length;
for(var i = 0;i<count;i++){
var re = new RegExp(keyWords[i],"g");
if(!re.test(message)) return false;
};
return true;
}
GmailBoxWatcher.prototype.notifyMessagesToSlack = function(messages){
if(messages) this.newMessagesCache = messages
if(this.newMessagesCache.length>0){
var _messages = this.newMessagesCache;
var count_j = _messages.length;
for(var j = 0; j < count_j; j++){
this.notifyMessageToSlack(_messages[j]);
}
}else{
return this._setNewMessages();
}
}
GmailBoxWatcher.load = function (options){
GmailBoxWatcher.USER_LABELS = GmailApp.getUserLabels();
GmailBoxWatcher.LIMIT_THREADS = options.limitThreads;
}
global.GmailBoxWatcher = GmailBoxWatcher;
})(this);
1回目の実装は面倒だけど2回目以降は大変便利に使えます。
巷では、es6やtypescriptをBUILDして、gasをかけるnode modulesがあるときいて、やりたい気持ちが高いけど、uploadにservice accountなどを使って割と大掛かりになるので、一旦保留中。このノウハウを確立してちゃんとバージョン管理したい。