【LINE Messaging API】Pythonで誰かと繋がる BOTを作成

#ランダムチャット
本Botを友達追加している中で、ランダムにユーザと繋がることができる

##流れ
１．「NEXT」を押下することで、誰かと繋がる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331630/74bb1394-10b6-52af-eed1-13abcf540fa3.png)

２．「REMOVE」を押下することで、離脱できる（※離脱しない限り、繋がり続ける）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331630/5c617738-0992-d1a4-94bd-f00a7247b40d.png)


##ソースコード

```
 randomchat
    |
    |_ config.py
    |
    |_ lineapp.py
    |
    |_ lineapphandl.py
    |
    |_ reply.py
    |
    |_ richmeny.py
```

ご自身のチャネルを確認して、設定する
・**チャネルアクセストークン**
・**チャネルシークレット**

```python:config.py
# LINE Messaging API
YOUR_CHANNEL_ACCESS_TOKEN = 'チャネルアクセストークン'
YOUR_CHANNEL_SECRET = 'チャネルシークレット'

# messages
NEXT = 'NEXT'
NOTNEXT = 'NO PARTICIPANT'
MATCHED = 'MATCHED'

REMOVE = 'REMOVE'

REMOVED = 'REMOVED'

FAILED = 'FAILED'
```

１．リッチメニューが存在するかチェックする
　（詳しくは、[リッチメニュー作成](https://qiita.com/yuj/items/44080e2d95d962b6ac43)を見てくください）

２．メッセージを受信すると、**TextMessageメソッド**が呼ばれる
　（詳しくは、[オウム返し BOT](https://qiita.com/yuj/items/fd865bd9a32bdf050851)を見てください）

```python:lineapp.py
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import config, lineapphandl, richmenu
import os


app = Flask(__name__)

YOUR_CHANNEL_SECRET = config.YOUR_CHANNEL_SECRET
YOUR_CHANNEL_ACCESS_TOKEN = config.YOUR_CHANNEL_ACCESS_TOKEN

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

# check for existing richmenu
rich_menu_list = line_bot_api.get_rich_menu_list()
if not rich_menu_list:
    result = richmenu.createRichmeu()
    if not result:
        reply.reply_message(event, config.FAILED)

@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    lineapphandl.TextMessage(event)

if __name__ == '__main__':
    app.run()
```

**＜createRichmenuメソッド＞**

```python:richmenu.py
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    RichMenu, RichMenuSize, RichMenuArea, RichMenuBounds, MessageAction, PostbackTemplateAction
)
import randomchat.config


def initMenu(line_bot_api):
    result = False
    try:
        # define a new richmenu
        rich_menu_to_create = RichMenu(
            size = RichMenuSize(width=1200, height=405),
            selected = True,
            name = 'richmenu for randomchat',
            chat_bar_text = 'TAP HERE',
            areas=[
                RichMenuArea(
                    bounds=RichMenuBounds(x=0, y=0, width=480, height=405),
                    action=MessageAction(text='REMOVE')
                ),
                RichMenuArea(
                    bounds=RichMenuBounds(x=480, y=0, width=720, height=405),
                    action=MessageAction(text='NEXT')
                )
            ]
        )
        richMenuId = line_bot_api.create_rich_menu(rich_menu=rich_menu_to_create)

        # upload an image for rich menu
        image = 'richmenu.jpg'
        path = '/home/web/randomchat/' + image
        
        with open(path, 'rb') as f:
            line_bot_api.set_rich_menu_image(richMenuId, "image/jpeg", f)
        
        # set the default rich menu
        line_bot_api.set_default_rich_menu(richMenuId)

        result = True

    except Exception:
        result = False


    return result

```


**＜TextMessageメソッド＞**
１．ユーザー管理の処理
２．「NEXT」or「REMOVE」or メッセージの処理

```python:lineapphandle.py
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import config, reply
import random, copy

YOUR_CHANNEL_SECRET = config.YOUR_CHANNEL_SECRET
YOUR_CHANNEL_ACCESS_TOKEN = config.YOUR_CHANNEL_ACCESS_TOKEN

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

usersList = []
usersDic = {}

def TextMessage(event):
    userId = event.source.user_id
    message = event.message.text
    
    if not userId in usersList:
        usersList.append(userId)
        if not userId in usersDic.keys():
            usersDic[userId] = {}
            usersDic[userId]['toUserId'] = ''
    
    toUsersList = copy.copy(usersList)
    toUsersList.remove(userId)


    if message == config.NEXT:
        if not len(toUsersList) == 0:
            num = random.randint(0, int(len(toUsersList)-1))
            usersDic[userId] = toUsersList[num]
            toUserId = toUsersList[num]
            usersDic[toUserId] = userId

            # delete Id form list
            usersList.remove(userId)
            usersList.remove(toUserId)
            
            # reply
            message = TextSendMessage(text=config.MATCHED)
            reply.reply_message(event, message)
            reply.push_message(toUserId, message)

        else:
            message = TextSendMessage(text=config.NOTNEXT)
            reply.reply_message(event, message)

    elif message == config.REMOVE:
        usersList.remove(userId)
        toUserId = usersDic[userId]
        if userId in usersDic.values():
            pushMessage = TextSendMessage(text=config.REMOVED)
            reply.push_message(toUserId, pushMessage)
            usersDic[toUserId] = ''
        usersDic.pop(userId)
        
        message = TextSendMessage(text=message)
        reply.reply_message(event, message)

    else:
        if usersDic[userId] == '':
            message = TextSendMessage(text=message)
            reply.reply_message(event, message)

        else:
            toUserId = usersDic[userId]
            message = TextSendMessage(text=message)
            reply.push_message(toUserId, message)
```

**＜リプライメソッド＞**
reply_message: メッセージを送信してきたユーザに送る（詳しくは、[]()を見てください）
push_message: 指定したユーザにメッセージを送る

```python:reply.py
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)
import config, lineapphandl


YOUR_CHANNEL_SECRET = config.YOUR_CHANNEL_SECRET
YOUR_CHANNEL_ACCESS_TOKEN = config.YOUR_CHANNEL_ACCESS_TOKEN

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


def reply_message(event, message):
    line_bot_api.reply_message(
        event.reply_token,
        message
    )

def push_message(toUserId, message):
    line_bot_api.push_message(
        toUserId,
        message
    )
```