DjangoでLINE BOTを作るメモ

▼YouTubeでも6/18(金)18時〜 プレミア公開で解説してます（30分）↓↓↓
YouTube : https://youtu.be/1QXvWOHhPGA

#LINE側の設定

## チャネルの作成
下記URLからLINE Developersにログインしてください。
https://developers.line.biz/ja/

まずはプロバイダーを作成して、LINE Messageing API のチャネルを発行します。
![スクリーンショット 2021-06-18 13.09.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/c553c0d2-3a70-80b4-6ab6-c6fe3a987394.png)
新しくチャネルが作られたら、チャネル基本設定の「LINE Official Account Manager」というボタンを押します。すると、新しくタブが開きます。
![スクリーンショット 2021-06-17 3.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/69c0f863-7b4a-c28f-f412-9d5bd13d92d8.png)

## LINE Official Account Manager の設定
応答設定をクリックして、下記のように設定します。
- 応答モード：BOT
- あいさつメッセージ：オフ
- 応答メッセージ：オフ
- Webhook：オン
![スクリーンショット 2021-06-17 3.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/6dd04a7e-24a0-d554-641c-007b2327c4e9.png)
LINE Official Account Manager の設定はこれだけなので、このタブは閉じてください。

## アクセストークンの発行
LINE Official Account Manager　ではなく、LINE Developers のページに戻り、MessagingAPI設定の一番下の、チャネルアクセストークンから、アクセストークンを取得します。
![スクリーンショット 2021-06-17 3.23.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/d4f38a3c-2f57-e2cc-0b20-20208ff13eab.png)
長い英数字が発行されると思います。後ほど使います。

# Django側の実装

## ディレクトリ作成
Djangoのプロジェクトを作るための、ディレクトリを作成します。

```
$ mkdir linebot
$ cd linebot
```

## 仮想環境を立ててDjangoをインストール
Python3.6以上であれば、Pythonコマンドで仮想環境を作ることができます。今回は`venv`という仮想環境を作ります。

```
$ python -m venv venv
$ source venv/bin/activate
$ pip install django
$ django-admin version
```

※Windowsの方は```source venv/bin/activate```ではなく、```source venv/Scripts/activate```で実行してみてください。

## プロジェクト作成
Djangoのバージョンを確認できたら、プロジェクトを作成します。

```
$ django-admin startproject line_bot
$ cd line_bot/
$ python manage.py startapp line_bot_ai
```

### Djangoの解説

Djangoは、プロジェクトの中の`urls.py`を見てから、各アプリケーションの中の`urls.py`を見て、次にそのアプリケーションの中の`views.py`を見て、最後にHTMLとしてユーザーに返す下記の図のような流れになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/8b049dcc-18ce-0ded-22a8-4a44d2542310.png)
図にはありませんが、プロジェクトの中にある`settings.py`も、基本的な設定周りをこのファイルで管理していくので重要ですね。

## アプリ側の`urls.py`を作成
まずは、作ったline_bot_aiのアプリケーションの中に、urls.pyファイルを作成します。

```line_bot_ai/urls.py
from django.urls import path
from . import views

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

## プロジェクト側の`urls.py`に反映
プロジェクト側のline_botフォルダの中にある`urls.py`に反映させるために、ファイルの中身を二箇所変更します。

```line_bot/urls.py
from django.contrib import admin
from django.urls import include, path # 追加部分

urlpatterns = [
    path('line_bot_ai/', include('line_bot_ai.urls')), # 追加部分
    path('admin/', admin.site.urls),
]
```

## アプリ側に`LineMessage`クラスの作成
views.pyを編集する前に、新しく`LineMessage`クラスを作成し、LINE Messaging APIにHTTPリクエストを送りまるための、replyメソッドを作成します。

```line_bot_ai/line_message.py
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import urllib.request
import json

REPLY_ENDPOINT_URL = "https://api.line.me/v2/bot/message/reply"
ACCESSTOKEN = '***先ほど発行したアクセストークンをここに貼り付け***'
HEADER = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + ACCESSTOKEN
}

class LineMessage():
    def __init__(self, messages):
        self.messages = messages

    def reply(self, reply_token):
        body = {
            'replyToken': reply_token,
            'messages': self.messages
        }
        print(body)
        req = urllib.request.Request(REPLY_ENDPOINT_URL, json.dumps(body).encode(), HEADER)
        try:
            with urllib.request.urlopen(req) as res:
                body = res.read()
        except urllib.error.HTTPError as err:
            print(err)
        except urllib.error.URLError as err:
            print(err.reason)
```

デプロイする際は、アクセストークンは別のjsonファイルとかにしておいた方が良さそうです。

また、ここでメソッド`reply`に渡されている`message`は以下のような形式を想定しています。

```
{
  type: "text",
  text: "hogehoge"
}
```

LINE Messaging APIは複数のメッセージの同時送信にも対応しています。（最大５件まで）
また、`type`に関してもtext以外に存在します。（スタンプとか、画像とか、リッチなメッセージとか）
https://developers.line.biz/en/docs/messaging-api/message-types/

クラスをさらに分けたり、直接views.pyに書くこともできますが、色々ググったり他の方のやり方も参考にした結果、下記の形で実装させてください。

## メッセージ作成用の`message_creater.py`を作成
大元の階層に、utilsというフォルダを作成して、LINEにメッセージを送るためのメッセージ作成用のpythonファイルを作成します。

```utils/message_creater.py
def create_single_text_message(message):
    if message == 'ありがとう':
        message = 'どういたしまして！'
    test_message = [
                {
                    'type': 'text',
                    'text': message
                }
            ]
    return test_message
```

「ありがとう」という文字が来たときにだけ「どういたしまして！」と返す仕様にしていますが、この辺はご自由に変更してください。[flex message](https://developers.line.biz/ja/docs/messaging-api/using-flex-messages/) に変えてみるのも良いでしょう。
https://developers.line.biz/ja/docs/messaging-api/using-flex-messages/

## アプリ側の`views.py`を編集

```line_bot_ai/view.py
from django.shortcuts import render
from django.http import HttpResponse
import json
from django.views.decorators.csrf import csrf_exempt

from utils import message_creater
from line_bot_ai.line_message import LineMessage

@csrf_exempt
def index(request):
    if request.method == 'POST':
        request = json.loads(request.body.decode('utf-8'))
        data = request['events'][0]
        message = data['message']
        reply_token = data['replyToken']
        line_message = LineMessage(message_creater.create_single_text_message(message['text']))
        line_message.reply(reply_token)
        return HttpResponse("ok")
```

これで実装は終了です。

#ngrokでLINEと連携

## `ALLOWED_HOSTS`の編集
`ALLOWED_HOSTS`に以下のようにngrokを追加します。

```settings.py
ALLOWED_HOSTS = [".ngrok.io"]
```

## ngrokの設定
LINE側のWebhook URLには、localhost で指定ができないので、今回はngrokを使ってテストします。

`npm install ngrok -g`などでインストールできたら、ポートは揃えて（デフォルトは8000なので、今回は8000）下記のコマンドを実行してください。

```
$ ngrok http 8000
```

## Webhook URLの設定

LINE Developersのページに戻り、Messaging APIのWebhook設定のすぐ下の、Webhook URLの部分に、`https://*********.ngrok.io/line_bot_ai/`を入力します。
![スクリーンショット 2021-06-17 3.38.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/d75558f3-e2e6-1ae5-0441-af297d5dcb25.png)
Webhookの利用がオフになっていたら、オンにしてください。
検証を押して、ポップアップで「成功」と出れば、ひとまず一安心です。

## 完成
これで準備は整いました。
サーバーを起動して、以下のようにおうむ返しされれば成功です！

```
$ python manage.py runserver
```

![スクリーンショット 2020-08-22 16.43.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/53a8b77f-4eaa-e583-669b-c3a8feca9dfe.png)
つくれるって、楽しい！