おにぎりくんbotの誕生、繁栄、そして死

この記事は[呉高専エンジニア勉強会 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/kure-kosen) 1日目の記事になります。

🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍙🍘🍙🍙🍙🍙

こんにちは、ちゃんゆーです。

趣味の延長で友人と[ローカルなコミュニティラジオ](http://www.kure-rad.io/)をPodcastで配信しています。
準備をTrelloでタスク管理しながら進めていくなかで、TrelloのカードをLINEで通知してくれたら便利だなーと思ったので、そんなおにぎりくんbotを作って壊した話です。

# 何を作ったのか
Trelloでカードが移動したらLINEに通知してくれるbot。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/177433/3873ac5f-3515-ca5f-eb43-433591ec07c7.png)

おにぎりくんと呼ばれています。

# なぜ作ったのか
## そもそもなぜLINEなのか
Slack使えば一瞬で作れますというか、ノンプログラミングで設定できますが、いかんせんSlackは特に情報系に疎い学生には敷居が高いのでした。(経験談)
Notificationナニソレ？ と言われてひとつづつ使い方教えるのも骨が折れるのです。

そうしてLINEでやり取りして開発やラジオの収録を行うことになったのでした。

## IFTTT時代
最初はIFTTT連携してLINE Notifyが教えてくれていました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/177433/afb06c6e-331d-edd7-7ef1-d5936df08591.png)

でも**ラグがひどくてつらかった**のです。

## おにぎりくんの誕生
そこで自作bot製作に踏み切りました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/177433/e1d96179-4722-a226-810c-e6c758288a4c.png)

こうしてTrelloのカードが移動する度におにぎりくんが教えてくれるようになりました。

# どうやって作ったのか
僕はPythonしか書けないので、PythonのDjangoでサクッと組みました。
コードは[GitHub](https://github.com/kure-kosen/onigiri)にあげています。

ざっくりこんな感じになりました。

```py3:trello/views.py
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

import json
import requests
import os

from line.views import push_message

REPLY_ENDPOINT = 'https://api.line.me/v2/bot/message/reply'
ACCESS_TOKEN = os.getenv('LINE_ACCESS_TOKEN')
LINE_USERID = os.getenv('LINE_USERID')
LINE_GROUPID = os.getenv('LINE_GROUPID')
HEADER = {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + ACCESS_TOKEN
}

def index(request):
    return HttpResponse("Hello World")

@csrf_exempt
def callback(request):
    try:
        action = json.loads(request.body.decode('utf-8'))['action']
        from pprint import pprint
        pprint(action)
        entities = action['display']['entities']
        action_type = action['display']['translationKey']
        if action_type == 'action_create_card':
            list_name = entities['list']['text']
            card_name = entities['card']['text']
            member_name = entities['memberCreator']['text']
            body = f'カード「{card_name}」がリスト「{list_name}」に追加されました。\n追加者:{member_name}'
            push_message(LINE_GROUPID, body)
        elif action_type == 'action_move_card_from_list_to_list':
            after_list_name = entities['listAfter']['text']
            before_list_name = entities['listBefore']['text']
            card_name = entities['card']['text']
            member_name = entities['memberCreator']['text']
            body = f'カード「{card_name}」がリスト「{before_list_name}」からリスト「{after_list_name}」に移動されました。\n移動者:{member_name}'
            push_message(LINE_GROUPID, body)
    except Exception as e:
        pass
    return HttpResponse("callback")

```

```py3:line/views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

import json
import requests
import os

REPLY_ENDPOINT = 'https://api.line.me/v2/bot/message/reply'
PUSH_ENDPOINT = 'https://api.line.me/v2/bot/message/push'
ACCESS_TOKEN = os.getenv('LINE_ACCESS_TOKEN')
HEADER = {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + ACCESS_TOKEN
}

def index(request):
    return HttpResponse("Hello World")

@csrf_exempt
def callback(request):
    events = json.loads(request.body.decode('utf-8'))['events']
    for event in events:
        reply_token = event['replyToken']
        if event['type'] == 'message':
            if event['message']['type'] == 'text':
                if 'debug' in event['message']['text']:
                    reply = event['message']['text']
                    reply += get_line_ids(event['source'])
                    reply_message(reply_token, reply)
                elif 'おにぎり' in event['message']['text']:
                    reply = 'おにぎりくんだよ。呼んだ？'
                    reply_message(reply_token, reply)
                else:
                    pass
            else:
                 pass
        else:
            pass
    return HttpResponse("callback")

def get_line_ids(source):
    reply = ''
    if 'userId' in source:
        reply += '\nuserId:' + source['userId']
    if 'groupId' in source:
        reply += '\ngroupId:' + source['groupId']
    if 'roomId' in source:
        reply += '\nroomId:' + source['roomId']
    return reply


def reply_message(reply_token, reply):
    reply_body = {
        "replyToken":reply_token,
        "messages":[
            {
                "type": "text",
                "text": reply
            }
        ]
    }
    requests.post(REPLY_ENDPOINT, headers=HEADER, data=json.dumps(reply_body))

def push_message(to, message):
    push_body = {
        "to": to,
        "messages":[
            {
                "type": "text",
                "text": message
            }
        ]
    }
    requests.post(PUSH_ENDPOINT, headers=HEADER, data=json.dumps(push_body))
    
```

改良の余地が大いにあるコードたちです。

## おにぎりくんの定着
コードを見ての通り、LINEのトーク内で `おにぎり`が含まれた発言をすると、おにぎりくんが反応してくれます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/177433/2ac82af3-8ed5-8443-0dd5-05eda476b1f8.png)

おぎにりはダメでした。

# 稼働後のおにぎりくん
その後、おにぎりくんは死亡、その後蘇生することで復活し、さらにはゾンビ化した挙句、巨人に取って代わられたのでした。
詳細についてはまた書きますね。

駄文失礼いたしました。