気まぐれ緋夜子

アウトプット力がほしい

perlでslack apiをちょっと使ってみた

最近slackを使う時間が増えて、起きてる時間がほとんどslackを開いています。そろそろ自分用のリマインドbotか面白いものが書きたくなったから、slackのapiをちょっと使ってみました。

api.slack.com

公式のドキュメントです。感想はやればなんでもできる、素晴らしいです。


tokenはhttps://api.slack.com/webで取れます

use Furl;
use HTTP::Request::Common;

my $req = POST 'https://slack.com/api/chat.postMessage',
    'Content' => [
        token   => "xxxxxxxxxxxxxxxxxxx"
        channel => "#test",
        text    => "test",
    ];
my $res = Furl->new->request($req);

でメセッジーが送れます。(https://api.slack.com/methods/chat.postMessage


デフォルトはこんな感じです:
f:id:hiyoko9191:20150614191449p:plain

usernameとicon_urlも送ったら画像と名前が簡単に変更できます:
f:id:hiyoko9191:20150614191748p:plain

as_userをtrueにすれば自分のアカウントで発言できます。
自分がいないPRIVATE GROUPには発言できないです。

自分の場合はslackチームが多いから毎回指定するのも面倒だから、ちょっとyamlにまとめました。

#yaml/config.yaml
slack_token:
   test-slack: "xoxp-xxxxxxxxxxxxxxxxxxx"

#yaml/setting.yaml
bot_type:
  katosan:
    username: "加藤さん"
    icon_url:
      - "https://docs.google.com/uc?id=0Bwf35y4fWlHhNHlvdm5HbkdzRms&ext=.png"
mode:
  test:
    token: "test-slack"
    channel: "test-channel"
    text: "test"
    bot: "katosan"

yamlはこんな感じです。

use YAML;
use Getopt::Long;

my $config = YAML::LoadFile("./yaml/config.yaml");
my $setting = YAML::LoadFile("./yaml/setting.yaml");
...

    my $opts = {};
    GetOptions($opts,
        'mode=s',
        'bot=s',
        'token=s',
        'channel=s',
        'text=s',
        'username=s',
        'icon_url=s',
        'file=s',
        'filename=s',
    );

    #mode
    if ($opts->{mode}) {
        die "no mode $opts->{mode}" unless ($setting->{mode} and $setting->{mode}->{$opts->{mode}});
        my $mode = $setting->{mode}->{$opts->{mode}};
        while (my ($key, $value) = each %$mode) {
            $opts->{$key} //= $value;
        }
    }

    #bot
    if ($opts->{bot} and $setting->{bot_type}) {
        my $bot = $setting->{bot_type}->{$opts->{bot}};
        die "no bot $opts->{bot}" unless $bot;
        $opts->{username} //= $bot->{username};
        unless (ref $bot->{icon_url} eq "ARRAY") {
            $opts->{icon_url} //= $bot->{icon_url};
        }   
        else {
            my $randam = rand(scalar @{$bot->{icon_url}}); 
            $opts->{icon_url} //= $bot->{icon_url}->[int($randam)];
        }   
    }

これからはmodeを指定すれば簡単に発言できます。

$ perl slack-test.pl --mode=test


ファイルも送れます(https://api.slack.com/methods/files.upload)。

    my $post = {
        token    => "xxxxxxxxx",
        channels => $channel_id,
        filename => $opts->{filename},
        file     => [$opts->{file}],
    };

    my $req = POST ('https://slack.com/api/files.upload',
        Content-Type => 'form-data',
        Content      => [
            %$post,
        ]);
    my $res = Furl->new->request($req);

主にAPIで画像をアプデートしたいです。

ちょっとハマったのは主に2点:
1:ここのchannelsはチャンネルの名前じゃなくてIDです
2:ファイルの送り方

slackの仕様では、CHANNELSと PRIVATE GROUPは分けています。
https://api.slack.com/methods/channels.list
https://api.slack.com/methods/groups.list
上の二つのAPIでgroupsとchannelsの参照表がもらえます。

# get channel id by channel name
sub _get_channel_id {
    my ($channel, $token) = @_; 

    my $res_channels = Furl->new->post('https://slack.com/api/channels.list', [], +{ token => $token });
    my %channels  = map { sprintf('#%s', $_->{name}) => $_->{id} } @{decode_json($res_channels->content)->{channels}};
    my $channel_id = $channels{$channel};
    return $channel_id if $channel_id;

    my $res_groups = Furl->new->post('https://slack.com/api/groups.list', [], +{ token => $token });
    my %groups  = map { sprintf('#%s', $_->{name}) => $_->{id} } @{decode_json($res_groups->content)->{groups}};
    $channel_id = $groups{$channel};
    return $channel_id if $channel_id;

    die "can't find channel id";
}

後もいろいろ使いところあるからあらかじめ参照表をyamlに保存します。

# make slack map
sub make_slack_map {
    my %slack_map;
    while (my ($key, $value) = each %{$config->{slack_token}}) {
        my $res_channels = Furl->new->post('https://slack.com/api/channels.list', [], +{ token => $value });
        my $res_groups = Furl->new->post('https://slack.com/api/groups.list', [], +{ token => $value });
        my %channels  = map { $_->{id} => $_->{name} } (@{decode_json($res_channels->content)->{channels}}, @{decode_jso<
        my $res_users = Furl->new->post('https://slack.com/api/users.list', [], +{ token => $value });
        my %users = map { $_->{id} => $_->{name} } @{decode_json($res_users->content)->{members}};
        $slack_map{$key} = {
            channels => \%channels,
            users => \%users,
        };
    }
    YAML::DumpFile("yaml/slack_map.yaml",\%slack_map );
    say "make slack map success";
}