Skip to content

Commit c25c4b9

Browse files
authored
Merge pull request #4 from MarletteFunding/feature/data-2830
Feature/data 2830
2 parents cb1296d + bfc7cab commit c25c4b9

15 files changed

+84
-17
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
command: |
2222
source dev_env.sh
2323
source /usr/local/share/virtualenvs/tap-zendesk-chat/bin/activate
24-
pylint tap_zendesk_chat -d "$PYLINT_DISABLE_LIST,no-self-use"
24+
pylint tap_zendesk_chat -d "$PYLINT_DISABLE_LIST"
2525
- run:
2626
name: 'JSON Validator'
2727
command: |

.github/pull_request_template.md

+4
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@
99

1010
# Rollback steps
1111
- revert this branch
12+
13+
#### AI generated code
14+
https://internal.qlik.dev/general/ways-of-working/code-reviews/#guidelines-for-ai-generated-code
15+
- [ ] this PR has been written with the help of GitHub Copilot or another generative AI tool

CHANGELOG.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
2-
## 0.4.0
32

3+
## 0.5.1
4+
* Bug Fix with chats stream [#54](https://github.com/singer-io/tap-zendesk-chat/pull/54)
5+
* Dependabot update
6+
7+
## 0.5.0
8+
* Zendesk Domain Change [#52](https://github.com/singer-io/tap-zendesk-chat/pull/52)
9+
10+
## 0.4.1
11+
* Dependabot update [#50](https://github.com/singer-io/tap-zendesk-chat/pull/50)
12+
13+
## 0.4.0
414
* Code Refactoring [#45](https://github.com/singer-io/tap-zendesk-chat/pull/45)
515
- Improved directory structure
616
- Added pagination support to BANS stream
@@ -52,4 +62,4 @@
5262
* Lowers the chat interval days retrieved to 14 to account for a 10k search result limit [#8](https://github.com/singer-io/tap-zendesk-chat/pull/8)
5363

5464
## 0.1.12
55-
* Allow chat interval days to be specified as a string in the config [#10](https://github.com/singer-io/tap-zendesk-chat/pull/10)
65+
* Allow chat interval days to be specified as a string in the config [#10](https://github.com/singer-io/tap-zendesk-chat/pull/10)

setup.py

100755100644
+2-2
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33

44
setup(
55
name="tap-zendesk-chat",
6-
version="0.4.0",
6+
version="0.5.1",
77
description="Singer.io tap for extracting data from the Zendesk Chat API",
88
author="Stitch",
99
url="https://singer.io",
1010
classifiers=["Programming Language :: Python :: 3 :: Only"],
1111
py_modules=["tap_zendesk_chat"],
1212
install_requires=[
1313
"singer-python==5.12.1",
14-
"requests==2.20.0",
14+
"requests==2.32.3",
1515
],
1616
extras_require={"dev": ["pylint", "ipdb", "nose"]},
1717
entry_points="""

tap_zendesk_chat/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ def main():
2323

2424
if __name__ == "__main__":
2525
main()
26+

tap_zendesk_chat/context.py

+1
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ def update_start_date_bookmark(self, path):
4949

5050
def write_state(self):
5151
write_state(self.state)
52+

tap_zendesk_chat/discover.py

+1
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,4 @@ def discover(config: dict) -> Catalog:
6565
}
6666
)
6767
return Catalog.from_dict({"streams": streams})
68+

tap_zendesk_chat/http_client.py

+36-2
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,54 @@
99
class RateLimitException(Exception):
1010
pass
1111

12+
class InvalidConfigurationError(Exception):
13+
pass
14+
1215

1316
class Client:
1417
def __init__(self, config):
1518
self.access_token = config["access_token"]
1619
self.user_agent = config.get("user_agent", "tap-zendesk-chat")
1720
self.headers = {}
21+
self.subdomain = config.get("subdomain")
1822
self.headers["Authorization"] = f"Bearer {self.access_token}"
1923
self.headers["User-Agent"] = self.user_agent
24+
self.base_url = self.get_base_url()
2025
self.session = requests.Session()
2126

27+
def get_base_url(self):
28+
"""
29+
Determines the base URL to use for Zendesk API requests.
30+
31+
Checks the availability of zendesk chat endpoints
32+
and returns the available one
33+
Returns:
34+
str: The base URL to use for subsequent API requests.
35+
36+
Raises:
37+
InvalidConfigurationError: If neither endpoint is accessible.
38+
"""
39+
urls = [
40+
(f"https://{self.subdomain}.zendesk.com" , "/api/v2/chat/agents"),
41+
(BASE_URL , "/api/v2/agents")
42+
]
43+
if not self.subdomain:
44+
# return base url incase of missing subdomain
45+
return BASE_URL
46+
for domain, endpoint in urls:
47+
resp = requests.get(f"{domain}{endpoint}", headers=self.headers, timeout=25)
48+
LOGGER.info("API CHECK %s %s", resp.url, resp.status_code)
49+
if resp.status_code == 200:
50+
return domain
51+
raise InvalidConfigurationError("Please check the URL or reauthenticate")
52+
2253
@backoff.on_exception(backoff.expo, RateLimitException, max_tries=10, factor=2)
2354
def request(self, tap_stream_id, params=None, url=None, url_extra=""):
2455
with metrics.http_request_timer(tap_stream_id) as timer:
25-
26-
url = url or f"{BASE_URL}/api/v2/{tap_stream_id}{url_extra}"
56+
if self.base_url == BASE_URL:
57+
url = url or f"{self.base_url}/api/v2/{tap_stream_id}{url_extra}"
58+
else:
59+
url = url or f"{self.base_url}/api/v2/chat/{tap_stream_id}{url_extra}"
2760
LOGGER.info("calling %s %s", url, params)
2861
response = self.session.get(url, headers=self.headers, params=params)
2962
timer.tags[metrics.Tag.http_status_code] = response.status_code
@@ -37,3 +70,4 @@ def request(self, tap_stream_id, params=None, url=None, url_extra=""):
3770
)
3871
response.raise_for_status()
3972
return response.json()
73+

tap_zendesk_chat/schemas/chat_engagement.json

+1
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,4 @@
102102
"object"
103103
]
104104
}
105+

tap_zendesk_chat/schemas/chat_history.json

+1
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,4 @@
163163
"chat_conversion"
164164
]
165165
}
166+

tap_zendesk_chat/schemas/chats.json

+1
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,4 @@
258258
"chat_engagement"
259259
]
260260
}
261+

tap_zendesk_chat/streams.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def _bulk_chats(self, ctx, chat_ids: List):
116116
body = ctx.client.request(self.tap_stream_id, params=params)
117117
return list(body["docs"].values())
118118

119-
def _pull(self, ctx, chat_type, ts_field, full_sync, schema: Dict, stream_metadata: Dict, transformer: Transformer):
119+
def _pull(self, *, ctx, chat_type, ts_field, full_sync, schema: Dict, stream_metadata: Dict, transformer: Transformer):
120120
"""Pulls and writes pages of data for the given chat_type, where
121121
chat_type can be either "chat" or "offline_msg".
122122
@@ -181,18 +181,18 @@ def _should_run_full_sync(self, ctx) -> bool:
181181
def sync(self, ctx, schema: Dict, stream_metadata: Dict, transformer: Transformer):
182182
full_sync = self._should_run_full_sync(ctx)
183183
self._pull(
184-
ctx,
185-
"chat",
186-
"end_timestamp",
184+
ctx=ctx,
185+
chat_type="chat",
186+
ts_field="end_timestamp",
187187
full_sync=full_sync,
188188
schema=schema,
189189
stream_metadata=stream_metadata,
190190
transformer=transformer,
191191
)
192192
self._pull(
193-
ctx,
194-
"offline_msg",
195-
"timestamp",
193+
ctx=ctx,
194+
chat_type="offline_msg",
195+
ts_field="timestamp",
196196
full_sync=full_sync,
197197
schema=schema,
198198
stream_metadata=stream_metadata,
@@ -237,3 +237,4 @@ class Triggers(BaseStream):
237237
Shortcuts.tap_stream_id: Shortcuts,
238238
Triggers.tap_stream_id: Triggers,
239239
}
240+

tap_zendesk_chat/sync.py

+1
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ def sync(ctx):
2929

3030
ctx.state = set_currently_syncing(ctx.state, None)
3131
write_state(ctx.state)
32+

tests/unittests/test_auth_discovery.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ def __init__(self):
1313
self.discover = True
1414
self.properties = False
1515
self.config = {"access_token": "abc-def"}
16+
self.config_wd_subdomain = {"access_token": "abc-def", "subdomain":"test"}
1617
self.state = False
1718
self.properties = {}
1819

@@ -43,9 +44,16 @@ def test_basic_auth_no_access_401(self):
4344

4445
with self.assertRaises(HTTPError) as e:
4546
tap_zendesk_chat.discover(args.config)
46-
# Verifying the message formed for the custom exception
47-
expected_error_message = "401 Client Error: Unauthorized for url:"
48-
self.assertIn(expected_error_message, str(e.exception))
47+
# Verifying the message formed for the custom exception
48+
expected_error_message = "401 Client Error: Unauthorized for url:"
49+
self.assertIn(expected_error_message, str(e.exception))
50+
51+
expected_error_message = "Please check the URL or reauthenticate"
52+
53+
with self.assertRaises(InvalidConfigurationError) as e:
54+
tap_zendesk_chat.discover(args.config_wd_subdomain)
55+
self.assertIn(expected_error_message, str(e.exception))
56+
4957

5058
@mock.patch("tap_zendesk_chat.utils", return_value=Args())
5159
@mock.patch("singer.catalog.Catalog.from_dict", return_value={"key": "value"})
@@ -63,6 +71,7 @@ def test_discovery(self, mock_utils, mock_catalog, mock_request):
6371
self.assertEqual(tap_zendesk_chat.discover(Args().config), expected)
6472

6573

74+
6675
class TestAccountEndpointAuthorized(unittest.TestCase):
6776
def test_is_account_not_authorized_404(self):
6877
"""tests if account_not_authorized method in discover raises http
@@ -73,3 +82,4 @@ def test_is_account_not_authorized_404(self):
7382

7483
expected_error_message = "404 Client Error: Not Found for url:"
7584
self.assertIn(expected_error_message, str(e.exception))
85+

tests/unittests/test_http_exceptions.py

+1
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ def test_rate_limit_502_error(self, mocked_send, mocked_sleep):
4747
with self.assertRaises(RateLimitException):
4848
client.request("departments")
4949
self.assertEqual(mocked_send.call_count, 10)
50+

0 commit comments

Comments
 (0)