mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 08:26:53 +08:00
fix(update_setting): 修复设置保存错误的问题
- adapt to Pydantic V2
This commit is contained in:
@@ -178,7 +178,7 @@ def get_global_setting(token: str):
|
|||||||
raise HTTPException(status_code=403, detail="Forbidden")
|
raise HTTPException(status_code=403, detail="Forbidden")
|
||||||
|
|
||||||
# FIXME: 新增敏感配置项时要在此处添加排除项
|
# FIXME: 新增敏感配置项时要在此处添加排除项
|
||||||
info = settings.dict(
|
info = settings.model_dump(
|
||||||
exclude={"SECRET_KEY", "RESOURCE_SECRET_KEY", "API_TOKEN", "TMDB_API_KEY", "TVDB_API_KEY", "FANART_API_KEY",
|
exclude={"SECRET_KEY", "RESOURCE_SECRET_KEY", "API_TOKEN", "TMDB_API_KEY", "TVDB_API_KEY", "FANART_API_KEY",
|
||||||
"COOKIECLOUD_KEY", "COOKIECLOUD_PASSWORD", "GITHUB_TOKEN", "REPO_GITHUB_TOKEN", "U115_APP_ID",
|
"COOKIECLOUD_KEY", "COOKIECLOUD_PASSWORD", "GITHUB_TOKEN", "REPO_GITHUB_TOKEN", "U115_APP_ID",
|
||||||
"ALIPAN_APP_ID", "TVDB_V4_API_KEY", "TVDB_V4_API_PIN"}
|
"ALIPAN_APP_ID", "TVDB_V4_API_KEY", "TVDB_V4_API_PIN"}
|
||||||
@@ -199,7 +199,7 @@ async def get_env_setting(_: User = Depends(get_current_active_user_async)):
|
|||||||
"""
|
"""
|
||||||
查询系统环境变量,包括当前版本号(仅管理员)
|
查询系统环境变量,包括当前版本号(仅管理员)
|
||||||
"""
|
"""
|
||||||
info = settings.dict(
|
info = settings.model_dump(
|
||||||
exclude={"SECRET_KEY", "RESOURCE_SECRET_KEY"}
|
exclude={"SECRET_KEY", "RESOURCE_SECRET_KEY"}
|
||||||
)
|
)
|
||||||
info.update({
|
info.update({
|
||||||
|
|||||||
+17
-27
@@ -547,18 +547,14 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(data, dict):
|
if not isinstance(data, dict):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# 处理 API_TOKEN 特殊验证
|
# 处理 API_TOKEN 特殊验证
|
||||||
if 'API_TOKEN' in data:
|
if 'API_TOKEN' in data:
|
||||||
converted_value, needs_update = cls.validate_api_token(data['API_TOKEN'], data['API_TOKEN'])
|
converted_value, needs_update = cls.validate_api_token(data['API_TOKEN'], data['API_TOKEN'])
|
||||||
if needs_update:
|
if needs_update:
|
||||||
cls.update_env_config(
|
cls.update_env_config("API_TOKEN", data["API_TOKEN"], converted_value)
|
||||||
type('Field', (), {'name': 'API_TOKEN'})(),
|
|
||||||
data['API_TOKEN'],
|
|
||||||
converted_value
|
|
||||||
)
|
|
||||||
data['API_TOKEN'] = converted_value
|
data['API_TOKEN'] = converted_value
|
||||||
|
|
||||||
# 对其他字段进行类型转换
|
# 对其他字段进行类型转换
|
||||||
for field_name, field_info in cls.model_fields.items():
|
for field_name, field_info in cls.model_fields.items():
|
||||||
if field_name not in data:
|
if field_name not in data:
|
||||||
@@ -566,35 +562,31 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
|||||||
value = data[field_name]
|
value = data[field_name]
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
field = cls.model_fields.get(field_name)
|
field = cls.model_fields.get(field_name)
|
||||||
if field:
|
if field:
|
||||||
converted_value, needs_update = cls.generic_type_converter(
|
converted_value, needs_update = cls.generic_type_converter(
|
||||||
value, value, field.annotation, field.default, field_name
|
value, value, field.annotation, field.default, field_name
|
||||||
)
|
)
|
||||||
if needs_update:
|
if needs_update:
|
||||||
cls.update_env_config(
|
cls.update_env_config(field_name, value, converted_value)
|
||||||
type('Field', (), {'name': field_name})(),
|
|
||||||
value,
|
|
||||||
converted_value
|
|
||||||
)
|
|
||||||
data[field_name] = converted_value
|
data[field_name] = converted_value
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_env_config(field: Any, original_value: Any, converted_value: Any) -> Tuple[bool, str]:
|
def update_env_config(field_name: str, original_value: Any, converted_value: Any) -> Tuple[bool, str]:
|
||||||
"""
|
"""
|
||||||
更新 env 配置
|
更新 env 配置
|
||||||
"""
|
"""
|
||||||
message = None
|
message = None
|
||||||
is_converted = original_value is not None and str(original_value) != str(converted_value)
|
is_converted = original_value is not None and str(original_value) != str(converted_value)
|
||||||
if is_converted:
|
if is_converted:
|
||||||
message = f"配置项 '{field.name}' 的值 '{original_value}' 无效,已替换为 '{converted_value}'"
|
message = f"配置项 '{field_name}' 的值 '{original_value}' 无效,已替换为 '{converted_value}'"
|
||||||
logger.warning(message)
|
logger.warning(message)
|
||||||
|
|
||||||
if field.name in os.environ:
|
if field_name in os.environ:
|
||||||
message = f"配置项 '{field.name}' 已在环境变量中设置,请手动更新以保持一致性"
|
message = f"配置项 '{field_name}' 已在环境变量中设置,请手动更新以保持一致性"
|
||||||
logger.warning(message)
|
logger.warning(message)
|
||||||
return False, message
|
return False, message
|
||||||
else:
|
else:
|
||||||
@@ -604,10 +596,10 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
|||||||
else:
|
else:
|
||||||
value_to_write = str(converted_value) if converted_value is not None else ""
|
value_to_write = str(converted_value) if converted_value is not None else ""
|
||||||
|
|
||||||
set_key(dotenv_path=SystemUtils.get_env_path(), key_to_set=field.name, value_to_set=value_to_write,
|
set_key(dotenv_path=SystemUtils.get_env_path(), key_to_set=field_name, value_to_set=value_to_write,
|
||||||
quote_mode="always")
|
quote_mode="always")
|
||||||
if is_converted:
|
if is_converted:
|
||||||
logger.info(f"配置项 '{field.name}' 已自动修正并写入到 'app.env' 文件")
|
logger.info(f"配置项 '{field_name}' 已自动修正并写入到 'app.env' 文件")
|
||||||
return True, message
|
return True, message
|
||||||
|
|
||||||
def update_setting(self, key: str, value: Any) -> Tuple[Optional[bool], str]:
|
def update_setting(self, key: str, value: Any) -> Tuple[Optional[bool], str]:
|
||||||
@@ -623,17 +615,15 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
|||||||
try:
|
try:
|
||||||
field = Settings.model_fields[key]
|
field = Settings.model_fields[key]
|
||||||
original_value = getattr(self, key)
|
original_value = getattr(self, key)
|
||||||
if field.name == "API_TOKEN":
|
if key == "API_TOKEN":
|
||||||
converted_value, needs_update = self.validate_api_token(value, original_value)
|
converted_value, needs_update = self.validate_api_token(value, original_value)
|
||||||
else:
|
else:
|
||||||
converted_value, needs_update = self.generic_type_converter(value,
|
converted_value, needs_update = self.generic_type_converter(
|
||||||
original_value,
|
value, original_value, field.annotation, field.default, key
|
||||||
field.type_,
|
)
|
||||||
field.default,
|
|
||||||
key)
|
|
||||||
# 如果没有抛出异常,则统一使用 converted_value 进行更新
|
# 如果没有抛出异常,则统一使用 converted_value 进行更新
|
||||||
if needs_update or str(value) != str(converted_value):
|
if needs_update or str(value) != str(converted_value):
|
||||||
success, message = self.update_env_config(field, value, converted_value)
|
success, message = self.update_env_config(key, value, converted_value)
|
||||||
# 仅成功更新配置时,才更新内存
|
# 仅成功更新配置时,才更新内存
|
||||||
if success:
|
if success:
|
||||||
setattr(self, key, converted_value)
|
setattr(self, key, converted_value)
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class TransHandler:
|
|||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify,
|
need_notify=need_notify,
|
||||||
)
|
)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
else:
|
else:
|
||||||
new_path = target_path / fileitem.name
|
new_path = target_path / fileitem.name
|
||||||
# 整理目录
|
# 整理目录
|
||||||
@@ -147,7 +147,7 @@ class TransHandler:
|
|||||||
fileitem=fileitem,
|
fileitem=fileitem,
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
|
|
||||||
logger.info(f"文件夹 {fileitem.path} 整理成功")
|
logger.info(f"文件夹 {fileitem.path} 整理成功")
|
||||||
# 返回整理后的路径
|
# 返回整理后的路径
|
||||||
@@ -158,7 +158,7 @@ class TransHandler:
|
|||||||
need_scrape=need_scrape,
|
need_scrape=need_scrape,
|
||||||
need_notify=need_notify,
|
need_notify=need_notify,
|
||||||
transfer_type=transfer_type)
|
transfer_type=transfer_type)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
else:
|
else:
|
||||||
# 整理单个文件
|
# 整理单个文件
|
||||||
if mediainfo.type == MediaType.TV:
|
if mediainfo.type == MediaType.TV:
|
||||||
@@ -171,7 +171,7 @@ class TransHandler:
|
|||||||
fail_list=[fileitem.path],
|
fail_list=[fileitem.path],
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
|
|
||||||
# 文件结束季为空
|
# 文件结束季为空
|
||||||
in_meta.end_season = None
|
in_meta.end_season = None
|
||||||
@@ -207,7 +207,7 @@ class TransHandler:
|
|||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify,
|
need_notify=need_notify,
|
||||||
)
|
)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
else:
|
else:
|
||||||
new_file = target_path / fileitem.name
|
new_file = target_path / fileitem.name
|
||||||
folder_path = target_path
|
folder_path = target_path
|
||||||
@@ -224,7 +224,7 @@ class TransHandler:
|
|||||||
fail_list=[fileitem.path],
|
fail_list=[fileitem.path],
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
# 目标文件
|
# 目标文件
|
||||||
target_item = target_oper.get_item(new_file)
|
target_item = target_oper.get_item(new_file)
|
||||||
if target_item:
|
if target_item:
|
||||||
@@ -255,7 +255,7 @@ class TransHandler:
|
|||||||
fail_list=[fileitem.path],
|
fail_list=[fileitem.path],
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
elif overwrite_mode == 'never':
|
elif overwrite_mode == 'never':
|
||||||
# 存在不覆盖
|
# 存在不覆盖
|
||||||
self.__set_result(success=False,
|
self.__set_result(success=False,
|
||||||
@@ -266,7 +266,7 @@ class TransHandler:
|
|||||||
fail_list=[fileitem.path],
|
fail_list=[fileitem.path],
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
elif overwrite_mode == 'latest':
|
elif overwrite_mode == 'latest':
|
||||||
# 仅保留最新版本
|
# 仅保留最新版本
|
||||||
logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}")
|
logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}")
|
||||||
@@ -293,7 +293,7 @@ class TransHandler:
|
|||||||
fail_list=[fileitem.path],
|
fail_list=[fileitem.path],
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
|
|
||||||
logger.info(f"文件 {fileitem.path} 整理成功")
|
logger.info(f"文件 {fileitem.path} 整理成功")
|
||||||
self.__set_result(success=True,
|
self.__set_result(success=True,
|
||||||
@@ -303,7 +303,7 @@ class TransHandler:
|
|||||||
need_scrape=need_scrape,
|
need_scrape=need_scrape,
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result.copy()
|
return self.result.model_copy()
|
||||||
finally:
|
finally:
|
||||||
self.result = None
|
self.result = None
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class Subscribe(BaseModel):
|
|||||||
# 背景图
|
# 背景图
|
||||||
backdrop: Optional[str] = None
|
backdrop: Optional[str] = None
|
||||||
# 评分
|
# 评分
|
||||||
vote: Optional[float] = 0
|
vote: Optional[float] = 0.0
|
||||||
# 描述
|
# 描述
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
# 过滤规则
|
# 过滤规则
|
||||||
@@ -110,7 +110,7 @@ class SubscribeShare(BaseModel):
|
|||||||
# 背景图
|
# 背景图
|
||||||
backdrop: Optional[str] = None
|
backdrop: Optional[str] = None
|
||||||
# 评分
|
# 评分
|
||||||
vote: Optional[int] = 0
|
vote: Optional[float] = 0.0
|
||||||
# 描述
|
# 描述
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
# 包含
|
# 包含
|
||||||
|
|||||||
Reference in New Issue
Block a user