diff --git a/src/posit/connect/__init__.py b/src/posit/connect/__init__.py index 5f22e94e..6eb66c5a 100644 --- a/src/posit/connect/__init__.py +++ b/src/posit/connect/__init__.py @@ -1 +1,10 @@ -from .client import Client # noqa +from typing import Optional + +from .client import Client + + +def make_client( + api_key: Optional[str] = None, endpoint: Optional[str] = None +) -> Client: + client = Client(api_key=api_key, endpoint=endpoint) + return client diff --git a/src/posit/connect/users.py b/src/posit/connect/users.py index c28fc53f..917daff9 100644 --- a/src/posit/connect/users.py +++ b/src/posit/connect/users.py @@ -1,17 +1,75 @@ +from __future__ import annotations + import os -from requests import Session, Response +from dataclasses import dataclass, asdict +from datetime import datetime +from requests import Session +from typing import Optional + + +@dataclass +class User: + guid: str + email: str + username: str + first_name: str + last_name: str + user_role: str + created_time: datetime + updated_time: datetime + active_time: datetime + confirmed: bool + locked: bool + + def to_dict(self) -> dict: + return asdict(self) + + +class Users(list[User]): + """An extension of :class:`list[User]` with additional fetch methods.""" + _endpoint: str + _session: Session -class Users: - def __init__(self, endpoint: str, session: Session) -> None: + def __init__(self, endpoint: str, session: Session): self._endpoint = endpoint self._session = session - def get_user(self, user_id: str) -> Response: - endpoint = os.path.join(self._endpoint, "__api__/v1/users", user_id) - return self._session.get(endpoint) + def find(self, params: dict = {}) -> Users: + """Finds any :class:`User` that matches the provided filter conditions + + Keyword Arguments: + params -- filter conditions (default: {{}}) + + Returns: + `self` + """ + self.clear() + endpoint = os.path.join(self._endpoint, "__api__/v1/users") + response = self._session.get(endpoint) + data = response.json() + for user in data["results"]: + if all(user.get(k) == v for k, v in params.items()): + self.append(User(**user)) + # todo - implement paging and caching + return self + + def find_one(self, params: dict = {}) -> Optional[User]: + """Finds one :class:`User` + + Keyword Arguments: + params -- filter conditions (default: {{}}) + + Returns: + A matching :class:`User`. + """ + if "guid" in params: + # Use the user details API if a 'guid' is provided. + # This is an example of how we can use different API endpoints to optimize execution time. + endpoint = os.path.join(self._endpoint, "__api__/v1/users", params["guid"]) + response = self._session.get(endpoint) + return User(**response.json()) - def get_current_user(self) -> Response: - endpoint = os.path.join(self._endpoint, "__api__/v1/user") - return self._session.get(endpoint) + # Otherwise, perform a normal search. + return next(iter(self.find(params)), None) diff --git a/src/posit/connect/users_test.py b/src/posit/connect/users_test.py index 689abcfd..e69de29b 100644 --- a/src/posit/connect/users_test.py +++ b/src/posit/connect/users_test.py @@ -1,21 +0,0 @@ -from unittest.mock import Mock - -from .users import Users - - -class TestUsers: - def test_get_user(self): - session = Mock() - session.get = Mock(return_value={}) - users = Users(endpoint="http://foo.bar/", session=session) - response = users.get_user(user_id="foo") - assert response == {} - session.get.assert_called_once_with("http://foo.bar/__api__/v1/users/foo") - - def test_get_current_user(self): - session = Mock() - session.get = Mock(return_value={}) - users = Users(endpoint="http://foo.bar/", session=session) - response = users.get_current_user() - assert response == {} - session.get.assert_called_once_with("http://foo.bar/__api__/v1/user") diff --git a/tinkering.py b/tinkering.py index 4a025882..c507c41d 100644 --- a/tinkering.py +++ b/tinkering.py @@ -1,5 +1,9 @@ -from posit.connect.client import Client +from posit.connect import make_client -client = Client() -res = client.users.get_current_user() -print(res.json()) +client = make_client() +for user in client.users.find({"username": "aaron"}): + print(user) + +print(client.users.find_one()) + +print(client.users.find_one({"guid": "f155520a-ca2e-4084-b0a0-12120b7d1add"}))