QiitaのOrganization内のユーザーが記事を投稿したらGASでTeamsに通知するBOTを作ってみた

## はじめに
弊社(株式会社コードユニット)は、技術記事投稿の文化を根付けるためにQiita Organizationを始めました。
そこで、Organization内のユーザーが投稿したら弊社Teamsに通知をすることにより、社員同士の投稿を確認しやすくなるのでは・・・？
と思い、BOTを作ってみました。

内々で使用するBOTなので、仕組みはちょっと甘めですが、参考になれば幸いです！

## 使用技術
- Teams Incomming Webhook
- GAS
- Qiita API

## 作り方
### TeamsのIncomming Webhookを設定する
Teamsで任意のチャンネルを右クリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178540/b67cc40a-7f48-fbe1-6b07-b5507c1fdd0e.png)
こちらの `チャネルの管理`を押下し、`コネクタの編集`を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178540/7c2fc8a2-4cf6-bd13-1037-2a434a5ea017.png)
Incomming Webhook の構成を押下し、各情報を入力します。
払い出されたWebhook URLをメモしておきましょう。

### GASで定期実行の処理を書く
処理内容としては以下のようになります。
今回はGASで10分毎の定期実行としました。

#### Qiita APIをコール
`https://qiita.com/api/v2/items`
でQiitaの全ての投稿が取得できます。

https://qiita.com/api/v2/docs
こちらによると、クエリパラメータで query=${}で、
https://help.qiita.com/ja/articles/qiita-search-options
の検索オプションが使えそうということがわかりましたので、試してみました。

結果、 https://qiita.com/api/v2/items?query=org:codeunit のようにOrganization名でも検索ができましたので、こちらを採用します。

https://qiita.com/fkooo/items/9f8e566c027bb833c29e
こちらを参考に、失敗回避のため、以下のオプションを追記しました。
```
headers: {
  'Accept-Encoding': 'identity',
},
```

#### キャッシュに保存する
今回は、処理を定期実行するにあたって、APIから取得した前回の値と、今回取得した値に変更があった場合に処理をしたいと考えました。
https://qiita.com/golyat/items/ba5d9ce38ec3308d3757
上記を参考に、100分間キャッシュすることにしました。

#### 比較
キャッシュデータと今回取得したデータを比較して、
追加のあった記事のみを取得します。

#### Teamsに通知
追加のあった記事の内容を
先ほど取得したWebhook URLに対してPOSTでメッセージを送信します。

#### ソースコード全文
```
function makeCache() {
  const cache = CacheService.getScriptCache();
  return {
    get: function (key) {
      const value = cache.get(key);
      return value ? JSON.parse(value) : null;
    },
    put: function (key, value, sec) {
      cache.put(key, JSON.stringify(value), sec || 6000);
      return value;
    }
  };
}

// Qiita APIのエンドポイント
const qiitaApiUrl = 'https://qiita.com/api/v2/items?query=org:codeunit';

// Teams WebhookのURL
const teamsWebhookUrl = 'ここに先ほどコピーしたWebhook URLを書きます';
// キャッシュを作成
const cache = makeCache();

// Qiita APIを呼び出してデータを取得
function fetchData() {
  const options = {
    headers: {
      'Accept-Encoding': 'identity',
    },
  };
  const response = UrlFetchApp.fetch(qiitaApiUrl, options);
  const data = JSON.parse(response.getContentText());
  return data.map(item => ({
    title: item.title,
    url: item.url,
    user: {
      id: item.user.id,
    },
  }));
}

// 前回のデータと比較して新しい記事を通知する
function notifyNewArticles() {
  const currentData = fetchData();
  const previousData = cache.get('qiitaData') || [];

  // 前回のデータと比較して新しい記事を取得
  const newArticles = currentData.filter(item => !previousData.some(prevItem => prevItem.url === item.url));

  // 新しい記事がある場合、Teamsに通知する
  if (newArticles.length > 0) {
    newArticles.forEach(article => {
      const message = `${article.user.id} さんが新しい記事を投稿したよ <br> タイトル: ${article.title} <br> URL: ${article.url}`;
      postToTeams(message);
    });

    // 新しいデータをキャッシュとして保存
    cache.put('qiitaData', currentData);
  }
}

// Teamsにメッセージを投稿する
function postToTeams(message) {
  const payload = {
    text: message,
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
  };

  UrlFetchApp.fetch(teamsWebhookUrl, options);
}
```

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178540/c41ca18f-f986-6b32-e304-d6a3a82ee233.png)
こんな感じで通知するBOTが出来ました！

## 追伸
株式会社コードユニットでは北海道札幌市で一緒に働けるメンバーを絶賛募集中です！
起業したばかりのベンチャーですが、和気あいあいと楽しく仕事をしています！
ご興味のある方は一度ご連絡ください！