feat: 添加系统配置,更新验证码接口
This commit is contained in:
@@ -6,20 +6,20 @@
|
|||||||
# @Software : PyCharm
|
# @Software : PyCharm
|
||||||
# @Comment : 本程序日志装饰器定义
|
# @Comment : 本程序日志装饰器定义
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
from datetime import datetime
|
|
||||||
from functools import wraps, lru_cache
|
|
||||||
from async_lru import alru_cache
|
|
||||||
from typing import Optional, Literal
|
|
||||||
import urllib
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import urllib
|
||||||
|
from functools import wraps
|
||||||
|
from typing import Optional, Literal
|
||||||
|
|
||||||
|
from async_lru import alru_cache
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from fastapi.responses import ORJSONResponse, UJSONResponse, JSONResponse
|
from fastapi.responses import ORJSONResponse, UJSONResponse, JSONResponse
|
||||||
from user_agents import parse
|
|
||||||
from httpx import AsyncClient
|
from httpx import AsyncClient
|
||||||
|
from user_agents import parse
|
||||||
|
|
||||||
from config.constant import BusinessType
|
from config.constant import BusinessType
|
||||||
from config.env import AppConfig, MapConfig
|
from config.env import AppConfig, MapConfig
|
||||||
from controller.login import LoginController
|
from controller.login import LoginController
|
||||||
@@ -226,7 +226,7 @@ async def get_ip_location(ip: str) -> str:
|
|||||||
# 将sn参数添加到请求中
|
# 将sn参数添加到请求中
|
||||||
queryStr = queryStr + "&sn=" + sn
|
queryStr = queryStr + "&sn=" + sn
|
||||||
url = host + queryStr
|
url = host + queryStr
|
||||||
async with AsyncClient(headers=headers,timeout=60) as client:
|
async with AsyncClient(headers=headers, timeout=60) as client:
|
||||||
response = await client.get(url)
|
response = await client.get(url)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
result = response.json()
|
result = response.json()
|
||||||
@@ -239,4 +239,3 @@ async def get_ip_location(ip: str) -> str:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
# 如果IP地址格式无效
|
# 如果IP地址格式无效
|
||||||
return "未知地点"
|
return "未知地点"
|
||||||
|
|
||||||
|
|||||||
143
api/config.py
Normal file
143
api/config.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
# _*_ coding : UTF-8 _*_
|
||||||
|
# @Time : 2025/02/12 16:58
|
||||||
|
# @UpdateTime : 2025/02/12 16:58
|
||||||
|
# @Author : sonder
|
||||||
|
# @File : config.py
|
||||||
|
# @Software : PyCharm
|
||||||
|
# @Comment : 本程序
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Path, Request, Query
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
|
from annotation.log import Log
|
||||||
|
from config.constant import BusinessType
|
||||||
|
from config.get_redis import Redis
|
||||||
|
from controller.login import LoginController
|
||||||
|
from models import Config
|
||||||
|
from schemas.common import BaseResponse
|
||||||
|
from schemas.config import AddConfigParams, DeleteConfigListParams, GetConfigInfoResponse, GetConfigListResponse
|
||||||
|
from utils.response import Response
|
||||||
|
|
||||||
|
configApi = APIRouter(
|
||||||
|
prefix="/config",
|
||||||
|
dependencies=[Depends(LoginController.get_current_user)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@configApi.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增配置")
|
||||||
|
@Log(title="新增配置", business_type=BusinessType.INSERT)
|
||||||
|
async def add_config(request: Request, params: AddConfigParams):
|
||||||
|
if await Config.get_or_none(name=params.name, key=params.key):
|
||||||
|
return Response.error(msg="配置已存在")
|
||||||
|
config = await Config.create(
|
||||||
|
name=params.name,
|
||||||
|
key=params.key,
|
||||||
|
value=params.value,
|
||||||
|
remark=params.remark,
|
||||||
|
type=params.type,
|
||||||
|
)
|
||||||
|
if config:
|
||||||
|
await Redis.init_system_config(request.app)
|
||||||
|
return Response.success(msg="新增成功")
|
||||||
|
else:
|
||||||
|
return Response.error(msg="新增失败")
|
||||||
|
|
||||||
|
|
||||||
|
@configApi.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除配置")
|
||||||
|
@configApi.post("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除配置")
|
||||||
|
@Log(title="删除配置", business_type=BusinessType.DELETE)
|
||||||
|
async def delete_config(request: Request, id: str = Path(description="配置ID")):
|
||||||
|
if config := await Config.get_or_none(id=id):
|
||||||
|
await config.delete()
|
||||||
|
await Redis.init_system_config(request.app)
|
||||||
|
return Response.success(msg="删除成功")
|
||||||
|
else:
|
||||||
|
return Response.error(msg="配置不存在")
|
||||||
|
|
||||||
|
|
||||||
|
@configApi.delete("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除配置")
|
||||||
|
@configApi.post("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除配置")
|
||||||
|
@Log(title="批量删除配置", business_type=BusinessType.DELETE)
|
||||||
|
async def delete_config_list(request: Request, params: DeleteConfigListParams):
|
||||||
|
for id in set(params.ids):
|
||||||
|
if config := await Config.get_or_none(id=id):
|
||||||
|
await config.delete()
|
||||||
|
await Redis.init_system_config(request.app)
|
||||||
|
return Response.success(msg="删除成功")
|
||||||
|
|
||||||
|
|
||||||
|
@configApi.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改配置")
|
||||||
|
@configApi.post("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改配置")
|
||||||
|
@Log(title="修改配置", business_type=BusinessType.UPDATE)
|
||||||
|
async def update_config(request: Request, params: AddConfigParams, id: str = Path(description="配置ID")):
|
||||||
|
if config := await Config.get_or_none(id=id):
|
||||||
|
config.name = params.name
|
||||||
|
config.key = params.key
|
||||||
|
config.value = params.value
|
||||||
|
config.remark = params.remark
|
||||||
|
config.type = params.type
|
||||||
|
await config.save()
|
||||||
|
await Redis.init_system_config(request.app)
|
||||||
|
return Response.success(msg="修改成功")
|
||||||
|
else:
|
||||||
|
return Response.error(msg="配置不存在")
|
||||||
|
|
||||||
|
|
||||||
|
@configApi.get("/info/{id}", response_class=JSONResponse, response_model=GetConfigInfoResponse, summary="获取配置信息")
|
||||||
|
@Log(title="获取配置信息", business_type=BusinessType.SELECT)
|
||||||
|
async def get_config_info(request: Request, id: str = Path(description="配置ID")):
|
||||||
|
if config := await Config.get_or_none(id=id):
|
||||||
|
data = {
|
||||||
|
"id": config.id,
|
||||||
|
"name": config.name,
|
||||||
|
"key": config.key,
|
||||||
|
"value": config.value,
|
||||||
|
"remark": config.remark,
|
||||||
|
"type": config.type,
|
||||||
|
"create_time": config.create_time,
|
||||||
|
"create_by": config.create_by,
|
||||||
|
"update_time": config.update_time,
|
||||||
|
"update_by": config.update_by,
|
||||||
|
}
|
||||||
|
return Response.success(data=data)
|
||||||
|
else:
|
||||||
|
return Response.error(msg="配置不存在")
|
||||||
|
|
||||||
|
|
||||||
|
@configApi.get("/list", response_class=JSONResponse, response_model=GetConfigListResponse, summary="获取配置列表")
|
||||||
|
@Log(title="获取配置列表", business_type=BusinessType.SELECT)
|
||||||
|
async def get_config_list(request: Request,
|
||||||
|
page: int = Query(default=1, description="当前页码"),
|
||||||
|
pageSize: int = Query(default=10, description="每页数量"),
|
||||||
|
key: Optional[str] = Query(default=None, description="配置键名"),
|
||||||
|
name: Optional[str] = Query(default=None, description="配置名称"),
|
||||||
|
type: Optional[str] = Query(default=None, description="系统内置"),
|
||||||
|
):
|
||||||
|
filterArgs = {
|
||||||
|
f'{k}__contains': v for k, v in {
|
||||||
|
'name': name,
|
||||||
|
'key': key,
|
||||||
|
'type': type,
|
||||||
|
}.items() if v
|
||||||
|
}
|
||||||
|
total = await Config.filter(**filterArgs).count()
|
||||||
|
data = await Config.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values(
|
||||||
|
id="id",
|
||||||
|
name="name",
|
||||||
|
key="key",
|
||||||
|
value="value",
|
||||||
|
remark="remark",
|
||||||
|
type="type",
|
||||||
|
create_time="create_time",
|
||||||
|
create_by="create_by",
|
||||||
|
update_time="update_time",
|
||||||
|
update_by="update_by",
|
||||||
|
)
|
||||||
|
return Response.success(data={
|
||||||
|
"total": total,
|
||||||
|
"result": data,
|
||||||
|
"page": page,
|
||||||
|
"pageSize": pageSize,
|
||||||
|
})
|
||||||
@@ -137,7 +137,7 @@ async def get_file_info(
|
|||||||
async def delete_file(
|
async def delete_file(
|
||||||
request: Request,
|
request: Request,
|
||||||
id: str = Path(..., description="文件ID"),
|
id: str = Path(..., description="文件ID"),
|
||||||
current_user: dict = Depends(LoginController.get_current_user),):
|
current_user: dict = Depends(LoginController.get_current_user), ):
|
||||||
# 1. 查询文件记录
|
# 1. 查询文件记录
|
||||||
file_record = await FileModel.get_or_none(id=id)
|
file_record = await FileModel.get_or_none(id=id)
|
||||||
if not file_record:
|
if not file_record:
|
||||||
@@ -161,7 +161,7 @@ async def get_file_list(
|
|||||||
uploader_nickname: str = Query(default=None, description="上传者昵称"),
|
uploader_nickname: str = Query(default=None, description="上传者昵称"),
|
||||||
department_id: str = Query(default=None, description="上传者部门ID"),
|
department_id: str = Query(default=None, description="上传者部门ID"),
|
||||||
department_name: str = Query(default=None, description="上传者部门名称"),
|
department_name: str = Query(default=None, description="上传者部门名称"),
|
||||||
current_user: dict = Depends(LoginController.get_current_user),):
|
current_user: dict = Depends(LoginController.get_current_user), ):
|
||||||
# 1. 查询文件记录
|
# 1. 查询文件记录
|
||||||
filterArgs = {
|
filterArgs = {
|
||||||
f'{k}__contains': v for k, v in {
|
f'{k}__contains': v for k, v in {
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ from fastapi.responses import JSONResponse
|
|||||||
from annotation.log import Log
|
from annotation.log import Log
|
||||||
from config.constant import BusinessType, RedisKeyConfig
|
from config.constant import BusinessType, RedisKeyConfig
|
||||||
from controller.login import LoginController
|
from controller.login import LoginController
|
||||||
|
from models import I18n, Locale
|
||||||
from schemas.common import BaseResponse
|
from schemas.common import BaseResponse
|
||||||
from schemas.i18n import AddLocaleParams, GetLocaleInfoResponse, AddI18nParams, GetI18nInfoResponse, \
|
from schemas.i18n import AddLocaleParams, GetLocaleInfoResponse, AddI18nParams, GetI18nInfoResponse, \
|
||||||
GetI18nInfoListResponse, GetI18nListResponse
|
GetI18nInfoListResponse, GetI18nListResponse
|
||||||
from utils.response import Response
|
from utils.response import Response
|
||||||
from models import I18n, Locale
|
|
||||||
|
|
||||||
i18nAPI = APIRouter(
|
i18nAPI = APIRouter(
|
||||||
prefix="/i18n",
|
prefix="/i18n",
|
||||||
@@ -263,4 +263,3 @@ async def get_i18n_info_list(request: Request, id: str = Path(description="国
|
|||||||
"name": locale.name,
|
"name": locale.name,
|
||||||
})
|
})
|
||||||
return Response.error(msg="该国际化内容语言不存在!")
|
return Response.error(msg="该国际化内容语言不存在!")
|
||||||
|
|
||||||
|
|||||||
21
api/login.py
21
api/login.py
@@ -124,7 +124,19 @@ async def register(request: Request, params: RegisterUserParams):
|
|||||||
|
|
||||||
@loginAPI.get("/captcha", response_class=JSONResponse, response_model=GetCaptchaResponse, summary="获取验证码")
|
@loginAPI.get("/captcha", response_class=JSONResponse, response_model=GetCaptchaResponse, summary="获取验证码")
|
||||||
async def get_captcha(request: Request):
|
async def get_captcha(request: Request):
|
||||||
captcha_result = await Captcha.create_captcha("1")
|
captcha_enabled = (
|
||||||
|
True
|
||||||
|
if await request.app.state.redis.get(f'{RedisKeyConfig.SYSTEM_CONFIG.key}:account_captcha_enabled')
|
||||||
|
== 'true'
|
||||||
|
else False
|
||||||
|
)
|
||||||
|
if captcha_enabled:
|
||||||
|
captcha_type = (
|
||||||
|
await request.app.state.redis.get(f'{RedisKeyConfig.SYSTEM_CONFIG.key}:account_captcha_type')
|
||||||
|
if await request.app.state.redis.get(f'{RedisKeyConfig.SYSTEM_CONFIG.key}:account_captcha_type')
|
||||||
|
else "1"
|
||||||
|
)
|
||||||
|
captcha_result = await Captcha.create_captcha(captcha_type)
|
||||||
session_id = str(uuid.uuid4())
|
session_id = str(uuid.uuid4())
|
||||||
captcha = captcha_result[0]
|
captcha = captcha_result[0]
|
||||||
result = captcha_result[-1]
|
result = captcha_result[-1]
|
||||||
@@ -136,6 +148,13 @@ async def get_captcha(request: Request):
|
|||||||
return Response.success(data={
|
return Response.success(data={
|
||||||
"uuid": session_id,
|
"uuid": session_id,
|
||||||
"captcha": captcha,
|
"captcha": captcha,
|
||||||
|
"captcha_enabled": captcha_enabled,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
return Response.success(data={
|
||||||
|
"uuid": None,
|
||||||
|
"captcha": None,
|
||||||
|
"captcha_enabled": captcha_enabled,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
app.py
6
app.py
@@ -13,15 +13,16 @@ from fastapi import FastAPI
|
|||||||
from fastapi.openapi.utils import get_openapi
|
from fastapi.openapi.utils import get_openapi
|
||||||
|
|
||||||
from api.cache import cacheAPI
|
from api.cache import cacheAPI
|
||||||
|
from api.config import configApi
|
||||||
from api.department import departmentAPI
|
from api.department import departmentAPI
|
||||||
from api.file import fileAPI
|
from api.file import fileAPI
|
||||||
|
from api.i18n import i18nAPI
|
||||||
from api.log import logAPI
|
from api.log import logAPI
|
||||||
from api.login import loginAPI
|
from api.login import loginAPI
|
||||||
from api.permission import permissionAPI
|
from api.permission import permissionAPI
|
||||||
from api.role import roleAPI
|
from api.role import roleAPI
|
||||||
from api.server import serverAPI
|
from api.server import serverAPI
|
||||||
from api.user import userAPI
|
from api.user import userAPI
|
||||||
from api.i18n import i18nAPI
|
|
||||||
from config.database import init_db, close_db
|
from config.database import init_db, close_db
|
||||||
from config.env import AppConfig
|
from config.env import AppConfig
|
||||||
from config.get_redis import Redis
|
from config.get_redis import Redis
|
||||||
@@ -36,6 +37,7 @@ async def lifespan(app: FastAPI):
|
|||||||
app.state.redis = await Redis.create_redis_pool()
|
app.state.redis = await Redis.create_redis_pool()
|
||||||
logger.info(f'{AppConfig.app_name}启动成功')
|
logger.info(f'{AppConfig.app_name}启动成功')
|
||||||
await init_db()
|
await init_db()
|
||||||
|
await Redis.init_system_config(app)
|
||||||
yield
|
yield
|
||||||
await close_db()
|
await close_db()
|
||||||
await Redis.close_redis_pool(app)
|
await Redis.close_redis_pool(app)
|
||||||
@@ -84,7 +86,7 @@ api_list = [
|
|||||||
{'api': cacheAPI, 'tags': ['缓存管理']},
|
{'api': cacheAPI, 'tags': ['缓存管理']},
|
||||||
{'api': serverAPI, 'tags': ['服务器管理']},
|
{'api': serverAPI, 'tags': ['服务器管理']},
|
||||||
{'api': i18nAPI, 'tags': ['国际化管理']},
|
{'api': i18nAPI, 'tags': ['国际化管理']},
|
||||||
|
{'api': configApi, 'tags': ['配置管理']},
|
||||||
]
|
]
|
||||||
|
|
||||||
for api in api_list:
|
for api in api_list:
|
||||||
|
|||||||
@@ -263,3 +263,5 @@ class RedisKeyConfig(Enum):
|
|||||||
"""用于存储国际化数据。"""
|
"""用于存储国际化数据。"""
|
||||||
TRANSLATION_TYPES = {'key': 'translation_types', 'remark': '国际化类型'}
|
TRANSLATION_TYPES = {'key': 'translation_types', 'remark': '国际化类型'}
|
||||||
"""国际化类型,存储国际化类型及其配置信息。"""
|
"""国际化类型,存储国际化类型及其配置信息。"""
|
||||||
|
SYSTEM_CONFIG = {'key': 'system_config', 'remark': '系统配置信息'}
|
||||||
|
"""系统配置信息,存储系统的配置信息。"""
|
||||||
|
|||||||
@@ -473,6 +473,7 @@ class GetConfig:
|
|||||||
"""
|
"""
|
||||||
# 实例化邮件配置
|
# 实例化邮件配置
|
||||||
return EmailSettings()
|
return EmailSettings()
|
||||||
|
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def get_map_config(self) -> 'MapSettings':
|
def get_map_config(self) -> 'MapSettings':
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
from redis import asyncio as aioredis
|
from redis import asyncio as aioredis
|
||||||
from redis.exceptions import AuthenticationError, TimeoutError, RedisError
|
from redis.exceptions import AuthenticationError, TimeoutError, RedisError
|
||||||
|
|
||||||
|
from config.constant import RedisKeyConfig
|
||||||
from config.env import RedisConfig
|
from config.env import RedisConfig
|
||||||
|
from models import Config
|
||||||
from utils.log import logger
|
from utils.log import logger
|
||||||
|
|
||||||
|
|
||||||
@@ -66,3 +68,18 @@ class Redis:
|
|||||||
"""
|
"""
|
||||||
await app.state.redis.close()
|
await app.state.redis.close()
|
||||||
logger.info('关闭 Redis 连接成功')
|
logger.info('关闭 Redis 连接成功')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def init_system_config(cls, app):
|
||||||
|
"""
|
||||||
|
初始化系统配置
|
||||||
|
"""
|
||||||
|
# 获取以sys_config:开头的键列表
|
||||||
|
keys = await app.state.redis.keys(f'{RedisKeyConfig.SYSTEM_CONFIG.key}:*')
|
||||||
|
# 删除匹配的键
|
||||||
|
if keys:
|
||||||
|
await app.state.redis.delete(*keys)
|
||||||
|
config = await Config.all().values()
|
||||||
|
for item in config:
|
||||||
|
await app.state.redis.set(f"{RedisKeyConfig.SYSTEM_CONFIG.key}:{item.get('key')}",
|
||||||
|
item.get('value'), )
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
# @Software : PyCharm
|
# @Software : PyCharm
|
||||||
# @Comment : 本程序
|
# @Comment : 本程序
|
||||||
|
|
||||||
|
from models.config import Config
|
||||||
from models.department import Department, DepartmentRole
|
from models.department import Department, DepartmentRole
|
||||||
from models.file import File
|
from models.file import File
|
||||||
|
from models.i18n import I18n, Locale
|
||||||
from models.log import LoginLog, OperationLog
|
from models.log import LoginLog, OperationLog
|
||||||
from models.permission import Permission
|
from models.permission import Permission
|
||||||
from models.role import Role, RolePermission
|
from models.role import Role, RolePermission
|
||||||
from models.user import User, UserRole
|
from models.user import User, UserRole
|
||||||
from models.i18n import I18n,Locale
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Department',
|
'Department',
|
||||||
@@ -26,5 +27,6 @@ __all__ = [
|
|||||||
'User',
|
'User',
|
||||||
'UserRole',
|
'UserRole',
|
||||||
'I18n',
|
'I18n',
|
||||||
'Locale'
|
'Locale',
|
||||||
|
'Config'
|
||||||
]
|
]
|
||||||
|
|||||||
70
models/config.py
Normal file
70
models/config.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# _*_ coding : UTF-8 _*_
|
||||||
|
# @Time : 2025/02/12 16:43
|
||||||
|
# @UpdateTime : 2025/02/12 16:43
|
||||||
|
# @Author : sonder
|
||||||
|
# @File : config.py
|
||||||
|
# @Software : PyCharm
|
||||||
|
# @Comment : 本程序
|
||||||
|
|
||||||
|
from tortoise import fields
|
||||||
|
|
||||||
|
from models.common import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Config(BaseModel):
|
||||||
|
"""
|
||||||
|
系统配置模型
|
||||||
|
"""
|
||||||
|
name = fields.CharField(
|
||||||
|
max_length=100,
|
||||||
|
description="配置名称",
|
||||||
|
source_field="name"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
配置名称。
|
||||||
|
- 最大长度为 100 个字符
|
||||||
|
- 映射到数据库字段 name
|
||||||
|
"""
|
||||||
|
key = fields.CharField(
|
||||||
|
max_length=100,
|
||||||
|
description="配置键名",
|
||||||
|
source_field="key"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
配置键名。
|
||||||
|
- 最大长度为 100 个字符
|
||||||
|
- 映射到数据库字段 key
|
||||||
|
"""
|
||||||
|
value = fields.CharField(
|
||||||
|
max_length=100,
|
||||||
|
description="配置值",
|
||||||
|
source_field="value"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
配置值。
|
||||||
|
- 最大长度为 100 个字符
|
||||||
|
- 映射到数据库字段 value
|
||||||
|
"""
|
||||||
|
type = fields.BooleanField(
|
||||||
|
default=False,
|
||||||
|
description="系统内置",
|
||||||
|
source_field="type"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
是否为系统内置
|
||||||
|
- 默认为不是
|
||||||
|
"""
|
||||||
|
remark = fields.TextField(
|
||||||
|
null=True,
|
||||||
|
description="备注",
|
||||||
|
source_field="remark"
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
备注信息。
|
||||||
|
- 最大长度为 255 个字符
|
||||||
|
- 可为空
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table = "sys_config"
|
||||||
|
table_description = "系统配置表"
|
||||||
@@ -54,7 +54,7 @@ class Role(BaseModel):
|
|||||||
- 映射到数据库字段 role_description。
|
- 映射到数据库字段 role_description。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status=fields.SmallIntField(
|
status = fields.SmallIntField(
|
||||||
default=1,
|
default=1,
|
||||||
description="角色状态",
|
description="角色状态",
|
||||||
source_field="status"
|
source_field="status"
|
||||||
|
|||||||
70
schemas/config.py
Normal file
70
schemas/config.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# _*_ coding : UTF-8 _*_
|
||||||
|
# @Time : 2025/02/12 17:03
|
||||||
|
# @UpdateTime : 2025/02/12 17:03
|
||||||
|
# @Author : sonder
|
||||||
|
# @File : config.py
|
||||||
|
# @Software : PyCharm
|
||||||
|
# @Comment : 本程序
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field, ConfigDict
|
||||||
|
from pydantic.alias_generators import to_camel
|
||||||
|
|
||||||
|
from schemas.common import BaseResponse, ListQueryResult
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigInfo(BaseModel):
|
||||||
|
"""
|
||||||
|
配置信息模型
|
||||||
|
"""
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
id: str = Field(..., description="主键")
|
||||||
|
create_by: str = Field(default="", description="创建者")
|
||||||
|
create_time: Optional[datetime] = Field(default=None, description="创建时间")
|
||||||
|
update_by: str = Field(default="", description="更新者")
|
||||||
|
update_time: Optional[datetime] = Field(default=None, description="更新时间")
|
||||||
|
name: str = Field(default="", description="配置名称")
|
||||||
|
key: str = Field(default="", description="配置键名")
|
||||||
|
value: str = Field(default="", description="配置值")
|
||||||
|
type: bool = Field(default=False, description="系统内置")
|
||||||
|
remark: str = Field(default="", description="备注")
|
||||||
|
|
||||||
|
|
||||||
|
class AddConfigParams(BaseModel):
|
||||||
|
"""
|
||||||
|
添加配置参数模型
|
||||||
|
"""
|
||||||
|
name: str = Field(..., max_length=100, description="配置名称")
|
||||||
|
key: str = Field(..., max_length=100, description="配置键名")
|
||||||
|
value: str = Field(..., max_length=100, description="配置值")
|
||||||
|
type: bool = Field(default=False, description="系统内置")
|
||||||
|
remark: Optional[str] = Field(default=None, max_length=255, description="备注信息")
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteConfigListParams(BaseModel):
|
||||||
|
"""
|
||||||
|
批量删除配置参数模型
|
||||||
|
"""
|
||||||
|
ids: List[str] = Field(default=[], description="配置ID")
|
||||||
|
|
||||||
|
|
||||||
|
class GetConfigInfoResponse(BaseResponse):
|
||||||
|
"""
|
||||||
|
获取配置模型信息响应
|
||||||
|
"""
|
||||||
|
data: ConfigInfo = Field(default=None, description="响应数据")
|
||||||
|
|
||||||
|
|
||||||
|
class GetConfigInfoResult(ListQueryResult):
|
||||||
|
"""
|
||||||
|
获取配置模型信息结果
|
||||||
|
"""
|
||||||
|
result: List[ConfigInfo] = Field(default=[], description="列表数据")
|
||||||
|
|
||||||
|
|
||||||
|
class GetConfigListResponse(BaseResponse):
|
||||||
|
"""
|
||||||
|
获取配置列表响应
|
||||||
|
"""
|
||||||
|
data: GetConfigInfoResult = Field(default=None, description="响应数据")
|
||||||
@@ -114,14 +114,16 @@ class GetCaptchaResult(BaseModel):
|
|||||||
"""
|
"""
|
||||||
获取验证码结果模型
|
获取验证码结果模型
|
||||||
"""
|
"""
|
||||||
uuid: str = Field(default="", description="验证码UUID")
|
uuid: Optional[str] = Field(default=None, description="验证码UUID")
|
||||||
captcha: str = Field(default="", description="验证码图片")
|
captcha: Optional[str] = Field(default=None, description="验证码图片")
|
||||||
|
captcha_enabled: Optional[bool] = Field(default=False, description="是否开启验证码")
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
json_schema_extra = {
|
json_schema_extra = {
|
||||||
"example": {
|
"example": {
|
||||||
"uuid": "1234567890",
|
"uuid": "1234567890",
|
||||||
"captcha": "base64编码的图片"
|
"captcha": "base64编码的图片",
|
||||||
|
"captcha_enabled": True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +132,7 @@ class GetEmailCodeParams(BaseModel):
|
|||||||
"""
|
"""
|
||||||
获取邮箱验证码请求模型
|
获取邮箱验证码请求模型
|
||||||
"""
|
"""
|
||||||
username:str=Field(default="", description="用户名")
|
username: str = Field(default="", description="用户名")
|
||||||
title: str = Field(default="注册", description="邮件类型")
|
title: str = Field(default="注册", description="邮件类型")
|
||||||
mail: str = Field(default="", description="邮箱地址")
|
mail: str = Field(default="", description="邮箱地址")
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ class Email:
|
|||||||
username=EmailConfig.email_username,
|
username=EmailConfig.email_username,
|
||||||
password=EmailConfig.email_password
|
password=EmailConfig.email_password
|
||||||
)
|
)
|
||||||
await request.app.state.redis.set(f"{RedisKeyConfig.EMAIL_CODES.key}:{mail}-{username}", code, ex=timedelta(minutes=2))
|
await request.app.state.redis.set(f"{RedisKeyConfig.EMAIL_CODES.key}:{mail}-{username}", code,
|
||||||
|
ex=timedelta(minutes=2))
|
||||||
logger.info(f"发送邮件至{mail}成功,验证码:{code}")
|
logger.info(f"发送邮件至{mail}成功,验证码:{code}")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user