mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-06-29 23:41:12 +08:00
Fix team member cannot edit agent (#14612)
### What problem does this PR solve? Follow on PR: https://github.com/infiniflow/ragflow/pull/14602 to fix: team member cannot edit agent. new behavior: beside delete, everything is allowed for team member. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@@ -72,7 +72,27 @@ def _require_canvas_access_sync(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not UserCanvasService.accessible(kwargs.get('agent_id'), kwargs.get('tenant_id')):
|
||||
return get_json_result(data=False, message="Only owner of canvas authorized for this operation.", code=RetCode.OPERATING_ERROR)
|
||||
return get_json_result(data=False, message="Make sure you have permission to access the agent.", code=RetCode.OPERATING_ERROR)
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def _require_canvas_access_async(func):
|
||||
@wraps(func)
|
||||
async def wrapper(*args, **kwargs):
|
||||
agent_id = kwargs.get('agent_id')
|
||||
tenant_id = kwargs.get('tenant_id')
|
||||
if not await thread_pool_exec(UserCanvasService.accessible, agent_id, tenant_id):
|
||||
return get_json_result(data=False, message="Make sure you have permission to access the agent.", code=RetCode.OPERATING_ERROR)
|
||||
return await func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def _require_canvas_owner_sync(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not UserCanvasService.query(user_id=kwargs.get('tenant_id'), id=kwargs.get('agent_id')):
|
||||
return get_json_result(data=False, message="Only the owner of the agent is authorized for this operation.", code=RetCode.OPERATING_ERROR)
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
@@ -172,6 +192,7 @@ def list_agent_sessions(agent_id, tenant_id):
|
||||
@manager.route("/agents/<agent_id>/sessions", methods=["POST"]) # noqa: F821
|
||||
@login_required
|
||||
@add_tenant_id_to_kwargs
|
||||
@_require_canvas_access_async
|
||||
async def create_agent_session(agent_id, tenant_id):
|
||||
req = await get_request_json()
|
||||
user_id = req.get("user_id") or request.args.get("user_id", tenant_id)
|
||||
@@ -422,18 +443,12 @@ async def upload_agent_file(agent_id):
|
||||
@manager.route("/agents/<agent_id>/components/<component_id>/input-form", methods=["GET"]) # noqa: F821
|
||||
@login_required
|
||||
@add_tenant_id_to_kwargs
|
||||
@_require_canvas_access_sync
|
||||
def get_agent_component_input_form(agent_id, component_id, tenant_id):
|
||||
try:
|
||||
exists, user_canvas = UserCanvasService.get_by_id(agent_id)
|
||||
if not exists:
|
||||
return get_data_error_result(message="canvas not found.")
|
||||
if not UserCanvasService.query(user_id=tenant_id, id=agent_id):
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message="Only owner of canvas authorized for this operation.",
|
||||
code=RetCode.OPERATING_ERROR,
|
||||
)
|
||||
|
||||
canvas = Canvas(json.dumps(user_canvas.dsl), tenant_id, canvas_id=user_canvas.id)
|
||||
return get_json_result(data=canvas.get_component_input_form(component_id))
|
||||
except Exception as exc:
|
||||
@@ -444,14 +459,9 @@ def get_agent_component_input_form(agent_id, component_id, tenant_id):
|
||||
@validate_request("params")
|
||||
@login_required
|
||||
@add_tenant_id_to_kwargs
|
||||
@_require_canvas_access_async
|
||||
async def debug_agent_component(agent_id, component_id, tenant_id):
|
||||
req = await get_request_json()
|
||||
if not UserCanvasService.accessible(agent_id, tenant_id):
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message="Only owner of canvas authorized for this operation.",
|
||||
code=RetCode.OPERATING_ERROR,
|
||||
)
|
||||
try:
|
||||
_, user_canvas = UserCanvasService.get_by_id(agent_id)
|
||||
canvas = Canvas(json.dumps(user_canvas.dsl), tenant_id, canvas_id=user_canvas.id)
|
||||
@@ -569,14 +579,8 @@ def get_agent_logs(agent_id, message_id, tenant_id):
|
||||
@manager.route("/agents/<agent_id>", methods=["DELETE"]) # noqa: F821
|
||||
@login_required
|
||||
@add_tenant_id_to_kwargs
|
||||
@_require_canvas_owner_sync
|
||||
def delete_agent(agent_id, tenant_id):
|
||||
if not UserCanvasService.query(user_id=tenant_id, id=agent_id):
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message="Only owner of canvas authorized for this operation.",
|
||||
code=RetCode.OPERATING_ERROR,
|
||||
)
|
||||
|
||||
UserCanvasService.delete_by_id(agent_id)
|
||||
return get_json_result(data=True)
|
||||
|
||||
@@ -584,9 +588,9 @@ def delete_agent(agent_id, tenant_id):
|
||||
@manager.route("/agents/<agent_id>", methods=["PUT"]) # noqa: F821
|
||||
@login_required
|
||||
@add_tenant_id_to_kwargs
|
||||
@_require_canvas_access_async
|
||||
async def update_agent(agent_id, tenant_id):
|
||||
req = {k: v for k, v in (await get_request_json()).items() if v is not None}
|
||||
req["user_id"] = tenant_id
|
||||
req["release"] = bool(req.get("release", ""))
|
||||
|
||||
if req.get("dsl") is not None:
|
||||
@@ -602,13 +606,6 @@ async def update_agent(agent_id, tenant_id):
|
||||
if req.get("title") is not None:
|
||||
req["title"] = req["title"].strip()
|
||||
|
||||
if not UserCanvasService.query(user_id=tenant_id, id=agent_id):
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message="Only owner of canvas authorized for this operation.",
|
||||
code=RetCode.OPERATING_ERROR,
|
||||
)
|
||||
|
||||
_, current_agent = UserCanvasService.get_by_id(agent_id)
|
||||
agent_title_for_version = req.get("title") or (current_agent.title if current_agent else "")
|
||||
canvas_category = (
|
||||
@@ -642,14 +639,8 @@ async def update_agent(agent_id, tenant_id):
|
||||
@manager.route("/agents/<agent_id>/reset", methods=["POST"]) # noqa: F821
|
||||
@login_required
|
||||
@add_tenant_id_to_kwargs
|
||||
@_require_canvas_access_async
|
||||
async def reset_agent(agent_id, tenant_id):
|
||||
if not UserCanvasService.accessible(agent_id, tenant_id):
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message="Only owner of canvas authorized for this operation.",
|
||||
code=RetCode.OPERATING_ERROR,
|
||||
)
|
||||
|
||||
try:
|
||||
exists, user_canvas = UserCanvasService.get_by_id(agent_id)
|
||||
if not exists:
|
||||
@@ -911,10 +902,11 @@ async def agent_chat_completion(tenant_id, agent_id=None):
|
||||
runtime_user_id = req.get("user_id") or tenant_id
|
||||
user_id = str(runtime_user_id)
|
||||
custom_header = req.get("custom_header", "")
|
||||
if not await thread_pool_exec(UserCanvasService.accessible, agent_id, tenant_id):
|
||||
|
||||
if not UserCanvasService.accessible(agent_id, tenant_id):
|
||||
return get_json_result(
|
||||
data=False,
|
||||
message="Only owner of canvas authorized for this operation.",
|
||||
message="Make sure you have permission to access the agent.",
|
||||
code=RetCode.OPERATING_ERROR,
|
||||
)
|
||||
|
||||
|
||||
@@ -221,8 +221,6 @@ class UserCanvasService(CommonService):
|
||||
e, cvs = cls.get_by_id(agent_id)
|
||||
if not e:
|
||||
raise LookupError("Agent not found.")
|
||||
if tenant_id and cvs.user_id != tenant_id:
|
||||
raise PermissionError("You do not own the agent.")
|
||||
|
||||
if release_mode:
|
||||
released_version = UserCanvasVersionService.get_latest_released(agent_id)
|
||||
|
||||
@@ -108,8 +108,8 @@ class TestAgentSessions:
|
||||
update_url = f"{HOST_ADDRESS}/api/{VERSION}/agents/invalid-agent-id"
|
||||
res = requests.put(update_url, auth=HttpApiAuth, json={"title": "updated", "dsl": MINIMAL_DSL}).json()
|
||||
assert res["code"] == 103, res
|
||||
assert "Only owner of canvas authorized" in res["message"], res
|
||||
assert "Make sure you have permission to access the agent." in res["message"], res
|
||||
|
||||
res = delete_agent(HttpApiAuth, "invalid-agent-id")
|
||||
assert res["code"] == 103, res
|
||||
assert "Only owner of canvas authorized" in res["message"], res
|
||||
assert "Only the owner of the agent is authorized for this operation." in res["message"], res
|
||||
|
||||
@@ -568,12 +568,17 @@ def test_agents_crud_unit_branches(monkeypatch):
|
||||
return {"dsl": {"nodes": []}, "title": " webhook-agent ", "unused": None}
|
||||
|
||||
monkeypatch.setattr(module, "get_request_json", req_update)
|
||||
monkeypatch.setattr(module.UserCanvasService, "query", lambda **_kwargs: False)
|
||||
res = _run(module.update_agent.__wrapped__("agent-1", "tenant-1"))
|
||||
monkeypatch.setattr(module.UserCanvasService, "accessible", lambda *_a, **_kw: False)
|
||||
|
||||
@module._require_canvas_access_async
|
||||
async def _dummy_update(agent_id, tenant_id):
|
||||
return module.get_json_result(data=True)
|
||||
|
||||
res = _run(_dummy_update(agent_id="agent-1", tenant_id="tenant-1"))
|
||||
assert res["code"] == module.RetCode.OPERATING_ERROR
|
||||
|
||||
calls = {"update": 0, "save_or_replace_latest": 0, "replace_for_set": 0}
|
||||
monkeypatch.setattr(module.UserCanvasService, "query", lambda **_kwargs: True)
|
||||
monkeypatch.setattr(module.UserCanvasService, "accessible", lambda *_a, **_kw: True)
|
||||
monkeypatch.setattr(
|
||||
module.UserCanvasService,
|
||||
"get_by_id",
|
||||
@@ -599,7 +604,12 @@ def test_agents_crud_unit_branches(monkeypatch):
|
||||
assert calls == {"update": 1, "save_or_replace_latest": 1, "replace_for_set": 1}
|
||||
|
||||
monkeypatch.setattr(module.UserCanvasService, "query", lambda **_kwargs: False)
|
||||
res = module.delete_agent.__wrapped__("agent-1", "tenant-1")
|
||||
|
||||
@module._require_canvas_owner_sync
|
||||
def _dummy_delete(agent_id, tenant_id):
|
||||
return module.get_json_result(data=True)
|
||||
|
||||
res = _dummy_delete(agent_id="agent-1", tenant_id="tenant-1")
|
||||
assert res["code"] == module.RetCode.OPERATING_ERROR
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user