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

Add method get_lists_users to retrieve members of a shared list #130

Merged
merged 1 commit into from
Jan 22, 2025
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
58 changes: 58 additions & 0 deletions bring_api/bring.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
BringNotificationType,
BringSyncCurrentUserResponse,
BringUserSettingsResponse,
BringUsersResponse,
ReactionType,
UserLocale,
)
Expand Down Expand Up @@ -1552,3 +1553,60 @@ async def get_activity(self, list_uuid: str) -> BringActivityResponse:
raise BringRequestException(
"Loading list activity failed due to request exception."
) from e

async def get_list_users(self, list_uuid: str) -> BringUsersResponse:
"""Retrieve members of a shared list."""

try:
url = self.url / "v2/bringlists" / list_uuid / "users"
async with self._session.get(url, headers=self.headers) as r:
_LOGGER.debug(
"Response from %s [%s]: %s", url, r.status, await r.text()
)

if r.status == HTTPStatus.UNAUTHORIZED:
try:
errmsg = BringErrorResponse.from_json(await r.text())
except (JSONDecodeError, aiohttp.ClientError):
_LOGGER.debug(
"Exception: Cannot parse request response:", exc_info=True
)
else:
_LOGGER.debug(
"Exception: Cannot get list users: %s", errmsg.message
)
raise BringAuthException(
"Loading list users failed due to authorization failure, "
"the authorization token is invalid or expired."
)

r.raise_for_status()

try:
return BringUsersResponse.from_json(await r.text())
except MissingField as e:
raise BringMissingFieldException(e) from e
except (JSONDecodeError, KeyError) as e:
_LOGGER.debug(
"Exception: Cannot get users for list %s:",
list_uuid,
exc_info=True,
)
raise BringParseException(
"Loading list users failed during parsing of request response."
) from e

except TimeoutError as e:
_LOGGER.debug(
"Exception: Cannot get users for list %s:", list_uuid, exc_info=True
)
raise BringRequestException(
"Loading list users failed due to connection timeout."
) from e
except aiohttp.ClientError as e:
_LOGGER.debug(
"Exception: Cannot get users for list %s:", list_uuid, exc_info=True
)
raise BringRequestException(
"Loading list users failed due to request exception."
) from e
21 changes: 21 additions & 0 deletions bring_api/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,24 @@ class BringErrorResponse(DataClassORJSONMixin):
error: str
error_description: str
errorcode: int


@dataclass(kw_only=True)
class BringUser:
"""A Bring user."""

publicUuid: str
pushEnabled: bool
plusTryOut: bool
country: str
language: str
name: str = ""
email: str = ""
photoPath: str = ""


@dataclass(kw_only=True)
class BringUsersResponse(DataClassORJSONMixin):
"""List users."""

users: list[BringUser] = field(default_factory=list)
3 changes: 3 additions & 0 deletions tests/__snapshots__/test_bring.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
# name: TestGetList.test_get_list
BringItemsResponse(uuid='00000000-0000-0000-0000-000000000000', status='SHARED', items=Items(purchase=[BringPurchase(uuid='43bdd5a2-740a-4230-8b27-d0bbde886da7', itemId='Paprika', specification='grün', attributes=[]), BringPurchase(uuid='2de9d1c0-c211-4129-b6c5-c1260c3fc735', itemId='Zucchetti', specification='gelb', attributes=[])], recently=[BringPurchase(uuid='5681ed79-c8e4-4c8b-95ec-112999d016c0', itemId='Paprika', specification='rot', attributes=[]), BringPurchase(uuid='01eea2cd-f433-4263-ad08-3d71317c4298', itemId='Pouletbrüstli', specification='', attributes=[])]))
# ---
# name: TestGetListUsers.test_get_lists_users
BringUsersResponse(users=[BringUser(publicUuid='98615d7e-0a7d-4a7e-8f73-a9cbb9f1bc32', pushEnabled=True, plusTryOut=False, country='DE', language='de', name='NAME', email='EMAIL', photoPath=''), BringUser(publicUuid='73af455f-c158-4004-a5e0-79f4f8a6d4bd', pushEnabled=True, plusTryOut=False, country='US', language='en', name='NAME', email='EMAIL', photoPath=''), BringUser(publicUuid='7d5e9d08-877a-4c36-8740-a9bf74ec690a', pushEnabled=True, plusTryOut=False, country='US', language='en', name='', email='', photoPath='')])
# ---
# name: TestGetUserAccount.test_get_user_account
BringSyncCurrentUserResponse(email='{email}', emailVerified=True, premiumConfiguration={'hasPremium': False, 'hideSponsoredProducts': False, 'hideSponsoredTemplates': False, 'hideSponsoredPosts': False, 'hideSponsoredCategories': False, 'hideOffersOnMain': False}, publicUserUuid='00000000-0000-0000-0000-000000000000', userLocale=UserLocale(language='de', country='DE'), userUuid='00000000-0000-0000-0000-000000000000', name='{user_name}', photoPath='bring/user/portrait/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx')
# ---
Expand Down
32 changes: 32 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,38 @@
"totalEvents": 2,
}

BRING_GET_LIST_USERS_RESPONSE = {
"users": [
{
"publicUuid": "98615d7e-0a7d-4a7e-8f73-a9cbb9f1bc32",
"name": "NAME",
"email": "EMAIL",
"photoPath": "",
"pushEnabled": True,
"plusTryOut": False,
"country": "DE",
"language": "de",
},
{
"publicUuid": "73af455f-c158-4004-a5e0-79f4f8a6d4bd",
"name": "NAME",
"email": "EMAIL",
"photoPath": "",
"pushEnabled": True,
"plusTryOut": False,
"country": "US",
"language": "en",
},
{
"publicUuid": "7d5e9d08-877a-4c36-8740-a9bf74ec690a",
"pushEnabled": True,
"plusTryOut": False,
"country": "US",
"language": "en",
},
]
}

BRING_ERROR_RESPONSE = {
"message": "",
"error": "",
Expand Down
83 changes: 83 additions & 0 deletions tests/test_bring.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
BRING_GET_ACTIVITY_RESPONSE,
BRING_GET_ALL_ITEM_DETAILS_RESPONSE,
BRING_GET_LIST_RESPONSE,
BRING_GET_LIST_USERS_RESPONSE,
BRING_LOAD_LISTS_RESPONSE,
BRING_LOGIN_RESPONSE,
BRING_TOKEN_RESPONSE,
Expand Down Expand Up @@ -1658,3 +1659,85 @@ async def test_parse_exception(self, mocked, bring, status, exception):

with pytest.raises(exception):
await bring.get_activity(UUID)


class TestGetListUsers:
"""Tests for get_list_users method."""

async def test_get_lists_users(
self,
bring: Bring,
mocked: aioresponses,
monkeypatch: pytest.MonkeyPatch,
snapshot: SnapshotAssertion,
):
"""Test get_list_users."""

mocked.get(
f"https://api.getbring.com/rest/v2/bringlists/{UUID}/users",
status=HTTPStatus.OK,
payload=BRING_GET_LIST_USERS_RESPONSE,
)
monkeypatch.setattr(bring, "uuid", UUID)

activity = await bring.get_list_users(UUID)

assert activity == snapshot

@pytest.mark.parametrize(
"exception",
[
asyncio.TimeoutError,
aiohttp.ClientError,
],
)
async def test_request_exception(
self, mocked: aioresponses, bring: Bring, exception: Exception
):
"""Test request exceptions."""

mocked.get(
f"https://api.getbring.com/rest/v2/bringlists/{UUID}/users",
exception=exception,
)

with pytest.raises(BringRequestException):
await bring.get_list_users(UUID)

async def test_auth_exception(self, mocked: aioresponses, bring: Bring):
"""Test request exceptions."""

mocked.get(
f"https://api.getbring.com/rest/v2/bringlists/{UUID}/users",
status=HTTPStatus.UNAUTHORIZED,
payload=BRING_ERROR_RESPONSE,
)

with pytest.raises(BringAuthException):
await bring.get_list_users(UUID)

@pytest.mark.parametrize(
("status", "exception"),
[
(HTTPStatus.OK, BringParseException),
(HTTPStatus.UNAUTHORIZED, BringAuthException),
],
)
async def test_parse_exception(
self,
mocked: aioresponses,
bring: Bring,
status: HTTPStatus,
exception: Exception,
):
"""Test request exceptions."""

mocked.get(
f"https://api.getbring.com/rest/v2/bringlists/{UUID}/users",
status=status,
body="not json",
content_type="application/json",
)

with pytest.raises(exception):
await bring.get_list_users(UUID)
Loading