Skip to content

Commit e5483db

Browse files
committed
Lots of cleanup and add more workbook endpoints.
1 parent 22cc46b commit e5483db

20 files changed

+1534
-692
lines changed

ms_graph/_workbooks.py

Lines changed: 0 additions & 33 deletions
This file was deleted.

ms_graph/client.py

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
from ms_graph.personal_contacts import PersonalContacts
2121
from ms_graph.mail import Mail
2222

23+
from ms_graph.workbooks_and_charts.workbook import Workbooks
2324

24-
class MicrosoftGraphClient():
25+
26+
class MicrosoftGraphClient:
2527

2628
"""
2729
### Overview:
@@ -30,25 +32,25 @@ class MicrosoftGraphClient():
3032
API Service.
3133
"""
3234

33-
RESOURCE = 'https://graph.microsoft.com/'
35+
RESOURCE = "https://graph.microsoft.com/"
3436

35-
AUTHORITY_URL = 'https://login.microsoftonline.com/'
36-
AUTH_ENDPOINT = '/oauth2/v2.0/authorize?'
37-
TOKEN_ENDPOINT = '/oauth2/v2.0/token'
37+
AUTHORITY_URL = "https://login.microsoftonline.com/"
38+
AUTH_ENDPOINT = "/oauth2/v2.0/authorize?"
39+
TOKEN_ENDPOINT = "/oauth2/v2.0/token"
3840

39-
OFFICE365_AUTHORITY_URL = 'https://login.live.com'
40-
OFFICE365_AUTH_ENDPOINT = '/oauth20_authorize.srf?'
41-
OFFICE365_TOKEN_ENDPOINT = '/oauth20_token.srf'
41+
OFFICE365_AUTHORITY_URL = "https://login.live.com"
42+
OFFICE365_AUTH_ENDPOINT = "/oauth20_authorize.srf?"
43+
OFFICE365_TOKEN_ENDPOINT = "/oauth20_token.srf"
4244

4345
def __init__(
4446
self,
4547
client_id: str,
4648
client_secret: str,
4749
redirect_uri: str,
4850
scope: List[str],
49-
account_type: str = 'consumers',
51+
account_type: str = "consumers",
5052
office365: bool = False,
51-
credentials: str = None
53+
credentials: str = None,
5254
):
5355
"""Initializes the Graph Client.
5456
@@ -71,7 +73,7 @@ def __init__(
7173
to have access to.
7274
7375
account_type : str, optional
74-
[description], by default 'common'
76+
[description], by default "common"
7577
7678
office365 : bool, optional
7779
[description], by default False
@@ -85,19 +87,19 @@ def __init__(
8587

8688
self.client_id = client_id
8789
self.client_secret = client_secret
88-
self.api_version = 'v1.0'
90+
self.api_version = "v1.0"
8991
self.account_type = account_type
9092
self.redirect_uri = redirect_uri
9193

9294
self.scope = scope
93-
self.state = ''.join(random.choice(letters) for i in range(10))
95+
self.state = "".join(random.choice(letters) for i in range(10))
9496

9597
self.access_token = None
9698
self.refresh_token = None
9799
self.graph_session = None
98100
self.id_token = None
99101

100-
self.base_url = self.RESOURCE + self.api_version + '/'
102+
self.base_url = self.RESOURCE + self.api_version + "/"
101103
self.office_url = self.OFFICE365_AUTHORITY_URL + self.OFFICE365_AUTH_ENDPOINT
102104
self.graph_url = self.AUTHORITY_URL + self.account_type + self.AUTH_ENDPOINT
103105
self.office365 = office365
@@ -107,7 +109,7 @@ def __init__(
107109
self.client_app = msal.ConfidentialClientApplication(
108110
client_id=self.client_id,
109111
authority=self.AUTHORITY_URL + self.account_type,
110-
client_credential=self.client_secret
112+
client_credential=self.client_secret,
111113
)
112114

113115
def _state(self, action: str, token_dict: dict = None) -> bool:
@@ -134,18 +136,18 @@ def _state(self, action: str, token_dict: dict = None) -> bool:
134136
does_exists = pathlib.Path(self.credentials).exists()
135137

136138
# If it exists and we are loading it then proceed.
137-
if does_exists and action == 'load':
139+
if does_exists and action == "load":
138140

139141
# Load the file.
140-
with open(file=self.credentials, mode='r', encoding='utf-8') as state_file:
142+
with open(file=self.credentials, mode="r", encoding="utf-8") as state_file:
141143
credentials = json.load(fp=state_file)
142144

143145
# Grab the Token if it exists.
144-
if 'refresh_token' in credentials:
146+
if "refresh_token" in credentials:
145147

146-
self.refresh_token = credentials['refresh_token']
147-
self.access_token = credentials['access_token']
148-
self.id_token = credentials['id_token']
148+
self.refresh_token = credentials["refresh_token"]
149+
self.access_token = credentials["access_token"]
150+
self.id_token = credentials["id_token"]
149151
self.token_dict = credentials
150152

151153
return True
@@ -154,22 +156,22 @@ def _state(self, action: str, token_dict: dict = None) -> bool:
154156
return False
155157

156158
# If we are saving the state then open the file and dump the dictionary.
157-
elif action == 'save':
159+
elif action == "save":
158160

159-
token_dict['expires_in'] = time.time(
160-
) + int(token_dict['expires_in'])
161-
token_dict['ext_expires_in'] = time.time(
162-
) + int(token_dict['ext_expires_in'])
161+
token_dict["expires_in"] = time.time() + int(token_dict["expires_in"])
162+
token_dict["ext_expires_in"] = time.time() + int(
163+
token_dict["ext_expires_in"]
164+
)
163165

164-
self.refresh_token = token_dict['refresh_token']
165-
self.access_token = token_dict['access_token']
166-
self.id_token = token_dict['id_token']
166+
self.refresh_token = token_dict["refresh_token"]
167+
self.access_token = token_dict["access_token"]
168+
self.id_token = token_dict["id_token"]
167169
self.token_dict = token_dict
168170

169-
with open(file=self.credentials, mode='w+', encoding='utf-8') as state_file:
171+
with open(file=self.credentials, mode="w+", encoding="utf-8") as state_file:
170172
json.dump(obj=token_dict, fp=state_file, indent=2)
171173

172-
def _token_seconds(self, token_type: str = 'access_token') -> int:
174+
def _token_seconds(self, token_type: str = "access_token") -> int:
173175
"""Determines time till expiration for a token.
174176
175177
Return the number of seconds until the current access token or refresh token
@@ -179,34 +181,36 @@ def _token_seconds(self, token_type: str = 'access_token') -> int:
179181
### Arguments:
180182
----
181183
token_type {str} -- The type of token you would like to determine lifespan for.
182-
Possible values are ['access_token', 'refresh_token'] (default: {access_token})
184+
Possible values are ["access_token", "refresh_token"] (default: {access_token})
183185
184186
### Returns:
185187
----
186188
{int} -- The number of seconds till expiration.
187189
"""
188190

189191
# if needed check the access token.
190-
if token_type == 'access_token':
192+
if token_type == "access_token":
191193

192194
# if the time to expiration is less than or equal to 0, return 0.
193-
if not self.access_token or (time.time() + 60 >= self.token_dict['expires_in']):
195+
if not self.access_token or (
196+
time.time() + 60 >= self.token_dict["expires_in"]
197+
):
194198
return 0
195199

196200
# else return the number of seconds until expiration.
197-
token_exp = int(self.token_dict['expires_in'] - time.time() - 60)
201+
token_exp = int(self.token_dict["expires_in"] - time.time() - 60)
198202

199203
# if needed check the refresh token.
200-
elif token_type == 'refresh_token':
204+
elif token_type == "refresh_token":
201205

202206
# if the time to expiration is less than or equal to 0, return 0.
203-
if not self.refresh_token or (time.time() + 60 >= self.token_dict['ext_expires_in']):
207+
if not self.refresh_token or (
208+
time.time() + 60 >= self.token_dict["ext_expires_in"]
209+
):
204210
return 0
205211

206212
# else return the number of seconds until expiration.
207-
token_exp = int(
208-
self.token_dict['ext_expires_in'] - time.time() - 60
209-
)
213+
token_exp = int(self.token_dict["ext_expires_in"] - time.time() - 60)
210214

211215
return token_exp
212216

@@ -223,7 +227,7 @@ def _token_validation(self, nseconds: int = 60):
223227
valid for before attempting to get a refresh token. (default: {5})
224228
"""
225229

226-
if self._token_seconds(token_type='access_token') < nseconds:
230+
if self._token_seconds(token_type="access_token") < nseconds:
227231
self.grab_refresh_token()
228232

229233
def _silent_sso(self) -> bool:
@@ -236,21 +240,21 @@ def _silent_sso(self) -> bool:
236240
"""
237241

238242
# if the current access token is not expired then we are still authenticated.
239-
if self._token_seconds(token_type='access_token') > 0:
243+
if self._token_seconds(token_type="access_token") > 0:
240244
return True
241245

242246
# if the current access token is expired then try and refresh access token.
243247
elif self.refresh_token and self.grab_refresh_token():
244248
return True
245249

246-
# More than likely a first time login, so can't do silent authenticaiton.
250+
# More than likely a first time login, so can"t do silent authenticaiton.
247251
return False
248252

249253
def login(self) -> None:
250254
"""Logs the user into the session."""
251255

252256
# Load the State.
253-
self._state(action='load')
257+
self._state(action="load")
254258

255259
# Try a Silent SSO First.
256260
if self._silent_sso():
@@ -267,11 +271,11 @@ def login(self) -> None:
267271

268272
# aks the user to go to the URL provided, they will be prompted
269273
# to authenticate themsevles.
270-
print(f'Please go to URL provided authorize your account: {url}')
274+
print(f"Please go to URL provided authorize your account: {url}")
271275

272276
# ask the user to take the final URL after authentication and
273277
# paste here so we can parse.
274-
my_response = input('Paste the full URL redirect here: ')
278+
my_response = input("Paste the full URL redirect here: ")
275279

276280
# store the redirect URL
277281
self._redirect_code = my_response
@@ -292,9 +296,7 @@ def authorization_url(self):
292296

293297
# Build the Auth URL.
294298
auth_url = self.client_app.get_authorization_request_url(
295-
scopes=self.scope,
296-
state=self.state,
297-
redirect_uri=self.redirect_uri
299+
scopes=self.scope, state=self.state, redirect_uri=self.redirect_uri
298300
)
299301

300302
return auth_url
@@ -315,16 +317,11 @@ def grab_access_token(self) -> Dict:
315317

316318
# Grab the Token.
317319
token_dict = self.client_app.acquire_token_by_authorization_code(
318-
code=code,
319-
scopes=self.scope,
320-
redirect_uri=self.redirect_uri
320+
code=code, scopes=self.scope, redirect_uri=self.redirect_uri
321321
)
322322

323323
# Save the token dict.
324-
self._state(
325-
action='save',
326-
token_dict=token_dict
327-
)
324+
self._state(action="save", token_dict=token_dict)
328325

329326
return token_dict
330327

@@ -339,19 +336,17 @@ def grab_refresh_token(self) -> Dict:
339336

340337
# Grab a new token using our refresh token.
341338
token_dict = self.client_app.acquire_token_by_refresh_token(
342-
refresh_token=self.refresh_token,
343-
scopes=self.scope
339+
refresh_token=self.refresh_token, scopes=self.scope
344340
)
345341

346-
if 'error' in token_dict:
342+
if "error" in token_dict:
347343
print(token_dict)
348-
raise PermissionError("Permissions not authorized, delete json file and run again.")
344+
raise PermissionError(
345+
"Permissions not authorized, delete json file and run again."
346+
)
349347

350348
# Save the Token.
351-
self._state(
352-
action='save',
353-
token_dict=token_dict
354-
)
349+
self._state(action="save", token_dict=token_dict)
355350

356351
return token_dict
357352

@@ -449,7 +444,9 @@ def personal_contacts(self) -> PersonalContacts:
449444
"""
450445

451446
# Grab the `PersonalContacts` Object for the session.
452-
personal_contacts_object: PersonalContacts = PersonalContacts(session=self.graph_session)
447+
personal_contacts_object: PersonalContacts = PersonalContacts(
448+
session=self.graph_session
449+
)
453450

454451
return personal_contacts_object
455452

@@ -466,3 +463,17 @@ def mail(self) -> Mail:
466463
mail_service: Mail = Mail(session=self.graph_session)
467464

468465
return mail_service
466+
467+
def workbooks(self) -> Workbooks:
468+
"""Used to access the Workbooks Services and metadata.
469+
470+
### Returns
471+
---
472+
Workbooks:
473+
The `Workbooks` services Object.
474+
"""
475+
476+
# Grab the `Workbooks` Object for the session.
477+
workbook_service: Workbooks = Workbooks(session=self.graph_session)
478+
479+
return workbook_service

0 commit comments

Comments
 (0)