Skip to content

Commit 89c5a86

Browse files
authored
Merge pull request #218 from canonical/wd-2024
feat: Add better error handling for missing api key and username
2 parents 461e5cd + d7ab798 commit 89c5a86

File tree

5 files changed

+38
-1
lines changed

5 files changed

+38
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 7.1.1 [01-07-2025]
2+
**Added**
3+
- Better error handling when api key and username is missing
4+
15
### 7.1.0 [17-11-2025]
26
**Updated** EngagePages class
37
- Support optional `value` in `get_engage_pages_tags` to return tags for a specific engage page type

canonicalwebteam/discourse/models.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,27 @@ def __init__(
2727
self.base_url = base_url.rstrip("/")
2828
self.session = session
2929
self.get_topics_query_id = get_topics_query_id
30+
self.api_key = api_key
31+
self.api_username = api_username
3032

3133
if api_key and api_username:
3234
self.session.headers = {
3335
"Api-Key": api_key,
3436
"Api-Username": api_username,
3537
}
3638

39+
def _require_authentication(self):
40+
"""
41+
Check if API credentials are available and raise an error if not.
42+
This should be called before accessing authenticated endpoints.
43+
a.k.a. Data Explorer endpoints.
44+
"""
45+
if not self.api_key or not self.api_username:
46+
raise ValueError(
47+
"API authentication required: API key and username "
48+
"are required to access this endpoint"
49+
)
50+
3751
def __del__(self):
3852
self.session.close()
3953

@@ -54,6 +68,8 @@ def get_topics(self, topic_ids):
5468
we are using it to obtain multiple Tutorials content without
5569
doing multiple API calls.
5670
"""
71+
self._require_authentication()
72+
5773
headers = {
5874
"Accept": "application/json",
5975
"Content-Type": "multipart/form-data;",
@@ -167,6 +183,8 @@ def get_topic_list_by_category(self, category_id, limit=100, offset=0):
167183
- limit [int]: 100 by default, also set in data explorer
168184
- offset [int]: 0 by default (first page)
169185
"""
186+
self._require_authentication()
187+
170188
# See https://discourse.ubuntu.com/admin/plugins/explorer?id=89
171189
data_explorer_id = 89
172190
headers = {
@@ -203,6 +221,8 @@ def get_topics_last_activity_time(self, topic_id):
203221
Args:
204222
- topic_id [int]: The topic ID
205223
"""
224+
self._require_authentication()
225+
206226
# See https://discourse.ubuntu.com/admin/plugins/explorer?id=122
207227
data_explorer_id = 122
208228
headers = {
@@ -228,6 +248,8 @@ def get_categories_last_activity_time(self, category_id):
228248
Args:
229249
- category_id [int]: The category ID
230250
"""
251+
self._require_authentication()
252+
231253
# See https://discourse.ubuntu.com/admin/plugins/explorer?id=123
232254
data_explorer_id = 123
233255
headers = {
@@ -331,6 +353,8 @@ def get_engage_pages_by_param(
331353
- limit [int]: 50 by default, also set in data explorer
332354
- offset [int]: 0 by default (first page)
333355
"""
356+
self._require_authentication()
357+
334358
headers = {
335359
"Accept": "application/json",
336360
"Content-Type": "multipart/form-data;",
@@ -392,6 +416,8 @@ def get_engage_pages_by_tag(self, category_id, tag, limit=50, offset=0):
392416
- limit [int]: 50 by default, also set in data explorer
393417
- offset [int]: 0 by default (first page)
394418
"""
419+
self._require_authentication()
420+
395421
headers = {
396422
"Accept": "application/json",
397423
"Content-Type": "multipart/form-data;",

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name="canonicalwebteam.discourse",
7-
version="7.1.0",
7+
version="7.1.1",
88
author="Canonical webteam",
99
author_email="webteam@canonical.com",
1010
url="https://github.com/canonical/canonicalwebteam.discourse",

tests/test_engage_pages.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def setUp(self):
2828
self.discourse_api = DiscourseAPI(
2929
base_url="https://discourse.ubuntu.com/",
3030
session=session,
31+
api_key="fake-api-key",
32+
api_username="fake-username",
3133
)
3234
self.engage_pages = EngagePages(
3335
category_id=51,

tests/test_models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ def test_get_topic(self):
2626
self.assertEqual(topic["id"], 34)
2727
self.assertEqual(topic["title"], "An index page")
2828

29+
def test_require_authentication_raises_error_without_credentials(self):
30+
with self.assertRaises(ValueError) as context:
31+
self.api._require_authentication()
32+
self.assertIn("API authentication required", str(context.exception))
33+
2934

3035
if __name__ == "__main__":
3136
unittest.main()

0 commit comments

Comments
 (0)