Skip to content

Commit 4de9e92

Browse files
SharePoint API: sharing & permissions namespaces changes (RoleDefintion and RoleAssignment resources)
1 parent 23a8b90 commit 4de9e92

23 files changed

+286
-105
lines changed

generator/metadata/SharePoint.xml

+1-1
Large diffs are not rendered by default.

office365/graph/onedrive/driveItem.py

+13-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from functools import partial
21
from office365.graph.directory.permission_collection import PermissionCollection
32
from office365.graph.onedrive.folder import Folder
43
from office365.graph.onedrive.conflictBehavior import ConflictBehavior
@@ -13,10 +12,6 @@
1312
from office365.runtime.queries.serviceOperationQuery import ServiceOperationQuery
1413

1514

16-
def _content_downloaded(file_object, result):
17-
file_object.write(result.value)
18-
19-
2015
class DriveItem(BaseItem):
2116
"""The driveItem resource represents a file, folder, or other item stored in a drive. All file system objects in
2217
OneDrive and SharePoint are returned as driveItem resources """
@@ -61,8 +56,11 @@ def get_content(self):
6156
return qry.return_type
6257

6358
def download(self, file_object):
59+
def _content_downloaded(result):
60+
file_object.write(result.value)
61+
6462
self.get_content()
65-
self.context.afterExecuteOnce += partial(_content_downloaded, file_object)
63+
self.context.after_query_executed(_content_downloaded)
6664

6765
def create_folder(self, name):
6866
"""Create a new folder or DriveItem in a Drive with a specified parent item or path.
@@ -151,20 +149,15 @@ def invite(self, recipients, message, require_sign_in=True, send_invitation=True
151149
"""Sends a sharing invitation for a driveItem. A sharing invitation provides permissions to the recipients
152150
and optionally sends them an email with a sharing link.
153151
154-
:param recipients: A collection of recipients who will receive access and the sharing invitation.
155-
:type recipients: list[DriveRecipient]
156-
157-
:param message: A plain text formatted message that is included in the sharing invitation. Maximum length 2000 characters.
158-
:type message: str
159-
160-
:param require_sign_in: Specifies whether the recipient of the invitation is required to sign-in to view the shared item.
161-
:type require_sign_in: bool
162-
163-
:param send_invitation: If true, a sharing link is sent to the recipient. Otherwise, a permission is granted directly without sending a notification.
164-
:type send_invitation: bool
165-
166-
:param roles: Specify the roles that are to be granted to the recipients of the sharing invitation.
167-
:type roles: list[str]
152+
:param list[DriveRecipient] recipients: A collection of recipients who will receive access and the sharing
153+
invitation.
154+
:param str message: A plain text formatted message that is included in the sharing invitation.
155+
Maximum length 2000 characters.
156+
:param bool require_sign_in: Specifies whether the recipient of the invitation is required to sign-in to view
157+
the shared item.
158+
:param bool send_invitation: If true, a sharing link is sent to the recipient. Otherwise, a permission is
159+
granted directly without sending a notification.
160+
:param list[str] roles: Specify the roles that are to be granted to the recipients of the sharing invitation.
168161
"""
169162
if roles is None:
170163
roles = ["read"]

office365/runtime/client_object.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def ensure_property(self, name_or_names, action):
7979
"""
8080
Ensures if property is loaded or list of properties are loaded
8181
82-
:type action: any
82+
:type action: (any) -> None
8383
:type name_or_names: str or list[str]
8484
"""
8585
names_to_include = []
@@ -91,7 +91,7 @@ def ensure_property(self, name_or_names, action):
9191

9292
if len(names_to_include) > 0:
9393
self.context.load(self, names_to_include)
94-
self.context.afterExecuteOnce += action
94+
self.context.after_query_executed(action)
9595
else:
9696
action(self)
9797

office365/runtime/client_object_collection.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,12 @@ def get_items_count(self):
103103
:return: ClientResult
104104
"""
105105
result = ClientResult(None)
106-
self.context.load(self)
107106

108107
def _calc_items_count(target_collection):
109108
list(iter(target_collection))
110109
result.value = len(target_collection)
111-
self.context.afterExecuteOnce += _calc_items_count
110+
self.context.load(self)
111+
self.context.after_query_executed(_calc_items_count)
112112
return result
113113

114114
def _load_paged_items(self):

office365/runtime/client_request.py

+31-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from office365.runtime.client_request_exception import ClientRequestException
55
from office365.runtime.http.http_method import HttpMethod
66
from office365.runtime.types.EventHandler import EventHandler
7+
from office365.runtime.client_query import ClientQuery
8+
from office365.runtime.http.request_options import RequestOptions
79

810

911
class ClientRequest(object):
@@ -16,13 +18,42 @@ def __init__(self, context):
1618
"""
1719
self.context = context
1820
self._queries = []
21+
self._current_query = None
1922
self.beforeExecute = EventHandler()
2023
self.afterExecute = EventHandler()
2124

2225
@property
2326
def queries(self):
27+
"""
28+
:rtype: list[ClientQuery]
29+
"""
2430
return self._queries
2531

32+
@property
33+
def current_query(self):
34+
"""
35+
:rtype: ClientQuery or None
36+
"""
37+
if self._current_query is None and len(self._queries) > 0:
38+
self.next_query()
39+
return self._current_query
40+
41+
@property
42+
def last_query(self):
43+
"""
44+
:rtype: ClientQuery or None
45+
"""
46+
return self._queries and self._queries[-1]
47+
48+
def next_query(self):
49+
self._current_query = self._queries and self._queries.pop(0)
50+
51+
def add_query(self, query):
52+
"""
53+
:type query: ClientQuery
54+
"""
55+
self._queries.append(query)
56+
2657
@abstractmethod
2758
def build_request(self):
2859
pass
@@ -87,10 +118,3 @@ def execute_request_direct(self, request_options):
87118
stream=request_options.stream,
88119
proxies=request_options.proxies)
89120
return result
90-
91-
def add_query(self, query):
92-
"""
93-
:type query: ClientQuery
94-
95-
"""
96-
self._queries.append(query)

office365/runtime/client_runtime_context.py

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import abc
2-
2+
from functools import partial
33
from office365.runtime.client_query import ReadEntityQuery
4-
from office365.runtime.types.EventHandler import EventHandler
54

65

76
class ClientRuntimeContext(object):
@@ -15,12 +14,11 @@ def __init__(self, service_root_url, auth_context=None):
1514
"""
1615
self._service_root_url = service_root_url
1716
self._auth_context = auth_context
18-
self.afterExecuteOnce = EventHandler(True)
1917

2018
@abc.abstractmethod
2119
def get_pending_request(self):
2220
"""
23-
:rtype: ClientRequest
21+
:rtype: office365.runtime.client_request.ClientRequest
2422
"""
2523
pass
2624

@@ -40,18 +38,27 @@ def load(self, client_object, properties_to_retrieve=None):
4038
qry = ReadEntityQuery(client_object, properties_to_retrieve)
4139
self.get_pending_request().add_query(qry)
4240

43-
def execute_request_direct(self, request):
41+
def after_query_executed(self, action):
4442
"""
43+
:param (office365.runtime.client_object.ClientObject or office365.runtime.client_result.ClientResult) -> None action:
44+
"""
45+
46+
def _process_response(qry, response):
47+
current_qry = self.get_pending_request().current_query
48+
if current_qry.id == qry.id:
49+
action(qry.return_type)
50+
self.get_pending_request().afterExecute += partial(_process_response, self.get_pending_request().last_query)
4551

52+
def execute_request_direct(self, request):
53+
"""
4654
:type request: RequestOptions
4755
"""
4856
return self.get_pending_request().execute_request_direct(request)
4957

5058
def execute_query(self):
5159
while self.has_pending_request:
60+
self.get_pending_request().next_query()
5261
self.get_pending_request().execute_query()
53-
query = self.get_pending_request().current_query
54-
self.afterExecuteOnce.notify(query.return_type)
5562

5663
def add_query(self, query):
5764
"""
@@ -60,9 +67,6 @@ def add_query(self, query):
6067
"""
6168
self.get_pending_request().add_query(query)
6269

63-
def add_query_first(self, query):
64-
self.get_pending_request().queries.insert(0, query)
65-
6670
def clear_queries(self):
6771
self.get_pending_request().queries.clear()
6872

office365/runtime/odata/odata_request.py

+5-14
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ def __init__(self, context, json_format):
2222
"""
2323
super(ODataRequest, self).__init__(context)
2424
self._json_format = json_format
25-
self._current_query = None
25+
26+
@property
27+
def json_format(self):
28+
return self._json_format
2629

2730
def execute_request_direct(self, request):
2831
"""
@@ -36,20 +39,8 @@ def execute_request_direct(self, request):
3639
request.ensure_header('Accept', media_type)
3740
return super(ODataRequest, self).execute_request_direct(request)
3841

39-
@property
40-
def current_query(self):
41-
return self._current_query
42-
43-
@property
44-
def json_format(self):
45-
return self._json_format
46-
47-
def _get_next_query(self):
48-
self._current_query = self._queries.pop(0)
49-
return self._current_query
50-
5142
def build_request(self):
52-
qry = self._get_next_query()
43+
qry = self.current_query
5344
self.json_format.function_tag_name = None
5445

5546
if isinstance(qry, ServiceOperationQuery):

office365/sharepoint/actions/create_file.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
class CreateFileQuery(ServiceOperationQuery):
66

7-
def __init__(self, container, file_creation_information):
7+
def __init__(self, files, file_creation_information):
88
"""
99
1010
:type file_creation_information: office365.sharepoint.file_creation_information.FileCreationInformation
11-
:type container: FileCollection
11+
:type files: FileCollection
1212
"""
13-
self._return_type = File(container.context)
14-
super().__init__(container, "add", {
13+
self._return_type = File(files.context)
14+
super().__init__(files, "add", {
1515
"overwrite": file_creation_information.overwrite,
1616
"url": file_creation_information.url
1717
}, file_creation_information.content, None, self._return_type)
18-
container.add_child(self._return_type)
18+
files.add_child(self._return_type)
+16-19
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import os
22
import uuid
3-
43
from office365.runtime.client_result import ClientResult
4+
from office365.sharepoint.actions.create_file import CreateFileQuery
55
from office365.sharepoint.files.file import File
66
from office365.sharepoint.files.file_creation_information import FileCreationInformation
7-
from office365.sharepoint.actions.create_file import CreateFileQuery
87

98

109
def read_in_chunks(file_object, size=1024):
@@ -25,56 +24,54 @@ def _create_empty_file(path):
2524

2625

2726
class UploadSessionQuery(CreateFileQuery):
28-
def __init__(self, container, source_path, chunk_size, chunk_uploaded):
27+
def __init__(self, files, source_path, chunk_size, chunk_uploaded):
2928
"""
3029
31-
:type container: office365.sharepoint.file_collection.FileCollection
30+
:type files: office365.sharepoint.files.file_collection.FileCollection
3231
:type source_path: str
3332
:type chunk_size: int
3433
:type chunk_uploaded: (int)->None
3534
"""
3635

37-
super().__init__(container, _create_empty_file(source_path))
36+
super().__init__(files, _create_empty_file(source_path))
3837
self._chunk_size = chunk_size
3938
self._upload_id = str(uuid.uuid4())
4039
self._source_path = source_path
4140
self._chunk_uploaded = chunk_uploaded
4241
self._uploaded_bytes = 0
4342
self._upload_results = []
44-
container.context.afterExecuteOnce += self._build_upload_query
45-
46-
def _build_upload_query(self, target_file):
47-
"""
43+
self._binding_type.context.get_pending_request().afterExecute += self._build_upload_session_query
4844

49-
:type target_file: File
50-
"""
45+
def _build_upload_session_query(self, response):
46+
self._binding_type.context.get_pending_request().afterExecute -= self._build_upload_session_query
5147
st = os.stat(self._source_path)
52-
5348
# upload a file in chunks
5449
f_pos = 0
5550
fh = open(self._source_path, 'rb')
5651
for piece in read_in_chunks(fh, size=self._chunk_size):
5752
if f_pos == 0:
58-
upload_result = target_file.start_upload(self._upload_id, piece)
53+
upload_result = self.file.start_upload(self._upload_id, piece)
5954
self._upload_results.append(upload_result)
6055
elif f_pos + len(piece) < st.st_size:
61-
upload_result = target_file.continue_upload(self._upload_id, f_pos, piece)
56+
upload_result = self.file.continue_upload(self._upload_id, f_pos, piece)
6257
self._upload_results.append(upload_result)
6358
else:
64-
self._return_type = target_file.finish_upload(self._upload_id, f_pos, piece)
59+
self._return_type = self.file.finish_upload(self._upload_id, f_pos, piece)
6560
f_pos += len(piece)
61+
if self._chunk_uploaded is not None:
62+
self._binding_type.context.after_query_executed(self._process_chunk_upload)
6663
fh.close()
67-
if self._chunk_uploaded is not None:
68-
self._binding_type.context.afterExecuteOnce += self._process_chunk_upload
6964

7065
def _process_chunk_upload(self, result_object):
71-
self._binding_type.context.afterExecuteOnce += self._process_chunk_upload
7266
if isinstance(result_object, ClientResult):
7367
self._uploaded_bytes = int(result_object.value)
7468
elif isinstance(result_object, File):
75-
self._uploaded_bytes = int(result_object.properties['Length'])
69+
self._uploaded_bytes = result_object.length
7670
self._chunk_uploaded(self._uploaded_bytes)
7771

7872
@property
7973
def file(self):
74+
"""
75+
:rtype: File
76+
"""
8077
return self.return_type

office365/sharepoint/client_context.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ def from_url(abs_url):
5656
Web.get_web_url_from_page_url(ctx, abs_url)
5757

5858
def _init_context_for_web(result):
59+
"""
60+
:param office365.runtime.client_result.ClientResult result:
61+
"""
5962
ctx._base_url = result.value
60-
61-
ctx.afterExecuteOnce += _init_context_for_web
63+
ctx.after_query_executed(_init_context_for_web)
6264
return ctx
6365

6466
@staticmethod
@@ -103,7 +105,7 @@ def acquire_token():
103105

104106
def with_credentials(self, credentials):
105107
"""
106-
Sets credentials
108+
Assigns credentials
107109
108110
:type credentials: UserCredential or ClientCredential
109111
"""
@@ -117,6 +119,9 @@ def authenticate_request(self, request):
117119
super(ClientContext, self).authenticate_request(request)
118120

119121
def get_pending_request(self):
122+
"""
123+
:return: ODataRequest
124+
"""
120125
return self._pendingRequest
121126

122127
def ensure_form_digest(self, request_options):

0 commit comments

Comments
 (0)