Redmine から Slack に Mention 通知

在宅勤務とはあまり縁のない職場(うちの部署は在宅の方が効率良い筈)なのですが,緊急事態宣言の際には何日か在宅勤務をしていた訳で,その頃部署内で Slack が定着してくれた事もあり,色々インテグレーションをしています.今回,Redmine から Slack に Mention 通知できる事を知り,自分の環境に実装したので纏めておきます.
参考にさせていただいたのは,ふみ八さんの Post です.

oratio.hatenablog.com

うちの環境は残念ながら Slack user ID と Redmine の login ID が異なっていて,今から Slack ID を変更して... とも言えないので,別の属性から Slack ID を取得出来ないかなぁ?という所から始めました. redmine-slack plugin の install とかのあたりは端折って,ふみ八さんが公開している修正ソースにフォーカスする事にしたいと思います.


■ listener.rb

私は古いインフラ管理者なので,ruby も Slack API も初心者レベルですが,ソース読むくらいは出来るのでリファレンス探して試行錯誤すればなんとかなりそうと極めて楽観的でした(苦笑).すると,まさに私のためのような API Tester があるではないですか!ふみ八さんのソースでは client.users_list で取得した real_name を Redmine の login ID とマッチさせているので,Tester で取得出来る値から使えそうなものを探せば良さそうです.

    def getSlackID(user_name)
        @token = "<your token>"

        Slack.configure {|config| config.token = @token }
        client = Slack::Client.new

        client.users_list['members'].map{ |v|
            if v['real_name'] == "#{user_name}"
                return "#{v['id']}"
            end
        }
    end


早速,App 登録時に取得した Token を使って users.list Tester を実行してみると,取得できた値が戻ってきます.

        {
            "id": "MY_SLACK_ID",
            "team_id": "MY_TEAM_ID",
            "name": "My_NAME",
            "deleted": false,
            "color": "9f69e7",
            "real_name": "MY_REAL_NAME",
            "tz": "Asia\/Tokyo",
            "tz_label": "Japan Standard Time",
            "tz_offset": 32400,
            "profile": {
                "title": "MY_TITLE",
                "phone": "",
                "skype": "",
                "real_name": "MY_REAL_NAME",
                "real_name_normalized": "MY_REAL_NAME",
                "display_name": "MY_DISPLAY_NAME",
                "display_name_normalized": "MY_DISPLAY_NAME",
                "fields": null,
                "status_text": "\u5927\u5b66\u3067\u52e4\u52d9",
                "status_emoji": ":wink:",
                "status_expiration": 1595602799,
                "avatar_hash": "d8baa72dc71c",
                "image_original": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_original.png",
                "is_custom_image": true,
                "email": "MY_EMAIL",
                "first_name": "MY_FIRST_NAME",
                "last_name": "MY_LAST_NAME",
                "image_24": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_24.png",
                "image_32": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_32.png",
                "image_48": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_48.png",
                "image_72": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_72.png",
                "image_192": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_192.png",
                "image_512": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_512.png",
                "image_1024": "https:\/\/avatars.slack-edge.com\/2020-04-07\/1053339198996_d8baa72dc71c36ea14d5_1024.png",
                "status_text_canonical": "",
                "team": "MY_TEAM_ID"
            },
            "is_admin": true,
            "is_owner": true,
            "is_primary_owner": true,
            "is_restricted": false,
            "is_ultra_restricted": false,
            "is_bot": false,
            "is_app_user": false,
            "updated": 1595547262
        },


うちの環境では Redmine を AD 認証させているので,name の値が Redmine login ID と同じである事が分かりました.マッチさせる値を変更するだけなので,

            if v['name'] == "#{user_name}"

の修正だけで対応完了です!環境によっては email や skype 等の値でマッチさせるのもありですね.


■ 今回ハマった点
ふみ八さんの Blog では Legacy tokens へのリンクが貼られていたのですが,Slack の Incoming Webhook の設定が変わっていたので,正解に辿り着くまでに右往左往してしまいました(苦笑).詳細は Sending messages using Incoming Webhooks で説明されていますが,おおよそ以下の通りで動きます.

  1. https://api.slack.com/apps から "Create New App"
  2. OAuth & Permissions の Bot Token Scopes から必要な Scope を追加
  3. Incoming Webhooks を On にして Add New Webhook to Workspace で送信先の channel を指定.

これで,listener.rb 中に記載する Token も,plugin の configure から指定する Webhook URL も取得することができます.