はじめに

slackのBOTを作っていろいろやりたい。どうせなら拡張性も高く、高機能でかつwebページからでもslackのモバイルアプリからでも操作しやすいようにしたい。

と、おもっていたけどその前提となるeventsAPIでつまづくんじゃああああああ!!!!!

という全国の「ちょっとslack使い始めました」的なユーザーの声が聞こえてくる。

Webページ制作にもつなげやすく、データベース関連もやりやすいようにpythonフレームワークの一つであるDjangoを用いてSlackのEventsAPIをすべて無料で使えるようにしていこうと思う。

用意するもの

  • Slackワークスペースの管理者権限
  • herokuアカウント(ここにデプロイしVerificationを通します)
  • heroku のCLI(heroku toolbelt:手元からherokuを操作するために利用)
  • Githubアカウント(herokuにデプロイするのに必要となる)

環境

やること

  1. heroku上にアプリをつくる
  2. ローカル開発環境でDjangoのアプリケーションをつくる
  3. Githubにpushする
  4. Githubのリポジトリからherokuへデプロイ(本番環境に移す)
  5. herokuの環境変数を設定する
  6. SlackのEvenvtsAPIのVerificationを通す

heroku上にアプリをつくる

前提として、

  • herokuのアカウント
  • heroku CLI(heroku toolbelt)

の二つが必要となるので以下のページを参考に揃える。

◇ アカウントについて
Herokuアカウントとコマンドラインツール(CLI)をセットアップしよう!
◇ heroku CLIについて(全文English;しかしとても読みやすい丁寧なドキュメントである)
Heroku CLI | Heroku Dev Center

heroku CLIからログインする

bash
$ heroku login
Enter your Heroku credentials:
Email: hogehoge@gmail.com        # <= Enter Your Account's email address.
Password (typing will be hidden) # <= Enter your Password
Authentication successful.      

# Logged in as hogehoge@gmail.com

上記のようにして、アカウントに紐付けられたメールアドレスとパスワードを入力してheroku CLIを経由してログインする。

次に、heroku上で動くアプリケーションを作成し、Githubからデプロイするための前準備を行う。単なるアプリケーションの名前でしかないが、ブラウザからアクセスする際のドメイン名に表示されるのでわかりやすいものを決めること。指定しない場合、heroku側でテキトーに決めてくれる。

bash
$ cd ~/myapp
$ heroku create                             # <= 名前を指定しない場合
Creating app... done, ⬢ sleepy-meadow-81798
https://sleepy-meadow-81798.herokuapp.com/ | https://git.heroku.com/sleepy-meadow-81798.git

この手順で行なった場合、リモートレポジトリの設定等も自動でやってくれる。もし、開発途中でこの記事を見て実践しようとしている場合、現在のGitリポジトリをherokuに登録するという一手間がかかるかもしれないので適宜「heroku デプロイ」などでググってほしい。

ローカル開発環境でDjangoのアプリケーションをつくる

Djangoの開発環境

Macやその他lunuxユーザには関係のない話だが、以前に記事を書いたので参考にしてほしい。
PyCharm + WSLを導入したWindows10でのDjango開発 - Qiita

以下、Terminalでのコマンドはすべてubuntuベースで行うので、どうしてもコマンドプロンプトでやる場合は適宜読み替えること。

Djangoを使う前に:仮想環境とGithubリポジトリの登録

基本的にDjangoはワンワイナーでプロジェクトが発足し、ワンライナーでアプリの雛形が出来る。しかし、ここで注意したいのが、名前空間の都合上、プロジェクト名は変更出来ても、アプリ名は変更できない(プロジェクト直下に作成されるプロジェクトと同名のプロジェクト管理アプリ名)。

また、Djangoについてインターネットで検索すると、その多くが「mysite」という名前になっているので、いちいち読み替える手間を省くためにも(そして無用な混乱を避けるためにも)、一番最初のプロジェクト作成コマンドは「django-admin startproject mysite」や「django-admin startproject website」などにすべきかと思う。

bash
$ python3.X -m venv myvenv    # create virtual env
$ source myvenv/bin/activate  # Enter 'myvenv'

(myvenv) $ pip install --upgrade pip
(myvenv) $ pip install django

/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/

(myvenv) $ django-admin startproject mysite

(myvenv) $ ls                 # confirm your Django-project-dir
mysite                        # directory created

この時点でディレクトリ構成は以下のようになっている。

Django-Project-Directory
mysite
├── manage.py
└── mysite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

一番外側の「mysite」がプロジェクト名ディレクトリであり、変更可能である一方、内側の「mysite」はプロジェクト全体の設定に関わってくるので、後々変更するのは面倒な作業が必要になるらしい。ネット上の多くのドキュメントが内側を「mysite」としているのでそれに従ったほうがストレスなくコーディングすることが出来ると思われる。

それでは、ここまで来て初めて外側の「mysite」を自身の好きなプロジェクト名に変更し、Githubにpushしてみよう。

bash
(myvenv) $ cd ~
(myvenv) $ mv mysite yourProject
(myvenv) $ tree

yourProject           # <= 外側の mysite だったもの
├── manage.py
└── mysite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

# 前提:Githubに「yourProject」というリポジトリを作成してあること
(myvenv) $ git init
(myvenv) $ git add -A .
(myvenv) $ git commit -m "start Django project!"
(myvenv) $ git remote add origin https://github.com/username/yourProject.git
(myvenv) $ git push -u origin master

Djangoアプリケーションの作成

Djangoのプロジェクト「yourProject」ディレクトリの直下に「myapp」というアプリを作成する。そしてこのアプリだけでEventsAPIの認証も終わらせてしまうようにする。

手順としては、

  1. アプリをまとめておくディレクトリをワンライナーで構築
  2. myapp/views.pyをコピペ
  3. myapp/urls.pyを新規に作成
  4. mysite/urls.pyを編集
  5. mysite/settings.pyを設定
  6. mysite/wsgi.pyを設定

このようになっている。

bash
# 特に断らない限り、yourProjectディレクトリ内で作業している
(myvenv) $ python manage.py startapp myapp
(myvenv) $ vi myapp/views.py
(myvenv) $ vi myapp/urls.py      # <= add new file
(myvenv) $ vi mysite/urls.py
(myvenv) $ vi mysite/settings.py

それぞれ、以下のようにかいておく。(大幅なバージョン変更の壁がない限り、以下をコピペすれば対応ができるはず)

views.py
import json

from django.conf import settings
from django.shortcuts import render
from django.http import HttpResponse

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

from slackclient import SlackClient


SLACK_VERIFICATION_TOKEN = getattr(settings, 'SLACK_VERIFICATION_TOKEN', None)
SLACK_BOT_USER_TOKEN = getattr(settings,'SLACK_BOT_USER_TOKEN', None)
Client = SlackClient(SLACK_BOT_USER_TOKEN)


class Events(APIView):

    def post(self, request, *args, **kwargs):
        slack_message = request.data

        # verification challenge
        if slack_message.get('type') == 'url_verification':
            return Response(data=slack_message,
                            status=status.HTTP_200_OK)

########################### Pages ###################################
def index(request):
    # index.html
    return HttpResponse('インデックスページ')

myappディレクトリをコマンドで作った段階ではmyapp/urls.pyは存在していないので、自分で作成することになる。

myapp/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

仕組みとしては、アプリディレクトリのurls.pyviews.pyをどのURLが来たときに表示するのかを振り分けるような役割を持っていると考える。正規表現等も用いてかなり自由度高く設定できるようなので、ページを作るときはぜひよく調べてから作成したい。(EventsAPIにおいてはほとんど関係がないので省略)

mysite/urls.py
from django.contrib import admin
from django.urls import path, include
from tool_manage.views import Events

from django.views.decorators.csrf import csrf_exempt

urlpatterns = [
    path('', include('tool_manage.urls')),           # <= add
    path('admin/', admin.site.urls),                 # <= default
    path('events/', csrf_exempt(Events.as_view())),  # <= add
    # csrf無効についての参考:https://bit.ly/2juuJpa
]

Djangoにどんなアプリがインストールされるべきかを教え、どのような言語やエンコードで表示すればよいのかを伝え、機密情報を含む環境変数をどうやって読み込むのかを伝えているのがこのsettings.pyである。トークンやパスワード、クライアントIDなどをプログラム中にハードコーディングした上でGithubのパブリックリポジトリにpushしてしまうことだけは絶対に避けなければならない(「Github ハードコーディング」等で検索してみるといい)

pythonの場合、実に簡単に環境変数を読み込むことが出来る(し、pythonが環境変数を設定することも出来る)ので、VPSやPaaSを利用して本番環境へのデプロイを行うためにGithub等を用いる場合、環境変数のなかにパスワードやトークン、IDを仕込むことが多いようだ。

mysite/settings.py
/~~~~~~~~~~~~~~~~~~~ 前略 ~~~~~~~~~~~~~~~~~~~~~~/
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',                       # <= add
    'rest_framework',              # <= add
]

/~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~/

# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'ja-JP'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = False
/~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~/

########## slack API configuration #############

# SLACK API Configurations
# ----------------------------------------------
# use your keys  # load os.environ(環境変数を読み込む)
SLACK_CLIENT_ID = os.environ["SLACK_CLIENT_ID"]
SLACK_CLIENT_SECRET = os.environ["SLACK_CLIENT_SECRET"]
SLACK_VERIFICATION_TOKEN = os.environ["SLACK_VERIFICATION_TOKEN"]
SLACK_BOT_USER_TOKEN = os.environ["SLACK_BOT_USER_TOKEN"]

heroku環境でのDjangoの諸設定

herokuへのデプロイを前提としたDjangoアプリの設定等を行う。これについては、デプロイ! · workshop_tutorialJPが詳しい。情報が少し古いため、インポートするpythonライブラリのバージョンが更新されているはずなので、適宜読み替えて調整すること。

bash
(myvenv) $ pip install dj-database-url gunicorn whitenoise
(myvenv) $ pip freeze > requirements.txt
(myvenv) $ vi requirements.txt

# 以下を'requirements.txt'の最後の一行に追加
psycopg2

※ProcfileのPは大文字であることに注意。

Procfile
web: gunicorn mysite.wsgi

herokuでサポートされているpythonは3.6.4なので、そのバージョンで実行されるように指定する。

runtime.txt
python-3.6.4

コンピューター上のローカルとサーバーでは設定に違いがあります。Herokuとコンピューターでは別のデータベースをそれぞれつかっています。そこで、別途ファイルを作成し、ローカル環境で動かすための設定を保存しておく必要があります。
では、ファイルを作成しましょう。mysite/local_settings.pyというファイルです。その中には、mysite/settings.pyファイルからの DATABASE の設定が必要です。

というようなことがDjangoGirlsTutorialJPには書かれています。そのまま従いましょう。

local_settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

DEBUG = True

さらに、mysite/settings.pyの後ろの行に以下の内容を追記します。

mysite/settings.py
/ ~~~~~~~~~~~~~~~~~~  中略 ~~~~~~~~~~~~~~~~~~~~ /
import dj_database_url
DATABASES['default'] = dj_database_url.config()

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

ALLOWED_HOSTS = ['*']

STATIC_ROOT = 'staticfiles'

DEBUG = False

try:
    from .local_settings import *
except ImportError:
    pass                         # <= ここが最終行です

仕上げに、wsgi.pyの設定を弄ってあげれば、herokuにおけるDjango側の設定は終了です。

mysite/wsgi.py
from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)

Githubにpushする

これまでの追記や編集などの作業記録を「Git」にaddおよびcommitし、それを「Github」へpushしましょう。Gitが作業記録を残しておくレポート書類だとすれば、Githubはそれらをまとめておいておく、世界規模のLibraryのイメージです。('図書館'ではないのが一つポイントかもしれません)
以下をコピペして構いませんので、gitを使ってaddcommitし、Githubへpushしましょう。

bash
(myvenv) $ git status
(myvenv) $ git add -A .
(myvenv) $ git commit -m "heroku環境におけるDjangoのアプリ設定を追加"
(myvenv) $ git push https://github.com/username/yourProject.git

なお、もしかするとGithubへのユーザ認証が必要になるかもしれません。その場合はそのやり方を適宜ググってもらうか、以下を参考にしてSSH接続に切り替えてやってみてください。
参考:gitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita

Githubのリポジトリからherokuへデプロイ(本番環境に移す)

無事、Githubにアップロード(push)出来たのであれば、あとはherokuにデプロイし、プロセスを起動するだけです。コマンドを以下のように入力してください。

bash
(myvenv) $ git push heroku master

/ ~~~~~~~~~~ 省略 ~~~~~~~~~~~~~ /

(myvenv) $ heroku ps:scale web=1

(myvenv) $ heroku open           # <= 実際にアプリが動いているページのURLを表示

herokuの環境変数を設定する

最後に、herokuの環境変数を編集します。これは、パスワードやトークン,IDをプログラム中にハードコーディングする(直接書き込んでしまう)ことを避けるための方策の一つです。pythonの場合、デフォルトのライブラリを用いて簡単に環境変数を読み込むことが出来るのでこの方法を採用しています。
heroku CLIからheroku config:set HOGEHOGE="FUGAFUGA"の構文でコマンドを入力しましょう。

bash
(myvenv) $ heroku config:set SLACK_BOT_USER_TOKEN="xoxb-111122223333-iEUserT0kenhHfM53HtxHSl0" \
                             SLACK_CLIENT_SECRET="40ji7secreta665294secrete97y3r7O" \
                             SLACK_VERIFICATION_TOKEN="verificationgedXbv9gehow" \
                             SLACK_CLIENT_ID="212341111111.287651111111"
(myvenv) $ heroku config

'''
SLACK_BOT_USER_TOKEN:       "xoxb-111122223333-iEUserT0kenhHfM53HtxHSl0"
SLACK_CLIENT_SECRET:        "40ji7secreta665294secrete97y$r7O"
SLACK_VERIFICATION_TOKEN:   "verificationgedXbv9gehow"
SLACK_CLIENT_ID:            "212341111111.287651111111"
'''

SlackのEvenvtsAPIのVerificationを通す

以下のページから、「https://<your-heroku-app-name>.herokuapp.com/events」と入力し、Verified!されるのを確認する。
Events API | Slack

参考文献

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.