티스토리 뷰
요즘 반복적인 운영 업무가 지속적으로 오는 것에 대해서 어떻게 처리할까 고민하던 와중 slack app으로 처리할 수 있지 않을까라는 문득 번쩍이는 생각이 들었다.
슬랙 앱을 만들어주고 그것을 유관부서에서 처리를 해주면 내가 개발할 수 있는 시간을 더 벌수 있을테니까...
우선 어떻게 작동시킬건지 아키텍처 먼저 간단하게 그려냈다.
대략적인 로직은 다음 위의 플로우대로 처리했다.
1.Block-kit
그러면 우선 Block-kit을 통해 원하는 view를 만들어 볼까?
https://app.slack.com/block-kit-builder
필자는 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
slack 관련 라이브러리로서 사용하는 데 있어서 상당히 편리하므로 애용하시길 바란다.
3. Slack app
1. oAuth & Permissions
scopes는 우선 필요해보이는 것만 클릭했는데 독자들이 판단해서 추가하시면 될 것 같습니다.
install Workspace를 클릭해주자
App Home 에 들어가서 Message Tab 아래에 있는 Allow~~ 를 클릭해주자
2. Slash Commands
slash commands는 모달 뷰를 가져올 때 사용되는 기능이라고 생각하면 된다.
필자는 로컬로 테스트 할 때 ngrok이라는 것을 썼다.
리눅스나 맥의 환경에서
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_id
private_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
- docker-compose
- DRF
- Linux
- setattr
- 프로그래머스
- 그래프
- docker
- Java
- Celery
- headers
- 자바
- 면접
- 카카오
- dockerignore
- django
- Command Line
- Collections
- Spring
- 2021 KAKAO BLIND RECRUITMENT
- env
- thread
- 백준
- 파이썬
- Python
- BFS
- Pattern
- PostgreSQL
- postgres
- 알고리즘
- ubuntu
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |