brunch

You can make anything
by writing

C.S.Lewis

by 유윤식 Nov 12. 2021

Python & Slack API Code

#message post, update, delete hand-on

이어서,

그럼 메시지를 어떻게 게시하고, 수정하고, 삭제할 수 있을까?


1. https://api.slack.com/

여기에서 Create an app 을 통해서 앱을 하나 생성한다.

그럼 두가지 옵션이 보인다.

첫째는 From scratch, 둘째는 From an app manifest(BETA)

일단 첫번째를 선택!


그럼 App Name에 원하는 이름을 넣고,

Pick a workspace to develop you app in 에서 자신의 Workspace 를 선택!


그럼,

Your Apps 에 생성한 App 이 나타단다.


이번엔 중요한 개인정보를 살펴봐야하는데,

OAuth & Permissions 를 찾아가서 페이지를 열어보면

- OAuth Tokens for Your Workspace

- Redirect URLs

- Scopes


위 3가지를 확인한다.

Redirect URLs 는 개인이 직접 적어줘야하는데,

localhost 이런건 안되다...


나는 ngrok 으로 잠시 URL을 생성해서 사용하는데,

각자 설치해서 임시 도메인을 얻어서 활용할 수 있다.


https://gist.github.com/wosephjeber/aa174fb851dfe87e644e



Scope 는 접근권한을 말하는데,

일단 헤딩(?)을 하면서 어떤 권한이 필요한지 알려주는 정보를 바탕으로 각 권한에 대한 공부를 시작해도 될 것 같다.


이제 다음 스텝으로,

Imcoming Wehooks 페이지에서 

Active Incoming Webhooks 를 활성화 해준다.

이제 아래쪽에서

Webhook URLs for Your Workspace

을 설정해준다.


내 Workspace 에 있는 채널, 사람에 대해서 Webhook URL을 생성하는데,

테스트를 위해서

한개의 Direct Message Channel과 두개의 Chat Message Channel을 생성했다.

마지막으로

Interactivity & Shortcuts 페이지에 Request URL을 등록하면 끝이나는데,

이건 내 웹 서버로 응답을 받을 용도로 사용한다.

물론 활성화 해줘야 사용이 가능하다.


슬랙 API 에서 해야할 준비는 끝이다.


이제 간단한 파이썬 서버를 만들면 되는데

사실 코드를 공유하는게 좀 귀찮고 의미도 없다.


서버는 각자 알아서 Flask, Go, Node, FastAPI, 등등 사용해서

후딱 만들면 되고,


Route 코드만 잠시 살펴보면

두개를 만들껀데


@app.post("/slack/message/")
async def slack_msg(channel: SlackChannel, msg: str = None):
    # 보내려는 message 내용만 간단하게 바꿔치고,
    blocks[0].update({"text": {
            "type": "plain_text",
            "text": f"{msg}",
            "emoji": True
        }})
    # message를 Slack 특정 채널로 보내는데,
    res = client.chat_postMessage(channel=channel.name,
                                  user="YOUR_USER_ID",
                                  blocks=blocks,
                                  as_user=True)
    # 결과는 이렇더라.
    print(res)
    return "OK"


@app.post("/from_slack/")
async def post_slack(request: Request):
    # slack 에서 응답을 받아서 뭔가 처리를 하고,
    res: Form(...) = await request.form()
    j = json.loads(res['payload'])
    # 그 다음에 해당 메시지를 수정해 주면 되는데,
    res = client.chat_update(channel=j['container']['channel_id'],
                             ts=j['container']['message_ts'],
                             text="updated from fastapi",
                             blocks=blocks2)

    # 결과는 이렇더라.
    print(res)
    return "OK"


결국 메시지를 보내는건 너무나 쉽게

채널 정보와 사용자 아이디만 있으면 보낼 수 있다.


blocks 에 어떠한 Interactivity Component 를 넣어서 보내는지

그리고 어떤 결과를 서버에서 받아보는지를 확인한다.



# 슬랙 Tester 코드 어느 부분에서 가져다가 썼다.

blocks = [
    {
        "type": "header",
        "text": {
            "type": "plain_text",
            "text": "New request",
            "emoji": True
        }
    },
    {
        "type": "section",
        "fields": [
            {
                "type": "mrkdwn",
                "text": "*Type:*\nhello world!"
            }
        ]
    },
    {
        "type": "section",
        "fields": [
            {
                "type": "mrkdwn",
                "text": "*When:*\nAug 10 - Aug 13"
            }
        ]
    },
    {
        "type": "actions",
        "elements": [
            {
                "type": "button",
                "text": {
                    "type": "plain_text",
                    "emoji": True,
                    "text": "Approve"
                },
                "style": "primary",
                "value": "Answer is 0"
            },
            {
                "type": "button",
                "text": {
                    "type": "plain_text",
                    "emoji": True,
                    "text": "Reject"
                },
                "style": "danger",
                "value": "answer is 1"
            }
        ]
    }
]


심플하다.


Message를 보내보면,

Swagger 를 통해서 messsage 를 #cs_web 채널로 보낸 결과다.

blocks 에 대해서는 참고 페이지를 살펴보면서 만들면 된다.


주목할 부분은 Approve, Reject 버튼이다.

버튼을 눌렀을 때, 우리가 등록한 Interactivity & Shortcuts 페이지에 Request URL 을 통해서

응답을 받을 수 있다.


일단 눌러보면

버튼이 사라졌다.

코드에서 blocks2 로 만들어 놓은 값에서 임의로 버튼을 제거한 뒤에 기존 message 를 update 했다.


서버-사이드 로그에는 이런 결과물이 적혀있다.


{'ok': True, 'channel': 'CHANNEL_ID_MASKED', 'ts': '1636710721.001400', 'text': 'updated from fastapi', 'message': {'bot_id': 'B02M76P7BUZ', 'type': 'message', 'text': 'updated from fastapi', 'user': 'U01RW7ZSWE4', 'team': 'T01RK249XU1', 'bot_profile': {'id': 'B02M76P7BUZ', 'app_id': 'A02LU31G5MG', 'name': 'SLACK_IC_TEST', 'icons': {'image_36': 'https://a.slack-edge.com/80588/img/plugins/app/bot_36.png', 'image_48': 'https://a.slack-edge.com/80588/img/plugins/app/bot_48.png', 'image_72': 'https://a.slack-edge.com/80588/img/plugins/app/service_72.png'}, 'deleted': False, 'updated': 1636547213, 'team_id': 'T01RK249XU1'}, 'blocks': [{'type': 'header', 'block_id': 'Z4Km', 'text': {'type': 'plain_text', 'text': '응답이 정상적으로 수정 되었어요.', 'emoji': True}}, {'type': 'section', 'block_id': 'qmeq', 'fields': [{'type': 'mrkdwn', 'text': '*Type:*\nUpdated', 'verbatim': False}, {'type': 'mrkdwn', 'text': '*Created by:*\nSik', 'verbatim': False}]}, {'type': 'section', 'block_id': 'wGu', 'fields': [{'type': 'mrkdwn', 'text': '*When:*\nAug 10 - Aug 13', 'verbatim': False}]}]}}



이게 끝이다.

사용자의 응답, 여기서는 버튼을 통해서 Approve, Reject 라는 두가지 응답을 받았다.

서버-사이드에서는 이 응답을 아마도 DB에 업데이트 시킬 수 있고

또는 다른 Slack 채널에 포워딩 시켜 줄 수 있다.


다양한 시나리오가 있을 수 있는데,

여기서는 기존의 message를 update 함으로써 해당 채널의 메시지를 어떻게 핸들링 할 수 있는지에 집중했다.


위의 전체적인 흐름을 따라해보려면

Python, Slack_sdk, FastAPI 를 공부해야한다.

https://fastapi.tiangolo.com/

https://slack.dev/python-slack-sdk/web/index.html#messaging


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari