Slack APIを使ってユーザーグループのメンバーをCSVからまとめて追加する

Slackのユーザグループ管理が面倒なのでなんとか楽にしようとしてみた．
今回やりたいことのイメージはGSuiteのユーザー追加のときみたいに，CSVを読み込んでまとめてメンバーを追加する．

最低限の動作確認しかしていないので，使用するときは自己責任で．
（使用してる関数が，以前のグループメンバーに上書きされるのでとても注意）

追記：Slackの名前にはfullname, displaynameなどたくさんあって，一意にもとめにくかったのでemailで追加できるうように変更しました．

#参考資料
https://api.slack.com/methods
https://api.slack.com/apps/AK24J41GT/oauth?success=1

https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html

#環境
MacOS Mojave 10.14.5
Python3.7
slackclient 2.0.1

#ユーザグループのメンバーの出力
まずは現在存在するユーザグループとその中にいるユーザをまとめてCSVに出力する．
###使用したScope
- usergroups:read 
- usergroups:write
- users:read 
- users:read.email


###ソースコード

インポートと関数定義

```python
import os
import slack
import json
import pandas as pd
import datetime

LOG_PATH = 'log/'
USERGROUP_PATH = 'usergroups/'
if not os.path.exists(LOG_PATH): os.mkdir(LOG_PATH)
if not os.path.exists(USERGROUP_PATH): os.mkdir(USERGROUP_PATH)


def get_usergroups_list(client):
    user_groups = client.usergroups_list()
    if user_groups['ok']:
        return user_groups['usergroups']
    else:
        assert user_groups['ok']
        return None


def get_users(client):
    userdata = client.users_list()
    if userdata["ok"]:
        return userdata['members']
    else:
        assert userdata['ok']
        return None


def get_usergroups_member(client, user_groups_id):
    member = client.usergroups_users_list(usergroup=user_groups_id)
    if member['ok']:
        return member['users']
    else:
        assert member['ok']
        return None
```

メイン関数（もっと上手く書きたい）
今回は必要そうなデータだけとって出力するようにした．

```python
if __name__ == '__main__':
    client = slack.WebClient(token=os.environ['SLACK_API_TOKEN'])

    users = get_users(client)
    user_groups = get_usergroups_list(client)

    df_users = pd.DataFrame(users)
    df_user_groups = pd.DataFrame(user_groups)

    # get current users who are in each user group
    for group_id in df_user_groups['id']:
        group_members = get_usergroups_member(client, group_id)
        save_data = pd.DataFrame({},
                                 columns={'group_id', 'group_name', 'user_id', 'user_name', 'user_real_name', 'email'})
        save_data['group_id'] = [group_id] * len(group_members)
        save_data['group_name'] = list(df_user_groups[df_user_groups['id'] == group_id]['name'].values) * len(
            group_members)
        save_data['user_id'] = df_users[df_users['id'].isin(group_members)].loc[:, 'id'].values
        save_data['user_name'] = df_users[df_users['id'].isin(group_members)].loc[:, 'name'].values
        save_data['user_real_name'] = df_users[df_users['id'].isin(group_members)].loc[:, 'real_name'].values
        save_data['email'] = df_users[df_users['id'].isin(save_data['user_id'])]['profile'].values
        save_data['email'] = save_data['email'].apply(lambda x: x['email'])
        save_data.to_csv(USERGROUP_PATH + "usergroups_" + save_data['group_name'][0] + "_list.csv")
```

#ユーザグループのメンバーの追加
###形式の決定
CSVの形式は次のようにした．

|Group Name          |User EMAIL            |
|:------------------:|:-------------------:|
|              Test1 |       Mr. Test1     |
|              Test1 |       Mr. Test2     |
|              Test1 |       Mr. Test3     |
|              Test1 |       Mr. Test4     |


この形式のCSVを読み込んでそれぞれのユーザグループにユーザを追加していく．
内部でIDとの紐付けを行い，最終的にAPIに送るのは以下のテーブル

| Group ID         |Group Name      |User ID             |User EMAIL           |
|:-----------------|---------------:|:------------------:|:------------------:|
|      T04J043MC   |          Test1 | T04J041MC          |       Mr. Test1    |
|      T04J043MC   |          Test1 | T04J042MC          |       Mr. Test2    |
|      T04J043MC   |          Test1 | T04J043MC          |       Mr. Test3    |
|      T04J043MC   |          Test1 | T04J044MC          |       Mr. Test4    |


ユーザグループが存在しないときはエラーとしてログに吐き出すようにする．

###ソースコード

```python
def usergroups_users_update(client, user_group, users):
    update = client.usergroups_users_update(usergroup=user_group, users=users)
    log = "upload_log" + datetime.datetime.today().strftime("%Y%m%d_%H%M%S") + ".txt"
    if update['ok']:
        with open(LOG_PATH + log, "w") as f:
            f.write("uploaded to {0} correctly: {1}".format(user_group, update['usergroup']['users']))
        return update['usergroup']
    else:
        assert update['error']
        with open(log, "w") as f:
            f.write("Error: {0}".format(update['error']))
        return None

if __name__ == '__main__':
    filename = "template.csv"
    filelist = glob.glob("template/*")

    client = slack.WebClient(token=os.environ['SLACK_API_TOKEN'])
    # ユーザのemailとIDとの紐付けを取得
    users = get_users(client)
    df_useremails = pd.DataFrame(users)

    # print(template)
    # ユーザグループの名前とIDとの紐付けを取得
    user_groups = get_usergroups_list(client)
    df_user_groups = pd.DataFrame(user_groups)
    for filename in filelist:
        if filename in ['template/template_CMAll.csv', 'template/template_tokyoCMAll.csv',
                        'template/template_tokushimaCMAll.csv', 'template/template_onagawaCMAll.csv',
                        'template/template_obuseCMAll.csv', 'template/template_tfcs.csv', ]:
            continue
        print(filename)
        template = pd.read_csv(filename)
        # 更新したいユーザグループIDとユーザーIDをグループ名とユーザー名と対応させる
        upload_data = pd.DataFrame({}, columns={'usergroup_id', 'usergroup_name', 'user_id', 'user_email'})
        upload_data['usergroup_name'] = template['usergroup_name'].values
        upload_data['user_email'] = template['user_email'].values
        upload_data['usergroup_id'] = template.apply(
            lambda x: df_user_groups[df_user_groups['name'].isin(template['usergroup_name'])]['id'], axis=1
        )
        tmp = pd.DataFrame(list(df_useremails['profile']))
        
        upload_data['user_id'] = df_useremails[tmp.loc[:, 'email'].isin(template['user_email'])].loc[:, 'id'].values
        upload_data = upload_data.groupby('usergroup_id')['user_id'].apply(",".join)
        print(len(upload_data))
        # 更新(以前のユーザーリストは消滅して新しく作成される)
        for key, value in upload_data.items():
            usergroups_users_update(client, key, value)
```


tmplate.csvに先ほどの2列のテーブルを作成すれば既存のグループメンバーを更新することができる．

pandasの処理がとても大変だった．なんかもっとうまい書き方をしたい（切実）．