【初心者に優しいLINEbot30分講座】他のサイトじゃうまくできなかったよね。オウム返し

#環境

pyenv Python 3.6.7
　Django==2.1.7
　line-bot-sdk
　gunicorn
　django-heroku
　psycopg2-binary

Heroku

#ディレクトリ構成
このディレクトリ構成を間違えて何度もエラーになったので、ここはしっかりする

```
/djangobot
 /bot
   /_pycache_
   /migrations
   /_init.py
   /admin.py
   /apps.py
   /models.py
   /tests.py
   /urls.py
   /views.py
 /djangobot
   /_pychache_
   /settings.py
   /urls.py
   /wdgi.py
 /manage.py
 /Procfile
 /requirements.txt
 /runtime.txt
 /djangoenv
```
#LINE Developersでチャネル登録

登録完了後
・チャンネル基本設定ページのチャネルアクセストークン
・Messaging API設定ページのチャネルシークレット
の二つはメモ

Messaging API設定のQRコードでスマホからチャンネル登録できる
挨拶メッセージもMessaging API設定から登録できる

#Python環境設定

https://qiita.com/yutoun/items/788fac08bf73f173d447

この記事を参考に環境構築を行う。

#venvで仮想環境を構築
pythonでは多くのライブラリを使用する可能性があるためそれぞれプロジェクトごとに仮想環境を立てるのがベターのようです。

```
python -m venv djangoenv
```
これでvenvというpython標準の機能を使ってdjangoenvという仮想環境を構築する。(名前は好きなものでok)
>
venvは一つのシステムの中に分離されたPythonの環境を作ることができるソフトウェアです。コマンドで仮想環境を作ったり、仮想環境に出入りすることができます。

```
source djangoenv/bin/activate
```
その後djangoenvをactivateする。

終了する場合は

```
deactivate
```
万が一削除したい場合は

```
rm -rf <仮想環境名>/
```

#Djangoインストール
ここでDjangoのバージョンを指定し、venv上にインストールする。
後にインポートするdjango_herokuはDjango2系のみ互換性があるため、2系をインストールする。

```
pip install Django==2.1.7
```
Djangoがインストールされているか確認する。

```
python -m django --version
```
#line-bot-sdkインストール

###linebotSDKとは
MessagingAPIを利用したLINEアプリケーション開発で機能の実装に利用できるSDK（ライブラリ、ツール、およびサンプル)。

```
pip install line-bot-sdk
```

#プロジェクト作成 && アプリ作成

```
django-admin startproject djangobot && cd djangobot
```
django-adminを利用し、djangobotというプロジェクトを作成し、作成したディレクトリに移動する。

```
python manage.py startapp bot
```
djangobotディレクトリ内のmanage.pyを利用し、botというアプリを作成する。

```
/djangobot
  /djangobot
  /bot
  manage.py
```
※このようにdjangobotディレクトリの中にdjangobotディレクトリがあることを理解しておく必要がある。

#pythonファイルの変更

###djangobot/djangobot/settings.py

```python:djangobot/settings.py
import os
import django_heroku # 追加
```

```python:djangobot/djangobot/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bot.apps.BotConfig', #追加
]
```
既存のsettings.pyでdjango_herokuをインポートする。
さらに作成したbotアプリをdjangobotと結びつけるためINSTALLED_APPに追加。

```python:djangobot/djangobot/settings.py
LANGUAGE_CODE = 'ja' #変更

TIME_ZONE = 'Asia/Tokyo' #変更
```
さらに言語とタイムゾーンを日本語、東京に変更。

```python:djangobot/djangobot/settings.py
django_heroku.settings(locals()) #追加
```
importしたdjango_herokuをactivateする。

###djangobot/djangobot/urs.py

```python:djangobot/djangobot/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('callback/', include('bot.urls')), # url(callback/)に、botアプリケーションフォルダのurls.py(下記コード)が紐づく
]
```
include詳細はこちら

https://www.nblog09.com/w/2019/01/20/django-mapping/

###djangobot/bot/urs.py

```python:djangobot/bot/urs.py
from . import views
from django.urls import path

app_name = 'bot'

urlpatterns = [
    path('', views.callback, name='callback'), # djangobot/urls.pyに呼び出され、views.pyのcallback関数を呼び出す
]
```
LINEdevelopersページでwebhookURLの設定をする時にこのurls.pyのcallbackが使われる


###djangobot/bot/views.py
このファイルで実際にlinebot-messagingAPIの設定や動きを定義する。
os.environはpythonで環境変数を追加、取得するためのもの。ここで書き換えた環境変数はこのpythonプログラムの中でのみ有効であるためシステムの環境変数には影響しない。


```python:djangobot/bot/urs.py
from django.shortcuts import render
from django.http import HttpResponseForbidden, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (
    MessageEvent,
    TextMessage,
    TextSendMessage,
)
import os

YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"] # YOUR_CHANNEL_ACCESS_TOKENは環境変数であり、後に設定する
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]# YOUR_CHANNEL_SECRETも環境変数であり、後に設定する

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)


@csrf_exempt #csrf攻撃対策
def callback(request):
    # リクエストヘッダーから署名検証用の値を取得する
    signature = request.META['HTTP_X_LINE_SIGNATURE']
    #リクエストの内容を取得
    body = request.body.decode('utf-8')
    try:
        # 署名を検証して問題がなければ下に定義されたhandleを実行する
        handler.handle(body, signature)
    except InvalidSignatureError:
        # 検証でエラーがあればエラー文を出す
        HttpResponseForbidden()
    # tryがうまく行けば200を返す
    return HttpResponse('OK', status=200)


# オウム返し
@handler.add(MessageEvent, message=TextMessage) 
# Messageが送られてきた時の処理のため、
# MessageEventを第一引数に、第二引数でmessageにmessage内容を代入
def handle_text_message(event):
    line_bot_api.reply_message(event.reply_token,
                               TextSendMessage(text=event.message.text))
```
###CSRFとは
>CSRFとはクロスサイトリクエストフォージェリの略であり、Webアプリケーションの脆弱性を利用したサイバー攻撃の一種です。 インターネット回線の高速化やデバイスの普及によって、気軽にオンラインサービスを利用する方も増えました

https://www.shadan-kun.com/blog/measure/2640/#:~:text=CSRF%E3%81%A8%E3%81%AF%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88,%E6%96%B9%E3%82%82%E5%A2%97%E3%81%88%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82

djangoではwebhookへのリクエストなどPOST時にCSRF対策が必要だとのこと。

####環境変数とは
>環境変数とは、OSの環境をカスタマイズするためのシステム変数である。

###djangobot/Procfile
・Procfileはheroku webアプリケーションには必須
・このファイルはアプリケーションのプロセスタイプとエントリポイントを宣言するために使われる
・Django アプリケーションに推奨される本番環境の Web サーバーである Gunicornが必要
・gunicornはNginxなどのwebサーバとdjangoの中間に存在するアプリケーションサーバというイメージ


```python:djangobot/Procfile
web: gunicorn djangobot.wsgi --log-file -
```

###djangobot/requirements.txt
プロジェクトにインストールしたいパッケージを記載する

```python:djangobot/requirements.txt
Django==2.1.7 # 先ほどインストールしたバージョン
line-bot-sdk==1.8.0
gunicorn
django-heroku
psycopg2-binary
```

###djangobot/runtime.txt

```python:djangobot/runtime.txt
python-3.6.7
```

#heroku
簡単に言えば、小さな開発レベルであれば無料で簡単にアプリを公開するためのPaaS

###herokuインストール&ログイン&アプリケーション作成

```
brew tap heroku/brew && brew install heroku
```

```
heroku login
```
herokuの登録が完了していなければ、登録を先に行う。
セキュリティが堅牢で、ログインの際にアプリをインストールしてコードを入力する手間があり面倒だ。

```
heroku create アプリケーション名
```
アプリケーション名は世界中のherokuアプリとかぶらない必要があるため考慮する。

#herokuの環境変数を設定する
記事の冒頭でメモしたトークンを使う時がきた。

```
heroku config:set YOUR_CHANNEL_SECRET="チャンネルシークレットの欄の文字列" --app createの時に入力したアプリケーション名
heroku config:set YOUR_CHANNEL_ACCESS_TOKEN="チャネルアクセストークンの欄の文字列" --app createの時に入力したアプリケーション名
```

#heroku stack
```
heroku stack:set heroku-18 -a <app name>
```
herokuのstackのバージョンと互換性がないため、デフォルトで20になっているものを18に変更する。
versionの互換性をしっかり確認する必要を学ぶことができた。実はかなりここで詰まった。

#gitの設定

まずはgitを初期化する

```
git init
```
herokuのgitを登録する

```
git remote add heroku https://git.heroku.com/アプリケーション名.git
```
あとは基本のgit操作通り

```
git init
git add .
git commit -m "new commit"
git push heroku master
```

#うまくいかない場合

```
heroku logs --tail -app アプリケーション名
```
このコマンドでherokuのエラーログを見ることができる。
私はかなり苦労したためお世話になりました。。。。。。。

#参考
・一番参考にしたもの

https://murabitoleg.com/line-bot/#botviewspy

・python仮想環境構築

https://kimoba.com/kasegu/install-python3anddjango.html

・heorku公式

https://devcenter.heroku.com/ja/articles/django-app-configuration

・gunicornとは

https://blog.hirokiky.org/entry/2018/10/06/151830

・heroku stack

https://na-ginnan.com/rails-heroku-20/

・LINE公式

https://developers.line.biz/ja/reference/messaging-api/#channel-access-token