Skip to content

Commit 660bfca

Browse files
authored
[ BB2-1152 ] Updates from utilizing the SDK in the sample app (#7)
* Improve packaging per sample app testing * Fix bug with callback in auth url * Update README.md * Add get/set methods to AuthorizationToken class - Add `get_dict()` to `AuthorizationToken` class for SDK user to get auth token config dictionary in a format that is nice from them to store. expires_at is in an ISO date/time string format. - Add `set_dict()` to `AuthorizationToken` class for SDK user to be able to configurate a class instance with their stored configuration values. - Add related tests to `test_auth.py`. BB2-1152 * Fix call to refresh_auth_token() method * Fix url issue if version is integer
1 parent f57156c commit 660bfca

22 files changed

+133
-51
lines changed

MANIFEST.in

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1-
recursive-include src *.py
1+
recursive-include . *.py
2+
3+
include *.json
4+
recursive-include cms_bluebutton *.json
5+
recursive-include cms_bluebutton *.yaml
6+
7+
exclude .bluebutton-config.json
8+
9+
include .flake8
10+
exclude requirements/*
11+

README.md

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,20 @@ Introduction goes here!
2626
$ source bb2_env/bin/activate
2727
# Perform install and commands after sourcing the venv.
2828
```
29-
30-
## Build
31-
32-
To build the cms_bluebutton package do the following:
33-
34-
- Build the package:
35-
36-
```
37-
# From repository root directory:
38-
$ python setup.py bdist_wheel
39-
```
40-
4129
## Installation
4230

43-
To install the package locally do the following:
31+
To install the package file do the following:
4432

4533
```
4634
# From repository root directory:
47-
$ pip install -e .
35+
$ pip install <package file name>
4836
```
4937

5038
## Usage
5139

5240
Usage goes here!
5341

42+
5443
## Developing the Blue Button 2.0 SDK (for BB2 team SDK developers)
5544

5645
### Install Development
@@ -63,12 +52,14 @@ From the repository base directory:
6352
$ pip install -e .[dev]
6453
```
6554

55+
### Running tests
56+
6657
To run the tests, use the following commands:
6758

6859
From the package base directory:
6960

7061
```
71-
$ cd src/cms_bluebutton
62+
$ cd cms_bluebutton
7263
7364
$ # To run all tests:
7465
$ pytest
@@ -88,26 +79,59 @@ $ coverage run -m pytest
8879
$ coverage report -m
8980
```
9081

91-
### Create Distribution
82+
## Packaging and Publishing
9283

93-
To create a distribution run the following command:
9484

95-
From the repository base directory:
85+
### Create or Update Manifest
86+
87+
If check-manifest is not yet installed run the following:
9688

9789
```
98-
$ python setup.py sdist
90+
$ pip install check-manifest # If not already installed.
9991
```
10092

101-
The resulting distribution files with be created in the `sdist/` directory.
93+
If MANIFEST.in does not yet exist, run the following to create it:
10294

103-
### Create Manifest
104-
105-
Note that the previous distribution did not include the license.txt or test files. This requires creating a manifest.
95+
```
96+
$ check-manifest --create
97+
```
10698

107-
To create a MANIFEST.in file run the following commands:
99+
To help with updating MANIFEST.in run the following to get information:
108100

109101
```
110-
$ pip install check-manifest # If not already installed.
111-
$ check-manifest --create
112-
$ python setup.py sdist
113-
```
102+
$ check-manifest
103+
# This creates the following directory: cms_bluebutton.egg-info
104+
```
105+
106+
### Build Packages
107+
108+
To build the cms_bluebutton packages do the following:
109+
110+
- Build a wheel distribution package (.whl):
111+
112+
```
113+
# From repository root directory:
114+
$ rm -rf build/
115+
$ python setup.py bdist_wheel
116+
```
117+
118+
- Build a distribution package (.tar.gz):
119+
120+
```
121+
# From repository root directory:
122+
$ rm -rf build/
123+
$ python setup.py sdist
124+
```
125+
126+
- Build a source package:
127+
128+
```
129+
# From repository root directory:
130+
$ rm -rf build/
131+
$ python setup.py sdist
132+
```
133+
134+
The resulting distribution files with be created in the `dist/` directory.
135+
136+
137+
### Publishing
Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,45 @@
1111

1212

1313
class AuthorizationToken:
14-
def __init__(self, auth_token):
15-
self.access_token = auth_token.get("access_token")
16-
self.expires_in = auth_token.get("expires_in")
17-
self.expires_at = (
18-
auth_token.get("expires_at")
19-
if auth_token.get("expires_at")
20-
else datetime.datetime.now(datetime.timezone.utc)
21-
+ datetime.timedelta(seconds=self.expires_in)
22-
)
23-
self.patient = auth_token.get("patient")
24-
self.refresh_token = auth_token.get("refresh_token")
25-
self.scope = auth_token.get("scope")
26-
self.token_type = auth_token.get("token_type")
14+
def __init__(self, auth_token_dict):
15+
self.set_dict(auth_token_dict)
2716

2817
def access_token_expired(self):
2918
return self.expires_at < datetime.datetime.now(datetime.timezone.utc)
3019

20+
def get_dict(self):
21+
return {
22+
"access_token": self.access_token,
23+
"expires_in": self.expires_in,
24+
"expires_at": self.expires_at.astimezone(datetime.timezone.utc)
25+
.replace(microsecond=0)
26+
.isoformat(),
27+
"patient": self.patient,
28+
"refresh_token": self.refresh_token,
29+
"scope": self.scope,
30+
"token_type": self.token_type,
31+
}
32+
33+
def set_dict(self, auth_token_dict):
34+
self.access_token = auth_token_dict.get("access_token")
35+
self.expires_in = auth_token_dict.get("expires_in")
36+
37+
if auth_token_dict.get("expires_at"):
38+
if type(auth_token_dict.get("expires_at")) == datetime.datetime:
39+
self.expires_at = auth_token_dict.get("expires_at")
40+
else:
41+
self.expires_at = datetime.datetime.fromisoformat(
42+
auth_token_dict.get("expires_at")
43+
).astimezone(datetime.timezone.utc)
44+
else:
45+
self.expires_at = datetime.datetime.now(datetime.timezone.utc)
46+
+datetime.timedelta(seconds=self.expires_in)
47+
48+
self.patient = auth_token_dict.get("patient")
49+
self.refresh_token = auth_token_dict.get("refresh_token")
50+
self.scope = auth_token_dict.get("scope")
51+
self.token_type = auth_token_dict.get("token_type")
52+
3153

3254
def refresh_auth_token(bb, auth_token):
3355
data = {
@@ -54,7 +76,7 @@ def refresh_auth_token(bb, auth_token):
5476
def generate_authorize_url(bb, auth_data):
5577
params = {
5678
"client_id": bb.client_id,
57-
"redirect_uri": bb.client_secret,
79+
"redirect_uri": bb.callback_url,
5880
"state": auth_data["state"],
5981
"response_type": "code",
6082
"code_challenge_method": "S256",
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def fhir_request(bb, config):
1414
retry_config = Retry(
1515
total=3, backoff_factor=5, status_forcelist=[500, 502, 503, 504]
1616
)
17-
full_url = bb.base_url + "/v" + bb.version + "/" + config["url"]
17+
full_url = "{}/v{}/{}".format(bb.base_url, bb.version, config["url"])
1818
headers = {
1919
"Authorization": "Bearer " + auth_token.access_token,
2020
SDK_HEADER_KEY: SDK_HEADER,
@@ -30,6 +30,6 @@ def fhir_request(bb, config):
3030

3131
def handle_expired(bb, auth_token):
3232
if auth_token.access_token_expired():
33-
return bb.refresh_auth_token(bb, auth_token)
33+
return bb.refresh_auth_token(auth_token)
3434
else:
3535
return None
File renamed without changes.
Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import datetime
12
import pytest
23
import requests_mock
34
from urllib.parse import urlparse, parse_qs
45

5-
from cms_bluebutton import BlueButton
6+
from cms_bluebutton import BlueButton, AuthorizationToken
67
from .fixtures.token_response import TOKEN_RESPONSE, REFRESH_TOKEN_RESPONSE
78

89

@@ -36,7 +37,10 @@ def test_auth_url_v1():
3637
assert parsed_url.path == "/v1/o/authorize"
3738
qps = parse_qs(parsed_url.query)
3839
assert bb.client_id in qps["client_id"]
40+
assert bb.callback_url in qps["redirect_uri"]
41+
assert "code" in qps["response_type"]
3942
assert auth_data["state"] in qps["state"]
43+
assert "S256" in qps["code_challenge_method"]
4044
assert auth_data["code_challenge"] in qps["code_challenge"]
4145

4246

@@ -100,6 +104,28 @@ def test_get_authorization_token_callback():
100104
assert auth_token.expires_in == TOKEN_RESPONSE.get("expires_in")
101105
assert not auth_token.access_token_expired()
102106

107+
# Test .get_dict() method
108+
token_dict = auth_token.get_dict()
109+
110+
# Test .set_dict() method where auth_token2 should be the same
111+
auth_token2 = AuthorizationToken(token_dict)
112+
auth_token2.set_dict(token_dict)
113+
114+
assert auth_token2 is not None
115+
assert auth_token2.access_token == TOKEN_RESPONSE.get("access_token")
116+
assert auth_token2.refresh_token == TOKEN_RESPONSE.get("refresh_token")
117+
assert auth_token2.patient == TOKEN_RESPONSE.get("patient")
118+
assert auth_token2.expires_in == TOKEN_RESPONSE.get("expires_in")
119+
assert not auth_token2.access_token_expired()
120+
121+
# Test expired token
122+
token_dict = auth_token.get_dict()
123+
token_dict["expires_at"] = datetime.datetime.now(
124+
datetime.timezone.utc
125+
) - datetime.timedelta(seconds=10)
126+
auth_token2.set_dict(token_dict)
127+
assert auth_token2.access_token_expired() is True
128+
103129

104130
def test_refresh_access_token_without_refreshtoken():
105131
bb = BlueButton(BB2_CONFIG_V1)

0 commit comments

Comments
 (0)