TogglとSlackを連携して定期的に作業状況を共有する

TogglとSlackを連携して定期的に作業状況を共有する仕組みを作ってみました。

#背景
他拠点にいるメンバーから「今なにしてるー？」と聞かれる頻度が結構多かったので、いちいち聞かれるなら自分から発信してしまおうと思って作成しました。

#目的
「Togglのタイマー内容を取得し、Slackの特定のチャンネルに投稿する」ことを定期的に実行して、いま自分が何をしているのかを他メンバーと共有する仕組みを作ります。

# 使うサービス
- Toggl
- Slack
- AWS
    - Lambda (コードはNodejs8.10で実装)
    - Cloudwatch

# 手順
## 1. TogglとSlackのAPIトークンを取得する
### 1-1.Togglのトークン取得

Togglにログインした状態でプロフィール画面( https://toggl.com/app/profile )の一番下に記載されているAPI tokenを控えておきます。

### 1-2.Slackのトークン取得

チャンネル一覧にある「App」からアプリ一覧に移動し、Incoming Webhookをチャンネルに追加します。
その後、Incoming Webhookの設定画面に記載されているWebhook URLを控えておきます。

## 2.AWS Lambdaで関数を作成する
### 2-1.関数を作成
以下内容で関数を作成します。ランタイムはNodejs8.10で。

```javascript

'use strict';

const AWS = require('aws-sdk');
const url = require('url');
const https = require('https');

const slackWebhookUrl = process.env.slackWebhookUrl;
const slackChannel = process.env.slackChannel;
const togglApiToken = process.env.togglApiToken;
const togglTimeEntrysPath = '/api/v8/time_entries/current';

//前回投稿分のタイムエントリ
let slackTextBefore;

const getTogglMessage = (togglTimeEntrysPath) => {
    const options = {
        method: "GET",
        host :"www.toggl.com",
        auth: togglApiToken+":api_token",
        path: togglTimeEntrysPath,
        json : true
    };
    return new Promise((resolve,reject) => {
        var body = "";
        const req = https.request(options, (res) => {
                res.setEncoding('utf8');
                res.on('data', (chunk) => {
                body += chunk;
            });
            res.on('end', () => {
                resolve(body);
            });
        });
        req.end();
    });
};

function createMessage(json){
    var message;
        json = JSON.parse(json);
        //Slackに投稿するメッセージの作成
         if(json.data == null){
            message = "現在実施している作業はありません。";
         }else if (typeof json.data.description === 'undefined'){ //タイムエントリ未設定時
            message ="現在、何かの作業を実施中です。(Description未入力)";
        }else { 
            message =`現在${json.data.description}を実施中です。`; 
        }    
    return message;
}

const PostMessage = (message) => {
    var postMessage={
        channel: slackChannel,
        text: message
    };
    const body = JSON.stringify(postMessage);
    return new Promise((resolve,reject) =>{
        const param = url.parse(slackWebhookUrl);
        param.method = "POST";
        param.headers = {
            'Content-Type': 'application/json',
            'Content-Length': Buffer.byteLength(body),
        };
        console.log(param);
        console.log(`body: ${body}`);
        const postReq = https.request(param, (res) => {
            const chunks = [];
            res.setEncoding('utf8');
            res.on('data', (chunk) => {
                chunks.push(chunk);
            });
            res.on('end', () => {
                resolve(null);
            });
        });
        postReq.write(body);
        postReq.end();
    });
};

exports.handler = async (event) => {
    try{
        var timeEntryDescription = await getTogglMessage(togglTimeEntrysPath);
        var message = createMessage(timeEntryDescription);
        if (message !== slackTextBefore) {
            await PostMessage(message);
            slackTextBefore = message;
        } else {
            console.log("No Change description, skip post massage.");
        }
    }catch(err){
        console.log(err);
    }
};

```
ちなみに、上記の関数はLambdaのインスタンスが再利用される仕様を利用して、前回投稿時から状態が変わっていない場合は投稿しないよう考慮しています。
(インスタンスが再作成された際は状態が変わっていない場合でも投稿されます。自分が運用していたものは大体7時間毎に投稿されていました)

### 2-2. 環境変数を設定
以下内容でLambdaの環境変数を設定します。

| キー |値| 
|:-------------------:|:-------------------:|
| togglApiToken|1-1.Togglのトークン取得 で取得したTogglのAPI token 
|slackWebhookUrl| 1-2.Slackのトークン取得 で取得したWebhook URL
|slackChannel| 投稿したいSlackチャンネル名
<img width="721" alt="20190208_環境変数設定例.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/179346/290962cd-0a8e-3f73-67b4-9fd327fd981f.png">

### 2-3. バージョン作成
Cloudwatchで実行するためのバージョンを作成しておきます。

## 3. Cloudwatchで定期的に関数を実行するルールを設定する
Cloudwatch Events で関数の実行ルールを作成します。
毎分実行する場合は以下のような形で。
<img width="796" alt="20190208_Cloudwatchevent.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/179346/4f493448-1866-ec6f-4894-a7eed493f958.png">

投稿されない時間帯を設定したい場合は面倒ですがcron式で設定する必要があります。


---

動かすとこんな感じで投稿されます。
<img width="316" alt="20180208_実行零.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/179346/4bc3d7d6-1180-77d1-c4b4-f99901cdd5f1.png">


## カレンダーやプロジェクト管理ツールと連携する
[Togglが公式で出しているChromeの拡張機能](https://chrome.google.com/webstore/detail/toggl-button-productivity/oejgccbfbmkkpaidnkphaiaecficdnfn)を入れることで、GoogleカレンダーやRedmine・Backlog等のプロジェクト管理ツールからタイマーをスタートさせることができます。
拡張機能をインストールして連携したいサイトをチェックするだけです。
<img width="592" alt="20190208_togglpermission.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/179346/e62221d2-4db9-8e32-b86b-39ca75f109f8.png">
チケットやカレンダーの予定を開いて中身確認してタイマースタートをポチって作業開始…みたいな流れもできるので便利です。
<img width="328" alt="20180208_googleカレンダーでの表示.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/179346/71a4e1fb-d20f-935e-a5b5-ef91ee0f7025.png">




## まとめ
LambdaとCloudwatchを使用して、Togglのタイマー内容を取得してSlackの特定のチャンネルに投稿することで自分が何をしているのかを他メンバーと共有する仕組みを作りました。