Refactor routes to better align with RESTful (#645)

This commit is contained in:
Wu Clan
2025-05-31 17:01:44 +08:00
committed by GitHub
parent 6ee3983846
commit 57ae7f03a6
11 changed files with 84 additions and 89 deletions
+2 -2
View File
@@ -34,8 +34,8 @@ async def user_login(
return response_base.success(data=data)
@router.post('/token/new', summary='创建新 token')
async def create_new_token(request: Request) -> ResponseSchemaModel[GetNewToken]:
@router.post('/tokens/refresh', summary='新 token')
async def refresh_token(request: Request) -> ResponseSchemaModel[GetNewToken]:
data = await auth_service.new_token(request=request)
return response_base.success(data=data)
+1 -1
View File
@@ -20,4 +20,4 @@ router.include_router(user_router, prefix='/users', tags=['系统用户'])
router.include_router(data_rule_router, prefix='/data-rules', tags=['系统数据规则'])
router.include_router(data_scope_router, prefix='/data-scopes', tags=['系统数据范围'])
router.include_router(upload_router, prefix='/upload', tags=['系统上传'])
router.include_router(plugin_router, prefix='/plugin', tags=['系统插件'])
router.include_router(plugin_router, prefix='/plugins', tags=['系统插件'])
+1 -1
View File
@@ -27,7 +27,7 @@ async def get_data_rule_models() -> ResponseSchemaModel[list[str]]:
return response_base.success(data=models)
@router.get('/model/{model}/columns', summary='获取数据规则可用模型列', dependencies=[DependsJwtAuth])
@router.get('/models/{model}/columns', summary='获取数据规则可用模型列', dependencies=[DependsJwtAuth])
async def get_data_rule_model_columns(
model: Annotated[str, Path(description='模型名称')],
) -> ResponseSchemaModel[list[GetDataRuleColumnDetail]]:
+12 -12
View File
@@ -22,18 +22,18 @@ async def get_all_plugins() -> ResponseSchemaModel[list[dict[str, Any]]]:
return response_base.success(data=plugins)
@router.get('/changed', summary='插件状态是否变更', dependencies=[DependsJwtAuth])
@router.get('/changes', summary='插件状态是否变更', dependencies=[DependsJwtAuth])
async def plugin_changed() -> ResponseSchemaModel[bool]:
plugins = await plugin_service.changed()
return response_base.success(data=bool(plugins))
@router.post(
'/install/zip',
'/zip',
summary='安装 zip 插件',
description='使用插件 zip 压缩包进行安装',
dependencies=[
Depends(RequestPermission('sys:plugin:install')),
Depends(RequestPermission('sys:plugin:zip')),
DependsRBAC,
],
)
@@ -43,11 +43,11 @@ async def install_zip_plugin(file: Annotated[UploadFile, File()]) -> ResponseMod
@router.post(
'/install/git',
'/git',
summary='安装 git 插件',
description='使用插件 git 仓库地址进行安装,不限制平台;如果需要凭证,需在 git 仓库地址中添加凭证信息',
dependencies=[
Depends(RequestPermission('sys:plugin:install')),
Depends(RequestPermission('sys:plugin:git')),
DependsRBAC,
],
)
@@ -57,35 +57,35 @@ async def install_git_plugin(repo_url: Annotated[str, Query(description='插件
@router.delete(
'/uninstall',
'/{plugin}',
summary='卸载插件',
description='此操作会直接删除插件依赖,但不会直接删除插件,而是将插件移动到备份目录',
dependencies=[
Depends(RequestPermission('sys:plugin:uninstall')),
Depends(RequestPermission('sys:plugin:del')),
DependsRBAC,
],
)
async def uninstall_plugin(plugin: Annotated[str, Query(description='插件名称')]) -> ResponseModel:
async def uninstall_plugin(plugin: Annotated[str, Path(description='插件名称')]) -> ResponseModel:
await plugin_service.uninstall(plugin=plugin)
return response_base.success(res=CustomResponseCode.PLUGIN_UNINSTALL_SUCCESS)
@router.post(
'/status',
'/{plugin}/status',
summary='更新插件状态',
dependencies=[
Depends(RequestPermission('sys:plugin:status')),
DependsRBAC,
],
)
async def update_plugin_status(plugin: Annotated[str, Query(description='插件名称')]) -> ResponseModel:
async def update_plugin_status(plugin: Annotated[str, Path(description='插件名称')]) -> ResponseModel:
await plugin_service.update_status(plugin=plugin)
return response_base.success()
@router.get(
'/zip/{plugin}',
summary='打包插件',
'/{plugin}',
summary='打包并下载插件',
dependencies=[
Depends(RequestPermission('sys:plugin:zip')),
DependsRBAC,
+2 -10
View File
@@ -29,14 +29,6 @@ async def get_all_roles() -> ResponseSchemaModel[list[GetRoleDetail]]:
return response_base.success(data=data)
@router.get('/{pk}/all', summary='获取用户所有角色', dependencies=[DependsJwtAuth])
async def get_user_all_roles(
pk: Annotated[int, Path(description='用户 ID')],
) -> ResponseSchemaModel[list[GetRoleDetail]]:
data = await role_service.get_users(pk=pk)
return response_base.success(data=data)
@router.get('/{pk}/menus', summary='获取角色所有菜单', dependencies=[DependsJwtAuth])
async def get_role_all_menus(
pk: Annotated[int, Path(description='角色 ID')],
@@ -106,7 +98,7 @@ async def update_role(pk: Annotated[int, Path(description='角色 ID')], obj: Up
@router.put(
'/{pk}/menu',
'/{pk}/menus',
summary='更新角色菜单',
dependencies=[
Depends(RequestPermission('sys:role:menu:edit')),
@@ -123,7 +115,7 @@ async def update_role_menus(
@router.put(
'/{pk}/scope',
'/{pk}/scopes',
summary='更新角色数据范围',
dependencies=[
Depends(RequestPermission('sys:role:scope:edit')),
+22 -11
View File
@@ -4,6 +4,7 @@ from typing import Annotated
from fastapi import APIRouter, Depends, Path, Query, Request
from backend.app.admin.schema.role import GetRoleDetail
from backend.app.admin.schema.user import (
AddUserParam,
GetCurrentUserInfoWithRelationDetail,
@@ -36,9 +37,11 @@ async def add_user(request: Request, obj: AddUserParam) -> ResponseSchemaModel[G
return response_base.success(data=data)
@router.post('/password/reset', summary='密码重置', dependencies=[DependsJwtAuth])
async def password_reset(request: Request, obj: ResetPasswordParam) -> ResponseModel:
count = await user_service.pwd_reset(request=request, obj=obj)
@router.post('/{username}/password', summary='密码重置', dependencies=[DependsJwtAuth])
async def password_reset(
username: Annotated[str, Path(description='用户名')], obj: ResetPasswordParam
) -> ResponseModel:
count = await user_service.pwd_reset(username=username, obj=obj)
if count > 0:
return response_base.success()
return response_base.fail()
@@ -58,14 +61,12 @@ async def get_user(
return response_base.success(data=data)
@router.put('/{username}', summary='更新用户信息', dependencies=[DependsJwtAuth])
async def update_user(
request: Request, username: Annotated[str, Path(description='用户名')], obj: UpdateUserParam
) -> ResponseModel:
count = await user_service.update(request=request, username=username, obj=obj)
if count > 0:
return response_base.success()
return response_base.fail()
@router.get('/{username}/roles', summary='获取用户所有角色', dependencies=[DependsJwtAuth])
async def get_user_all_roles(
username: Annotated[str, Path(description='用户名')],
) -> ResponseSchemaModel[list[GetRoleDetail]]:
data = await user_service.get_roles(username=username)
return response_base.success(data=data)
@router.get(
@@ -88,6 +89,16 @@ async def get_pagination_users(
return response_base.success(data=page_data)
@router.put('/{username}', summary='更新用户信息', dependencies=[DependsJwtAuth])
async def update_user(
request: Request, username: Annotated[str, Path(description='用户名')], obj: UpdateUserParam
) -> ResponseModel:
count = await user_service.update(request=request, username=username, obj=obj)
if count > 0:
return response_base.success()
return response_base.fail()
@router.put('/{pk}/super', summary='修改用户超级权限', dependencies=[DependsRBAC])
async def super_set(request: Request, pk: Annotated[int, Path(description='用户 ID')]) -> ResponseModel:
count = await user_service.update_permission(request=request, pk=pk)
+1 -13
View File
@@ -7,7 +7,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import noload, selectinload
from sqlalchemy_crud_plus import CRUDPlus
from backend.app.admin.model import DataScope, Menu, Role, User
from backend.app.admin.model import DataScope, Menu, Role
from backend.app.admin.schema.role import (
CreateRoleParam,
UpdateRoleMenuParam,
@@ -54,18 +54,6 @@ class CRUDRole(CRUDPlus[Role]):
"""
return await self.select_models(db)
async def get_users(self, db: AsyncSession, user_id: int) -> Sequence[Role]:
"""
获取用户角色列表
:param db: 数据库会话
:param user_id: 用户 ID
:return:
"""
stmt = select(self.model).join(self.model.users).where(User.id == user_id)
roles = await db.execute(stmt)
return roles.scalars().all()
async def get_list(self, name: str | None, status: int | None) -> Select:
"""
获取角色列表
-12
View File
@@ -45,18 +45,6 @@ class RoleService:
roles = await role_dao.get_all(db)
return roles
@staticmethod
async def get_users(*, pk: int) -> Sequence[Role]:
"""
获取用户的角色列表
:param pk: 用户 ID
:return:
"""
async with async_db_session() as db:
roles = await role_dao.get_users(db, user_id=pk)
return roles
@staticmethod
async def get_select(*, name: str | None, status: int | None) -> Select:
"""
+37 -21
View File
@@ -2,13 +2,15 @@
# -*- coding: utf-8 -*-
import random
from typing import Sequence
from fastapi import Request
from sqlalchemy import Select
from backend.app.admin.crud.crud_dept import dept_dao
from backend.app.admin.crud.crud_role import role_dao
from backend.app.admin.crud.crud_user import user_dao
from backend.app.admin.model import User
from backend.app.admin.model import Role, User
from backend.app.admin.schema.user import (
AddUserParam,
RegisterUserParam,
@@ -81,16 +83,16 @@ class UserService:
await user_dao.add(db, obj)
@staticmethod
async def pwd_reset(*, request: Request, obj: ResetPasswordParam) -> int:
async def pwd_reset(*, username: str, obj: ResetPasswordParam) -> int:
"""
重置用户密码
:param request: FastAPI 请求对象
:param username: 用户名
:param obj: 密码重置参数
:return:
"""
async with async_db_session.begin() as db:
user = await user_dao.get(db, request.user.id)
user = await user_dao.get_by_username(db, username)
if not user:
raise errors.NotFoundError(msg='用户不存在')
if not password_verify(obj.old_password, user.password):
@@ -98,11 +100,11 @@ class UserService:
if obj.new_password != obj.confirm_password:
raise errors.ForbiddenError(msg='密码输入不一致')
new_pwd = get_hash_password(obj.new_password, user.salt)
count = await user_dao.reset_password(db, request.user.id, new_pwd)
count = await user_dao.reset_password(db, user.id, new_pwd)
key_prefix = [
f'{settings.TOKEN_REDIS_PREFIX}:{request.user.id}',
f'{settings.TOKEN_REFRESH_REDIS_PREFIX}:{request.user.id}',
f'{settings.JWT_USER_REDIS_PREFIX}:{request.user.id}',
f'{settings.TOKEN_REDIS_PREFIX}:{user.id}',
f'{settings.TOKEN_REFRESH_REDIS_PREFIX}:{user.id}',
f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}',
]
for prefix in key_prefix:
await redis_client.delete_prefix(prefix)
@@ -122,6 +124,33 @@ class UserService:
raise errors.NotFoundError(msg='用户不存在')
return user
@staticmethod
async def get_roles(*, username: str) -> Sequence[Role]:
"""
获取用户所有角色
:param username: 用户名
:return:
"""
async with async_db_session() as db:
user = await user_dao.get_with_relation(db, username=username)
if not user:
raise errors.NotFoundError(msg='用户不存在')
return user.roles
@staticmethod
async def get_select(*, dept: int, username: str, phone: str, status: int) -> Select:
"""
获取用户列表查询条件
:param dept: 部门 ID
:param username: 用户名
:param phone: 手机号
:param status: 状态
:return:
"""
return await user_dao.get_list(dept=dept, username=username, phone=phone, status=status)
@staticmethod
async def update(*, request: Request, username: str, obj: UpdateUserParam) -> int:
"""
@@ -158,19 +187,6 @@ class UserService:
await redis_client.delete(f'{settings.JWT_USER_REDIS_PREFIX}:{user.id}')
return count
@staticmethod
async def get_select(*, dept: int, username: str, phone: str, status: int) -> Select:
"""
获取用户列表查询条件
:param dept: 部门 ID
:param username: 用户名
:param phone: 手机号
:param status: 状态
:return:
"""
return await user_dao.get_list(dept=dept, username=username, phone=phone, status=status)
@staticmethod
async def update_permission(*, request: Request, pk: int) -> int:
"""
+1 -1
View File
@@ -9,6 +9,6 @@ from backend.plugin.code_generator.api.v1.gen import router as gen_router
v1 = APIRouter(prefix=f'{settings.FASTAPI_API_V1_PATH}/gen', tags=['代码生成'])
v1.include_router(gen_router)
v1.include_router(gen_router, prefix='/tables')
v1.include_router(business_router, prefix='/businesses')
v1.include_router(model_router, prefix='/models')
+5 -5
View File
@@ -16,7 +16,7 @@ from backend.plugin.code_generator.service.gen_service import gen_service
router = APIRouter()
@router.get('/tables', summary='获取数据库表')
@router.get('', summary='获取数据库表')
async def get_all_tables(
table_schema: Annotated[str, Query(description='数据库名')] = 'fba',
) -> ResponseSchemaModel[list[str]]:
@@ -37,20 +37,20 @@ async def import_table(obj: ImportParam) -> ResponseModel:
return response_base.success()
@router.get('/preview/{pk}', summary='生成代码预览', dependencies=[DependsJwtAuth])
@router.get('/{pk}/preview', summary='生成代码预览', dependencies=[DependsJwtAuth])
async def preview_code(pk: Annotated[int, Path(description='业务 ID')]) -> ResponseSchemaModel[dict[str, bytes]]:
data = await gen_service.preview(pk=pk)
return response_base.success(data=data)
@router.get('/generate/{pk}/path', summary='获取代码生成路径', dependencies=[DependsJwtAuth])
@router.get('/{pk}/code/path', summary='获取代码生成路径', dependencies=[DependsJwtAuth])
async def generate_path(pk: Annotated[int, Path(description='业务 ID')]) -> ResponseSchemaModel[list[str]]:
data = await gen_service.get_generate_path(pk=pk)
return response_base.success(data=data)
@router.post(
'/generate/{pk}',
'/{pk}/code',
summary='代码生成',
description='文件磁盘写入,请谨慎操作',
dependencies=[
@@ -63,7 +63,7 @@ async def generate_code(pk: Annotated[int, Path(description='业务 ID')]) -> Re
return response_base.success()
@router.get('/download/{pk}', summary='下载代码', dependencies=[DependsJwtAuth])
@router.get('/{pk}', summary='下载代码', dependencies=[DependsJwtAuth])
async def download_code(pk: Annotated[int, Path(description='业务 ID')]):
bio = await gen_service.download(pk=pk)
return StreamingResponse(