장고(Django) 이용해서 슬랙(Slack)에 출석체크 챗봇 만들기 [2]

     

 

이전 글 - 2020/11/22 - [Study/서버] - 장고(Django) 이용해서 슬랙(Slack)에 출석체크 챗봇 만들기 [1]

 

 

들어가기 전에

 

지난 포스팅에서 슬랙 채널에서 메시지가 발생했을 때 Slack API를 통해서 장고 서버로 사용자 ID와 메시지가 들어오는 것을 확인했습니다.

 

이제 특정 메시지가 왔을 때 사용자를 구분하여 출석을 체크해주는 로직을 넣고, 다시 슬랙 채널로 메시지를 보내는 작업을 진행해볼 예정입니다. 출석체크 로직은 여러분이 재미있게 만드실 수 있습니다. 저는 간단히~ 출석 체크하면 점수가 1점이 오르고, 연속으로 출석을 할 경우 연속(combo)만큼 점수가 오르는 로직을 넣어보겠습니다. ㅎㅎ

 

 

 

 

 

일단 슬랙 채널로 메시지를 보내보자

 

python에서 slack으로 메시지를 보내는 방법은 간단합니다. slacker라는 패키지를 받으면 코드 몇줄로 슬랙으로 메시지를 전달할 수 있습니다. (오픈소스 만세)

 

pip install slacker

 

slacker를 설치하고 나서 슬랙에서 넘어온 메시지를 처리하는 부분에 슬랙 채널로 응답하는 내용을 적어줍니다. 딱 3줄만 추가하면 됩니다.

 

# ~/slackbot/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from slacker import Slacker

# 봇 토큰 추가
bot_token = 'xoxb-'

# Create your views here.
class Attend(APIView):
    def post(self, request):
        """
        슬랙에서 채팅 이벤트가 있을 때 호출하는 API
        :param request:
        :return:
        """

        # 요청이 어떻게 들어오나 찍어보기
        print(request.body)

        # body에서 challenge 필드만 빼오기
        challenge = request.data.get('challenge')

        user = request.data.get('event').get('user')
        text = request.data.get('event').get('text')
        print("사용자 :", user, "| 메시지 :", text)

        # 토큰으로 slacker를 만들어줍니다.
        slack = Slacker(bot_token)
        # 요기가 메시지 보내는 부분 
        slack.chat.post_message('#일반', f'너가 쓴 메시지:{text}', as_user=True)

        # 응답 데이터로 { challenge : challenge } 주기
        return Response(status=200, data=dict(challenge=challenge))

 

Slacker를 import하고 bot_token값을 넣어줍니다. 여기서 bot_token은 여러분의 slack-bot에 대한 토큰이기 때문에 슬랙 API페이지에서 확인할 수 있습니다.

 

요거를 가지고 가시면 됩니다.

 

slack.chat.post_message에서는 보내는 채널과 메시지, 그리고 as_user 옵션을 넣었는데 이 옵션을 as_user=None으로 넣으면 봇 프로필 사진이 안 나옵니다. 한번 바꿔해 보세요 ㅎㅎ

 

이제 서버를 다시 기동시키고 슬랙에 메시지를 써봅시다.

 

얌마

오 바로 응답 오죠?

그런데,,,

 

뭐야 무서워,,

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

봇이 자기가 쓴 메시지에 반응해서 응답을 보내줍니다. 

혼자서 무한 루프,,,,

얼른 서버를 끕니다.

 

이 문제를 해결하기 위해 로그를 봅니다.

 

사용자가 입력한 메시지랑 봇이 입력한 메시지는 포맷이 다르다!!

 

사용자가 입력한 메시지는 client_msg_id를 달고 옵니다. 근데 봇이 혼자 입력한 메시지는 bot_id를 달고 오네요. 그럼 event에 bot_id가 있고 없고로 봇인지 사람인지를 구분할 수 있겠죠!!?!?!? 

아니면 사용자가 U01C9LJS1PF일경우 무시하도록 할 수 있습니다. 이 사용자 id 값이 아마 안 바뀔 거니까 이걸로 해볼게요~

 

# ~/slackbot/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from slacker import Slacker

# 봇 토큰 추가
bot_token = 'xoxb-'

# Create your views here.
class Attend(APIView):
    def post(self, request):
        """
        슬랙에서 채팅 이벤트가 있을 때 호출하는 API
        :param request:
        :return:
        """

        # 요청이 어떻게 들어오나 찍어보기
        print(request.body)

        # body에서 challenge 필드만 빼오기
        challenge = request.data.get('challenge')

        user = request.data.get('event').get('user')
        text = request.data.get('event').get('text')
        print("사용자 :", user, "| 메시지 :", text)

        if user == 'U01C9LJS1PF':
            print("봇 메시지")
        else:
            # 토큰으로 slacker를 만들어줍니다.
            slack = Slacker(bot_token)
            # 요기가 메시지 보내는 부분
            slack.chat.post_message('#일반', f'너가 쓴 메시지:{text}', as_user=None)

        # 응답 데이터로 { challenge : challenge } 주기
        return Response(status=200, data=dict(challenge=challenge))
​

 

중간에 if문으로 user가 봇이 아닐 경우에만 post_message로 메시지를 보내주게 만들었습니다. 다시 한번 슬랙에 메시지를 날려볼까요? 

 

한번만 깔끔
위는 사용자 아래는 봇

 

자 이제 사람과 봇을 구분할 수 있게 되었습니다~!!!!!

 

 

 

 

사용자별로 출석체크 하기

 

채널에서 "ㅊㅊ"이라는 단어를 쓰면 출석 count를 +1해 주도록 하겠습니다. 일단 출석한 데이터를 저장할 수 있는 모델을 만들어야겠죠? models.py에서 간단하게 사용자의 id와 count를 저장할 수 있는 모델을 만들어줍니다.

 

# ~/slackbot/models.py
from django.db import models


# Create your models here.
class Attention(models.Model):
    user_id = models.CharField(max_length=20, unique=True)
    attend_count = models.IntegerField(default=0)

    class Meta:
        db_table = 'attention'
        verbose_name = '출석체크'

 

모델을 만들었으면 makemigrations -> migrate를 해주어야 합니다. (Django에 대해서 아신다고 생각하고 자세한 설명은 생략하겠습니다.)

 

만약 모델을 추가했는데도 makemigrations시 변경된 점을 찾을 수 없다고 나온다면, settings.py에 있는 INSTALLED_APP에 우리가 새로 만든 app인 slackbot을 추가해주었는지 확인합니다.

 

slackbot을 추가하세요~
migrate

 

 

이제 DB까지 만들어졌습니다. 이제 사용자가 'ㅊㅊ'라고 입력했을 때 로직을 만들어 봅시다.

 

from rest_framework.views import APIView
from rest_framework.response import Response
from slacker import Slacker
from .models import Attention

# 봇 토큰 추가
bot_token = 'xoxb-'

# Create your views here.
class Attend(APIView):
    def post(self, request):
        """
        슬랙에서 채팅 이벤트가 있을 때 호출하는 API
        :param request:
        :return:
        """

        # 요청이 어떻게 들어오나 찍어보기
        # print(request.body)

        # body에서 challenge 필드만 빼오기
        challenge = request.data.get('challenge')

        user = request.data.get('event').get('user')
        text = request.data.get('event').get('text')
        print("사용자 :", user, "| 메시지 :", text)

        # 메시지가 봇인지 체크
        if user == 'U01C9LJS1PF':
            print("봇 메시지")
        else:
            # 토큰으로 slacker를 만들어줍니다.
            slack = Slacker(bot_token)
            # 요기가 메시지 보내는 부분
            # slack.chat.post_message('#일반', f'너가 쓴 메시지:{text}', as_user=None)

            # 출석체크 인지 확인
            if text == 'ㅊㅊ':
                attention = Attention.objects.filter(user_id=user).first()
                if attention is None:
                    Attention.objects.create(user_id=user, attend_count=1)
                else:
                    attention.attend_count = attention.attend_count + 1
                    attention.save()
                slack.chat.post_message('#일반', f'출석체크!: {attention.attend_count}회', as_user=None)


        # 응답 데이터로 { challenge : challenge } 주기
        return Response(status=200, data=dict(challenge=challenge))

 

사용자의 메시지를 그대로 슬랙으로 보내주던 곳에 메시지가 'ㅊㅊ'이면 출석 횟수를 +1해 주는 코드를 추가했습니다.

 

1. Attention 모델에서 채팅을 입력한 사용자의 id를 검색

2. 사용자의 id가 있으면 attend_count를 1 증가

3. 없으면 attend_count=1로 해서 신규 생성 (최초 출첵인 경우)

 

이제 슬랙에서 ㅊㅊ를 입력해 봅시다.

 

ㅊㅊ

정상적으로 출석체크가 작동하는 모습이군요.

 

 

 

추가적인 기능 넣기

 

출석체크 기능을 만들기는 했는데 뭔가 부족해 보이죠? ㅊㅊ을 입력할 때마다 횟수가 1회씩 올라가니,, ㅊㅊ을 막 입력하면 엄청 늘어날 겁니다. 이러면 출석체크가 아무 의미 없죠? 하루에 한 번씩만 체크가 되도록 조금 수정해봅시다.

 

 

 

어떻게 수정하면 될까요?

 

 

.

.

.

.

.

 

 

 

 

가장 마지막 출석체크 날짜를 기록하고, 오늘 출석체크를 했으면 패스, 오늘이 아니면 출석체크를 시켜주게 만들면 됩니다!! 물론 다른 방법도 있겠지만~~~ 저는 이걸로!

 

날짜를 기록하기 위해 models.py에서 datetime필드를 하나 추가해줍니다.

 

 

# ~/slackbot/models.py

from django.db import models
from django.utils import timezone


# Create your models here.
class Attention(models.Model):
    user_id = models.CharField(max_length=20, unique=True)
    attend_count = models.IntegerField(default=0)
    last_attend = models.DateTimeField(default=timezone.now())

    class Meta:
        db_table = 'attention'
        verbose_name = '출석체크'

 

default에 timezone.now()를 넣어놓으면 create 할 때 자동으로 오늘 날짜를 넣습니다. (입력을 안 할 경우)

 

attention db

테이블을 까 보면 위처럼 날짜가 저장되는 걸 볼 수 있습니다.

 

이제 ㅊㅊ을 할 때, last_attend가 오늘인지 체크해서 오늘이면 이미 출석체크를 한 것이니 PASS, 아니면 count +1을 해주면 됩니다.

 

 # ~/slackbot/views.py
 ...
 			# 출석체크 인지 확인
            if text == 'ㅊㅊ':
                attention = Attention.objects.filter(user_id=user).first()
                if attention is None:
                    Attention.objects.create(user_id=user, attend_count=1)
                else:

                    # 마지막 로그인 날짜가 오늘인지 체크
                    if attention.last_attend.date() == timezone.now().date():
                        slack.chat.post_message('#일반', f'오늘은 이미 출석체크를 했습니다.', as_user=None)
                    else:
                        attention.attend_count = attention.attend_count + 1
                        attention.save()
                slack.chat.post_message('#일반', f'출석체크!: {attention.attend_count}회', as_user=None)

...​

 

오늘은 이미 했다~!

 

 

자 이제 여러분의 아이디어를 더해서 추가적인 기능들을 넣으면 됩니다.

 

저는 연속적으로 출석체크를 할 경우 combo시스템을 넣어서 점수를 더 높게 주도록 구현했고, ㅊㅊ말고도 ㅊㅋ(체크)를 입력할 경우 전체 사용자의 점수를 출력하게 만들었습니다. 

 

여 히사시부리~

 

 

마치며

 

슬랙 API를 이용해서 간단하게 출석체크 챗봇을 만들었는데요, 요즘 슬랙으로 업무를 하는 팀이 많이 늘어서 출석체크처럼 재미를 위한 챗봇 말고도 업무의 효율성을 높여주는 챗봇을 만들면 좋을 것 같습니다. 가령 특정 데이터를 뽑아준다던지, 문서를 쉽게 찾아서 다운로드할 수 있다던지 무궁무진할 것 같네요.

 

슬랙으로 출석체크 챗봇을 만드는 건 이것으로 마치겠습니다.

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY