Compare commits

...

31 commits

Author SHA1 Message Date
707e2e3ed6 ログアウトボタンの表記をサインアウトに変更 2024-07-08 11:42:19 +09:00
d76ba87887 ヘルプ、サインアウトの関数を追加 2024-07-08 11:41:38 +09:00
889c464c5f 使用履歴出力のreturn修正 2024-07-08 11:30:20 +09:00
abf03bd4d6 Excelシートで出力できるように 2024-07-08 11:23:19 +09:00
b37573a371 出力されるcsvファイルが履歴のid順で並ぶように 2024-07-07 18:15:15 +09:00
9f59b8dab1 csv出力のコードを修正その5 2024-07-07 18:09:25 +09:00
ce3bf1cd3c csv出力のコードを修正その4 2024-07-07 18:07:53 +09:00
e1fee8b2e5 csv出力のコードを修正その3 2024-07-07 18:00:49 +09:00
d640155e75 csv出力のコード修正その2 2024-07-07 17:48:54 +09:00
8b7e7a2a65 csv出力のコード修正 2024-07-07 17:43:36 +09:00
f26e0d9ad9 force_stopのreturnを追加 2024-07-07 17:40:03 +09:00
c9b7259728 fstopの引数が間違っていたのを修正 2024-07-07 17:37:53 +09:00
aeb9553113 int判定を修正 2024-07-07 17:34:51 +09:00
80a266142b printfデバックを削除、チャンネルIDがintで記述されていない場合は起動しなくなるように 2024-07-07 17:24:33 +09:00
62537a1038 printデバック用 2024-07-07 17:10:05 +09:00
57f428e910 使用登録の強制停止を実装 2024-07-07 16:35:57 +09:00
18970c9079 メッセージの文言を変更 2024-07-07 16:08:17 +09:00
9e4f39f8fa ようやく理解した selfを追加 2024-07-07 16:04:46 +09:00
60af46a32b returnを回避 2024-07-07 15:55:14 +09:00
bf418936d4 tryを修正 2024-07-07 15:52:46 +09:00
73502817e0 きれそう 2024-07-07 15:48:43 +09:00
4ecf209e7e データベース接続時の例外処理を追加 2024-07-07 15:43:43 +09:00
f7f7033ea5 class名だめだったから修正 2024-07-07 15:33:30 +09:00
2ef4d639bf やっぱ初期処理と関連の変数のクラスを分けた 2024-07-07 15:24:55 +09:00
a16a0424dc 初期挙動をbotクラスに統合、csvファイルの出力ができるように 2024-07-07 15:02:54 +09:00
41e85cb6bc csv出力のテスト 2024-07-07 15:02:11 +09:00
dde933fc14 名前変更に伴い削除 2024-07-07 15:01:24 +09:00
5de39f92a4 PC使用履歴のテーブルからcsvファイルを作成できるように 2024-07-07 13:50:57 +09:00
7d06ad18c4 設定がひとつのjsonファイルで完結するように 2024-07-07 13:49:53 +09:00
0a7bb89a98 GUIを再設計 (thanks for 八咫烏!) 2024-07-04 20:40:03 +09:00
5cd099a411 GUIデザインをコンセプトに近づける 2024-07-01 12:51:17 +09:00
4 changed files with 549 additions and 153 deletions

View file

@ -2,14 +2,70 @@ import json
import discord
import os
import psycopg2
from psycopg2 import sql
import hashlib
import string
import random
from datetime import datetime
from openpyxl import Workbook
class DL():
def __init__(self):
self.config_dir_path = "./config/"
self.export_dir_path = "./export/"
self.server_config_path = self.config_dir_path + "server.json"
try:
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 = {
"db": {
"host": "localhost",
"port": "5432",
"db_name": "dislocker",
"username": "user",
"password": "password"
},
"bot": {
"token": "TYPE HERE BOTS TOKEN KEY",
"log_channel_id" : "TYPE HERE CHANNEL ID (YOU MUST USE INT !!!!)",
"config_channel_id": "TYPE HERE CHANNEL ID (YOU MUST USE INT !!!!)"
}
}
with open(self.server_config_path, "w") as w:
json.dump(self.server_config, w, indent=4)
elif os.path.isfile(self.server_config_path):
with open(self.server_config_path, "r") as r:
self.server_config = json.load(r)
print("config ファイルを読み込みました。")
if not os.path.isdir(self.export_dir_path):
print("export ディレクトリが見つかりません... 作成します。")
os.mkdir(self.export_dir_path)
if type(self.server_config["bot"]["log_channel_id"]) is not int or type(self.server_config["bot"]["config_channel_id"]) is not int:
print("config ファイル内でチャンネルIDがint型で記述されていません。int型で記述して、起動してください。")
self.init_result = "not_int"
else:
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']}")
self.init_result = "ok"
except (Exception) as error:
print("初回処理でエラーが発生しました。\nエラー内容\n" + str(error))
self.init_result = "error"
finally:
pass
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}")
def password_generate(self, length):
numbers = string.digits # (1)
password = ''.join(random.choice(numbers) for _ in range(length)) # (2)
@ -19,12 +75,13 @@ 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):
try:
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
#パスワード生成、ハッシュ化
@ -32,7 +89,7 @@ class Bot(discord.Client):
password_hash = self.hash_genarate(password)
print("password generated")
#メンバーリストと送信者を照合
cursor = self.db.cursor()
cursor = dislocker.db.cursor()
cursor.execute("SELECT * FROM club_member WHERE discord_userid = %s", (discord_user_id,))
user_record = cursor.fetchall()
#ユーザーデータがなかったら(未登録の場合)
@ -61,7 +118,7 @@ class Bot(discord.Client):
cursor.execute("UPDATE pc_list SET using_user_id = %s WHERE pc_number = %s", (user_record[0][0], pc_number))
cursor.execute("UPDATE pc_list SET password_hash = %s WHERE pc_number = %s", (password_hash, pc_number))
self.db.commit()
dislocker.db.commit()
result = {"result": "ok", "password": str(password), "name": str(user_record[0][1])}
else:
cursor.execute("SELECT * FROM pc_list WHERE pc_number=%s", (pc_number,))
@ -77,14 +134,20 @@ class Bot(discord.Client):
cursor.execute("UPDATE pc_list SET using_user_id = %s WHERE pc_number = %s", (user_record[0][0], pc_number))
cursor.execute("UPDATE pc_list SET password_hash = %s WHERE pc_number = %s", (password_hash, pc_number))
self.db.commit()
dislocker.db.commit()
result = {"result": "ok", "password": str(password), "name": str(user_record[0][1])}
except:
print("登録処理中にエラーが発生しました。")
result = {"result": "error"}
finally:
cursor.close()
return result
def stop(self, **kwrags):
discord_user_id = str(kwrags["user_id"])
cursor = self.db.cursor()
def stop(self, **kwargs):
try:
discord_user_id = str(kwargs["user_id"])
cursor = dislocker.db.cursor()
cursor.execute("SELECT * FROM club_member WHERE discord_userid = %s", (discord_user_id,))
user_record = cursor.fetchall()
cursor.execute("SELECT * FROM pc_usage_history WHERE member_id= %s ORDER BY id DESC LIMIT 1", (user_record[0][0],))
@ -96,29 +159,145 @@ class Bot(discord.Client):
cursor.execute("UPDATE pc_usage_history SET end_use_time = current_timestamp WHERE id = %s", (pc_usage_history_record[0][0],))
cursor.execute("UPDATE pc_list SET using_user_id = NULL WHERE pc_number = %s", (pc_usage_history_record[0][2],))
cursor.execute("UPDATE pc_list SET password_hash = NULL WHERE pc_number = %s", (pc_usage_history_record[0][2],))
self.db.commit()
dislocker.db.commit()
result = {"result": "ok", "pc_number": str(pc_usage_history_record[0][2]), "name": str(user_record[0][1])}
except:
print("停止処理にエラーが発生しました。")
result = {"result": "error"}
finally:
cursor.close()
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"])
cursor = self.db.cursor()
def user_register(self, **kwargs):
try:
discord_user_id = str(kwargs["discord_user_id"])
discord_user_name = str(kwargs["discord_user_name"])
name = str(kwargs["name"])
cursor = dislocker.db.cursor()
cursor.execute("SELECT * FROM club_member WHERE discord_userid = %s", (discord_user_id,))
user_record = cursor.fetchall()
if not user_record:
cursor.execute("INSERT INTO club_member (name, discord_username, discord_userid) VALUES (%s, %s, %s)", (name, discord_user_name, discord_user_id))
self.db.commit()
dislocker.db.commit()
result = {"result": "ok"}
else:
result = {"result": "already_exists"}
except:
print("ユーザー登録中にエラーが発生しました。")
result = {"result": "error"}
finally:
cursor.close()
return result
def format_datetime(self, value):
if isinstance(value, datetime):
return value.strftime('%Y-%m-%d %H:%M:%S')
return value
def report_export(self, **kwargs):
try:
cursor = dislocker.db.cursor()
csv_file_path = dislocker.export_dir_path + "pc_usage_history.csv"
main_table = "pc_usage_history"
related_table = "club_member"
excel_file_path = dislocker.export_dir_path + "pc_usage_history.xlsx"
# メインテーブルの列情報を取得user_idを除く
cursor.execute(sql.SQL("SELECT * FROM {} LIMIT 0").format(sql.Identifier(main_table)))
main_columns = [desc[0] for desc in cursor.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
ORDER BY 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)
)
cursor.execute(query)
# 列名を再構成nameを2番目に配置
column_names = [main_columns[0], 'name'] + main_columns[1:]
rows = cursor.fetchall()
# Excelワークブックを作成
wb = Workbook()
ws = wb.active
# 列名を書き込み
ws.append(column_names)
# データを書き込み
for row in rows:
# nameを2番目に移動
formatted_row = [self.format_datetime(row[0])] + [row[-1]] + [self.format_datetime(field) if field is not None else '' for field in row[1:-1]]
ws.append(formatted_row)
# 列幅を自動調整
for col in ws.columns:
max_length = 0
column = col[0].column_letter
for cell in col:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = (max_length + 2) * 1.2
ws.column_dimensions[column].width = adjusted_width
# Excelファイルを保存
wb.save(excel_file_path)
print(f"テーブル '{main_table}' の内容を '{excel_file_path}' に出力しました。")
result = {"result": "ok", "file_path": excel_file_path}
except (Exception, psycopg2.Error) as error:
print("使用履歴のエクスポート時にエラーが発生しました\nエラー内容\n", str(error))
result = {"result": "export_error"}
finally:
cursor.close()
return result
def force_stop(self, **kwargs):
try:
pc_number = kwargs["pc_number"]
cursor = dislocker.db.cursor()
cursor.execute("SELECT * FROM pc_list WHERE pc_number = %s", (pc_number,))
pc_list_record = cursor.fetchall()
if not pc_list_record[0][1] == None:
cursor.execute("UPDATE pc_list SET using_user_id = NULL WHERE pc_number = %s", (pc_number,))
if not pc_list_record[0][2] == None:
cursor.execute("UPDATE pc_list SET password_hash = NULL WHERE pc_number = %s", (pc_number,))
cursor.execute("SELECT * FROM pc_usage_history WHERE member_id = %s AND pc_number = %s ORDER BY id DESC LIMIT 1", (pc_list_record[0][1], pc_number))
pc_usage_history_record = cursor.fetchall()
cursor.execute("UPDATE pc_usage_history SET end_use_time = current_timestamp WHERE id = %s", (pc_usage_history_record[0][0],))
dislocker.db.commit()
result = {"result": "ok"}
else:
result = {"result": "not_used"}
except:
result = {"result": "error"}
finally:
cursor.close()
return result
async def on_ready(self):
print("ログイン成功")
print("DiscordのBotが起動しました。")
async def on_message(self, message):
if message.author.bot:
@ -146,13 +325,13 @@ 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(bot_config["log_channel_id"]).send(f'{register["name"]} さんがPC {msg_split[1]} を使用しています')
await self.get_channel(dislocker.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":
await message.channel.send(f"あなたはPCをもう使用されているようです。使用状態を解除するには /stop で使用終了をお知らせください。\nPC番号 | {register["pc_number"]}\nデバイス番号 | {register["device_number"]}\n使用開始時刻 | {register["start_time"]}\n使用目的 | {register["detail"]}")
elif register["result"] == "pc_already_in_use_by_other":
await message.channel.send(f"PCはもう使用されています。別のPC番号を指定して、再度お試しください。")
await message.channel.send(f"そのPCは他のメンバーによって使用されています。別のPC番号を指定して、再度お試しください。")
else:
await message.channel.send("番号がおかしいようです。")
else:
@ -164,9 +343,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(bot_config["log_channel_id"]).send(f'{stop["name"]} さんがPC {stop["pc_number"]} の使用を終了しました')
await self.get_channel(dislocker.server_config["bot"]["log_channel_id"]).send(f'{stop["name"]} さんがPC {stop["pc_number"]} の使用を終了しました')
elif message.channel.id == bot_config["config_channel_id"]:
elif message.channel.id == dislocker.server_config["bot"]["config_channel_id"]:
msg_split = message.content.split()
if msg_split[0] == "/register":
if len(msg_split) <= 3:
@ -183,46 +362,34 @@ 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("エクスポートに失敗しました。")
config_dir_path = "./config/"
db_config_path = config_dir_path + "db.json"
if not os.path.isfile(db_config_path):
if not os.path.isdir(config_dir_path):
os.mkdir(config_dir_path)
elif msg_split[0] == "/fstop":
if len(msg_split) == 1:
await message.channel.send("PC番号を指定してください。")
elif len(msg_split) == 2:
fstop = self.force_stop(pc_number=msg_split[1])
if fstop["result"] == "ok":
await message.channel.send(f"PC番号 {msg_split[1]} の使用登録を解除しました。")
elif fstop["result"] == "not_used":
await message.channel.send("PCは使用されていないようです...")
else:
await message.channel.send("エラーが発生しました。")
else:
await message.channel.send("引数が多すぎます。")
db_config = {
"host": "localhost",
"db": "dislocker",
"username": "user",
"password": "example_pass",
"port": "5432"
}
with open(db_config_path, "w") as w:
json.dump(db_config, w, indent=4)
elif os.path.isfile(db_config_path):
with open(db_config_path, "r") as r:
db_config = json.load(r)
bot_config_path = config_dir_path + "bot.json"
if not os.path.isfile(bot_config_path):
if not os.path.isdir(config_dir_path):
os.mkdir(config_dir_path)
bot_config = {
"token": "TYPE HERE BOTS TOKEN KEY",
"log_channel_id" : "TYPE HERE CHANNEL ID",
"config_channel_id": "TYPE HERE CHANNEL ID"
}
with open(bot_config_path, "w") as w:
json.dump(bot_config, w, indent=4)
elif os.path.isfile(bot_config_path):
with open(bot_config_path, "r") as r:
bot_config = json.load(r)
intents = discord.Intents.default()
intents.message_content = True
bot = Bot(intents=intents)
bot.db_connect(db_config["host"], db_config["db"], db_config["port"], db_config["username"], db_config["password"])
bot.run(bot_config["token"])
dislocker = DL()
if dislocker.init_result == "ok":
intents = discord.Intents.default()
intents.message_content = True
bot = Bot(intents=intents)
bot.run(dislocker.server_config['bot']['token'])
else:
pass

View file

@ -21,12 +21,12 @@ class App(customtkinter.CTk):
else:
self.attributes('-fullscreen', True)
self.attributes('-topmost', True)
self.block_taskmgr()
self.block_key()
self.frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent')
self.frame.grid(row=0, column=0, sticky='nsew')
self.block_taskmgr()
self.block_key()
lock = Lock()
def exit(self):
@ -65,47 +65,76 @@ class App(customtkinter.CTk):
class Lock(customtkinter.CTkToplevel):
def __init__(self):
super().__init__()
if client_config["testing"] == 1:
self.title(f'{app_name} | PC番号 {client_config["pc_number"]} | テストモード')
else:
self.title(f'{app_name} | PC番号 {client_config["pc_number"]} | ロックされています')
self.geometry('400x200')
self.geometry("600x400")
self.resizable(height=False, width=False)
self.attributes('-topmost', True)
self.grab_set()
self.lift()
self.protocol("WM_DELETE_WINDOW", self.handler_close)
self.title_font = customtkinter.CTkFont(family="meiryo", size=24, weight="bold")
self.general_font = customtkinter.CTkFont(family="meiryo", size=14)
self.emoji_font = customtkinter.CTkFont(family="Segoe UI Emoji", size=32)
self.title_font = customtkinter.CTkFont(family="meiryo", size=32, weight="bold")
self.title_small_font = customtkinter.CTkFont(family="meiryo", size=16)
self.general_font = customtkinter.CTkFont(family="meiryo", size=18)
self.general_small_font = customtkinter.CTkFont(family="meiryo", size=12)
self.textbox_font = customtkinter.CTkFont(family="meiryo", size=14)
self.button_font = customtkinter.CTkFont(family="meiryo", size=14)
self.msg_title_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent')
self.msg_title_frame.grid(row=0, column=0, sticky="nsew")
self.msg_title_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
self.msg_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text='ちょっと待って!!', font=self.title_font, anchor=tkinter.W)
self.msg_title_1.grid(row=0, column=0, padx=10, pady=10)
self.icon_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text='😎', font=self.emoji_font, justify="left")
self.icon_title_1.grid(row=0, column=0, padx=10, sticky="w")
self.msg_title_1 = customtkinter.CTkLabel(self.msg_title_frame, text='ちょっと待って!!', font=self.title_font, justify="left")
self.msg_title_1.grid(row=0, column=1, padx=10, sticky="w")
self.msg_title_2 = customtkinter.CTkLabel(self.msg_title_frame, text="本当にあなたですか?", font=self.title_small_font, justify="left")
self.msg_title_2.grid(row=1, column=1, padx=10, sticky="w")
self.msg_subtitle_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent')
self.msg_subtitle_frame.grid(row=1, column=0, sticky="nsew")
self.msg_subtitle_frame.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
self.msg_subtitle_frame.grid_columnconfigure(0, weight=1)
self.msg_subtitle_1 = customtkinter.CTkLabel(self.msg_subtitle_frame, text='サインインするには、パスワードが必要です。', font=self.general_font, anchor=tkinter.W)
self.msg_subtitle_1.grid(row=0, column=0, padx=10, pady=10)
self.msg_subtitle_1 = customtkinter.CTkLabel(self.msg_subtitle_frame, text='サインインするには、Discordのダイレクトメッセージに送信された\nパスワードを入力してください。', font=self.general_font, justify="left")
self.msg_subtitle_1.grid(row=0, column=0, padx=10, sticky="ew")
self.msg_subtitle_2 = customtkinter.CTkLabel(self.msg_subtitle_frame, text='※ パスワードの有効期限は23:59までです。', font=self.general_small_font, justify="left")
self.msg_subtitle_2.grid(row=1, column=0, padx=10, sticky="w")
self.input_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent')
self.input_frame.grid(row=2, column=0, sticky="nsew")
self.input_frame.grid(row=2, column=0, padx=10, pady=10, sticky="nsew")
self.input_frame.columnconfigure(0, weight=1)
self.password_entry = customtkinter.CTkEntry(self.input_frame, placeholder_text='パスワード', width=380, show='*', font=self.general_small_font)
self.password_entry.grid(row=0, column=0, padx=10, pady=10)
self.password_entry = customtkinter.CTkEntry(self.input_frame, placeholder_text='パスワード', show='*', font=self.textbox_font)
self.password_entry.grid(row=0, column=0, padx=10, sticky="ew")
self.button_frame = customtkinter.CTkFrame(self, corner_radius=0, fg_color='transparent')
self.button_frame.grid(row=3, column=0, sticky="nsew")
self.button_frame.grid(row=3, column=0, padx=10, pady=10, sticky="nsew")
self.button_frame.columnconfigure(0, weight=3)
self.button_frame.columnconfigure(1, weight=1)
self.button_frame.columnconfigure(2, weight=1)
self.signin_button = customtkinter.CTkButton(self.button_frame, text='サインイン', command=self.auth, font=self.general_font)
self.signin_button.grid(row=0, column=1, padx=10, pady=10)
self.signin_button.pack(padx=10, anchor=tkinter.E)
self.signin_button = customtkinter.CTkButton(self.button_frame, text='サインイン', command=self.auth, font=self.button_font)
self.signin_button.grid(row=0, column=2, padx=10, sticky="e")
self.logout_button = customtkinter.CTkButton(self.button_frame, text='サインアウト', command=self.logout, font=self.button_font)
self.logout_button.grid(row=0, column=1, padx=10, sticky="e")
self.signin_button = customtkinter.CTkButton(self.button_frame, text='ヘルプ', command=self.help_wakeup, font=self.button_font)
self.signin_button.grid(row=0, column=0, padx=10, sticky="w")
self.keyboard_listener_thread = threading.Thread(target=self.keyboard_listener)
self.keyboard_listener_thread.daemon = True
self.keyboard_listener_thread.start()
def help_wakeup(self):
help = Help()
def keyboard_listener(self):
keyboard.add_hotkey('ctrl+shift+q', self.exit)
@ -114,6 +143,7 @@ class Lock(customtkinter.CTkToplevel):
return hashed.hexdigest()
def auth(self):
print("認証サーバーにアクセスします。")
auth_url = client_config["auth_host_url"] + "/verify"
auth_json = {
"pc_number": int(client_config["pc_number"]),
@ -121,21 +151,25 @@ class Lock(customtkinter.CTkToplevel):
}
try:
responce = requests.post(auth_url, json=auth_json)
except:
master_password_hash = self.hash_genarate(str(self.password_entry.get()))
if client_config["master_password_hash"] == master_password_hash:
self.exit()
else:
self.msg_subtitle_1.configure(text='サインインするには、パスワードが必要です。\nネットワークエラーが発生しています。\n続行するには、マスターパスワードを入力して下さい。')
if responce.status_code == 200:
print("認証サーバー経由で認証しました。")
self.exit()
else:
except:
print("認証サーバーにアクセスできません。マスターパスワードで認証を試行します。")
master_password_hash = self.hash_genarate(str(self.password_entry.get()))
if client_config["master_password_hash"] == master_password_hash:
print("マスターパスワードで認証しました。")
self.exit()
else:
self.msg_subtitle_1.configure(text='サインインするには、パスワードが必要です。\nパスワードが違います!')
print("マスターパスワードで認証できませんでした。")
self.msg_subtitle_1.configure(text='ネットワークエラーが発生しています。\n続行するには、マスターパスワードを入力して下さい。 ')
def logout(self):
self.destroy()
logout_command = subprocess.run(['shutdown', '/l', '/f'])
print(logout_command)
def handler_close(self):
pass
@ -144,6 +178,27 @@ class Lock(customtkinter.CTkToplevel):
self.destroy()
app.exit()
class Help(customtkinter.CTkToplevel):
def __init__(self):
super().__init__()
if client_config["testing"] == 1:
self.title(f'{app_name} | ヘルプ | テストモード')
else:
self.title(f'{app_name} | ヘルプ')
self.geometry("600x400")
self.resizable(height=False, width=False)
self.attributes('-topmost', True)
self.grab_set()
self.lift()
self.protocol("WM_DELETE_WINDOW", self.handler_close)
def handler_close(self):
self.destroy()
def master_password_gen():
numbers = string.digits # (1)
password = ''.join(random.choice(numbers) for _ in range(10)) # (2)

77
temp/csv_test.py Normal file
View file

@ -0,0 +1,77 @@
import psycopg2
import csv
from psycopg2 import sql
from datetime import datetime
def format_datetime(value):
if isinstance(value, datetime):
return value.strftime('%Y-%m-%d %H:%M:%S')
return value
def export_table_to_csv(host, port, database, user, password, main_table, related_table, related_column, csv_file_path):
try:
# データベースに接続
conn = psycopg2.connect(
host=host,
port=port,
database=database,
user=user,
password=password
)
cur = conn.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("エラーが発生しました:", error)
finally:
if conn:
cur.close()
conn.close()
print("データベース接続を閉じました。")
# 使用例
host = "192.168.1.220"
port = "12245"
database = "dislocker"
user = "suti7"
password = "Testing1234"
main_table = "pc_usage_history"
related_table = "club_member"
related_column = "name" # 例: 登録者の名前を表示したい場合
csv_file_path = "output.csv"
export_table_to_csv(host, port, database, user, password, main_table, related_table, related_column, csv_file_path)

97
temp/xcel.py Normal file
View file

@ -0,0 +1,97 @@
import psycopg2
import csv
from psycopg2 import sql
from datetime import datetime
from openpyxl import Workbook
from openpyxl.utils import get_column_letter
def format_datetime(value):
if isinstance(value, datetime):
return value.strftime('%Y-%m-%d %H:%M:%S')
return value
def export_table_to_excel(host, port, database, user, password, main_table, related_table, excel_file_path):
try:
conn = psycopg2.connect(
host=host,
port=port,
database=database,
user=user,
password=password
)
cur = conn.cursor()
# メインテーブルの列情報を取得member_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()
# Excelワークブックを作成
wb = Workbook()
ws = wb.active
# 列名を書き込み
ws.append(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]]
ws.append(formatted_row)
# 列幅を自動調整
for col in ws.columns:
max_length = 0
column = col[0].column_letter
for cell in col:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = (max_length + 2) * 1.2
ws.column_dimensions[column].width = adjusted_width
# Excelファイルを保存
wb.save(excel_file_path)
print(f"テーブル '{main_table}' の内容を '{excel_file_path}' に出力しました。")
except (Exception, psycopg2.Error) as error:
print("エラーが発生しました:", error)
finally:
if conn:
cur.close()
conn.close()
print("データベース接続を閉じました。")
# 使用例
host = "192.168.1.220"
port = "12245"
database = "dislocker"
user = "suti7"
password = "Testing1234"
main_table = "pc_usage_history"
related_table = "club_member"
excel_file_path = "output.xlsx"
export_table_to_excel(host, port, database, user, password, main_table, related_table, excel_file_path)