diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..267ca8b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+__pycache__/
+.pytest_cache/
+.venv/
+.env/
+.vscode/
+.VSCodeCounter/
+
+*.py[cod]
+*.pyo
+*.pyd
+
+*.code-workspace
\ No newline at end of file
diff --git a/README.md b/README.md
index 929150e..8b8033a 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,27 @@
-# Server
-DiskNext 服务端。支持多家云存储的公私兼备的网盘系统。
+
+
+ DiskNext Server
+
+
+
+支持多家云存储的公私兼备的云服务系统.
+
+本来此项目并没有这么快开始,但由于我曾经使用过的某个类似产品的作者吃相实在难看,故决定自己实现一个。
+
+此项目的愿景是集百家之长(Cloudreve + Alist + FnOS)。你也可以考虑付费支持我们的发展 -> `DiskNext Pro`.
+
+目前正处于 `OMEGA` 实验阶段,比 `Alpha` 版还更早期,仅供测试。
+
+## :alembic: 技术栈
+
+* [Python ](https://www.python.org/) + [FastAPI](https://fastapi.tiangolo.com/)
+
+
+
+## :scroll: 许可证
+
+GPL V3
+
+---
+> GitHub [@Yuerchu](https://github.com/Yuerchu) ·
+> Twitter [@LaBoyXiaoXin](https://twitter.com/LaBoyXiaoXin)
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..84e0456
--- /dev/null
+++ b/main.py
@@ -0,0 +1,29 @@
+from fastapi import FastAPI
+from routers import routers
+from pkg.conf import appmeta
+
+app = FastAPI(
+ title=appmeta.APP_NAME,
+ summary=appmeta.summary,
+ description=appmeta.description,
+ version=appmeta.BackendVersion,
+ openapi_tags=appmeta.tags_meta,
+ license_info=appmeta.license_info,
+
+)
+
+for router in routers.Router:
+ app.include_router(
+ router,
+ prefix='/api',
+ responses={
+ 200: {"description": "成功响应 Successful operation"},
+ 401: {"description": "未授权 Unauthorized"},
+ 403: {"description": "禁止访问 Forbidden"},
+ 404: {"description": "未找到 Not found"},
+ 500: {"description": "内部服务器错误 Internal server error"}
+ },)
+
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run(app='main:app', host="0.0.0.0", port=5213, reload=True)
\ No newline at end of file
diff --git a/middleware/auth.py b/middleware/auth.py
new file mode 100644
index 0000000..69ac55c
--- /dev/null
+++ b/middleware/auth.py
@@ -0,0 +1,30 @@
+from typing import Annotated, Literal
+from fastapi import Depends
+from pkg.JWT import jwt
+
+async def AuthRequired(
+ token: Annotated[str, Depends(jwt.oauth2_scheme)]
+) -> Literal[True]:
+ '''
+ AuthRequired 需要登录
+ '''
+ return True
+
+async def SignRequired(
+ token: Annotated[str, Depends(jwt.oauth2_scheme)]
+) -> Literal[True]:
+ '''
+ SignAuthRequired 需要登录并验证请求签名
+ '''
+ return True
+
+async def AdminRequired(
+ token: Annotated[str, Depends(jwt.oauth2_scheme)]
+) -> Literal[True]:
+ '''
+ 验证是否为管理员。
+
+ 使用方法:
+ >>> APIRouter(dependencies=[Depends(is_admin)])
+ '''
+ ...
\ No newline at end of file
diff --git a/models/model.py b/models/model.py
new file mode 100644
index 0000000..cd6f7e2
--- /dev/null
+++ b/models/model.py
@@ -0,0 +1,215 @@
+from datetime import datetime
+from sqlalchemy import Column, Integer, String, Text, BigInteger, Boolean, DateTime, ForeignKey
+from sqlalchemy.ext.declarative import declarative_base
+
+Base = declarative_base()
+
+class BaseModel(Base):
+ __abstract__ = True
+
+ id = Column(Integer, primary_key=True, autoincrement=True)
+ created_at = Column(DateTime, default=datetime.now)
+ updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
+ deleted_at = Column(DateTime, nullable=True)
+
+class Download(BaseModel):
+ __tablename__ = 'downloads'
+
+ status = Column(Integer, nullable=True)
+ type = Column(Integer, nullable=True)
+ source = Column(Text, nullable=True)
+ total_size = Column(BigInteger, nullable=True)
+ downloaded_size = Column(BigInteger, nullable=True)
+ g_id = Column(Text, nullable=True)
+ speed = Column(Integer, nullable=True)
+ parent = Column(Text, nullable=True)
+ attrs = Column(Text, nullable=True)
+ error = Column(Text, nullable=True)
+ dst = Column(Text, nullable=True)
+ user_id = Column(Integer, nullable=True)
+ task_id = Column(Integer, nullable=True)
+ node_id = Column(Integer, nullable=True)
+
+class File(BaseModel):
+ __tablename__ = 'files'
+
+ name = Column(String(255), nullable=True)
+ source_name = Column(Text, nullable=True)
+ user_id = Column(Integer, nullable=True)
+ size = Column(BigInteger, nullable=True)
+ pic_info = Column(String(255), nullable=True)
+ folder_id = Column(Integer, nullable=True)
+ policy_id = Column(Integer, nullable=True)
+ upload_session_id = Column(String(255), nullable=True, unique=True)
+ metadata = Column(Text, nullable=True)
+
+class Folder(BaseModel):
+ __tablename__ = 'folders'
+
+ name = Column(String(255), nullable=True)
+ parent_id = Column(Integer, nullable=True, index=True)
+ owner_id = Column(Integer, nullable=True, index=True)
+ policy_id = Column(Integer, nullable=True)
+
+ __table_args__ = {'uniqueConstraints': [('name', 'parent_id')]}
+
+class Group(BaseModel):
+ __tablename__ = 'groups'
+
+ name = Column(String(255), nullable=True)
+ policies = Column(String(255), nullable=True)
+ max_storage = Column(BigInteger, nullable=True)
+ share_enabled = Column(Boolean, nullable=True)
+ web_dav_enabled = Column(Boolean, nullable=True)
+ speed_limit = Column(Integer, nullable=True)
+ options = Column(String(255), nullable=True)
+
+class Node(BaseModel):
+ __tablename__ = 'nodes'
+
+ status = Column(Integer, nullable=True)
+ name = Column(String(255), nullable=True)
+ type = Column(Integer, nullable=True)
+ server = Column(String(255), nullable=True)
+ slave_key = Column(Text, nullable=True)
+ master_key = Column(Text, nullable=True)
+ aria2_enabled = Column(Boolean, nullable=True)
+ aria2_options = Column(Text, nullable=True)
+ rank = Column(Integer, nullable=True)
+
+class Order(BaseModel):
+ __tablename__ = 'orders'
+
+ user_id = Column(Integer, nullable=True)
+ order_no = Column(String(255), nullable=True, index=True)
+ type = Column(Integer, nullable=True)
+ method = Column(String(255), nullable=True)
+ product_id = Column(BigInteger, nullable=True)
+ num = Column(Integer, nullable=True)
+ name = Column(String(255), nullable=True)
+ price = Column(Integer, nullable=True)
+ status = Column(Integer, nullable=True)
+
+class Policy(BaseModel):
+ __tablename__ = 'policies'
+
+ name = Column(String(255), nullable=True)
+ type = Column(String(255), nullable=True)
+ server = Column(String(255), nullable=True)
+ bucket_name = Column(String(255), nullable=True)
+ is_private = Column(Boolean, nullable=True)
+ base_url = Column(String(255), nullable=True)
+ access_key = Column(Text, nullable=True)
+ secret_key = Column(Text, nullable=True)
+ max_size = Column(BigInteger, nullable=True)
+ auto_rename = Column(Boolean, nullable=True)
+ dir_name_rule = Column(String(255), nullable=True)
+ file_name_rule = Column(String(255), nullable=True)
+ is_origin_link_enable = Column(Boolean, nullable=True)
+ options = Column(Text, nullable=True)
+
+class Redeem(BaseModel):
+ __tablename__ = 'redeems'
+
+ type = Column(Integer, nullable=True)
+ product_id = Column(BigInteger, nullable=True)
+ num = Column(Integer, nullable=True)
+ code = Column(Text, nullable=True)
+ used = Column(Boolean, nullable=True)
+
+class Report(BaseModel):
+ __tablename__ = 'reports'
+
+ share_id = Column(Integer, nullable=True, index=True)
+ reason = Column(Integer, nullable=True)
+ description = Column(String(255), nullable=True)
+
+class Setting(BaseModel):
+ __tablename__ = 'settings'
+
+ type = Column(String(255), nullable=False)
+ name = Column(String(255), nullable=False, unique=True, index=True)
+ value = Column(Text, nullable=True)
+
+class Share(BaseModel):
+ __tablename__ = 'shares'
+
+ password = Column(String(255), nullable=True)
+ is_dir = Column(Boolean, nullable=True)
+ user_id = Column(Integer, nullable=True)
+ source_id = Column(Integer, nullable=True)
+ views = Column(Integer, nullable=True)
+ downloads = Column(Integer, nullable=True)
+ remain_downloads = Column(Integer, nullable=True)
+ expires = Column(DateTime, nullable=True)
+ preview_enabled = Column(Boolean, nullable=True)
+ source_name = Column(String(255), nullable=True, index=True)
+ score = Column(Integer, nullable=True)
+
+class SourceLink(BaseModel):
+ __tablename__ = 'source_links'
+
+ file_id = Column(Integer, nullable=True)
+ name = Column(String(255), nullable=True)
+ downloads = Column(Integer, nullable=True)
+
+class StoragePack(BaseModel):
+ __tablename__ = 'storage_packs'
+
+ name = Column(String(255), nullable=True)
+ user_id = Column(Integer, nullable=True)
+ active_time = Column(DateTime, nullable=True)
+ expired_time = Column(DateTime, nullable=True, index=True)
+ size = Column(BigInteger, nullable=True)
+
+class Tag(BaseModel):
+ __tablename__ = 'tags'
+
+ name = Column(String(255), nullable=True)
+ icon = Column(String(255), nullable=True)
+ color = Column(String(255), nullable=True)
+ type = Column(Integer, nullable=True)
+ expression = Column(Text, nullable=True)
+ user_id = Column(Integer, nullable=True)
+
+class Task(BaseModel):
+ __tablename__ = 'tasks'
+
+ status = Column(Integer, nullable=True)
+ type = Column(Integer, nullable=True)
+ user_id = Column(Integer, nullable=True)
+ progress = Column(Integer, nullable=True)
+ error = Column(Text, nullable=True)
+ props = Column(Text, nullable=True)
+
+class User(BaseModel):
+ __tablename__ = 'users'
+
+ email = Column(String(100), nullable=True, unique=True)
+ nick = Column(String(50), nullable=True)
+ password = Column(String(255), nullable=True)
+ status = Column(Integer, nullable=True)
+ group_id = Column(Integer, nullable=True)
+ storage = Column(BigInteger, nullable=True)
+ two_factor = Column(String(255), nullable=True)
+ avatar = Column(String(255), nullable=True)
+ options = Column(Text, nullable=True)
+ authn = Column(Text, nullable=True)
+ open_id = Column(String(255), nullable=True)
+ score = Column(Integer, nullable=True)
+ previous_group_id = Column(Integer, nullable=True)
+ group_expires = Column(DateTime, nullable=True)
+ notify_date = Column(DateTime, nullable=True)
+ phone = Column(String(255), nullable=True)
+
+class WebDAV(BaseModel):
+ __tablename__ = 'webdavs'
+
+ name = Column(String(255), nullable=True)
+ password = Column(String(255), nullable=True)
+ user_id = Column(Integer, nullable=True)
+ root = Column(Text, nullable=True)
+ readonly = Column(Boolean, nullable=True)
+ use_proxy = Column(Boolean, nullable=True)
+
+ __table_args__ = {'uniqueConstraints': [('password', 'user_id')]}
diff --git a/models/response.py b/models/response.py
new file mode 100644
index 0000000..c00211d
--- /dev/null
+++ b/models/response.py
@@ -0,0 +1,7 @@
+from pydantic import BaseModel, Field
+from typing import Union, Optional
+
+class ResponseModel(BaseModel):
+ code: int = Field(default=0, description="系统内部状态码, 0表示成功,其他表示失败", lt=60000, gt=0)
+ data: Union[dict, list, str, int, float, None] = Field(None, description="响应数据")
+ msg: Optional[str] = Field(default=None, description="响应消息,可以是错误消息或信息提示")
\ No newline at end of file
diff --git a/pkg/JWT/jwt.py b/pkg/JWT/jwt.py
new file mode 100644
index 0000000..35dde07
--- /dev/null
+++ b/pkg/JWT/jwt.py
@@ -0,0 +1,9 @@
+from fastapi.security import OAuth2PasswordBearer
+
+oauth2_scheme = OAuth2PasswordBearer(
+ scheme_name='获取 JWT Bearer 令牌',
+ description='用于获取 JWT Bearer 令牌,需要以表单的形式提交',
+ tokenUrl="/api/user/session",
+ )
+
+SECRET_KEY = ''
\ No newline at end of file
diff --git a/pkg/conf/appmeta.py b/pkg/conf/appmeta.py
new file mode 100644
index 0000000..f0f10d6
--- /dev/null
+++ b/pkg/conf/appmeta.py
@@ -0,0 +1,103 @@
+APP_NAME = 'DiskNext Server'
+summary = '一款基于 FastAPI 的可公私兼备的网盘系统'
+description = 'DiskNext Server 是一款基于 FastAPI 的网盘系统,支持个人和企业使用。它提供了高性能的文件存储和管理功能,支持多种认证方式。'
+license_info = {"name": "GPLv3", "url": "https://opensource.org/license/gpl-3.0"}
+
+BackendVersion = "0.0.1"
+
+IsPro = False
+
+tags_meta = [
+ {
+ "name": "site",
+ "description": "站点",
+ },
+ {
+ "name": "user",
+ "description": "用户",
+ },
+ {
+ "name": "user_settings",
+ "description": "用户设置",
+ },
+ {
+ "name": "share",
+ "description": "分享",
+ },
+ {
+ "name": "file",
+ "description": "文件",
+ },
+ {
+ "name": "aria2",
+ "description": "离线下载",
+ },
+ {
+ "name": "directory",
+ "description": "目录",
+ },
+ {
+ "name": "object",
+ "description": "对象,文件和目录的抽象",
+ },
+ {
+ "name": "callback",
+ "description": "回调接口",
+ },
+ {
+ "name": "oauth",
+ "description": "OAuth 认证",
+ },
+ {
+ "name": "pay",
+ "description": "支付回调",
+ },
+ {
+ "name": "upload",
+ "description": "上传回调",
+ },
+ {
+ "name": "vas",
+ "description": "增值服务",
+ },
+ {
+ "name": "tag",
+ "description": "用户标签",
+ },
+ {
+ "name": "webdav",
+ "description": "WebDAV管理相关",
+ },
+ {
+ "name": "admin",
+ "description": "管理员接口",
+ },
+ {
+ "name": "admin_group",
+ "description": "管理员组接口",
+ },
+ {
+ "name": "admin_user",
+ "description": "管理员用户接口",
+ },
+ {
+ "name": "admin_file",
+ "description": "管理员文件接口",
+ },
+ {
+ "name": "admin_aria2",
+ "description": "管理员离线下载接口",
+ },
+ {
+ "name": "admin_policy",
+ "description": "管理员策略接口",
+ },
+ {
+ "name": "admin_task",
+ "description": "管理员任务接口",
+ },
+ {
+ "name": "admin_vas",
+ "description": "管理员增值服务接口",
+ }
+]
\ No newline at end of file
diff --git a/routers/controllers/admin.py b/routers/controllers/admin.py
new file mode 100644
index 0000000..cd91549
--- /dev/null
+++ b/routers/controllers/admin.py
@@ -0,0 +1,487 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import AdminRequired
+from models.response import ResponseModel
+
+# 管理员根目录 /api/admin
+admin_router = APIRouter(
+ prefix="/admin",
+ tags=["admin"],
+)
+
+# 用户组 /api/admin/group
+admin_group_router = APIRouter(
+ prefix="/admin/group",
+ tags=["admin", "admin_group"],
+)
+
+# 用户 /api/admin/user
+admin_user_router = APIRouter(
+ prefix="/admin/user",
+ tags=["admin", "admin_user"],
+)
+
+# 文件 /api/admin/file
+admin_file_router = APIRouter(
+ prefix="/admin/file",
+ tags=["admin", "admin_file"],
+)
+
+# 离线下载 /api/admin/aria2
+admin_aria2_router = APIRouter(
+ prefix='/admin/aria2',
+ tags=['admin', 'admin_aria2']
+)
+
+# 存储策略管理 /api/admin/policy
+admin_policy_router = APIRouter(
+ prefix='/admin/policy',
+ tags=['admin', 'admin_policy']
+)
+
+# 分享 /api/admin/share
+admin_share_router = APIRouter(
+ prefix='/admin/share',
+ tags=['admin', 'admin_share']
+)
+
+# 任务 /api/admin/task
+admin_task_router = APIRouter(
+ prefix='/admin/task',
+ tags=['admin', 'admin_task']
+)
+
+# 增值服务 /api/admin/vas
+admin_vas_router = APIRouter(
+ prefix='/admin/vas',
+ tags=['admin', 'admin_vas']
+)
+
+
+@admin_router.get(
+ path='/summary',
+ summary='获取站点概况',
+ description='Get site summary information',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_summary() -> ResponseModel:
+ """
+ 获取站点概况信息,包括用户数、分享数、文件数等。
+
+ Returns:
+ ResponseModel: 包含站点概况信息的响应模型。
+ """
+ ...
+
+@admin_router.get(
+ path='/news',
+ summary='获取社区新闻',
+ description='Get community news',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_news() -> ResponseModel:
+ """
+ 获取社区新闻信息,包括最新的动态和公告。
+
+ Returns:
+ ResponseModel: 包含社区新闻信息的响应模型。
+ """
+ ...
+
+@admin_router.patch(
+ path='/settings',
+ summary='更新设置',
+ description='Update settings',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_update_settings() -> ResponseModel:
+ """
+ 更新站点设置,包括站点名称、描述等。
+
+ Returns:
+ ResponseModel: 包含更新结果的响应模型。
+ """
+ ...
+
+@admin_router.get(
+ path='/settings',
+ summary='获取设置',
+ description='Get settings',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_settings() -> ResponseModel:
+ """
+ 获取站点设置,包括站点名称、描述等。
+
+ Returns:
+ ResponseModel: 包含站点设置的响应模型。
+ """
+ ...
+
+@admin_group_router.get(
+ path='/',
+ summary='获取用户组列表',
+ description='Get user group list',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_groups() -> ResponseModel:
+ """
+ 获取用户组列表,包括每个用户组的名称和权限信息。
+
+ Returns:
+ ResponseModel: 包含用户组列表的响应模型。
+ """
+ ...
+
+@admin_group_router.get(
+ path='/{group_id}',
+ summary='获取用户组信息',
+ description='Get user group information by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_group(group_id: int) -> ResponseModel:
+ """
+ 根据用户组ID获取用户组信息,包括名称、权限等。
+
+ Args:
+ group_id (int): 用户组ID。
+
+ Returns:
+ ResponseModel: 包含用户组信息的响应模型。
+ """
+ ...
+
+@admin_group_router.get(
+ path='/list/{group_id}',
+ summary='获取用户组成员列表',
+ description='Get user group member list by group ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_group_members(
+ group_id: int,
+ page: int = 1,
+ page_size: int = 20
+) -> ResponseModel:
+ """
+ 根据用户组ID获取用户组成员列表。
+
+ Args:
+ group_id (int): 用户组ID。
+ page (int): 页码,默认为1。
+ page_size (int, optional): 每页显示的成员数量,默认为20。
+
+ Returns:
+ ResponseModel: 包含用户组成员列表的响应模型。
+ """
+ ...
+
+@admin_group_router.post(
+ path='/',
+ summary='创建用户组',
+ description='Create a new user group',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_create_group() -> ResponseModel:
+ """
+ 创建一个新的用户组,设置名称和权限等信息。
+
+ Returns:
+ ResponseModel: 包含创建结果的响应模型。
+ """
+ ...
+
+@admin_group_router.patch(
+ path='/{group_id}',
+ summary='更新用户组信息',
+ description='Update user group information by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_update_group(group_id: int) -> ResponseModel:
+ """
+ 根据用户组ID更新用户组信息,包括名称、权限等。
+
+ Args:
+ group_id (int): 用户组ID。
+
+ Returns:
+ ResponseModel: 包含更新结果的响应模型。
+ """
+ ...
+
+@admin_group_router.delete(
+ path='/{group_id}',
+ summary='删除用户组',
+ description='Delete user group by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_delete_group(group_id: int) -> ResponseModel:
+ """
+ 根据用户组ID删除用户组。
+
+ Args:
+ group_id (int): 用户组ID。
+
+ Returns:
+ ResponseModel: 包含删除结果的响应模型。
+ """
+ ...
+
+@admin_user_router.get(
+ path='/info/{user_id}',
+ summary='获取用户信息',
+ description='Get user information by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_user(user_id: int) -> ResponseModel:
+ """
+ 根据用户ID获取用户信息,包括用户名、邮箱、注册时间等。
+
+ Args:
+ user_id (int): 用户ID。
+
+ Returns:
+ ResponseModel: 包含用户信息的响应模型。
+ """
+ ...
+
+@admin_user_router.get(
+ path='/list',
+ summary='获取用户列表',
+ description='Get user list',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_users(
+ page: int = 1,
+ page_size: int = 20
+) -> ResponseModel:
+ """
+ 获取用户列表,支持分页。
+
+ Args:
+ page (int): 页码,默认为1。
+ page_size (int, optional): 每页显示的用户数量,默认为20。
+
+ Returns:
+ ResponseModel: 包含用户列表的响应模型。
+ """
+ ...
+
+@admin_user_router.post(
+ path='/create',
+ summary='创建用户',
+ description='Create a new user',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_create_user() -> ResponseModel:
+ """
+ 创建一个新的用户,设置用户名、密码等信息。
+
+ Returns:
+ ResponseModel: 包含创建结果的响应模型。
+ """
+ ...
+
+@admin_user_router.patch(
+ path='/{user_id}',
+ summary='更新用户信息',
+ description='Update user information by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_update_user(user_id: int) -> ResponseModel:
+ """
+ 根据用户ID更新用户信息,包括用户名、邮箱等。
+
+ Args:
+ user_id (int): 用户ID。
+
+ Returns:
+ ResponseModel: 包含更新结果的响应模型。
+ """
+ ...
+
+@admin_user_router.delete(
+ path='/{user_id}',
+ summary='删除用户',
+ description='Delete user by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_delete_user(user_id: int) -> ResponseModel:
+ """
+ 根据用户ID删除用户。
+
+ Args:
+ user_id (int): 用户ID。
+
+ Returns:
+ ResponseModel: 包含删除结果的响应模型。
+ """
+ ...
+
+@admin_user_router.post(
+ path='/calibrate/{user_id}',
+ summary='校准用户存储容量',
+ description='Calibrate the user storage.',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_admin_calibrate_storage():
+ ...
+
+@admin_file_router.get(
+ path='/list',
+ summary='获取文件',
+ description='Get file list',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_get_file_list() -> ResponseModel:
+ """
+ 获取文件列表,包括文件名称、大小、上传时间等。
+
+ Returns:
+ ResponseModel: 包含文件列表的响应模型。
+ """
+ ...
+
+@admin_file_router.get(
+ path='/preview/{file_id}',
+ summary='预览文件',
+ description='Preview file by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_preview_file(file_id: int) -> ResponseModel:
+ """
+ 根据文件ID预览文件内容。
+
+ Args:
+ file_id (int): 文件ID。
+
+ Returns:
+ ResponseModel: 包含文件预览内容的响应模型。
+ """
+ ...
+
+@admin_file_router.patch(
+ path='/ban/{file_id}',
+ summary='封禁文件',
+ description='Ban the file, user can\'t open, copy, move, download or share this file if administrator ban.',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_ban_file(file_id: int) -> ResponseModel:
+ """
+ 根据文件ID封禁文件。
+
+ 如果管理员封禁了某个文件,用户将无法打开、复制或移动、下载或分享此文件。
+
+ Args:
+ file_id (int): 文件ID。
+
+ Returns:
+ ResponseModel: 包含删除结果的响应模型。
+ """
+ ...
+
+@admin_file_router.delete(
+ path='/{file_id}',
+ summary='删除文件',
+ description='Delete file by ID',
+ dependencies=[Depends(AdminRequired)],
+)
+def router_admin_delete_file(file_id: int) -> ResponseModel:
+ """
+ 根据文件ID删除文件。
+
+ Args:
+ file_id (int): 文件ID。
+
+ Returns:
+ ResponseModel: 包含删除结果的响应模型。
+ """
+ ...
+
+@admin_aria2_router.post(
+ path='/test',
+ summary='测试连接配置',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_admin_aira2_test() -> ResponseModel:
+ ...
+
+@admin_policy_router.get(
+ path='/list',
+ summary='列出存储策略',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_list() -> ResponseModel:
+ ...
+
+@admin_policy_router.post(
+ path='/test/path',
+ summary='测试本地路径可用性',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_test_path() -> ResponseModel:
+ ...
+
+@admin_policy_router.post(
+ path='/test/slave',
+ summary='测试从机通信',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_test_slave() -> ResponseModel:
+ ...
+
+@admin_policy_router.post(
+ path='/',
+ summary='创建存储策略',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_add_policy() -> ResponseModel:
+ ...
+
+@admin_policy_router.post(
+ path='/cors',
+ summary='创建跨域策略',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_add_cors() -> ResponseModel:
+ ...
+
+@admin_policy_router.post(
+ path='/scf',
+ summary='创建COS回调函数',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_add_scf() -> ResponseModel:
+ ...
+
+@admin_policy_router.get(
+ path='/{id}/oauth',
+ summary='获取 OneDrive OAuth URL',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_onddrive_oauth() -> ResponseModel:
+ ...
+
+@admin_policy_router.get(
+ path='/{id}',
+ summary='获取存储策略',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_get_policy() -> ResponseModel:
+ ...
+
+@admin_policy_router.delete(
+ path='/{id}',
+ summary='删除存储策略',
+ description='',
+ dependencies=[Depends(AdminRequired)]
+)
+def router_policy_delete_policy() -> ResponseModel:
+ ...
\ No newline at end of file
diff --git a/routers/controllers/aria2.py b/routers/controllers/aria2.py
new file mode 100644
index 0000000..d9799c5
--- /dev/null
+++ b/routers/controllers/aria2.py
@@ -0,0 +1,107 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+aria2_router = APIRouter(
+ prefix="/aria2",
+ tags=["aria2"]
+)
+
+@aria2_router.post(
+ path='/url',
+ summary='创建URL下载任务',
+ description='Create a URL download task endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_aria2_url() -> ResponseModel:
+ """
+ Create a URL download task endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the URL download task.
+ """
+ ...
+
+@aria2_router.post(
+ path='/torrent/{id}',
+ summary='创建种子下载任务',
+ description='Create a torrent download task endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_aria2_torrent(id: str) -> ResponseModel:
+ """
+ Create a torrent download task endpoint.
+
+ Args:
+ id (str): The ID of the torrent to download.
+
+ Returns:
+ ResponseModel: A model containing the response data for the torrent download task.
+ """
+ ...
+
+@aria2_router.put(
+ path='/select/{gid}',
+ summary='重新选择要下载的文件',
+ description='Re-select files to download endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_aria2_select(gid: str) -> ResponseModel:
+ """
+ Re-select files to download endpoint.
+
+ Args:
+ gid (str): The GID of the download task.
+
+ Returns:
+ ResponseModel: A model containing the response data for the re-selection of files.
+ """
+ ...
+
+@aria2_router.delete(
+ path='/task/{gid}',
+ summary='取消或删除下载任务',
+ description='Delete a download task endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_aria2_delete(gid: str) -> ResponseModel:
+ """
+ Delete a download task endpoint.
+
+ Args:
+ gid (str): The GID of the download task to delete.
+
+ Returns:
+ ResponseModel: A model containing the response data for the deletion of the download task.
+ """
+ ...
+
+@aria2_router.get(
+ '/downloading',
+ summary='获取正在下载中的任务',
+ description='Get currently downloading tasks endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_aria2_downloading() -> ResponseModel:
+ """
+ Get currently downloading tasks endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for currently downloading tasks.
+ """
+ ...
+
+@aria2_router.get(
+ path='/finished',
+ summary='获取已完成的任务',
+ description='Get finished tasks endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_aria2_finished() -> ResponseModel:
+ """
+ Get finished tasks endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for finished tasks.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/callback.py b/routers/controllers/callback.py
new file mode 100644
index 0000000..019f4c2
--- /dev/null
+++ b/routers/controllers/callback.py
@@ -0,0 +1,279 @@
+from fastapi import APIRouter, Depends
+from fastapi.responses import PlainTextResponse
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+callback_router = APIRouter(
+ prefix='/callback',
+ tags=["callback"],
+)
+
+oauth_router = APIRouter(
+ prefix='/callback/oauth',
+ tags=["callback", "oauth"],
+)
+
+pay_router = APIRouter(
+ prefix='/callback/pay',
+ tags=["callback", "pay"],
+)
+
+upload_router = APIRouter(
+ prefix='/callback/upload',
+ tags=["callback", "upload"],
+)
+
+callback_router.include_router(oauth_router)
+callback_router.include_router(pay_router)
+callback_router.include_router(upload_router)
+
+@oauth_router.post(
+ path='/qq',
+ summary='QQ互联回调',
+ description='Handle QQ OAuth callback and return user information.',
+)
+def router_callback_qq() -> ResponseModel:
+ """
+ Handle QQ OAuth callback and return user information.
+
+ Returns:
+ ResponseModel: A model containing the response data for the QQ OAuth callback.
+ """
+ ...
+
+@oauth_router.post(
+ path='/github',
+ summary='GitHub OAuth 回调',
+ description='Handle GitHub OAuth callback and return user information.',
+)
+def router_callback_github() -> ResponseModel:
+ """
+ Handle GitHub OAuth callback and return user information.
+
+ Returns:
+ ResponseModel: A model containing the response data for the GitHub OAuth callback.
+ """
+ ...
+
+@pay_router.post(
+ path='/alipay',
+ summary='支付宝支付回调',
+ description='Handle Alipay payment callback and return payment status.',
+)
+def router_callback_alipay() -> ResponseModel:
+ """
+ Handle Alipay payment callback and return payment status.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Alipay payment callback.
+ """
+ ...
+
+@pay_router.post(
+ path='/wechat',
+ summary='微信支付回调',
+ description='Handle WeChat Pay payment callback and return payment status.',
+)
+def router_callback_wechat() -> ResponseModel:
+ """
+ Handle WeChat Pay payment callback and return payment status.
+
+ Returns:
+ ResponseModel: A model containing the response data for the WeChat Pay payment callback.
+ """
+ ...
+
+@pay_router.post(
+ path='/stripe',
+ summary='Stripe支付回调',
+ description='Handle Stripe payment callback and return payment status.',
+)
+def router_callback_stripe() -> ResponseModel:
+ """
+ Handle Stripe payment callback and return payment status.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Stripe payment callback.
+ """
+ ...
+
+@pay_router.get(
+ path='/easypay',
+ summary='易支付回调',
+ description='Handle EasyPay payment callback and return payment status.',
+)
+def router_callback_easypay() -> PlainTextResponse:
+ """
+ Handle EasyPay payment callback and return payment status.
+
+ Returns:
+ PlainTextResponse: A response containing the payment status for the EasyPay payment callback.
+ """
+ ...
+ # return PlainTextResponse("success", status_code=200)
+
+@pay_router.get(
+ path='/custom/{order_no}/{id}',
+ summary='自定义支付回调',
+ description='Handle custom payment callback and return payment status.',
+)
+def router_callback_custom(order_no: str, id: str) -> ResponseModel:
+ """
+ Handle custom payment callback and return payment status.
+
+ Args:
+ order_no (str): The order number for the payment.
+ id (str): The ID associated with the payment.
+
+ Returns:
+ ResponseModel: A model containing the response data for the custom payment callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/remote/{session_id}/{key}',
+ summary='远程上传回调',
+ description='Handle remote upload callback and return upload status.',
+)
+def router_callback_remote(session_id: str, key: str) -> ResponseModel:
+ """
+ Handle remote upload callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+ key (str): The key for the uploaded file.
+
+ Returns:
+ ResponseModel: A model containing the response data for the remote upload callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/qiniu/{session_id}',
+ summary='七牛云上传回调',
+ description='Handle Qiniu Cloud upload callback and return upload status.',
+)
+def router_callback_qiniu(session_id: str) -> ResponseModel:
+ """
+ Handle Qiniu Cloud upload callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Qiniu Cloud upload callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/tencent/{session_id}',
+ summary='腾讯云上传回调',
+ description='Handle Tencent Cloud upload callback and return upload status.',
+)
+def router_callback_tencent(session_id: str) -> ResponseModel:
+ """
+ Handle Tencent Cloud upload callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Tencent Cloud upload callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/aliyun/{session_id}',
+ summary='阿里云上传回调',
+ description='Handle Aliyun upload callback and return upload status.',
+)
+def router_callback_aliyun(session_id: str) -> ResponseModel:
+ """
+ Handle Aliyun upload callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Aliyun upload callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/upyun/{session_id}',
+ summary='又拍云上传回调',
+ description='Handle Upyun upload callback and return upload status.',
+)
+def router_callback_upyun(session_id: str) -> ResponseModel:
+ """
+ Handle Upyun upload callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Upyun upload callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/aws/{session_id}',
+ summary='AWS S3上传回调',
+ description='Handle AWS S3 upload callback and return upload status.',
+)
+def router_callback_aws(session_id: str) -> ResponseModel:
+ """
+ Handle AWS S3 upload callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+
+ Returns:
+ ResponseModel: A model containing the response data for the AWS S3 upload callback.
+ """
+ ...
+
+@upload_router.post(
+ path='/onedrive/finish/{session_id}',
+ summary='OneDrive上传完成回调',
+ description='Handle OneDrive upload completion callback and return upload status.',
+)
+def router_callback_onedrive_finish(session_id: str) -> ResponseModel:
+ """
+ Handle OneDrive upload completion callback and return upload status.
+
+ Args:
+ session_id (str): The session ID for the upload.
+
+ Returns:
+ ResponseModel: A model containing the response data for the OneDrive upload completion callback.
+ """
+ ...
+
+@upload_router.get(
+ path='/ondrive/auth',
+ summary='OneDrive授权回调',
+ description='Handle OneDrive authorization callback and return authorization status.',
+)
+def router_callback_onedrive_auth() -> ResponseModel:
+ """
+ Handle OneDrive authorization callback and return authorization status.
+
+ Returns:
+ ResponseModel: A model containing the response data for the OneDrive authorization callback.
+ """
+ ...
+
+@upload_router.get(
+ path='/google/auth',
+ summary='Google OAuth 完成',
+ description='Handle Google OAuth completion callback and return authorization status.',
+)
+def router_callback_google_auth() -> ResponseModel:
+ """
+ Handle Google OAuth completion callback and return authorization status.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Google OAuth completion callback.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/directory.py b/routers/controllers/directory.py
new file mode 100644
index 0000000..77e43f6
--- /dev/null
+++ b/routers/controllers/directory.py
@@ -0,0 +1,41 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+directory_router = APIRouter(
+ prefix="/directory",
+ tags=["directory"]
+)
+
+@directory_router.put(
+ path='/',
+ summary='创建目录',
+ description='Create a directory endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_directory_create() -> ResponseModel:
+ """
+ Create a directory endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the directory creation.
+ """
+ ...
+
+@directory_router.get(
+ path='/{path:path}',
+ summary='获取目录内容',
+ description='Get directory contents endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_directory_get(path: str) -> ResponseModel:
+ """
+ Get directory contents endpoint.
+
+ Args:
+ path (str): The path of the directory to retrieve contents from.
+
+ Returns:
+ ResponseModel: A model containing the response data for the directory contents.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/file.py b/routers/controllers/file.py
new file mode 100644
index 0000000..48c7178
--- /dev/null
+++ b/routers/controllers/file.py
@@ -0,0 +1,381 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+file_router = APIRouter(
+ prefix="/file",
+ tags=["file"]
+)
+
+file_upload_router = APIRouter(
+ prefix="/file/upload",
+ tags=["file"]
+)
+
+@file_router.get(
+ path='/get/{id}/{name}',
+ summary='文件外链(直接输出文件数据)',
+ description='Get file external link endpoint.',
+)
+def router_file_get(id: str, name: str) -> ResponseModel:
+ """
+ Get file external link endpoint.
+
+ Args:
+ id (str): The ID of the file.
+ name (str): The name of the file.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file.
+ """
+ ...
+
+@file_router.get(
+ path='/source/{id}/{name}',
+ summary='文件外链(301跳转)',
+ description='Get file external link with 301 redirect endpoint.',
+)
+def router_file_source(id: str, name: str) -> ResponseModel:
+ """
+ Get file external link with 301 redirect endpoint.
+
+ Args:
+ id (str): The ID of the file.
+ name (str): The name of the file.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file with a redirect.
+ """
+ ...
+
+@file_upload_router.get(
+ path='/download/{id}',
+ summary='下载文件',
+ description='Download file endpoint.',
+)
+def router_file_download(id: str) -> ResponseModel:
+ """
+ Download file endpoint.
+
+ Args:
+ id (str): The ID of the file to download.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file download.
+ """
+ ...
+
+@file_upload_router.get(
+ path='/archive/{sessionID}/archive.zip',
+ summary='打包并下载文件',
+ description='Archive and download files endpoint.',
+)
+def router_file_archive_download(sessionID: str) -> ResponseModel:
+ """
+ Archive and download files endpoint.
+
+ Args:
+ sessionID (str): The session ID for the archive.
+
+ Returns:
+ ResponseModel: A model containing the response data for the archived files download.
+ """
+ ...
+
+@file_upload_router.post(
+ path='/{sessionID}/{index}',
+ summary='文件上传',
+ description='File upload endpoint.',
+)
+def router_file_upload(sessionID: str, index: int) -> ResponseModel:
+ """
+ File upload endpoint.
+
+ Args:
+ sessionID (str): The session ID for the upload.
+ index (int): The index of the file being uploaded.
+
+ Returns:
+ ResponseModel: A model containing the response data.
+ """
+ ...
+
+@file_upload_router.put(
+ path='/',
+ summary='创建上传会话',
+ description='Create an upload session endpoint.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_file_upload_session() -> ResponseModel:
+ """
+ Create an upload session endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the upload session.
+ """
+ ...
+
+@file_upload_router.delete(
+ path='/{sessionID}',
+ summary='删除上传会话',
+ description='Delete an upload session endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_upload_session_delete(sessionID: str) -> ResponseModel:
+ """
+ Delete an upload session endpoint.
+
+ Args:
+ sessionID (str): The session ID to delete.
+
+ Returns:
+ ResponseModel: A model containing the response data for the deletion.
+ """
+ ...
+
+@file_upload_router.delete(
+ path='/',
+ summary='清除所有上传会话',
+ description='Clear all upload sessions endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_upload_session_clear() -> ResponseModel:
+ """
+ Clear all upload sessions endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for clearing all sessions.
+ """
+ ...
+
+@file_router.put(
+ path='/update/{id}',
+ summary='更新文件',
+ description='Update file information endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_update(id: str) -> ResponseModel:
+ """
+ Update file information endpoint.
+
+ Args:
+ id (str): The ID of the file to update.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file update.
+ """
+ ...
+
+@file_router.post(
+ path='/create',
+ summary='创建空白文件',
+ description='Create a blank file endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_create() -> ResponseModel:
+ """
+ Create a blank file endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file creation.
+ """
+ ...
+
+@file_router.put(
+ path='/download/{id}',
+ summary='创建文件下载会话',
+ description='Create a file download session endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_download(id: str) -> ResponseModel:
+ """
+ Create a file download session endpoint.
+
+ Args:
+ id (str): The ID of the file to download.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file download session.
+ """
+ ...
+
+@file_router.get(
+ path='/preview/{id}',
+ summary='预览文件',
+ description='Preview file endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_preview(id: str) -> ResponseModel:
+ """
+ Preview file endpoint.
+
+ Args:
+ id (str): The ID of the file to preview.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file preview.
+ """
+ ...
+
+@file_router.get(
+ path='/content/{id}',
+ summary='获取文本文件内容',
+ description='Get text file content endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_content(id: str) -> ResponseModel:
+ """
+ Get text file content endpoint.
+
+ Args:
+ id (str): The ID of the text file.
+
+ Returns:
+ ResponseModel: A model containing the response data for the text file content.
+ """
+ ...
+
+@file_router.get(
+ path='/doc/{id}',
+ summary='获取Office文档预览地址',
+ description='Get Office document preview URL endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_doc(id: str) -> ResponseModel:
+ """
+ Get Office document preview URL endpoint.
+
+ Args:
+ id (str): The ID of the Office document.
+
+ Returns:
+ ResponseModel: A model containing the response data for the Office document preview URL.
+ """
+ ...
+
+@file_router.get(
+ path='/thumb/{id}',
+ summary='获取文件缩略图',
+ description='Get file thumbnail endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_thumb(id: str) -> ResponseModel:
+ """
+ Get file thumbnail endpoint.
+
+ Args:
+ id (str): The ID of the file to get the thumbnail for.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file thumbnail.
+ """
+ ...
+
+@file_router.post(
+ path='/source/{id}',
+ summary='取得文件外链',
+ description='Get file external link endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_source(id: str) -> ResponseModel:
+ """
+ Get file external link endpoint.
+
+ Args:
+ id (str): The ID of the file to get the external link for.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file external link.
+ """
+ ...
+
+@file_router.post(
+ path='/archive',
+ summary='打包要下载的文件',
+ description='Archive files for download endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_archive(id: str) -> ResponseModel:
+ """
+ Archive files for download endpoint.
+
+ Args:
+ id (str): The ID of the file to archive.
+
+ Returns:
+ ResponseModel: A model containing the response data for the archived files.
+ """
+ ...
+
+@file_router.post(
+ path='/compress',
+ summary='创建文件压缩任务',
+ description='Create file compression task endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_compress(id: str) -> ResponseModel:
+ """
+ Create file compression task endpoint.
+
+ Args:
+ id (str): The ID of the file to compress.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file compression task.
+ """
+ ...
+
+@file_router.post(
+ path='/decompress',
+ summary='创建文件解压任务',
+ description='Create file extraction task endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_decompress(id: str) -> ResponseModel:
+ """
+ Create file extraction task endpoint.
+
+ Args:
+ id (str): The ID of the file to decompress.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file extraction task.
+ """
+ ...
+
+@file_router.post(
+ path='/relocate',
+ summary='创建文件转移任务',
+ description='Create file relocation task endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_relocate(id: str) -> ResponseModel:
+ """
+ Create file relocation task endpoint.
+
+ Args:
+ id (str): The ID of the file to relocate.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file relocation task.
+ """
+ ...
+
+@file_router.get(
+ path='/search/{type}/{keyword}',
+ summary='搜索文件',
+ description='Search files by keyword endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_file_search(type: str, keyword: str) -> ResponseModel:
+ """
+ Search files by keyword endpoint.
+
+ Args:
+ type (str): The type of search (e.g., 'name', 'content').
+ keyword (str): The keyword to search for.
+
+ Returns:
+ ResponseModel: A model containing the response data for the file search.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/object.py b/routers/controllers/object.py
new file mode 100644
index 0000000..0724c02
--- /dev/null
+++ b/routers/controllers/object.py
@@ -0,0 +1,86 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+object_router = APIRouter(
+ prefix="/object",
+ tags=["object"]
+)
+
+@object_router.delete(
+ path='/',
+ summary='删除对象',
+ description='Delete an object endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_object_delete() -> ResponseModel:
+ """
+ Delete an object endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the object deletion.
+ """
+ ...
+
+@object_router.patch(
+ path='/',
+ summary='移动对象',
+ description='Move an object endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_object_move() -> ResponseModel:
+ """
+ Move an object endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the object move.
+ """
+ ...
+
+@object_router.post(
+ path='/copy',
+ summary='复制对象',
+ description='Copy an object endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_object_copy() -> ResponseModel:
+ """
+ Copy an object endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the object copy.
+ """
+ ...
+
+@object_router.post(
+ path='/rename',
+ summary='重命名对象',
+ description='Rename an object endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_object_rename() -> ResponseModel:
+ """
+ Rename an object endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the object rename.
+ """
+ ...
+
+@object_router.get(
+ path='/property/{id}',
+ summary='获取对象属性',
+ description='Get object properties endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_object_property(id: str) -> ResponseModel:
+ """
+ Get object properties endpoint.
+
+ Args:
+ id (str): The ID of the object to retrieve properties for.
+
+ Returns:
+ ResponseModel: A model containing the response data for the object properties.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/share.py b/routers/controllers/share.py
new file mode 100644
index 0000000..98b7ab1
--- /dev/null
+++ b/routers/controllers/share.py
@@ -0,0 +1,306 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+share_router = APIRouter(
+ prefix='/share',
+ tags=["share"],
+)
+
+@share_router.get(
+ path='/{info}/{id}',
+ summary='获取分享',
+ description='Get shared content by info type and ID.',
+)
+def router_share_get(info: str, id: str) -> ResponseModel:
+ """
+ Get shared content by info type and ID.
+
+ Args:
+ info (str): The type of information being shared.
+ id (str): The ID of the shared content.
+
+ Returns:
+ dict: A dictionary containing shared content information.
+ """
+ ...
+
+@share_router.put(
+ path='/download/{id}',
+ summary='创建文件下载会话',
+ description='Create a file download session by ID.',
+)
+def router_share_download(id: str) -> ResponseModel:
+ """
+ Create a file download session by ID.
+
+ Args:
+ id (str): The ID of the file to be downloaded.
+
+ Returns:
+ dict: A dictionary containing download session information.
+ """
+ ...
+
+@share_router.get(
+ path='preview/{id}',
+ summary='预览分享文件',
+ description='Preview shared file by ID.',
+)
+def router_share_preview(id: str) -> ResponseModel:
+ """
+ Preview shared file by ID.
+
+ Args:
+ id (str): The ID of the file to be previewed.
+
+ Returns:
+ dict: A dictionary containing preview information.
+ """
+ ...
+
+@share_router.get(
+ path='/doc/{id}',
+ summary='取得Office文档预览地址',
+ description='Get Office document preview URL by ID.',
+)
+def router_share_doc(id: str) -> ResponseModel:
+ """
+ Get Office document preview URL by ID.
+
+ Args:
+ id (str): The ID of the Office document.
+
+ Returns:
+ dict: A dictionary containing the document preview URL.
+ """
+ ...
+
+@share_router.get(
+ path='/content/{id}',
+ summary='获取文本文件内容',
+ description='Get text file content by ID.',
+)
+def router_share_content(id: str) -> ResponseModel:
+ """
+ Get text file content by ID.
+
+ Args:
+ id (str): The ID of the text file.
+
+ Returns:
+ str: The content of the text file.
+ """
+ ...
+
+@share_router.get(
+ path='/list/{id}/{path:path}',
+ summary='获取目录列文件',
+ description='Get directory listing by ID and path.',
+)
+def router_share_list(id: str, path: str = '') -> ResponseModel:
+ """
+ Get directory listing by ID and path.
+
+ Args:
+ id (str): The ID of the directory.
+ path (str): The path within the directory.
+
+ Returns:
+ dict: A dictionary containing directory listing information.
+ """
+ ...
+
+@share_router.get(
+ path='/search/{id}/{type}/{keywords}',
+ summary='分享目录搜索',
+ description='Search within a shared directory by ID, type, and keywords.',
+)
+def router_share_search(id: str, type: str, keywords: str) -> ResponseModel:
+ """
+ Search within a shared directory by ID, type, and keywords.
+
+ Args:
+ id (str): The ID of the shared directory.
+ type (str): The type of search (e.g., file, folder).
+ keywords (str): The keywords to search for.
+
+ Returns:
+ dict: A dictionary containing search results.
+ """
+ ...
+
+@share_router.post(
+ path='/archive/{id}',
+ summary='归档打包下载',
+ description='Archive and download shared content by ID.',
+)
+def router_share_archive(id: str) -> ResponseModel:
+ """
+ Archive and download shared content by ID.
+
+ Args:
+ id (str): The ID of the content to be archived.
+
+ Returns:
+ dict: A dictionary containing archive download information.
+ """
+ ...
+
+@share_router.get(
+ path='/readme/{id}',
+ summary='获取README文本文件内容',
+ description='Get README text file content by ID.',
+)
+def router_share_readme(id: str) -> ResponseModel:
+ """
+ Get README text file content by ID.
+
+ Args:
+ id (str): The ID of the README file.
+
+ Returns:
+ str: The content of the README file.
+ """
+ ...
+
+@share_router.get(
+ path='/thumb/{id}/{file}',
+ summary='获取缩略图',
+ description='Get thumbnail image by ID and file name.',
+)
+def router_share_thumb(id: str, file: str) -> ResponseModel:
+ """
+ Get thumbnail image by ID and file name.
+
+ Args:
+ id (str): The ID of the shared content.
+ file (str): The name of the file for which to get the thumbnail.
+
+ Returns:
+ str: A Base64 encoded string of the thumbnail image.
+ """
+ ...
+
+@share_router.post(
+ path='/report/{id}',
+ summary='举报分享',
+ description='Report shared content by ID.',
+)
+def router_share_report(id: str) -> ResponseModel:
+ """
+ Report shared content by ID.
+
+ Args:
+ id (str): The ID of the shared content to report.
+
+ Returns:
+ dict: A dictionary containing report submission information.
+ """
+ ...
+
+@share_router.get(
+ path='/search',
+ summary='搜索公共分享',
+ description='Search public shares by keywords and type.',
+)
+def router_share_search_public(keywords: str, type: str = 'all') -> ResponseModel:
+ """
+ Search public shares by keywords and type.
+
+ Args:
+ keywords (str): The keywords to search for.
+ type (str): The type of search (e.g., all, file, folder).
+
+ Returns:
+ dict: A dictionary containing search results for public shares.
+ """
+ ...
+
+#####################
+# 需要登录的接口
+#####################
+
+@share_router.post(
+ path='/',
+ summary='创建新分享',
+ description='Create a new share endpoint.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_share_create() -> ResponseModel:
+ """
+ Create a new share endpoint.
+
+ Returns:
+ ResponseModel: A model containing the response data for the new share creation.
+ """
+ ...
+
+@share_router.get(
+ path='/',
+ summary='列出我的分享',
+ description='Get a list of shares.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_share_list() -> ResponseModel:
+ """
+ Get a list of shares.
+
+ Returns:
+ ResponseModel: A model containing the response data for the list of shares.
+ """
+ ...
+
+@share_router.post(
+ path='/save/{id}',
+ summary='转存他人分享',
+ description='Save another user\'s share by ID.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_share_save(id: str) -> ResponseModel:
+ """
+ Save another user's share by ID.
+
+ Args:
+ id (str): The ID of the share to be saved.
+
+ Returns:
+ ResponseModel: A model containing the response data for the saved share.
+ """
+ ...
+
+@share_router.patch(
+ path='/{id}',
+ summary='更新分享信息',
+ description='Update share information by ID.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_share_update(id: str) -> ResponseModel:
+ """
+ Update share information by ID.
+
+ Args:
+ id (str): The ID of the share to be updated.
+
+ Returns:
+ ResponseModel: A model containing the response data for the updated share.
+ """
+ ...
+
+@share_router.delete(
+ path='/{id}',
+ summary='删除分享',
+ description='Delete a share by ID.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_share_delete(id: str) -> ResponseModel:
+ """
+ Delete a share by ID.
+
+ Args:
+ id (str): The ID of the share to be deleted.
+
+ Returns:
+ ResponseModel: A model containing the response data for the deleted share.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/site.py b/routers/controllers/site.py
new file mode 100644
index 0000000..8dd8f5d
--- /dev/null
+++ b/routers/controllers/site.py
@@ -0,0 +1,52 @@
+from fastapi import APIRouter
+from models.response import ResponseModel
+
+site_router = APIRouter(
+ prefix="/site",
+ tags=["site"],
+)
+
+@site_router.get(
+ path="/ping",
+ summary="测试用路由",
+ description="A simple endpoint to check if the site is up and running.",
+ response_model=ResponseModel,)
+def router_site_ping():
+ """
+ Ping the site to check if it is up and running.
+
+ Returns:
+ str: A message indicating the site is running.
+ """
+ from pkg.conf.appmeta import BackendVersion
+ return ResponseModel(data=BackendVersion)
+
+@site_router.get(
+ path='/captcha',
+ summary='验证码',
+ description='Get a Base64 captcha image.',
+ response_model=ResponseModel,
+)
+def router_site_captcha():
+ """
+ Get a Base64 captcha image.
+
+ Returns:
+ str: A Base64 encoded string of the captcha image.
+ """
+ ...
+
+@site_router.get(
+ path='/config',
+ summary='站点全局配置',
+ description='Get the configuration file.',
+ response_model=ResponseModel,
+)
+def router_site_config():
+ """
+ Get the configuration file.
+
+ Returns:
+ dict: The site configuration.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/tag.py b/routers/controllers/tag.py
new file mode 100644
index 0000000..650d2d4
--- /dev/null
+++ b/routers/controllers/tag.py
@@ -0,0 +1,56 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+tag_router = APIRouter(
+ prefix='/tag',
+ tags=["tag"],
+)
+
+@tag_router.post(
+ path='/filter',
+ summary='创建文件分类标签',
+ description='Create a file classification tag.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_tag_create_filter() -> ResponseModel:
+ """
+ Create a file classification tag.
+
+ Returns:
+ ResponseModel: A model containing the response data for the created tag.
+ """
+ ...
+
+@tag_router.post(
+ path='/link',
+ summary='创建目录快捷方式标签',
+ description='Create a directory shortcut tag.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_tag_create_link() -> ResponseModel:
+ """
+ Create a directory shortcut tag.
+
+ Returns:
+ ResponseModel: A model containing the response data for the created tag.
+ """
+ ...
+
+@tag_router.delete(
+ path='/{id}',
+ summary='删除标签',
+ description='Delete a tag by its ID.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_tag_delete(id: str) -> ResponseModel:
+ """
+ Delete a tag by its ID.
+
+ Args:
+ id (str): The ID of the tag to be deleted.
+
+ Returns:
+ ResponseModel: A model containing the response data for the deletion operation.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/user.py b/routers/controllers/user.py
new file mode 100644
index 0000000..81a5f06
--- /dev/null
+++ b/routers/controllers/user.py
@@ -0,0 +1,370 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+user_router = APIRouter(
+ prefix="/user",
+ tags=["user"],
+)
+
+user_settings_router = APIRouter(
+ prefix='/user/settings',
+ tags=["user", "user_settings"],
+ dependencies=[Depends(SignRequired)],
+)
+
+@user_router.post(
+ path='/session',
+ summary='用户登录',
+ description='User login endpoint.',
+)
+def router_user_session() -> ResponseModel:
+ """
+ User login endpoint.
+
+ Returns:
+ dict: A dictionary containing user session information.
+ """
+ ...
+
+@user_router.post(
+ path='/',
+ summary='用户注册',
+ description='User registration endpoint.',
+)
+def router_user_register() -> ResponseModel:
+ """
+ User registration endpoint.
+
+ Returns:
+ dict: A dictionary containing user registration information.
+ """
+ ...
+
+@user_router.post(
+ path='/2fa',
+ summary='用两步验证登录',
+ description='Two-factor authentication login endpoint.',
+)
+def router_user_2fa() -> ResponseModel:
+ """
+ Two-factor authentication login endpoint.
+
+ Returns:
+ dict: A dictionary containing two-factor authentication information.
+ """
+ ...
+
+@user_router.post(
+ path='/reset',
+ summary='发送密码重设邮件',
+ description='Send a password reset email.',
+)
+def router_user_reset() -> ResponseModel:
+ """
+ Send a password reset email.
+
+ Returns:
+ dict: A dictionary containing information about the password reset email.
+ """
+ ...
+
+@user_router.patch(
+ path='/reset',
+ summary='通过邮件里的链接重设密码',
+ description='Reset password via email link.',
+)
+def router_user_reset_patch() -> ResponseModel:
+ """
+ Reset password via email link.
+
+ Returns:
+ dict: A dictionary containing information about the password reset.
+ """
+ ...
+
+@user_router.get(
+ path='/qq',
+ summary='初始化QQ登录',
+ description='Initialize QQ login for a user.',
+)
+def router_user_qq() -> ResponseModel:
+ """
+ Initialize QQ login for a user.
+
+ Returns:
+ dict: A dictionary containing QQ login initialization information.
+ """
+ ...
+
+@user_router.get(
+ path='/activate/{id}',
+ summary='邮件激活',
+ description='Activate user account via email link.',
+)
+def router_user_activate(id: str) -> ResponseModel:
+ """
+ Activate user account via email link.
+
+ Args:
+ id (str): The activation ID from the email link.
+
+ Returns:
+ dict: A dictionary containing activation information.
+ """
+ ...
+
+@user_router.get(
+ path='authn/{username}',
+ summary='WebAuthn登录初始化',
+ description='Initialize WebAuthn login for a user.',
+)
+def router_user_authn(username: str) -> ResponseModel:
+ """
+ Initialize WebAuthn login for a user.
+
+ Args:
+ username (str): The username of the user.
+
+ Returns:
+ dict: A dictionary containing WebAuthn initialization information.
+ """
+ ...
+
+@user_router.post(
+ path='authn/finish/{username}',
+ summary='WebAuthn登录',
+ description='Finish WebAuthn login for a user.',
+)
+def router_user_authn_finish(username: str) -> ResponseModel:
+ """
+ Finish WebAuthn login for a user.
+
+ Args:
+ username (str): The username of the user.
+
+ Returns:
+ dict: A dictionary containing WebAuthn login information.
+ """
+ ...
+
+@user_router.get(
+ path='/profile/{id}',
+ summary='获取用户主页展示用分享',
+ description='Get user profile for display.',
+)
+def router_user_profile(id: str) -> ResponseModel:
+ """
+ Get user profile for display.
+
+ Args:
+ id (str): The user ID.
+
+ Returns:
+ dict: A dictionary containing user profile information.
+ """
+ ...
+
+@user_router.get(
+ path='/avatar/{id}/{size}',
+ summary='获取用户头像',
+ description='Get user avatar by ID and size.',
+)
+def router_user_avatar(id: str, size: int = 128) -> ResponseModel:
+ """
+ Get user avatar by ID and size.
+
+ Args:
+ id (str): The user ID.
+ size (int): The size of the avatar image.
+
+ Returns:
+ str: A Base64 encoded string of the user avatar image.
+ """
+ ...
+
+#####################
+# 需要登录的接口
+#####################
+
+@user_router.get(
+ path='/me',
+ summary='获取用户信息',
+ description='Get user information.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_me() -> ResponseModel:
+ """
+ Get user information.
+
+ Returns:
+ dict: A dictionary containing user information.
+ """
+ ...
+
+@user_router.get(
+ path='/storage',
+ summary='存储信息',
+ description='Get user storage information.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_storage() -> ResponseModel:
+ """
+ Get user storage information.
+
+ Returns:
+ dict: A dictionary containing user storage information.
+ """
+ ...
+
+@user_router.put(
+ path='/authn/start',
+ summary='WebAuthn登录初始化',
+ description='Initialize WebAuthn login for a user.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_authn_start() -> ResponseModel:
+ """
+ Initialize WebAuthn login for a user.
+
+ Returns:
+ dict: A dictionary containing WebAuthn initialization information.
+ """
+ ...
+
+@user_router.put(
+ path='/authn/finish',
+ summary='WebAuthn登录',
+ description='Finish WebAuthn login for a user.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_authn_finish() -> ResponseModel:
+ """
+ Finish WebAuthn login for a user.
+
+ Returns:
+ dict: A dictionary containing WebAuthn login information.
+ """
+ ...
+
+@user_settings_router.get(
+ path='/policies',
+ summary='获取用户可选存储策略',
+ description='Get user selectable storage policies.',
+)
+def router_user_settings_policies() -> ResponseModel:
+ """
+ Get user selectable storage policies.
+
+ Returns:
+ dict: A dictionary containing available storage policies for the user.
+ """
+ ...
+
+@user_settings_router.get(
+ path='/nodes',
+ summary='获取用户可选节点',
+ description='Get user selectable nodes.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings_nodes() -> ResponseModel:
+ """
+ Get user selectable nodes.
+
+ Returns:
+ dict: A dictionary containing available nodes for the user.
+ """
+ ...
+
+@user_settings_router.get(
+ path='/tasks',
+ summary='任务队列',
+ description='Get user task queue.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings_tasks() -> ResponseModel:
+ """
+ Get user task queue.
+
+ Returns:
+ dict: A dictionary containing the user's task queue information.
+ """
+ ...
+
+@user_settings_router.get(
+ path='/',
+ summary='获取当前用户设定',
+ description='Get current user settings.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings() -> ResponseModel:
+ """
+ Get current user settings.
+
+ Returns:
+ dict: A dictionary containing the user's current settings.
+ """
+ ...
+
+@user_settings_router.post(
+ path='/avatar',
+ summary='从文件上传头像',
+ description='Upload user avatar from file.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings_avatar() -> ResponseModel:
+ """
+ Upload user avatar from file.
+
+ Returns:
+ dict: A dictionary containing the result of the avatar upload.
+ """
+ ...
+
+@user_settings_router.put(
+ path='/avatar',
+ summary='设定为Gravatar头像',
+ description='Set user avatar to Gravatar.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings_avatar_gravatar() -> ResponseModel:
+ """
+ Set user avatar to Gravatar.
+
+ Returns:
+ dict: A dictionary containing the result of setting the Gravatar avatar.
+ """
+ ...
+
+@user_settings_router.patch(
+ path='/{option}',
+ summary='更新用户设定',
+ description='Update user settings.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings_patch(option: str) -> ResponseModel:
+ """
+ Update user settings.
+
+ Args:
+ option (str): The setting option to update.
+
+ Returns:
+ dict: A dictionary containing the result of the settings update.
+ """
+ ...
+
+@user_settings_router.get(
+ path='/2fa',
+ summary='获取两步验证初始化信息',
+ description='Get two-factor authentication initialization information.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_user_settings_2fa() -> ResponseModel:
+ """
+ Get two-factor authentication initialization information.
+
+ Returns:
+ dict: A dictionary containing two-factor authentication setup information.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/vas.py b/routers/controllers/vas.py
new file mode 100644
index 0000000..8e98569
--- /dev/null
+++ b/routers/controllers/vas.py
@@ -0,0 +1,104 @@
+from fastapi import APIRouter, Depends
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+vas_router = APIRouter(
+ prefix="/vas",
+ tags=["vas"]
+)
+
+@vas_router.get(
+ path='/pack',
+ summary='获取容量包及配额信息',
+ description='Get information about storage packs and quotas.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_vas_pack() -> ResponseModel:
+ """
+ Get information about storage packs and quotas.
+
+ Returns:
+ ResponseModel: A model containing the response data for storage packs and quotas.
+ """
+ ...
+
+@vas_router.get(
+ path='/product',
+ summary='获取商品信息,同时返回支付信息',
+ description='Get product information along with payment details.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_vas_product() -> ResponseModel:
+ """
+ Get product information along with payment details.
+
+ Returns:
+ ResponseModel: A model containing the response data for products and payment information.
+ """
+ ...
+
+@vas_router.post(
+ path='/order',
+ summary='新建支付订单',
+ description='Create an order for a product.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_vas_order() -> ResponseModel:
+ """
+ Create an order for a product.
+
+ Returns:
+ ResponseModel: A model containing the response data for the created order.
+ """
+ ...
+
+@vas_router.get(
+ path='/order/{id}',
+ summary='查询订单状态',
+ description='Get information about a specific payment order by ID.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_vas_order_get(id: str) -> ResponseModel:
+ """
+ Get information about a specific payment order by ID.
+
+ Args:
+ id (str): The ID of the order to retrieve information for.
+
+ Returns:
+ ResponseModel: A model containing the response data for the specified order.
+ """
+ ...
+
+@vas_router.get(
+ path='/redeem',
+ summary='获取兑换码信息',
+ description='Get information about a specific redemption code.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_vas_redeem(code: str) -> ResponseModel:
+ """
+ Get information about a specific redemption code.
+
+ Args:
+ code (str): The redemption code to retrieve information for.
+
+ Returns:
+ ResponseModel: A model containing the response data for the specified redemption code.
+ """
+ ...
+
+@vas_router.post(
+ path='/redeem',
+ summary='执行兑换',
+ description='Redeem a redemption code for a product or service.',
+ dependencies=[Depends(SignRequired)]
+)
+def router_vas_redeem_post() -> ResponseModel:
+ """
+ Redeem a redemption code for a product or service.
+
+ Returns:
+ ResponseModel: A model containing the response data for the redeemed code.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/controllers/webdav.py b/routers/controllers/webdav.py
new file mode 100644
index 0000000..489a6e7
--- /dev/null
+++ b/routers/controllers/webdav.py
@@ -0,0 +1,108 @@
+from fastapi import APIRouter, Depends, Request
+from middleware.auth import SignRequired
+from models.response import ResponseModel
+
+# WebDAV 管理路由
+webdav_router = APIRouter(
+ prefix='/webdav',
+ tags=["webdav"],
+)
+
+@webdav_router.get(
+ path='/accounts',
+ summary='获取账号信息',
+ description='Get account information for WebDAV.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_webdav_accounts() -> ResponseModel:
+ """
+ Get account information for WebDAV.
+
+ Returns:
+ ResponseModel: A model containing the response data for the account information.
+ """
+ ...
+
+@webdav_router.post(
+ path='/accounts',
+ summary='新建账号',
+ description='Create a new WebDAV account.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_webdav_create_account() -> ResponseModel:
+ """
+ Create a new WebDAV account.
+
+ Returns:
+ ResponseModel: A model containing the response data for the created account.
+ """
+ ...
+
+@webdav_router.delete(
+ path='/accounts/{id}',
+ summary='删除账号',
+ description='Delete a WebDAV account by its ID.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_webdav_delete_account(id: str) -> ResponseModel:
+ """
+ Delete a WebDAV account by its ID.
+
+ Args:
+ id (str): The ID of the account to be deleted.
+
+ Returns:
+ ResponseModel: A model containing the response data for the deletion operation.
+ """
+ ...
+
+@webdav_router.post(
+ path='/mount',
+ summary='新建目录挂载',
+ description='Create a new WebDAV mount point.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_webdav_create_mount() -> ResponseModel:
+ """
+ Create a new WebDAV mount point.
+
+ Returns:
+ ResponseModel: A model containing the response data for the created mount point.
+ """
+ ...
+
+@webdav_router.delete(
+ path='/mount/{id}',
+ summary='删除目录挂载',
+ description='Delete a WebDAV mount point by its ID.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_webdav_delete_mount(id: str) -> ResponseModel:
+ """
+ Delete a WebDAV mount point by its ID.
+
+ Args:
+ id (str): The ID of the mount point to be deleted.
+
+ Returns:
+ ResponseModel: A model containing the response data for the deletion operation.
+ """
+ ...
+
+@webdav_router.patch(
+ path='accounts/{id}',
+ summary='更新账号信息',
+ description='Update WebDAV account information by ID.',
+ dependencies=[Depends(SignRequired)],
+)
+def router_webdav_update_account(id: str) -> ResponseModel:
+ """
+ Update WebDAV account information by ID.
+
+ Args:
+ id (str): The ID of the account to be updated.
+
+ Returns:
+ ResponseModel: A model containing the response data for the updated account.
+ """
+ ...
\ No newline at end of file
diff --git a/routers/routers.py b/routers/routers.py
new file mode 100644
index 0000000..8e180d0
--- /dev/null
+++ b/routers/routers.py
@@ -0,0 +1,43 @@
+from fastapi import APIRouter
+
+from .controllers import (
+ share,
+ site,
+ user,
+ file,
+ aria2,
+ directory,
+ object,
+ callback,
+ vas,
+ tag,
+ webdav,
+ admin
+)
+
+Router: list[APIRouter] = [
+ share.share_router,
+ site.site_router,
+ user.user_router,
+ user.user_settings_router,
+ file.file_router,
+ file.file_upload_router,
+ aria2.aria2_router,
+ directory.directory_router,
+ object.object_router,
+ callback.callback_router,
+ callback.oauth_router,
+ callback.pay_router,
+ callback.upload_router,
+ vas.vas_router,
+ tag.tag_router,
+ webdav.webdav_router,
+ admin.admin_router,
+ admin.admin_group_router,
+ admin.admin_user_router,
+ admin.admin_file_router,
+ admin.admin_aria2_router,
+ admin.admin_policy_router,
+ admin.admin_task_router,
+ admin.admin_vas_router
+]
\ No newline at end of file
diff --git a/test_main.py b/test_main.py
new file mode 100644
index 0000000..074f5fc
--- /dev/null
+++ b/test_main.py
@@ -0,0 +1,15 @@
+from fastapi.testclient import TestClient
+
+from main import app
+
+client = TestClient(app)
+
+
+def test_read_main():
+ from pkg.conf.appmeta import BackendVersion
+ response = client.get("/api/site/ping")
+ assert response.status_code == 200
+ assert response.json() == {
+ "code": 0,
+ 'data': BackendVersion,
+ 'msg': None}
\ No newline at end of file