質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • JavaScript

    20429questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • API

    1827questions

    APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

  • Hubot

    29questions

    HubotはGitHub社が開発したチャットbotのフレームワークです。

slackAPIで取得したユーザーIDをslackに投稿すると不具合

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 958

tarou212

score 1

backlogの課題が追加&更新された時に、hubotを通じてslackのチャンネルに投稿できるようにしました。
個人通知出来るように、slackAPIのuser.list(https://api.slack.com/methods/users.list/test)を使用し、backlogから取得した通知相手の名前を元にユーザーIDをslackに投稿し個人通知出来るようにしたのですが、backlogを更新すると通知相手がずれて通知されてしまいます。


1回目
山田さんに対してbacklog更新→slackに通知されない
2回目
山田さんに対してbacklog更新→山田さんに対してslackに通知される
3回目
佐藤さんに対してbacklog更新→山田さんに対してslackに通知される
4回目
山田さんに対してbacklog更新→佐藤さんに対してslackに通知される
5回目
鈴木さんに対してbacklog更新→山田さんに対してslackに通知される

下記の部分を消すとズレが無くなるので、slackAPIの部分の記述が原因だと考えています。
1回目のslackに通知されない時に、エラーログを見ると「ReferenceError: memberid is not defined」と書かれていました。

message += "<@" + memberid + ">"; //ここを消すとズレが直る

backlogからユーザー名の取得とユーザー名を元にslackAPIからslackのユーザーIDを取得する箇所です。

        if (body.notifications.length > 0) {
          ref1 = body.notifications;
          for (i = 0, len = ref1.length; i < len; i++) {
            a = ref1[i];
            username = "" + a.user.name;
            message += "" + a.user.name; //名前表示
            console.log(a.user.name);
            console.log(a.user.id);
            request.get({
              url: "https://slack.com/api/users.list?token=" + process.env.HUBOT_SLACK_TOKEN
            }, function(err, response, body) {
              var member;
                var j, len1, ref2;
                ref2 = JSON.parse(body).members;
                for (j = 0, len1 = ref2.length; j < len1; j++) {
                  member = ref2[j];
                  if (member.profile.display_name === username) { //slackの表示名とバックログの名前が一致した時に、slackID
                    memberid = member.id;//slackID取得
                  }
                }
            });
            message += "<@" + memberid + ">"; //ここを消すとズレが直る
          }
        }

全体のコード

var backlogUrl, request;

backlogUrl = 'https://backlog.jp/';

request = require('request');

module.exports = (function(_this) {
  return function(robot) {
    return robot.router.post("/slackroom/:room", function(req, res) {
      var a, body, error, i, label, len, message, username, ref, ref1, ref2, room, url,memberid;
      room = req.params.room;
      body = req.body;
      console.log('body type = ' + body.type);
      console.log('room = ' + room);
      try {
        switch (body.type) {
          case 1:
            label = '課題の追加';
            break;
          case 2:
          case 3:
            label = '課題の更新';
            break;
          default:
            return;
        }
        url = backlogUrl + "view/" + body.project.projectKey + "-" + body.content.key_id;
        if (((ref = body.content.comment) !== null ? ref.id : void 0) !== null) {
          url += "#comment-" + body.content.comment.id;
        }
        message = "*Backlog " + label + "*\n";
        if (body.notifications.length > 0) {
          ref1 = body.notifications;
          for (i = 0, len = ref1.length; i < len; i++) {
            a = ref1[i];
            username = "" + a.user.name;
            message += "" + a.user.name; //名前表示
            console.log(a.user.name);
            console.log(a.user.id);
            request.get({
              url: "https://slack.com/api/users.list?token=" + process.env.HUBOT_SLACK_TOKEN
            }, function(err, response, body) {
              var member;
                var j, len1, ref2;
                ref2 = JSON.parse(body).members;
                for (j = 0, len1 = ref2.length; j < len1; j++) {
                  member = ref2[j];
                  if (member.profile.display_name === username) { //slackの表示名とバックログの名前が一致した時に、slackID
                    memberid = member.id;//slackID取得
                  }
                }
            });
            message += "<@" + memberid + ">";
          }
        }
        message += "\n[" + body.project.projectKey + "-" + body.content.key_id + "] - ";
        message += body.content.summary + " _by" + body.createdUser.name + "_\n>>> ";
        if (((ref2 = body.content.comment) !== null ? ref2.content : void 0) !== null) {
          message += body.content.comment.content + "\n";
        }
        message += "" + url;
        console.log('message = ' + message);
        if (message !== null) {
          robot.messageRoom(room, message);
          return res.end("OK");
        } else {
          robot.messageRoom(room, "Backlog integration error.");
          return res.end("Error");
        }
      } catch (_error) {
        error = _error;
        console.log(error);
        return robot.send;
      }
    });
  };
})(this);

コールバック関数を使用した記述

        if (body.notifications.length > 0) {
          ref1 = body.notifications;
          for (i = 0, len = ref1.length; i < len; i++) {
            a = ref1[i];
            username = "" + a.user.name;
            message += "" + a.user.name; //名前表示
            console.log(a.user.name);
            console.log(a.user.id);
          }
          function execCallback (callback) {
            request.get({
              url: "https://slack.com/api/users.list?token=" + process.env.HUBOT_SLACK_TOKEN
            }, function(err, response, body) {
              var member;
                var j, len1, ref2;
                ref2 = JSON.parse(body).members;
                for (j = 0, len1 = ref2.length; j < len1; j++) {
                  member = ref2[j];
                  if (member.profile.display_name === username) { //slackの表示名とバックログの名前が一致した時に、slackID
                    memberid = member.id;//slackID取得
                  }
                }
            });
              callback();
           }
           var myCallback = function () {
           message += "<@" + memberid + ">"; 
           };
           execCallback(myCallback);
        }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • CHERRY

    2018/03/01 17:40

    slack api の呼び出しをを非同期で実行されていますが、「message += "<@" + memberid + ">";」の部分で、memberid に slack の id は、入っているのでしょうか?

    キャンセル

  • tarou212

    2018/03/01 17:41

    message += "<@" + memberid + ">";で、通知相手(slackのID)をslackに投稿している部分で、こちらがslack上で「undefined」と表示されました。backlogのユーザー名(a.user.name)とslackの表示名(member.profile.display_name)が一致した人のみ、slackのID(member.id)を取得し、slackのIDをslackに投稿したいです。

    キャンセル

  • tarou212

    2018/03/01 17:45

    message += "<@" + memberid + ">";で、backlogから1度目の更新&追加した時は、「ReferenceError: memberid is not defined」とエラーログが表示されて入っていないのですが、2回目以降は、slackIDは、入っています。途中で通知相手を変えると質問の例に書いてあるように、一人分ズレて相手に通知されます。

    キャンセル

回答 1

checkベストアンサー

+1

原因はおそらく、memberidがグローバル変数になっていてrequest.getのコールバック内で非同期に値が変わるため、このような状況になっているのからではないかと思います。

  • memberid = undefined
  • 1回目 -> request -> memberid = undefined に通知
  • requestのresponseが返ってくる -> memberid = 1回目のslack id
  • 2回目 -> request -> memberid = 1回目のslack id に通知
  • ...

request.getは非同期なので完了を待って結果を得てから送信しなければいけません。つまりrequest.getの後に書いてある処理はすべてrequest.getのコールバックで実行する必要があります。

補足: 上の最後の文は、request.getforループ内で毎回実行するのではなく、最初に一回だけ行う、という前提での話でした。


細かい所は適当ですがこんな感じの構成にすればいいのではないでしょうか。

if (body.notifications.length > 0) {
  ref1 = body.notifications;
  request.get({
    url: "https://slack.com/api/users.list?token=" + process.env.HUBOT_SLACK_TOKEN
  }, function(err, response, body) {
    var member;
    var j, len1, ref2;
    ref2 = JSON.parse(body).members;
    for (i = 0, len = ref1.length; i < len; i++) {
      a = ref1[i];
      username = "" + a.user.name;
      message += "" + a.user.name; //名前表示
      console.log(a.user.name);
      console.log(a.user.id);
      for (j = 0, len1 = ref2.length; j < len1; j++) {
        member = ref2[j];
        if (member.profile.display_name === username) { //slackの表示名とバックログの名前が一致した時に、slackID
          var memberid = member.id; //slackID取得
          message += "<@" + memberid + ">";
        }
      }
    }
    appendFooterAndSend();
  });
} else {
  appendFooterAndSend();
}

function appendFooterAndSend() {
  message += "\n[" + body.project.projectKey + "-" + body.content.key_id + "] - ";
  message += body.content.summary + " _by" + body.createdUser.name + "_\n>>> ";
  if (((ref2 = body.content.comment) !== null ? ref2.content : void 0) !== null) {
    message += body.content.comment.content + "\n";
  }
  message += "" + url;
  console.log('message = ' + message);
  if (message !== null) {
    robot.messageRoom(room, message);
    return res.end("OK");
  } else {
    robot.messageRoom(room, "Backlog integration error.");
    return res.end("Error");
  }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/01 18:27 編集

    ご回答ありがとうございます!
    まずは、request.getをループ外で実行してみます!

    キャンセル

  • 2018/03/01 19:01

    コールバック関数を使ってみたのですが、試してみた結果動作は、変わりませんでした。どこかおかしい点がありましたらご教授お願いします。コードは、質問のコールバック関数を使用した記述に記載してあります。

    参考サイト:https://qiita.com/matsuby/items/3f635943f25e520b7c20

    キャンセル

  • 2018/03/01 20:10

    それだと何も変わってないですね...。また、結局 memberid はどこで宣言されているのでしょうか?

    キャンセル

  • 2018/03/01 20:13

    また、コールバックというのはrequest.getの第2引数のことを言ってました。

    キャンセル

  • 2018/03/02 10:52

    ありがとうございます!回答のコードで、backlogから課題の更新&追加をした時に、hubotを通してslackに通知したい相手のslackIDを投稿することが出来ました!

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    20429questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • API

    1827questions

    APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

  • Hubot

    29questions

    HubotはGitHub社が開発したチャットbotのフレームワークです。