🫱

アドベントカレンダーや会社ブログの進捗管理を自動化

2024/02/15に公開

はじめに

電話自動応答サービスIVRyでエンジニアをしている小瀬です。
https://ivry.jp/

普段はバックエンドの開発がメインですが、今回はプロダクト開発ではなく、社内業務で利用する便利なリマインダーを作成した経験についてブログに書きたいと思います。

2023年のアドカレは50ブログ

2023年のIVRyのアドカレは、紅組と白組に分かれてPV数で競う紅白戦を実施しました。
そのため、IVRy全体で25 x 2 = 50件のブログを投稿しました。
https://x.com/IVRy_jp/status/1730521537294520802?s=20

この進捗管理を人の手で行うのはとても大変なので、ブログ投稿に着手してない人に通知をするリマインダを作成しました。

余談ですが、私がアドカレで書いたブログが1万PVを超えてすごく嬉しかったです。
ただ、内容は私ではなくみんなの提案を書いているので、みんなの力で達成したPVだなと思っています。笑
https://zenn.dev/ivry/articles/d5ccc376d0840c

Notionで投稿予定日を管理

まず、Notionのデータベースにマスター情報を作ります。ここは手で作成する必要があります。

重要なプロパティとして

  • 投稿予定日
  • Status

    この2つの情報は必ず必要です。

どういった条件で通知をするか

合計4つの通知機能を作りました。

  1. 投稿日2週間前、1週間前に予定思い出しのためのリマインド
  2. 投稿予定日3日前なのにNotionのStatusが変わってない人へ強めのリマインド
  3. 投稿後にStatusを公開済みに変更するリマインド
  4. Statusがレビュー中になってる人を褒める通知

ただ単にリマインドするだけではなく、レビュー中になっている人を褒めることで「レビュー中にしたい!」という気持ちが湧けば良いなと思い、4つ目も実装しました。

Slackに通知するコードを実装

コードの中身は非常にシンプルで、大きく分けると

  1. Notionにクエリを投げる
  2. 文面を作ってSlackに投稿
    です。

イメージが湧くと思うので先に成果物を貼っておくと、下記のような通知機能を作成しました。

Notionにクエリを投げる

クエリの中身はNotionのデータベースによって変わると思いますので、ここでは一例を置いておきます。
下記は、「投稿予定日3日前なのにNotionのStatusが変わってない人」のクエリです。

def review_reminder_query():
    # データ取得のためのクエリ
    query = {
        "sorts": [
            {
                "property": "公開予定日",
                "direction": "ascending"
            }
        ],
        "filter": {
            "and": [
                {
                    "property": "公開予定日",
                    "date": {
                        "before": (datetime.now() + timedelta(days=3)).strftime('%Y-%m-%d'),
                    }
                },
                {
                    "property": "公開予定日",
                    "date": {
                        "after": (datetime.now() + timedelta(days=0)).strftime('%Y-%m-%d'),
                    }
                },
                {
                    "property": "Status",
                    "select": {
                        "does_not_equal": "公開済"
                    }
                },
                {
                    "property": "Status",
                    "select": {
                        "does_not_equal": "公開可能"
                    }
                },
                {
                    "property": "Status",
                    "select": {
                        "does_not_equal": "レビュー中"
                    }
                },
                {
                    "property": "Writer",
                    "people": {
                        "is_not_empty": True
                    }
                }
            ]
        }
    }

    # Notion APIにリクエストを送信
    response = notion_query(query)

def notion_query(query):
    # Notion APIのエンドポイントとヘッダー
    url = "https://api.notion.com/v1/databases/" + DATABASE_ID + "/query"
    headers = {
        "Accept": "application/json",
        "Notion-Version": "2022-06-28",
        "Authorization": "Bearer " + NOTION_API_KEY
    }
    response = requests.post(url, headers=headers, json=query)
    return response
    # Notion APIにリクエストを送信

文面を作ってSlackに投稿

こちらもNotionのクエリのレスポンスから通知内容を決めてSlackに通知するだけです。

def notify_slack(response, title, icon_emoji=u':mihogananteiukana:', user_name='mihoリマインド'):
    # レスポンスデータを取得
    data = response.json()
    for page in data.get('results', []):
        email = get_email(page)
        page_id = get_page_id(page)
        text = f"公開予定日: {get_release_date(page)}\n記事タイトル: {get_title_text(page)}"

        page_id = page_id.replace("-", "")
        page_url = f"https://www.notion.so/xxxx/xxxxx?p={page_id}"
        text = f"<@{email_to_slack_id(email)}>\n{title}\n{text}\n{page_url}"
        requests.post(WEBHOOK_URL, data=json.dumps({
            'text': text,  # 通知内容
            'username': user_name,  # ユーザー名
            'icon_emoji': icon_emoji,  # アイコン
            'link_names': 1,  # 名前をリンク化
        }))

Slackでメンションをした方が通知に気づくので、メールアドレスからSlackのuser_idを取得するコードも実装しました。Notionの情報からSlackにメンションできる(メールアドレスが一緒の場合)ので便利です。

def email_to_slack_id(email):
    client = WebClient(SLACK_ACCESS_TOKEN)
    response = client.users_lookupByEmail(email=email)
    return response['user']['id']

Github Actionsで定期実行する

あとは、該当のコードをGithub Actionsで定期実行すれば完成です。今回私が作ったymlを例として置いておきます。

on:
  schedule:
    - cron: '30 1 * * 1-5'
  workflow_dispatch:

jobs:
  numpy-test:
    runs-on: ubuntu-latest
    environment:
      name: production
    steps:
      - uses: actions/checkout@v2
      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'
          architecture: 'x64'
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run Python
        run: python review_reminder.py
        env:
          NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
          SLACK_ACCESS_TOKEN: ${{ secrets.SLACK_ACCESS_TOKEN }}
          WEBHOOK_URL: ${{ secrets.OUTERBLOG_WEBHOOK }}

些細なこだわり

些細なこだわりですが、リマインド側はバリエーションを1パターンにして、褒める側はバリエーションを30個以上作りました。リマインド側がおもしろいのではなく、褒める側におもしろさを置くことで、少しでもブログ執筆に取り掛かるまでの時間が早くなれば良いなという気持ちでそのような設計にしました。

また、ちょくちょく登場する「miho」についてですが、これはIVRyの大沼美穂さんから取っています。理由は、これまで大沼さんのがブログの進捗管理を行なっていたためです。そのため自動通知の名前を「miho bot」にしました。
https://note.com/miho_onuma/n/n1053fc427106

アイコンも大沼さんと全く同じアイコンにすることで、通知を受けた人は本物の大沼さんだと勘違いして、botの言うことを聞くのではないかという淡い期待を込めました(本人の許可を取ってから実装しています)

完成後の反応

IVRyメンバーが協力的なこともあり、アドカレは無事50件滞りなく投稿することができました!
所感としては、リマインドだけではなく、褒める通知が好評でした。

ぜひ実装する際は褒めるbotも作ってあげてください!笑

そして何より、これまでブログの進捗管理をしていた本人からの感謝の声がいただけたのが一番嬉しかったです!

今後の課題

IVRyでは、毎日ブログ投稿をやっています。この管理も自動化を目指しています。
一度書く人が決まればいいのですが、各人をアサインする部分はまだ自動化できていません。

今は、「mihoの涙」という通知で予定がない日を通知していますが、この通知だけでは予定が埋まらないので、最近執筆してない人を抽出してメンションする、などの工夫が必要だなと感じています。

さいごに

私が開発したこの機能は、IVRyの開発合宿での成果物になります。
https://zenn.dev/ivry/articles/93cffc3b6f5b03

普段のプロダクト開発だけではなく、こうした業務オペレーションの改善などに取り組めるのもIVRyの開発の楽しさだと思います。IVRyの別メンバーが作った社内業務支援システム系のブログもございますのでぜひこちらも見てください。
https://zenn.dev/ivry/articles/80ad98e7607034

そんなIVRyで働くことに少しでも興味が湧いた方、ぜひ採用情報を見ていってください!
https://ivry-jp.notion.site/IVRy-e1d47e4a79ba4f9d8a891fc938e02271

IVRyテックブログ

Discussion