Togglでタスクログを記録しているので,そのログをGoogle カレンダーに出力したい.
いくつか方法はあるようですが,私が利用している方法を紹介します.
やること
- Google Apps Scriptを使用して
- Togglのログから,内容とプロジェクトを
- Google カレンダーに自動で出力する
Google Apps Scriptを作成する
さて,ここからが作業内容です.
Google Apps Scriptをインストールする
私の場合は元々メニューに出ていたのですが,もしも無ければ,
Google ドライブの新規ボタン→アプリを追加
Google Apps Scriptを検索してインストールします.
Google Apps Scriptの新規プロジェクトを作る
Google ドライブの新規ボタン→その他→Google Apps Script
“無題のプロジェクト”が作成されます.
プロジェクト名は好きな名前をつけてください.
必要なライブラリを追加します.
リソース→ライブラリ
“Add a library”にプロジェクトキーを入力して,追加をクリック.
プロジェクトキー:MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
バージョンは最新で大丈夫だと思います.
保存をクリックしてコードの編集画面に戻ります.
ソースコードの編集
デフォルトで入力されているコードを削除して,けっこう長いですが,以下のコードをコピペしてください.
/*
export Toggl log to GoogleCalendar
library: moment.js
project-key: MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48
*/
var CACHE_KEY = 'toggl_exporter:lastmodify_datetime';
var TIME_OFFSET = 9 * 60 * 60;
var TOGGL_BASIC_AUTH = 'REPLACE:api_token';
var GOOGLE_CALENDAR_ID = 'REPLACE';
function getLastModifyTime()
{
var cache = {};
var file = DriveApp.getFilesByName('toggl_exporter_cache');
if(!file.hasNext())
{
var now = Moment.moment().format('X');
var beginning_of_day = parseInt(now - (now % 86400 + TIME_OFFSET), 10).toFixed();
putLastModifyTime(beginning_of_day);
return beginning_of_day;
}
file = file.next();
var data = JSON.parse(file.getAs("application/octet-stream").getDataAsString());
return parseInt(data[CACHE_KEY], 10).toFixed();
}
function putLastModifyTime(unix_timestamp)
{
var cache = {};
cache[CACHE_KEY] = unix_timestamp;
var file = DriveApp.getFilesByName('toggl_exporter_cache');
if(!file.hasNext())
{
DriveApp.createFile('toggl_exporter_cache', JSON.stringify(cache));
return true;
}
file = file.next();
file.setContent(JSON.stringify(cache));
return true;
}
function getTimeEntries(unix_timestamp)
{
var uri = 'https://www.toggl.com/api/v8/time_entries' + '?' + 'start_date=' + encodeURIComponent(Moment.moment(unix_timestamp, 'X').format());
var response = UrlFetchApp.fetch(
uri,
{
'method' : 'GET',
'headers' : { "Authorization" : " Basic " + Utilities.base64Encode(TOGGL_BASIC_AUTH) },
'muteHttpExceptions': true
}
);
try
{
return JSON.parse(response);
}
catch (e)
{
Logger.log([unix_timestamp, e]);
}
}
function getProjectData(project_id)
{
if(!!project_id == false) return {};
var uri = 'https://www.toggl.com/api/v8/projects/'+ project_id;
var response = UrlFetchApp.fetch(
uri,
{
'method' : 'GET',
'headers' : { "Authorization" : " Basic " + Utilities.base64Encode(TOGGL_BASIC_AUTH) },
'muteHttpExceptions': true
}
);
try
{
return JSON.parse(response).data;
}
catch (e)
{
Logger.log(["getProjectData", e]);
}
}
function recordActivityLog(description, started_at, ended_at)
{
var calendar = CalendarApp.getCalendarById(GOOGLE_CALENDAR_ID);
calendar.setTimeZone('Asia/Tokyo');
calendar.createEvent(description, new Date(started_at), new Date(ended_at));
}
function watch()
{
try
{
var check_time = getLastModifyTime();
var time_entries = getTimeEntries(check_time);
if(time_entries)
{
last_stop_time = null;
for (var i = 0; i < time_entries.length; i++)
{
var record = time_entries[i];
if(record.stop == null) continue;
var project_data = getProjectData(record.pid);
var project_name = project_data.name || '';
var activity_log = [(record.description || '名称なし'), project_name].filter(function(e){return e}).join(" : ");
recordActivityLog(
activity_log,
Moment.moment(record.start).format(),
Moment.moment(record.stop).format()
);
last_stop_time = record.stop;
}
if(last_stop_time)
{
putLastModifyTime((parseInt(Moment.moment(last_stop_time).format('X'), 10) + 1).toFixed());
}
}
}
catch (e)
{
Logger.log(e);
}
}
2箇所,書き換えてもらう必要があります.
TogglのAPI tokenを取得する
Togglにログインして,画面左下の自分のアカウント名をクリック→Profile Settings→下へスクロールして“API token”(英数字)をコピー
10行目を書き換えます.
var TOGGL_BASIC_AUTH = ‘REPLACE:api_token’;
REPLACEの部分だけを,コピーしておいたAPI tokenに置き換えます.
API tokenが“ABC123”なら,
var TOGGL_BASIC_AUTH = ‘ABC123:api_token’;
となります.
Google カレンダーのカレンダーIDを取得する
記録を反映したいカレンダーの,オーバーフローメニュー(︙)から設定を共有→カレンダーを統合→カレンダーIDをコピー
11行目を書き換えます.
var GOOGLE_CALENDAR_ID = ‘REPLACE’;
API tokenのときと同様にREPLACEの部分だけを,コピーしておいたカレンダーIDに置き換えます.
var GOOGLE_CALENDAR_ID = ‘xxxxx@group.calendar.google.com’;
になったら,保存をします.
トリガーの設定
自動で実行されるように設定をします.
編集→現在のプロジェクトのトリガー
画面遷移をした後に,“トリガーの追加”からトリガーを設定します.
5分おきに実行したい場合には,以下の画像のように設定してください.
トリガーのタイプを時間ベースにすれば,1時間おきや,他の時間の間隔を選べます.
リクエストの許可
デバッグをして,無事に実行できるか確認します.
その際に,警告といくつか許可することを求められます.
- Google ドライブ:ログの多重記録を防ぐために,最後にログを記録した日時を保存するのに使用します.
- Google カレンダー:取得したログをカレンダーに反映するのに使用します.
- 外部サービスへの接続:TogglのサービスのAPI経由でデータを取得するのに使用します.
実行→関数をデバッグ→“watch”を選択
すると,許可を確認することを求められます.
Googleアカウントを選択し,
詳細をクリック,
“プロジェクト名”(安全ではないページ)に移動,
下へスクロールして,許可をクリックします.
エラーが出なければ成功です.
以上で設定は終了です.
おまけ:トリガーの発動時間を細かく設定する
トリガーの設定では,12時30分ぴったりという指定ができません.
そこで,1つ関数を挟むことで解決します.
トリガーの設定は,実際に発動させたい時刻よりも前の範囲を指定します.
var GOOGLE_CALENDAR_IDよりも後,function getLastModifyTime()よりも前に,下の2つの関数を追加して,
function setTrigger()
{
var triggerDay = new Date();
triggerDay.setHours(12);
triggerDay.setMinutes(30);
ScriptApp.newTrigger("main").timeBased().at(triggerDay).create();
}
function deleteTrigger()
{
var triggers = ScriptApp.getProjectTriggers();
for(var =0; < iitriggers.length; ++)
{
if (itriggers[].igetHandlerFunction() == "main")
{
ScriptApp.deleteTrigger(triggers[i]);
}
}
}
function watchの中に,deleteTrigger();を追加します.
function watch()
{
deleteTrigger();
//
//
//
}
作成したトリガーを消さないと残ってしまうので,deleteTrigger()で削除します.
これで終了です.
コメント