Skip to content

Commit

Permalink
馃帀Source Monday: support oauth (#8172)
Browse files Browse the repository at this point in the history
* support oauth

* fix

* update after review

* upd spec

* add java part

* add oauth to spec

* add oauth java test

* add changelog

* update after review

* update spec

* bump version
  • Loading branch information
annalvova05 committed Dec 28, 2021
1 parent d437f64 commit 069587b
Show file tree
Hide file tree
Showing 11 changed files with 420 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@
- name: Monday
sourceDefinitionId: 80a54ea2-9959-4040-aac1-eee42423ec9b
dockerRepository: airbyte/source-monday
dockerImageTag: 0.1.2
dockerImageTag: 0.1.3
documentationUrl: https://docs.airbyte.io/integrations/sources/monday
icon: monday.svg
sourceType: api
Expand Down
118 changes: 109 additions & 9 deletions airbyte-config/init/src/main/resources/seed/source_specs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4250,25 +4250,125 @@
supportsNormalization: false
supportsDBT: false
supported_destination_sync_modes: []
- dockerImage: "airbyte/source-monday:0.1.2"
- dockerImage: "airbyte/source-monday:0.1.3"
spec:
documentationUrl: "https://docs.airbyte.io/integrations/sources/monday"
connectionSpecification:
$schema: "http://json-schema.org/draft-07/schema#"
title: "Monday Spec"
type: "object"
required:
- "api_token"
additionalProperties: false
required: []
additionalProperties: true
properties:
api_token:
type: "string"
title: "Personal Access Token"
description: "Access Token for making authenticated requests."
airbyte_secret: true
credentials:
title: "Authorization Method"
type: "object"
oneOf:
- type: "object"
title: "OAuth2.0"
required:
- "auth_type"
- "client_id"
- "client_secret"
- "access_token"
properties:
subdomain:
type: "string"
title: "Subdomain/Slug (Optional)"
description: "Slug/subdomain of the account, or the first part of\
\ the URL that comes before .monday.com"
default: ""
order: 0
auth_type:
type: "string"
const: "oauth2.0"
enum:
- "oauth2.0"
default: "oauth2.0"
order: 1
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: "Access Token for making authenticated requests."
airbyte_secret: true
- type: "object"
title: "API Token"
required:
- "auth_type"
- "api_token"
properties:
auth_type:
type: "string"
const: "api_token"
enum:
- "api_token"
default: "api_token"
order: 0
api_token:
type: "string"
title: "Personal API Token"
description: "API Token for making authenticated requests."
airbyte_secret: true
supportsNormalization: false
supportsDBT: false
supported_destination_sync_modes: []
advanced_auth:
auth_flow_type: "oauth2.0"
predicate_key:
- "credentials"
- "auth_type"
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:
- "credentials"
- "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: true
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-mongodb-v2:0.1.9"
spec:
documentationUrl: "https://docs.airbyte.io/integrations/sources/mongodb-v2"
Expand Down
2 changes: 1 addition & 1 deletion airbyte-integrations/connectors/source-monday/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ COPY source_monday ./source_monday
ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py"
ENTRYPOINT ["python", "/airbyte/integration_code/main.py"]

LABEL io.airbyte.version=0.1.2
LABEL io.airbyte.version=0.1.3
LABEL io.airbyte.name=airbyte/source-monday
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,25 @@ tests:
connection:
- config_path: "secrets/config.json"
status: "succeed"
- config_path: "secrets/config_api_token.json"
status: "succeed"
- config_path: "secrets/config_oauth.json"
status: "succeed"
- config_path: "integration_tests/invalid_config.json"
status: "failed"
- config_path: "integration_tests/invalid_config_oauth.json"
status: "failed"
discovery:
- config_path: "secrets/config.json"
- config_path: "secrets/config_api_token.json"
- config_path: "secrets/config_oauth.json"
basic_read:
- config_path: "secrets/config.json"
configured_catalog_path: "integration_tests/configured_catalog.json"
empty_streams: ["teams"]
- 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"
full_refresh:
- config_path: "secrets/config.json"
configured_catalog_path: "integration_tests/configured_catalog.json"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"credentials": {
"auth_type": "oauth2.0",
"client_id": "q1q1q1q1q1q1q1q1q1q1q",
"client_secret": "2w2w2w2w2w2w2w2w2w2w2",
"access_token": "qwerty",
"subdomain": "subdomain"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import json
import os
from abc import ABC
from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Tuple
from typing import Any, Iterable, List, Mapping, MutableMapping, Optional, Tuple, Dict

import requests
from airbyte_cdk.sources import AbstractSource
Expand All @@ -18,9 +18,9 @@

# Basic full refresh stream
class MondayStream(HttpStream, ABC):
url_base = "https://api.monday.com/v2"
primary_key = "id"
page = 1
url_base: str = "https://api.monday.com/v2"
primary_key: str = "id"
page: int = 1
transformer: TypeTransformer = TypeTransformer(TransformConfig.DefaultSchemaNormalization)

def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]:
Expand Down Expand Up @@ -123,24 +123,46 @@ class Users(MondayStream):
"""

def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]:
pass
# Stream Users doesn't support pagination
return


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

def __init__(self, config: Dict):
self.config = config

def get_token(self):
# the old config supports for backward capability
token = self.config.get("api_token")
if not token:
auth_type = self.config["credentials"]["auth_type"]
if auth_type == "oauth2.0":
token = self.config["credentials"]["access_token"]
if auth_type == "api_token":
token = self.config["credentials"]["api_token"]
return token

def get_auth(self) -> TokenAuthenticator:
""" Return the TokenAuthenticator object with access or api token. """
return TokenAuthenticator(token=self.get_token())


# Source
class SourceMonday(AbstractSource):
def check_connection(self, logger, config) -> Tuple[bool, any]:
url = "https://api.monday.com/v2"
params = {"query": "{boards(limit:1){id name}}"}
auth = TokenAuthenticator(config["api_token"]).get_auth_header()
params = {"query": "query { me { is_guest created_at name id}}"}
auth_header = MondayAuthentication(config).get_auth().get_auth_header()
try:
response = requests.post(url, params=params, headers=auth)
response = requests.post(url, params=params, headers=auth_header)
response.raise_for_status()
return True, None
except requests.exceptions.RequestException as e:
return False, e

def streams(self, config: Mapping[str, Any]) -> List[Stream]:
auth = TokenAuthenticator(token=config["api_token"])
auth = MondayAuthentication(config).get_auth()
return [
Items(authenticator=auth),
Boards(authenticator=auth),
Expand Down
126 changes: 119 additions & 7 deletions airbyte-integrations/connectors/source-monday/source_monday/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,126 @@
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Monday Spec",
"type": "object",
"required": ["api_token"],
"additionalProperties": false,
"required": [],
"additionalProperties": true,
"properties": {
"api_token": {
"type": "string",
"title": "Personal Access Token",
"description": "Access Token for making authenticated requests.",
"airbyte_secret": true
"credentials": {
"title": "Authorization Method",
"type": "object",
"oneOf": [
{
"type": "object",
"title": "OAuth2.0",
"required": ["auth_type", "client_id", "client_secret", "access_token"],
"properties": {
"subdomain": {
"type": "string",
"title": "Subdomain/Slug (Optional)",
"description": "Slug/subdomain of the account, or the first part of the URL that comes before .monday.com",
"default": "",
"order": 0
},
"auth_type": {
"type": "string",
"const": "oauth2.0",
"enum": ["oauth2.0"],
"default": "oauth2.0",
"order": 1
},
"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": "Access Token for making authenticated requests.",
"airbyte_secret": true
}
}
},
{
"type": "object",
"title": "API Token",
"required": ["auth_type", "api_token"],
"properties": {
"auth_type": {
"type": "string",
"const": "api_token",
"enum": ["api_token"],
"default": "api_token",
"order": 0
},
"api_token": {
"type": "string",
"title": "Personal API Token",
"description": "API Token for making authenticated requests.",
"airbyte_secret": true
}
}
}
]
}
}
},
"advanced_auth": {
"auth_flow_type": "oauth2.0",
"predicate_key": ["credentials", "auth_type"],
"predicate_value": "oauth2.0",
"oauth_config_specification": {
"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": true,
"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"]
}
}
},
"oauth_user_input_from_connector_config_specification": {
"type": "object",
"additionalProperties": false,
"properties": {
"subdomain": {
"type": "string",
"path_in_connector_config": ["credentials", "subdomain"]
}
}
}
}
}
Expand Down

0 comments on commit 069587b

Please sign in to comment.