[Go]slack apiでチャンネル名/ユーザ名からチャンネルID/ユーザーIDを検索する
経緯
- slack apiのパラメータにはchannel idやuser idが必要
- 手動でも取得できるがブラウザ開く必要があるのでちと面倒
参考: SlackのチャンネルIDを確認する方法 - Qiita
- じゃあチャンネル名/ユーザー名でIDを検索する処理を作ろう
チャンネル名からIDを検索する
参考: SlackのチャンネルIDを確認する方法 - Qiita
slackのOAuth Tokensを作る方法は探せば出てくるので省略。
必要な権限は以下の通りです。
権限 |
---|
channels:read |
slackでチャンネル名からIDを検索するためにはconversations.listでチャンネル一覧を取得する必要があります。
そしてこのconversations.listには一度で取得できるチャンネル数に上限があるためチャンネルが多い場合はcursorを指定して何度か叩かなければいけません。
今回はslack-go/slackという便利なライブラリがあるのでこれを使用します。
内部でリクエストを作成してGET叩いてるだけなのでapiを直接GETで叩いても行けると思います。
実装してみるとこんな感じ。
package slackclient
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/slack-go/slack"
)
type SlackClient interface {
SearchChannel(ctx context.Context, channelName string) (*slack.Channel, error)
}
type slackClient struct {
Api *slack.Client
}
func NewClient(token string, options ...slack.Option) SlackClient {
api := slack.New(token, options...)
return &slackClient{api}
}
func (s slackClient) SearchChannel(ctx context.Context, channelName string) (*slack.Channel, error) {
var cursor string
for {
requestParam := &slack.GetConversationsParameters{
// public, private両方対象にしていますがどちらかにする場合は不要な方を外せばok
// conversations.list的にはDMも対応しているけど今回は対象外
Types: []string{"public_channel", "private_channel"},
// Must be an integer no larger than 1000.
// https://api.slack.com/methods/conversations.list#arg_limit
Limit: 1000,
// アーカイブされたチャンネルは除外
// アーカイブされたチャンネルも検索したいならfalseに設定
ExcludeArchived: "true",
}
if cursor != "" {
requestParam.Cursor = cursor
}
var channels []slack.Channel
var err error
channels, cursor, err = s.Api.GetConversationsContext(ctx, requestParam)
if err != nil {
return nil, errors.WithStack(err)
}
for _, channel := range channels {
if channel.Name == channelName {
return &channel, nil
}
}
if cursor == "" {
break
}
}
return nil, errors.New(fmt.Sprintf("channel not found. channelName=%s", channelName))
}
一度のapi callで全部のチャンネルを取り切れないのでそこまでシンプルにはならないが、一度実装してしまえば使い回せるのでヨシ。
早速テストを書いて動作確認をしてみる。
package slackclient_test
import (
"context"
"github.com/stretchr/testify/assert"
"os"
"testing"
"trial-go/syusya/slackclient"
)
func TestSlackClient_SearchChannel(t *testing.T) {
token := os.Getenv("SLACK_TOKEN")
if !assert.NotZero(t, token) {
t.FailNow()
}
t.Run("Search for existing channel", func(t *testing.T) {
ctx := context.Background()
client := slackclient.NewClient(token)
channelName := "harada-debug"
channel, err := client.SearchChannel(ctx, channelName)
if !assert.NoError(t ,err) {
t.FailNow()
}
assert.Equal(t, channelName, channel.Name)
})
t.Run("Search for non-existent channel", func(t *testing.T) {
ctx := context.Background()
client := slackclient.NewClient(token)
channelName := "not exists channel"
_, err := client.SearchChannel(ctx, channelName)
assert.Error(t ,err)
})
}
=== RUN TestSlackClient_SearchChannel
--- PASS: TestSlackClient_SearchChannel (1.52s)
=== RUN TestSlackClient_SearchChannel/Search_for_existing_channel
channel_id=<チャンネルID>, channel_name=harada-debug
--- PASS: TestSlackClient_SearchChannel/Search_for_existing_channel (0.87s)
=== RUN TestSlackClient_SearchChannel/Search_for_non-existent_channel
error: channel not found. channelName=not exists channel
--- PASS: TestSlackClient_SearchChannel/Search_for_non-existent_channel (0.65s)
PASS
上手く動いてますね。
ちょっと心配なのは例えばチャンネル数が1万とかあった場合10回api callが連続で飛ぶけどapi limitに引っかからないかなという所ですかね。
api limitに引っかかった場合はwait入れてみるしかないのかもしれません。
ユーザー名からIDを検索する
チャンネル一覧と違ってユーザ一覧はcursor操作がないのでシンプルです。
ただし、検索対象としてはメンションで指定する表示名はuser.Name
ではなくuser.Profile.DisplayName
になるので注意が必要です。
権限 |
---|
- |
package slackclient
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/slack-go/slack"
)
type SlackClient interface {
SearchChannel(ctx context.Context, channelName string) (*slack.Channel, error)
SearchUser(ctx context.Context, userName string) (*slack.User, error)
}
func (s slackClient) SearchUser(ctx context.Context, userName string) (*slack.User, error) {
users, err := s.Api.GetUsersContext(ctx)
if err != nil {
return nil, errors.WithStack(err)
}
for _, user := range users {
if user.IsAppUser || user.IsBot || user.Deleted {
continue
}
if user.Profile.DisplayName == userName {
return &user, nil
}
}
return nil, errors.New(fmt.Sprintf("user not found. userName=%s", userName))
}
テストで動かしてみます。
func TestSlackClient_SearchUser(t *testing.T) {
token := os.Getenv("SLACK_TOKEN")
if !assert.NotZero(t, token) {
t.FailNow()
}
t.Run("Search for existing user", func(t *testing.T) {
ctx := context.Background()
client := slackclient.NewClient(token)
userName := "tharada"
user, err := client.SearchUser(ctx, userName)
if !assert.NoError(t, err) {
t.FailNow()
}
assert.Equal(t, "tharada", user.Profile.DisplayName)
fmt.Printf("user_id=%s, user_name=%s\n", user.ID, user.Profile.DisplayName)
})
t.Run("Search for non-existent user", func(t *testing.T) {
ctx := context.Background()
client := slackclient.NewClient(token)
userName := "not exists user"
_, err := client.SearchUser(ctx, userName)
assert.Error(t, err)
})
}
=== RUN TestSlackClient_SearchUser
--- PASS: TestSlackClient_SearchUser (2.45s)
=== RUN TestSlackClient_SearchUser/Search_for_existing_user
user_id=<user id>, user_name=tharada
--- PASS: TestSlackClient_SearchUser/Search_for_existing_user (1.22s)
=== RUN TestSlackClient_SearchUser/Search_for_non-existent_user
--- PASS: TestSlackClient_SearchUser/Search_for_non-existent_user (1.23s)
無事ユーザ名からユーザー情報が取得できました。
Author And Source
この問題について([Go]slack apiでチャンネル名/ユーザ名からチャンネルID/ユーザーIDを検索する), 我々は、より多くの情報をここで見つけました https://qiita.com/tomtwinkle/items/797769c6257caed14536著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .