mirror of
https://github.com/langgenius/dify.git
synced 2026-05-10 05:56:31 +08:00
refactor: refactor rbac api
This commit is contained in:
parent
9fa1e69904
commit
435c8ec96c
@ -276,11 +276,8 @@ class RBACAccessPolicyCopyApi(Resource):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class _ReplaceRoleBindingsRequest(BaseModel):
|
||||
class _ReplaceBindingsRequest(BaseModel):
|
||||
role_ids: list[str] = []
|
||||
|
||||
|
||||
class _ReplaceMemberBindingsRequest(BaseModel):
|
||||
account_ids: list[str] = []
|
||||
|
||||
|
||||
@ -319,21 +316,6 @@ class RBACAppRoleBindingsApi(Resource):
|
||||
svc.RBACService.AppAccess.list_role_bindings(tenant_id, account_id, str(app_id), str(policy_id))
|
||||
)
|
||||
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, app_id, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceRoleBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.AppAccess.replace_role_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(app_id),
|
||||
str(policy_id),
|
||||
svc.ReplaceRoleBindings(role_ids=list(request.role_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/access-policies/<uuid:policy_id>/member-bindings")
|
||||
class RBACAppMemberBindingsApi(Resource):
|
||||
@ -345,18 +327,21 @@ class RBACAppMemberBindingsApi(Resource):
|
||||
svc.RBACService.AppAccess.list_member_bindings(tenant_id, account_id, str(app_id), str(policy_id))
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/access-policies/<uuid:policy_id>/bindings")
|
||||
class RBACAppBindingsApi(Resource):
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, app_id, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceMemberBindingsRequest)
|
||||
request = _payload(_ReplaceBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.AppAccess.replace_member_bindings(
|
||||
svc.RBACService.AppAccess.replace_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(app_id),
|
||||
str(policy_id),
|
||||
svc.ReplaceMemberBindings(account_ids=list(request.account_ids)),
|
||||
svc.ReplaceBindings(role_ids=list(request.role_ids), account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
@ -387,18 +372,21 @@ class RBACDatasetRoleBindingsApi(Resource):
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/access-policies/<uuid:policy_id>/bindings")
|
||||
class RBACDatasetBindingsApi(Resource):
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, dataset_id, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceRoleBindingsRequest)
|
||||
request = _payload(_ReplaceBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.DatasetAccess.replace_role_bindings(
|
||||
svc.RBACService.DatasetAccess.replace_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(dataset_id),
|
||||
str(policy_id),
|
||||
svc.ReplaceRoleBindings(role_ids=list(request.role_ids)),
|
||||
svc.ReplaceBindings(role_ids=list(request.role_ids), account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
@ -417,21 +405,6 @@ class RBACDatasetMemberBindingsApi(Resource):
|
||||
)
|
||||
)
|
||||
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, dataset_id, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceMemberBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.DatasetAccess.replace_member_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(dataset_id),
|
||||
str(policy_id),
|
||||
svc.ReplaceMemberBindings(account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Workspace-level access (Settings > Access Rules).
|
||||
@ -458,17 +431,20 @@ class RBACWorkspaceAppRoleBindingsApi(Resource):
|
||||
svc.RBACService.WorkspaceAccess.list_app_role_bindings(tenant_id, account_id, str(policy_id))
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/rbac/workspace/apps/access-policies/<uuid:policy_id>/bindings")
|
||||
class RBACWorkspaceAppBindingsApi(Resource):
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceRoleBindingsRequest)
|
||||
request = _payload(_ReplaceBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.WorkspaceAccess.replace_app_role_bindings(
|
||||
svc.RBACService.WorkspaceAccess.replace_app_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(policy_id),
|
||||
svc.ReplaceRoleBindings(role_ids=list(request.role_ids)),
|
||||
svc.ReplaceBindings(role_ids=list(request.role_ids), account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
@ -483,20 +459,6 @@ class RBACWorkspaceAppMemberBindingsApi(Resource):
|
||||
svc.RBACService.WorkspaceAccess.list_app_member_bindings(tenant_id, account_id, str(policy_id))
|
||||
)
|
||||
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceMemberBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.WorkspaceAccess.replace_app_member_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(policy_id),
|
||||
svc.ReplaceMemberBindings(account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/rbac/workspace/datasets/access-policy")
|
||||
class RBACWorkspaceDatasetMatrixApi(Resource):
|
||||
@ -518,17 +480,20 @@ class RBACWorkspaceDatasetRoleBindingsApi(Resource):
|
||||
svc.RBACService.WorkspaceAccess.list_dataset_role_bindings(tenant_id, account_id, str(policy_id))
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/workspaces/current/rbac/workspace/datasets/access-policies/<uuid:policy_id>/bindings")
|
||||
class RBACWorkspaceDatasetBindingsApi(Resource):
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceRoleBindingsRequest)
|
||||
request = _payload(_ReplaceBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.WorkspaceAccess.replace_dataset_role_bindings(
|
||||
svc.RBACService.WorkspaceAccess.replace_dataset_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(policy_id),
|
||||
svc.ReplaceRoleBindings(role_ids=list(request.role_ids)),
|
||||
svc.ReplaceBindings(role_ids=list(request.role_ids), account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
@ -543,20 +508,6 @@ class RBACWorkspaceDatasetMemberBindingsApi(Resource):
|
||||
svc.RBACService.WorkspaceAccess.list_dataset_member_bindings(tenant_id, account_id, str(policy_id))
|
||||
)
|
||||
|
||||
@enterprise_only
|
||||
@login_required
|
||||
def put(self, policy_id):
|
||||
tenant_id, account_id = _current_ids()
|
||||
request = _payload(_ReplaceMemberBindingsRequest)
|
||||
return _dump(
|
||||
svc.RBACService.WorkspaceAccess.replace_dataset_member_bindings(
|
||||
tenant_id,
|
||||
account_id,
|
||||
str(policy_id),
|
||||
svc.ReplaceMemberBindings(account_ids=list(request.account_ids)),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Member ↔ role bindings (Settings > Members > Assign roles).
|
||||
|
||||
@ -192,6 +192,11 @@ class ReplaceMemberBindings(_RBACModel):
|
||||
account_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ReplaceBindings(_RBACModel):
|
||||
role_ids: list[str] = Field(default_factory=list)
|
||||
account_ids: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ListOption(_RBACModel):
|
||||
page_number: int | None = None
|
||||
results_per_page: int | None = None
|
||||
@ -525,6 +530,24 @@ class RBACService:
|
||||
)
|
||||
return MemberBindingsResponse.model_validate(data or {})
|
||||
|
||||
@staticmethod
|
||||
def replace_bindings(
|
||||
tenant_id: str,
|
||||
account_id: str | None,
|
||||
app_id: str,
|
||||
policy_id: str,
|
||||
payload: ReplaceBindings,
|
||||
) -> AccessMatrixItem:
|
||||
data = _inner_call(
|
||||
"PUT",
|
||||
f"{_INNER_PREFIX}/apps/access-policy/bindings",
|
||||
tenant_id=tenant_id,
|
||||
account_id=account_id,
|
||||
params={"app_id": app_id, "policy_id": policy_id},
|
||||
json=payload.model_dump(mode="json"),
|
||||
)
|
||||
return AccessMatrixItem.model_validate(data or {})
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Per-dataset access (screenshot 1: Knowledge Base Access Config).
|
||||
# ------------------------------------------------------------------
|
||||
@ -608,6 +631,24 @@ class RBACService:
|
||||
)
|
||||
return MemberBindingsResponse.model_validate(data or {})
|
||||
|
||||
@staticmethod
|
||||
def replace_bindings(
|
||||
tenant_id: str,
|
||||
account_id: str | None,
|
||||
dataset_id: str,
|
||||
policy_id: str,
|
||||
payload: ReplaceBindings,
|
||||
) -> AccessMatrixItem:
|
||||
data = _inner_call(
|
||||
"PUT",
|
||||
f"{_INNER_PREFIX}/datasets/access-policy/bindings",
|
||||
tenant_id=tenant_id,
|
||||
account_id=account_id,
|
||||
params={"dataset_id": dataset_id, "policy_id": policy_id},
|
||||
json=payload.model_dump(mode="json"),
|
||||
)
|
||||
return AccessMatrixItem.model_validate(data or {})
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Workspace-level access (screenshot 2: Settings > Access Rules).
|
||||
# ------------------------------------------------------------------
|
||||
@ -708,6 +749,23 @@ class RBACService:
|
||||
)
|
||||
return MemberBindingsResponse.model_validate(data or {})
|
||||
|
||||
@staticmethod
|
||||
def replace_app_bindings(
|
||||
tenant_id: str,
|
||||
account_id: str | None,
|
||||
policy_id: str,
|
||||
payload: ReplaceBindings,
|
||||
) -> AccessMatrixItem:
|
||||
data = _inner_call(
|
||||
"PUT",
|
||||
f"{_INNER_PREFIX}/workspace/apps/access-policy/bindings",
|
||||
tenant_id=tenant_id,
|
||||
account_id=account_id,
|
||||
params={"policy_id": policy_id},
|
||||
json=payload.model_dump(mode="json"),
|
||||
)
|
||||
return AccessMatrixItem.model_validate(data or {})
|
||||
|
||||
@staticmethod
|
||||
def list_dataset_role_bindings(
|
||||
tenant_id: str,
|
||||
@ -772,6 +830,23 @@ class RBACService:
|
||||
)
|
||||
return MemberBindingsResponse.model_validate(data or {})
|
||||
|
||||
@staticmethod
|
||||
def replace_dataset_bindings(
|
||||
tenant_id: str,
|
||||
account_id: str | None,
|
||||
policy_id: str,
|
||||
payload: ReplaceBindings,
|
||||
) -> AccessMatrixItem:
|
||||
data = _inner_call(
|
||||
"PUT",
|
||||
f"{_INNER_PREFIX}/workspace/datasets/access-policy/bindings",
|
||||
tenant_id=tenant_id,
|
||||
account_id=account_id,
|
||||
params={"policy_id": policy_id},
|
||||
json=payload.model_dump(mode="json"),
|
||||
)
|
||||
return AccessMatrixItem.model_validate(data or {})
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Member ↔ role bindings (screenshot 3: Settings > Members > Assign roles).
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@ -110,9 +110,10 @@ class TestPydanticModels:
|
||||
with pytest.raises(ValidationError):
|
||||
rbac_mod._AccessPolicyCreateRequest.model_validate({"name": "bad", "resource_type": "unknown"})
|
||||
|
||||
def test_replace_role_bindings_defaults_empty(self):
|
||||
parsed = rbac_mod._ReplaceRoleBindingsRequest.model_validate({})
|
||||
def test_replace_bindings_defaults_empty(self):
|
||||
parsed = rbac_mod._ReplaceBindingsRequest.model_validate({})
|
||||
assert parsed.role_ids == []
|
||||
assert parsed.account_ids == []
|
||||
|
||||
def test_pagination_query_accepts_page_and_limit_aliases(self):
|
||||
parsed = rbac_mod._PaginationQuery.model_validate({"page": 3, "limit": 25, "reverse": True})
|
||||
|
||||
@ -191,27 +191,25 @@ class TestResourceAccess:
|
||||
assert call.params == {"app_id": "app-1"}
|
||||
assert out.app_id == "app-1"
|
||||
|
||||
def test_app_replace_role_bindings(self, mock_send: MagicMock):
|
||||
def test_app_replace_bindings(self, mock_send: MagicMock):
|
||||
mock_send.return_value = {"data": []}
|
||||
payload = svc.ReplaceRoleBindings(role_ids=["workspace.owner"])
|
||||
svc.RBACService.AppAccess.replace_role_bindings("tenant-1", "acct-1", "app-1", "policy-1", payload)
|
||||
payload = svc.ReplaceBindings(role_ids=["workspace.owner"], account_ids=["acct-2"])
|
||||
svc.RBACService.AppAccess.replace_bindings("tenant-1", "acct-1", "app-1", "policy-1", payload)
|
||||
call = _call_args(mock_send)
|
||||
assert call.method == "PUT"
|
||||
assert call.endpoint == "/rbac/apps/access-policy/role-bindings"
|
||||
assert call.endpoint == "/rbac/apps/access-policy/bindings"
|
||||
assert call.params == {"app_id": "app-1", "policy_id": "policy-1"}
|
||||
assert call.json == {"role_ids": ["workspace.owner"]}
|
||||
assert call.json == {"role_ids": ["workspace.owner"], "account_ids": ["acct-2"]}
|
||||
|
||||
def test_dataset_replace_member_bindings(self, mock_send: MagicMock):
|
||||
def test_dataset_replace_bindings(self, mock_send: MagicMock):
|
||||
mock_send.return_value = {"data": []}
|
||||
payload = svc.ReplaceMemberBindings(account_ids=["acct-2"])
|
||||
svc.RBACService.DatasetAccess.replace_member_bindings(
|
||||
"tenant-1", "acct-1", "ds-1", "policy-1", payload
|
||||
)
|
||||
payload = svc.ReplaceBindings(role_ids=["workspace.editor"], account_ids=["acct-2"])
|
||||
svc.RBACService.DatasetAccess.replace_bindings("tenant-1", "acct-1", "ds-1", "policy-1", payload)
|
||||
call = _call_args(mock_send)
|
||||
assert call.method == "PUT"
|
||||
assert call.endpoint == "/rbac/datasets/access-policy/member-bindings"
|
||||
assert call.endpoint == "/rbac/datasets/access-policy/bindings"
|
||||
assert call.params == {"dataset_id": "ds-1", "policy_id": "policy-1"}
|
||||
assert call.json == {"account_ids": ["acct-2"]}
|
||||
assert call.json == {"role_ids": ["workspace.editor"], "account_ids": ["acct-2"]}
|
||||
|
||||
|
||||
class TestWorkspaceAccess:
|
||||
@ -235,17 +233,29 @@ class TestWorkspaceAccess:
|
||||
assert call.endpoint == "/rbac/workspace/datasets/access-policy"
|
||||
assert call.params is None
|
||||
|
||||
def test_dataset_replace_role_bindings(self, mock_send: MagicMock):
|
||||
def test_workspace_app_replace_bindings(self, mock_send: MagicMock):
|
||||
mock_send.return_value = {"data": []}
|
||||
payload = svc.ReplaceRoleBindings(role_ids=["workspace.editor"])
|
||||
svc.RBACService.WorkspaceAccess.replace_dataset_role_bindings(
|
||||
payload = svc.ReplaceBindings(role_ids=["workspace.editor"], account_ids=["acct-2"])
|
||||
svc.RBACService.WorkspaceAccess.replace_app_bindings(
|
||||
"tenant-1", "acct-1", "policy-1", payload
|
||||
)
|
||||
call = _call_args(mock_send)
|
||||
assert call.method == "PUT"
|
||||
assert call.endpoint == "/rbac/workspace/datasets/access-policy/role-bindings"
|
||||
assert call.endpoint == "/rbac/workspace/apps/access-policy/bindings"
|
||||
assert call.params == {"policy_id": "policy-1"}
|
||||
assert call.json == {"role_ids": ["workspace.editor"]}
|
||||
assert call.json == {"role_ids": ["workspace.editor"], "account_ids": ["acct-2"]}
|
||||
|
||||
def test_workspace_dataset_replace_bindings(self, mock_send: MagicMock):
|
||||
mock_send.return_value = {"data": []}
|
||||
payload = svc.ReplaceBindings(role_ids=["workspace.editor"], account_ids=["acct-2"])
|
||||
svc.RBACService.WorkspaceAccess.replace_dataset_bindings(
|
||||
"tenant-1", "acct-1", "policy-1", payload
|
||||
)
|
||||
call = _call_args(mock_send)
|
||||
assert call.method == "PUT"
|
||||
assert call.endpoint == "/rbac/workspace/datasets/access-policy/bindings"
|
||||
assert call.params == {"policy_id": "policy-1"}
|
||||
assert call.json == {"role_ids": ["workspace.editor"], "account_ids": ["acct-2"]}
|
||||
|
||||
|
||||
class TestMyPermissions:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user