diff --git a/backend/connector_v2/serializers.py b/backend/connector_v2/serializers.py index 5517bc525..86e873480 100644 --- a/backend/connector_v2/serializers.py +++ b/backend/connector_v2/serializers.py @@ -53,10 +53,10 @@ def save(self, **kwargs): # type: ignore oauth_credentials=kwargs[CIKey.CONNECTOR_METADATA], ) kwargs[CIKey.CONNECTOR_AUTH] = connector_oauth - ( - kwargs[CIKey.CONNECTOR_METADATA], - refresh_status, - ) = connector_oauth.get_and_refresh_tokens() + # Discard return value: ConnectorAuth.extra_data is shared across + # every connector with the same (provider, uid) and would overwrite + # this connector's form fields (site_url, drive_id). + connector_oauth.get_and_refresh_tokens() except Exception as exc: logger.error( "Error while obtaining ConnectorAuth for connector id " diff --git a/backend/connector_v2/views.py b/backend/connector_v2/views.py index 09a33be98..a8268acb3 100644 --- a/backend/connector_v2/views.py +++ b/backend/connector_v2/views.py @@ -90,12 +90,15 @@ def _get_connector_metadata(self, connector_id: str) -> dict[str, str] | None: # Only use OAuth flow if connector supports it AND oauth_key is provided if ConnectorInstance.supportsOAuth(connector_id=connector_id) and oauth_key: - connector_metadata = ConnectorAuthHelper.get_oauth_creds_from_cache( + oauth_tokens = ConnectorAuthHelper.get_oauth_creds_from_cache( cache_key=oauth_key, delete_key=False, # Don't delete yet - wait for successful operation ) - if connector_metadata is None: + if oauth_tokens is None: raise MissingParamException(param=ConnectorAuthKey.OAUTH_KEY) + # Preserve non-secret form fields (e.g. site_url connector Sharepoint) + form_metadata = self.request.data.get(CIKey.CONNECTOR_METADATA) or {} + connector_metadata = {**form_metadata, **oauth_tokens} else: connector_metadata = self.request.data.get(CIKey.CONNECTOR_METADATA) return connector_metadata diff --git a/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/sharepoint.py b/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/sharepoint.py index 3eacdac30..e8acd44f3 100644 --- a/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/sharepoint.py +++ b/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/sharepoint.py @@ -137,8 +137,8 @@ def _get_drive(self) -> Any: ctx = self._get_context() if self.drive_id: - # Specific drive by ID - self._drive = ctx.drives.get_by_id(self.drive_id) + # Specific drive by ID — EntityCollection uses bracket indexing. + self._drive = ctx.drives[self.drive_id] elif self.site_url and "sharepoint.com" in self.site_url.lower(): # SharePoint site - get default document library self._drive = self._get_sharepoint_site_drive(ctx) @@ -149,15 +149,15 @@ def _get_drive(self) -> Any: return self._drive def _get_sharepoint_site_drive(self, ctx: Any) -> Any: - """Get drive from SharePoint site URL.""" + """Get drive from SharePoint site URL. + + Uses the library's get_by_url, which maps an absolute site URL to the + Graph API's ``/sites/{hostname}:/{server-relative-path}`` addressing. + """ from urllib.parse import urlparse - parsed = urlparse(self.site_url) - # Extract site path from URL like - # https://tenant.sharepoint.com/sites/sitename - site_path = parsed.path.rstrip("/") - if site_path: - return ctx.sites.get_by_path(site_path).drive + if urlparse(self.site_url).path.strip("/"): + return ctx.sites.get_by_url(self.site_url).drive return ctx.sites.root.drive def _get_onedrive_drive(self, ctx: Any) -> Any: diff --git a/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/static/json_schema.json b/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/static/json_schema.json index d83f84c8a..6070cbd84 100644 --- a/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/static/json_schema.json +++ b/unstract/connectors/src/unstract/connectors/filesystems/sharepoint/static/json_schema.json @@ -63,8 +63,7 @@ "user_email": { "type": "string", "title": "User Email", - "format": "password", - "description": "User's email address. Required ONLY for OneDrive with Client Credentials (not needed for SharePoint).", + "description": "Required only to access OneDrive with Client Credentials (e.g., user@company.com). Leave empty when accessing a SharePoint site via Site URL.", "examples": [ "user@company.onmicrosoft.com", "user@company.com"