From 666d6eb048c4853433b17edf9a8658da3bc55cea Mon Sep 17 00:00:00 2001 From: Allen Date: Thu, 18 Apr 2024 12:33:35 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9B=B8=E5=85=B3=E8=83=BD=E5=8A=9B=E5=92=8C?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/endpoints/user.py | 23 +++++++- app/db/models/__init__.py | 1 + app/db/models/userconfig.py | 38 ++++++++++++++ app/db/userconfig_oper.py | 102 ++++++++++++++++++++++++++++++++++++ app/schemas/types.py | 6 +++ 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 app/db/models/userconfig.py create mode 100644 app/db/userconfig_oper.py diff --git a/app/api/endpoints/user.py b/app/api/endpoints/user.py index 85ae3036..0bce3875 100644 --- a/app/api/endpoints/user.py +++ b/app/api/endpoints/user.py @@ -1,6 +1,6 @@ import base64 import re -from typing import Any, List +from typing import Any, List, Union from fastapi import APIRouter, Depends, HTTPException, UploadFile, File from sqlalchemy.orm import Session @@ -10,6 +10,7 @@ from app.core.security import get_password_hash from app.db import get_db from app.db.models.user import User from app.db.userauth import get_current_active_superuser, get_current_active_user +from app.db.userconfig_oper import UserConfigOper from app.utils.otp import OtpUtils router = APIRouter() @@ -182,3 +183,23 @@ def read_user_by_id( detail="用户权限不足" ) return user + +@router.get("/config/{key}", summary="查询用户配置", response_model=schemas.Response) +def get_config(key: str, + current_user: User = Depends(get_current_active_user)): + """ + 查询用户配置 + """ + value = UserConfigOper().get(current_user.id, key) + return schemas.Response(success=True, data={ + "value": value + }) + +@router.post("/config/{key}", summary="更新用户配置", response_model=schemas.Response) +def set_config(key: str, value: Union[list, dict, bool, int, str] = None, + current_user: User = Depends(get_current_active_user)): + """ + 更新用户配置 + """ + UserConfigOper().set(current_user.id, key, value) + return schemas.Response(success=True) diff --git a/app/db/models/__init__.py b/app/db/models/__init__.py index 57ddee03..661f1107 100644 --- a/app/db/models/__init__.py +++ b/app/db/models/__init__.py @@ -7,3 +7,4 @@ from .subscribe import Subscribe from .systemconfig import SystemConfig from .transferhistory import TransferHistory from .user import User +from .userconfig import UserConfig \ No newline at end of file diff --git a/app/db/models/userconfig.py b/app/db/models/userconfig.py new file mode 100644 index 00000000..d90b04c6 --- /dev/null +++ b/app/db/models/userconfig.py @@ -0,0 +1,38 @@ +from sqlalchemy import Column, Integer, String, Sequence, UniqueConstraint, Index +from sqlalchemy.orm import Session + +from app.db import db_query, db_update, Base + + +class UserConfig(Base): + """ + 用户配置表 + """ + id = Column(Integer, Sequence('id'), primary_key=True, index=True) + # 用户ID + user_id = Column(Integer, index=True) + # 配置键 + key = Column(String) + # 值 + value = Column(String, nullable=True) + + __table_args__ = ( + # 用户ID和配置键联合唯一 + UniqueConstraint('user_id', 'key'), + Index('ix_userconfig_userid_key', 'user_id', 'key'), + ) + + @staticmethod + @db_query + def get_by_key(db: Session, user_id: int, key: str): + return db.query(UserConfig) \ + .filter(UserConfig.user_id == user_id) \ + .filter(UserConfig.key == key) \ + .first() + + @db_update + def delete_by_key(self, db: Session, user_id: int, key: str): + userconfig = self.get_by_key(db, user_id, key) + if userconfig: + userconfig.delete(db, userconfig.id) + return True diff --git a/app/db/userconfig_oper.py b/app/db/userconfig_oper.py new file mode 100644 index 00000000..854665a8 --- /dev/null +++ b/app/db/userconfig_oper.py @@ -0,0 +1,102 @@ +import json +from typing import Any, Union, Dict + +from app.db import DbOper +from app.db.models.userconfig import UserConfig +from app.schemas.types import UserConfigKey +from app.utils.object import ObjectUtils +from app.utils.singleton import Singleton + + +class UserConfigOper(DbOper, metaclass=Singleton): + # 配置缓存 + __USERCONF: Dict[int, Dict[str, Any]] = {} + + def __init__(self): + """ + 加载配置到内存 + """ + super().__init__() + for item in UserConfig.list(self._db): + self.__set_config_cache(user_id=item.user_id, key=item.key, value=item.value) + + def set(self, user_id: int, key: Union[str, UserConfigKey], value: Any): + """ + 设置用户配置 + """ + if isinstance(key, UserConfigKey): + key = key.value + # 更新内存 + self.__set_config_cache(user_id=user_id, key=key, value=value) + # 写入数据库 + if ObjectUtils.is_obj(value): + value = json.dumps(value) + elif value is None: + value = '' + conf = UserConfig.get_by_key(self._db, user_id, key) + if conf: + if value: + conf.update(self._db, {"value": value}) + else: + conf.delete(self._db, conf.id) + else: + conf = UserConfig(user_id=user_id, key=key, value=value) + conf.create(self._db) + + def get(self, user_id: int, key: Union[str, UserConfigKey] = None) -> Any: + """ + 获取用户配置 + """ + if not user_id: + return self.__USERCONF + if isinstance(key, UserConfigKey): + key = key.value + if not key: + return self.__get_config_caches(user_id=user_id) + return self.__get_config_cache(user_id=user_id, key=key) + + def __del__(self): + if self._db: + self._db.close() + + def __set_config_cache(self, user_id: int, key: str, value: Any): + """ + 设置配置缓存 + """ + if not user_id or not key: + return + cache = self.__USERCONF + if not cache: + cache = {} + user_cache = cache.get(user_id) + if not user_cache: + user_cache = {} + cache[user_id] = user_cache + if ObjectUtils.is_obj(value): + user_cache[key] = json.loads(value) + else: + user_cache[key] = value + self.__USERCONF = cache + + def __get_config_caches(self, user_id: int) -> Dict[str, Any]: + """ + 获取配置缓存 + """ + if not user_id: + return None + if not self.__USERCONF: + return None + return self.__USERCONF.get(user_id) + + def __get_config_cache(self, user_id: int, key: str) -> Any: + """ + 获取配置缓存 + """ + if not user_id or not key: + return None + if not self.__USERCONF: + return None + user_cache = self.__USERCONF.get(user_id) + if not user_cache: + return None + return user_cache.get(key) diff --git a/app/schemas/types.py b/app/schemas/types.py index cc28bf67..242bd087 100644 --- a/app/schemas/types.py +++ b/app/schemas/types.py @@ -124,3 +124,9 @@ class MessageChannel(Enum): SynologyChat = "SynologyChat" VoceChat = "VoceChat" Web = "Web" + + +# 用户配置Key字典 +class UserConfigKey(Enum): + # 监控面板 + Dashboard = "Dashboard" From ae60040120f3b19750fd4d83b76c4595612387bf Mon Sep 17 00:00:00 2001 From: Allen Date: Thu, 18 Apr 2024 15:19:46 +0800 Subject: [PATCH 2/3] fixbug --- app/db/userconfig_oper.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/db/userconfig_oper.py b/app/db/userconfig_oper.py index 854665a8..d6ff7ed2 100644 --- a/app/db/userconfig_oper.py +++ b/app/db/userconfig_oper.py @@ -18,7 +18,10 @@ class UserConfigOper(DbOper, metaclass=Singleton): """ super().__init__() for item in UserConfig.list(self._db): - self.__set_config_cache(user_id=item.user_id, key=item.key, value=item.value) + if ObjectUtils.is_obj(item.value): + self.__set_config_cache(user_id=item.user_id, key=item.key, value=json.loads(item.value)) + else: + self.__set_config_cache(user_id=item.user_id, key=item.key, value=item.value) def set(self, user_id: int, key: Union[str, UserConfigKey], value: Any): """ @@ -72,10 +75,7 @@ class UserConfigOper(DbOper, metaclass=Singleton): if not user_cache: user_cache = {} cache[user_id] = user_cache - if ObjectUtils.is_obj(value): - user_cache[key] = json.loads(value) - else: - user_cache[key] = value + user_cache[key] = value self.__USERCONF = cache def __get_config_caches(self, user_id: int) -> Dict[str, Any]: From d6c6c999fcf17e940cf13f8c032c1214098af877 Mon Sep 17 00:00:00 2001 From: Allen Date: Tue, 23 Apr 2024 09:51:18 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=BA=A7=E9=85=8D=E7=BD=AE=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/endpoints/user.py | 4 +-- app/db/models/userconfig.py | 20 ++++++------- app/db/userconfig_oper.py | 56 +++++++++++++++++-------------------- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/app/api/endpoints/user.py b/app/api/endpoints/user.py index 0bce3875..580ce16e 100644 --- a/app/api/endpoints/user.py +++ b/app/api/endpoints/user.py @@ -190,7 +190,7 @@ def get_config(key: str, """ 查询用户配置 """ - value = UserConfigOper().get(current_user.id, key) + value = UserConfigOper().get(username=current_user.name, key=key) return schemas.Response(success=True, data={ "value": value }) @@ -201,5 +201,5 @@ def set_config(key: str, value: Union[list, dict, bool, int, str] = None, """ 更新用户配置 """ - UserConfigOper().set(current_user.id, key, value) + UserConfigOper().set(username=current_user.name, key=key, value=value) return schemas.Response(success=True) diff --git a/app/db/models/userconfig.py b/app/db/models/userconfig.py index d90b04c6..fce73578 100644 --- a/app/db/models/userconfig.py +++ b/app/db/models/userconfig.py @@ -9,30 +9,30 @@ class UserConfig(Base): 用户配置表 """ id = Column(Integer, Sequence('id'), primary_key=True, index=True) - # 用户ID - user_id = Column(Integer, index=True) + # 用户名 + username = Column(String, index=True) # 配置键 key = Column(String) # 值 value = Column(String, nullable=True) __table_args__ = ( - # 用户ID和配置键联合唯一 - UniqueConstraint('user_id', 'key'), - Index('ix_userconfig_userid_key', 'user_id', 'key'), + # 用户名和配置键联合唯一 + UniqueConstraint('username', 'key'), + Index('ix_userconfig_username_key', 'username', 'key'), ) @staticmethod @db_query - def get_by_key(db: Session, user_id: int, key: str): + def get_by_key(db: Session, username: str, key: str): return db.query(UserConfig) \ - .filter(UserConfig.user_id == user_id) \ + .filter(UserConfig.username == username) \ .filter(UserConfig.key == key) \ .first() @db_update - def delete_by_key(self, db: Session, user_id: int, key: str): - userconfig = self.get_by_key(db, user_id, key) + def delete_by_key(self, db: Session, username: str, key: str): + userconfig = self.get_by_key(db=db, username=username, key=key) if userconfig: - userconfig.delete(db, userconfig.id) + userconfig.delete(db=db, rid=userconfig.id) return True diff --git a/app/db/userconfig_oper.py b/app/db/userconfig_oper.py index d6ff7ed2..d8c614f1 100644 --- a/app/db/userconfig_oper.py +++ b/app/db/userconfig_oper.py @@ -10,7 +10,7 @@ from app.utils.singleton import Singleton class UserConfigOper(DbOper, metaclass=Singleton): # 配置缓存 - __USERCONF: Dict[int, Dict[str, Any]] = {} + __USERCONF: Dict[str, Dict[str, Any]] = {} def __init__(self): """ @@ -18,85 +18,79 @@ class UserConfigOper(DbOper, metaclass=Singleton): """ super().__init__() for item in UserConfig.list(self._db): - if ObjectUtils.is_obj(item.value): - self.__set_config_cache(user_id=item.user_id, key=item.key, value=json.loads(item.value)) - else: - self.__set_config_cache(user_id=item.user_id, key=item.key, value=item.value) + value = json.loads(item.value) if ObjectUtils.is_obj(item.value) else item.value + self.__set_config_cache(username=item.username, key=item.key, value=value) - def set(self, user_id: int, key: Union[str, UserConfigKey], value: Any): + def set(self, username: str, key: Union[str, UserConfigKey], value: Any): """ 设置用户配置 """ if isinstance(key, UserConfigKey): key = key.value # 更新内存 - self.__set_config_cache(user_id=user_id, key=key, value=value) + self.__set_config_cache(username=username, key=key, value=value) # 写入数据库 if ObjectUtils.is_obj(value): value = json.dumps(value) elif value is None: value = '' - conf = UserConfig.get_by_key(self._db, user_id, key) + conf = UserConfig.get_by_key(db=self._db, username=username, key=key) if conf: if value: conf.update(self._db, {"value": value}) else: conf.delete(self._db, conf.id) else: - conf = UserConfig(user_id=user_id, key=key, value=value) + conf = UserConfig(username=username, key=key, value=value) conf.create(self._db) - def get(self, user_id: int, key: Union[str, UserConfigKey] = None) -> Any: + def get(self, username: str, key: Union[str, UserConfigKey] = None) -> Any: """ 获取用户配置 """ - if not user_id: + if not username: return self.__USERCONF if isinstance(key, UserConfigKey): key = key.value if not key: - return self.__get_config_caches(user_id=user_id) - return self.__get_config_cache(user_id=user_id, key=key) + return self.__get_config_caches(username=username) + return self.__get_config_cache(username=username, key=key) def __del__(self): if self._db: self._db.close() - def __set_config_cache(self, user_id: int, key: str, value: Any): + def __set_config_cache(self, username: str, key: str, value: Any): """ 设置配置缓存 """ - if not user_id or not key: + if not username or not key: return cache = self.__USERCONF if not cache: cache = {} - user_cache = cache.get(user_id) + user_cache = cache.get(username) if not user_cache: user_cache = {} - cache[user_id] = user_cache + cache[username] = user_cache user_cache[key] = value self.__USERCONF = cache - - def __get_config_caches(self, user_id: int) -> Dict[str, Any]: - """ - 获取配置缓存 - """ - if not user_id: - return None - if not self.__USERCONF: - return None - return self.__USERCONF.get(user_id) - def __get_config_cache(self, user_id: int, key: str) -> Any: + def __get_config_caches(self, username: str) -> Dict[str, Any]: """ 获取配置缓存 """ - if not user_id or not key: + if not username or not self.__USERCONF: return None - if not self.__USERCONF: + return self.__USERCONF.get(username) + + def __get_config_cache(self, username: str, key: str) -> Any: + """ + 获取配置缓存 + """ + if not username or not key or not self.__USERCONF: return None - user_cache = self.__USERCONF.get(user_id) + user_cache = self.__get_config_caches(username) if not user_cache: return None return user_cache.get(key)