From 1c8b18890dc42383597754fdd4e5f1a115274ed9 Mon Sep 17 00:00:00 2001 From: Serhii Chvaliuk Date: Thu, 12 May 2022 12:50:43 +0300 Subject: [PATCH] Source Hubspot: ensure all oauth2.0 scopes in "check" command (#12711) Signed-off-by: Sergey Chvalyuk --- .../resources/seed/source_definitions.yaml | 2 +- .../src/main/resources/seed/source_specs.yaml | 2 +- .../connectors/source-hubspot/Dockerfile | 2 +- .../source-hubspot/source_hubspot/source.py | 43 ++++++++++++++++++- .../airbyte/oauth/flows/HubspotOAuthFlow.java | 5 ++- docs/integrations/sources/hubspot.md | 3 ++ 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml index 381cae9d39de..a804d8e657c4 100644 --- a/airbyte-config/init/src/main/resources/seed/source_definitions.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_definitions.yaml @@ -390,7 +390,7 @@ - name: HubSpot sourceDefinitionId: 36c891d9-4bd9-43ac-bad2-10e12756272c dockerRepository: airbyte/source-hubspot - dockerImageTag: 0.1.58 + dockerImageTag: 0.1.59 documentationUrl: https://docs.airbyte.io/integrations/sources/hubspot icon: hubspot.svg sourceType: api diff --git a/airbyte-config/init/src/main/resources/seed/source_specs.yaml b/airbyte-config/init/src/main/resources/seed/source_specs.yaml index 82cf9c9a1420..4f16ad96510b 100644 --- a/airbyte-config/init/src/main/resources/seed/source_specs.yaml +++ b/airbyte-config/init/src/main/resources/seed/source_specs.yaml @@ -3536,7 +3536,7 @@ supportsNormalization: false supportsDBT: false supported_destination_sync_modes: [] -- dockerImage: "airbyte/source-hubspot:0.1.58" +- dockerImage: "airbyte/source-hubspot:0.1.59" spec: documentationUrl: "https://docs.airbyte.io/integrations/sources/hubspot" connectionSpecification: diff --git a/airbyte-integrations/connectors/source-hubspot/Dockerfile b/airbyte-integrations/connectors/source-hubspot/Dockerfile index 6743bbbf23d0..8e61ae2aae27 100644 --- a/airbyte-integrations/connectors/source-hubspot/Dockerfile +++ b/airbyte-integrations/connectors/source-hubspot/Dockerfile @@ -34,5 +34,5 @@ COPY source_hubspot ./source_hubspot ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.58 +LABEL io.airbyte.version=0.1.59 LABEL io.airbyte.name=airbyte/source-hubspot diff --git a/airbyte-integrations/connectors/source-hubspot/source_hubspot/source.py b/airbyte-integrations/connectors/source-hubspot/source_hubspot/source.py index 4a321404950a..9a0b24916c05 100644 --- a/airbyte-integrations/connectors/source-hubspot/source_hubspot/source.py +++ b/airbyte-integrations/connectors/source-hubspot/source_hubspot/source.py @@ -6,6 +6,7 @@ import logging from typing import Any, Iterator, List, Mapping, MutableMapping, Optional, Tuple +import requests from airbyte_cdk.models import AirbyteMessage, ConfiguredAirbyteCatalog from airbyte_cdk.sources import AbstractSource from airbyte_cdk.sources.deprecated.base_source import ConfiguredAirbyteStream @@ -44,22 +45,60 @@ Workflows, ) +SCOPES = [ + "automation", + "content", + "crm.lists.read", + "crm.objects.companies.read", + "crm.objects.contacts.read", + "crm.objects.deals.read", + "crm.objects.feedback_submissions.read", + "crm.objects.owners.read", + "crm.schemas.companies.read", + "crm.schemas.contacts.read", + "crm.schemas.deals.read", + "e-commerce", + "files", + "files.ui_hidden.read", + "forms", + "forms-uploaded-files", + "sales-email-read", + "tickets", +] + class SourceHubspot(AbstractSource): def check_connection(self, logger: logging.Logger, config: Mapping[str, Any]) -> Tuple[bool, Optional[Any]]: """Check connection""" + common_params = self.get_common_params(config=config) + if common_params.get("authenticator"): + access_token = common_params["authenticator"].get_access_token() + url = f"https://api.hubapi.com/oauth/v1/access-tokens/{access_token}" + try: + response = requests.get(url=url) + response.raise_for_status() + return self.check_scopes(response.json()) + except Exception as e: + return False, repr(e) + alive = True error_msg = None - common_params = self.get_common_params(config=config) try: contacts = Contacts(**common_params) _ = contacts.properties except HTTPError as error: alive = False error_msg = repr(error) - return alive, error_msg + @staticmethod + def check_scopes(response_json): + granted_scopes = response_json["scopes"] + missed_scopes = set(SCOPES) - set(granted_scopes) + if missed_scopes: + return False, "missed required scopes: " + ", ".join(sorted(missed_scopes)) + return True, None + @staticmethod def get_api(config: Mapping[str, Any]) -> API: credentials = config.get("credentials", {}) diff --git a/airbyte-oauth/src/main/java/io/airbyte/oauth/flows/HubspotOAuthFlow.java b/airbyte-oauth/src/main/java/io/airbyte/oauth/flows/HubspotOAuthFlow.java index 1effe6381250..90936bdd09d6 100644 --- a/airbyte-oauth/src/main/java/io/airbyte/oauth/flows/HubspotOAuthFlow.java +++ b/airbyte-oauth/src/main/java/io/airbyte/oauth/flows/HubspotOAuthFlow.java @@ -76,7 +76,10 @@ private String getScopes() { "crm.schemas.companies.read", "files", "forms-uploaded-files", - "files.ui_hidden.read"); + "files.ui_hidden.read", + "crm.objects.feedback_submissions.read", + "sales-email-read", + "automation"); } /** diff --git a/docs/integrations/sources/hubspot.md b/docs/integrations/sources/hubspot.md index 6268f44bd819..9da35b236ced 100644 --- a/docs/integrations/sources/hubspot.md +++ b/docs/integrations/sources/hubspot.md @@ -132,6 +132,8 @@ If you are using OAuth, most of the streams require the appropriate [scopes](htt | `deals` | `contacts` | | `email_events` | `content` | | `engagements` | `contacts` | +| `engagements_emails` | `sales-email-read` | +| `feedback_submissions` | `crm.objects.feedback_submissions.read` | | `forms` | `forms` | | `form_submissions`| `forms` | | `line_items` | `e-commerce` | @@ -147,6 +149,7 @@ If you are using OAuth, most of the streams require the appropriate [scopes](htt | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------| +| 0.1.59 | 2022-05-10 | [\#12711](https://github.com/airbytehq/airbyte/pull/12711) | Ensure oauth2.0 token has all needed scopes in "check" command | | 0.1.58 | 2022-05-04 | [\#12482](https://github.com/airbytehq/airbyte/pull/12482) | Update input configuration copy | | 0.1.57 | 2022-05-04 | [12198](https://github.com/airbytehq/airbyte/pull/12198) | Add deals associations for quotes | 0.1.56 | 2022-05-02 | [12515](https://github.com/airbytehq/airbyte/pull/12515) | Extra logs for troubleshooting 403 errors |