bpeldi2oerkd8の開発日誌

とあるひよっこエンジニアの成長の記録。

Botを使った出欠確認機能の実装 - 自作サービスづくり7

今回の記事もWeb開発に関する記事です。
前回はslack上のbotから前々回実装した出欠更新APIを叩きました。
developer-bpeldi2oerkd8.hatenablog.com

このままでは、現在の出欠情報を確認する際にその都度出欠を更新する必要があります。
このため、出欠情報の確認のみをする機能も必要だと考えました。
そこで、今回は出欠確認APIを実装し、botからこのAPIを叩いてみたいと思います。

出欠確認APIの実装

出欠更新APIと同じように実装していきます。
基本的には同じで、変更部分はAvailabilityの更新部分をfindOneに変えるだけです。

    getData()
    .then(([schedule, user, date]) => {
      Availability.findOne({
        where: {
          scheduleId: schedule.scheduleId,
          userId: user.userId,
          dateId: date.dateId
        }
      })
      .then((a) => {
        if(a) {
          res.json({
            status: 'OK',
            data: {
              slackId: user.slackId,
              date: date.date,
              availability: a.availability
            }
          });
        }
        //出欠登録情報がない場合は欠席
        else {
          res.json({
            status: 'OK',
            data: {
              slackId: user.slackId,
              date: date.date,
              availability: 0
            }
          });
        }
      });
    })
    .catch(([scheduleMessage, userMessage, dateMessage]) => {
      res.json({
        status: 'NG',
        error: {
          messages: [scheduleMessage, userMessage, dateMessage]
        } 
      });
    });

データベースに出欠情報が登録されていない場合は欠席として扱っているため、その処理が入っています。

そのほかのコードについてはこちらです。
github.com

エラーメッセージが正しく出力されるように修正

テストコードを書き、正常時は登録が可能になったことが確認できたのですが、予定に存在しない日付を入れるとエラーメッセージが正常に返ってこない問題がありました。

私はエラーが出た場合Promiseのrejectでエラーメッセージを返していたのですが、Javascriptでは複数のPromiseを非同期処理する場合、1つrejectでエラーを返されると、そこでcatch内の処理に入ってしまうそうです。
今回はエラーが発生した場合、そのすべてのエラーメッセージを出力したかったため、エラーが起きた場合でもresolveでエラー状態であることを返し、その後エラーメッセージを配列にしてJSONで返す情報に入れました。

具体的には、以下のようにエラーの場合'error'という文字列を返し、

  if(d) {
    resolve(d);
  }
  else {
    resolve('error');
  }

エラーの場合は、そのエラーメッセージをmessagesという配列に入れるようにしました。

  schedule = schedule === 'error' ? 'このルームIDはシステムに登録されていません' : '';
  user = user === 'error' ? 'このSlackIDはシステムに登録されていません' : '';
  date = date === 'error' ? '入力した日付はこの予定に存在しません' : '';
  const messages = [];
  if(schedule) {
    messages.push(schedule);
  }
  if(user) {
    messages.push(user);
  }
  if(date) {
    messages.push(date);
  }

もう少しきれいに書けるような気もしますが、ひとまずこちらで行きます。

コードの詳細については以下のようになっています。
github.com

Jestでテストコードを書き、問題がないか確認しました。
結果がこちらです。
f:id:bpeldi2oerkd8:20210621205255p:plain
問題なくテストが通っています。

BotからAPIを叩く

APIが完成したので、今度はbotのほうを実装していきます。
出欠更新APIの時と同じように実装します。
違いは、今回はPOSTではなく、GETを用いる点です。

function confirmAvailability(msg, roomId, slackId, dateString){
  const confirm_url = api_url + '/' + roomId + '/users/' + slackId + '/dates/' + dateString;

  msg.http(confirm_url)
  .get() ((err, res, body) => {
    if(err) {
      msg.send(err);
      return;
    }

    const data = JSON.parse(body);
    const availabilityStatus = ['欠席', '不明', '出席'];
    if(data.status === 'OK'){
      msg.send('出欠確認成功:' + '<@' + data.data.slackId + '> さんの' 
        + data.data.date + 'の予定は ' + availabilityStatus[data.data.availability] + ' です');
    } 
    else {
      msg.send('出欠確認失敗:' + '\n' + data.error.messages.join('\n'));
    }
  });
} 

そのほかのコードについてはこちらです。
github.com

動作確認

どちらも完成したため、動作確認をします。
Slack上のbotから決められた形式でbotにメンションすると、結果を返してくれます。
出欠を確認する場合は、

@bot名 確認 日付(月/日の形式)

でメッセージを送ります。

実際に動かした結果がこちらです。
f:id:bpeldi2oerkd8:20210621211353j:plain
エラーの場合はエラーメッセージを返しています。
はじめ6/15の予定が欠席だったのが、出欠更新後出席に変わっていることがわかります。

Webサイト(Lattendance)の表示も出席に更新されています。
f:id:bpeldi2oerkd8:20210621211755j:plain


今回は、出欠確認機能の実装に取り組みました。
次回こそは、APIの認証に取り組みたいと思います。