From c0acb58bad056d91b9972f858f495b727e5dfdad Mon Sep 17 00:00:00 2001 From: Halla Moore Date: Tue, 23 Jun 2020 16:39:46 -0400 Subject: [PATCH] Implement MoveFolder and add folder.move() --- exchangelib/folders.py | 5 ++++- exchangelib/services.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/exchangelib/folders.py b/exchangelib/folders.py index c7f4ad41..b074797c 100644 --- a/exchangelib/folders.py +++ b/exchangelib/folders.py @@ -23,7 +23,7 @@ from .queryset import QuerySet, SearchableMixIn from .restriction import Restriction from .services import FindFolder, GetFolder, FindItem, CreateFolder, UpdateFolder, DeleteFolder, EmptyFolder, FindPeople, \ - SyncFolderItems + SyncFolderItems, MoveFolder from .util import TNS, MNS from .version import EXCHANGE_2007_SP1, EXCHANGE_2010_SP1, EXCHANGE_2013, EXCHANGE_2013_SP1 @@ -742,6 +742,9 @@ def empty(self, delete_type=HARD_DELETE, delete_sub_folders=False): # We don't know exactly what was deleted, so invalidate the entire folder cache to be safe self.account.root.clear_cache() + def move(self, to_folder): + return MoveFolder(account=self.account).call(folders=[self], to_folder=to_folder) + def wipe(self): # Recursively deletes all items in this folder, and all subfolders and their content. Attempts to protect # distinguished folders from being deleted. Use with caution! diff --git a/exchangelib/services.py b/exchangelib/services.py index 5e63b195..bae046c6 100644 --- a/exchangelib/services.py +++ b/exchangelib/services.py @@ -2360,6 +2360,40 @@ def _get_elements_in_response(self, response): yield c +class MoveFolder(EWSAccountService): + """ + https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movefolder-operation + """ + + SERVICE_NAME = "MoveFolder" + element_container_name = None + + def call(self, folders, to_folder): + return list(self._get_elements(payload=self.get_payload(folders, to_folder))) + + def get_payload(self, folders, to_folder): + from .folders import Folder, FolderId, DistinguishedFolderId + + payload = create_element("m:{}".format(self.SERVICE_NAME)) + + to_folder_elem = create_element("m:ToFolderId") + if not isinstance(to_folder, (Folder, FolderId, DistinguishedFolderId)): + to_folder = to_item_id(to_folder, FolderId) + set_xml_value(to_folder_elem, to_folder, version=self.account.version) + + folder_ids = create_element("m:FolderIds") + for folder in folders: + if not isinstance(folder, (Folder, FolderId, DistinguishedFolderId)): + folder = to_item_id(folder, FolderId) + set_xml_value(folder_ids, folder, version=self.account.version) + if not len(folder_ids): + raise ValueError('"folders" must not be empty') + + payload.append(to_folder_elem) + payload.append(folder_ids) + return payload + + def to_item_id(item, item_cls): # Coerce a tuple, dict or object to an 'item_cls' instance. Used to create [Parent][Item|Folder]Id instances from a # variety of input.