From a16a0424dce94daba5c2a855007bd4194cc7f0d0 Mon Sep 17 00:00:00 2001 From: suti7yk5032 Date: Sun, 7 Jul 2024 15:02:54 +0900 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=9C=9F=E6=8C=99=E5=8B=95=E3=82=92bo?= =?UTF-8?q?t=E3=82=AF=E3=83=A9=E3=82=B9=E3=81=AB=E7=B5=B1=E5=90=88?= =?UTF-8?q?=E3=80=81csv=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE?= =?UTF-8?q?=E5=87=BA=E5=8A=9B=E3=81=8C=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dislocker.py | 108 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 26 deletions(-) diff --git a/dislocker.py b/dislocker.py index d666344..33ea745 100644 --- a/dislocker.py +++ b/dislocker.py @@ -5,16 +5,19 @@ import psycopg2 import hashlib import string import random +import csv -class Dislocker(): + +class Bot(discord.Client): def __init__(self): self.config_dir_path = "./config/" + self.export_dir_path = "./export/" self.server_config_path = self.config_dir_path + "server.json" if not os.path.isdir(self.config_dir_path): print("config ディレクトリが見つかりません... 作成します。") os.mkdir(self.config_dir_path) - + if not os.path.isfile(self.server_config_path): print("config ファイルが見つかりません... 作成します。") self.server_config = { @@ -39,12 +42,11 @@ class Dislocker(): with open(self.server_config_path, "r") as r: self.server_config = json.load(r) - + if not os.path.isdir(self.export_dir_path): + print("export ディレクトリが見つかりません... 作成します。") + os.mkdir(self.export_dir_path) - -class Bot(discord.Client): - def db_connect(self, host, db, port, user, password): - self.db = psycopg2.connect(f"host={host} dbname={db} port={port} user={user} password={password}") + self.db = psycopg2.connect(f"host={self.server_config['db']['host']} dbname={self.server_config['db']['db_name']} port={self.server_config['db']['port']} user={self.server_config['db']['username']} password={self.server_config['db']['password']}") def password_generate(self, length): numbers = string.digits # (1) @@ -55,12 +57,12 @@ class Bot(discord.Client): hashed = hashlib.md5(source.encode()) return hashed.hexdigest() - def register(self, **kwrags): - discord_user_id = str(kwrags["user_id"]) - pc_number = int(kwrags["pc_number"]) - device_number = int(kwrags["device_number"]) - if "detail" in kwrags: - detail = str(kwrags["detail"]) + def register(self, **kwargs): + discord_user_id = str(kwargs["user_id"]) + pc_number = int(kwargs["pc_number"]) + device_number = int(kwargs["device_number"]) + if "detail" in kwargs: + detail = str(kwargs["detail"]) else: detail = None #パスワード生成、ハッシュ化 @@ -118,8 +120,8 @@ class Bot(discord.Client): return result - def stop(self, **kwrags): - discord_user_id = str(kwrags["user_id"]) + def stop(self, **kwargs): + discord_user_id = str(kwargs["user_id"]) cursor = self.db.cursor() cursor.execute("SELECT * FROM club_member WHERE discord_userid = %s", (discord_user_id,)) user_record = cursor.fetchall() @@ -137,10 +139,10 @@ class Bot(discord.Client): return result - def user_register(self, **kwrags): - discord_user_id = str(kwrags["discord_user_id"]) - discord_user_name = str(kwrags["discord_user_name"]) - name = str(kwrags["name"]) + def user_register(self, **kwargs): + discord_user_id = str(kwargs["discord_user_id"]) + discord_user_name = str(kwargs["discord_user_name"]) + name = str(kwargs["name"]) cursor = self.db.cursor() cursor.execute("SELECT * FROM club_member WHERE discord_userid = %s", (discord_user_id,)) user_record = cursor.fetchall() @@ -150,9 +152,57 @@ class Bot(discord.Client): result = {"result": "ok"} else: result = {"result": "already_exists"} - return result + def report_export(self, **kwargs): + try: + csv_file_path = self.export_dir_path + "pc_usage_history.csv" + cursor = self.db.cursor() + # メインテーブルの列情報を取得(user_idを除く) + cur.execute(sql.SQL("SELECT * FROM {} LIMIT 0").format(sql.Identifier(main_table))) + main_columns = [desc[0] for desc in cur.description if desc[0] != 'member_id'] + + # クエリを作成(列名を明確に指定) + query = sql.SQL(""" + SELECT {main_columns}, {related_table}.name + FROM {main_table} + LEFT JOIN {related_table} ON {main_table}.member_id = {related_table}.id + """).format( + main_columns=sql.SQL(', ').join([sql.SQL("{}.{}").format(sql.Identifier(main_table), sql.Identifier(col)) for col in main_columns]), + main_table=sql.Identifier(main_table), + related_table=sql.Identifier(related_table) + ) + + cur.execute(query) + + # 列名を再構成(nameを2番目に配置) + column_names = [main_columns[0], 'name'] + main_columns[1:] + + rows = cur.fetchall() + + with open(csv_file_path, 'w', newline='', encoding='utf-8-sig') as csvfile: + csvwriter = csv.writer(csvfile) + csvwriter.writerow(column_names) + + for row in rows: + # nameを2番目に移動 + formatted_row = [format_datetime(row[0])] + [row[-1]] + [format_datetime(field) if field is not None else '' for field in row[1:-1]] + csvwriter.writerow(formatted_row) + + print(f"テーブル '{main_table}' の内容を '{csv_file_path}' に出力しました。") + + except (Exception, psycopg2.Error) as error: + print("使用履歴のエクスポート時にエラーが発生しました\nエラー内容\n", error) + result = {"result": "export_error"} + + finally: + cursor.close() + result = {"result": "ok", "file_path": csv_file_path} + + return result + + + async def on_ready(self): print("ログイン成功") @@ -182,7 +232,7 @@ class Bot(discord.Client): await message.channel.send(f"使用が開始されました。\nパスワード | {register["password"]}\nPC番号 | {msg_split[1]}\nデバイス番号 | {msg_split[2]}") elif len(msg_split) == 4: await message.channel.send(f"使用が開始されました。\nパスワード | {register["password"]}\nPC番号 | {msg_split[1]}\nデバイス番号 | {msg_split[2]}\n使用目的 | {msg_split[3]}") - await self.get_channel(dislocker.server_config["bot"]["log_channel_id"]).send(f'{register["name"]} さんがPC {msg_split[1]} を使用しています') + await self.get_channel(self.server_config["bot"]["log_channel_id"]).send(f'{register["name"]} さんがPC {msg_split[1]} を使用しています') elif register["result"] == "user_data_not_found": await message.channel.send("ユーザーとして登録されていないようです。管理者に問い合わせてください。") elif register["result"] == "pc_already_in_use_by_you": @@ -200,9 +250,9 @@ class Bot(discord.Client): await message.channel.send("使用されていないようです...") elif stop["result"] == "ok": await message.channel.send(f"PC番号 {stop["pc_number"]} の使用が終了されました。") - await self.get_channel(dislocker.server_config["bot"]["log_channel_id"]).send(f'{stop["name"]} さんがPC {stop["pc_number"]} の使用を終了しました') + await self.get_channel(self.server_config["bot"]["log_channel_id"]).send(f'{stop["name"]} さんがPC {stop["pc_number"]} の使用を終了しました') - elif message.channel.id == dislocker.server_config["bot"]["config_channel_id"]: + elif message.channel.id == self.server_config["bot"]["config_channel_id"]: msg_split = message.content.split() if msg_split[0] == "/register": if len(msg_split) <= 3: @@ -219,11 +269,17 @@ class Bot(discord.Client): else: await message.channel.send("なんでかわからんけど不正です。") + elif msg_split[0] == "/export": + export = self.report_export() + if export["result"] == "ok": + await message.channel.send("使用履歴のレポートです。", file=discord.file(export["file_path"])) + pass + elif export["result"] == "export_error": + await message.channel.send("エクスポートに失敗しました。") + intents = discord.Intents.default() intents.message_content = True -dislocker = Dislocker() bot = Bot(intents=intents) -bot.db_connect(dislocker.server_config["db"]["host"], dislocker.server_config["db"]["db_name"], dislocker.server_config["db"]["port"], dislocker.server_config["db"]["username"], dislocker.server_config["db"]["password"]) -bot.run(dislocker.server_config["bot"]["token"]) \ No newline at end of file +bot.run(bot.server_config['bot']['token'])