1
0
mirror of synced 2026-01-07 09:05:45 -05:00
Files
airbyte/airbyte-integrations/connectors/source-copper/source_copper/source.py
richardlam-quotapath 9d2d7d0319 Source Copper: Add opportunities to streams (#24824)
* Add opportunities to copper streams

* Fix version

* update schema

* update versions and fix schema formatting

* auto-bump connector version

---------

Co-authored-by: Mal Hancock <mhancock@archangelic.space>
Co-authored-by: Octavia Squidington III <octavia-squidington-iii@users.noreply.github.com>
2023-04-17 14:08:50 -07:00

115 lines
3.6 KiB
Python

#
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
#
import json
from abc import ABC
from typing import Any, Iterable, List, Mapping, Optional, Tuple
import requests
from airbyte_cdk.models import SyncMode
from airbyte_cdk.sources import AbstractSource
from airbyte_cdk.sources.streams import Stream
from airbyte_cdk.sources.streams.http import HttpStream
# Basic full refresh stream
class CopperStream(HttpStream, ABC):
def __init__(self, *args, api_key: str = None, user_email: str = None, **kwargs):
super().__init__(*args, **kwargs)
self._user_email = user_email
self._api_key = api_key
url_base = "https://api.copper.com/developer_api/v1/"
@property
def http_method(self) -> str:
return "POST"
def next_page_token(self, response: requests.Response) -> Optional[Mapping[str, Any]]:
body = json.loads(response.request.body)
result = response.json()
if body and result:
page_number = body.get("page_number")
return {"page_number": page_number + 1, "page_size": 200}
else:
return None
def request_body_json(
self,
stream_state: Mapping[str, Any],
stream_slice: Mapping[str, Any] = None,
next_page_token: Mapping[str, Any] = None,
) -> Optional[Mapping]:
if next_page_token:
return next_page_token
return {"page_number": 1, "page_size": 200}
def request_headers(
self, stream_state: Mapping[str, Any], stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None
) -> Mapping[str, Any]:
return {
"X-PW-AccessToken": self._api_key,
"X-PW-UserEmail": self._user_email,
"X-PW-Application": "developer_api",
"Content-type": "application/json",
}
def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapping]:
response_result = response.json()
if response_result:
yield from response_result
return
class People(CopperStream):
primary_key = "id"
def path(
self, stream_state: Mapping[str, Any] = None, stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None
) -> str:
return "people/search"
class Projects(CopperStream):
primary_key = "id"
def path(
self, stream_state: Mapping[str, Any] = None, stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None
) -> str:
return "projects/search"
class Companies(CopperStream):
primary_key = "id"
def path(
self, stream_state: Mapping[str, Any] = None, stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None
) -> str:
return "companies/search"
class Opportunities(CopperStream):
primary_key = "id"
def path(
self, stream_state: Mapping[str, Any] = None, stream_slice: Mapping[str, Any] = None, next_page_token: Mapping[str, Any] = None
) -> str:
return "opportunities/search"
# Source
class SourceCopper(AbstractSource):
def check_connection(self, logger, config) -> Tuple[bool, any]:
try:
records = People(**config).read_records(sync_mode=SyncMode.full_refresh)
next(records, None)
return True, None
except Exception as error:
return False, f"Unable to connect to Copper API with the provided credentials - {repr(error)}"
def streams(self, config: Mapping[str, Any]) -> List[Stream]:
return [People(**config), Companies(**config), Projects(**config), Opportunities(**config)]