mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
refactor(api): continue decoupling dify_graph from API concerns (#33580)
Signed-off-by: -LAN- <laipz8200@outlook.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: WH-2099 <wh2099@pm.me>
This commit is contained in:
103
api/core/app/file_access/controller.py
Normal file
103
api/core/app/file_access/controller.py
Normal file
@ -0,0 +1,103 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.sql import Select
|
||||
|
||||
from models import ToolFile, UploadFile
|
||||
from models.enums import CreatorUserRole
|
||||
|
||||
from .protocols import FileAccessControllerProtocol
|
||||
from .scope import FileAccessScope, get_current_file_access_scope
|
||||
|
||||
|
||||
class DatabaseFileAccessController(FileAccessControllerProtocol):
|
||||
"""Workflow-layer authorization helper for database-backed file lookups.
|
||||
|
||||
Tenant scoping remains mandatory. When the current execution belongs to an
|
||||
end user, the lookup is additionally constrained to that end user's file
|
||||
ownership markers.
|
||||
"""
|
||||
|
||||
_scope_getter: Callable[[], FileAccessScope | None]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
scope_getter: Callable[[], FileAccessScope | None] = get_current_file_access_scope,
|
||||
) -> None:
|
||||
self._scope_getter = scope_getter
|
||||
|
||||
def current_scope(self) -> FileAccessScope | None:
|
||||
return self._scope_getter()
|
||||
|
||||
def apply_upload_file_filters(
|
||||
self,
|
||||
stmt: Select[tuple[UploadFile]],
|
||||
*,
|
||||
scope: FileAccessScope | None = None,
|
||||
) -> Select[tuple[UploadFile]]:
|
||||
resolved_scope = scope or self.current_scope()
|
||||
if resolved_scope is None:
|
||||
return stmt
|
||||
|
||||
scoped_stmt = stmt.where(UploadFile.tenant_id == resolved_scope.tenant_id)
|
||||
if not resolved_scope.requires_user_ownership:
|
||||
return scoped_stmt
|
||||
|
||||
return scoped_stmt.where(
|
||||
UploadFile.created_by_role == CreatorUserRole.END_USER,
|
||||
UploadFile.created_by == resolved_scope.user_id,
|
||||
)
|
||||
|
||||
def apply_tool_file_filters(
|
||||
self,
|
||||
stmt: Select[tuple[ToolFile]],
|
||||
*,
|
||||
scope: FileAccessScope | None = None,
|
||||
) -> Select[tuple[ToolFile]]:
|
||||
resolved_scope = scope or self.current_scope()
|
||||
if resolved_scope is None:
|
||||
return stmt
|
||||
|
||||
scoped_stmt = stmt.where(ToolFile.tenant_id == resolved_scope.tenant_id)
|
||||
if not resolved_scope.requires_user_ownership:
|
||||
return scoped_stmt
|
||||
|
||||
return scoped_stmt.where(ToolFile.user_id == resolved_scope.user_id)
|
||||
|
||||
def get_upload_file(
|
||||
self,
|
||||
*,
|
||||
session: Session,
|
||||
file_id: str,
|
||||
scope: FileAccessScope | None = None,
|
||||
) -> UploadFile | None:
|
||||
resolved_scope = scope or self.current_scope()
|
||||
if resolved_scope is None:
|
||||
return session.get(UploadFile, file_id)
|
||||
|
||||
stmt = self.apply_upload_file_filters(
|
||||
select(UploadFile).where(UploadFile.id == file_id),
|
||||
scope=resolved_scope,
|
||||
)
|
||||
return session.scalar(stmt)
|
||||
|
||||
def get_tool_file(
|
||||
self,
|
||||
*,
|
||||
session: Session,
|
||||
file_id: str,
|
||||
scope: FileAccessScope | None = None,
|
||||
) -> ToolFile | None:
|
||||
resolved_scope = scope or self.current_scope()
|
||||
if resolved_scope is None:
|
||||
return session.get(ToolFile, file_id)
|
||||
|
||||
stmt = self.apply_tool_file_filters(
|
||||
select(ToolFile).where(ToolFile.id == file_id),
|
||||
scope=resolved_scope,
|
||||
)
|
||||
return session.scalar(stmt)
|
||||
Reference in New Issue
Block a user