From 765f3a15a08088dbce6adef008dbaa8d46453224 Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Fri, 7 Nov 2025 01:01:37 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E7=BD=AE=E6=95=B0=E6=8D=AE=E5=AD=98?= =?UTF-8?q?=E8=B4=AE=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PWF | 2 +- Plugins/WPSDailyAPI.py | 197 ++++++++++++++++------------------------- 2 files changed, 77 insertions(+), 122 deletions(-) diff --git a/PWF b/PWF index 14ce7e6..a1b3f51 160000 --- a/PWF +++ b/PWF @@ -1 +1 @@ -Subproject commit 14ce7e6e3f29238f8bc56931eb70ddb52a44c909 +Subproject commit a1b3f51b613c45330cf940c22541191b1e88af16 diff --git a/Plugins/WPSDailyAPI.py b/Plugins/WPSDailyAPI.py index 7dd736f..74c6d38 100644 --- a/Plugins/WPSDailyAPI.py +++ b/Plugins/WPSDailyAPI.py @@ -1,39 +1,17 @@ from __future__ import annotations -import asyncio -import time - -from pydantic import BaseModel, Field from PWF.Convention.Runtime.Config import * from PWF.Convention.Runtime.Architecture import Architecture -from PWF.Convention.Runtime.File import ToolFile from PWF.Convention.Runtime.GlobalConfig import ProjectConfig +from PWF.CoreModules.plugin_interface import DatabaseModel, get_db + from .WPSAPI import WPSAPI config = ProjectConfig() -class UserConfigEntry(BaseModel): - chat_id: int - user_id: int - data: Dict[str, Any] = Field(default_factory=dict) - updated_at: int = Field(default_factory=lambda: int(time.time())) - - -class UserConfigStore(BaseModel): - entries: List[UserConfigEntry] = Field(default_factory=list) - - class WPSConfigAPI(WPSAPI): - def __init__(self) -> None: - super().__init__() - self._lock = asyncio.Lock() - self._store = UserConfigStore() - self._entries: Dict[Tuple[int, int], UserConfigEntry] = {} - self._setting = self._build_setting() - self._load_store() - @override def dependencies(self) -> List[Type]: return [WPSAPI] @@ -42,12 +20,17 @@ class WPSConfigAPI(WPSAPI): def is_enable_plugin(self) -> bool: return True - def _build_setting(self) -> ToolFile: - data_file: ToolFile = config.GetFile("user_configs.json", False) - data_file.TryCreateParentPath() - if data_file.Exists() == False: - data_file.SaveAsJson(self._store) - return data_file + @override + def register_db_model(self) -> DatabaseModel: + return DatabaseModel( + table_name="user_info", + column_defs={ + "user_id": "INTEGER", + "username": "TEXT DEFAULT ''", + "userurl": "TEXT DEFAULT ''", + "userpoint": "INTEGER DEFAULT 0" + } + ) @override def wake_up(self) -> None: @@ -68,15 +51,7 @@ class WPSConfigAPI(WPSAPI): if action == "get" and len(tokens) >= 2: key = tokens[1].lower() return await self._handle_get(chat_id, user_id, key) - # if action in {"adjust", "add", "sub"} and len(tokens) >= 3: - # key = tokens[1].lower() - # delta_token = tokens[2] - # reason = " ".join(tokens[3:]).strip() if len(tokens) > 3 else "" - # signed_delta = self._parse_delta(action, delta_token) - # if signed_delta is None: - # return "❌ 积分变更失败: delta 需要是整数" - # return await self._handle_adjust(chat_id, user_id, key, signed_delta, reason) - + return self._help_message() @override @@ -115,28 +90,22 @@ class WPSConfigAPI(WPSAPI): await self._set_value(chat_id, user_id, key, value) return "✅ 已更新个人URL" - # if key == "user.point": - # try: - # # points = int(value) - # return "❌ 无权限设置积分" - # except ValueError: - # return "❌ 积分必须是整数" - # await self._set_value(chat_id, user_id, key, points) - # return f"✅ 已将积分设置为 {points}" - - # return "❌ 未识别的配置键,请使用 user.name / user.url / user.point" return "❌ 未识别的配置键,请使用 user.name / user.url" async def _handle_get(self, chat_id: int, user_id: int, key: str) -> str: - entry = self._get_entry(chat_id, user_id, create=False) - if entry is None or key not in entry.data: - if key == "user.point": - return "当前积分: 0" - return f"⚠️ 尚未设置 {key}" - - value = entry.data.get(key) + record = self._get_user_record(user_id) if key == "user.point": - return f"当前积分: {int(value)}" + points = record.get("userpoint") if record else 0 + return f"当前积分: {self._coerce_int(points)}" + if key == "user.name": + value = record.get("username") if record else None + elif key == "user.url": + value = record.get("userurl") if record else None + else: + return "❌ 未识别的配置键,请使用 user.name / user.url" + + if value is None or value == "": + return f"⚠️ 尚未设置 {key}" return f"当前 {key} = {value}" async def _handle_adjust(self, chat_id: int, user_id: int, key: str, delta: int, reason: str) -> str: @@ -149,66 +118,51 @@ class WPSConfigAPI(WPSAPI): return f"✅ {detail},当前积分: {new_value}" async def _set_value(self, chat_id: int, user_id: int, key: str, value: Any) -> None: - entry = self._get_entry(chat_id, user_id, create=True) - entry.data[key] = value - entry.updated_at = int(time.time()) - await self._save_store() + if key == "user.name": + self._update_user_field(user_id, "username", value) + elif key == "user.url": + self._update_user_field(user_id, "userurl", value) async def _adjust_points(self, chat_id: int, user_id: int, delta: int, reason: str) -> int: - entry = self._get_entry(chat_id, user_id, create=True) - current = self._coerce_int(entry.data.get("user.point", 0)) - new_value = current + delta - entry.data["user.point"] = new_value - history: List[Dict[str, Any]] = entry.data.setdefault("user.point_history", []) # type: ignore[assignment] - history.append({ - "delta": delta, - "reason": reason, - "timestamp": int(time.time()), - }) - if len(history) > 100: - entry.data["user.point_history"] = history[-100:] - entry.updated_at = int(time.time()) - await self._save_store() - return new_value + return self._adjust_db_points(user_id, delta) - def _get_entry(self, chat_id: int, user_id: int, create: bool) -> Optional[UserConfigEntry]: - key = (chat_id, user_id) - if key in self._entries: - return self._entries[key] - if not create: - return None - entry = UserConfigEntry(chat_id=chat_id, user_id=user_id) - self._entries[key] = entry - self._store.entries.append(entry) - return entry + def _get_user_record(self, user_id: int) -> Optional[Dict[str, Any]]: + cursor = self._db.conn.cursor() + cursor.execute( + "SELECT user_id, username, userurl, userpoint FROM user_info WHERE user_id = ?", + (user_id,) + ) + row = cursor.fetchone() + return dict(row) if row else None - def _ignore_lock_save_store(self) -> None: - self._store.entries = list(self._entries.values()) - try: - #EasySave.Write(self._store, setting=self._setting) - self._setting.SaveAsJson(self._store.model_dump()) - except Exception as exc: - config.Log("Error", f"ConfigPlugin 保存失败: {exc}") - raise + def _ensure_user_row(self, user_id: int) -> None: + cursor = self._db.conn.cursor() + cursor.execute( + "INSERT INTO user_info (user_id) VALUES (?) ON CONFLICT(user_id) DO NOTHING", + (user_id,) + ) - async def _save_store(self) -> None: - async with self._lock: - self._ignore_lock_save_store() + def _update_user_field(self, user_id: int, column: str, value: Any) -> None: + self._ensure_user_row(user_id) + cursor = self._db.conn.cursor() + cursor.execute( + f""" + INSERT INTO user_info (user_id, {column}) VALUES (?, ?) + ON CONFLICT(user_id) DO UPDATE SET {column} = excluded.{column} + """, + (user_id, value) + ) - def _load_store(self) -> None: - try: - store = UserConfigStore.model_validate(self._setting.LoadAsJson()) - self._store = store or UserConfigStore() - except FileNotFoundError: - self._store = UserConfigStore() - except Exception as exc: - config.Log("Error", f"{traceback.format_exc()}") - self._store = UserConfigStore() - - self._entries = { - (entry.chat_id, entry.user_id): entry - for entry in self._store.entries - } + def _adjust_db_points(self, user_id: int, delta: int) -> int: + self._ensure_user_row(user_id) + cursor = self._db.conn.cursor() + cursor.execute( + "UPDATE user_info SET userpoint = COALESCE(userpoint, 0) + ? WHERE user_id = ?", + (delta, user_id) + ) + cursor.execute("SELECT userpoint FROM user_info WHERE user_id = ?", (user_id,)) + row = cursor.fetchone() + return self._coerce_int(row[0] if row else 0) def _coerce_int(self, value: Any) -> int: try: @@ -217,23 +171,24 @@ class WPSConfigAPI(WPSAPI): return 0 def get_user_name(self, chat_id: int, user_id: int) -> Optional[str]: - entry = self._entries.get((chat_id, user_id)) - if not entry: + record = self._get_user_record(user_id) + if not record: return f"user_{user_id}" - return str(entry.data.get("user.name", f"user_{user_id}")) + value = record.get("username") + return str(value) if value else f"user_{user_id}" def get_user_url(self, chat_id: int, user_id: int) -> Optional[str]: - entry = self._entries.get((chat_id, user_id)) - if not entry: + record = self._get_user_record(user_id) + if not record: return None - value = entry.data.get("user.url") - return str(value) if value is not None else None + value = record.get("userurl") + return str(value) if value else None def get_user_points(self, chat_id: int, user_id: int) -> int: - entry = self._entries.get((chat_id, user_id)) - if not entry: + record = self._get_user_record(user_id) + if not record: return 0 - return self._coerce_int(entry.data.get("user.point", 0)) + return self._coerce_int(record.get("userpoint", 0)) async def adjust_user_points(self, chat_id: int, user_id: int, delta: int, reason: str = "") -> int: return await self._adjust_points(chat_id, user_id, delta, reason)