Skip to content

Commit 5f6cc74

Browse files
vvgrem@gmail.comvvgrem@gmail.com
authored andcommitted
GraphClient: support for MSAL library introduced, Model type builder implementation
1 parent 0d5168b commit 5f6cc74

File tree

15 files changed

+123
-42
lines changed

15 files changed

+123
-42
lines changed

README.md

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,57 @@ the following clients are available:
112112

113113
#### Authentication
114114

115-
[ADAL Python](https://adal-python.readthedocs.io/en/latest/#)
116-
library is utilized to authenticate users to Active Directory (AD) and obtain tokens
115+
In terms of Microsoft Graph API authentication, there is no any dependency to any particular library implementation,
116+
the following libraries are supported at least:
117+
118+
> Note: access token is getting acquired via [Client Credential flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow)
119+
> in the provided examples
117120
121+
[Microsoft Authentication Library (MSAL) for Python](https://pypi.org/project/msal/)
122+
123+
```python
124+
import msal
125+
from office365.graph_client import GraphClient
126+
127+
def acquire_token():
128+
"""
129+
Acquire token via MSAL
130+
"""
131+
authority_url = 'https://login.microsoftonline.com/{tenant_id_or_name}'
132+
app = msal.ConfidentialClientApplication(
133+
authority=authority_url,
134+
client_id='{client_id}',
135+
client_credential='{client_secret}'
136+
)
137+
result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
138+
return result
139+
140+
141+
client = GraphClient(acquire_token)
142+
143+
```
144+
145+
146+
[ADAL Python](https://adal-python.readthedocs.io/en/latest/#)
147+
148+
Usage
149+
150+
```python
151+
import adal
152+
from office365.graph_client import GraphClient
153+
154+
def get_token():
155+
authority_url = 'https://login.microsoftonline.com/{tenant_id_or_name}'
156+
auth_ctx = adal.AuthenticationContext(authority_url)
157+
token = auth_ctx.acquire_token_with_client_credentials(
158+
"https://graph.microsoft.com",
159+
"{client_id}",
160+
"{client_secret}")
161+
return token
162+
163+
client = GraphClient(get_token)
164+
165+
```
118166

119167
#### Example
120168

@@ -123,17 +171,19 @@ The example demonstrates how to send an email via [Microsoft Graph endpoint](htt
123171
> Note: access token is getting acquired via [Client Credential flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow)
124172
125173
```python
174+
import adal
126175
from office365.graph_client import GraphClient
127-
def get_token(auth_ctx):
176+
177+
def get_token():
178+
authority_url = 'https://login.microsoftonline.com/{tenant_id_or_name}'
179+
auth_ctx = adal.AuthenticationContext(authority_url)
128180
token = auth_ctx.acquire_token_with_client_credentials(
129181
"https://graph.microsoft.com",
130182
"{client_id}",
131183
"{client_secret}")
132184
return token
133185

134-
135-
tenant_name = "{your-tenant-prefix}.onmicrosoft.com"
136-
client = GraphClient(tenant_name, get_token)
186+
client = GraphClient(get_token)
137187

138188
message_json = {
139189
"Message": {
@@ -191,7 +241,7 @@ def get_token(auth_ctx):
191241

192242

193243
tenant_name = "contoso.onmicrosoft.com"
194-
client = GraphClient(tenant_name, get_token)
244+
client = GraphClient(get_token)
195245
drives = client.drives
196246
client.load(drives)
197247
client.execute_query()
@@ -204,7 +254,7 @@ for drive in drives:
204254

205255
```python
206256
from office365.graph_client import GraphClient
207-
client = GraphClient("{tenant_name}", get_token)
257+
client = GraphClient(get_token)
208258
# retrieve drive properties
209259
drive = client.users["{user_id_or_principal_name}"].drive
210260
client.load(drive)

examples/directory/clear_directory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_token_for_user():
1616
return token
1717

1818

19-
client = GraphClient(settings['tenant'], get_token_for_user)
19+
client = GraphClient(get_token_for_user)
2020

2121
deleted_groups = client.directory.deletedGroups.get().execute_query()
2222
# deleted_users = client.directory.deletedUsers.get().execute_query()

examples/directory/import_users.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def generate_user_profile():
3636
return UserProfile(**user_json)
3737

3838

39-
client = GraphClient(settings['tenant'], acquire_token)
39+
client = GraphClient(acquire_token)
4040

4141
for idx in range(0, 5):
4242
user_profile = generate_user_profile()

examples/onedrive/export_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def download_files(remote_folder, local_path):
4141
# --------------------------------------------------------------------------
4242

4343
# connect
44-
client = GraphClient(settings['tenant'], get_token)
44+
client = GraphClient(get_token)
4545

4646
# load drive properties
4747
drive = client.users["jdoe@mediadev8.onmicrosoft.com"].drive

examples/onedrive/import_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def upload_files(remote_drive, local_root_path):
3737

3838

3939
# get target drive
40-
client = GraphClient(settings['tenant'], get_token)
40+
client = GraphClient(get_token)
4141
target_drive = client.users["jdoe@mediadev8.onmicrosoft.com"].drive
4242
# import local files into OneDrive
4343
upload_files(target_drive, "../data")

examples/onedrive/print_folders_and_files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ def enum_folders_and_files(root_folder):
3030
enum_folders_and_files(drive_item)
3131

3232

33-
client = GraphClient(settings['tenant'], get_token_for_user)
33+
client = GraphClient(get_token_for_user)
3434
root = client.me.drive.root
3535
enum_folders_and_files(root)

examples/outlook/send_message.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_token():
1616
return token
1717

1818

19-
client = GraphClient(settings['tenant'], get_token)
19+
client = GraphClient(get_token)
2020
message_json = {
2121
"Message": {
2222
"Subject": "Meet for lunch?",

examples/teams/connect_with_client_secret.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def acquire_token_msal():
1919
return result
2020

2121

22-
client = GraphClient(settings['tenant'], acquire_token_msal)
22+
client = GraphClient(acquire_token_msal)
2323
teams = client.teams.get_all().execute_query()
2424
for team in teams:
2525
print(team.id)

examples/teams/provision_team.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def print_failure(retry_number):
3232
print(f"{retry_number}: trying to create a team...")
3333

3434

35-
client = GraphClient(settings['tenant'], acquire_token)
35+
client = GraphClient(acquire_token)
3636

3737
group_name = "Team_" + uuid.uuid4().hex
3838
result = client.teams.create(group_name)

generator/builders/type_builder.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
import ast
2+
import os
3+
24

35
import astunparse
46

57

6-
class TypeBuilder(object):
8+
class TypeBuilder(ast.NodeTransformer):
79

8-
def __init__(self, schema):
9-
self._schema = schema
10-
self._node = None
10+
def __init__(self, options):
11+
self._schema = None
12+
self._options = options
13+
14+
def generic_visit(self, node):
15+
if isinstance(node, ast.ClassDef):
16+
node.name = self._schema["name"].title()
17+
ast.NodeVisitor.generic_visit(self, node)
1118

12-
def build(self, options):
13-
if self._schema['state'] == 'attached':
14-
with open(self._schema['file']) as f:
15-
self._node = ast.parse(f.read())
16-
return True
19+
def build(self, schema):
20+
result = dict(status=None, output_file=None, source_tree=None)
21+
if schema['state'] == 'attached':
22+
result.output_file = schema['file']
23+
with open(schema['file']) as f:
24+
result["source_tree"] = ast.parse(f.read())
25+
result["status"] = "updated"
1726
else:
18-
with open(options['complexTypeFile']) as f:
19-
self._node = ast.parse(f.read())
20-
return False
27+
template_file = self._resolve_template_file(schema['baseType'])
28+
result["output_file"] = os.path.join(self._options['outputPath'], schema["name"] + ".py")
29+
with open(template_file) as f:
30+
result["source_tree"] = ast.parse(f.read())
31+
result["status"] = "created"
32+
self._schema = schema
33+
self.visit(result["source_tree"])
34+
return result
2135

22-
def save(self):
23-
code = astunparse.unparse(self._node)
24-
with open(self._schema['file']) as f:
36+
def save(self, result):
37+
code = astunparse.unparse(result["source_tree"])
38+
with open(result["output_file"], 'w') as f:
2539
f.write(code)
40+
41+
def _resolve_template_file(self, type_name):
42+
file_mapping = {
43+
"ComplexType": "complex_type.py",
44+
"EntityType": "entity_type.py"
45+
}
46+
path = os.path.join(self._options['templatePath'], file_mapping[type_name])
47+
return path

0 commit comments

Comments
 (0)