Skip to content

Commit ee9e616

Browse files
committed
SharePoint API: folders namespace enhancements
1 parent 8a0b3b7 commit ee9e616

File tree

8 files changed

+141
-132
lines changed

8 files changed

+141
-132
lines changed

examples/outlook/messages/download.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from tests.graph_case import acquire_token_by_username_password
1414

1515
client = GraphClient(acquire_token_by_username_password)
16-
messages = client.me.messages.select(["id"]).top(2).get().execute_query()
16+
messages = client.me.messages.select(["id", "subject"]).top(2).get().execute_query()
1717
with tempfile.TemporaryDirectory() as local_path:
1818
for message in messages: # type: Message
1919
with open(os.path.join(local_path, message.id + ".eml"), 'wb') as local_file:

examples/sharepoint/folders/copy_folder.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
ctx = ClientContext(test_team_site_url).with_credentials(test_user_credentials)
88

99
# creates a temporary folder first in a Documents library
10-
folder_name = create_unique_name("New folder")
11-
folder_from = ctx.web.default_document_library().root_folder.add(folder_name)
10+
folder_from = ctx.web.default_document_library().root_folder.add(create_unique_name("from"))
11+
folder_to = ctx.web.default_document_library().root_folder.add(create_unique_name("to"))
1212

1313
# copies the folder with a new name
14-
new_folder_name = create_unique_name("Copied folder")
15-
folder_to = folder_from.copy_to(new_folder_name).execute_query()
16-
print("Folder has been copied from '{0}' into '{1}'".format(folder_from.serverRelativeUrl, folder_to.serverRelativeUrl))
14+
folder = folder_from.copy_to_using_path(folder_to).execute_query()
15+
print("Folder has been copied from '{0}' into '{1}'".format(folder_from.serverRelativeUrl, folder.serverRelativeUrl))
1716

1817
# clean up
1918
folder_from.delete_object().execute_query()

examples/sharepoint/folders/move.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66

77
ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
88

9-
folder_name = create_unique_name("New folder")
10-
print("Creating a temporary folder in a Documents library ...")
11-
folder_from = ctx.web.default_document_library().root_folder.add(folder_name).execute_query()
12-
print("Folder '{0}' has been created".format(folder_from.serverRelativeUrl))
139

14-
new_folder_name = create_unique_name("Moved folder")
10+
print("Creating a temporary folders in a Documents library ...")
11+
folder_from = ctx.web.default_document_library().root_folder.add(create_unique_name("in"))
12+
folder_to_parent = ctx.web.default_document_library().root_folder.add(create_unique_name("out"))
13+
# folder_to_url = "Shared Documents/archive"
14+
1515
print("Moving folder...")
16-
folder_to = folder_from.move_to(new_folder_name).execute_query()
17-
print("Folder has been moved from '{0}' into '{1}'".format(folder_from.serverRelativeUrl, folder_to.serverRelativeUrl))
16+
folder_to = folder_from.move_to_using_path(folder_to_parent).execute_query()
17+
print("Folder has been moved into '{0}'".format(folder_to.serverRelativeUrl))
1818

1919
print("Cleaning up temporary folders ...")
20-
folder_from.delete_object().execute_query()
21-
folder_to.delete_object().execute_query()
20+
folder_to_parent.delete_object().execute_query()
2221
print("Done")

office365/outlook/mail/messages/message.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,12 @@ def download(self, file_object):
3939
4040
:type file_object: typing.IO
4141
"""
42-
result = self.get_content()
43-
44-
def _content_downloaded(resp):
42+
def _save_content(return_type):
4543
"""
46-
:type resp: requests.Response
44+
:type return_type: ClientResult
4745
"""
48-
resp.raise_for_status()
49-
file_object.write(result.value)
50-
51-
self.context.after_execute(_content_downloaded)
46+
file_object.write(return_type.value)
47+
self.get_content().after_execute(_save_content)
5248
return self
5349

5450
def get_content(self):

office365/runtime/queries/update_entity.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33

44
class UpdateEntityQuery(ClientQuery):
5-
def __init__(self, entity_to_update):
5+
def __init__(self, update_type):
66
"""
77
Update client object query
88
9-
:type entity_to_update: office365.runtime.client_object.ClientObject
9+
:type update_type: office365.runtime.client_object.ClientObject
1010
"""
11-
super(UpdateEntityQuery, self).__init__(entity_to_update.context, entity_to_update, entity_to_update)
11+
super(UpdateEntityQuery, self).__init__(update_type.context, update_type, update_type)

office365/sharepoint/files/file.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -366,15 +366,16 @@ def publish(self, comment):
366366
return self
367367

368368
def unpublish(self, comment):
369-
"""Removes the file from content approval or unpublish a major version.
369+
"""Removes the file from content approval or unpublishes a major version.
370370
371-
:type comment: str
371+
:param str comment: Specifies the comment for UnPublish. Its length MUST be equal to or less than 1023.
372372
"""
373373
qry = ServiceOperationQuery(self, "unpublish", {"comment": comment})
374374
self.context.add_query(qry)
375375
return self
376376

377377
def check_access_and_post_view_audit_event(self):
378+
""""""
378379
return_type = ClientResult(self.context, bool())
379380
qry = ServiceOperationQuery(self, "CheckAccessAndPostViewAuditEvent", return_type=return_type)
380381
self.context.add_query(qry)
@@ -396,13 +397,11 @@ def checkin(self, comment, checkin_type):
396397
https://docs.microsoft.com/en-us/previous-versions/office/sharepoint-csom/ee542953(v%3Doffice.15)
397398
:param int checkin_type: Specifies the type of check-in.
398399
"""
399-
qry = ServiceOperationQuery(self,
400-
"checkin",
401-
{
402-
"comment": comment,
403-
"checkInType": checkin_type
404-
}
405-
)
400+
params = {
401+
"comment": comment,
402+
"checkInType": checkin_type
403+
}
404+
qry = ServiceOperationQuery(self, "checkin", params)
406405
self.context.add_query(qry)
407406
return self
408407

office365/sharepoint/folders/folder.py

Lines changed: 91 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -56,57 +56,82 @@ def get_sharing_information(self):
5656
"""Gets the sharing information for a folder."""
5757
return self.list_item_all_fields.get_sharing_information()
5858

59-
def move_to(self, new_url, parent_folder=None):
59+
def move_to(self, destination):
6060
"""
61-
Moves the folder and its contents to a new folder at the specified URL.
61+
Moves the folder and its contents under a new folder at the specified destination.
6262
This method applies only to the context of a single site.
6363
6464
An exception is thrown if a folder with the same name as specified in the parameter already exists.
6565
66-
:param str new_url: A string that specifies the URL for the new folder.
67-
:param Folder or None parent_folder: The existing parent folder where to move folder
66+
:param str or Folder destination: Specifies the server relative url or an existing folder
67+
where to move a folder.
6868
"""
69-
if parent_folder is None:
70-
parent_folder = self.parent_folder
7169

72-
return_type = Folder(self.context)
70+
def _update_folder(url):
71+
self.set_property("ServerRelativeUrl", url)
7372

74-
def _parent_folder_resolved():
75-
new_path = SPResPath.create_relative(parent_folder.serverRelativeUrl, new_url)
76-
return_type.set_property("ServerRelativeUrl", str(new_path))
77-
qry = ServiceOperationQuery(self, "MoveTo", {"newUrl": str(new_path)})
78-
self.context.add_query(qry)
73+
def _move_to(destination_folder):
74+
"""
75+
:type destination_folder: Folder
76+
"""
77+
destination_url = "/".join([destination_folder.serverRelativeUrl, self.name])
78+
qry = ServiceOperationQuery(self, "MoveTo", {"newUrl": destination_url})
79+
self.context.add_query(qry).after_query_execute(_update_folder, destination_url)
7980

80-
parent_folder.ensure_property("ServerRelativeUrl", _parent_folder_resolved)
81-
return return_type
81+
def _source_folder_resolved():
82+
if isinstance(destination, Folder):
83+
destination.ensure_property("ServerRelativeUrl", _move_to, destination)
84+
else:
85+
self.context.web.ensure_folder_path(destination).after_execute(_move_to)
86+
87+
self.ensure_properties(["ServerRelativeUrl", "Name"], _source_folder_resolved)
88+
return self
89+
90+
def move_to_using_path(self, destination):
91+
"""
92+
Moves the folder and its contents to a new folder at the specified path.
93+
An exception is thrown if a folder with the same name as specified in the parameter already exists.
94+
95+
:param str or Folder destination: Specifies the server relative url or an existing folder
96+
where to move a folder.
97+
"""
98+
99+
def _update_folder(url):
100+
self.set_property("ServerRelativePath", url)
101+
102+
def _move_to_using_path(destination_folder):
103+
"""
104+
:type destination_folder: Folder
105+
"""
106+
destination_url = "/".join([str(destination_folder.server_relative_path), self.name])
107+
qry = ServiceOperationQuery(self, "MoveToUsingPath", {"DecodedUrl": destination_url})
108+
self.context.add_query(qry).after_query_execute(_update_folder, destination_url)
82109

83-
def move_to_with_parameters(self, new_relative_url, retain_editor_and_modified=False):
84-
"""Moves the folder with files to the destination URL.
110+
def _source_folder_resolved():
111+
if isinstance(destination, Folder):
112+
destination.ensure_property("ServerRelativePath", _move_to_using_path, destination)
113+
else:
114+
self.context.web.ensure_folder_path(destination).after_execute(_move_to_using_path)
115+
116+
self.ensure_properties(["ServerRelativePath", "Name"], _source_folder_resolved)
117+
return self
118+
119+
def move_to_using_path_with_parameters(self, new_relative_path, retain_editor_and_modified=False):
120+
"""Moves the folder with files to the destination Path.
85121
86-
:type new_relative_url: str
87-
:type retain_editor_and_modified: bool
122+
:param str new_relative_path: A full URL path that represents the destination folder.
123+
:param bool retain_editor_and_modified:
88124
"""
89125
return_type = Folder(self.context)
90-
return_type.set_property("ServerRelativeUrl", new_relative_url)
126+
return_type.set_property("ServerRelativePath", SPResPath(new_relative_path))
91127

92128
def _move_folder():
93129
opt = MoveCopyOptions(retain_editor_and_modified_on_move=retain_editor_and_modified)
94-
MoveCopyUtil.move_folder(self.context, self.serverRelativeUrl, new_relative_url, opt)
130+
MoveCopyUtil.move_folder_by_path(self.context, self.server_relative_path.DecodedUrl, new_relative_path, opt)
95131

96-
self.ensure_property("ServerRelativeUrl", _move_folder)
132+
self.ensure_property("ServerRelativePath", _move_folder)
97133
return return_type
98134

99-
def move_to_using_path(self, new_path):
100-
"""
101-
Moves the folder and its contents to a new folder at the specified path.
102-
An exception is thrown if a folder with the same name as specified in the parameter already exists.
103-
104-
:param str new_path: Specifies the destination path.
105-
"""
106-
qry = ServiceOperationQuery(self, "MoveToUsingPath", SPResPath(new_path))
107-
self.context.add_query(qry)
108-
return self
109-
110135
def share_link(self, link_kind, expiration=None):
111136
"""Creates a tokenized sharing link for a folder based on the specified parameters and optionally
112137
sends an email to the people that are listed in the specified parameters.
@@ -252,66 +277,65 @@ def _loaded():
252277
include_anonymous_links_in_notification,
253278
propagate_acl,
254279
return_type)
280+
255281
self.ensure_property("ServerRelativePath", _loaded)
256282
return return_type
257283

258-
def copy_to(self, new_relative_url, keep_both=False, reset_author_and_created=False, parent_folder=None):
284+
def copy_to(self, destination, keep_both=False, reset_author_and_created=False):
259285
"""Copies the folder with files to the destination URL.
260286
261-
:param str new_relative_url: Folder name or server relative url
287+
:param str or Folder destination: Parent folder object or server relative folder url
262288
:param bool keep_both: bool
263289
:param bool reset_author_and_created:
264-
:param Folder or None parent_folder: The existing parent folder
265290
"""
266-
if parent_folder is None:
267-
parent_folder = self.parent_folder
268291
return_type = Folder(self.context)
292+
self.parent_collection.add_child(return_type)
269293

270-
def _parent_folder_resolved():
271-
new_path = SPResPath.create_relative(parent_folder.serverRelativeUrl, new_relative_url)
272-
return_type.set_property("ServerRelativeUrl", str(new_path))
273-
self.ensure_property("ServerRelativeUrl", _copy_to, folder_path=new_path)
274-
parent_folder.ensure_property("ServerRelativeUrl", _parent_folder_resolved)
275-
276-
def _copy_to(folder_path):
294+
def _copy_folder(destination_folder):
295+
"""
296+
:type destination_folder: Folder
297+
"""
298+
destination_url = "/".join([destination_folder.serverRelativeUrl, self.name])
299+
return_type.set_property("ServerRelativeUrl", destination_url)
277300
opts = MoveCopyOptions(keep_both=keep_both, reset_author_and_created_on_copy=reset_author_and_created)
278-
MoveCopyUtil.copy_folder(self.context, self.serverRelativeUrl, str(folder_path), opts)
301+
MoveCopyUtil.copy_folder(self.context, self.serverRelativeUrl, destination_url, opts)
302+
303+
def _source_folder_resolved():
304+
if isinstance(destination, Folder):
305+
destination.ensure_property("ServerRelativeUrl", _copy_folder, destination)
306+
else:
307+
self.context.web.ensure_folder_path(destination).after_execute(_copy_folder)
279308

309+
self.ensure_property("ServerRelativeUrl", _source_folder_resolved)
280310
return return_type
281311

282-
def copy_to_using_path(self, new_relative_path, keep_both=False, reset_author_and_created=False):
312+
def copy_to_using_path(self, destination, keep_both=False, reset_author_and_created=False):
283313
"""Copies the folder with files to the destination Path.
284314
285-
:type new_relative_path: str
315+
:param str or Folder destination: Parent folder object or server relative folder url
286316
:type keep_both: bool
287317
:type reset_author_and_created: bool
288318
"""
289319

290320
return_type = Folder(self.context)
291-
return_type.set_property("ServerRelativePath", new_relative_path)
321+
self.parent_collection.add_child(return_type)
292322

293-
def _copy_folder():
323+
def _copy_folder_by_path(destination_folder):
324+
"""
325+
:type destination_folder: Folder
326+
"""
327+
destination_url = "/".join([str(destination_folder.server_relative_path), self.name])
328+
return_type.set_property("ServerRelativePath", destination_url)
294329
opts = MoveCopyOptions(keep_both=keep_both, reset_author_and_created_on_copy=reset_author_and_created)
295-
MoveCopyUtil.copy_folder_by_path(self.context, str(self.server_relative_path), new_relative_path,
296-
opts)
297-
298-
self.ensure_property("ServerRelativePath", _copy_folder)
299-
return return_type
300-
301-
def move_to_using_path_with_parameters(self, new_relative_path, retain_editor_and_modified=False):
302-
"""Moves the folder with files to the destination Path.
303-
304-
:param str new_relative_path: A full URL path that represents the destination folder.
305-
:param bool retain_editor_and_modified:
306-
"""
307-
return_type = Folder(self.context)
308-
return_type.set_property("ServerRelativePath", SPResPath(new_relative_path))
330+
MoveCopyUtil.copy_folder_by_path(self.context, str(self.server_relative_path), destination_url, opts)
309331

310-
def _move_folder():
311-
opt = MoveCopyOptions(retain_editor_and_modified_on_move=retain_editor_and_modified)
312-
MoveCopyUtil.move_folder_by_path(self.context, self.server_relative_path.DecodedUrl, new_relative_path, opt)
332+
def _source_folder_resolved():
333+
if isinstance(destination, Folder):
334+
destination.ensure_property("ServerRelativePath", _copy_folder_by_path, destination)
335+
else:
336+
self.context.web.ensure_folder_path(destination).after_execute(_copy_folder_by_path)
313337

314-
self.ensure_property("ServerRelativePath", _move_folder)
338+
self.ensure_properties(["ServerRelativePath", "Name"], _source_folder_resolved)
315339
return return_type
316340

317341
@property

0 commit comments

Comments
 (0)