Skip to content

Commit 4acf296

Browse files
authored
Add API and codecs for PUT /api/cloud_tokens (#16)
This implements the upcoming PUT /api/cloud_tokens API.
1 parent 5603390 commit 4acf296

7 files changed

Lines changed: 89 additions & 1 deletion

File tree

brainframe/api/bf_codecs/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@
2222
LicenseInfo,
2323
DATE_FORMAT,
2424
)
25+
from .cloud_codecs import CloudTokens, CloudUserInfo
2526
from .sorting import SortOptions, Ordering
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from dataclasses import dataclass
2+
3+
from .base_codecs import Codec
4+
5+
6+
@dataclass
7+
class CloudTokens(Codec):
8+
"""OAuth2 tokens for a BrainFrame Cloud user"""
9+
10+
access_token: str
11+
"""Provides access to the API"""
12+
13+
refresh_token: str
14+
"""Used to refresh the access token when it expires"""
15+
16+
def to_dict(self) -> dict:
17+
return dict(self.__dict__)
18+
19+
@staticmethod
20+
def from_dict(d: dict) -> "CloudTokens":
21+
return CloudTokens(
22+
access_token=d["access_token"],
23+
refresh_token=d["refresh_token"],
24+
)
25+
26+
27+
@dataclass
28+
class CloudUserInfo(Codec):
29+
"""Information on a BrainFrame Cloud user"""
30+
31+
sub: str
32+
"""A unique identifier for the user"""
33+
34+
email: str
35+
"""The user's email address"""
36+
37+
def to_dict(self):
38+
return dict(self.__dict__)
39+
40+
@staticmethod
41+
def from_dict(d: dict) -> "CloudUserInfo":
42+
return CloudUserInfo(
43+
sub=d["sub"],
44+
email=d["email"],
45+
)

brainframe/api/bf_errors.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,11 @@ class IncompatibleCapsuleError(BaseAPIError):
303303
"""
304304

305305

306+
@_server_origin_error()
307+
class UnauthorizedTokensError(BaseAPIError):
308+
"""The provided tokens do not correctly authorize a BrainFrame Cloud user"""
309+
310+
306311
class ServerNotReadyError(BaseAPIError):
307312
"""The client was able to communicate with the server, but the server had
308313
not completed startup or was in an invalid state"""

brainframe/api/stub.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ class BrainFrameAPI(stubs.AlertStubMixin,
2121
stubs.EncodingStubMixIn,
2222
stubs.PremisesStubMixin,
2323
stubs.UserStubMixin,
24-
stubs.LicenseStubMixIn):
24+
stubs.LicenseStubMixIn,
25+
stubs.CloudTokensStubMixin):
2526
"""Provides access to BrainFrame API endpoints."""
2627

2728
def __init__(self, server_url=None, credentials: Tuple[str, str] = None):

brainframe/api/stubs/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@
1212
from .premises import PremisesStubMixin
1313
from .users import UserStubMixin
1414
from .licenses import LicenseStubMixIn
15+
from .cloud_tokens import CloudTokensStubMixin
1516
from .base_stub import BaseStub

brainframe/api/stubs/base_stub.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ def _get_json(self, api_url, timeout, params=None) -> Tuple[Any, dict]:
5858
return json.loads(resp.content), resp.headers
5959
return None, resp.headers
6060

61+
def _put_codec(self, api_url, timeout, codec: bf_codecs.Codec):
62+
"""Send a PUT request to the given URL.
63+
64+
:param api_url: The path to append to the base_url
65+
:param timeout: The timeout to use for this request
66+
:param codec: A codec to convert to JSON and send
67+
:return: The JSON response as a dict, or None if none was sent
68+
"""
69+
codec_data = codec.to_json()
70+
resp = self._put(api_url,
71+
timeout,
72+
data=codec_data,
73+
content_type="application/json")
74+
75+
if resp.content:
76+
return json.loads(resp.content)
77+
return None
78+
6179
def _put_json(self, api_url, timeout, json_data) -> Any:
6280
"""Send a PUT request to the given URL.
6381
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from brainframe.api.bf_codecs import CloudTokens, CloudUserInfo
2+
from .base_stub import BaseStub, DEFAULT_TIMEOUT
3+
4+
5+
class CloudTokensStubMixin(BaseStub):
6+
def set_cloud_tokens(self, cloud_tokens: CloudTokens,
7+
timeout=DEFAULT_TIMEOUT) -> CloudUserInfo:
8+
"""Authorizes the server against BrainFrame Cloud using the provided tokens.
9+
10+
:param cloud_tokens: The tokens to use for authorization
11+
:param timeout: the timeout to use for this request
12+
:return: Info on the BrainFrame Cloud user that corresponds to these tokens
13+
"""
14+
req = "/api/cloud_tokens"
15+
user_info_dict = self._put_codec(req, timeout, cloud_tokens)
16+
17+
return CloudUserInfo.from_dict(user_info_dict)

0 commit comments

Comments
 (0)