【DiscordBot】かわいい女の子に進捗管理してもらう【リファレンス】

# はじめに
個人的にSQLのデータベースを扱った作品を作りたくなったので作りました．(まだまだ技術は浅いですが…)
かわいい女の子が作業開始，終了宣言時に反応してくれたり，記録した開始時刻，終了時刻から進捗内容とその時間を把握して月の頭に先月の作業量を報告してくれたりします！
<img src=https://pbs.twimg.com/media/Ewng6JzVkAMkJm7?format=png&name=900x900 width=40%>

# マニュアル v1.1
マニュアルを兼ねた記事なので先に使用方法から．
まだ開発段階なのでこれからも機能を追加すると思います．
不具合やBotが停止した場合は[@PigeonsHouse](https://twitter.com/PigeonsHouse)までご連絡ください．
つまるところデバッグをお手伝いいただきたい．

## 導入
こちらのリンクから→[進捗ちゃん](https://discord.com/api/oauth2/authorize?client_id=821046992460316733&permissions=0&scope=bot)
~~現在故意に停止しております．デプロイ先が枯渇気味()~~
デプロイ再開しています．
## 開始打刻
任意のボイスチャンネルに入って任意のテキストチャンネルで
`DO hogehoge`(hogehogeは作業内容の名前)
## 終了打刻
任意のテキストチャンネルで
`END TASK`
もしくはボイスチャンネルを抜ける
## 進捗報告チャンネルの変更
進捗の報告をしてほしいチャンネルで`SET HERE`(メンション)
未設定の場合はsystem_channel(新規参加者が流れるテキストチャンネル)になっています．

# 使用技術
Bot：Pythonのライブラリ,Discord.py
データベース：PostgreSQL

仕組みはそれほど難しくなく，on_message関数内でメッセージを受けて，データを保存し，返答しています．
データは一度Python上にオブジェクトの型で保存しており，作業中に新しく宣言をするとそのオブジェクトから既に宣言済みか調べるためなどに使用します．

```python
@client.event
async def on_message(message):

...

    if re.match(r'^DO .+', content):
        task = content[3:]
        if len(task) > 125:
            await m_channel.send(f'<@!{uid}>さん\nタスク名が長すぎるよ！\n短くまとめて宣言し直してくれたら嬉しいなっ！')
            return
        for data in Data:
            if data['user_id'] == uid:
                if data['task'] == task:
                    await m_channel.send(f'<@!{uid}> さんが「{task}」をしてるのちゃんと見てるよ？\n応援してるよ！頑張ってね！')
                    return
                else:
                    await m_channel.send(f'<@!{uid}>さん\n作業を変更するときは一度終了してからもう一度宣言してね！')
                    return
        if not searchGuild(guild_id):
            addGuild(message.guild, uid)
        if not (searchUser(uid) and searchGuildMember(guild_id, uid)):
            addUser(uid, name, guild_id)
        tid = searchTask(uid, task)
        await m_channel.send('<@!{uid}> さんは{task}をやるんだね！\n今日も頑張ろう！')
        Data.append({
            'user_id': uid,
            'name': name,
            'start_at': datetime.datetime.now().isoformat(),
            'task': task,
            'task_id': tid,
            'channel': m_channel
        })
```
終了の宣言をするとオブジェクトから該当の宣言を削除しDBに保存します．

```python
def addProgressTime(taskId, duration):
    with psycopg2.connect('postgresql://admin:admin@localhost:15432/admin') as conn:
        with conn.cursor() as cur:
            cur.execute("UPDATE progress_app.task SET duration=(duration+%s) WHERE id=%s", (duration, taskId))
        conn.commit()

...

@client.event
async def on_message(message):

...

    if content == 'END TASK':
        for data in Data:
            if data['user_id'] == uid:
                duration = datetime.datetime.now() - datetime.datetime.fromisoformat(data['start_at'])
                task_name = data['task']
                view_duration = view(duration)
                await m_channel.send(f'<@!{uid}>さん\n了解だよ！お疲れ様！\n【{task_name}】{view_duration}')
                addProgressTime(data['task_id'], duration)
                Data.remove(data)
                return
        await m_channel.send('<@!{uid}>さんはまだ作業開始の宣言をしてないよ？\n何の作業をしてるか教えてね！')
```
そして月が変わったタイミングなのですが，Discord.pyの性質上Scheduleライブラリと併用できない(まだいまいちわかってない)っぽいのでon_ready関数内にwhile Trueを回してそこで時間を確認しています．
Botで時刻をトリガーとした挙動とメッセージなどのDiscordの機能をトリガーとした挙動を併用する際にはわりと使えるのではないでしょうか．

```python
@client.event
async def on_ready():
    print('sintyokuBot is running')
    while True:
        nowTime = datetime.datetime.now()
        if nowTime.strftime('%d-%H:%M:%S') == '01-00:00:00':
                await reportTheirProgress()
        await asyncio.sleep(60)
```

# リポジトリ
GithubのURLはこちら→[sintyokuBot](https://github.com/PigeonsHouse/sintyokuBot)　即席かつ勉強中のソースなので汚いですが．
readmeは用意していませんが，オープンソースなので理論上誰でも進捗ちゃんのデプロイは出来ちゃいます．
(共同開発とかってできるんかな…できるならそこもお手伝いいただきたい…)

# おわりに
デプロイを急いだためマニュアル含めまだまだ穴だらけですのでじゃんじゃん改善していきたいと思います！
そして可愛い女の子に~~愛し愛され~~進捗管理されましょう！