티스토리 뷰

반응형

요즘 반복적인 운영 업무가 지속적으로 오는 것에 대해서 어떻게 처리할까 고민하던 와중 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이라는 것을 썼다.

https://ngrok.com/download

 

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_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를 통해  운영 업무를 유관 부서에게 넘기는 개발자의 흔적입니다. 하하...

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함