docker build 构建修改
This commit is contained in:
@@ -162,6 +162,9 @@ def setup_routes(app: FastAPI):
|
||||
from api.apps.chunk_app import router as chunk_router
|
||||
from api.apps.mcp_server_app import router as mcp_router
|
||||
from api.apps.canvas_app import router as canvas_router
|
||||
from api.apps.tenant_app import router as tenant_router
|
||||
from api.apps.dialog_app import router as dialog_router
|
||||
from api.apps.system_app import router as system_router
|
||||
|
||||
app.include_router(user_router, prefix=f"/{API_VERSION}/user", tags=["User"])
|
||||
app.include_router(kb_router, prefix=f"/{API_VERSION}/kb", tags=["KnowledgeBase"])
|
||||
@@ -170,6 +173,9 @@ def setup_routes(app: FastAPI):
|
||||
app.include_router(chunk_router, prefix=f"/{API_VERSION}/chunk", tags=["Chunk"])
|
||||
app.include_router(mcp_router, prefix=f"/{API_VERSION}/mcp", tags=["MCP"])
|
||||
app.include_router(canvas_router, prefix=f"/{API_VERSION}/canvas", tags=["Canvas"])
|
||||
app.include_router(tenant_router, prefix=f"/{API_VERSION}/tenant", tags=["Tenant"])
|
||||
app.include_router(dialog_router, prefix=f"/{API_VERSION}/dialog", tags=["Dialog"])
|
||||
app.include_router(system_router, prefix=f"/{API_VERSION}/system", tags=["System"])
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,8 +14,17 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from flask import request
|
||||
from flask_login import login_required, current_user
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
|
||||
from api.apps.models.auth_dependencies import get_current_user
|
||||
from api.apps.models.dialog_models import (
|
||||
SetDialogRequest,
|
||||
ListDialogsNextQuery,
|
||||
ListDialogsNextBody,
|
||||
DeleteDialogRequest,
|
||||
)
|
||||
from api.db.services import duplicate_name
|
||||
from api.db.services.dialog_service import DialogService
|
||||
from api.db import StatusEnum
|
||||
@@ -23,16 +32,21 @@ from api.db.services.tenant_llm_service import TenantLLMService
|
||||
from api.db.services.knowledgebase_service import KnowledgebaseService
|
||||
from api.db.services.user_service import TenantService, UserTenantService
|
||||
from api import settings
|
||||
from api.utils.api_utils import server_error_response, get_data_error_result, validate_request
|
||||
from api.utils.api_utils import server_error_response, get_data_error_result
|
||||
from api.utils import get_uuid
|
||||
from api.utils.api_utils import get_json_result
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter()
|
||||
|
||||
@manager.route('/set', methods=['POST']) # noqa: F821
|
||||
@validate_request("prompt_config")
|
||||
@login_required
|
||||
def set_dialog():
|
||||
req = request.json
|
||||
|
||||
@router.post('/set')
|
||||
async def set_dialog(
|
||||
request: SetDialogRequest,
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""设置/创建对话框"""
|
||||
req = request.model_dump(exclude_unset=True)
|
||||
dialog_id = req.get("dialog_id", "")
|
||||
is_create = not dialog_id
|
||||
name = req.get("name", "New Dialog")
|
||||
@@ -124,10 +138,12 @@ def set_dialog():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route('/get', methods=['GET']) # noqa: F821
|
||||
@login_required
|
||||
def get():
|
||||
dialog_id = request.args["dialog_id"]
|
||||
@router.get('/get')
|
||||
async def get(
|
||||
dialog_id: str = Query(..., description="对话框ID"),
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""获取对话框详情"""
|
||||
try:
|
||||
e, dia = DialogService.get_by_id(dialog_id)
|
||||
if not e:
|
||||
@@ -150,9 +166,11 @@ def get_kb_names(kb_ids):
|
||||
return ids, nms
|
||||
|
||||
|
||||
@manager.route('/list', methods=['GET']) # noqa: F821
|
||||
@login_required
|
||||
def list_dialogs():
|
||||
@router.get('/list')
|
||||
async def list_dialogs(
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""列出对话框"""
|
||||
try:
|
||||
diags = DialogService.query(
|
||||
tenant_id=current_user.id,
|
||||
@@ -167,21 +185,24 @@ def list_dialogs():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route('/next', methods=['POST']) # noqa: F821
|
||||
@login_required
|
||||
def list_dialogs_next():
|
||||
keywords = request.args.get("keywords", "")
|
||||
page_number = int(request.args.get("page", 0))
|
||||
items_per_page = int(request.args.get("page_size", 0))
|
||||
parser_id = request.args.get("parser_id")
|
||||
orderby = request.args.get("orderby", "create_time")
|
||||
if request.args.get("desc", "true").lower() == "false":
|
||||
desc = False
|
||||
else:
|
||||
desc = True
|
||||
@router.post('/next')
|
||||
async def list_dialogs_next(
|
||||
query: ListDialogsNextQuery = Depends(),
|
||||
body: Optional[ListDialogsNextBody] = None,
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""列出对话框(分页)"""
|
||||
if body is None:
|
||||
body = ListDialogsNextBody()
|
||||
|
||||
keywords = query.keywords or ""
|
||||
page_number = int(query.page or 0)
|
||||
items_per_page = int(query.page_size or 0)
|
||||
parser_id = query.parser_id
|
||||
orderby = query.orderby or "create_time"
|
||||
desc = query.desc.lower() == "true" if query.desc else True
|
||||
|
||||
req = request.get_json()
|
||||
owner_ids = req.get("owner_ids", [])
|
||||
owner_ids = body.owner_ids or []
|
||||
try:
|
||||
if not owner_ids:
|
||||
# tenants = TenantService.get_joined_tenants_by_user_id(current_user.id)
|
||||
@@ -204,15 +225,16 @@ def list_dialogs_next():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route('/rm', methods=['POST']) # noqa: F821
|
||||
@login_required
|
||||
@validate_request("dialog_ids")
|
||||
def rm():
|
||||
req = request.json
|
||||
dialog_list=[]
|
||||
@router.post('/rm')
|
||||
async def rm(
|
||||
request: DeleteDialogRequest,
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""删除对话框"""
|
||||
dialog_list = []
|
||||
tenants = UserTenantService.query(user_id=current_user.id)
|
||||
try:
|
||||
for id in req["dialog_ids"]:
|
||||
for id in request.dialog_ids:
|
||||
for tenant in tenants:
|
||||
if DialogService.query(tenant_id=tenant.tenant_id, id=id):
|
||||
break
|
||||
@@ -220,7 +242,7 @@ def rm():
|
||||
return get_json_result(
|
||||
data=False, message='Only owner of dialog authorized for this operation.',
|
||||
code=settings.RetCode.OPERATING_ERROR)
|
||||
dialog_list.append({"id": id,"status":StatusEnum.INVALID.value})
|
||||
dialog_list.append({"id": id, "status": StatusEnum.INVALID.value})
|
||||
DialogService.update_many_by_id(dialog_list)
|
||||
return get_json_result(data=True)
|
||||
except Exception as e:
|
||||
|
||||
@@ -24,25 +24,43 @@ from api.utils.api_utils import get_json_result
|
||||
http_bearer = HTTPBearer(auto_error=False)
|
||||
|
||||
|
||||
def get_current_user(credentials: Optional[HTTPAuthorizationCredentials] = Security(http_bearer)):
|
||||
def get_current_user(
|
||||
authorization: Optional[str] = Header(None, alias="Authorization"),
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Security(http_bearer)
|
||||
):
|
||||
"""FastAPI 依赖注入:获取当前用户(替代 Flask 的 login_required 和 current_user)
|
||||
|
||||
支持两种格式的 Authorization 头:
|
||||
1. 标准格式:Bearer <token>
|
||||
2. 简化格式:<token>(不带 Bearer 前缀)
|
||||
|
||||
使用 Security(http_bearer) 可以让 FastAPI 自动在 OpenAPI schema 中添加安全要求,
|
||||
这样 Swagger UI 就会显示授权输入框并自动在请求中添加 Authorization 头。
|
||||
"""
|
||||
# 延迟导入以避免循环导入
|
||||
from api.apps.__init___fastapi import get_current_user_from_token
|
||||
|
||||
if not credentials:
|
||||
token = None
|
||||
|
||||
# 优先从 HTTPBearer 获取(标准格式:Bearer <token>)
|
||||
if credentials:
|
||||
token = credentials.credentials
|
||||
# 如果 HTTPBearer 没有获取到,尝试直接从 Header 获取(可能是简化格式)
|
||||
elif authorization:
|
||||
# 如果包含 "Bearer " 前缀,则去除它
|
||||
if authorization.startswith("Bearer "):
|
||||
token = authorization[7:] # 去除 "Bearer " 前缀(7个字符)
|
||||
else:
|
||||
# 不带 Bearer 前缀,直接使用
|
||||
token = authorization
|
||||
|
||||
if not token:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Authorization header is required"
|
||||
)
|
||||
|
||||
# HTTPBearer 已经提取了 Bearer token,credentials.credentials 就是 token 本身
|
||||
authorization = credentials.credentials
|
||||
|
||||
user = get_current_user_from_token(authorization)
|
||||
user = get_current_user_from_token(token)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
|
||||
57
api/apps/models/dialog_models.py
Normal file
57
api/apps/models/dialog_models.py
Normal file
@@ -0,0 +1,57 @@
|
||||
#
|
||||
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from typing import Optional, List, Dict, Any
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class SetDialogRequest(BaseModel):
|
||||
"""设置/创建对话框请求"""
|
||||
dialog_id: Optional[str] = Field(default="", description="对话框ID,为空时创建新对话框")
|
||||
name: Optional[str] = Field(default="New Dialog", description="对话框名称")
|
||||
description: Optional[str] = Field(default="A helpful dialog", description="对话框描述")
|
||||
icon: Optional[str] = Field(default="", description="图标")
|
||||
top_n: Optional[int] = Field(default=6, description="Top N")
|
||||
top_k: Optional[int] = Field(default=1024, description="Top K")
|
||||
rerank_id: Optional[str] = Field(default="", description="重排序模型ID")
|
||||
similarity_threshold: Optional[float] = Field(default=0.1, description="相似度阈值")
|
||||
vector_similarity_weight: Optional[float] = Field(default=0.3, description="向量相似度权重")
|
||||
llm_setting: Optional[Dict[str, Any]] = Field(default={}, description="LLM设置")
|
||||
meta_data_filter: Optional[Dict[str, Any]] = Field(default={}, description="元数据过滤器")
|
||||
prompt_config: Dict[str, Any] = Field(..., description="提示配置")
|
||||
kb_ids: Optional[List[str]] = Field(default=[], description="知识库ID列表")
|
||||
llm_id: Optional[str] = Field(default=None, description="LLM ID")
|
||||
|
||||
|
||||
class ListDialogsNextQuery(BaseModel):
|
||||
"""列出对话框查询参数"""
|
||||
keywords: Optional[str] = ""
|
||||
page: Optional[int] = 0
|
||||
page_size: Optional[int] = 0
|
||||
parser_id: Optional[str] = None
|
||||
orderby: Optional[str] = "create_time"
|
||||
desc: Optional[str] = "true"
|
||||
|
||||
|
||||
class ListDialogsNextBody(BaseModel):
|
||||
"""列出对话框请求体"""
|
||||
owner_ids: Optional[List[str]] = []
|
||||
|
||||
|
||||
class DeleteDialogRequest(BaseModel):
|
||||
"""删除对话框请求"""
|
||||
dialog_ids: List[str] = Field(..., description="要删除的对话框ID列表")
|
||||
|
||||
@@ -138,11 +138,11 @@ class GetDocumentInfosRequest(BaseModel):
|
||||
class ChangeStatusRequest(BaseModel):
|
||||
"""修改文档状态请求"""
|
||||
doc_ids: List[str]
|
||||
status: str # "0" 或 "1"
|
||||
status: int
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_status(self):
|
||||
if self.status not in ["0", "1"]:
|
||||
if self.status not in [0, 1]:
|
||||
raise ValueError('Status must be either 0 or 1!')
|
||||
return self
|
||||
|
||||
@@ -155,7 +155,7 @@ class DeleteDocumentRequest(BaseModel):
|
||||
class RunDocumentRequest(BaseModel):
|
||||
"""运行文档解析请求"""
|
||||
doc_ids: List[str]
|
||||
run: str # TaskStatus 值
|
||||
run: int # TaskStatus 值
|
||||
delete: Optional[bool] = False
|
||||
|
||||
|
||||
|
||||
23
api/apps/models/tenant_models.py
Normal file
23
api/apps/models/tenant_models.py
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from pydantic import BaseModel, Field, EmailStr
|
||||
|
||||
|
||||
class InviteUserRequest(BaseModel):
|
||||
"""邀请用户请求"""
|
||||
email: EmailStr = Field(..., description="要邀请的用户邮箱")
|
||||
|
||||
@@ -17,7 +17,8 @@ import logging
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
from flask_login import login_required, current_user
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from api.db.db_models import APIToken
|
||||
from api.db.services.api_service import APITokenService
|
||||
@@ -36,67 +37,26 @@ from rag.utils.storage_factory import STORAGE_IMPL, STORAGE_IMPL_TYPE
|
||||
from timeit import default_timer as timer
|
||||
|
||||
from rag.utils.redis_conn import REDIS_CONN
|
||||
from flask import jsonify
|
||||
from api.utils.health_utils import run_health_checks
|
||||
from api.apps.models.auth_dependencies import get_current_user
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@manager.route("/version", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def version():
|
||||
"""
|
||||
Get the current version of the application.
|
||||
---
|
||||
tags:
|
||||
- System
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: Version retrieved successfully.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
description: Version number.
|
||||
"""
|
||||
@router.get("/version")
|
||||
async def version(
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""获取应用程序当前版本"""
|
||||
return get_json_result(data=get_ragflow_version())
|
||||
|
||||
|
||||
@manager.route("/status", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def status():
|
||||
"""
|
||||
Get the system status.
|
||||
---
|
||||
tags:
|
||||
- System
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: System is operational.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
es:
|
||||
type: object
|
||||
description: Elasticsearch status.
|
||||
storage:
|
||||
type: object
|
||||
description: Storage status.
|
||||
database:
|
||||
type: object
|
||||
description: Database status.
|
||||
503:
|
||||
description: Service unavailable.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Error message.
|
||||
"""
|
||||
@router.get("/status")
|
||||
async def status(
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""获取系统状态"""
|
||||
res = {}
|
||||
st = timer()
|
||||
try:
|
||||
@@ -172,43 +132,24 @@ def status():
|
||||
return get_json_result(data=res)
|
||||
|
||||
|
||||
@manager.route("/healthz", methods=["GET"]) # noqa: F821
|
||||
def healthz():
|
||||
@router.get("/healthz")
|
||||
async def healthz():
|
||||
"""健康检查"""
|
||||
result, all_ok = run_health_checks()
|
||||
return jsonify(result), (200 if all_ok else 500)
|
||||
return JSONResponse(content=result, status_code=200 if all_ok else 500)
|
||||
|
||||
|
||||
@manager.route("/ping", methods=["GET"]) # noqa: F821
|
||||
def ping():
|
||||
return "pong", 200
|
||||
@router.get("/ping")
|
||||
async def ping():
|
||||
"""心跳检测"""
|
||||
return "pong"
|
||||
|
||||
|
||||
@manager.route("/new_token", methods=["POST"]) # noqa: F821
|
||||
@login_required
|
||||
def new_token():
|
||||
"""
|
||||
Generate a new API token.
|
||||
---
|
||||
tags:
|
||||
- API Tokens
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
parameters:
|
||||
- in: query
|
||||
name: name
|
||||
type: string
|
||||
required: false
|
||||
description: Name of the token.
|
||||
responses:
|
||||
200:
|
||||
description: Token generated successfully.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: The generated API token.
|
||||
"""
|
||||
@router.post("/new_token")
|
||||
async def new_token(
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""生成新的 API 令牌"""
|
||||
try:
|
||||
tenants = UserTenantService.query(user_id=current_user.id)
|
||||
if not tenants:
|
||||
@@ -233,37 +174,11 @@ def new_token():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/token_list", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def token_list():
|
||||
"""
|
||||
List all API tokens for the current user.
|
||||
---
|
||||
tags:
|
||||
- API Tokens
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: List of API tokens.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
tokens:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: The API token.
|
||||
name:
|
||||
type: string
|
||||
description: Name of the token.
|
||||
create_time:
|
||||
type: string
|
||||
description: Token creation time.
|
||||
"""
|
||||
@router.get("/token_list")
|
||||
async def token_list(
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""列出当前用户的所有 API 令牌"""
|
||||
try:
|
||||
tenants = UserTenantService.query(user_id=current_user.id)
|
||||
if not tenants:
|
||||
@@ -282,55 +197,21 @@ def token_list():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/token/<token>", methods=["DELETE"]) # noqa: F821
|
||||
@login_required
|
||||
def rm(token):
|
||||
"""
|
||||
Remove an API token.
|
||||
---
|
||||
tags:
|
||||
- API Tokens
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
parameters:
|
||||
- in: path
|
||||
name: token
|
||||
type: string
|
||||
required: true
|
||||
description: The API token to remove.
|
||||
responses:
|
||||
200:
|
||||
description: Token removed successfully.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success:
|
||||
type: boolean
|
||||
description: Deletion status.
|
||||
"""
|
||||
@router.delete("/token/{token}")
|
||||
async def rm(
|
||||
token: str,
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""删除 API 令牌"""
|
||||
APITokenService.filter_delete(
|
||||
[APIToken.tenant_id == current_user.id, APIToken.token == token]
|
||||
)
|
||||
return get_json_result(data=True)
|
||||
|
||||
|
||||
@manager.route('/config', methods=['GET']) # noqa: F821
|
||||
def get_config():
|
||||
"""
|
||||
Get system configuration.
|
||||
---
|
||||
tags:
|
||||
- System
|
||||
responses:
|
||||
200:
|
||||
description: Return system configuration
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
registerEnable:
|
||||
type: integer 0 means disabled, 1 means enabled
|
||||
description: Whether user registration is enabled
|
||||
"""
|
||||
@router.get('/config')
|
||||
async def get_config():
|
||||
"""获取系统配置"""
|
||||
return get_json_result(data={
|
||||
"registerEnabled": settings.REGISTER_ENABLED
|
||||
})
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from flask import request
|
||||
from flask_login import login_required, current_user
|
||||
from fastapi import APIRouter, Depends, Path
|
||||
|
||||
from api.apps.models.auth_dependencies import get_current_user
|
||||
from api.apps.models.tenant_models import InviteUserRequest
|
||||
from api import settings
|
||||
from api.apps import smtp_mail_server
|
||||
from api.db import UserTenantRole, StatusEnum
|
||||
@@ -24,13 +25,19 @@ from api.db.db_models import UserTenant
|
||||
from api.db.services.user_service import UserTenantService, UserService
|
||||
|
||||
from api.utils import get_uuid, delta_seconds
|
||||
from api.utils.api_utils import get_json_result, validate_request, server_error_response, get_data_error_result
|
||||
from api.utils.api_utils import get_json_result, server_error_response, get_data_error_result
|
||||
from api.utils.web_utils import send_invite_email
|
||||
|
||||
# 创建路由器
|
||||
router = APIRouter()
|
||||
|
||||
@manager.route("/<tenant_id>/user/list", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def user_list(tenant_id):
|
||||
|
||||
@router.get("/{tenant_id}/user/list")
|
||||
async def user_list(
|
||||
tenant_id: str = Path(..., description="租户ID"),
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""获取租户用户列表"""
|
||||
if current_user.id != tenant_id:
|
||||
return get_json_result(
|
||||
data=False,
|
||||
@@ -46,18 +53,20 @@ def user_list(tenant_id):
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route('/<tenant_id>/user', methods=['POST']) # noqa: F821
|
||||
@login_required
|
||||
@validate_request("email")
|
||||
def create(tenant_id):
|
||||
@router.post('/{tenant_id}/user')
|
||||
async def create(
|
||||
tenant_id: str,
|
||||
request: InviteUserRequest,
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""邀请用户加入租户"""
|
||||
if current_user.id != tenant_id:
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message='No authorization.',
|
||||
code=settings.RetCode.AUTHENTICATION_ERROR)
|
||||
|
||||
req = request.json
|
||||
invite_user_email = req["email"]
|
||||
invite_user_email = request.email
|
||||
invite_users = UserService.query(email=invite_user_email)
|
||||
if not invite_users:
|
||||
return get_data_error_result(message="User not found.")
|
||||
@@ -101,9 +110,13 @@ def create(tenant_id):
|
||||
return get_json_result(data=usr)
|
||||
|
||||
|
||||
@manager.route('/<tenant_id>/user/<user_id>', methods=['DELETE']) # noqa: F821
|
||||
@login_required
|
||||
def rm(tenant_id, user_id):
|
||||
@router.delete('/{tenant_id}/user/{user_id}')
|
||||
async def rm(
|
||||
tenant_id: str = Path(..., description="租户ID"),
|
||||
user_id: str = Path(..., description="用户ID"),
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""从租户中删除用户"""
|
||||
if current_user.id != tenant_id and current_user.id != user_id:
|
||||
return get_json_result(
|
||||
data=False,
|
||||
@@ -117,9 +130,11 @@ def rm(tenant_id, user_id):
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/list", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
def tenant_list():
|
||||
@router.get("/list")
|
||||
async def tenant_list(
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""获取租户列表"""
|
||||
try:
|
||||
users = UserTenantService.get_tenants_by_user_id(current_user.id)
|
||||
for u in users:
|
||||
@@ -129,9 +144,12 @@ def tenant_list():
|
||||
return server_error_response(e)
|
||||
|
||||
|
||||
@manager.route("/agree/<tenant_id>", methods=["PUT"]) # noqa: F821
|
||||
@login_required
|
||||
def agree(tenant_id):
|
||||
@router.put("/agree/{tenant_id}")
|
||||
async def agree(
|
||||
tenant_id: str = Path(..., description="租户ID"),
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
"""同意加入租户邀请"""
|
||||
try:
|
||||
UserTenantService.filter_update([UserTenant.tenant_id == tenant_id, UserTenant.user_id == current_user.id],
|
||||
{"role": UserTenantRole.NORMAL})
|
||||
|
||||
Reference in New Issue
Block a user