From 631127377acf79109f2b3269f925536fd8135626 Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Fri, 19 Jul 2024 12:08:40 -0400 Subject: [PATCH] =?UTF-8?q?dev:=20=E6=B7=BB=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/config_utils.py | 73 +++++++++++++++++++++++++++++++++++++++++++ lib/global_config.py | 4 --- lib/kps_operations.py | 8 ++--- main.py | 9 +++++- src/mw_kps_unifier.py | 43 +++++++++---------------- src/page_load.py | 15 +++++---- src/page_query.py | 19 +++++------ 7 files changed, 117 insertions(+), 54 deletions(-) create mode 100644 lib/config_utils.py delete mode 100644 lib/global_config.py diff --git a/lib/config_utils.py b/lib/config_utils.py new file mode 100644 index 0000000..e17a45d --- /dev/null +++ b/lib/config_utils.py @@ -0,0 +1,73 @@ +# coding: utf8 +import os +import sys +import json +from pathlib import Path + + +def path_not_exist(path: str | Path) -> bool: + """ + 判断目标路径是否存在 + 如果参数为空或者 None,亦认为不存在 + + :param path: 目标路径 + :return: + """ + if isinstance(path, str): + return len(path) == 0 or not Path(path).exists() + elif isinstance(path, Path): + return not path.exists() + else: + return True + + +def get_data_dir() -> str: + plat = sys.platform + if plat == "win32": + data_dir = os.path.expandvars("%appdata%") + elif plat == "darwin": + data_dir = os.path.expanduser("~/Library/Application Support") + else: + raise OSError("Unsupported platform") + return data_dir + + +def get_app_dir(org_name: str, app_name: str) -> Path: + data_dir = get_data_dir() + app_dir = Path(data_dir, org_name, app_name) + if not app_dir.exists(): + app_dir.mkdir(parents=True, exist_ok=True) + + return app_dir + + +def get_config_path(org_name: str, app_name: str) -> Path: + data_dir = get_app_dir(org_name, app_name) + return Path(data_dir, "config.json") + + +def read_config(org_name: str, app_name: str) -> dict: + config_path = get_config_path(org_name, app_name) + if not config_path.exists(): + config = { + "table_name": "entries", + "button_min_width": 120, + "last_db_path": "", + "loaded_memory": {} + } + config_path.write_text(json.dumps(config, ensure_ascii=False, indent=4), encoding="utf-8") + return config + else: + return json.loads(config_path.read_text(encoding="utf-8")) + + +def write_config(config: dict, org_name: str, app_name: str): + config_path = get_config_path(org_name, app_name) + config_path.write_text(json.dumps(config, ensure_ascii=False, indent=4), encoding="utf-8") + + +def get_default_db_path(config: dict, org_name: str, app_name: str) -> str: + if path_not_exist(config["last_db_path"]): + app_dir = get_app_dir(org_name, app_name) + return str(app_dir / f"default.db") + return config["last_db_path"] diff --git a/lib/global_config.py b/lib/global_config.py deleted file mode 100644 index 091b645..0000000 --- a/lib/global_config.py +++ /dev/null @@ -1,4 +0,0 @@ -# coding: utf8 - -table_name = "entries" -button_min_width = 120 diff --git a/lib/kps_operations.py b/lib/kps_operations.py index 9acc253..65a5ca3 100644 --- a/lib/kps_operations.py +++ b/lib/kps_operations.py @@ -1,8 +1,8 @@ # coding: utf8 from os import PathLike from pykeepass import PyKeePass -from .Sqlite3Helper import Sqlite3Worker, BlobType, Column -from .global_config import table_name +from lib.db_columns_def import all_columns +from .Sqlite3Helper import Sqlite3Worker, BlobType def trim_str(value): @@ -28,7 +28,7 @@ def blob_fy(value: str) -> BlobType: def read_kps_to_db(kps_file: str | PathLike[str], password: str, - columns: list[Column], sqh: Sqlite3Worker) -> PyKeePass: + table_name: str, sqh: Sqlite3Worker) -> PyKeePass: kp = PyKeePass(kps_file, password=password) values = [] @@ -44,5 +44,5 @@ def read_kps_to_db(kps_file: str | PathLike[str], password: str, blob_fy("::".join([kps_file] + entry.path[:-1])), ]) - sqh.insert_into(table_name, columns, values) + sqh.insert_into(table_name, all_columns[1:], values) return kp diff --git a/main.py b/main.py index 3ffc869..131a553 100644 --- a/main.py +++ b/main.py @@ -3,9 +3,13 @@ import sys from PySide6.QtWidgets import QApplication +from lib.config_utils import get_default_db_path, read_config from src.mw_kps_unifier import KpsUnifier import src.rc_kps_unifier +__version__ = '0.1.0' +__version_info__ = tuple(map(int, __version__.split('.'))) + ORG_NAME = "JnPrograms" APP_NAME = "KpsUnifier" @@ -15,7 +19,10 @@ def main(): app.setOrganizationName(ORG_NAME) app.setApplicationName(APP_NAME) - win = KpsUnifier() + config = read_config(ORG_NAME, APP_NAME) + db_path = get_default_db_path(config, ORG_NAME, APP_NAME) + + win = KpsUnifier(db_path, config) win.show() return app.exec() diff --git a/src/mw_kps_unifier.py b/src/mw_kps_unifier.py index 4658ab7..2cf05b9 100644 --- a/src/mw_kps_unifier.py +++ b/src/mw_kps_unifier.py @@ -1,7 +1,4 @@ # coding: utf8 -import os -import sys -from pathlib import Path from PySide6 import QtWidgets, QtCore, QtGui from .page_load import PageLoad @@ -9,28 +6,11 @@ from .page_query import PageQuery from .cmbx_styles import StyleComboBox from lib.Sqlite3Helper import Sqlite3Worker from lib.db_columns_def import all_columns -from lib.global_config import table_name - - -def get_default_db_path() -> str: - plat = sys.platform - if plat == "win32": - data_dir = os.path.expandvars("%appdata%") - elif plat == "darwin": - data_dir = os.path.expanduser("~/Library/Application Support") - else: - raise OSError("Unsupported platform") - app_dir = Path(data_dir, - QtWidgets.QApplication.organizationName(), - QtWidgets.QApplication.applicationName()) - if not app_dir.exists(): - app_dir.mkdir(parents=True, exist_ok=True) - - return str(app_dir / f"default.db") +from lib.config_utils import write_config class UiKpsUnifier(object): - def __init__(self, default_db_path: str, sqh: Sqlite3Worker, window: QtWidgets.QMainWindow): + def __init__(self, default_db_path: str, config: dict, sqh: Sqlite3Worker, window: QtWidgets.QMainWindow): window.setWindowTitle('KeePassXC 多合一') self.cw = QtWidgets.QWidget(window) self.vly_m = QtWidgets.QVBoxLayout() @@ -61,9 +41,9 @@ class UiKpsUnifier(object): self.sw_m = QtWidgets.QStackedWidget(self.cw) self.vly_m.addWidget(self.sw_m) - self.page_load = PageLoad(sqh, self.cw) + self.page_load = PageLoad(sqh, config, self.cw) self.sw_m.addWidget(self.page_load) - self.page_query = PageQuery(sqh, self.cw) + self.page_query = PageQuery(sqh, config, self.cw) self.sw_m.addWidget(self.page_query) def update_sqh(self, sqh: Sqlite3Worker): @@ -72,24 +52,31 @@ class UiKpsUnifier(object): class KpsUnifier(QtWidgets.QMainWindow): - def __init__(self, parent=None): + def __init__(self, db_path: str, config: dict, parent=None): super().__init__(parent) - self.db_path = get_default_db_path() + self.db_path = db_path + self.config = config self.sqh = self.init_db() - self.ui = UiKpsUnifier(self.db_path, self.sqh, self) + self.ui = UiKpsUnifier(self.db_path, self.config, self.sqh, self) self.ui.act_new.triggered.connect(self.on_act_new_triggered) self.ui.act_open.triggered.connect(self.on_act_open_triggered) self.ui.act_load.triggered.connect(self.on_act_load_triggered) self.ui.act_query.triggered.connect(self.on_act_query_triggered) + def __del__(self): + self.config["last_db_path"] = self.db_path + write_config(self.config, + QtWidgets.QApplication.organizationName(), + QtWidgets.QApplication.applicationName()) + def sizeHint(self): return QtCore.QSize(860, 640) def init_db(self) -> Sqlite3Worker: sqh = Sqlite3Worker(self.db_path) - sqh.create_table(table_name, all_columns, if_not_exists=True) + sqh.create_table(self.config["table_name"], all_columns, if_not_exists=True) return sqh def update_db(self, filename: str): diff --git a/src/page_load.py b/src/page_load.py index 86bf31c..669d05b 100644 --- a/src/page_load.py +++ b/src/page_load.py @@ -4,15 +4,14 @@ from pykeepass.exceptions import CredentialsError from .gbx_kps_login import GbxKpsLogin from lib.Sqlite3Helper import Sqlite3Worker -from lib.db_columns_def import all_columns from lib.kps_operations import read_kps_to_db -from lib.global_config import button_min_width class WgLoadKps(QtWidgets.QWidget): - def __init__(self, sqh: Sqlite3Worker, parent=None): + def __init__(self, sqh: Sqlite3Worker, config: dict, parent=None): super().__init__(parent) self.sqh = sqh + self.config = config self.kps_wgs: list[GbxKpsLogin] = [] self.vly_m = QtWidgets.QVBoxLayout() @@ -36,7 +35,7 @@ class WgLoadKps(QtWidgets.QWidget): try: read_kps_to_db(kps_file=item.lne_path.text(), password=item.lne_password.text(), - columns=all_columns[1:], + table_name=self.config["table_name"], sqh=self.sqh) except CredentialsError: QtWidgets.QMessageBox.critical(self, "密码错误", @@ -52,7 +51,7 @@ class WgLoadKps(QtWidgets.QWidget): class PageLoad(QtWidgets.QWidget): - def __init__(self, sqh: Sqlite3Worker, parent=None): + def __init__(self, sqh: Sqlite3Worker, config: dict, parent=None): super().__init__(parent) self.hly_m = QtWidgets.QHBoxLayout() self.setLayout(self.hly_m) @@ -60,10 +59,10 @@ class PageLoad(QtWidgets.QWidget): self.hly_m.addLayout(self.vly_left) self.pbn_add = QtWidgets.QPushButton("添加", self) - self.pbn_add.setMinimumWidth(button_min_width) + self.pbn_add.setMinimumWidth(config["button_min_width"]) self.vly_left.addWidget(self.pbn_add) self.pbn_load_all = QtWidgets.QPushButton("加载全部", self) - self.pbn_load_all.setMinimumWidth(button_min_width) + self.pbn_load_all.setMinimumWidth(config["button_min_width"]) self.pbn_load_all.setDisabled(True) self.vly_left.addWidget(self.pbn_load_all) self.vly_left.addStretch(1) @@ -71,7 +70,7 @@ class PageLoad(QtWidgets.QWidget): self.sa_m = QtWidgets.QScrollArea(self) self.sa_m.setWidgetResizable(True) self.hly_m.addWidget(self.sa_m) - self.wg_sa = WgLoadKps(sqh, self.sa_m) + self.wg_sa = WgLoadKps(sqh, config, self.sa_m) self.sa_m.setWidget(self.wg_sa) self.pbn_add.clicked.connect(self.on_pbn_add_clicked) diff --git a/src/page_query.py b/src/page_query.py index cccafc5..78f28cf 100644 --- a/src/page_query.py +++ b/src/page_query.py @@ -1,10 +1,9 @@ # coding: utf8 import json -from PySide6 import QtWidgets, QtCore, QtGui -from lib.Sqlite3Helper import Sqlite3Worker, Operand, Expression +from PySide6 import QtWidgets, QtCore +from lib.Sqlite3Helper import Sqlite3Worker, Expression from lib.db_columns_def import query_columns -from lib.global_config import button_min_width, table_name class QueryTableModel(QtCore.QAbstractTableModel): @@ -34,9 +33,10 @@ class QueryTableModel(QtCore.QAbstractTableModel): class PageQuery(QtWidgets.QWidget): - def __init__(self, sqh: Sqlite3Worker, parent=None): + def __init__(self, sqh: Sqlite3Worker, config: dict, parent=None): super().__init__(parent) self.sqh = sqh + self.config = config self.hly_m = QtWidgets.QHBoxLayout() self.setLayout(self.hly_m) @@ -53,13 +53,13 @@ class PageQuery(QtWidgets.QWidget): self.sa_left.setWidget(self.sa_wg) self.pbn_all = QtWidgets.QPushButton("全部", self.sa_wg) - self.pbn_all.setMinimumWidth(button_min_width) + self.pbn_all.setMinimumWidth(config["button_min_width"]) self.vly_sa_wg.addWidget(self.pbn_all) self.vly_sa_wg.addStretch(1) self.pbn_read_filters = QtWidgets.QPushButton("更多过滤", self) - self.pbn_read_filters.setMinimumWidth(button_min_width) + self.pbn_read_filters.setMinimumWidth(config["button_min_width"]) self.vly_sa_wg.addWidget(self.pbn_read_filters) self.trv_m = QtWidgets.QTreeView(self) @@ -91,7 +91,7 @@ class PageQuery(QtWidgets.QWidget): def set_filter_button(self, fil: dict): pbn_fil = PushButtonWithData(fil, self.sa_wg, fil["name"]) - pbn_fil.setMinimumWidth(button_min_width) + pbn_fil.setMinimumWidth(self.config["button_min_width"]) self.vly_sa_wg.insertWidget(self.vly_sa_wg.count() - 2, pbn_fil) pbn_fil.clicked_with_data.connect(self.on_custom_filters_clicked_with_data) @@ -107,7 +107,8 @@ class PageQuery(QtWidgets.QWidget): self.set_filter_button(fil) def on_custom_filters_clicked_with_data(self, data: dict): - _, results = self.sqh.select(table_name, query_columns, where=Expression(data["where"])) + _, results = self.sqh.select(self.config["table_name"], query_columns, + where=Expression(data["where"])) model = QueryTableModel(results, self) self.trv_m.setModel(model) @@ -115,7 +116,7 @@ class PageQuery(QtWidgets.QWidget): self.sqh = sqh def on_pbn_all_clicked(self): - _, results = self.sqh.select(table_name, query_columns) + _, results = self.sqh.select(self.config["table_name"], query_columns) model = QueryTableModel(results, self) self.trv_m.setModel(model)