Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎉 Source Zendesk Sunshine: support oauth #7976

Merged
merged 10 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@
- name: Zendesk Sunshine
sourceDefinitionId: 325e0640-e7b3-4e24-b823-3361008f603f
dockerRepository: airbyte/source-zendesk-sunshine
dockerImageTag: 0.1.0
dockerImageTag: 0.1.1
documentationUrl: https://docs.airbyte.io/integrations/sources/zendesk-sunshine
icon: zendesk.svg
sourceType: api
Expand Down
127 changes: 112 additions & 15 deletions airbyte-config/init/src/main/resources/seed/source_specs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7553,40 +7553,137 @@
path_in_connector_config:
- "credentials"
- "client_secret"
- dockerImage: "airbyte/source-zendesk-sunshine:0.1.0"
- dockerImage: "airbyte/source-zendesk-sunshine:0.1.1"
spec:
documentationUrl: "https://docs.airbyte.io/integrations/sources/zendesk_sunshine"
connectionSpecification:
$schema: "http://json-schema.org/draft-07/schema#"
title: "Zendesk Sunshine Spec"
type: "object"
required:
- "api_token"
- "email"
- "start_date"
- "subdomain"
additionalProperties: false
additionalProperties: true
properties:
api_token:
type: "string"
airbyte_secret: true
description: "API Token. See the <a href=\"https://docs.airbyte.io/integrations/sources/zendesk_sunshine\"\
>docs</a> for information on how to generate this key."
email:
type: "string"
description: "The user email for your Zendesk account"
subdomain:
title: "Subdomain"
type: "string"
description: "The subdomain for your Zendesk Account"
description: "The subdomain for your Zendesk Account."
start_date:
title: "Start Date"
type: "string"
description: "The date from which you'd like to replicate the data"
description: "The date from which you'd like to replicate data for Zendesk\
\ Sunshine API, in the format YYYY-MM-DDT00:00:00Z."
pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
examples: "2021-01-01T00:00:00.000000Z"
examples:
- "2021-01-01T00:00:00Z"
credentials:
title: "Authorization Method"
type: "object"
oneOf:
- type: "object"
title: "OAuth2.0"
required:
- "auth_method"
- "client_id"
- "client_secret"
- "access_token"
properties:
auth_method:
type: "string"
const: "oauth2.0"
enum:
- "oauth2.0"
default: "oauth2.0"
order: 0
client_id:
type: "string"
title: "Client ID"
description: "The Client ID of your OAuth application."
airbyte_secret: true
client_secret:
type: "string"
title: "Client Secret"
description: "The Client Secret of your OAuth application."
airbyte_secret: true
access_token:
type: "string"
title: "Access Token"
description: "Long-term access Token for making authenticated requests."
airbyte_secret: true
- type: "object"
title: "API Token"
required:
- "auth_method"
- "api_token"
- "email"
properties:
auth_method:
type: "string"
const: "api_token"
enum:
- "api_token"
default: "api_token"
order: 1
api_token:
type: "string"
title: "API Token"
description: "API Token. See the <a href=\"https://docs.airbyte.io/integrations/sources/zendesk_sunshine\"\
>docs</a> for information on how to generate this key."
airbyte_secret: true
email:
type: "string"
title: "Email"
description: "The user email for your Zendesk account"
supportsNormalization: false
supportsDBT: false
supported_destination_sync_modes: []
advanced_auth:
auth_flow_type: "oauth2.0"
predicate_key:
- "credentials"
- "auth_method"
predicate_value: "oauth2.0"
oauth_config_specification:
oauth_user_input_from_connector_config_specification:
type: "object"
additionalProperties: false
properties:
subdomain:
type: "string"
path_in_connector_config:
- "subdomain"
complete_oauth_output_specification:
type: "object"
additionalProperties: false
properties:
access_token:
type: "string"
path_in_connector_config:
- "credentials"
- "access_token"
complete_oauth_server_input_specification:
type: "object"
additionalProperties: false
properties:
client_id:
type: "string"
client_secret:
type: "string"
complete_oauth_server_output_specification:
type: "object"
additionalProperties: false
properties:
client_id:
type: "string"
path_in_connector_config:
- "credentials"
- "client_id"
client_secret:
type: "string"
path_in_connector_config:
- "credentials"
- "client_secret"
- dockerImage: "airbyte/source-zendesk-support:0.1.11"
spec:
documentationUrl: "https://docs.airbyte.io/integrations/sources/zendesk-support"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ RUN pip install .
ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py"
ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]

LABEL io.airbyte.version=0.1.0
LABEL io.airbyte.version=0.1.1
LABEL io.airbyte.name=airbyte/source-zendesk-sunshine
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,25 @@ tests:
connection:
- config_path: "secrets/config.json"
status: "succeed"
- config_path: "secrets/config_oauth.json"
status: "succeed"
- config_path: "secrets/config_api_token.json"
status: "succeed"
- config_path: "integration_tests/invalid_config.json"
status: "failed"
- config_path: "integration_tests/invalid_config_api_token.json"
status: "failed"
- config_path: "integration_tests/invalid_config_oauth.json"
status: "failed"
discovery:
- config_path: "secrets/config.json"
basic_read:
- config_path: "secrets/config.json"
configured_catalog_path: "integration_tests/configured_catalog.json"
- config_path: "secrets/config_api_token.json"
configured_catalog_path: "integration_tests/configured_catalog.json"
- config_path: "secrets/config_oauth.json"
configured_catalog_path: "integration_tests/configured_catalog.json"
# incremental: # complex state ( {parent_id: {cur_field: value}} still not supported )
# - config_path: "secrets/config.json"
# configured_catalog_path: "integration_tests/configured_catalog.json"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"credentials": {
"auth_method": "api_token",
"email": "test@ayhghghte.io",
"api_token": "fgfgvf ghnbvg hnghbvnhbvnvbn"
},
"subdomain": "d3v-airbyte",
"start_date": "2020-01-01T00:00:00Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"credentials": {
"auth_method": "oauth2.0",
"client_id": "some_client_id",
"client_secret": "some_client_secret",
"access_token": "some_access_token"
},
"subdomain": "d3v-airbyte",
"start_date": "2020-01-01T00:00:00Z"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


import base64
from typing import Any, List, Mapping, Tuple
from typing import Any, List, Mapping, Tuple, Union

import pendulum
from airbyte_cdk.logger import AirbyteLogger
Expand All @@ -23,11 +23,24 @@ def __init__(self, auth: Tuple[str, str], auth_method: str = "Basic", **kwargs):
super().__init__(token=b64_encoded, auth_method=auth_method, **kwargs)


class ZendeskSunshineAuthenticator:
"""Provides the authentication capabilities for both old and new methods."""

@staticmethod
def get_auth(config: Mapping[str, Any]) -> Union[Base64HttpAuthenticator, TokenAuthenticator]:
credentials = config.get("credentials", {})
token = config.get("api_token") or credentials.get("api_token")
email = config.get("email") or credentials.get("email")
if email and token:
return Base64HttpAuthenticator(auth=(f"{email}/token", token))
return TokenAuthenticator(token=credentials["access_token"])


class SourceZendeskSunshine(AbstractSource):
def check_connection(self, logger: AirbyteLogger, config: Mapping[str, Any]) -> Tuple[bool, Any]:
try:
pendulum.parse(config["start_date"], strict=True)
authenticator = Base64HttpAuthenticator(auth=(f'{config["email"]}/token', config["api_token"]))
authenticator = ZendeskSunshineAuthenticator.get_auth(config)
stream = Limits(authenticator=authenticator, subdomain=config["subdomain"], start_date=pendulum.parse(config["start_date"]))
records = stream.read_records(sync_mode=SyncMode.full_refresh)
next(records)
Expand All @@ -47,7 +60,7 @@ def streams(self, config: Mapping[str, Any]) -> List[Stream]:
After this time is passed we have no data. It will require permanent population, to pass
the test criteria `stream should contain at least 1 record)
"""
authenticator = Base64HttpAuthenticator(auth=(f'{config["email"]}/token', config["api_token"]))
authenticator = ZendeskSunshineAuthenticator.get_auth(config)
args = {"authenticator": authenticator, "subdomain": config["subdomain"], "start_date": config["start_date"]}
return [
ObjectTypes(**args),
Expand Down
Loading