図書管理システム

# システム概要
### 目的
本システムはキャンパス図書を管理することが目的で制作されました。
システム名を図書管理システム
Qiitaの記事を、図書システムの取扱説明書の代りとします。
プログラムの詳細に関しては、GitHub上の[README.md](https://github.com/MT472562/Library_Tool_Ver3/blob/main/README.md)を確認してください


### 過去情報
本システムには、それ以前に使用されていたシステムを元に再設計をしています。
[~~図書管理システムVersion1~~](https://github.com/n-s-fukuoka-cp-book/cp-book-management)→スプレッドシートの設計のため、使用非推奨
[~~図書管理システムVersion2~~](https://github.com/n-s-fukuoka-cp-book/cp-book-managementV2)→システム設計中止
[図書管理システムVersion3(本システム)](https://github.com/MT472562/Library_Tool_Ver3)


# 環境

### 開発環境
- 開発環境は以下のとおりです。
- M1 MacBook Air 
- Mac OS Ventura 13.4.1
- Python3.11.4
- venvを使用

# モジュール

### モジュールインポート
```python
import base64
import hashlib
import logging
import os
import random
import secrets
import sqlite3
import string
import time
from datetime import date
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from urllib.parse import urlparse
from ics import Calendar, Event
import arrow
import flask
from flask import render_template, url_for, request, redirect, jsonify, send_file
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
```

### 使用モジュールのリファレンスリンク

:::note warn
警告
ライブラリのリンクを表示すると、表示文字数が多くなるので、ご注意ください
:::
<details><summary>使用モジュールのリファレンスリンク</summary>

:::note alert
警告
このモジュール説明はAIを使用して記述されています。
参考程度にしてください
:::
base64: [base64](https://docs.python.org/3/library/base64.html)
hashlib: [hashlib](https://docs.python.org/3/library/hashlib.html)
logging: [logging](https://docs.python.org/3/library/logging.html)
os: [os](https://docs.python.org/3/library/os.html)
random: [random](https://docs.python.org/3/library/random.html)
secrets: [secrets](https://docs.python.org/3/library/secrets.html)
sqlite3: [sqlite3](https://docs.python.org/3/library/sqlite3.html)
string: [string](https://docs.python.org/3/library/string.html)
time: [time](https://docs.python.org/3/library/time.html)
date: [date](https://docs.python.org/3/library/datetime.html)
encoders: [encoders](https://docs.python.org/3/library/email.encoders.html)
MIMEBase: [MIMEBase](https://docs.python.org/3/library/email.mime.base.html)
MIMEMultipart: [MIMEMultipart](https://docs.python.org/3/library/email.mime.multipart.html)
MIMEText: [MIMEText](https://docs.python.org/3/library/email.mime.text.html)
urlparse: [urlparse](https://docs.python.org/3/library/urllib.parse.html)
Calendar: [Calendar](https://icspy.readthedocs.io/en/stable/api.html#ics.Calendar)
Event: [Event](https://icspy.readthedocs.io/en/stable/api.html#ics.Event)
arrow: [arrow](https://arrow.readthedocs.io/en/stable/)
flask: [Flask](https://flask.palletsprojects.com/en/2.1.x/)
render_template: [render_template](https://flask.palletsprojects.com/en/2.1.x/api/#flask.render_template)
url_for: [url_for](https://flask.palletsprojects.com/en/2.1.x/api/#flask.url_for)
request: [request](https://flask.palletsprojects.com/en/2.1.x/api/#flask.request)
redirect: [redirect](https://flask.palletsprojects.com/en/2.1.x/api/#flask.redirect)
jsonify: [jsonify](https://flask.palletsprojects.com/en/2.1.x/api/#flask.jsonify)
send_file: [send_file](https://flask.palletsprojects.com/en/2.1.x/api/#flask.send_file)
Credentials: [Credentials](https://google-auth.readthedocs.io/en/latest/reference/google.oauth2.credentials.html)
build: [build](https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html)

</details>


# ログデータ


### ログデータの内容

ログデータはPythonプログラムを実行した日付を元に、処理を開始されます。
 **停止するまでの間、そのセッションは開始日のログデータに保存され続けます。** 

:::note warn
一例
2023/01/01にアプリを起動
日付を超えて2023/01/03にプログラム停止
＞＞2023-01-01.log
にデータが保存されます。
:::

### ログのファイルの生成と保存期間
保存期間は、ログファイル名に基づく生成日付から7日分に指定されています。
 **その期間がすぎると、プログラム再スタート時に削除処理が行われるので、ご注意ください** 

```Python
logging.basicConfig(filename=f'logs/{today}.log', level=logging.DEBUG,
                    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
(levelname)s - %(message)s')
logging.debug('デバッグメッセージ')
logging.info('一般情報メッセージ')
logging.warning('警告メッセージ')
logging.error('エラーメッセージ')
logging.critical('重大エラーメッセージ')

# 一週間よりも古い日付を計算
today = datetime.now()
one_week_ago = (today - timedelta(days=7)).strftime('%Y-%m-%d.log')

# ログファイルのあるディレクトリのパス
files = os.listdir('./logs')
for file in files:
    if one_week_ago > file:
        os.remove(f"logs/{file}")
    else:
        pass
```

# セッション
 
### Flaskの制約

Flaskでは、アプリの再スタート時に一度初期化されるようになっています。
また、再スタートしない場合でも、ログインされている情報は７日間でセッションアウトするように設計されています。

```Python
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
```

# 定期実行プログラムについて
図書管理システムでは１時間おきにメール等の処理を定期実行しています。
>以下は返却当日のメール送信と、その日の送信チェックデータベース生成関数および、Flaskアプリケーション実行を含みます
``` python
def run_flask_app():
    app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
    app.run(host='0.0.0.0', port=9000)


def other_code():
    while True:
        import datetime

        now = datetime.datetime.now()
        h = now.hour
        if h > 7 and h < 16:
            new_date_in()
            return_mail_post()
            time.sleep(1)
            print("実行")
        time.sleep(60)
    pass


import threading

if __name__ == '__main__':
    flask_thread = threading.Thread(target=run_flask_app)
    flask_thread.start()

    other_code()
```

# 実行
Flaskでは、実行時にhostを0,0,0,0に設定することで同じLAN内からアクセスすることができるようになっています。
 **もし実行できない場合はhostのアドレスやport番号を変更してください** 
```Python
app.run(host='0.0.0.0', port=9000)
```







# 各ページの利用方法について
::: note alert
**レイアウトが多少異なる場合がありますが、
基本的に操作性は変わりませんので、ご安心ください**
:::

## メニュー
<img width="50" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/ba623b8b-2546-df78-1287-8dc9290a6d10.png"</img>
<details><summary>メニューの説明</summary>

:::note alert
このメニュー説明はAIを使用して記述されています。
参考程度にしてください
:::
- ホーム（トップ）ページへ移動するための家のマークです。ここからはピックアップの本を確認することができます。

- アカウントのページへ移動するための人のマークです。ログインページやアカウントに関する情報を確認することができます。

- 本の検索ページへ移動するための虫眼鏡マークです。ここから本の検索が可能です。

- 貸出ページへ移動するための本のマークです。アカウントを持っている人はここから本を貸出することができます。

- 返却ページへ移動するための本棚マークです。貸出時に付与される貸出IDを入力することで、本を返却することができます。

- 新規本の登録ページへ移動するための記述マークです。ただし、図書委員会など限られた権限を持つ人のみがアクセスできます。ここでは新しい本を登録することができます。

- 棚卸し機能であるしおりマークです。同様に、図書委員会など限られた権限を持つ人のみがアクセスできます。ここでは年度末に本の棚卸しを行うことができます。

- ログイン中の情報や各種操作マニュアルなどのリンクが搭載されているinfoマークです。



</details>


## トップページ
:::note info

図書システムでのトップページに当たります。
新規で購入した本をメインに表示しています。
本の画像をクリックすると、対象の本をGoogle検索で検索することができます。  

:::
アクセスURL
```md
/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/58093567-26af-d288-ed95-06089a988f86.png "トップページのイメージ")
---






## アカウント
:::note info

アカウントログインページになります。
アカウントを作成している場合ここで、ユーザーIDとパスワードを入力してサインインします。
アカウントの情報更新などもできます。
アカウント未作成の場合やパスワードを忘れた場合は作成や、リセットが必要です。


:::
アクセスURL
```md
/account
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/aa8c84b5-725d-6ec5-6fec-9338f11571d4.png "ログインページのイメージ")
---






## パスワードのリセットページ
:::note info

アカウントを作成していた場合、でパスワードを忘れしまった場合はこちらからリセットトークンを含むメールを送信します。
対象のユーザーIDと登録時に使用したメールアドレスを入力してください。
ユーザーIDがわからない場合は、図書委員会に声をかけてください。
:::
:::note warn
リセットメールからパスワードをリセットするリングが送られてくるので、メール送信後にメールフォルダを確認してください。
そのURLにアクセスすることでパスワードリセットできます。
:::
アクセスURL
```md
/reset_account
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/23ba6f6c-336d-803e-98e2-42c876bbe932.png "パスワードリセットページのイメージ")
---






## アカウント新規作成
:::note info

アカウントを持っていないひとが、新規でアカウントを登録するページです。
- メールアドレス
- パスワード
- 希望するログインID
- 使う人の名前（ニックネーム可）
などを入力します。
アクセス権限レベルは一般ユーザーは「Level１」で大丈夫です。
Level３以上のアカウント作成には、許可されたアカウントの認証が必要です。

:::
:::note warn
上記と同様のことになりますが、アカウント作成時のLevelは一般ユーザーは必ず１を選択してください。
Level１の場合アカウンの認証IDの入力などは、自動入力されるので、触らないでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/bf77a229-151a-c1cf-1d7f-6b1804bcf7e4.png)

:::
アクセスURL
```md
/new_account
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/f258b2b6-65e4-11aa-9a32-b5f26ea7b20d.png "アカウント作成ページのイメージ")

:::note warn
詳細は **[アカウントを作る](https://qiita.com/magirawashili/private/0eb97adab73b62e80ad0#%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B)** を確認してください。
:::
---






## 本の検索
:::note info

本の検索をすることができます。
キーワード入力欄に本の名前などを入力してください
チェックマークをつけると、その本に関連しそうなワードも調べることができます。

:::
アクセスURL
```md
/search
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/4862a6b7-c7fb-9159-12f2-064ea5965dd4.png)

:::note info

本の詳細を見るには、検索結果からその本のタイトルをクリックしてください
その本の詳細等を確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/2e4c9755-1280-7253-7be4-d7187082eb3c.png)

:::
---







## 本の貸出
:::note info

このページはログインしている人のみが、アクセスすることができます。
本の裏に貼ってあるバーコードのうちA10,,,,から始まる８桁のバーコードをスキャナで読み込むか、手打ちしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/f5c0dc54-1619-bf1f-e1c2-9934221a92fd.png)
貸出可能な本のみが、こちらに追加されます。
貸出したい本がきまったら、貸出ボタンを押してください。

しばらくしてシステムから自動でメールが配信されます。
※もしこない場合は、迷惑メールフォルダを確認してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/88eecb6a-6f46-6b93-50cd-0dc639fedf21.png)




例の中では202307142,,から始まる返却コードが返却時に必要なIDです。
添付ファイルの中に、返却コードをバーコード化したものが含まれるので、そちらを利用して返却することもできます。
また、カレンダーファイルも添付されているので、画像の中だと、一番上の「本の返却日のお知らせ」の下の方にある「カレンダーに追加」というところを押して、カレンダーに追加することが可能になっています。詳細は[公式ページ](https://support.google.com/calendar/answer/6192039?hl=ja&co=GENIE.Platform%3DDesktop&oco=1)を確認してください


:::
アクセスURL
```md
/lending
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/c04cb368-c38d-f1a1-bbd3-d85d78a512f0.png "本のレンタルページのイメージ")

---






## 本の返却
:::note info

貸出した本の返却をするページです。
貸出した時や、返却日のお知らせなどのメールに返却コード（バーコードも可）が記載されています。
そのコードを入力して返却を完了させてください。

:::
アクセスURL
```md
/return
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/9a8190c9-57c8-ff02-9ac4-e3901f24e1f3.png)

---





## 新本登録
:::note info

新本登録はアクセスレベル３以上の権限がないと実行できません。
新本登録の際は管理番号を新しい本に貼ってそのコードを管理番号とします。
管理番号のあとに、ISBNを入力してください
APIを使用して基本情報を取得します

:::
:::note warn
注意点としては、APIが情報を引っ張って来れない場合があります、この場合は、空白の場所を手動で入力してください
また、この紐づけ作業を謝ると、以後のデータが誤ったものになるので、十分に注意してください。

:::
アクセスURL
```md
/new-book
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/5e5db816-2142-e19a-06d8-b0dff79cfd1b.png)

---

## 棚卸し
本の棚卸しページです。
キャンパスに蔵書している本の棚卸しと、棚卸し終了後にCSVファイルを出力することができます。
アカウントレベルが２，４，５のアカウントでアクセスすることができます。

アクセスURL
```md
/inventory
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/f5aedbb2-d14a-d2b1-5e5b-c812b3571be1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/37d8b83a-f29c-279e-3510-04e9452ff9e6.png)


---






# アカウントを作る
アカウント作成の動画を添付していますのでご確認ください
:::note info

まずは、アカウント作成ページヘ移動してください
URLにアクセスしてください
```md
/new_account
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/f258b2b6-65e4-11aa-9a32-b5f26ea7b20d.png "アカウント作成ページのイメージ")
この画面が表示されたら成功です。

有効なメールアドレス
パスワード **（大文字　小文字　数字　のすべてを含む）** 
ログインID（Twitterで言うところの@~~~~~に当たる部分） **(学籍番号推奨)** 
名前（NN太郎など）
を入力してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/f0f8dc2c-04fc-c7bd-0c39-5698d5037997.png)

次にアカウントの権限レベルを選択します。
一般ユーザー（図書委員会などではない人）はLevel１を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/4f15f442-4d95-cf8f-2325-5070eb01bf02.png)
 **Level１を選択すると自動で認証用IDと認証パスワードが入力されますので、その欄を触らないでください** 

次にアカウント登録ボタンを押します。

正常に次に進むと、画像のようにメールに送信された数字を入力するように指示するページが表示されます。
別のタブでメールを開いて６桁の数字を入力してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/1c93fbd3-be03-998f-9edf-149d8a4b44af.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/ecc4efbb-fb41-d3ef-e087-c3915e429613.png)


認証番号を入力して、以下のようなページが表示されれば、登録完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/e3be499d-a16b-2beb-2147-29bd57ecf9f6.png)



:::note warn
アクセスレベル別の権限
※詳細は[GitHub #axesslevel](https://github.com/MT472562/Library_Tool_Ver3/blob/main/README.md#axesslevel)を参照してください
| Access Level   | 実行可能処理              |
|----------------|---------------------|
| Access Level 1 | 貸出　返却               |
| Access Level 2 | ログの出力と確認            |
| Access Level 3 | 新本登録                |
| Access Level 4 | データベースの編集（削除）       |
| Access Level 5 | ユーザーの新規追加　パスワードリセット |
:::

<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/dKLmapyHmP8?si=LW5jDlPSpmCevLVe" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

# エラー対処

### エラーIDの見方
:::note warn
エラーIDの内容は、以下の文字列で構成されます。

(例)"ERR-3-001"

"ERR" はエラーIDであることを示します。
"4" は操作に必要なアクセスレベルを示します。
"001" はエラーメッセージです。エラーの理由と解決に使用できます。
(エラーの詳細詳細はGitHub上の[エラーIDの種類と対処方法](https://github.com/MT472562/Library_Tool_Ver3#%E3%82%A8%E3%83%A9%E3%83%BCid%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%A8%E5%AF%BE%E5%87%A6%E6%96%B9%E6%B3%95)を確認してください。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/7a678d18-764b-1c75-6dc1-2440e9ecee3f.png)

:::
### その他エラー
:::note alert
このエラー説明はAIを使用して記述されています。
参考程度にしてください
:::

:::note warn
エラーには様々な種類のものがあります。
それは、意図されていないエラーが発生した場合などは、また別のエラーが発生します。
その一例が404Not Foundです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3130847/5456729d-10a6-f0c8-7430-f9df44aa8b79.png)


以下におおよそのエラーの種類を記載します。


|ErrorCode|ErrorMessage|ErrorDescription|
|------|------|-----|
|400 Bad Request|不正なリクエスト|クライアントから送信されたリクエストが不正であることを示します。|
|401 Unauthorized|認証が必要です|クライアントが認証を行う必要があることを示します。|
|403 Forbidden|アクセスが禁止されています|クライアントがリソースにアクセスする権限を持っていないことを示します。|
|404 Not Found|ページが見つかりません|クライアントがリクエストしたリソースが存在しないことを示します。|
|500 Internal Server Error|サーバ内部エラー|サーバ内で予期しないエラーが発生したことを示します。|
|503 Service Unavailable|サービス利用不可|サーバが一時的にリクエストを処理できない状態であることを示します。|
:::