ローカルでも動くSlackBot管理ツールができるまで 〜 WebUI編 1 〜

Share on Facebook
Pocket
LINEで送る
Bookmark this on Google Bookmarks

今回から何回かに分けて、はてブから情報を取得しSlackに投稿するBOTを管理するツールを作成していく。
今までにこのブログ内で紹介しgithubにあげているソースを利用する。

完成形

[雑][Python] ローカルでも動くSlackのBot管理ツールを作成してみた(Bottle + jinja2 + Slacker)

 

構成

slack_botter

 

開発環境

今回はローカル(MacBookAir)で開発してみた。
brewでpython3をインストールしている前提とする。

$ sudo brew install python3

データベースはローカルであることとPython標準ライブラリとして入っているため、
sqlite3で構築する。

 

venvで仮想環境を構築する

pyvenvで仮想環境を構築し、pipをアップデートしておく。

$ cd ~/Documents
$ pyvenv slack_botter
$ cd slack_botter
$ source bin/activate
(slack_botter)$ pip install --upgrade pip

 

githubから必要なファイルを取得する

以前、Pythonフレームワーク bottle とテンプレートエンジン jinja2 で作ったものを利用するため、githubからダウンロードする。
ダウンロードしたものをsitesという名前にリネームしておく。

(slack_botter)$ cd ~/Documents/slack_botter
(slack_botter)$ git clone https://github.com/umentu/bottle_jinja2
(slack_botter)$ mv bottle_jinja2 sites

 

pipで必要なライブラリをインストール

githubからダウンロードしたものの中にrequirements.txtが入っているため、pipで必要なライブラリをインストールする。

(slack_botter)$ pip install -r ./sites/requirements.txt

sites/index.pyを実行し、ブラウザで http://localhost:8080/top/ にアクセスして表示できるかを確認してみる。

(slack_botter)$ python sites/index.py

 

Slackのチャンネル名一覧を取得するため、gitからslackbotを取得

SlackBotを管理する際に、存在するチャンネル一覧を表示させたいため、Slackからチャンネル一覧を取得する。
これも以前作ったものを利用するため、
githubからダウンロードする。

今回はslack_bot.pyというファイルのみ必要なため、sites内に移動しておく。
また、requirements.txtがあるため、slackbot用に必要なライブラリをpipでインストールする。
以上が終わったらslackbotディレクトリは必要ないため、slackbotディレクトリを削除する。

(slack_botter)$ cd ~/Documents/slack_botter
(slack_botter)$ git clone https://github.com/umentu/slackbot
(slack_botter)$ mv slackbot/slack_bot.py ./ 
(slack_botter)$ pip install -r slackbox/requirements.txt
(slack_botter)$ rm -rf ./slackbot

 

sqlite3 でデータベース作成

sqlite3のDBファイルを作成するために、slack_botterディレクトリ配下にdbディレクトリを作成しておく。

(slack_botter)$ cd ~/Documents/slack_botter
(slack_botter)$ mkdir db

dbディレクトリ配下に、データベース・テーブル・テストデータを作成するためのcreate_db.pyファイルを作成する。

# -*- coding: utf-8 -*-

import os
import sqlite3

if __name__ == '__main__':

    # データベースアクセス

    path = os.path.dirname( os.path.abspath(__file__))
    connect = sqlite3.connect(path + "/hatena.db")
    cursor = connect.cursor()

    # テーブル作成

    sql = """
    CREATE TABLE hatebu_list (
        id INTEGER PRIMARY KEY, 
        channel VARCHAR(128),
        word TEXT, 
        bookmark_count INTEGER,
        last_post TEXT
    );
    """

    # テーブル確認

    cursor.execute(sql)

    sql = """ 
    SELECT * FROM sqlite_master;
    """

    con = cursor.execute(sql)
    for row in con:
        print(row)

    # テストデータ挿入

    sql = """ 
    INSERT INTO hatebu_list (
         channel, 
         word, 
         bookmark_count, 
         last_post) 
         VALUES ( 
        'test_channel', 
        'test_word', 
        100, 
        '2000-01-01T00:00:00+09:00'
    );
    """

    cursor.execute(sql)

    # テストデータ確認

    sql = """
    SELECT * FROM hatebu_list;
    """

    con = cursor.execute(sql)
    for row in con:
        print(row)

    # 変更を更新する
    connect.commit()

    # データベースを閉じる
    connect.close()

実行すると、dbディレクトリ配下に hatena.db というDBファイルが作成される。

(slack_botter)$ python db/create_db.py
('table', 'hatebu_list', 'hatebu_list', 2, 'CREATE TABLE hatebu_list (
        id INTEGER PRIMARY KEY, 
        channel VARCHAR(128),
        word TEXT, 
        bookmark_count INTEGER,
        last_post TEXT
    )')
(1, 'test_channel', 'test_word', 100, '2000-01-01T00:00:00+09:00')
(slack_botter)$ ls -l ./db
total 16
-rw-r--r--  1 umentu  staff  1236  6 16 23:39 create_db.py
-rw-r--r--  1 umentu  staff  2048  6 16 23:40 hatena.db

UIを作成

(以降から若干置いてけぼり感が出てしまうかもしれないのですが。。。)

sitesディレクトリ配下にWebUIの本体となるsites.pyを作成する。
index.pyをコピーして作成すると楽。

# -*- coding: utf-8 -*-
 
import os
import sys
import csv

# sqlite3をインポート
import sqlite3

# slack_botライブラリもインポート
sys.path.append( os.path.dirname(__file__) )
from slack_bot import Slack

from bottle import route, run
from bottle import TEMPLATE_PATH, jinja2_template as template
from bottle import static_file
from bottle import get, post, request, response
from bottle import redirect 


# sites.pyが設置されているディレクトリの絶対パスを取得
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# テンプレートファイルを設置するディレクトリのパスを指定
TEMPLATE_PATH.append(BASE_DIR + "/views")

@route('/css/<filename>')
def server_css(filename):
    """ setting for css file """
    return static_file(filename, root=BASE_DIR+"/static/css")

@route('/js/<filename>')
def server_js(filename):
    """ setting for js file """
    return static_file(filename, root=BASE_DIR+"/static/js")

@route('/img/<filename>')
def server_img(filename):
    """ setting for img file """
    return static_file(filename, root=BASE_DIR+"/static/img")

@route('/font/<filename>')
def server_font(filename):
    """ setting for font file """
    return static_file(filename, root=BASE_DIR+"/static/fonts") 

@route('/hatebu')
@route('/hatebu/')
def hatebu():

    return template('hatebu')

if __name__ == "__main__":
    run(host="localhost", port=8080, debug=True, reloader=True)

sites/views 配下のtop.htmlをhatebu.htmlという名前でコピー

(slack_botter)$ cp sites/views/top.html sites/views/hatebu.html

sites.pyを実行して、ブラウザでhttp://localhost:8080/hatebuにアクセスできるか確かめる。

アクセスできたら、sites/sites.py のhatebu関数を再度編集

@route('/hatebu')
@route('/hatebu/')
def hatebu():

    # データベースアクセス

    path = os.path.dirname(os.path.dirname( os.path.abspath(__file__))) + "/db"
    connect = sqlite3.connect(path + "/hatena.db")
    cursor = connect.cursor()

    # hatebu_list テーブルからデータを取得
    sql = """ 
    SELECT * FROM hatebu_list
    """ 

    # 取得したデータをパースしてリストに保存

    hatebu_list = []
    con = cursor.execute(sql)
    for row in con:
        tmp_row = {}
        for idx, col in enumerate(cursor.description):
            tmp_row[col[0]] = row[idx]

        hatebu_list.append(tmp_row)            

    connect.close()

    # Slackのチャンネル一覧を取得
    slack = Slack("SlackのToken")
    channel_list = slack.get_channnel_list()

    return template('hatebu', hatebu_list=hatebu_list, channel_list=channel_list)

sites/views/hatebu.html を以下のように編集
(formはここで紹介したように記述している。)
作成ボタンが押された場合は、 /hatebu_create に
更新ボタン、削除ボタンが押された場合は、 /hatebu_updel に移動して処理する。

実際の作成・更新・削除の処理は次回実装する。

{% extends 'base.html' %}

{# base.html の title の中に入れるコンテンツ #}
{% block title %}
Slackツール
{% endblock %}

{# ヘッダー情報を追加する場合はここに記述する。 #}
{% block header %}
{% endblock%}


{# base.html の contents の中に入れるコンテンツ #}
{% block contents %}

<h1>Slackツール</h1>
<div>
    <form action="/hatebu_create" method="get" accept-charset="utf-8" id="create"></form>

    <table class="table">
        <tbody>
            <tr>
                <td>チャンネル</td>
                <td>
                    <select name="channel" form="create">
                        {% for cl in channel_list %}
                            <option value="{{cl.channel_name}}">{{cl.channel_name}}</option>
                        {% endfor %}
                    </select>
                </td>
            </tr>
            <tr>
                <td>キーワード</td>
                <td><input type="text" name="word" form="create" placeholder="キーワード" /></td>
            </tr>
            <tr>
                <td>取得するブックマーク数</td>
                <td><input type="number" name="bookmark_count" form="create" placeholder="ブックマーク数" /></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" name="create" value="作成" form="create" class="btn btn-success" /></td>
            </tr>

        </tbody>
    </table>
</div>

<div>
    <table class="table table-striped">
        <thead>
            <tr>
                <td>ID</td>
                <td>チャンネル</td>
                <td>キーワード</td>
                <td>取得するブックマーク数</td>
                <td>更新</td>
                <td>削除</td>
            </tr>
        </thead>
        <tbody>
            {% for hl in hatebu_list %}
            <tr>
                <td>
                    {{hl.id}}
                    <input type="hidden" name="id" form="form{{hl.id}}" value="{{hl.id}}" />
                </td>
                <td>
                    <select name="channel" form="form{{hl.id}}">
                        {% for cl in channel_list %}

                            {# 登録されているBOTのチャンネルと一致している場合は選択されているようにする。 #}

                            {% if cl.channel_name == hl.channel %}
                                <option value="{{cl.channel_name}}" selected="selected">{{cl.channel_name}}</option>
                            {% else %}
                                <option value="{{cl.channel_name}}">{{cl.channel_name}}</option>
                            {% endif %}                               
                        {% endfor %}
                    </select>
                </td>
                <td>
                    <input type="text" name="word" form="form{{hl.id}}" value="{{hl.word}}" />
                </td>
                <td>
                    <input type="number" name="bookmark_count" form="form{{hl.id}}" value="{{hl.bookmark_count}}" />
                </td>
                <td>
                    <input type="submit" name="updel" form="form{{hl.id}}" value="更新" class="btn btn-info" />
                </td>
                <td>
                    <input type="submit" name="updel" form="form{{hl.id}}" value="削除" class="btn btn-danger" />
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</div>

{% for hl in hatebu_list %}
<form action="/hatebu_updel" method="get" id="form{{hl.id}}" accept-charset="utf-8"></form>
{% endfor %}

{% endblock %}

sites.pyを実行し、http://localhost:8080/hatebu にアクセスしてデータが表示されたら、とりあえずUI風完成。
次回、作成・更新・削除の実装を紹介する。

 

続き:

ローカルでも動くSlackBot管理ツールができるまで 〜 WebUI編 2 〜

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です