user icon

Slackのリアクション通知から元のメッセージを取得

前回のリアクション通知からリスト表示をした際に、リアクションを付けた元メッセージも表示したいと思います。

1.Appのパーミッション追加

https://api.slack.com/messaging/retrieving
メッセージ取得方法については、こちらを参考に進めます。
※最初から元メッセージが付いているわけではなく、しかも取得にid的なものが使えないとか不便だったりします。

https://api.slack.com/apps から前回のReactionListを表示し、Add features and functionalityからPermissionsをクリックします。
User Token Scopesにメッセージを取得するための各history権限(groups.history im.history mpim.history channels.history)を追加します。
前回追加したread権限はそのまま残します。
ブラウザ上部に黄色い帯が表示されるので、reinstall your appのリンクをクリックすると再度権限の確認が出るので、許可するをクリックします。
これで権限については完了です。

2.PHP

今度はPHP側です。まずはメッセージの取得と整形を行うクラスclass_slack_message.phpを作成します。
メッセージがファイルだったりBotのものだったりすると勝手が違って来るのでその分の調整をしたり、取得するメッセージがSlackのマークダウン形式なのでテキスト表示用に変換したりと、面倒さが増してきます。
他のパターンも有ると思うので、実際にはもっと処理が必要になってくると思います。
<?php
include_once(__DIR__."/class_slack_base.php");
//
class SlackMessage extends SlackBase{
    /**
     * イベント元のメッセージデータを取得
     *
     * @param array $json
     * @param string $type
     * @return array
     */
    function getMessage(array $json, string $type="reaction"):array{
        $RET = array();
        $Params = ["inclusive"=>"true", "limit"=>1];
        switch($type){
            case "reaction":default:
                if(!isset($json["event"])){var_dump($json);throw new Exception("no json.event");}
                $channel_id = $json["event"]["item"]["channel"];
                $ts = $json["event"]["item"]["ts"];
                if(!$channel_id){throw new Exception("no channel id");}
            break;
        }
        $Params["channel"] = $channel_id;
        $Params["latest"] = $ts;
        $cache = true;
        // https://api.slack.com/messaging/retrieving
        $RET = $this->get("https://slack.com/api/conversations.history", $Params, $cache);
        return $RET;
    }
    /**
     * getMessage()からテキスト形式で抜き出して返す
     *
     * @param array $json
     * @param string $type
     * @return string
     */
    function getMessageText(array $json, string $type="reaction"):string{
        $Data = $this->getMessage($json, $type);
        //
        $Messages = $Data["messages"];
        $text = colVal($Messages[0], "text");
        if(!$text){
            // ファイルのみ
            if(isset($Messages[0]["files"][0])){
                $File = $Messages[0]["files"][0];
                $text = colVal($File, "preview");
                if(!$text){
                    $text = colVal($File, "name");
                }
            }else if(isset($Messages[0]["attachments"][0])){
                $Attach = $Messages[0]["attachments"][0];
                $text = colVal($Attach, "pretext");
                if(!$text){
                    $text = colVal($Attach, "text");
                }
            }
        }
        if(!$text){
            echo "<pre>". print_r($json, true)."</pre>";
            echo "<pre>". print_r($Data, true)."</pre>";
            throw new Exception("No Text");
        }else{
            $text = $this->textJustify($text);
            $text = "\t".str_replace("\n", "\n\t", $text);
            $text .= "\n\n";
        }
        return $text;
    }
    /**
     * Slack形式のマークダウンをtext形式に直す
     *
     * @param string $text
     * @return string
     */
    function textJustify(string $text):string{
        // @ユーザ
        preg_match_all("/<@(.*)>/", $text, $matches);
        foreach($matches[0] as $key => $from){
            $to = "@".colVal($this->UserNames, $matches[1][$key]);
            $text = str_replace($from, $to, $text);
        }
        // url補完を消す
        preg_match_all("/<http([^|]*)[|]([^>]*)>/", $text, $matches);
        foreach($matches[0] as $key => $from){
            $to = $matches[2][$key];
            $text = str_replace($from, $to, $text);
        }
        // http link等を
        preg_match_all("/<([^>]*)>/", $text, $matches);
        foreach($matches[0] as $key => $from){
            $to = $matches[1][$key];
            $text = str_replace($from, $to, $text);
        }
        return $text;
    }
    /**
     * リアクション内容を表示
     *
     * @param array $json
     * @return string
     */
    function dispReaction(array $json):string{
        $Data = $this->reaction2DispData($json);
        extract($Data);
        //
        $line = $time."\t".$channel."で".$user."が".$m_user."の発言に:".$reaction.": のリアクションをしました。\n";
        return $line;
    }
    /**
     * イベントから表示に必要なデータを作る
     *
     * @param array $json
     * @return array
     */
    function reaction2DispData(array $json):array{
        $event = $json["event"];

        // timestamp
        $ts = $event["event_ts"];
        $time = date("Y-m-d H:i:s", $ts);

        // channel
        $channel_id = $event["item"]["channel"];
        $channel = colVal($this->ChannelNames, $channel_id);

        // reaction user
        $user_id = $event["user"];
        $user = colVal($this->UserNames, $user_id);

        // message user
        if(isset($event["item_user"])){
            $m_user_id = $event["item_user"];
            $m_user = colVal($this->UserNames, $m_user_id);
        }else if(isset($json["api_app_id"])){
            $m_user_id = "";
            $m_user = "Bot";
        }else{
            var_dump($json);
            throw new Exception("No From User");
        }

        // reaction
        $reaction = $event["reaction"];

        $RET = compact("time", "channel", "user", "m_user", "reaction");
        return $RET;
    }
}
reaction_list.phpを書き換えます。
<?php
{   // setting
    define("TEMP_DIR", __DIR__."/.file");
    if(!is_dir(TEMP_DIR)){mkdir(TEMP_DIR);}
    define("CACHE_DIR", TEMP_DIR."/cache");
    if(!is_dir(CACHE_DIR)){mkdir(CACHE_DIR);}
    define("LOG_DIR", __DIR__."/logs");
    // method
    function colVal($Arr, $key){
        return (isset($Arr[$key]))? $Arr[$key]: "";
    }
    include(__DIR__."/class_slack_message.php");
}
{
    $slack = new SlackMessage();
    $Users = $slack->getUsers();
    $Channels = $slack->getChannels();
}

if($handle = opendir(LOG_DIR)){
    while(false !== ($file = readdir($handle))){
        $path = LOG_DIR."/".$file;
        if(is_file($path)){
            $str = file_get_contents($path);
            $json = json_decode($str, true);
            if($json){
                echo $slack->dispReaction($json);
                // text message
                echo $slack->getMessageText($json);
            }
        }
    }
}
Slackのメッセージ取得APIについては正直複雑な感じがします。なので手順というか表示までが長いです。元メッセージがファイルだったりBotからのものだったりすると、主文に当たるものの場所が散逸しているのが最も嫌です。
出来ればAltTextプロパティとか何か適当な名前を付けてメッセージの主文的なものを共通化してくれるとありがたいのですが・・・。 Facebooktwitterlinkedintumblrmail

Tags:

名前
E-mail
URL
コメント

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)