From 666d6eb048c4853433b17edf9a8658da3bc55cea Mon Sep 17 00:00:00 2001 From: Allen Date: Thu, 18 Apr 2024 12:33:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=9B=B8=E5=85=B3=E8=83=BD=E5=8A=9B=E5=92=8C=E6=8E=A5?= =?UTF-8?q?=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"