Mattermostでリマインダーを作ってみたよ

この記事は、[富士通システムズウェブテクノロジー Advent Calendar](https://qiita.com/advent-calendar/2019/fsweb)の3日目の記事です。
（お約束）本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。

## はじめに
MattermostにはSlackと違い、リマインダーが標準で用意されていない。
社内でリマインダー機能が欲しいって意見があったので、「リマインダーくらい直ぐ作ってるよー」って意気込みで作ってみました。
※Slackと同じ使い勝手のリマインダーが一応プラグインとして提供されてるらしい。

## 用意するもの
- Node-RED
- SQLServer<br>※データベースを使ってますが、ファイルでも代用可能です。

## 処理について
### 登録処理：Mattermostのスラッシュコマンドからリマインダーを登録する。
1. ユーザーはスラッシュコマンドを入力する。<br>コマンド：`/reminder`
2. BOTはリマインダー登録ダイアログを作成しJSON形式でMattermostに送信する。
3. ユーザーはダイアログにリマインダーの登録したい情報を入力し、ボタンを押す
4. BOTは入力内容を受け取り、データベースに登録し、登録結果をMattermostにJSON形式で送信する。

### 通知処理：指定した日時になったらMattermostに通知を投げる。
1. BOTは毎分データベースにDELETE_FLGはOFFのリマインダー情報をSELECT文で受け取る。
2. SELECT文実行結果を1行ずつ読み込み、ユーザーの指定した日時が現在日時と一致した場合、Mattermostにリマインダー情報をJSON形式で送信する。

## 登録処理
Mattermostに表示されるダイアログは以下のとおりである。ここにリマインダー情報を入力し、DBに登録される。

<details><summary>ダイアログ</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528240/be6ced7f-dad8-daaa-3b58-10185fe2c7b4.png)
</div></details>

テキストボックスに日時のサブタイプがない為、yyyyMMddhhmm形式でゴリ押しで作成した。
とりあえず、日付と時間のところは現在の日時を入れ、必要がある人だけが書き換えれば良いという風にした。

<details><summary>ソースコード</summary><div>

````Javascript
var dt = new Date();
var message_help_text = "メッセージは本ダイアログ呼出し時のチャンネルにリマインドされます。" +
                        "プライベートチャンネルにはリマインド出来ません。" +
                        "Markdown記法に対応しています。" +
                        "メンションをメッセージに含ませると、指定したメンション先に通知が来るようになります。";
msg.payload = {
    url:"http://**.**.**.**:8888/reminder2",
    channel_id:msg.payload.channel_id,
    trigger_id:msg.payload.trigger_id,
    dialog: {
        title: "開発用リマインダー設定（公開チャンネルのみ）",
        submit_label: "SET",
        state:msg.payload.response_url + "," + msg.payload.channel_name + "," + msg.payload.user_name,
        elements: [
            {
                display_name: "メッセージ",
                name: "MESSAGE",
                type: "textarea",
                default:msg.payload.text,
                placeholder: "担当者は顧客に提示報告メールを送信してください。",
                help_text:message_help_text
            },
            {
                display_name: "繰り返し",
                name: "INTERVAL",
                type: "select",
                options: [
                    {
                        text: "しない",
                        value: "None"
                    },
                    {
                        text: "平日",
                        value: "Weekdays"
                    },
                    {
                        text: "休日",
                        value: "Holiday"
                    },
                    {
                        text: "毎日",
                        value: "EveryDay"
                    },
                    {
                        text: "毎週",
                        value: "EveryWeek"
                    },
                    {
                        text: "毎月",
                        value: "Monthly"
                    },
                ]
            },
            {
                display_name: "開始日付(yyyyMMdd)",
                name: "TARGET_DATE",
                type: "text",
                max_length:8,
                min_length:8,
                default:createDate(),
                placeholder:"yyyyMMdd",
                help_text:"デフォルト値：ダイアログ表示時の日付"
            },
            {
                display_name: "指定時刻(hhmm)",
                name: "TARGET_TIME",
                type: "text",
                max_length:4,
                min_length:4,
                default:createTime(),
                placeholder:"hhmm",
                help_text:"デフォルト値：ダイアログ表示時の時刻"
            }
        ],
    }
}
return msg;

function createDate()
{
    var format = String(dt.getFullYear());
    if(String((dt.getMonth() + 1)).length === 1) {
        format += "0" +  String((dt.getMonth() + 1));
    } else {
        format += String((dt.getMonth() + 1));
    }
    
    if(String(dt.getDate()).length === 1) {
        format += "0" +  String(dt.getDate());
    } else {
        format += String(dt.getDate());
    }
    return format;
}

function createTime()
{
    var format = null;
    if(String(dt.getHours()).length === 1) {
        format = "0" + dt.getHours(); 
    } else {
        format = String(dt.getHours());
    }
    
    if(String(dt.getMinutes()).length === 1) {
        format += "0" +  String(dt.getMinutes());
    } else {
        format += String(dt.getMinutes());
    }
    return format;
}

````
</div></details>

ダイアログで必要事項を入力し「SET」ボタンを押すと、コマンドを実行したチャンネルに以下のような通知がBOTから来る。

<details><summary>BOTからのメッセージ</summary><div>
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528240/7febc96e-5079-da15-ee38-3a5946a03896.png)
</div></details>



## 通知処理

先ほど登録したリマインダーはこんな感じで通知が来ます。
<details><summary>通知内容</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528240/da3524e7-c251-a1a2-cf08-5cc0e6d68ecb.png)
</div></details>

BOTは毎分データベースにDELETE_FLGはOFFのリマインダー情報をSELECT文で受け取り、条件と一致したリマインダーをMattermostに送信する。

<details><summary>ソースコード</summary><div>

```Javascript
var dt = new Date();
var WeekChars = [ "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日" ];
var wDay = WeekChars[dt.getDay()];
var hh = ("0"+dt.getHours()).slice(-2);
var mm = ("0"+dt.getMinutes()).slice(-2);
var hhmm = hh + "" + mm;
var yyyy = dt.getFullYear();
var MM = (dt.getMonth() + 1);
var dd = dt.getDate();
var yyyyMMdd = String(yyyy) + String(MM) + String(dd); 

var year = null;
var month = null;
var date = null;
var dayOfWeek = null;
var hour = null;
var minute = null;
var thisInterval = "Weekdays";
if (wDay === "日曜日" || wDay === "土曜日" ) {
        thisInterval = "Holiday";
}
for(i=0;i<msg.database.length;i++)
{
    year = msg.database[i].TARGET_DATE.slice(0, 4);
    month = msg.database[i].TARGET_DATE.slice(4, 6);
    date = msg.database[i].TARGET_DATE.slice( -2 );
    var targetDate =  new Date(parseInt(year), (parseInt(month) -1), parseInt(date));
    dayOfWeek = targetDate.getDay();
    
    if(msg.database[i].TARGET_TIME === hhmm) {
        if (msg.database[i].INTERVAL === "EveryDay") {
            return createMsg();　//毎日
        } else if (msg.database[i].INTERVAL === "None" && msg.database[i].TARGET_DATE === yyyyMMdd) {
            return createMsg();　//繰り返しなし
        } else if (msg.database[i].INTERVAL === thisInterval) {
            return createMsg(); //平日or休日
        } else if (dayOfWeek === dt.getDay() && msg.database[i].INTERVAL === "EveryWeek") {
            return createMsg(); // 毎週
        } else if (date === date && msg.database[i].INTERVAL === "Monthly") {
            return createMsg(); // 毎月
        }
    }
}
return null;

function createMsg() {
    if (msg.database[i].INTERVAL === "None") {
        msg.payload = {
            userName: "いつもアシスト ふくまろ",
            channel:msg.database[i].CHANNEL_NAME,
            text:"リマインドします。",
            attachments: 
            [{
                author_name:"REMINDER_ID." + msg.database[i].REMINDER_ID,
                text:msg.database[i].MESSAGE,
            }]
        };
        msg.database = {
            "REMINDER_ID":msg.database[i].REMINDER_ID,
            "CHANNEL":msg.database[i].CHANNEL_NAME,
            "INTERVAL":msg.database[i].INTERVAL
        };
    } else {
        msg.payload = {
            userName: "いつもアシスト ふくまろ",
            channel:msg.database[i].CHANNEL_NAME,
            text:"リマインドします。",
            attachments: 
            [{
                author_name:"REMINDER_ID." + msg.database[i].REMINDER_ID,
                text:msg.database[i].MESSAGE,
                actions:[{
                    name:"このリマインダーを停止させる",
                    integration: {
                        url: "http://**.**.**.**:8888/stop/reminder",
                        context:{
                            "REMINDER_ID":msg.database[i].REMINDER_ID,
                            "CHANNEL":msg.database[i].CHANNEL_NAME,
                            "INTERVAL":msg.database[i].INTERVAL
                        }
                    }
                }]
            }]
        };
    }
    return msg;
}
```
</div></details>

## ひとこと
Slackのコマンドより個人的には使いやすい自分好みのリマインダーを作ることが出来ました。
次回はプラグイン化してどこの環境でも使えるリマインダーに出来たらなぁって思ってます。ﾉｼ