Skip to content

Commit bed4619

Browse files
committed
fix(projects): keep paginated flow visibility scoped to current user
1 parent 65c3139 commit bed4619

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

src/backend/base/langflow/api/v1/projects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ async def read_project(
268268
try:
269269
# Check if pagination is explicitly requested by the user (both page and size provided)
270270
if page is not None and size is not None:
271-
stmt = select(Flow).where(Flow.folder_id == project_id)
271+
stmt = select(Flow).where(Flow.folder_id == project_id, Flow.user_id == current_user.id)
272272

273273
if Flow.updated_at is not None:
274274
stmt = stmt.order_by(Flow.updated_at.desc()) # type: ignore[attr-defined]

src/backend/tests/unit/api/v1/test_projects.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,49 @@ async def test_read_project_error_handling_consistency(self, client: AsyncClient
15451545
f"Error message should mention 'not found' for params: {params}"
15461546
)
15471547

1548+
async def test_read_project_paginated_flows_match_current_user_visibility(
1549+
self, client: AsyncClient, logged_in_headers, basic_case
1550+
):
1551+
project_response = await client.post("api/v1/projects/", json=basic_case, headers=logged_in_headers)
1552+
assert project_response.status_code == status.HTTP_201_CREATED
1553+
project_id = project_response.json()["id"]
1554+
1555+
own_flow_payload = {
1556+
"name": "Owned flow",
1557+
"description": "Visible to the project owner",
1558+
"data": {},
1559+
"folder_id": project_id,
1560+
}
1561+
own_flow_response = await client.post("api/v1/flows/", json=own_flow_payload, headers=logged_in_headers)
1562+
assert own_flow_response.status_code == status.HTTP_201_CREATED
1563+
own_flow_id = own_flow_response.json()["id"]
1564+
1565+
other_user_flow_id = uuid4()
1566+
async with session_scope() as session:
1567+
flow_create = FlowCreate(
1568+
id=other_user_flow_id,
1569+
name="Other user's flow",
1570+
description="Should stay hidden from paginated project reads",
1571+
data={},
1572+
folder_id=project_id,
1573+
user_id=uuid4(),
1574+
)
1575+
flow = Flow.model_validate(flow_create, from_attributes=True)
1576+
session.add(flow)
1577+
await session.commit()
1578+
1579+
response = await client.get(
1580+
f"api/v1/projects/{project_id}?page=1&size=10",
1581+
headers=logged_in_headers,
1582+
)
1583+
assert response.status_code == status.HTTP_200_OK
1584+
1585+
result = response.json()
1586+
flow_ids = {flow["id"] for flow in result["flows"]["items"]}
1587+
1588+
assert own_flow_id in flow_ids
1589+
assert str(other_user_flow_id) not in flow_ids
1590+
15481591

15491592
async def test_download_file_starter_project(client: AsyncClient, logged_in_headers, active_user, json_flow):
15501593
"""Test downloading a project with multiple flows.

0 commit comments

Comments
 (0)