티스토리 뷰
요즘 반복적인 운영 업무가 지속적으로 오는 것에 대해서 어떻게 처리할까 고민하던 와중 slack app으로 처리할 수 있지 않을까라는 문득 번쩍이는 생각이 들었다.
슬랙 앱을 만들어주고 그것을 유관부서에서 처리를 해주면 내가 개발할 수 있는 시간을 더 벌수 있을테니까...
우선 어떻게 작동시킬건지 아키텍처 먼저 간단하게 그려냈다.

대략적인 로직은 다음 위의 플로우대로 처리했다.
1.Block-kit
그러면 우선 Block-kit을 통해 원하는 view를 만들어 볼까?
https://app.slack.com/block-kit-builder
Slack
nav.top { position: relative; } #page_contents > h1 { width: 920px; margin-right: auto; margin-left: auto; } h2, .align_margin { padding-left: 50px; } .card { width: 920px; margin: 0 auto; .card { width: 880px; } } .linux_col { display: none; } .platform_i
app.slack.com


필자는 4개의 뷰 기능 중 Modal Preview 기능을 사용하였다.
		{
			"dispatch_action": true,
			"type": "input",
			"element": {
				"type": "plain_text_input",
				"dispatch_action_config": {
					"trigger_actions_on": [
						"on_character_entered"
					]
				},
				"action_id": "plain_text_input-action"
			},
			"label": {
				"type": "plain_text",
				"text": "Label",
				"emoji": true
			}
		},
기본 input 형태는 다음과 같이 이루어져있다.
여기서 우리가 주의 깊게 다룰 필드는
- action_id
- label.text
두 부분이다. action_id는 나중에 해당 값의 key의 형태로 사용할 예정이다.
label.text는 모달 뷰에서 인 풋 제목에 해당하는 부분으로 독자들이 원하는 필드의 이름을 작성해주시면 된다.
2. slack-sdk
https://github.com/slackapi/python-slack-sdk
GitHub - slackapi/python-slack-sdk: Slack Developer Kit for Python
Slack Developer Kit for Python. Contribute to slackapi/python-slack-sdk development by creating an account on GitHub.
github.com
slack 관련 라이브러리로서 사용하는 데 있어서 상당히 편리하므로 애용하시길 바란다.
3. Slack app


1. oAuth & Permissions

scopes는 우선 필요해보이는 것만 클릭했는데 독자들이 판단해서 추가하시면 될 것 같습니다.

install Workspace를 클릭해주자


App Home 에 들어가서 Message Tab 아래에 있는 Allow~~ 를 클릭해주자
2. Slash Commands
slash commands는 모달 뷰를 가져올 때 사용되는 기능이라고 생각하면 된다.


필자는 로컬로 테스트 할 때 ngrok이라는 것을 썼다.
ngrok - download
Install ngrok via Homebrew $ brew install ngrok/ngrok/ngrok Download ZIP file Intel (AMD64) Apple Silicon (ARM64) Then unzip ngrok from the terminal $ Install ngrok via Chocolatey $ choco install ngrok Download ZIP file Windows (64-bit) Windows (32-bit) Do
ngrok.com
리눅스나 맥의 환경에서
ngrok http 80
과 같이 적으면 임시적으로 도메인을 사용할 수 있다.
그럼 이제 코드 레벨로 가볼까요?
import slack_sdk
from flask import Flask, request, make_response
app = Flask(__name__)
token = ''
@app.route('/request-view', methods=['POST'])
def request_view():
    slack_client = slack_sdk.WebClient(token=token)
    print(request.form)
    trigger_id = request.form.get('trigger_id')
    channel_id = request.form.get('channel_id')
    command = request.form.get('command')[1:]
    from views import views
    view = views[command]
    if view:
        view['private_metadata'] = channel_id
        slack_client.views_open(trigger_id=trigger_id, view=view)
    return make_response("", 200)
if __name__ == '__main__':
    app.run()
views = {
    "테스트": {
        "callback_id": "테스트",
        "type": "modal",
        "title": {
            "type": "plain_text",
            "text": "My App",
            "emoji": True
        },
        "submit": {
            "type": "plain_text",
            "text": "Submit",
            "emoji": True
        },
        "close": {
            "type": "plain_text",
            "text": "Cancel",
            "emoji": True
        },
        "blocks": [
            {
                "type": "section",
                "text": {
                    "type": "plain_text",
                    "text": "This is a plain text section block.",
                    "emoji": True
                }
            },
            {
                "dispatch_action": True,
                "type": "input",
                "element": {
                    "type": "plain_text_input",
                    "dispatch_action_config": {
                        "trigger_actions_on": [
                            "on_character_entered"
                        ]
                    },
                    "action_id": "test_id"
                },
                "label": {
                    "type": "plain_text",
                    "text": "테스트 아이디",
                    "emoji": True
                }
            },
            {
                "dispatch_action": True,
                "type": "input",
                "element": {
                    "type": "plain_text_input",
                    "dispatch_action_config": {
                        "trigger_actions_on": [
                            "on_character_entered"
                        ]
                    },
                    "action_id": "dummy"
                },
                "label": {
                    "type": "plain_text",
                    "text": "더미",
                    "emoji": True
                }
            }
        ]
    }
}
위의 코드를 돌리면 다음과 같이 뜹니다.
코드에서 보시면
    trigger_id = request.form.get('trigger_id')
    channel_id = request.form.get('channel_id')이렇게 두개가 있습니다.
trigger_id는 모달 뷰를 띄우기 위해 필요한 인자 값으로서 가지고 있어야 합니다.
channel_id는 응답을 보낼 때 가지고 있어야 하므로 미리 get 해놨습니다.
command = request.form.get('command')[1:]command는 view의 이름과 똑같이 해놨는데 그 이유는 if문을 안 적기 위한 꼼수라 보시면 됩니다.
 ('command', '/테스트'),내용은 이런식으로 오는데 [1:]을 하게 되면 온전히 command만 가져올 수 있습니다.
view['private_metadata'] = channel_idprivate_metadata는 자바스크립트에서의 hidden 필드로서 겉에는 안보이고 값을 취하고 싶을 때 쓸 수 있는 필드입니다. 그래서 채널 정보를 위와 같이 저장했습니다.
그러면 이제 view-submission 작업에 대해서 해볼까요?
interactivity & shortcuts


위와 같이 해주세요
그리고 코드 상에서는 다음과 같습니다.
@app.route('/submit', methods=['POST'])
def submit():
    from flask import make_response
    payload = json.loads(request.form.get('payload'))
    action_type = payload['type']
    if action_type == 'view_submission':
        view = payload['view']
        channel_id = view['private_metadata']
        state = view['state']
        state_values = state['values']
        request_body = {}
        for _, item in state_values.items():
            for k, v in item.items():
                request_body[k] = v['value']
        slack_client = slack_sdk.WebClient(app.config['SLACK_OAUTH_TOKEN'])
        slack_client.chat_postMessage(channel=channel_id, text=request_body.__str__())
    return make_response('', 200)

2중 for문에 대해서 이해하기 쉽게 하기 위해 다음 위의 json 형태를 보자.
8bRH 이라는 key와 {'dummy': {'type': 'plain_text_input', 'value': '바이'}이라는 value가 있다.
우리는 그 중에
dummy라는 key에 바이 라는 value의 값을 취하고 싶다.그래서 다음과 같은 2중 for문이 나오게 된다.

실제 서버에 전송하는 것은 python 모듈인 requests 를 사용하시면 됩니다.
이렇게 modal를 통해 운영 업무를 유관 부서에게 넘기는 개발자의 흔적입니다. 하하...
'회고록' 카테고리의 다른 글
| [회고록] 라인 합격하기까지(코테/필기/1차면접/2차면접) [신입공채][2022][상반기] (3) | 2022.06.11 | 
|---|---|
| Django 와 Spring 둘 다 해보며 개인적으로 느낀 점들 (0) | 2022.05.06 | 
| [Refactoring] 조건문이 많다면 리팩토링을 해야할 시점이다. (0) | 2022.03.05 | 
| [회고] 응답에 대한 처리 속도 개선 방안은 뭐가 있을까? (2) | 2022.02.26 | 
| 2021년 전반기 끝없는 실패 그리고 하나의 성공 (0) | 2021.06.27 | 
- Total
- Today
- Yesterday
- BFS
- Celery
- Java
- Collections
- Linux
- 카카오
- postgres
- setattr
- 면접
- 2021 KAKAO BLIND RECRUITMENT
- Python
- headers
- dockerignore
- 알고리즘
- 그래프
- django
- docker
- 프로그래머스
- ubuntu
- docker-compose
- DRF
- thread
- Spring
- 파이썬
- Pattern
- PostgreSQL
- env
- 자바
- Command Line
- 백준
| 일 | 월 | 화 | 수 | 목 | 금 | 토 | 
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 | 
| 12 | 13 | 14 | 15 | 16 | 17 | 18 | 
| 19 | 20 | 21 | 22 | 23 | 24 | 25 | 
| 26 | 27 | 28 | 29 | 30 | 31 |