单元测试:新建用户与用户组
This commit is contained in:
10
clean.py
10
clean.py
@@ -69,7 +69,7 @@ def get_excluded_dirs(exclude_arg: str) -> Set[str]:
|
||||
|
||||
def clean_pycache(root_dir: str, exclude_dirs: Set[str], dry_run: bool = False) -> List[str]:
|
||||
"""清理 __pycache__ 目录"""
|
||||
log.info("开始清理 __pycache__ 目录...")
|
||||
log.info("开始清理 __pycache__ 目录pass")
|
||||
cleaned_paths = []
|
||||
|
||||
for dirpath, dirnames, _ in os.walk(root_dir):
|
||||
@@ -90,7 +90,7 @@ def clean_pycache(root_dir: str, exclude_dirs: Set[str], dry_run: bool = False)
|
||||
|
||||
def clean_pyc_files(root_dir: str, exclude_dirs: Set[str], dry_run: bool = False) -> List[str]:
|
||||
"""清理 .pyc 文件"""
|
||||
log.info("开始清理 .pyc 文件...")
|
||||
log.info("开始清理 .pyc 文件pass")
|
||||
cleaned_files = []
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root_dir):
|
||||
@@ -112,7 +112,7 @@ def clean_pyc_files(root_dir: str, exclude_dirs: Set[str], dry_run: bool = False
|
||||
|
||||
def clean_pytest_cache(root_dir: str, exclude_dirs: Set[str], dry_run: bool = False) -> List[str]:
|
||||
"""清理 .pytest_cache 目录"""
|
||||
log.info("开始清理 .pytest_cache 目录...")
|
||||
log.info("开始清理 .pytest_cache 目录pass")
|
||||
cleaned_paths = []
|
||||
|
||||
for dirpath, dirnames, _ in os.walk(root_dir):
|
||||
@@ -133,7 +133,7 @@ def clean_pytest_cache(root_dir: str, exclude_dirs: Set[str], dry_run: bool = Fa
|
||||
|
||||
def clean_nicegui(root_dir: str, dry_run: bool = False) -> Tuple[bool, str]:
|
||||
"""清理 .nicegui 目录"""
|
||||
log.info("开始清理 .nicegui 目录...")
|
||||
log.info("开始清理 .nicegui 目录pass")
|
||||
nicegui_dir = os.path.join(root_dir, ".nicegui")
|
||||
if os.path.exists(nicegui_dir) and os.path.isdir(nicegui_dir):
|
||||
success, error = safe_remove(nicegui_dir, dry_run)
|
||||
@@ -146,7 +146,7 @@ def clean_nicegui(root_dir: str, dry_run: bool = False) -> Tuple[bool, str]:
|
||||
|
||||
def clean_testdb(root_dir: str, dry_run: bool = False) -> Tuple[bool, str, str]:
|
||||
"""清理测试数据库文件"""
|
||||
log.info("开始清理 test.db 文件...")
|
||||
log.info("开始清理 test.db 文件pass")
|
||||
test_db = os.path.join(root_dir, "test.db")
|
||||
if os.path.exists(test_db) and os.path.isfile(test_db):
|
||||
success, error = safe_remove(test_db, dry_run)
|
||||
|
||||
10
main.py
10
main.py
@@ -4,10 +4,14 @@ from pkg.conf import appmeta
|
||||
from models.database import init_db
|
||||
from models.migration import init_default_settings
|
||||
from pkg.lifespan import lifespan
|
||||
from pkg.JWT import jwt
|
||||
|
||||
# 添加初始化数据库启动项
|
||||
lifespan.add_startup(init_db)
|
||||
lifespan.add_startup(init_default_settings)
|
||||
lifespan.add_startup(jwt.load_secret_key)
|
||||
|
||||
# 创建应用实例并设置元数据
|
||||
app = FastAPI(
|
||||
title=appmeta.APP_NAME,
|
||||
summary=appmeta.summary,
|
||||
@@ -18,6 +22,7 @@ app = FastAPI(
|
||||
lifespan=lifespan.lifespan,
|
||||
)
|
||||
|
||||
# 挂载路由
|
||||
for router in routers.Router:
|
||||
app.include_router(
|
||||
router,
|
||||
@@ -30,7 +35,8 @@ for router in routers.Router:
|
||||
500: {"description": "内部服务器错误 Internal server error"}
|
||||
},)
|
||||
|
||||
# 启动时打印欢迎信息
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app=app, host="0.0.0.0", port=5213)
|
||||
# uvicorn.run(app='main:app', host="0.0.0.0", port=5213, reload=True)
|
||||
# uvicorn.run(app=app, host="0.0.0.0", port=5213) # 生产环境
|
||||
uvicorn.run(app='main:app', host="0.0.0.0", port=5213, reload=True) # 开发环境
|
||||
@@ -8,7 +8,7 @@ async def AuthRequired(
|
||||
'''
|
||||
AuthRequired 需要登录
|
||||
'''
|
||||
return True
|
||||
from models.user import User
|
||||
|
||||
async def SignRequired(
|
||||
token: Annotated[str, Depends(jwt.oauth2_scheme)]
|
||||
@@ -27,4 +27,4 @@ async def AdminRequired(
|
||||
使用方法:
|
||||
>>> APIRouter(dependencies=[Depends(is_admin)])
|
||||
'''
|
||||
...
|
||||
pass
|
||||
@@ -6,7 +6,7 @@ from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from typing import AsyncGenerator
|
||||
|
||||
ASYNC_DATABASE_URL = "sqlite+aiosqlite:///database.db"
|
||||
ASYNC_DATABASE_URL = "sqlite+aiosqlite:///:memory:"
|
||||
|
||||
engine = create_async_engine(
|
||||
ASYNC_DATABASE_URL,
|
||||
|
||||
@@ -49,43 +49,58 @@ class Group(BaseModel, table=True):
|
||||
sa_relationship_kwargs={"foreign_keys": "User.previous_group_id"}
|
||||
)
|
||||
|
||||
async def add_group(self, name: str, policies: Optional[str] = None, max_storage: int = 0,
|
||||
share_enabled: bool = False, web_dav_enabled: bool = False,
|
||||
speed_limit: int = 0, options: Optional[str] = None) -> "Group":
|
||||
@staticmethod
|
||||
async def create(
|
||||
group: "Group"
|
||||
) -> "Group":
|
||||
"""
|
||||
向数据库内添加用户组。
|
||||
|
||||
:param name: 用户组名
|
||||
:type name: str
|
||||
:param policies: 允许的策略ID列表,逗号分隔,默认为 None
|
||||
:type policies: Optional[str]
|
||||
:param max_storage: 最大存储空间(字节),默认为 0
|
||||
:type max_storage: int
|
||||
:param share_enabled: 是否允许创建分享,默认为 False
|
||||
:type share_enabled: bool
|
||||
:param web_dav_enabled: 是否允许使用WebDAV,默认为 False
|
||||
:type web_dav_enabled: bool
|
||||
:param speed_limit: 速度限制 (KB/s), 0为不限制,默认为 0
|
||||
:type speed_limit: int
|
||||
:param options: 其他选项 (JSON格式),默认为 None
|
||||
:type options: Optional[str]
|
||||
:param group: 用户组对象
|
||||
:type group: Group
|
||||
:return: 新创建的用户组对象
|
||||
:rtype: Group
|
||||
"""
|
||||
|
||||
from .database import get_session
|
||||
|
||||
async for session in get_session():
|
||||
try:
|
||||
session.add(group)
|
||||
await session.commit()
|
||||
await session.refresh(group)
|
||||
except Exception as e:
|
||||
await session.rollback()
|
||||
raise e
|
||||
return group
|
||||
|
||||
@staticmethod
|
||||
async def get(
|
||||
id: int = None
|
||||
) -> Optional["Group"]:
|
||||
"""
|
||||
获取用户组信息。
|
||||
|
||||
:param id: 用户组ID,默认为 None
|
||||
:type id: int
|
||||
|
||||
:return: 用户组对象或 None
|
||||
:rtype: Optional[Group]
|
||||
"""
|
||||
from .database import get_session
|
||||
from sqlmodel import select
|
||||
|
||||
session = get_session()
|
||||
|
||||
new_group = Group(
|
||||
name=name,
|
||||
policies=policies,
|
||||
max_storage=max_storage,
|
||||
share_enabled=share_enabled,
|
||||
web_dav_enabled=web_dav_enabled,
|
||||
speed_limit=speed_limit,
|
||||
options=options
|
||||
)
|
||||
session.add(new_group)
|
||||
if id is None:
|
||||
return None
|
||||
|
||||
session.commit()
|
||||
session.refresh(new_group)
|
||||
async for session in get_session():
|
||||
statement = select(Group).where(Group.id == id)
|
||||
result = await session.exec(statement)
|
||||
group = result.one_or_none()
|
||||
|
||||
if group:
|
||||
return group
|
||||
else:
|
||||
return None
|
||||
@@ -113,4 +113,55 @@ async def init_default_settings() -> None:
|
||||
type=setting.type,
|
||||
name=setting.name,
|
||||
value=setting.value
|
||||
)
|
||||
)
|
||||
|
||||
async def init_default_group() -> None:
|
||||
from .group import Group
|
||||
|
||||
try:
|
||||
# 未找到初始管理组时,则创建
|
||||
if not Group.get(id=1):
|
||||
Group.add(
|
||||
name="管理员",
|
||||
max_storage=1 * 1024 * 1024 * 1024, # 1GB
|
||||
share_enabled=True,
|
||||
web_dav_enabled=True,
|
||||
options={
|
||||
"ArchiveDownload": True,
|
||||
"ArchiveTask": True,
|
||||
"ShareDownload": True,
|
||||
"Aria2": True,
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"无法创建管理员用户组: {e}") from e
|
||||
|
||||
try:
|
||||
# 未找到初始注册会员时,则创建
|
||||
if not Group.get(id=2):
|
||||
Group.add(
|
||||
name="注册会员",
|
||||
max_storage=1 * 1024 * 1024 * 1024, # 1GB
|
||||
share_enabled=True,
|
||||
web_dav_enabled=True,
|
||||
options={
|
||||
"ShareDownload": True,
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"无法创建初始注册会员用户组: {e}") from e
|
||||
|
||||
try:
|
||||
# 未找到初始游客组时,则创建
|
||||
if not Group.get(id=3):
|
||||
Group.add(
|
||||
name="游客",
|
||||
policies="[]",
|
||||
share_enabled=False,
|
||||
web_dav_enabled=False,
|
||||
options={
|
||||
"ShareDownload": True,
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"无法创建初始游客用户组: {e}") from e
|
||||
|
||||
@@ -71,6 +71,7 @@ class Setting(BaseModel, table=True):
|
||||
),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def add(
|
||||
type: SETTINGS_TYPE = None,
|
||||
name: str = None,
|
||||
@@ -97,6 +98,7 @@ class Setting(BaseModel, table=True):
|
||||
|
||||
await session.commit()
|
||||
|
||||
@staticmethod
|
||||
async def get(
|
||||
type: SETTINGS_TYPE,
|
||||
name: str,
|
||||
@@ -138,6 +140,7 @@ class Setting(BaseModel, table=True):
|
||||
else:
|
||||
raise ValueError(f"Unsupported format: {format}")
|
||||
|
||||
@staticmethod
|
||||
async def set(
|
||||
type: SETTINGS_TYPE,
|
||||
name: str,
|
||||
@@ -177,6 +180,7 @@ class Setting(BaseModel, table=True):
|
||||
setting.value = value
|
||||
await session.commit()
|
||||
|
||||
@staticmethod
|
||||
async def delete(
|
||||
type: SETTINGS_TYPE,
|
||||
name: str
|
||||
|
||||
@@ -86,4 +86,25 @@ class User(BaseModel, table=True):
|
||||
storage_packs: list["StoragePack"] = Relationship(back_populates="user")
|
||||
tags: list["Tag"] = Relationship(back_populates="user")
|
||||
tasks: list["Task"] = Relationship(back_populates="user")
|
||||
webdavs: list["WebDAV"] = Relationship(back_populates="user")
|
||||
webdavs: list["WebDAV"] = Relationship(back_populates="user")
|
||||
|
||||
async def create(
|
||||
user: "User"
|
||||
):
|
||||
"""
|
||||
向数据库内添加用户。
|
||||
|
||||
:param user: User 实例
|
||||
:type user: User
|
||||
"""
|
||||
from .database import get_session
|
||||
|
||||
async for session in get_session():
|
||||
try:
|
||||
session.add(user)
|
||||
await session.commit()
|
||||
await session.refresh(user)
|
||||
except Exception as e:
|
||||
await session.rollback()
|
||||
raise e
|
||||
return user
|
||||
@@ -1,4 +1,5 @@
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from models.setting import Setting
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(
|
||||
scheme_name='获取 JWT Bearer 令牌',
|
||||
@@ -6,4 +7,14 @@ oauth2_scheme = OAuth2PasswordBearer(
|
||||
tokenUrl="/api/user/session",
|
||||
)
|
||||
|
||||
SECRET_KEY = ''
|
||||
SECRET_KEY = ''
|
||||
|
||||
async def load_secret_key() -> None:
|
||||
"""
|
||||
从数据库读取 JWT 的密钥。
|
||||
|
||||
:param key: 用于加密和解密 JWT 的密钥
|
||||
:type key: str
|
||||
"""
|
||||
global SECRET_KEY
|
||||
SECRET_KEY = await Setting.get(type='auth', name='secret_key')
|
||||
@@ -70,7 +70,7 @@ def router_admin_get_summary() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含站点概况信息的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_router.get(
|
||||
path='/news',
|
||||
@@ -85,7 +85,7 @@ def router_admin_get_news() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含社区新闻信息的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_router.patch(
|
||||
path='/settings',
|
||||
@@ -100,7 +100,7 @@ def router_admin_update_settings() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含更新结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_router.get(
|
||||
path='/settings',
|
||||
@@ -115,7 +115,7 @@ def router_admin_get_settings() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含站点设置的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_group_router.get(
|
||||
path='/',
|
||||
@@ -130,7 +130,7 @@ def router_admin_get_groups() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含用户组列表的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_group_router.get(
|
||||
path='/{group_id}',
|
||||
@@ -148,7 +148,7 @@ def router_admin_get_group(group_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含用户组信息的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_group_router.get(
|
||||
path='/list/{group_id}',
|
||||
@@ -172,7 +172,7 @@ def router_admin_get_group_members(
|
||||
Returns:
|
||||
ResponseModel: 包含用户组成员列表的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_group_router.post(
|
||||
path='/',
|
||||
@@ -187,7 +187,7 @@ def router_admin_create_group() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含创建结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_group_router.patch(
|
||||
path='/{group_id}',
|
||||
@@ -205,7 +205,7 @@ def router_admin_update_group(group_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含更新结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_group_router.delete(
|
||||
path='/{group_id}',
|
||||
@@ -223,7 +223,7 @@ def router_admin_delete_group(group_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含删除结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_user_router.get(
|
||||
path='/info/{user_id}',
|
||||
@@ -241,7 +241,7 @@ def router_admin_get_user(user_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含用户信息的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_user_router.get(
|
||||
path='/list',
|
||||
@@ -263,7 +263,7 @@ def router_admin_get_users(
|
||||
Returns:
|
||||
ResponseModel: 包含用户列表的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_user_router.post(
|
||||
path='/create',
|
||||
@@ -278,7 +278,7 @@ def router_admin_create_user() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含创建结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_user_router.patch(
|
||||
path='/{user_id}',
|
||||
@@ -296,7 +296,7 @@ def router_admin_update_user(user_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含更新结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_user_router.delete(
|
||||
path='/{user_id}',
|
||||
@@ -314,7 +314,7 @@ def router_admin_delete_user(user_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含删除结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_user_router.post(
|
||||
path='/calibrate/{user_id}',
|
||||
@@ -323,7 +323,7 @@ def router_admin_delete_user(user_id: int) -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_admin_calibrate_storage():
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_file_router.get(
|
||||
path='/list',
|
||||
@@ -338,7 +338,7 @@ def router_admin_get_file_list() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含文件列表的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_file_router.get(
|
||||
path='/preview/{file_id}',
|
||||
@@ -356,7 +356,7 @@ def router_admin_preview_file(file_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含文件预览内容的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_file_router.patch(
|
||||
path='/ban/{file_id}',
|
||||
@@ -376,7 +376,7 @@ def router_admin_ban_file(file_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含删除结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_file_router.delete(
|
||||
path='/{file_id}',
|
||||
@@ -394,7 +394,7 @@ def router_admin_delete_file(file_id: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: 包含删除结果的响应模型。
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_aria2_router.post(
|
||||
path='/test',
|
||||
@@ -403,7 +403,7 @@ def router_admin_delete_file(file_id: int) -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_admin_aira2_test() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.get(
|
||||
path='/list',
|
||||
@@ -412,7 +412,7 @@ def router_admin_aira2_test() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_list() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.post(
|
||||
path='/test/path',
|
||||
@@ -421,7 +421,7 @@ def router_policy_list() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_test_path() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.post(
|
||||
path='/test/slave',
|
||||
@@ -430,7 +430,7 @@ def router_policy_test_path() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_test_slave() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.post(
|
||||
path='/',
|
||||
@@ -439,7 +439,7 @@ def router_policy_test_slave() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_add_policy() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.post(
|
||||
path='/cors',
|
||||
@@ -448,7 +448,7 @@ def router_policy_add_policy() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_add_cors() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.post(
|
||||
path='/scf',
|
||||
@@ -457,7 +457,7 @@ def router_policy_add_cors() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_add_scf() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.get(
|
||||
path='/{id}/oauth',
|
||||
@@ -466,7 +466,7 @@ def router_policy_add_scf() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_onddrive_oauth() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.get(
|
||||
path='/{id}',
|
||||
@@ -475,7 +475,7 @@ def router_policy_onddrive_oauth() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_get_policy() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
|
||||
@admin_policy_router.delete(
|
||||
path='/{id}',
|
||||
@@ -484,4 +484,4 @@ def router_policy_get_policy() -> ResponseModel:
|
||||
dependencies=[Depends(AdminRequired)]
|
||||
)
|
||||
def router_policy_delete_policy() -> ResponseModel:
|
||||
...
|
||||
pass
|
||||
@@ -20,7 +20,7 @@ def router_aria2_url() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the URL download task.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@aria2_router.post(
|
||||
path='/torrent/{id}',
|
||||
@@ -38,7 +38,7 @@ def router_aria2_torrent(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the torrent download task.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@aria2_router.put(
|
||||
path='/select/{gid}',
|
||||
@@ -56,7 +56,7 @@ def router_aria2_select(gid: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the re-selection of files.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@aria2_router.delete(
|
||||
path='/task/{gid}',
|
||||
@@ -74,7 +74,7 @@ def router_aria2_delete(gid: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the deletion of the download task.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@aria2_router.get(
|
||||
'/downloading',
|
||||
@@ -89,7 +89,7 @@ def router_aria2_downloading() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for currently downloading tasks.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@aria2_router.get(
|
||||
path='/finished',
|
||||
@@ -104,4 +104,4 @@ def router_aria2_finished() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for finished tasks.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -39,7 +39,7 @@ def router_callback_qq() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the QQ OAuth callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@oauth_router.post(
|
||||
path='/github',
|
||||
@@ -53,7 +53,7 @@ def router_callback_github() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the GitHub OAuth callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@pay_router.post(
|
||||
path='/alipay',
|
||||
@@ -67,7 +67,7 @@ def router_callback_alipay() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Alipay payment callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@pay_router.post(
|
||||
path='/wechat',
|
||||
@@ -81,7 +81,7 @@ def router_callback_wechat() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the WeChat Pay payment callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@pay_router.post(
|
||||
path='/stripe',
|
||||
@@ -95,7 +95,7 @@ def router_callback_stripe() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Stripe payment callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@pay_router.get(
|
||||
path='/easypay',
|
||||
@@ -109,7 +109,7 @@ def router_callback_easypay() -> PlainTextResponse:
|
||||
Returns:
|
||||
PlainTextResponse: A response containing the payment status for the EasyPay payment callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
# return PlainTextResponse("success", status_code=200)
|
||||
|
||||
@pay_router.get(
|
||||
@@ -128,7 +128,7 @@ def router_callback_custom(order_no: str, id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the custom payment callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/remote/{session_id}/{key}',
|
||||
@@ -146,7 +146,7 @@ def router_callback_remote(session_id: str, key: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the remote upload callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/qiniu/{session_id}',
|
||||
@@ -163,7 +163,7 @@ def router_callback_qiniu(session_id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Qiniu Cloud upload callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/tencent/{session_id}',
|
||||
@@ -180,7 +180,7 @@ def router_callback_tencent(session_id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Tencent Cloud upload callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/aliyun/{session_id}',
|
||||
@@ -197,7 +197,7 @@ def router_callback_aliyun(session_id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Aliyun upload callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/upyun/{session_id}',
|
||||
@@ -214,7 +214,7 @@ def router_callback_upyun(session_id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Upyun upload callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/aws/{session_id}',
|
||||
@@ -231,7 +231,7 @@ def router_callback_aws(session_id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the AWS S3 upload callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.post(
|
||||
path='/onedrive/finish/{session_id}',
|
||||
@@ -248,7 +248,7 @@ def router_callback_onedrive_finish(session_id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the OneDrive upload completion callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.get(
|
||||
path='/ondrive/auth',
|
||||
@@ -262,7 +262,7 @@ def router_callback_onedrive_auth() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the OneDrive authorization callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@upload_router.get(
|
||||
path='/google/auth',
|
||||
@@ -276,4 +276,4 @@ def router_callback_google_auth() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Google OAuth completion callback.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -20,7 +20,7 @@ def router_directory_create() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the directory creation.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@directory_router.get(
|
||||
path='/{path:path}',
|
||||
@@ -38,4 +38,4 @@ def router_directory_get(path: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the directory contents.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -1,4 +1,5 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, UploadFile
|
||||
from fastapi.responses import FileResponse
|
||||
from middleware.auth import SignRequired
|
||||
from models.response import ResponseModel
|
||||
|
||||
@@ -17,7 +18,7 @@ file_upload_router = APIRouter(
|
||||
summary='文件外链(直接输出文件数据)',
|
||||
description='Get file external link endpoint.',
|
||||
)
|
||||
def router_file_get(id: str, name: str) -> ResponseModel:
|
||||
def router_file_get(id: str, name: str) -> FileResponse:
|
||||
"""
|
||||
Get file external link endpoint.
|
||||
|
||||
@@ -26,9 +27,9 @@ def router_file_get(id: str, name: str) -> ResponseModel:
|
||||
name (str): The name of the file.
|
||||
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file.
|
||||
FileResponse: A response containing the file data.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.get(
|
||||
path='/source/{id}/{name}',
|
||||
@@ -46,7 +47,7 @@ def router_file_source(id: str, name: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file with a redirect.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_upload_router.get(
|
||||
path='/download/{id}',
|
||||
@@ -63,7 +64,7 @@ def router_file_download(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file download.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_upload_router.get(
|
||||
path='/archive/{sessionID}/archive.zip',
|
||||
@@ -80,14 +81,14 @@ def router_file_archive_download(sessionID: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the archived files download.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_upload_router.post(
|
||||
path='/{sessionID}/{index}',
|
||||
summary='文件上传',
|
||||
description='File upload endpoint.',
|
||||
)
|
||||
def router_file_upload(sessionID: str, index: int) -> ResponseModel:
|
||||
def router_file_upload(sessionID: str, index: int, file: UploadFile) -> ResponseModel:
|
||||
"""
|
||||
File upload endpoint.
|
||||
|
||||
@@ -98,7 +99,7 @@ def router_file_upload(sessionID: str, index: int) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_upload_router.put(
|
||||
path='/',
|
||||
@@ -113,7 +114,7 @@ def router_file_upload_session() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the upload session.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_upload_router.delete(
|
||||
path='/{sessionID}',
|
||||
@@ -131,7 +132,7 @@ def router_file_upload_session_delete(sessionID: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the deletion.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_upload_router.delete(
|
||||
path='/',
|
||||
@@ -146,7 +147,7 @@ def router_file_upload_session_clear() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for clearing all sessions.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.put(
|
||||
path='/update/{id}',
|
||||
@@ -164,7 +165,7 @@ def router_file_update(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file update.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.post(
|
||||
path='/create',
|
||||
@@ -179,7 +180,7 @@ def router_file_create() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file creation.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.put(
|
||||
path='/download/{id}',
|
||||
@@ -197,7 +198,7 @@ def router_file_download(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file download session.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.get(
|
||||
path='/preview/{id}',
|
||||
@@ -215,7 +216,7 @@ def router_file_preview(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file preview.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.get(
|
||||
path='/content/{id}',
|
||||
@@ -233,7 +234,7 @@ def router_file_content(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the text file content.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.get(
|
||||
path='/doc/{id}',
|
||||
@@ -251,7 +252,7 @@ def router_file_doc(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the Office document preview URL.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.get(
|
||||
path='/thumb/{id}',
|
||||
@@ -269,7 +270,7 @@ def router_file_thumb(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file thumbnail.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.post(
|
||||
path='/source/{id}',
|
||||
@@ -287,7 +288,7 @@ def router_file_source(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file external link.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.post(
|
||||
path='/archive',
|
||||
@@ -305,7 +306,7 @@ def router_file_archive(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the archived files.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.post(
|
||||
path='/compress',
|
||||
@@ -323,7 +324,7 @@ def router_file_compress(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file compression task.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.post(
|
||||
path='/decompress',
|
||||
@@ -341,7 +342,7 @@ def router_file_decompress(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file extraction task.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.post(
|
||||
path='/relocate',
|
||||
@@ -359,7 +360,7 @@ def router_file_relocate(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file relocation task.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@file_router.get(
|
||||
path='/search/{type}/{keyword}',
|
||||
@@ -378,4 +379,4 @@ def router_file_search(type: str, keyword: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the file search.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -20,7 +20,7 @@ def router_object_delete() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the object deletion.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@object_router.patch(
|
||||
path='/',
|
||||
@@ -35,7 +35,7 @@ def router_object_move() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the object move.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@object_router.post(
|
||||
path='/copy',
|
||||
@@ -50,7 +50,7 @@ def router_object_copy() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the object copy.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@object_router.post(
|
||||
path='/rename',
|
||||
@@ -65,7 +65,7 @@ def router_object_rename() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the object rename.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@object_router.get(
|
||||
path='/property/{id}',
|
||||
@@ -83,4 +83,4 @@ def router_object_property(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the object properties.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -23,7 +23,7 @@ def router_share_get(info: str, id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing shared content information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.put(
|
||||
path='/download/{id}',
|
||||
@@ -40,7 +40,7 @@ def router_share_download(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing download session information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='preview/{id}',
|
||||
@@ -57,7 +57,7 @@ def router_share_preview(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing preview information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/doc/{id}',
|
||||
@@ -74,7 +74,7 @@ def router_share_doc(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing the document preview URL.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/content/{id}',
|
||||
@@ -91,7 +91,7 @@ def router_share_content(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
str: The content of the text file.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/list/{id}/{path:path}',
|
||||
@@ -109,7 +109,7 @@ def router_share_list(id: str, path: str = '') -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing directory listing information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/search/{id}/{type}/{keywords}',
|
||||
@@ -128,7 +128,7 @@ def router_share_search(id: str, type: str, keywords: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing search results.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.post(
|
||||
path='/archive/{id}',
|
||||
@@ -145,7 +145,7 @@ def router_share_archive(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing archive download information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/readme/{id}',
|
||||
@@ -162,7 +162,7 @@ def router_share_readme(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
str: The content of the README file.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/thumb/{id}/{file}',
|
||||
@@ -180,7 +180,7 @@ def router_share_thumb(id: str, file: str) -> ResponseModel:
|
||||
Returns:
|
||||
str: A Base64 encoded string of the thumbnail image.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.post(
|
||||
path='/report/{id}',
|
||||
@@ -197,7 +197,7 @@ def router_share_report(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing report submission information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/search',
|
||||
@@ -215,7 +215,7 @@ def router_share_search_public(keywords: str, type: str = 'all') -> ResponseMode
|
||||
Returns:
|
||||
dict: A dictionary containing search results for public shares.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
#####################
|
||||
# 需要登录的接口
|
||||
@@ -234,7 +234,7 @@ def router_share_create() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the new share creation.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.get(
|
||||
path='/',
|
||||
@@ -249,7 +249,7 @@ def router_share_list() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the list of shares.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.post(
|
||||
path='/save/{id}',
|
||||
@@ -267,7 +267,7 @@ def router_share_save(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the saved share.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.patch(
|
||||
path='/{id}',
|
||||
@@ -285,7 +285,7 @@ def router_share_update(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the updated share.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@share_router.delete(
|
||||
path='/{id}',
|
||||
@@ -303,4 +303,4 @@ def router_share_delete(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the deleted share.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -34,7 +34,7 @@ def router_site_captcha():
|
||||
Returns:
|
||||
str: A Base64 encoded string of the captcha image.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@site_router.get(
|
||||
path='/config',
|
||||
|
||||
@@ -44,7 +44,7 @@ def router_slave_post(data: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model indicating success.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_router.get(
|
||||
path='/get/{speed}/{path}/{name}',
|
||||
@@ -62,7 +62,7 @@ def router_slave_download(speed: int, path: str, name: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model containing download information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_router.get(
|
||||
path='/download/{sign}',
|
||||
@@ -80,7 +80,7 @@ def router_slave_download_by_sign(sign: str) -> FileResponse:
|
||||
Returns:
|
||||
FileResponse: A response containing the file to be downloaded.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_router.get(
|
||||
path='/source/{speed}/{path}/{name}',
|
||||
@@ -100,7 +100,7 @@ def router_slave_source(speed: int, path: str, name: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model containing the external link for the file.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_router.get(
|
||||
path='/source/{sign}',
|
||||
@@ -118,7 +118,7 @@ def router_slave_source_by_sign(sign: str) -> FileResponse:
|
||||
Returns:
|
||||
FileResponse: A response containing the file to be retrieved.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_router.get(
|
||||
path='/thumb/{id}',
|
||||
@@ -136,7 +136,7 @@ def router_slave_thumb(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model containing the Base64 encoded thumbnail image.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_router.delete(
|
||||
path='/delete',
|
||||
@@ -154,7 +154,7 @@ def router_slave_delete(path: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model indicating success or failure of the deletion.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_aria2_router.post(
|
||||
path='/test',
|
||||
@@ -166,7 +166,7 @@ def router_slave_aria2_test() -> ResponseModel:
|
||||
"""
|
||||
Test the connection to the Aria2 service from the slave.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_aria2_router.get(
|
||||
path='/get/{gid}',
|
||||
@@ -184,7 +184,7 @@ def router_slave_aria2_get(gid: str = None) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model containing the task information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_aria2_router.post(
|
||||
path='/add',
|
||||
@@ -204,7 +204,7 @@ def router_slave_aria2_add(gid: str, url: str, options: dict = None) -> Response
|
||||
Returns:
|
||||
ResponseModel: A response model indicating success or failure of the task addition.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@slave_aria2_router.delete(
|
||||
path='/remove/{gid}',
|
||||
@@ -222,4 +222,4 @@ def router_slave_aria2_remove(gid: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A response model indicating success or failure of the task removal.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -20,7 +20,7 @@ def router_tag_create_filter() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the created tag.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@tag_router.post(
|
||||
path='/link',
|
||||
@@ -35,7 +35,7 @@ def router_tag_create_link() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the created tag.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@tag_router.delete(
|
||||
path='/{id}',
|
||||
@@ -53,4 +53,4 @@ def router_tag_delete(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the deletion operation.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -25,7 +25,7 @@ def router_user_session() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing user session information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.post(
|
||||
path='/',
|
||||
@@ -39,7 +39,7 @@ def router_user_register() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing user registration information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.post(
|
||||
path='/2fa',
|
||||
@@ -53,7 +53,7 @@ def router_user_2fa() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing two-factor authentication information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.post(
|
||||
path='/reset',
|
||||
@@ -67,7 +67,7 @@ def router_user_reset() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing information about the password reset email.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.patch(
|
||||
path='/reset',
|
||||
@@ -81,7 +81,7 @@ def router_user_reset_patch() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing information about the password reset.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.get(
|
||||
path='/qq',
|
||||
@@ -95,7 +95,7 @@ def router_user_qq() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing QQ login initialization information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.get(
|
||||
path='/activate/{id}',
|
||||
@@ -112,7 +112,7 @@ def router_user_activate(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing activation information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.get(
|
||||
path='authn/{username}',
|
||||
@@ -129,7 +129,7 @@ def router_user_authn(username: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing WebAuthn initialization information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.post(
|
||||
path='authn/finish/{username}',
|
||||
@@ -146,7 +146,7 @@ def router_user_authn_finish(username: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing WebAuthn login information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.get(
|
||||
path='/profile/{id}',
|
||||
@@ -163,7 +163,7 @@ def router_user_profile(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing user profile information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.get(
|
||||
path='/avatar/{id}/{size}',
|
||||
@@ -181,7 +181,7 @@ def router_user_avatar(id: str, size: int = 128) -> ResponseModel:
|
||||
Returns:
|
||||
str: A Base64 encoded string of the user avatar image.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
#####################
|
||||
# 需要登录的接口
|
||||
@@ -200,7 +200,7 @@ def router_user_me() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing user information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.get(
|
||||
path='/storage',
|
||||
@@ -215,7 +215,7 @@ def router_user_storage() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing user storage information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.put(
|
||||
path='/authn/start',
|
||||
@@ -230,7 +230,7 @@ def router_user_authn_start() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing WebAuthn initialization information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_router.put(
|
||||
path='/authn/finish',
|
||||
@@ -245,7 +245,7 @@ def router_user_authn_finish() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing WebAuthn login information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.get(
|
||||
path='/policies',
|
||||
@@ -259,7 +259,7 @@ def router_user_settings_policies() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing available storage policies for the user.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.get(
|
||||
path='/nodes',
|
||||
@@ -274,7 +274,7 @@ def router_user_settings_nodes() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing available nodes for the user.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.get(
|
||||
path='/tasks',
|
||||
@@ -289,7 +289,7 @@ def router_user_settings_tasks() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing the user's task queue information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.get(
|
||||
path='/',
|
||||
@@ -304,7 +304,7 @@ def router_user_settings() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing the user's current settings.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.post(
|
||||
path='/avatar',
|
||||
@@ -319,7 +319,7 @@ def router_user_settings_avatar() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing the result of the avatar upload.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.put(
|
||||
path='/avatar',
|
||||
@@ -334,7 +334,7 @@ def router_user_settings_avatar_gravatar() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing the result of setting the Gravatar avatar.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.patch(
|
||||
path='/{option}',
|
||||
@@ -352,7 +352,7 @@ def router_user_settings_patch(option: str) -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing the result of the settings update.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@user_settings_router.get(
|
||||
path='/2fa',
|
||||
@@ -367,4 +367,4 @@ def router_user_settings_2fa() -> ResponseModel:
|
||||
Returns:
|
||||
dict: A dictionary containing two-factor authentication setup information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -20,7 +20,7 @@ def router_vas_pack() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for storage packs and quotas.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@vas_router.get(
|
||||
path='/product',
|
||||
@@ -35,7 +35,7 @@ def router_vas_product() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for products and payment information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@vas_router.post(
|
||||
path='/order',
|
||||
@@ -50,7 +50,7 @@ def router_vas_order() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the created order.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@vas_router.get(
|
||||
path='/order/{id}',
|
||||
@@ -68,7 +68,7 @@ def router_vas_order_get(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the specified order.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@vas_router.get(
|
||||
path='/redeem',
|
||||
@@ -86,7 +86,7 @@ def router_vas_redeem(code: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the specified redemption code.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@vas_router.post(
|
||||
path='/redeem',
|
||||
@@ -101,4 +101,4 @@ def router_vas_redeem_post() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the redeemed code.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
@@ -21,7 +21,7 @@ def router_webdav_accounts() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the account information.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@webdav_router.post(
|
||||
path='/accounts',
|
||||
@@ -36,7 +36,7 @@ def router_webdav_create_account() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the created account.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@webdav_router.delete(
|
||||
path='/accounts/{id}',
|
||||
@@ -54,7 +54,7 @@ def router_webdav_delete_account(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the deletion operation.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@webdav_router.post(
|
||||
path='/mount',
|
||||
@@ -69,7 +69,7 @@ def router_webdav_create_mount() -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the created mount point.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@webdav_router.delete(
|
||||
path='/mount/{id}',
|
||||
@@ -87,7 +87,7 @@ def router_webdav_delete_mount(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the deletion operation.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
|
||||
@webdav_router.patch(
|
||||
path='accounts/{id}',
|
||||
@@ -105,4 +105,4 @@ def router_webdav_update_account(id: str) -> ResponseModel:
|
||||
Returns:
|
||||
ResponseModel: A model containing the response data for the updated account.
|
||||
"""
|
||||
...
|
||||
pass
|
||||
15
service/user/login.py
Normal file
15
service/user/login.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from models.setting import Setting
|
||||
|
||||
async def login(
|
||||
username: str,
|
||||
password: str
|
||||
):
|
||||
"""
|
||||
"""
|
||||
|
||||
isCaptchaRequired = await Setting.get(type='auth', name='login_captcha', type=bool)
|
||||
captchaType = await Setting.get(type='auth', name='captcha_type', type=str)
|
||||
|
||||
# [TODO] 验证码校验
|
||||
|
||||
|
||||
@@ -25,52 +25,4 @@ async def test_initialize_db():
|
||||
|
||||
await database.init_db(url='sqlite:///:memory:')
|
||||
|
||||
await migration.init_default_settings()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_settings():
|
||||
"""测试数据库的增删改查"""
|
||||
from models import database
|
||||
from models.setting import Setting
|
||||
|
||||
await database.init_db(url='sqlite:///:memory:')
|
||||
|
||||
# 测试增 Create
|
||||
await Setting.add(
|
||||
type='example_type',
|
||||
name='example_name',
|
||||
value='example_value')
|
||||
|
||||
# 测试查 Read
|
||||
setting = await Setting.get(
|
||||
type='example_type',
|
||||
name='example_name')
|
||||
|
||||
assert setting is not None, "设置项应该存在"
|
||||
assert setting.value == 'example_value', "设置值不匹配"
|
||||
|
||||
# 测试改 Update
|
||||
await Setting.set(
|
||||
type='example_type',
|
||||
name='example_name',
|
||||
value='updated_value')
|
||||
|
||||
after_update_setting = await Setting.get(
|
||||
type='example_type',
|
||||
name='example_name'
|
||||
)
|
||||
|
||||
assert after_update_setting is not None, "设置项应该存在"
|
||||
assert after_update_setting.value == 'updated_value', "更新后的设置值不匹配"
|
||||
|
||||
# 测试删 Delete
|
||||
await Setting.delete(
|
||||
type='example_type',
|
||||
name='example_name')
|
||||
|
||||
after_delete_setting = await Setting.get(
|
||||
type='example_type',
|
||||
name='example_name'
|
||||
)
|
||||
|
||||
assert after_delete_setting is None, "设置项应该被删除"
|
||||
await migration.init_default_settings()
|
||||
49
tests/test_db_settings.py
Normal file
49
tests/test_db_settings.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import pytest
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_settings_curd():
|
||||
"""测试数据库的增删改查"""
|
||||
from models import database
|
||||
from models.setting import Setting
|
||||
|
||||
await database.init_db(url='sqlite:///:memory:')
|
||||
|
||||
# 测试增 Create
|
||||
await Setting.add(
|
||||
type='example_type',
|
||||
name='example_name',
|
||||
value='example_value')
|
||||
|
||||
# 测试查 Read
|
||||
setting = await Setting.get(
|
||||
type='example_type',
|
||||
name='example_name')
|
||||
|
||||
assert setting is not None, "设置项应该存在"
|
||||
assert setting == 'example_value', "设置值不匹配"
|
||||
|
||||
# 测试改 Update
|
||||
await Setting.set(
|
||||
type='example_type',
|
||||
name='example_name',
|
||||
value='updated_value')
|
||||
|
||||
after_update_setting = await Setting.get(
|
||||
type='example_type',
|
||||
name='example_name'
|
||||
)
|
||||
|
||||
assert after_update_setting is not None, "设置项应该存在"
|
||||
assert after_update_setting == 'updated_value', "更新后的设置值不匹配"
|
||||
|
||||
# 测试删 Delete
|
||||
await Setting.delete(
|
||||
type='example_type',
|
||||
name='example_name')
|
||||
|
||||
after_delete_setting = await Setting.get(
|
||||
type='example_type',
|
||||
name='example_name'
|
||||
)
|
||||
|
||||
assert after_delete_setting is None, "设置项应该被删除"
|
||||
29
tests/test_db_user.py
Normal file
29
tests/test_db_user.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import pytest
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_user_curd():
|
||||
"""测试数据库的增删改查"""
|
||||
from models import database
|
||||
from models.group import Group
|
||||
from models.user import User
|
||||
|
||||
await database.init_db(url='sqlite:///:memory:')
|
||||
|
||||
# 新建一个测试用户组
|
||||
test_group = Group(name='test_group')
|
||||
created_group = await Group.create(test_group)
|
||||
|
||||
test_user = User(
|
||||
email='test_user',
|
||||
password='test_password',
|
||||
group_id=created_group.id
|
||||
)
|
||||
|
||||
# 测试增 Create
|
||||
created_user = await User.create(test_user)
|
||||
|
||||
# 验证用户是否存在
|
||||
assert created_user.id is not None
|
||||
assert created_user.email == 'test_user'
|
||||
assert created_user.password == 'test_password'
|
||||
assert created_user.group_id == created_group.id
|
||||
Reference in New Issue
Block a user