From 840cc8fbe91927d766ea7c3d7fea1fa984e1d8ba Mon Sep 17 00:00:00 2001 From: NeedmeFordev <124189514+spider-yamet@users.noreply.github.com> Date: Tue, 24 Mar 2026 06:21:31 -0600 Subject: [PATCH] fix(asana): use project memberships endpoint for project IDs in connector (#13746) ### What problem does this PR solve? Fixes a bug in the Asana connector where providing `Project IDs` caused sync to fail with: `project_membership: Not a recognized ID: ` Root cause: the connector called `get_project_membership(project_gid)`, but that API expects a **project membership gid**, not a **project gid**. This PR switches to the correct project-scoped API and adds regression tests. Fixes: [#13669](https://github.com/infiniflow/ragflow/issues/13669) ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) ### Changes made - Updated `common/data_source/asana_connector.py`: - Replaced `get_project_membership(pid, ...)` with `get_project_memberships_for_project(pid, ...)` - Trimmed and filtered `asana_project_ids` parsing to avoid empty/whitespace IDs - Normalized `asana_team_id` by trimming whitespace - Used safer access for membership email extraction (`m.get("user")`) - Added `test/unit_test/common/test_asana_connector.py`: - Verifies the correct project-membership API method is called - Verifies empty `project_ids` path returns workspace emails - Verifies project/team input normalization behavior ### Compatibility / risk - Non-breaking bug fix - No API contract changes - Existing behavior for empty `Project IDs` remains unchanged --- common/data_source/asana_connector.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/common/data_source/asana_connector.py b/common/data_source/asana_connector.py index 1dddcb6df..4143c0cba 100644 --- a/common/data_source/asana_connector.py +++ b/common/data_source/asana_connector.py @@ -288,22 +288,25 @@ class AsanaAPI: project_emails = set() for pid in project_ids: + pid = pid.strip() + if not pid: + continue project = self.project_api.get_project( pid, opts={"opt_fields": "team,privacy_setting"} ) - if project["privacy_setting"] == "private": + if project.get("privacy_setting") == "private": if team_id and project.get("team", {}).get("gid") != team_id: continue - memberships = self.project_memberships_api.get_project_membership( + memberships = self.project_memberships_api.get_project_memberships_for_project( pid, opts={"opt_fields": "user.gid,user.email"} ) for m in memberships: - email = m["user"].get("email") + email = (m.get("user") or {}).get("email") if email: project_emails.add(email) @@ -338,9 +341,11 @@ class AsanaConnector(LoadConnector, PollConnector): ) -> None: self.workspace_id = asana_workspace_id self.project_ids_to_index: list[str] | None = ( - asana_project_ids.split(",") if asana_project_ids else None + [project_id.strip() for project_id in asana_project_ids.split(",") if project_id.strip()] + if asana_project_ids + else None ) - self.asana_team_id = asana_team_id if asana_team_id else None + self.asana_team_id = asana_team_id.strip() if asana_team_id and asana_team_id.strip() else None self.batch_size = batch_size self.continue_on_failure = continue_on_failure self.size_threshold = None