Module exchangelib.services
Implement a selection of EWS services (operations).
Exchange is very picky about things like the order of XML elements in SOAP requests, so we need to generate XML automatically instead of taking advantage of Python SOAP libraries and the WSDL file.
Exchange EWS operations overview: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/ews-operations-in-exchange
Expand source code
"""Implement a selection of EWS services (operations).
Exchange is very picky about things like the order of XML elements in SOAP requests, so we need to generate XML
automatically instead of taking advantage of Python SOAP libraries and the WSDL file.
Exchange EWS operations overview:
https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/ews-operations-in-exchange
"""
from .archive_item import ArchiveItem
from .common import CHUNK_SIZE
from .convert_id import ConvertId
from .copy_item import CopyItem
from .create_attachment import CreateAttachment
from .create_folder import CreateFolder
from .create_item import CreateItem
from .create_user_configuration import CreateUserConfiguration
from .delete_attachment import DeleteAttachment
from .delete_folder import DeleteFolder
from .delete_item import DeleteItem
from .delete_user_configuration import DeleteUserConfiguration
from .empty_folder import EmptyFolder
from .expand_dl import ExpandDL
from .export_items import ExportItems
from .find_folder import FindFolder
from .find_item import FindItem
from .find_people import FindPeople
from .get_attachment import GetAttachment
from .get_delegate import GetDelegate
from .get_events import GetEvents
from .get_folder import GetFolder
from .get_item import GetItem
from .get_mail_tips import GetMailTips
from .get_persona import GetPersona
from .get_room_lists import GetRoomLists
from .get_rooms import GetRooms
from .get_searchable_mailboxes import GetSearchableMailboxes
from .get_server_time_zones import GetServerTimeZones
from .get_streaming_events import GetStreamingEvents
from .get_user_availability import GetUserAvailability
from .get_user_configuration import GetUserConfiguration
from .get_user_oof_settings import GetUserOofSettings
from .mark_as_junk import MarkAsJunk
from .move_folder import MoveFolder
from .move_item import MoveItem
from .resolve_names import ResolveNames
from .send_item import SendItem
from .send_notification import SendNotification
from .set_user_oof_settings import SetUserOofSettings
from .subscribe import SubscribeToStreaming, SubscribeToPull, SubscribeToPush
from .sync_folder_hierarchy import SyncFolderHierarchy
from .sync_folder_items import SyncFolderItems
from .unsubscribe import Unsubscribe
from .update_folder import UpdateFolder
from .update_item import UpdateItem
from .update_user_configuration import UpdateUserConfiguration
from .upload_items import UploadItems
__all__ = [
'CHUNK_SIZE',
'ArchiveItem',
'ConvertId',
'CopyItem',
'CreateAttachment',
'CreateFolder',
'CreateItem',
'CreateUserConfiguration',
'DeleteAttachment',
'DeleteFolder',
'DeleteUserConfiguration',
'DeleteItem',
'EmptyFolder',
'ExpandDL',
'ExportItems',
'FindFolder',
'FindItem',
'FindPeople',
'GetAttachment',
'GetDelegate',
'GetEvents',
'GetFolder',
'GetItem',
'GetMailTips',
'GetPersona',
'GetRoomLists',
'GetRooms',
'GetSearchableMailboxes',
'GetServerTimeZones',
'GetStreamingEvents',
'GetUserAvailability',
'GetUserConfiguration',
'GetUserOofSettings',
'MarkAsJunk',
'MoveFolder',
'MoveItem',
'ResolveNames',
'SendItem',
'SendNotification',
'SetUserOofSettings',
'SubscribeToPull',
'SubscribeToPush',
'SubscribeToStreaming',
'SyncFolderHierarchy',
'SyncFolderItems',
'Unsubscribe',
'UpdateFolder',
'UpdateItem',
'UpdateUserConfiguration',
'UploadItems',
]
Sub-modules
exchangelib.services.archive_item
exchangelib.services.common
exchangelib.services.convert_id
exchangelib.services.copy_item
exchangelib.services.create_attachment
exchangelib.services.create_folder
exchangelib.services.create_item
exchangelib.services.create_user_configuration
exchangelib.services.delete_attachment
exchangelib.services.delete_folder
exchangelib.services.delete_item
exchangelib.services.delete_user_configuration
exchangelib.services.empty_folder
exchangelib.services.expand_dl
exchangelib.services.export_items
exchangelib.services.find_folder
exchangelib.services.find_item
exchangelib.services.find_people
exchangelib.services.get_attachment
exchangelib.services.get_delegate
exchangelib.services.get_events
exchangelib.services.get_folder
exchangelib.services.get_item
exchangelib.services.get_mail_tips
exchangelib.services.get_persona
exchangelib.services.get_room_lists
exchangelib.services.get_rooms
exchangelib.services.get_searchable_mailboxes
exchangelib.services.get_server_time_zones
exchangelib.services.get_streaming_events
exchangelib.services.get_user_availability
exchangelib.services.get_user_configuration
exchangelib.services.get_user_oof_settings
exchangelib.services.mark_as_junk
exchangelib.services.move_folder
exchangelib.services.move_item
exchangelib.services.resolve_names
exchangelib.services.send_item
exchangelib.services.send_notification
exchangelib.services.set_user_oof_settings
exchangelib.services.subscribe
-
The 'Subscribe' service has two different modes, pull and push, with different signatures. Implement as two distinct classes.
exchangelib.services.sync_folder_hierarchy
exchangelib.services.sync_folder_items
exchangelib.services.unsubscribe
exchangelib.services.update_folder
exchangelib.services.update_item
exchangelib.services.update_user_configuration
exchangelib.services.upload_items
Classes
class ArchiveItem (*args, **kwargs)
-
Expand source code
class ArchiveItem(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/archiveitem-operation""" SERVICE_NAME = 'ArchiveItem' element_container_name = '{%s}Items' % MNS supported_from = EXCHANGE_2013 def call(self, items, to_folder): """Move a list of items to a specific folder in the archive mailbox. :param items: a list of (id, changekey) tuples or Item objects :param to_folder: :return: None """ return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder)) def _elems_to_objs(self, elems): from ..items import Item for elem in elems: if isinstance(elem, Exception): yield elem continue yield Item.id_from_xml(elem) def get_payload(self, items, to_folder): archiveitem = create_element('m:%s' % self.SERVICE_NAME) folder_id = create_folder_ids_element(tag='m:ArchiveSourceFolderId', folders=[to_folder], version=self.account.version) item_ids = create_item_ids_element(items=items, version=self.account.version) archiveitem.append(folder_id) archiveitem.append(item_ids) return archiveitem
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var supported_from
Methods
def call(self, items, to_folder)
-
Move a list of items to a specific folder in the archive mailbox.
:param items: a list of (id, changekey) tuples or Item objects :param to_folder:
:return: None
Expand source code
def call(self, items, to_folder): """Move a list of items to a specific folder in the archive mailbox. :param items: a list of (id, changekey) tuples or Item objects :param to_folder: :return: None """ return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
def get_payload(self, items, to_folder)
-
Expand source code
def get_payload(self, items, to_folder): archiveitem = create_element('m:%s' % self.SERVICE_NAME) folder_id = create_folder_ids_element(tag='m:ArchiveSourceFolderId', folders=[to_folder], version=self.account.version) item_ids = create_item_ids_element(items=items, version=self.account.version) archiveitem.append(folder_id) archiveitem.append(item_ids) return archiveitem
Inherited members
class ConvertId (protocol, chunk_size=None, timeout=None)
-
Take a list of IDs to convert. Returns a list of converted IDs or exception instances, in the same order as the input list.
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/convertid-operation
Expand source code
class ConvertId(EWSService): """Take a list of IDs to convert. Returns a list of converted IDs or exception instances, in the same order as the input list. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/convertid-operation """ SERVICE_NAME = 'ConvertId' supported_from = EXCHANGE_2007_SP1 def call(self, items, destination_format): if destination_format not in ID_FORMATS: raise ValueError("'destination_format' %r must be one of %s" % (destination_format, ID_FORMATS)) return self._elems_to_objs( self._chunked_get_elements(self.get_payload, items=items, destination_format=destination_format) ) def _elems_to_objs(self, elems): cls_map = {cls.response_tag(): cls for cls in ( AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId )} for elem in elems: if isinstance(elem, Exception): yield elem continue yield cls_map[elem.tag].from_xml(elem, account=None) def get_payload(self, items, destination_format): supported_item_classes = AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId convertid = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(DestinationFormat=destination_format)) item_ids = create_element('m:SourceIds') for item in items: if not isinstance(item, supported_item_classes): raise ValueError("'item' value %r must be an instance of %r" % (item, supported_item_classes)) set_xml_value(item_ids, item, version=self.protocol.version) if not len(item_ids): raise ValueError('"items" must not be empty') convertid.append(item_ids) return convertid @classmethod def _get_elements_in_container(cls, container): # We may have other elements in here, e.g. 'ResponseCode'. Filter away those. return container.findall(AlternateId.response_tag()) \ + container.findall(AlternatePublicFolderId.response_tag()) \ + container.findall(AlternatePublicFolderItemId.response_tag())
Ancestors
Class variables
var SERVICE_NAME
var supported_from
Methods
def call(self, items, destination_format)
-
Expand source code
def call(self, items, destination_format): if destination_format not in ID_FORMATS: raise ValueError("'destination_format' %r must be one of %s" % (destination_format, ID_FORMATS)) return self._elems_to_objs( self._chunked_get_elements(self.get_payload, items=items, destination_format=destination_format) )
def get_payload(self, items, destination_format)
-
Expand source code
def get_payload(self, items, destination_format): supported_item_classes = AlternateId, AlternatePublicFolderId, AlternatePublicFolderItemId convertid = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(DestinationFormat=destination_format)) item_ids = create_element('m:SourceIds') for item in items: if not isinstance(item, supported_item_classes): raise ValueError("'item' value %r must be an instance of %r" % (item, supported_item_classes)) set_xml_value(item_ids, item, version=self.protocol.version) if not len(item_ids): raise ValueError('"items" must not be empty') convertid.append(item_ids) return convertid
Inherited members
class CopyItem (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copyitem-operation
Expand source code
class CopyItem(move_item.MoveItem): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/copyitem-operation""" SERVICE_NAME = 'CopyItem'
Ancestors
Class variables
var SERVICE_NAME
Inherited members
class CreateAttachment (*args, **kwargs)
-
Expand source code
class CreateAttachment(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createattachment-operation """ SERVICE_NAME = 'CreateAttachment' element_container_name = '{%s}Attachments' % MNS def call(self, parent_item, items): return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, parent_item=parent_item)) def _elems_to_objs(self, elems): from ..attachments import FileAttachment, ItemAttachment cls_map = {cls.response_tag(): cls for cls in (FileAttachment, ItemAttachment)} for elem in elems: if isinstance(elem, Exception): yield elem continue yield cls_map[elem.tag].from_xml(elem=elem, account=self.account) def get_payload(self, items, parent_item): from ..items import BaseItem payload = create_element('m:%s' % self.SERVICE_NAME) version = self.account.version if isinstance(parent_item, BaseItem): # to_item_id() would convert this to a normal ItemId, but the service wants a ParentItemId parent_item = ParentItemId(parent_item.id, parent_item.changekey) set_xml_value(payload, to_item_id(parent_item, ParentItemId, version=version), version=version) attachments = create_element('m:Attachments') for item in items: set_xml_value(attachments, item, version=self.account.version) if not len(attachments): raise ValueError('"items" must not be empty') payload.append(attachments) return payload
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, parent_item, items)
-
Expand source code
def call(self, parent_item, items): return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, parent_item=parent_item))
def get_payload(self, items, parent_item)
-
Expand source code
def get_payload(self, items, parent_item): from ..items import BaseItem payload = create_element('m:%s' % self.SERVICE_NAME) version = self.account.version if isinstance(parent_item, BaseItem): # to_item_id() would convert this to a normal ItemId, but the service wants a ParentItemId parent_item = ParentItemId(parent_item.id, parent_item.changekey) set_xml_value(payload, to_item_id(parent_item, ParentItemId, version=version), version=version) attachments = create_element('m:Attachments') for item in items: set_xml_value(attachments, item, version=self.account.version) if not len(attachments): raise ValueError('"items" must not be empty') payload.append(attachments) return payload
Inherited members
class CreateFolder (*args, **kwargs)
-
Expand source code
class CreateFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createfolder-operation""" SERVICE_NAME = 'CreateFolder' element_container_name = '{%s}Folders' % MNS def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.folders = [] # A hack to communicate parsing args to _elems_to_objs() def call(self, parent_folder, folders): # We can't easily find the correct folder class from the returned XML. Instead, return objects with the same # class as the folder instance it was requested with. self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice. return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=self.folders, parent_folder=parent_folder, )) def _elems_to_objs(self, elems): for folder, elem in zip(self.folders, elems): if isinstance(elem, Exception): yield elem continue yield parse_folder_elem(elem=elem, folder=folder, account=self.account) def get_payload(self, folders, parent_folder): create_folder = create_element('m:%s' % self.SERVICE_NAME) parentfolderid = create_element('m:ParentFolderId') set_xml_value(parentfolderid, parent_folder, version=self.account.version) set_xml_value(create_folder, parentfolderid, version=self.account.version) folder_ids = create_folder_ids_element(tag='m:Folders', folders=folders, version=self.account.version) create_folder.append(folder_ids) return create_folder
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, parent_folder, folders)
-
Expand source code
def call(self, parent_folder, folders): # We can't easily find the correct folder class from the returned XML. Instead, return objects with the same # class as the folder instance it was requested with. self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice. return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=self.folders, parent_folder=parent_folder, ))
def get_payload(self, folders, parent_folder)
-
Expand source code
def get_payload(self, folders, parent_folder): create_folder = create_element('m:%s' % self.SERVICE_NAME) parentfolderid = create_element('m:ParentFolderId') set_xml_value(parentfolderid, parent_folder, version=self.account.version) set_xml_value(create_folder, parentfolderid, version=self.account.version) folder_ids = create_folder_ids_element(tag='m:Folders', folders=folders, version=self.account.version) create_folder.append(folder_ids) return create_folder
Inherited members
class CreateItem (*args, **kwargs)
-
Take a folder and a list of items. Return the result of creation as a list of tuples (success[True|False], errormessage), in the same order as the input list.
Expand source code
class CreateItem(EWSAccountService): """Take a folder and a list of items. Return the result of creation as a list of tuples (success[True|False], errormessage), in the same order as the input list. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation """ SERVICE_NAME = 'CreateItem' element_container_name = '{%s}Items' % MNS def call(self, items, folder, message_disposition, send_meeting_invitations): from ..folders import BaseFolder, FolderId from ..items import SAVE_ONLY, SEND_AND_SAVE_COPY, SEND_ONLY, \ SEND_MEETING_INVITATIONS_CHOICES, MESSAGE_DISPOSITION_CHOICES if message_disposition not in MESSAGE_DISPOSITION_CHOICES: raise ValueError("'message_disposition' %s must be one of %s" % ( message_disposition, MESSAGE_DISPOSITION_CHOICES )) if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES: raise ValueError("'send_meeting_invitations' %s must be one of %s" % ( send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES )) if folder is not None: if not isinstance(folder, (BaseFolder, FolderId)): raise ValueError("'folder' %r must be a Folder or FolderId instance" % folder) if folder.account != self.account: raise ValueError('"Folder must belong to this account') if message_disposition == SAVE_ONLY and folder is None: raise AttributeError("Folder must be supplied when in save-only mode") if message_disposition == SEND_AND_SAVE_COPY and folder is None: folder = self.account.sent # 'Sent' is default EWS behaviour if message_disposition == SEND_ONLY and folder is not None: raise AttributeError("Folder must be None in send-ony mode") return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, folder=folder, message_disposition=message_disposition, send_meeting_invitations=send_meeting_invitations, )) def _elems_to_objs(self, elems): from ..items import BulkCreateResult for elem in elems: if isinstance(elem, (Exception, type(None))): yield elem continue if isinstance(elem, bool): yield elem continue yield BulkCreateResult.from_xml(elem=elem, account=self.account) @classmethod def _get_elements_in_container(cls, container): res = super()._get_elements_in_container(container) return res or [True] def get_payload(self, items, folder, message_disposition, send_meeting_invitations): """Take a list of Item objects (CalendarItem, Message etc) and return the XML for a CreateItem request. convert items to XML Elements. MessageDisposition is only applicable to email messages, where it is required. SendMeetingInvitations is required for calendar items. It is also applicable to tasks, meeting request responses (see https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation-meeting-request ) and sharing invitation accepts (see https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-acceptsharinginvitation ). The last two are not supported yet. :param items: :param folder: :param message_disposition: :param send_meeting_invitations: """ createitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('MessageDisposition', message_disposition), ('SendMeetingInvitations', send_meeting_invitations), ]) ) if folder: saveditemfolderid = create_element('m:SavedItemFolderId') set_xml_value(saveditemfolderid, folder, version=self.account.version) createitem.append(saveditemfolderid) item_elems = create_element('m:Items') for item in items: if not item.account: item.account = self.account set_xml_value(item_elems, item, version=self.account.version) if not len(item_elems): raise ValueError('"items" must not be empty') createitem.append(item_elems) return createitem
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, items, folder, message_disposition, send_meeting_invitations)
-
Expand source code
def call(self, items, folder, message_disposition, send_meeting_invitations): from ..folders import BaseFolder, FolderId from ..items import SAVE_ONLY, SEND_AND_SAVE_COPY, SEND_ONLY, \ SEND_MEETING_INVITATIONS_CHOICES, MESSAGE_DISPOSITION_CHOICES if message_disposition not in MESSAGE_DISPOSITION_CHOICES: raise ValueError("'message_disposition' %s must be one of %s" % ( message_disposition, MESSAGE_DISPOSITION_CHOICES )) if send_meeting_invitations not in SEND_MEETING_INVITATIONS_CHOICES: raise ValueError("'send_meeting_invitations' %s must be one of %s" % ( send_meeting_invitations, SEND_MEETING_INVITATIONS_CHOICES )) if folder is not None: if not isinstance(folder, (BaseFolder, FolderId)): raise ValueError("'folder' %r must be a Folder or FolderId instance" % folder) if folder.account != self.account: raise ValueError('"Folder must belong to this account') if message_disposition == SAVE_ONLY and folder is None: raise AttributeError("Folder must be supplied when in save-only mode") if message_disposition == SEND_AND_SAVE_COPY and folder is None: folder = self.account.sent # 'Sent' is default EWS behaviour if message_disposition == SEND_ONLY and folder is not None: raise AttributeError("Folder must be None in send-ony mode") return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, folder=folder, message_disposition=message_disposition, send_meeting_invitations=send_meeting_invitations, ))
def get_payload(self, items, folder, message_disposition, send_meeting_invitations)
-
Take a list of Item objects (CalendarItem, Message etc) and return the XML for a CreateItem request. convert items to XML Elements.
MessageDisposition is only applicable to email messages, where it is required.
SendMeetingInvitations is required for calendar items. It is also applicable to tasks, meeting request responses (see https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation-meeting-request ) and sharing invitation accepts (see https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-acceptsharinginvitation ). The last two are not supported yet.
:param items: :param folder: :param message_disposition: :param send_meeting_invitations:
Expand source code
def get_payload(self, items, folder, message_disposition, send_meeting_invitations): """Take a list of Item objects (CalendarItem, Message etc) and return the XML for a CreateItem request. convert items to XML Elements. MessageDisposition is only applicable to email messages, where it is required. SendMeetingInvitations is required for calendar items. It is also applicable to tasks, meeting request responses (see https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-operation-meeting-request ) and sharing invitation accepts (see https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createitem-acceptsharinginvitation ). The last two are not supported yet. :param items: :param folder: :param message_disposition: :param send_meeting_invitations: """ createitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('MessageDisposition', message_disposition), ('SendMeetingInvitations', send_meeting_invitations), ]) ) if folder: saveditemfolderid = create_element('m:SavedItemFolderId') set_xml_value(saveditemfolderid, folder, version=self.account.version) createitem.append(saveditemfolderid) item_elems = create_element('m:Items') for item in items: if not item.account: item.account = self.account set_xml_value(item_elems, item, version=self.account.version) if not len(item_elems): raise ValueError('"items" must not be empty') createitem.append(item_elems) return createitem
Inherited members
class CreateUserConfiguration (*args, **kwargs)
-
Expand source code
class CreateUserConfiguration(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/createuserconfiguration-operation """ SERVICE_NAME = 'CreateUserConfiguration' returns_elements = False def call(self, user_configuration): return self._get_elements(payload=self.get_payload(user_configuration=user_configuration)) def get_payload(self, user_configuration): createuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(createuserconfiguration, user_configuration, version=self.protocol.version) return createuserconfiguration
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, user_configuration)
-
Expand source code
def call(self, user_configuration): return self._get_elements(payload=self.get_payload(user_configuration=user_configuration))
def get_payload(self, user_configuration)
-
Expand source code
def get_payload(self, user_configuration): createuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(createuserconfiguration, user_configuration, version=self.protocol.version) return createuserconfiguration
Inherited members
class DeleteAttachment (*args, **kwargs)
-
Expand source code
class DeleteAttachment(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteattachment-operation """ SERVICE_NAME = 'DeleteAttachment' def call(self, items): return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items)) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield RootItemId.from_xml(elem=elem, account=self.account) @classmethod def _get_elements_in_container(cls, container): return container.findall(RootItemId.response_tag()) def get_payload(self, items): payload = create_element('m:%s' % self.SERVICE_NAME) attachment_ids = create_attachment_ids_element(items=items, version=self.account.version) payload.append(attachment_ids) return payload
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self, items)
-
Expand source code
def call(self, items): return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items))
def get_payload(self, items)
-
Expand source code
def get_payload(self, items): payload = create_element('m:%s' % self.SERVICE_NAME) attachment_ids = create_attachment_ids_element(items=items, version=self.account.version) payload.append(attachment_ids) return payload
Inherited members
class DeleteFolder (*args, **kwargs)
-
Expand source code
class DeleteFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deletefolder-operation""" SERVICE_NAME = 'DeleteFolder' returns_elements = False def call(self, folders, delete_type): return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type) def get_payload(self, folders, delete_type): deletefolder = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(DeleteType=delete_type)) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) deletefolder.append(folder_ids) return deletefolder
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, folders, delete_type)
-
Expand source code
def call(self, folders, delete_type): return self._chunked_get_elements(self.get_payload, items=folders, delete_type=delete_type)
def get_payload(self, folders, delete_type)
-
Expand source code
def get_payload(self, folders, delete_type): deletefolder = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(DeleteType=delete_type)) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) deletefolder.append(folder_ids) return deletefolder
Inherited members
class DeleteItem (*args, **kwargs)
-
Take a folder and a list of (id, changekey) tuples. Return result of deletion as a list of tuples (success[True|False], errormessage), in the same order as the input list.
Expand source code
class DeleteItem(EWSAccountService): """Take a folder and a list of (id, changekey) tuples. Return result of deletion as a list of tuples (success[True|False], errormessage), in the same order as the input list. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteitem-operation """ SERVICE_NAME = 'DeleteItem' returns_elements = False def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts): from ..items import DELETE_TYPE_CHOICES, SEND_MEETING_CANCELLATIONS_CHOICES, AFFECTED_TASK_OCCURRENCES_CHOICES if delete_type not in DELETE_TYPE_CHOICES: raise ValueError("'delete_type' %s must be one of %s" % ( delete_type, DELETE_TYPE_CHOICES )) if send_meeting_cancellations not in SEND_MEETING_CANCELLATIONS_CHOICES: raise ValueError("'send_meeting_cancellations' %s must be one of %s" % ( send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES )) if affected_task_occurrences not in AFFECTED_TASK_OCCURRENCES_CHOICES: raise ValueError("'affected_task_occurrences' %s must be one of %s" % ( affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES )) if suppress_read_receipts not in (True, False): raise ValueError("'suppress_read_receipts' %s must be True or False" % suppress_read_receipts) return self._chunked_get_elements( self.get_payload, items=items, delete_type=delete_type, send_meeting_cancellations=send_meeting_cancellations, affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts, ) def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts): # Takes a list of (id, changekey) tuples or Item objects and returns the XML for a DeleteItem request. if self.account.version.build >= EXCHANGE_2013_SP1: deleteitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('DeleteType', delete_type), ('SendMeetingCancellations', send_meeting_cancellations), ('AffectedTaskOccurrences', affected_task_occurrences), ('SuppressReadReceipts', 'true' if suppress_read_receipts else 'false'), ]) ) else: deleteitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('DeleteType', delete_type), ('SendMeetingCancellations', send_meeting_cancellations), ('AffectedTaskOccurrences', affected_task_occurrences), ]) ) item_ids = create_item_ids_element(items=items, version=self.account.version) deleteitem.append(item_ids) return deleteitem
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts)
-
Expand source code
def call(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts): from ..items import DELETE_TYPE_CHOICES, SEND_MEETING_CANCELLATIONS_CHOICES, AFFECTED_TASK_OCCURRENCES_CHOICES if delete_type not in DELETE_TYPE_CHOICES: raise ValueError("'delete_type' %s must be one of %s" % ( delete_type, DELETE_TYPE_CHOICES )) if send_meeting_cancellations not in SEND_MEETING_CANCELLATIONS_CHOICES: raise ValueError("'send_meeting_cancellations' %s must be one of %s" % ( send_meeting_cancellations, SEND_MEETING_CANCELLATIONS_CHOICES )) if affected_task_occurrences not in AFFECTED_TASK_OCCURRENCES_CHOICES: raise ValueError("'affected_task_occurrences' %s must be one of %s" % ( affected_task_occurrences, AFFECTED_TASK_OCCURRENCES_CHOICES )) if suppress_read_receipts not in (True, False): raise ValueError("'suppress_read_receipts' %s must be True or False" % suppress_read_receipts) return self._chunked_get_elements( self.get_payload, items=items, delete_type=delete_type, send_meeting_cancellations=send_meeting_cancellations, affected_task_occurrences=affected_task_occurrences, suppress_read_receipts=suppress_read_receipts, )
def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts)
-
Expand source code
def get_payload(self, items, delete_type, send_meeting_cancellations, affected_task_occurrences, suppress_read_receipts): # Takes a list of (id, changekey) tuples or Item objects and returns the XML for a DeleteItem request. if self.account.version.build >= EXCHANGE_2013_SP1: deleteitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('DeleteType', delete_type), ('SendMeetingCancellations', send_meeting_cancellations), ('AffectedTaskOccurrences', affected_task_occurrences), ('SuppressReadReceipts', 'true' if suppress_read_receipts else 'false'), ]) ) else: deleteitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('DeleteType', delete_type), ('SendMeetingCancellations', send_meeting_cancellations), ('AffectedTaskOccurrences', affected_task_occurrences), ]) ) item_ids = create_item_ids_element(items=items, version=self.account.version) deleteitem.append(item_ids) return deleteitem
Inherited members
class DeleteUserConfiguration (*args, **kwargs)
-
Expand source code
class DeleteUserConfiguration(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/deleteuserconfiguration-operation """ SERVICE_NAME = 'DeleteUserConfiguration' returns_elements = False def call(self, user_configuration_name): return self._get_elements(payload=self.get_payload(user_configuration_name=user_configuration_name)) def get_payload(self, user_configuration_name): deleteuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(deleteuserconfiguration, user_configuration_name, version=self.account.version) return deleteuserconfiguration
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, user_configuration_name)
-
Expand source code
def call(self, user_configuration_name): return self._get_elements(payload=self.get_payload(user_configuration_name=user_configuration_name))
def get_payload(self, user_configuration_name)
-
Expand source code
def get_payload(self, user_configuration_name): deleteuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(deleteuserconfiguration, user_configuration_name, version=self.account.version) return deleteuserconfiguration
Inherited members
class EmptyFolder (*args, **kwargs)
-
Expand source code
class EmptyFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/emptyfolder-operation""" SERVICE_NAME = 'EmptyFolder' returns_elements = False def call(self, folders, delete_type, delete_sub_folders): return self._chunked_get_elements( self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders ) def get_payload(self, folders, delete_type, delete_sub_folders): emptyfolder = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('DeleteType', delete_type), ('DeleteSubFolders', 'true' if delete_sub_folders else 'false'), ]) ) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) emptyfolder.append(folder_ids) return emptyfolder
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, folders, delete_type, delete_sub_folders)
-
Expand source code
def call(self, folders, delete_type, delete_sub_folders): return self._chunked_get_elements( self.get_payload, items=folders, delete_type=delete_type, delete_sub_folders=delete_sub_folders )
def get_payload(self, folders, delete_type, delete_sub_folders)
-
Expand source code
def get_payload(self, folders, delete_type, delete_sub_folders): emptyfolder = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('DeleteType', delete_type), ('DeleteSubFolders', 'true' if delete_sub_folders else 'false'), ]) ) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) emptyfolder.append(folder_ids) return emptyfolder
Inherited members
class ExpandDL (protocol, chunk_size=None, timeout=None)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/expanddl-operation
Expand source code
class ExpandDL(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/expanddl-operation""" SERVICE_NAME = 'ExpandDL' element_container_name = '{%s}DLExpansion' % MNS WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults def call(self, distribution_list): return self._elems_to_objs(self._get_elements(payload=self.get_payload(distribution_list=distribution_list))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield Mailbox.from_xml(elem, account=None) def get_payload(self, distribution_list): payload = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(payload, distribution_list, version=self.protocol.version) return payload
Ancestors
Class variables
var SERVICE_NAME
var WARNINGS_TO_IGNORE_IN_RESPONSE
-
Global error type within this module.
var element_container_name
Methods
def call(self, distribution_list)
-
Expand source code
def call(self, distribution_list): return self._elems_to_objs(self._get_elements(payload=self.get_payload(distribution_list=distribution_list)))
def get_payload(self, distribution_list)
-
Expand source code
def get_payload(self, distribution_list): payload = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(payload, distribution_list, version=self.protocol.version) return payload
Inherited members
class ExportItems (*args, **kwargs)
-
Expand source code
class ExportItems(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/exportitems-operation""" ERRORS_TO_CATCH_IN_RESPONSE = ResponseMessageError SERVICE_NAME = 'ExportItems' element_container_name = '{%s}Data' % MNS def call(self, items): return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items)) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield elem.text # All we want is the 64bit string in the 'Data' tag def get_payload(self, items): exportitems = create_element('m:%s' % self.SERVICE_NAME) item_ids = create_item_ids_element(items=items, version=self.account.version) exportitems.append(item_ids) return exportitems # We need to override this since ExportItemsResponseMessage is formatted a # little bit differently. . @classmethod def _get_elements_in_container(cls, container): return [container]
Ancestors
Class variables
var ERRORS_TO_CATCH_IN_RESPONSE
-
Global error type within this module.
var SERVICE_NAME
var element_container_name
Methods
def call(self, items)
-
Expand source code
def call(self, items): return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items))
def get_payload(self, items)
-
Expand source code
def get_payload(self, items): exportitems = create_element('m:%s' % self.SERVICE_NAME) item_ids = create_item_ids_element(items=items, version=self.account.version) exportitems.append(item_ids) return exportitems
Inherited members
class FindFolder (*args, **kwargs)
-
Expand source code
class FindFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findfolder-operation""" SERVICE_NAME = 'FindFolder' element_container_name = '{%s}Folders' % TNS paging_container_name = '{%s}RootFolder' % MNS supports_paging = True def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.root = None # A hack to communicate parsing args to _elems_to_objs() def call(self, folders, additional_fields, restriction, shape, depth, max_items, offset): """Find subfolders of a folder. :param folders: the folders to act on :param additional_fields: the extra fields that should be returned with the folder, as FieldPath objects :param restriction: Restriction object that defines the filters for the query :param shape: The set of attributes to return :param depth: How deep in the folder structure to search for folders :param max_items: The maximum number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0. :return: XML elements for the matching folders """ roots = {f.root for f in folders} if len(roots) != 1: raise ValueError('FindFolder must be called with folders in the same root hierarchy (%r)' % roots) self.root = roots.pop() return self._elems_to_objs(self._paged_call( payload_func=self.get_payload, max_items=max_items, folders=folders, **dict( additional_fields=additional_fields, restriction=restriction, shape=shape, depth=depth, page_size=self.chunk_size, offset=offset, ) )) def _elems_to_objs(self, elems): from ..folders import Folder for elem in elems: if isinstance(elem, Exception): yield elem continue yield Folder.from_xml_with_root(elem=elem, root=self.root) def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0): findfolder = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(Traversal=depth)) foldershape = create_shape_element( tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) findfolder.append(foldershape) if self.account.version.build >= EXCHANGE_2010: indexedpageviewitem = create_element( 'm:IndexedPageFolderView', attrs=OrderedDict([ ('MaxEntriesReturned', str(page_size)), ('Offset', str(offset)), ('BasePoint', 'Beginning'), ]) ) findfolder.append(indexedpageviewitem) else: if offset != 0: raise ValueError('Offsets are only supported from Exchange 2010') if restriction: findfolder.append(restriction.to_xml(version=self.account.version)) parentfolderids = create_element('m:ParentFolderIds') set_xml_value(parentfolderids, folders, version=self.account.version) findfolder.append(parentfolderids) return findfolder
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var paging_container_name
var supports_paging
Methods
def call(self, folders, additional_fields, restriction, shape, depth, max_items, offset)
-
Find subfolders of a folder.
:param folders: the folders to act on :param additional_fields: the extra fields that should be returned with the folder, as FieldPath objects :param restriction: Restriction object that defines the filters for the query :param shape: The set of attributes to return :param depth: How deep in the folder structure to search for folders :param max_items: The maximum number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0.
:return: XML elements for the matching folders
Expand source code
def call(self, folders, additional_fields, restriction, shape, depth, max_items, offset): """Find subfolders of a folder. :param folders: the folders to act on :param additional_fields: the extra fields that should be returned with the folder, as FieldPath objects :param restriction: Restriction object that defines the filters for the query :param shape: The set of attributes to return :param depth: How deep in the folder structure to search for folders :param max_items: The maximum number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0. :return: XML elements for the matching folders """ roots = {f.root for f in folders} if len(roots) != 1: raise ValueError('FindFolder must be called with folders in the same root hierarchy (%r)' % roots) self.root = roots.pop() return self._elems_to_objs(self._paged_call( payload_func=self.get_payload, max_items=max_items, folders=folders, **dict( additional_fields=additional_fields, restriction=restriction, shape=shape, depth=depth, page_size=self.chunk_size, offset=offset, ) ))
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0)
-
Expand source code
def get_payload(self, folders, additional_fields, restriction, shape, depth, page_size, offset=0): findfolder = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(Traversal=depth)) foldershape = create_shape_element( tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) findfolder.append(foldershape) if self.account.version.build >= EXCHANGE_2010: indexedpageviewitem = create_element( 'm:IndexedPageFolderView', attrs=OrderedDict([ ('MaxEntriesReturned', str(page_size)), ('Offset', str(offset)), ('BasePoint', 'Beginning'), ]) ) findfolder.append(indexedpageviewitem) else: if offset != 0: raise ValueError('Offsets are only supported from Exchange 2010') if restriction: findfolder.append(restriction.to_xml(version=self.account.version)) parentfolderids = create_element('m:ParentFolderIds') set_xml_value(parentfolderids, folders, version=self.account.version) findfolder.append(parentfolderids) return findfolder
Inherited members
class FindItem (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditem-operation
Expand source code
class FindItem(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/finditem-operation""" SERVICE_NAME = 'FindItem' element_container_name = '{%s}Items' % TNS paging_container_name = '{%s}RootFolder' % MNS supports_paging = True def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # A hack to communicate parsing args to _elems_to_objs() self.additional_fields = None self.shape = None def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view, max_items, offset): """Find items in an account. :param folders: the folders to act on :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param restriction: a Restriction object for :param order_fields: the fields to sort the results by :param shape: The set of attributes to return :param query_string: a QueryString object :param depth: How deep in the folder structure to search for items :param calendar_view: If set, returns recurring calendar items unfolded :param max_items: the max number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0. :return: XML elements for the matching items """ self.additional_fields = additional_fields self.shape = shape return self._elems_to_objs(self._paged_call( payload_func=self.get_payload, max_items=max_items, folders=folders, **dict( additional_fields=additional_fields, restriction=restriction, order_fields=order_fields, query_string=query_string, shape=shape, depth=depth, calendar_view=calendar_view, page_size=self.chunk_size, offset=offset, ) )) def _elems_to_objs(self, elems): from ..folders.base import BaseFolder from ..items import Item, ID_ONLY for elem in elems: if isinstance(elem, Exception): yield elem continue if self.shape == ID_ONLY and self.additional_fields is None: yield Item.id_from_xml(elem) continue yield BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account) def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, calendar_view, page_size, offset=0): finditem = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(Traversal=depth)) itemshape = create_shape_element( tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) finditem.append(itemshape) if calendar_view is None: view_type = create_element( 'm:IndexedPageItemView', attrs=OrderedDict([ ('MaxEntriesReturned', str(page_size)), ('Offset', str(offset)), ('BasePoint', 'Beginning'), ]) ) else: view_type = calendar_view.to_xml(version=self.account.version) finditem.append(view_type) if restriction: finditem.append(restriction.to_xml(version=self.account.version)) if order_fields: finditem.append(set_xml_value( create_element('m:SortOrder'), order_fields, version=self.account.version )) finditem.append(set_xml_value( create_element('m:ParentFolderIds'), folders, version=self.account.version )) if query_string: finditem.append(query_string.to_xml(version=self.account.version)) return finditem
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var paging_container_name
var supports_paging
Methods
def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view, max_items, offset)
-
Find items in an account.
:param folders: the folders to act on :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param restriction: a Restriction object for :param order_fields: the fields to sort the results by :param shape: The set of attributes to return :param query_string: a QueryString object :param depth: How deep in the folder structure to search for items :param calendar_view: If set, returns recurring calendar items unfolded :param max_items: the max number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0.
:return: XML elements for the matching items
Expand source code
def call(self, folders, additional_fields, restriction, order_fields, shape, query_string, depth, calendar_view, max_items, offset): """Find items in an account. :param folders: the folders to act on :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param restriction: a Restriction object for :param order_fields: the fields to sort the results by :param shape: The set of attributes to return :param query_string: a QueryString object :param depth: How deep in the folder structure to search for items :param calendar_view: If set, returns recurring calendar items unfolded :param max_items: the max number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0. :return: XML elements for the matching items """ self.additional_fields = additional_fields self.shape = shape return self._elems_to_objs(self._paged_call( payload_func=self.get_payload, max_items=max_items, folders=folders, **dict( additional_fields=additional_fields, restriction=restriction, order_fields=order_fields, query_string=query_string, shape=shape, depth=depth, calendar_view=calendar_view, page_size=self.chunk_size, offset=offset, ) ))
def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, calendar_view, page_size, offset=0)
-
Expand source code
def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, calendar_view, page_size, offset=0): finditem = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(Traversal=depth)) itemshape = create_shape_element( tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) finditem.append(itemshape) if calendar_view is None: view_type = create_element( 'm:IndexedPageItemView', attrs=OrderedDict([ ('MaxEntriesReturned', str(page_size)), ('Offset', str(offset)), ('BasePoint', 'Beginning'), ]) ) else: view_type = calendar_view.to_xml(version=self.account.version) finditem.append(view_type) if restriction: finditem.append(restriction.to_xml(version=self.account.version)) if order_fields: finditem.append(set_xml_value( create_element('m:SortOrder'), order_fields, version=self.account.version )) finditem.append(set_xml_value( create_element('m:ParentFolderIds'), folders, version=self.account.version )) if query_string: finditem.append(query_string.to_xml(version=self.account.version)) return finditem
Inherited members
class FindPeople (*args, **kwargs)
-
Expand source code
class FindPeople(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/findpeople-operation""" SERVICE_NAME = 'FindPeople' element_container_name = '{%s}People' % MNS supported_from = EXCHANGE_2013 supports_paging = True def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # A hack to communicate parsing args to _elems_to_objs() self.additional_fields = None self.shape = None def call(self, folder, additional_fields, restriction, order_fields, shape, query_string, depth, max_items, offset): """Find items in an account. :param folder: the Folder object to query :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param restriction: a Restriction object for :param order_fields: the fields to sort the results by :param shape: The set of attributes to return :param query_string: a QueryString object :param depth: How deep in the folder structure to search for items :param max_items: the max number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0. :return: XML elements for the matching items """ self.additional_fields = additional_fields self.shape = shape return self._elems_to_objs(self._paged_call( payload_func=self.get_payload, max_items=max_items, folders=[folder], # We can only query one folder, so there will only be one element in response **dict( additional_fields=additional_fields, restriction=restriction, order_fields=order_fields, query_string=query_string, shape=shape, depth=depth, page_size=self.chunk_size, offset=offset, ) )) def _elems_to_objs(self, elems): from ..items import Persona, ID_ONLY for elem in elems: if isinstance(elem, Exception): yield elem continue if self.shape == ID_ONLY and self.additional_fields is None: yield Persona.id_from_xml(elem) continue yield Persona.from_xml(elem, account=self.account) def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0): folders = list(folders) if len(folders) != 1: raise ValueError('%r can only query one folder' % self.SERVICE_NAME) folder = folders[0] findpeople = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(Traversal=depth)) personashape = create_shape_element( tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) findpeople.append(personashape) view_type = create_element( 'm:IndexedPageItemView', attrs=OrderedDict([ ('MaxEntriesReturned', str(page_size)), ('Offset', str(offset)), ('BasePoint', 'Beginning'), ]) ) findpeople.append(view_type) if restriction: findpeople.append(restriction.to_xml(version=self.account.version)) if order_fields: findpeople.append(set_xml_value( create_element('m:SortOrder'), order_fields, version=self.account.version )) findpeople.append(set_xml_value( create_element('m:ParentFolderId'), folder, version=self.account.version )) if query_string: findpeople.append(query_string.to_xml(version=self.account.version)) return findpeople @staticmethod def _get_paging_values(elem): """Find paging values. The paging element from FindPeople is different from other paging containers.""" item_count = int(elem.find('{%s}TotalNumberOfPeopleInView' % MNS).text) first_matching = int(elem.find('{%s}FirstMatchingRowIndex' % MNS).text) first_loaded = int(elem.find('{%s}FirstLoadedRowIndex' % MNS).text) log.debug('Got page with total items %s, first matching %s, first loaded %s ', item_count, first_matching, first_loaded) next_offset = None # GetPersona does not support fetching more pages return item_count, next_offset
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var supported_from
var supports_paging
Methods
def call(self, folder, additional_fields, restriction, order_fields, shape, query_string, depth, max_items, offset)
-
Find items in an account.
:param folder: the Folder object to query :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param restriction: a Restriction object for :param order_fields: the fields to sort the results by :param shape: The set of attributes to return :param query_string: a QueryString object :param depth: How deep in the folder structure to search for items :param max_items: the max number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0.
:return: XML elements for the matching items
Expand source code
def call(self, folder, additional_fields, restriction, order_fields, shape, query_string, depth, max_items, offset): """Find items in an account. :param folder: the Folder object to query :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param restriction: a Restriction object for :param order_fields: the fields to sort the results by :param shape: The set of attributes to return :param query_string: a QueryString object :param depth: How deep in the folder structure to search for items :param max_items: the max number of items to return :param offset: the offset relative to the first item in the item collection. Usually 0. :return: XML elements for the matching items """ self.additional_fields = additional_fields self.shape = shape return self._elems_to_objs(self._paged_call( payload_func=self.get_payload, max_items=max_items, folders=[folder], # We can only query one folder, so there will only be one element in response **dict( additional_fields=additional_fields, restriction=restriction, order_fields=order_fields, query_string=query_string, shape=shape, depth=depth, page_size=self.chunk_size, offset=offset, ) ))
def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0)
-
Expand source code
def get_payload(self, folders, additional_fields, restriction, order_fields, query_string, shape, depth, page_size, offset=0): folders = list(folders) if len(folders) != 1: raise ValueError('%r can only query one folder' % self.SERVICE_NAME) folder = folders[0] findpeople = create_element('m:%s' % self.SERVICE_NAME, attrs=dict(Traversal=depth)) personashape = create_shape_element( tag='m:PersonaShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) findpeople.append(personashape) view_type = create_element( 'm:IndexedPageItemView', attrs=OrderedDict([ ('MaxEntriesReturned', str(page_size)), ('Offset', str(offset)), ('BasePoint', 'Beginning'), ]) ) findpeople.append(view_type) if restriction: findpeople.append(restriction.to_xml(version=self.account.version)) if order_fields: findpeople.append(set_xml_value( create_element('m:SortOrder'), order_fields, version=self.account.version )) findpeople.append(set_xml_value( create_element('m:ParentFolderId'), folder, version=self.account.version )) if query_string: findpeople.append(query_string.to_xml(version=self.account.version)) return findpeople
Inherited members
class GetAttachment (*args, **kwargs)
-
Expand source code
class GetAttachment(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getattachment-operation""" SERVICE_NAME = 'GetAttachment' element_container_name = '{%s}Attachments' % MNS def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields): if body_type and body_type not in BODY_TYPE_CHOICES: raise ValueError("'body_type' %s must be one of %s" % (body_type, BODY_TYPE_CHOICES)) return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, include_mime_content=include_mime_content, body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields, )) def _elems_to_objs(self, elems): from ..attachments import FileAttachment, ItemAttachment cls_map = {cls.response_tag(): cls for cls in (FileAttachment, ItemAttachment)} for elem in elems: if isinstance(elem, Exception): yield elem continue yield cls_map[elem.tag].from_xml(elem=elem, account=self.account) def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields): payload = create_element('m:%s' % self.SERVICE_NAME) shape_elem = create_element('m:AttachmentShape') if include_mime_content: add_xml_child(shape_elem, 't:IncludeMimeContent', 'true') if body_type: add_xml_child(shape_elem, 't:BodyType', body_type) if filter_html_content is not None: add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false') if additional_fields: additional_properties = create_element('t:AdditionalProperties') expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields)) set_xml_value(additional_properties, sorted( expanded_fields, key=lambda f: (getattr(f.field, 'field_uri', ''), f.path) ), version=self.account.version) shape_elem.append(additional_properties) if len(shape_elem): payload.append(shape_elem) attachment_ids = create_attachment_ids_element(items=items, version=self.account.version) payload.append(attachment_ids) return payload def _update_api_version(self, api_version, header, **parse_opts): if not parse_opts.get('stream_file_content', False): super()._update_api_version(api_version, header, **parse_opts) # TODO: We're skipping this part in streaming mode because StreamingBase64Parser cannot parse the SOAP header @classmethod def _get_soap_parts(cls, response, **parse_opts): if not parse_opts.get('stream_file_content', False): return super()._get_soap_parts(response, **parse_opts) # Pass the response unaltered. We want to use our custom streaming parser return None, response def _get_soap_messages(self, body, **parse_opts): if not parse_opts.get('stream_file_content', False): return super()._get_soap_messages(body, **parse_opts) from ..attachments import FileAttachment # 'body' is actually the raw response passed on by '_get_soap_parts' r = body parser = StreamingBase64Parser() field = FileAttachment.get_field_by_fieldname('_content') handler = StreamingContentHandler(parser=parser, ns=field.namespace, element_name=field.field_uri) parser.setContentHandler(handler) return parser.parse(r) def stream_file_content(self, attachment_id): # The streaming XML parser can only stream content of one attachment payload = self.get_payload( items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None, additional_fields=None, ) self.streaming = True try: yield from self._get_response_xml(payload=payload, stream_file_content=True) except ElementNotFound as enf: # When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse(). # Let the non-streaming SOAP parser parse the response and hook into the normal exception handling. # Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method. response = DummyResponse(url=None, headers=None, request_headers=None, content=enf.data) _, body = super()._get_soap_parts(response=response) res = super()._get_soap_messages(body=body) for e in self._get_elements_in_response(response=res): if isinstance(e, Exception): raise e # The returned content did not contain any EWS exceptions. Give up and re-raise the original exception. raise enf finally: self.streaming = False self.stop_streaming()
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields)
-
Expand source code
def call(self, items, include_mime_content, body_type, filter_html_content, additional_fields): if body_type and body_type not in BODY_TYPE_CHOICES: raise ValueError("'body_type' %s must be one of %s" % (body_type, BODY_TYPE_CHOICES)) return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, include_mime_content=include_mime_content, body_type=body_type, filter_html_content=filter_html_content, additional_fields=additional_fields, ))
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields)
-
Expand source code
def get_payload(self, items, include_mime_content, body_type, filter_html_content, additional_fields): payload = create_element('m:%s' % self.SERVICE_NAME) shape_elem = create_element('m:AttachmentShape') if include_mime_content: add_xml_child(shape_elem, 't:IncludeMimeContent', 'true') if body_type: add_xml_child(shape_elem, 't:BodyType', body_type) if filter_html_content is not None: add_xml_child(shape_elem, 't:FilterHtmlContent', 'true' if filter_html_content else 'false') if additional_fields: additional_properties = create_element('t:AdditionalProperties') expanded_fields = chain(*(f.expand(version=self.account.version) for f in additional_fields)) set_xml_value(additional_properties, sorted( expanded_fields, key=lambda f: (getattr(f.field, 'field_uri', ''), f.path) ), version=self.account.version) shape_elem.append(additional_properties) if len(shape_elem): payload.append(shape_elem) attachment_ids = create_attachment_ids_element(items=items, version=self.account.version) payload.append(attachment_ids) return payload
def stream_file_content(self, attachment_id)
-
Expand source code
def stream_file_content(self, attachment_id): # The streaming XML parser can only stream content of one attachment payload = self.get_payload( items=[attachment_id], include_mime_content=False, body_type=None, filter_html_content=None, additional_fields=None, ) self.streaming = True try: yield from self._get_response_xml(payload=payload, stream_file_content=True) except ElementNotFound as enf: # When the returned XML does not contain a Content element, ElementNotFound is thrown by parser.parse(). # Let the non-streaming SOAP parser parse the response and hook into the normal exception handling. # Wrap in DummyResponse because _get_soap_parts() expects an iter_content() method. response = DummyResponse(url=None, headers=None, request_headers=None, content=enf.data) _, body = super()._get_soap_parts(response=response) res = super()._get_soap_messages(body=body) for e in self._get_elements_in_response(response=res): if isinstance(e, Exception): raise e # The returned content did not contain any EWS exceptions. Give up and re-raise the original exception. raise enf finally: self.streaming = False self.stop_streaming()
Inherited members
class GetDelegate (*args, **kwargs)
-
Expand source code
class GetDelegate(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getdelegate-operation""" SERVICE_NAME = 'GetDelegate' supported_from = EXCHANGE_2007_SP1 def call(self, user_ids, include_permissions): return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=user_ids or [None], mailbox=DLMailbox(email_address=self.account.primary_smtp_address), include_permissions=include_permissions, )) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield DelegateUser.from_xml(elem=elem, account=self.account) def get_payload(self, user_ids, mailbox, include_permissions): payload = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(IncludePermissions='true' if include_permissions else 'false'), ) set_xml_value(payload, mailbox, version=self.protocol.version) if user_ids != [None]: set_xml_value(payload, user_ids, version=self.protocol.version) return payload @classmethod def _get_elements_in_container(cls, container): return container.findall(DelegateUser.response_tag()) @classmethod def _response_message_tag(cls): return '{%s}DelegateUserResponseMessageType' % MNS
Ancestors
Class variables
var SERVICE_NAME
var supported_from
Methods
def call(self, user_ids, include_permissions)
-
Expand source code
def call(self, user_ids, include_permissions): return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=user_ids or [None], mailbox=DLMailbox(email_address=self.account.primary_smtp_address), include_permissions=include_permissions, ))
def get_payload(self, user_ids, mailbox, include_permissions)
-
Expand source code
def get_payload(self, user_ids, mailbox, include_permissions): payload = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(IncludePermissions='true' if include_permissions else 'false'), ) set_xml_value(payload, mailbox, version=self.protocol.version) if user_ids != [None]: set_xml_value(payload, user_ids, version=self.protocol.version) return payload
Inherited members
class GetEvents (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getevents-operation
Expand source code
class GetEvents(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getevents-operation """ SERVICE_NAME = 'GetEvents' prefer_affinity = True def call(self, subscription_id, watermark): return self._elems_to_objs(self._get_elements(payload=self.get_payload( subscription_id=subscription_id, watermark=watermark, ))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield Notification.from_xml(elem=elem, account=None) @classmethod def _get_elements_in_container(cls, container): return container.findall(Notification.response_tag()) def get_payload(self, subscription_id, watermark): getstreamingevents = create_element('m:%s' % self.SERVICE_NAME) add_xml_child(getstreamingevents, 'm:SubscriptionId', subscription_id) add_xml_child(getstreamingevents, 'm:Watermark', watermark) return getstreamingevents
Ancestors
Class variables
var SERVICE_NAME
var prefer_affinity
Methods
def call(self, subscription_id, watermark)
-
Expand source code
def call(self, subscription_id, watermark): return self._elems_to_objs(self._get_elements(payload=self.get_payload( subscription_id=subscription_id, watermark=watermark, )))
def get_payload(self, subscription_id, watermark)
-
Expand source code
def get_payload(self, subscription_id, watermark): getstreamingevents = create_element('m:%s' % self.SERVICE_NAME) add_xml_child(getstreamingevents, 'm:SubscriptionId', subscription_id) add_xml_child(getstreamingevents, 'm:Watermark', watermark) return getstreamingevents
Inherited members
class GetFolder (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getfolder-operation
Expand source code
class GetFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getfolder-operation""" SERVICE_NAME = 'GetFolder' element_container_name = '{%s}Folders' % MNS ERRORS_TO_CATCH_IN_RESPONSE = EWSAccountService.ERRORS_TO_CATCH_IN_RESPONSE + ( ErrorFolderNotFound, ErrorNoPublicFolderReplicaAvailable, ErrorInvalidOperation, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.folders = [] # A hack to communicate parsing args to _elems_to_objs() def call(self, folders, additional_fields, shape): """Take a folder ID and returns the full information for that folder. :param folders: a list of Folder objects :param additional_fields: the extra fields that should be returned with the folder, as FieldPath objects :param shape: The set of attributes to return :return: XML elements for the folders, in stable order """ # We can't easily find the correct folder class from the returned XML. Instead, return objects with the same # class as the folder instance it was requested with. self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice. return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=self.folders, additional_fields=additional_fields, shape=shape, )) def _elems_to_objs(self, elems): for folder, elem in zip(self.folders, elems): if isinstance(elem, Exception): yield elem continue yield parse_folder_elem(elem=elem, folder=folder, account=self.account) def get_payload(self, folders, additional_fields, shape): getfolder = create_element('m:%s' % self.SERVICE_NAME) foldershape = create_shape_element( tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) getfolder.append(foldershape) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) getfolder.append(folder_ids) return getfolder
Ancestors
Class variables
var ERRORS_TO_CATCH_IN_RESPONSE
var SERVICE_NAME
var element_container_name
Methods
def call(self, folders, additional_fields, shape)
-
Take a folder ID and returns the full information for that folder.
:param folders: a list of Folder objects :param additional_fields: the extra fields that should be returned with the folder, as FieldPath objects :param shape: The set of attributes to return
:return: XML elements for the folders, in stable order
Expand source code
def call(self, folders, additional_fields, shape): """Take a folder ID and returns the full information for that folder. :param folders: a list of Folder objects :param additional_fields: the extra fields that should be returned with the folder, as FieldPath objects :param shape: The set of attributes to return :return: XML elements for the folders, in stable order """ # We can't easily find the correct folder class from the returned XML. Instead, return objects with the same # class as the folder instance it was requested with. self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice. return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=self.folders, additional_fields=additional_fields, shape=shape, ))
def get_payload(self, folders, additional_fields, shape)
-
Expand source code
def get_payload(self, folders, additional_fields, shape): getfolder = create_element('m:%s' % self.SERVICE_NAME) foldershape = create_shape_element( tag='m:FolderShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) getfolder.append(foldershape) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) getfolder.append(folder_ids) return getfolder
Inherited members
class GetItem (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getitem-operation
Expand source code
class GetItem(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getitem-operation""" SERVICE_NAME = 'GetItem' element_container_name = '{%s}Items' % MNS def call(self, items, additional_fields, shape): """Return all items in an account that correspond to a list of ID's, in stable order. :param items: a list of (id, changekey) tuples or Item objects :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param shape: The shape of returned objects :return: XML elements for the items, in stable order """ return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, additional_fields=additional_fields, shape=shape, )) def _elems_to_objs(self, elems): from ..folders.base import BaseFolder for elem in elems: if isinstance(elem, Exception): yield elem continue yield BaseFolder.item_model_from_tag(elem.tag).from_xml(elem=elem, account=self.account) def get_payload(self, items, additional_fields, shape): getitem = create_element('m:%s' % self.SERVICE_NAME) itemshape = create_shape_element( tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) getitem.append(itemshape) item_ids = create_item_ids_element(items=items, version=self.account.version) getitem.append(item_ids) return getitem
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, items, additional_fields, shape)
-
Return all items in an account that correspond to a list of ID's, in stable order.
:param items: a list of (id, changekey) tuples or Item objects :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param shape: The shape of returned objects
:return: XML elements for the items, in stable order
Expand source code
def call(self, items, additional_fields, shape): """Return all items in an account that correspond to a list of ID's, in stable order. :param items: a list of (id, changekey) tuples or Item objects :param additional_fields: the extra fields that should be returned with the item, as FieldPath objects :param shape: The shape of returned objects :return: XML elements for the items, in stable order """ return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, additional_fields=additional_fields, shape=shape, ))
def get_payload(self, items, additional_fields, shape)
-
Expand source code
def get_payload(self, items, additional_fields, shape): getitem = create_element('m:%s' % self.SERVICE_NAME) itemshape = create_shape_element( tag='m:ItemShape', shape=shape, additional_fields=additional_fields, version=self.account.version ) getitem.append(itemshape) item_ids = create_item_ids_element(items=items, version=self.account.version) getitem.append(item_ids) return getitem
Inherited members
class GetMailTips (protocol, chunk_size=None, timeout=None)
-
Expand source code
class GetMailTips(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getmailtips-operation""" SERVICE_NAME = 'GetMailTips' def call(self, sending_as, recipients, mail_tips_requested): return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=recipients, sending_as=sending_as, mail_tips_requested=mail_tips_requested, )) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield MailTips.from_xml(elem=elem, account=None) def get_payload(self, recipients, sending_as, mail_tips_requested): payload = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(payload, sending_as, version=self.protocol.version) recipients_elem = create_element('m:Recipients') for recipient in recipients: set_xml_value(recipients_elem, recipient, version=self.protocol.version) if not len(recipients_elem): raise ValueError('"recipients" must not be empty') payload.append(recipients_elem) if mail_tips_requested: set_xml_value(payload, mail_tips_requested, version=self.protocol.version) return payload def _get_elements_in_response(self, response): for msg in response: yield self._get_element_container(message=msg, name=MailTips.response_tag()) @classmethod def _response_message_tag(cls): return '{%s}MailTipsResponseMessageType' % MNS
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self, sending_as, recipients, mail_tips_requested)
-
Expand source code
def call(self, sending_as, recipients, mail_tips_requested): return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=recipients, sending_as=sending_as, mail_tips_requested=mail_tips_requested, ))
def get_payload(self, recipients, sending_as, mail_tips_requested)
-
Expand source code
def get_payload(self, recipients, sending_as, mail_tips_requested): payload = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(payload, sending_as, version=self.protocol.version) recipients_elem = create_element('m:Recipients') for recipient in recipients: set_xml_value(recipients_elem, recipient, version=self.protocol.version) if not len(recipients_elem): raise ValueError('"recipients" must not be empty') payload.append(recipients_elem) if mail_tips_requested: set_xml_value(payload, mail_tips_requested, version=self.protocol.version) return payload
Inherited members
class GetPersona (*args, **kwargs)
-
Expand source code
class GetPersona(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getpersona-operation""" SERVICE_NAME = 'GetPersona' def call(self, persona): return self._elems_to_objs(self._get_elements(payload=self.get_payload(persona=persona))) def _elems_to_objs(self, elems): from ..items import Persona elements = list(elems) if len(elements) != 1: raise ValueError('Expected exactly one element in response') elem = elements[0] if isinstance(elem, Exception): raise elem return Persona.from_xml(elem=elem, account=None) def get_payload(self, persona): version = self.protocol.version payload = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(payload, to_item_id(persona, PersonaId, version=version), version=version) return payload @classmethod def _get_elements_in_container(cls, container): from ..items import Persona return container.findall('{%s}%s' % (MNS, Persona.ELEMENT_NAME)) @classmethod def _response_tag(cls): return '{%s}%sResponseMessage' % (MNS, cls.SERVICE_NAME)
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self, persona)
-
Expand source code
def call(self, persona): return self._elems_to_objs(self._get_elements(payload=self.get_payload(persona=persona)))
def get_payload(self, persona)
-
Expand source code
def get_payload(self, persona): version = self.protocol.version payload = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(payload, to_item_id(persona, PersonaId, version=version), version=version) return payload
Inherited members
class GetRoomLists (protocol, chunk_size=None, timeout=None)
-
Expand source code
class GetRoomLists(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getroomlists-operation""" SERVICE_NAME = 'GetRoomLists' element_container_name = '{%s}RoomLists' % MNS supported_from = EXCHANGE_2010 def call(self): return self._elems_to_objs(self._get_elements(payload=self.get_payload())) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield RoomList.from_xml(elem=elem, account=None) def get_payload(self): return create_element('m:%s' % self.SERVICE_NAME)
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var supported_from
Methods
def call(self)
-
Expand source code
def call(self): return self._elems_to_objs(self._get_elements(payload=self.get_payload()))
def get_payload(self)
-
Expand source code
def get_payload(self): return create_element('m:%s' % self.SERVICE_NAME)
Inherited members
class GetRooms (protocol, chunk_size=None, timeout=None)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getrooms-operation
Expand source code
class GetRooms(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getrooms-operation""" SERVICE_NAME = 'GetRooms' element_container_name = '{%s}Rooms' % MNS supported_from = EXCHANGE_2010 def call(self, roomlist): return self._elems_to_objs(self._get_elements(payload=self.get_payload(roomlist=roomlist))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield Room.from_xml(elem=elem, account=None) def get_payload(self, roomlist): getrooms = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(getrooms, roomlist, version=self.protocol.version) return getrooms
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var supported_from
Methods
def call(self, roomlist)
-
Expand source code
def call(self, roomlist): return self._elems_to_objs(self._get_elements(payload=self.get_payload(roomlist=roomlist)))
def get_payload(self, roomlist)
-
Expand source code
def get_payload(self, roomlist): getrooms = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(getrooms, roomlist, version=self.protocol.version) return getrooms
Inherited members
class GetSearchableMailboxes (protocol, chunk_size=None, timeout=None)
-
Expand source code
class GetSearchableMailboxes(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getsearchablemailboxes-operation """ SERVICE_NAME = 'GetSearchableMailboxes' element_container_name = '{%s}SearchableMailboxes' % MNS failed_mailboxes_container_name = '{%s}FailedMailboxes' % MNS supported_from = EXCHANGE_2013 def call(self, search_filter, expand_group_membership): return self._elems_to_objs(self._get_elements(payload=self.get_payload( search_filter=search_filter, expand_group_membership=expand_group_membership, ))) def _elems_to_objs(self, elems): cls_map = {cls.response_tag(): cls for cls in (SearchableMailbox, FailedMailbox)} for elem in elems: if isinstance(elem, Exception): yield elem continue yield cls_map[elem.tag].from_xml(elem=elem, account=None) def get_payload(self, search_filter, expand_group_membership): payload = create_element('m:%s' % self.SERVICE_NAME) if search_filter: add_xml_child(payload, 'm:SearchFilter', search_filter) if expand_group_membership is not None: add_xml_child(payload, 'm:ExpandGroupMembership', 'true' if expand_group_membership else 'false') return payload def _get_elements_in_response(self, response): for msg in response: for container_name in (self.element_container_name, self.failed_mailboxes_container_name): try: container_or_exc = self._get_element_container(message=msg, name=container_name) except MalformedResponseError: # Responses may contain no failed mailboxes. _get_element_container() does not accept this. if container_name == self.failed_mailboxes_container_name: continue raise if isinstance(container_or_exc, (bool, Exception)): yield container_or_exc continue yield from self._get_elements_in_container(container=container_or_exc)
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var failed_mailboxes_container_name
var supported_from
Methods
def call(self, search_filter, expand_group_membership)
-
Expand source code
def call(self, search_filter, expand_group_membership): return self._elems_to_objs(self._get_elements(payload=self.get_payload( search_filter=search_filter, expand_group_membership=expand_group_membership, )))
def get_payload(self, search_filter, expand_group_membership)
-
Expand source code
def get_payload(self, search_filter, expand_group_membership): payload = create_element('m:%s' % self.SERVICE_NAME) if search_filter: add_xml_child(payload, 'm:SearchFilter', search_filter) if expand_group_membership is not None: add_xml_child(payload, 'm:ExpandGroupMembership', 'true' if expand_group_membership else 'false') return payload
Inherited members
class GetServerTimeZones (protocol, chunk_size=None, timeout=None)
-
Expand source code
class GetServerTimeZones(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getservertimezones-operation """ SERVICE_NAME = 'GetServerTimeZones' element_container_name = '{%s}TimeZoneDefinitions' % MNS supported_from = EXCHANGE_2010 def call(self, timezones=None, return_full_timezone_data=False): return self._elems_to_objs(self._get_elements(payload=self.get_payload( timezones=timezones, return_full_timezone_data=return_full_timezone_data ))) def get_payload(self, timezones, return_full_timezone_data): payload = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(ReturnFullTimeZoneData='true' if return_full_timezone_data else 'false'), ) if timezones is not None: is_empty, timezones = peek(timezones) if not is_empty: tz_ids = create_element('m:Ids') for timezone in timezones: tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id, version=self.protocol.version) tz_ids.append(tz_id) payload.append(tz_ids) return payload def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue tz_id = elem.get('Id') tz_name = elem.get('Name') tz_periods = self._get_periods(elem) tz_transitions_groups = self._get_transitions_groups(elem) tz_transitions = self._get_transitions(elem) yield tz_id, tz_name, tz_periods, tz_transitions, tz_transitions_groups @staticmethod def _get_periods(timezonedef): tz_periods = {} periods = timezonedef.find('{%s}Periods' % TNS) for period in periods.findall('{%s}Period' % TNS): # Convert e.g. "trule:Microsoft/Registry/W. Europe Standard Time/2006-Daylight" to (2006, 'Daylight') p_year, p_type = period.get('Id').rsplit('/', 1)[1].split('-') tz_periods[(int(p_year), p_type)] = dict( name=period.get('Name'), bias=xml_text_to_value(period.get('Bias'), datetime.timedelta) ) return tz_periods @staticmethod def _get_transitions_groups(timezonedef): tz_transitions_groups = {} transitiongroups = timezonedef.find('{%s}TransitionsGroups' % TNS) if transitiongroups is not None: for transitiongroup in transitiongroups.findall('{%s}TransitionsGroup' % TNS): tg_id = int(transitiongroup.get('Id')) tz_transitions_groups[tg_id] = [] for transition in transitiongroup.findall('{%s}Transition' % TNS): # Apply same conversion to To as for period IDs to_year, to_type = transition.find('{%s}To' % TNS).text.rsplit('/', 1)[1].split('-') tz_transitions_groups[tg_id].append(dict( to=(int(to_year), to_type), )) for transition in transitiongroup.findall('{%s}RecurringDayTransition' % TNS): # Apply same conversion to To as for period IDs to_year, to_type = transition.find('{%s}To' % TNS).text.rsplit('/', 1)[1].split('-') occurrence = xml_text_to_value(transition.find('{%s}Occurrence' % TNS).text, int) if occurrence == -1: # See TimeZoneTransition.from_xml() occurrence = 5 tz_transitions_groups[tg_id].append(dict( to=(int(to_year), to_type), offset=xml_text_to_value(transition.find('{%s}TimeOffset' % TNS).text, datetime.timedelta), iso_month=xml_text_to_value(transition.find('{%s}Month' % TNS).text, int), iso_weekday=WEEKDAY_NAMES.index(transition.find('{%s}DayOfWeek' % TNS).text) + 1, occurrence=occurrence, )) return tz_transitions_groups @staticmethod def _get_transitions(timezonedef): tz_transitions = {} transitions = timezonedef.find('{%s}Transitions' % TNS) if transitions is not None: for transition in transitions.findall('{%s}Transition' % TNS): to = transition.find('{%s}To' % TNS) if to.get('Kind') != 'Group': raise ValueError('Unexpected "Kind" XML attr: %s' % to.get('Kind')) tg_id = xml_text_to_value(to.text, int) tz_transitions[tg_id] = None for transition in transitions.findall('{%s}AbsoluteDateTransition' % TNS): to = transition.find('{%s}To' % TNS) if to.get('Kind') != 'Group': raise ValueError('Unexpected "Kind" XML attr: %s' % to.get('Kind')) tg_id = xml_text_to_value(to.text, int) try: t_date = xml_text_to_value(transition.find('{%s}DateTime' % TNS).text, EWSDateTime).date() except NaiveDateTimeNotAllowed as e: # We encountered a naive datetime. Don't worry. we just need the date t_date = e.local_dt.date() tz_transitions[tg_id] = t_date return tz_transitions
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
var supported_from
Methods
def call(self, timezones=None, return_full_timezone_data=False)
-
Expand source code
def call(self, timezones=None, return_full_timezone_data=False): return self._elems_to_objs(self._get_elements(payload=self.get_payload( timezones=timezones, return_full_timezone_data=return_full_timezone_data )))
def get_payload(self, timezones, return_full_timezone_data)
-
Expand source code
def get_payload(self, timezones, return_full_timezone_data): payload = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(ReturnFullTimeZoneData='true' if return_full_timezone_data else 'false'), ) if timezones is not None: is_empty, timezones = peek(timezones) if not is_empty: tz_ids = create_element('m:Ids') for timezone in timezones: tz_id = set_xml_value(create_element('t:Id'), timezone.ms_id, version=self.protocol.version) tz_ids.append(tz_id) payload.append(tz_ids) return payload
Inherited members
class GetStreamingEvents (*args, **kwargs)
-
Expand source code
class GetStreamingEvents(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getstreamingevents-operation """ SERVICE_NAME = 'GetStreamingEvents' element_container_name = '{%s}Notifications' % MNS streaming = True prefer_affinity = True # Connection status values OK = 'OK' CLOSED = 'Closed' def __init__(self, *args, **kwargs): # These values are set each time call() is consumed self.connection_status = None self.error_subscription_ids = [] super().__init__(*args, **kwargs) def call(self, subscription_ids, connection_timeout): if connection_timeout < 1: raise ValueError("'connection_timeout' must be a positive integer") return self._elems_to_objs(self._get_elements(payload=self.get_payload( subscription_ids=subscription_ids, connection_timeout=connection_timeout, ))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield Notification.from_xml(elem=elem, account=None) @classmethod def _get_soap_parts(cls, response, **parse_opts): # Pass the response unaltered. We want to use our custom document yielder return None, response def _get_soap_messages(self, body, **parse_opts): # 'body' is actually the raw response passed on by '_get_soap_parts'. We want to continuously read the content, # looking for complete XML documents. When we have a full document, we want to parse it as if it was a normal # XML response. r = body for i, doc in enumerate(DocumentYielder(r.iter_content()), start=1): xml_log.debug('''Response XML (docs received: %(i)s): %(xml_response)s''', dict(i=i, xml_response=doc)) response = DummyResponse(url=None, headers=None, request_headers=None, content=doc) try: _, body = super()._get_soap_parts(response=response, **parse_opts) except Exception: r.close() # Release memory raise # TODO: We're skipping ._update_api_version() here because we don't have access to the 'api_version' used. # TODO: We should be doing a lot of error handling for ._get_soap_messages(). yield from super()._get_soap_messages(body=body, **parse_opts) if self.connection_status == self.CLOSED: # Don't wait for the TCP connection to timeout break def _get_element_container(self, message, name=None): error_ids_elem = message.find('{%s}ErrorSubscriptionIds' % MNS) if error_ids_elem is not None: self.error_subscription_ids = get_xml_attrs(error_ids_elem, '{%s}ErrorSubscriptionId' % MNS) log.debug('These subscription IDs are invalid: %s', self.error_subscription_ids) self.connection_status = get_xml_attr(message, '{%s}ConnectionStatus' % MNS) # Either 'OK' or 'Closed' log.debug('Connection status is: %s', self.connection_status) # Upstream expects to find a 'name' tag but our response does not always have it. Return an empty element. if message.find(name) is None: return [] return super()._get_element_container(message=message, name=name) def get_payload(self, subscription_ids, connection_timeout): getstreamingevents = create_element('m:%s' % self.SERVICE_NAME) subscriptions_elem = create_element('m:SubscriptionIds') for subscription_id in subscription_ids: add_xml_child(subscriptions_elem, 't:SubscriptionId', subscription_id) if not len(subscriptions_elem): raise ValueError('"subscription_ids" must not be empty') getstreamingevents.append(subscriptions_elem) add_xml_child(getstreamingevents, 'm:ConnectionTimeout', connection_timeout) return getstreamingevents
Ancestors
Class variables
var CLOSED
var OK
var SERVICE_NAME
var element_container_name
var prefer_affinity
var streaming
Methods
def call(self, subscription_ids, connection_timeout)
-
Expand source code
def call(self, subscription_ids, connection_timeout): if connection_timeout < 1: raise ValueError("'connection_timeout' must be a positive integer") return self._elems_to_objs(self._get_elements(payload=self.get_payload( subscription_ids=subscription_ids, connection_timeout=connection_timeout, )))
def get_payload(self, subscription_ids, connection_timeout)
-
Expand source code
def get_payload(self, subscription_ids, connection_timeout): getstreamingevents = create_element('m:%s' % self.SERVICE_NAME) subscriptions_elem = create_element('m:SubscriptionIds') for subscription_id in subscription_ids: add_xml_child(subscriptions_elem, 't:SubscriptionId', subscription_id) if not len(subscriptions_elem): raise ValueError('"subscription_ids" must not be empty') getstreamingevents.append(subscriptions_elem) add_xml_child(getstreamingevents, 'm:ConnectionTimeout', connection_timeout) return getstreamingevents
Inherited members
class GetUserAvailability (protocol, chunk_size=None, timeout=None)
-
Get detailed availability information for a list of users. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseravailability-operation
Expand source code
class GetUserAvailability(EWSService): """Get detailed availability information for a list of users. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseravailability-operation """ SERVICE_NAME = 'GetUserAvailability' def call(self, timezone, mailbox_data, free_busy_view_options): # TODO: Also supports SuggestionsViewOptions, see # https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions return self._elems_to_objs(self._get_elements(payload=self.get_payload( timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options ))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield FreeBusyView.from_xml(elem=elem, account=None) def get_payload(self, timezone, mailbox_data, free_busy_view_options): payload = create_element('m:%sRequest' % self.SERVICE_NAME) set_xml_value(payload, timezone, version=self.protocol.version) mailbox_data_array = create_element('m:MailboxDataArray') set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version) payload.append(mailbox_data_array) set_xml_value(payload, free_busy_view_options, version=self.protocol.version) return payload @staticmethod def _response_messages_tag(): return '{%s}FreeBusyResponseArray' % MNS @classmethod def _response_message_tag(cls): return '{%s}FreeBusyResponse' % MNS def _get_elements_in_response(self, response): for msg in response: # Just check the response code and raise errors self._get_element_container(message=msg.find('{%s}ResponseMessage' % MNS)) yield from self._get_elements_in_container(container=msg) @classmethod def _get_elements_in_container(cls, container): return [container.find('{%s}FreeBusyView' % MNS)]
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self, timezone, mailbox_data, free_busy_view_options)
-
Expand source code
def call(self, timezone, mailbox_data, free_busy_view_options): # TODO: Also supports SuggestionsViewOptions, see # https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/suggestionsviewoptions return self._elems_to_objs(self._get_elements(payload=self.get_payload( timezone=timezone, mailbox_data=mailbox_data, free_busy_view_options=free_busy_view_options )))
def get_payload(self, timezone, mailbox_data, free_busy_view_options)
-
Expand source code
def get_payload(self, timezone, mailbox_data, free_busy_view_options): payload = create_element('m:%sRequest' % self.SERVICE_NAME) set_xml_value(payload, timezone, version=self.protocol.version) mailbox_data_array = create_element('m:MailboxDataArray') set_xml_value(mailbox_data_array, mailbox_data, version=self.protocol.version) payload.append(mailbox_data_array) set_xml_value(payload, free_busy_view_options, version=self.protocol.version) return payload
Inherited members
class GetUserConfiguration (*args, **kwargs)
-
Expand source code
class GetUserConfiguration(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuserconfiguration-operation """ SERVICE_NAME = 'GetUserConfiguration' def call(self, user_configuration_name, properties): if properties not in PROPERTIES_CHOICES: raise ValueError("'properties' %r must be one of %s" % (properties, PROPERTIES_CHOICES)) return self._elems_to_objs(self._get_elements(payload=self.get_payload( user_configuration_name=user_configuration_name, properties=properties ))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield UserConfiguration.from_xml(elem=elem, account=self.account) @classmethod def _get_elements_in_container(cls, container): return container.findall(UserConfiguration.response_tag()) def get_payload(self, user_configuration_name, properties): getuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(getuserconfiguration, user_configuration_name, version=self.account.version) user_configuration_properties = create_element('m:UserConfigurationProperties') set_xml_value(user_configuration_properties, properties, version=self.account.version) getuserconfiguration.append(user_configuration_properties) return getuserconfiguration
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self, user_configuration_name, properties)
-
Expand source code
def call(self, user_configuration_name, properties): if properties not in PROPERTIES_CHOICES: raise ValueError("'properties' %r must be one of %s" % (properties, PROPERTIES_CHOICES)) return self._elems_to_objs(self._get_elements(payload=self.get_payload( user_configuration_name=user_configuration_name, properties=properties )))
def get_payload(self, user_configuration_name, properties)
-
Expand source code
def get_payload(self, user_configuration_name, properties): getuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(getuserconfiguration, user_configuration_name, version=self.account.version) user_configuration_properties = create_element('m:UserConfigurationProperties') set_xml_value(user_configuration_properties, properties, version=self.account.version) getuserconfiguration.append(user_configuration_properties) return getuserconfiguration
Inherited members
class GetUserOofSettings (*args, **kwargs)
-
Get automatic reply settings for the specified mailbox. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseroofsettings-operation
Expand source code
class GetUserOofSettings(EWSAccountService): """Get automatic reply settings for the specified mailbox. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuseroofsettings-operation """ SERVICE_NAME = 'GetUserOofSettings' element_container_name = '{%s}OofSettings' % TNS def call(self, mailbox): return self._elems_to_objs(self._get_elements(payload=self.get_payload(mailbox=mailbox))) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield OofSettings.from_xml(elem=elem, account=self.account) def get_payload(self, mailbox): payload = create_element('m:%sRequest' % self.SERVICE_NAME) return set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version) @classmethod def _get_elements_in_container(cls, container): # This service only returns one result, directly in 'container' return [container] def _get_element_container(self, message, name=None): # This service returns the result container outside the response message super()._get_element_container(message=message.find(self._response_message_tag()), name=None) return message.find(name) @classmethod def _response_message_tag(cls): return '{%s}ResponseMessage' % MNS
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, mailbox)
-
Expand source code
def call(self, mailbox): return self._elems_to_objs(self._get_elements(payload=self.get_payload(mailbox=mailbox)))
def get_payload(self, mailbox)
-
Expand source code
def get_payload(self, mailbox): payload = create_element('m:%sRequest' % self.SERVICE_NAME) return set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version)
Inherited members
class MarkAsJunk (*args, **kwargs)
-
Expand source code
class MarkAsJunk(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/markasjunk-operation""" SERVICE_NAME = 'MarkAsJunk' def call(self, items, is_junk, move_item): return self._elems_to_objs( self._chunked_get_elements(self.get_payload, items=items, is_junk=is_junk, move_item=move_item) ) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, (Exception, type(None))): yield elem continue yield MovedItemId.id_from_xml(elem) @classmethod def _get_elements_in_container(cls, container): return container.findall(MovedItemId.response_tag()) def get_payload(self, items, is_junk, move_item): # Takes a list of items and returns either success or raises an error message mark_as_junk = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(IsJunk='true' if is_junk else 'false', MoveItem='true' if move_item else 'false') ) item_ids = create_item_ids_element(items=items, version=self.account.version) mark_as_junk.append(item_ids) return mark_as_junk
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self, items, is_junk, move_item)
-
Expand source code
def call(self, items, is_junk, move_item): return self._elems_to_objs( self._chunked_get_elements(self.get_payload, items=items, is_junk=is_junk, move_item=move_item) )
def get_payload(self, items, is_junk, move_item)
-
Expand source code
def get_payload(self, items, is_junk, move_item): # Takes a list of items and returns either success or raises an error message mark_as_junk = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(IsJunk='true' if is_junk else 'false', MoveItem='true' if move_item else 'false') ) item_ids = create_item_ids_element(items=items, version=self.account.version) mark_as_junk.append(item_ids) return mark_as_junk
Inherited members
class MoveFolder (*args, **kwargs)
-
Expand source code
class MoveFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/movefolder-operation""" SERVICE_NAME = "MoveFolder" element_container_name = '{%s}Folders' % MNS def call(self, folders, to_folder): from ..folders import BaseFolder, FolderId if not isinstance(to_folder, (BaseFolder, FolderId)): raise ValueError("'to_folder' %r must be a Folder or FolderId instance" % to_folder) return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=folders, to_folder=to_folder)) def _elems_to_objs(self, elems): from ..folders import FolderId for elem in elems: if isinstance(elem, (Exception, type(None))): yield elem continue yield FolderId.from_xml(elem=elem.find(FolderId.response_tag()), account=self.account) def get_payload(self, folders, to_folder): # Takes a list of folders and returns their new folder IDs movefolder = create_element('m:%s' % self.SERVICE_NAME) tofolderid = create_element('m:ToFolderId') set_xml_value(tofolderid, to_folder, version=self.account.version) movefolder.append(tofolderid) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) movefolder.append(folder_ids) return movefolder
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, folders, to_folder)
-
Expand source code
def call(self, folders, to_folder): from ..folders import BaseFolder, FolderId if not isinstance(to_folder, (BaseFolder, FolderId)): raise ValueError("'to_folder' %r must be a Folder or FolderId instance" % to_folder) return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=folders, to_folder=to_folder))
def get_payload(self, folders, to_folder)
-
Expand source code
def get_payload(self, folders, to_folder): # Takes a list of folders and returns their new folder IDs movefolder = create_element('m:%s' % self.SERVICE_NAME) tofolderid = create_element('m:ToFolderId') set_xml_value(tofolderid, to_folder, version=self.account.version) movefolder.append(tofolderid) folder_ids = create_folder_ids_element(tag='m:FolderIds', folders=folders, version=self.account.version) movefolder.append(folder_ids) return movefolder
Inherited members
class MoveItem (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveitem-operation
Expand source code
class MoveItem(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/moveitem-operation""" SERVICE_NAME = 'MoveItem' element_container_name = '{%s}Items' % MNS def call(self, items, to_folder): from ..folders import BaseFolder, FolderId if not isinstance(to_folder, (BaseFolder, FolderId)): raise ValueError("'to_folder' %r must be a Folder or FolderId instance" % to_folder) return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder)) def _elems_to_objs(self, elems): from ..items import Item for elem in elems: if isinstance(elem, (Exception, type(None))): yield elem continue yield Item.id_from_xml(elem) def get_payload(self, items, to_folder): # Takes a list of items and returns their new item IDs moveitem = create_element('m:%s' % self.SERVICE_NAME) tofolderid = create_element('m:ToFolderId') set_xml_value(tofolderid, to_folder, version=self.account.version) moveitem.append(tofolderid) item_ids = create_item_ids_element(items=items, version=self.account.version) moveitem.append(item_ids) return moveitem
Ancestors
Subclasses
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, items, to_folder)
-
Expand source code
def call(self, items, to_folder): from ..folders import BaseFolder, FolderId if not isinstance(to_folder, (BaseFolder, FolderId)): raise ValueError("'to_folder' %r must be a Folder or FolderId instance" % to_folder) return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items, to_folder=to_folder))
def get_payload(self, items, to_folder)
-
Expand source code
def get_payload(self, items, to_folder): # Takes a list of items and returns their new item IDs moveitem = create_element('m:%s' % self.SERVICE_NAME) tofolderid = create_element('m:ToFolderId') set_xml_value(tofolderid, to_folder, version=self.account.version) moveitem.append(tofolderid) item_ids = create_item_ids_element(items=items, version=self.account.version) moveitem.append(item_ids) return moveitem
Inherited members
class ResolveNames (*args, **kwargs)
-
Expand source code
class ResolveNames(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/resolvenames-operation""" SERVICE_NAME = 'ResolveNames' element_container_name = '{%s}ResolutionSet' % MNS ERRORS_TO_CATCH_IN_RESPONSE = ErrorNameResolutionNoResults WARNINGS_TO_IGNORE_IN_RESPONSE = ErrorNameResolutionMultipleResults # Note: paging information is returned as attrs on the 'ResolutionSet' element, but this service does not # support the 'IndexedPageItemView' element, so it's not really a paging service. According to docs, at most # 100 candidates are returned for a lookup. supports_paging = False def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.return_full_contact_data = False # A hack to communicate parsing args to _elems_to_objs() def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None, contact_data_shape=None): from ..items import SHAPE_CHOICES, SEARCH_SCOPE_CHOICES if self.chunk_size > 100: log.warning( 'Chunk size %s is dangerously high. %s supports returning at most 100 candidates for a lookup', self.chunk_size, self.SERVICE_NAME ) if search_scope and search_scope not in SEARCH_SCOPE_CHOICES: raise ValueError("'search_scope' %s must be one if %s" % (search_scope, SEARCH_SCOPE_CHOICES)) if contact_data_shape and contact_data_shape not in SHAPE_CHOICES: raise ValueError("'shape' %s must be one if %s" % (contact_data_shape, SHAPE_CHOICES)) self.return_full_contact_data = return_full_contact_data return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=unresolved_entries, parent_folders=parent_folders, return_full_contact_data=return_full_contact_data, search_scope=search_scope, contact_data_shape=contact_data_shape, )) def _elems_to_objs(self, elems): from ..items import Contact for elem in elems: if isinstance(elem, Exception): yield elem continue if self.return_full_contact_data: mailbox_elem = elem.find(Mailbox.response_tag()) contact_elem = elem.find(Contact.response_tag()) yield ( None if mailbox_elem is None else Mailbox.from_xml(elem=mailbox_elem, account=None), None if contact_elem is None else Contact.from_xml(elem=contact_elem, account=None), ) else: yield Mailbox.from_xml(elem=elem.find(Mailbox.response_tag()), account=None) def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape): payload = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(ReturnFullContactData='true' if return_full_contact_data else 'false'), ) if search_scope: payload.set('SearchScope', search_scope) if contact_data_shape: if self.protocol.version.build < EXCHANGE_2010_SP2: raise NotImplementedError( "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later") payload.set('ContactDataShape', contact_data_shape) if parent_folders: parentfolderids = create_element('m:ParentFolderIds') set_xml_value(parentfolderids, parent_folders, version=self.protocol.version) for entry in unresolved_entries: add_xml_child(payload, 'm:UnresolvedEntry', entry) if not len(payload): raise ValueError('"unresolved_entries" must not be empty') return payload
Ancestors
Class variables
var ERRORS_TO_CATCH_IN_RESPONSE
-
Global error type within this module.
var SERVICE_NAME
var WARNINGS_TO_IGNORE_IN_RESPONSE
-
Global error type within this module.
var element_container_name
var supports_paging
Methods
def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None, contact_data_shape=None)
-
Expand source code
def call(self, unresolved_entries, parent_folders=None, return_full_contact_data=False, search_scope=None, contact_data_shape=None): from ..items import SHAPE_CHOICES, SEARCH_SCOPE_CHOICES if self.chunk_size > 100: log.warning( 'Chunk size %s is dangerously high. %s supports returning at most 100 candidates for a lookup', self.chunk_size, self.SERVICE_NAME ) if search_scope and search_scope not in SEARCH_SCOPE_CHOICES: raise ValueError("'search_scope' %s must be one if %s" % (search_scope, SEARCH_SCOPE_CHOICES)) if contact_data_shape and contact_data_shape not in SHAPE_CHOICES: raise ValueError("'shape' %s must be one if %s" % (contact_data_shape, SHAPE_CHOICES)) self.return_full_contact_data = return_full_contact_data return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=unresolved_entries, parent_folders=parent_folders, return_full_contact_data=return_full_contact_data, search_scope=search_scope, contact_data_shape=contact_data_shape, ))
def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape)
-
Expand source code
def get_payload(self, unresolved_entries, parent_folders, return_full_contact_data, search_scope, contact_data_shape): payload = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(ReturnFullContactData='true' if return_full_contact_data else 'false'), ) if search_scope: payload.set('SearchScope', search_scope) if contact_data_shape: if self.protocol.version.build < EXCHANGE_2010_SP2: raise NotImplementedError( "'contact_data_shape' is only supported for Exchange 2010 SP2 servers and later") payload.set('ContactDataShape', contact_data_shape) if parent_folders: parentfolderids = create_element('m:ParentFolderIds') set_xml_value(parentfolderids, parent_folders, version=self.protocol.version) for entry in unresolved_entries: add_xml_child(payload, 'm:UnresolvedEntry', entry) if not len(payload): raise ValueError('"unresolved_entries" must not be empty') return payload
Inherited members
class SendItem (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/senditem-operation
Expand source code
class SendItem(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/senditem-operation""" SERVICE_NAME = 'SendItem' returns_elements = False def call(self, items, saved_item_folder): from ..folders import BaseFolder, FolderId if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)): raise ValueError("'saved_item_folder' %r must be a Folder or FolderId instance" % saved_item_folder) return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder) def get_payload(self, items, saved_item_folder): senditem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(SaveItemToFolder='true' if saved_item_folder else 'false'), ) item_ids = create_item_ids_element(items=items, version=self.account.version) senditem.append(item_ids) if saved_item_folder: saveditemfolderid = create_element('m:SavedItemFolderId') set_xml_value(saveditemfolderid, saved_item_folder, version=self.account.version) senditem.append(saveditemfolderid) return senditem
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, items, saved_item_folder)
-
Expand source code
def call(self, items, saved_item_folder): from ..folders import BaseFolder, FolderId if saved_item_folder and not isinstance(saved_item_folder, (BaseFolder, FolderId)): raise ValueError("'saved_item_folder' %r must be a Folder or FolderId instance" % saved_item_folder) return self._chunked_get_elements(self.get_payload, items=items, saved_item_folder=saved_item_folder)
def get_payload(self, items, saved_item_folder)
-
Expand source code
def get_payload(self, items, saved_item_folder): senditem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=dict(SaveItemToFolder='true' if saved_item_folder else 'false'), ) item_ids = create_item_ids_element(items=items, version=self.account.version) senditem.append(item_ids) if saved_item_folder: saveditemfolderid = create_element('m:SavedItemFolderId') set_xml_value(saveditemfolderid, saved_item_folder, version=self.account.version) senditem.append(saveditemfolderid) return senditem
Inherited members
class SendNotification (protocol, chunk_size=None, timeout=None)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sendnotification
This is not an actual EWS service you can call. We only use it to parse the XML body of push notifications.
Expand source code
class SendNotification(EWSService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/sendnotification This is not an actual EWS service you can call. We only use it to parse the XML body of push notifications. """ SERVICE_NAME = 'SendNotification' def call(self): raise NotImplementedError() def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield Notification.from_xml(elem=elem, account=None) @classmethod def _response_tag(cls): """Return the name of the element containing the service response.""" return '{%s}%s' % (MNS, cls.SERVICE_NAME) @classmethod def _get_elements_in_container(cls, container): return container.findall(Notification.response_tag())
Ancestors
Class variables
var SERVICE_NAME
Methods
def call(self)
-
Expand source code
def call(self): raise NotImplementedError()
Inherited members
class SetUserOofSettings (*args, **kwargs)
-
Set automatic replies for the specified mailbox. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/setuseroofsettings-operation
Expand source code
class SetUserOofSettings(EWSAccountService): """Set automatic replies for the specified mailbox. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/setuseroofsettings-operation """ SERVICE_NAME = 'SetUserOofSettings' returns_elements = False def call(self, oof_settings, mailbox): if not isinstance(oof_settings, OofSettings): raise ValueError("'oof_settings' %r must be an OofSettings instance" % oof_settings) if not isinstance(mailbox, Mailbox): raise ValueError("'mailbox' %r must be an Mailbox instance" % mailbox) return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox)) def get_payload(self, oof_settings, mailbox): payload = create_element('m:%sRequest' % self.SERVICE_NAME) set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version) set_xml_value(payload, oof_settings, version=self.account.version) return payload def _get_element_container(self, message, name=None): message = message.find(self._response_message_tag()) return super()._get_element_container(message=message, name=name) @classmethod def _response_message_tag(cls): return '{%s}ResponseMessage' % MNS
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, oof_settings, mailbox)
-
Expand source code
def call(self, oof_settings, mailbox): if not isinstance(oof_settings, OofSettings): raise ValueError("'oof_settings' %r must be an OofSettings instance" % oof_settings) if not isinstance(mailbox, Mailbox): raise ValueError("'mailbox' %r must be an Mailbox instance" % mailbox) return self._get_elements(payload=self.get_payload(oof_settings=oof_settings, mailbox=mailbox))
def get_payload(self, oof_settings, mailbox)
-
Expand source code
def get_payload(self, oof_settings, mailbox): payload = create_element('m:%sRequest' % self.SERVICE_NAME) set_xml_value(payload, AvailabilityMailbox.from_mailbox(mailbox), version=self.account.version) set_xml_value(payload, oof_settings, version=self.account.version) return payload
Inherited members
class SubscribeToPull (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation
Expand source code
class SubscribeToPull(Subscribe): subscription_request_elem_tag = 'm:PullSubscriptionRequest' def call(self, folders, event_types, watermark, timeout): yield from self._partial_call( payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout, watermark=watermark, ) def get_payload(self, folders, event_types, watermark, timeout): subscribe = create_element('m:%s' % self.SERVICE_NAME) request_elem = self._partial_payload(folders=folders, event_types=event_types) if watermark: add_xml_child(request_elem, 'm:Watermark', watermark) add_xml_child(request_elem, 't:Timeout', timeout) # In minutes subscribe.append(request_elem) return subscribe
Ancestors
Class variables
var subscription_request_elem_tag
Methods
def call(self, folders, event_types, watermark, timeout)
-
Expand source code
def call(self, folders, event_types, watermark, timeout): yield from self._partial_call( payload_func=self.get_payload, folders=folders, event_types=event_types, timeout=timeout, watermark=watermark, )
def get_payload(self, folders, event_types, watermark, timeout)
-
Expand source code
def get_payload(self, folders, event_types, watermark, timeout): subscribe = create_element('m:%s' % self.SERVICE_NAME) request_elem = self._partial_payload(folders=folders, event_types=event_types) if watermark: add_xml_child(request_elem, 'm:Watermark', watermark) add_xml_child(request_elem, 't:Timeout', timeout) # In minutes subscribe.append(request_elem) return subscribe
Inherited members
class SubscribeToPush (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation
Expand source code
class SubscribeToPush(Subscribe): subscription_request_elem_tag = 'm:PushSubscriptionRequest' def call(self, folders, event_types, watermark, status_frequency, url): yield from self._partial_call( payload_func=self.get_payload, folders=folders, event_types=event_types, status_frequency=status_frequency, url=url, watermark=watermark, ) def get_payload(self, folders, event_types, watermark, status_frequency, url): subscribe = create_element('m:%s' % self.SERVICE_NAME) request_elem = self._partial_payload(folders=folders, event_types=event_types) if watermark: add_xml_child(request_elem, 'm:Watermark', watermark) add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes add_xml_child(request_elem, 't:URL', url) subscribe.append(request_elem) return subscribe
Ancestors
Class variables
var subscription_request_elem_tag
Methods
def call(self, folders, event_types, watermark, status_frequency, url)
-
Expand source code
def call(self, folders, event_types, watermark, status_frequency, url): yield from self._partial_call( payload_func=self.get_payload, folders=folders, event_types=event_types, status_frequency=status_frequency, url=url, watermark=watermark, )
def get_payload(self, folders, event_types, watermark, status_frequency, url)
-
Expand source code
def get_payload(self, folders, event_types, watermark, status_frequency, url): subscribe = create_element('m:%s' % self.SERVICE_NAME) request_elem = self._partial_payload(folders=folders, event_types=event_types) if watermark: add_xml_child(request_elem, 'm:Watermark', watermark) add_xml_child(request_elem, 't:StatusFrequency', status_frequency) # In minutes add_xml_child(request_elem, 't:URL', url) subscribe.append(request_elem) return subscribe
Inherited members
class SubscribeToStreaming (*args, **kwargs)
-
MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation
Expand source code
class SubscribeToStreaming(Subscribe): subscription_request_elem_tag = 'm:StreamingSubscriptionRequest' def call(self, folders, event_types): yield from self._partial_call(payload_func=self.get_payload, folders=folders, event_types=event_types) def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield elem.text @classmethod def _get_elements_in_container(cls, container): return [container.find('{%s}SubscriptionId' % MNS)] def get_payload(self, folders, event_types): subscribe = create_element('m:%s' % self.SERVICE_NAME) request_elem = self._partial_payload(folders=folders, event_types=event_types) subscribe.append(request_elem) return subscribe
Ancestors
Class variables
var subscription_request_elem_tag
Methods
def call(self, folders, event_types)
-
Expand source code
def call(self, folders, event_types): yield from self._partial_call(payload_func=self.get_payload, folders=folders, event_types=event_types)
def get_payload(self, folders, event_types)
-
Expand source code
def get_payload(self, folders, event_types): subscribe = create_element('m:%s' % self.SERVICE_NAME) request_elem = self._partial_payload(folders=folders, event_types=event_types) subscribe.append(request_elem) return subscribe
Inherited members
class SyncFolderHierarchy (*args, **kwargs)
-
Expand source code
class SyncFolderHierarchy(SyncFolder): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/syncfolderhierarchy-operation """ SERVICE_NAME = 'SyncFolderHierarchy' shape_tag = 'm:FolderShape' last_in_range_name = '{%s}IncludesLastFolderInRange' % MNS def call(self, folder, shape, additional_fields, sync_state): self.sync_state = sync_state change_types = self._change_types_map() for elem in self._get_elements(payload=self.get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state, )): if isinstance(elem, Exception): yield elem continue change_type = change_types[elem.tag] if change_type == self.DELETE: folder = FolderId.from_xml(elem=elem.find(FolderId.response_tag()), account=self.account) else: # We can't find() the element because we don't know which tag to look for. The change element can # contain multiple folder types, each with their own tag. folder_elem = elem[0] folder = parse_folder_elem(elem=folder_elem, folder=folder, account=self.account) yield change_type, folder def get_payload(self, folder, shape, additional_fields, sync_state): return self._partial_get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state )
Ancestors
Class variables
var SERVICE_NAME
var last_in_range_name
var shape_tag
Methods
def call(self, folder, shape, additional_fields, sync_state)
-
Expand source code
def call(self, folder, shape, additional_fields, sync_state): self.sync_state = sync_state change_types = self._change_types_map() for elem in self._get_elements(payload=self.get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state, )): if isinstance(elem, Exception): yield elem continue change_type = change_types[elem.tag] if change_type == self.DELETE: folder = FolderId.from_xml(elem=elem.find(FolderId.response_tag()), account=self.account) else: # We can't find() the element because we don't know which tag to look for. The change element can # contain multiple folder types, each with their own tag. folder_elem = elem[0] folder = parse_folder_elem(elem=folder_elem, folder=folder, account=self.account) yield change_type, folder
def get_payload(self, folder, shape, additional_fields, sync_state)
-
Expand source code
def get_payload(self, folder, shape, additional_fields, sync_state): return self._partial_get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state )
Inherited members
class SyncFolderItems (*args, **kwargs)
-
Expand source code
class SyncFolderItems(SyncFolder): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/syncfolderitems-operation """ SERVICE_NAME = 'SyncFolderItems' SYNC_SCOPES = { 'NormalItems', 'NormalAndAssociatedItems', } # Extra change type READ_FLAG_CHANGE = 'read_flag_change' CHANGE_TYPES = SyncFolder.CHANGE_TYPES + (READ_FLAG_CHANGE,) shape_tag = 'm:ItemShape' last_in_range_name = '{%s}IncludesLastItemInRange' % MNS def _change_types_map(self): res = super()._change_types_map() res['{%s}ReadFlagChange' % TNS] = self.READ_FLAG_CHANGE return res def call(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope): self.sync_state = sync_state if max_changes_returned is None: max_changes_returned = self.chunk_size if max_changes_returned <= 0: raise ValueError("'max_changes_returned' %s must be a positive integer" % max_changes_returned) if sync_scope is not None and sync_scope not in self.SYNC_SCOPES: raise ValueError("'sync_scope' %s must be one of %r" % (sync_scope, self.SYNC_SCOPES)) return self._elems_to_objs(self._get_elements(payload=self.get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state, ignore=ignore, max_changes_returned=max_changes_returned, sync_scope=sync_scope, ))) def _elems_to_objs(self, elems): from ..folders.base import BaseFolder change_types = self._change_types_map() for elem in elems: if isinstance(elem, Exception): yield elem continue change_type = change_types[elem.tag] if change_type == self.READ_FLAG_CHANGE: item = ( ItemId.from_xml(elem=elem.find(ItemId.response_tag()), account=self.account), xml_text_to_value(elem.find('{%s}IsRead' % TNS).text, bool) ) elif change_type == self.DELETE: item = ItemId.from_xml(elem=elem.find(ItemId.response_tag()), account=self.account) else: # We can't find() the element because we don't know which tag to look for. The change element can # contain multiple item types, each with their own tag. item_elem = elem[0] item = BaseFolder.item_model_from_tag(item_elem.tag).from_xml(elem=item_elem, account=self.account) yield change_type, item def get_payload(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope): syncfolderitems = self._partial_get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state ) is_empty, ignore = (True, None) if ignore is None else peek(ignore) if not is_empty: item_ids = create_item_ids_element(items=ignore, version=self.account.version, tag='m:Ignore') syncfolderitems.append(item_ids) add_xml_child(syncfolderitems, 'm:MaxChangesReturned', max_changes_returned) if sync_scope: add_xml_child(syncfolderitems, 'm:SyncScope', sync_scope) return syncfolderitems
Ancestors
Class variables
var CHANGE_TYPES
var READ_FLAG_CHANGE
var SERVICE_NAME
var SYNC_SCOPES
var last_in_range_name
var shape_tag
Methods
def call(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope)
-
Expand source code
def call(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope): self.sync_state = sync_state if max_changes_returned is None: max_changes_returned = self.chunk_size if max_changes_returned <= 0: raise ValueError("'max_changes_returned' %s must be a positive integer" % max_changes_returned) if sync_scope is not None and sync_scope not in self.SYNC_SCOPES: raise ValueError("'sync_scope' %s must be one of %r" % (sync_scope, self.SYNC_SCOPES)) return self._elems_to_objs(self._get_elements(payload=self.get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state, ignore=ignore, max_changes_returned=max_changes_returned, sync_scope=sync_scope, )))
def get_payload(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope)
-
Expand source code
def get_payload(self, folder, shape, additional_fields, sync_state, ignore, max_changes_returned, sync_scope): syncfolderitems = self._partial_get_payload( folder=folder, shape=shape, additional_fields=additional_fields, sync_state=sync_state ) is_empty, ignore = (True, None) if ignore is None else peek(ignore) if not is_empty: item_ids = create_item_ids_element(items=ignore, version=self.account.version, tag='m:Ignore') syncfolderitems.append(item_ids) add_xml_child(syncfolderitems, 'm:MaxChangesReturned', max_changes_returned) if sync_scope: add_xml_child(syncfolderitems, 'm:SyncScope', sync_scope) return syncfolderitems
Inherited members
class Unsubscribe (*args, **kwargs)
-
Unsubscribing is only valid for pull and streaming notifications.
Expand source code
class Unsubscribe(EWSAccountService): """Unsubscribing is only valid for pull and streaming notifications. MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/unsubscribe-operation """ SERVICE_NAME = 'Unsubscribe' returns_elements = False def call(self, subscription_id): return self._get_elements(payload=self.get_payload(subscription_id=subscription_id)) def get_payload(self, subscription_id): unsubscribe = create_element('m:%s' % self.SERVICE_NAME) add_xml_child(unsubscribe, 'm:SubscriptionId', subscription_id) return unsubscribe
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, subscription_id)
-
Expand source code
def call(self, subscription_id): return self._get_elements(payload=self.get_payload(subscription_id=subscription_id))
def get_payload(self, subscription_id)
-
Expand source code
def get_payload(self, subscription_id): unsubscribe = create_element('m:%s' % self.SERVICE_NAME) add_xml_child(unsubscribe, 'm:SubscriptionId', subscription_id) return unsubscribe
Inherited members
class UpdateFolder (*args, **kwargs)
-
Expand source code
class UpdateFolder(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updatefolder-operation""" SERVICE_NAME = 'UpdateFolder' element_container_name = '{%s}Folders' % MNS def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.folders = [] # A hack to communicate parsing args to _elems_to_objs() def call(self, folders): # We can't easily find the correct folder class from the returned XML. Instead, return objects with the same # class as the folder instance it was requested with. self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice. return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=self.folders)) def _elems_to_objs(self, elems): for (folder, _), elem in zip(self.folders, elems): if isinstance(elem, Exception): yield elem continue yield parse_folder_elem(elem=elem, folder=folder, account=self.account) @staticmethod def _sort_fieldnames(folder_model, fieldnames): # Take a list of fieldnames and return the fields in the order they are mentioned in folder_model.FIELDS. # Loop over FIELDS and not supported_fields(). Upstream should make sure not to update a non-supported field. for f in folder_model.FIELDS: if f.name in fieldnames: yield f.name def _set_folder_elem(self, folder_model, field_path, value): setfolderfield = create_element('t:SetFolderField') set_xml_value(setfolderfield, field_path, version=self.account.version) folder = create_element(folder_model.request_tag()) field_elem = field_path.field.to_xml(value, version=self.account.version) set_xml_value(folder, field_elem, version=self.account.version) setfolderfield.append(folder) return setfolderfield def _delete_folder_elem(self, field_path): deletefolderfield = create_element('t:DeleteFolderField') return set_xml_value(deletefolderfield, field_path, version=self.account.version) def _get_folder_update_elems(self, folder, fieldnames): folder_model = folder.__class__ fieldnames_set = set(fieldnames) for fieldname in self._sort_fieldnames(folder_model=folder_model, fieldnames=fieldnames_set): field = folder_model.get_field_by_fieldname(fieldname) if field.is_read_only: raise ValueError('%s is a read-only field' % field.name) value = field.clean(getattr(folder, field.name), version=self.account.version) # Make sure the value is OK if value is None or (field.is_list and not value): # A value of None or [] means we want to remove this field from the item if field.is_required or field.is_required_after_save: raise ValueError('%s is a required field and may not be deleted' % field.name) for field_path in FieldPath(field=field).expand(version=self.account.version): yield self._delete_folder_elem(field_path=field_path) continue yield self._set_folder_elem(folder_model=folder_model, field_path=FieldPath(field=field), value=value) def get_payload(self, folders): from ..folders import BaseFolder, FolderId updatefolder = create_element('m:%s' % self.SERVICE_NAME) folderchanges = create_element('m:FolderChanges') version = self.account.version for folder, fieldnames in folders: folderchange = create_element('t:FolderChange') if not isinstance(folder, (BaseFolder, FolderId)): folder = to_item_id(folder, FolderId, version=version) set_xml_value(folderchange, folder, version=version) updates = create_element('t:Updates') for elem in self._get_folder_update_elems(folder=folder, fieldnames=fieldnames): updates.append(elem) folderchange.append(updates) folderchanges.append(folderchange) if not len(folderchanges): raise ValueError('"folders" must not be empty') updatefolder.append(folderchanges) return updatefolder
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, folders)
-
Expand source code
def call(self, folders): # We can't easily find the correct folder class from the returned XML. Instead, return objects with the same # class as the folder instance it was requested with. self.folders = list(folders) # Convert to a list, in case 'folders' is a generator. We're iterating twice. return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=self.folders))
def get_payload(self, folders)
-
Expand source code
def get_payload(self, folders): from ..folders import BaseFolder, FolderId updatefolder = create_element('m:%s' % self.SERVICE_NAME) folderchanges = create_element('m:FolderChanges') version = self.account.version for folder, fieldnames in folders: folderchange = create_element('t:FolderChange') if not isinstance(folder, (BaseFolder, FolderId)): folder = to_item_id(folder, FolderId, version=version) set_xml_value(folderchange, folder, version=version) updates = create_element('t:Updates') for elem in self._get_folder_update_elems(folder=folder, fieldnames=fieldnames): updates.append(elem) folderchange.append(updates) folderchanges.append(folderchange) if not len(folderchanges): raise ValueError('"folders" must not be empty') updatefolder.append(folderchanges) return updatefolder
Inherited members
class UpdateItem (*args, **kwargs)
-
Expand source code
class UpdateItem(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateitem-operation""" SERVICE_NAME = 'UpdateItem' element_container_name = '{%s}Items' % MNS def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations, suppress_read_receipts): from ..items import CONFLICT_RESOLUTION_CHOICES, MESSAGE_DISPOSITION_CHOICES, \ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES, SEND_ONLY if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES: raise ValueError("'conflict_resolution' %s must be one of %s" % ( conflict_resolution, CONFLICT_RESOLUTION_CHOICES )) if message_disposition not in MESSAGE_DISPOSITION_CHOICES: raise ValueError("'message_disposition' %s must be one of %s" % ( message_disposition, MESSAGE_DISPOSITION_CHOICES )) if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES: raise ValueError("'send_meeting_invitations_or_cancellations' %s must be one of %s" % ( send_meeting_invitations_or_cancellations, SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES )) if suppress_read_receipts not in (True, False): raise ValueError("'suppress_read_receipts' %s must be True or False" % suppress_read_receipts) if message_disposition == SEND_ONLY: raise ValueError('Cannot send-only existing objects. Use SendItem service instead') return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, conflict_resolution=conflict_resolution, message_disposition=message_disposition, send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations, suppress_read_receipts=suppress_read_receipts, )) def _elems_to_objs(self, elems): from ..items import Item for elem in elems: if isinstance(elem, (Exception, type(None))): yield elem continue yield Item.id_from_xml(elem) def _delete_item_elem(self, field_path): deleteitemfield = create_element('t:DeleteItemField') return set_xml_value(deleteitemfield, field_path, version=self.account.version) def _set_item_elem(self, item_model, field_path, value): setitemfield = create_element('t:SetItemField') set_xml_value(setitemfield, field_path, version=self.account.version) item_elem = create_element(item_model.request_tag()) field_elem = field_path.field.to_xml(value, version=self.account.version) set_xml_value(item_elem, field_elem, version=self.account.version) setitemfield.append(item_elem) return setitemfield @staticmethod def _sorted_fields(item_model, fieldnames): # Take a list of fieldnames and return the (unique) fields in the order they are mentioned in item_class.FIELDS. # Checks that all fieldnames are valid. unique_fieldnames = list(OrderedDict.fromkeys(fieldnames)) # Make field names unique ,but keep ordering # Loop over FIELDS and not supported_fields(). Upstream should make sure not to update a non-supported field. for f in item_model.FIELDS: if f.name in unique_fieldnames: unique_fieldnames.remove(f.name) yield f if unique_fieldnames: raise ValueError("Field name(s) %s are not valid for a '%s' item" % ( ', '.join("'%s'" % f for f in unique_fieldnames), item_model.__name__)) def _get_item_update_elems(self, item, fieldnames): from ..items import CalendarItem fieldnames_copy = list(fieldnames) if item.__class__ == CalendarItem: # For CalendarItem items where we update 'start' or 'end', we want to update internal timezone fields item.clean_timezone_fields(version=self.account.version) # Possibly also sets timezone values for field_name in ('start', 'end'): if field_name in fieldnames_copy: tz_field_name = item.tz_field_for_field_name(field_name).name if tz_field_name not in fieldnames_copy: fieldnames_copy.append(tz_field_name) for field in self._sorted_fields(item_model=item.__class__, fieldnames=fieldnames_copy): if field.is_read_only: raise ValueError('%s is a read-only field' % field.name) value = self._get_item_value(item, field) if value is None or (field.is_list and not value): # A value of None or [] means we want to remove this field from the item yield from self._get_delete_item_elems(field=field) else: yield from self._get_set_item_elems(item_model=item.__class__, field=field, value=value) def _get_item_value(self, item, field): from ..items import CalendarItem value = field.clean(getattr(item, field.name), version=self.account.version) # Make sure the value is OK if item.__class__ == CalendarItem: # For CalendarItem items where we update 'start' or 'end', we want to send values in the local timezone if field.name in ('start', 'end'): if type(value) is EWSDate: # EWS always expects a datetime return item.date_to_datetime(field_name=field.name) tz_field_name = item.tz_field_for_field_name(field.name).name return value.astimezone(getattr(item, tz_field_name)) return value def _get_delete_item_elems(self, field): if field.is_required or field.is_required_after_save: raise ValueError('%s is a required field and may not be deleted' % field.name) for field_path in FieldPath(field=field).expand(version=self.account.version): yield self._delete_item_elem(field_path=field_path) def _get_set_item_elems(self, item_model, field, value): if isinstance(field, IndexedField): # Generate either set or delete elements for all combinations of labels and subfields supported_labels = field.value_cls.get_field_by_fieldname('label')\ .supported_choices(version=self.account.version) seen_labels = set() subfields = field.value_cls.supported_fields(version=self.account.version) for v in value: seen_labels.add(v.label) for subfield in subfields: field_path = FieldPath(field=field, label=v.label, subfield=subfield) subfield_value = getattr(v, subfield.name) if not subfield_value: # Generate delete elements for blank subfield values yield self._delete_item_elem(field_path=field_path) else: # Generate set elements for non-null subfield values yield self._set_item_elem( item_model=item_model, field_path=field_path, value=field.value_cls(**{'label': v.label, subfield.name: subfield_value}), ) # Generate delete elements for all subfields of all labels not mentioned in the list of values for label in (label for label in supported_labels if label not in seen_labels): for subfield in subfields: yield self._delete_item_elem(field_path=FieldPath(field=field, label=label, subfield=subfield)) else: yield self._set_item_elem(item_model=item_model, field_path=FieldPath(field=field), value=value) def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations, suppress_read_receipts): # Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames' # are the attribute names that were updated. Returns the XML for an UpdateItem call. # an UpdateItem request. if self.account.version.build >= EXCHANGE_2013_SP1: updateitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('ConflictResolution', conflict_resolution), ('MessageDisposition', message_disposition), ('SendMeetingInvitationsOrCancellations', send_meeting_invitations_or_cancellations), ('SuppressReadReceipts', 'true' if suppress_read_receipts else 'false'), ]) ) else: updateitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('ConflictResolution', conflict_resolution), ('MessageDisposition', message_disposition), ('SendMeetingInvitationsOrCancellations', send_meeting_invitations_or_cancellations), ]) ) itemchanges = create_element('m:ItemChanges') version = self.account.version for item, fieldnames in items: if not item.account: item.account = self.account if not fieldnames: raise ValueError('"fieldnames" must not be empty') itemchange = create_element('t:ItemChange') set_xml_value(itemchange, to_item_id(item, ItemId, version=version), version=version) updates = create_element('t:Updates') for elem in self._get_item_update_elems(item=item, fieldnames=fieldnames): updates.append(elem) itemchange.append(updates) itemchanges.append(itemchange) if not len(itemchanges): raise ValueError('"items" must not be empty') updateitem.append(itemchanges) return updateitem
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations, suppress_read_receipts)
-
Expand source code
def call(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations, suppress_read_receipts): from ..items import CONFLICT_RESOLUTION_CHOICES, MESSAGE_DISPOSITION_CHOICES, \ SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES, SEND_ONLY if conflict_resolution not in CONFLICT_RESOLUTION_CHOICES: raise ValueError("'conflict_resolution' %s must be one of %s" % ( conflict_resolution, CONFLICT_RESOLUTION_CHOICES )) if message_disposition not in MESSAGE_DISPOSITION_CHOICES: raise ValueError("'message_disposition' %s must be one of %s" % ( message_disposition, MESSAGE_DISPOSITION_CHOICES )) if send_meeting_invitations_or_cancellations not in SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES: raise ValueError("'send_meeting_invitations_or_cancellations' %s must be one of %s" % ( send_meeting_invitations_or_cancellations, SEND_MEETING_INVITATIONS_AND_CANCELLATIONS_CHOICES )) if suppress_read_receipts not in (True, False): raise ValueError("'suppress_read_receipts' %s must be True or False" % suppress_read_receipts) if message_disposition == SEND_ONLY: raise ValueError('Cannot send-only existing objects. Use SendItem service instead') return self._elems_to_objs(self._chunked_get_elements( self.get_payload, items=items, conflict_resolution=conflict_resolution, message_disposition=message_disposition, send_meeting_invitations_or_cancellations=send_meeting_invitations_or_cancellations, suppress_read_receipts=suppress_read_receipts, ))
def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations, suppress_read_receipts)
-
Expand source code
def get_payload(self, items, conflict_resolution, message_disposition, send_meeting_invitations_or_cancellations, suppress_read_receipts): # Takes a list of (Item, fieldnames) tuples where 'Item' is a instance of a subclass of Item and 'fieldnames' # are the attribute names that were updated. Returns the XML for an UpdateItem call. # an UpdateItem request. if self.account.version.build >= EXCHANGE_2013_SP1: updateitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('ConflictResolution', conflict_resolution), ('MessageDisposition', message_disposition), ('SendMeetingInvitationsOrCancellations', send_meeting_invitations_or_cancellations), ('SuppressReadReceipts', 'true' if suppress_read_receipts else 'false'), ]) ) else: updateitem = create_element( 'm:%s' % self.SERVICE_NAME, attrs=OrderedDict([ ('ConflictResolution', conflict_resolution), ('MessageDisposition', message_disposition), ('SendMeetingInvitationsOrCancellations', send_meeting_invitations_or_cancellations), ]) ) itemchanges = create_element('m:ItemChanges') version = self.account.version for item, fieldnames in items: if not item.account: item.account = self.account if not fieldnames: raise ValueError('"fieldnames" must not be empty') itemchange = create_element('t:ItemChange') set_xml_value(itemchange, to_item_id(item, ItemId, version=version), version=version) updates = create_element('t:Updates') for elem in self._get_item_update_elems(item=item, fieldnames=fieldnames): updates.append(elem) itemchange.append(updates) itemchanges.append(itemchange) if not len(itemchanges): raise ValueError('"items" must not be empty') updateitem.append(itemchanges) return updateitem
Inherited members
class UpdateUserConfiguration (*args, **kwargs)
-
Expand source code
class UpdateUserConfiguration(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/updateuserconfiguration-operation """ SERVICE_NAME = 'UpdateUserConfiguration' returns_elements = False def call(self, user_configuration): return self._get_elements(payload=self.get_payload(user_configuration=user_configuration)) def get_payload(self, user_configuration): updateuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(updateuserconfiguration, user_configuration, version=self.account.version) return updateuserconfiguration
Ancestors
Class variables
var SERVICE_NAME
var returns_elements
Methods
def call(self, user_configuration)
-
Expand source code
def call(self, user_configuration): return self._get_elements(payload=self.get_payload(user_configuration=user_configuration))
def get_payload(self, user_configuration)
-
Expand source code
def get_payload(self, user_configuration): updateuserconfiguration = create_element('m:%s' % self.SERVICE_NAME) set_xml_value(updateuserconfiguration, user_configuration, version=self.account.version) return updateuserconfiguration
Inherited members
class UploadItems (*args, **kwargs)
-
Expand source code
class UploadItems(EWSAccountService): """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/uploaditems-operation """ SERVICE_NAME = 'UploadItems' element_container_name = '{%s}ItemId' % MNS def call(self, items): # _pool_requests expects 'items', not 'data' return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items)) def get_payload(self, items): """Upload given items to given account. 'items' is an iterable of tuples where the first element is a Folder instance representing the ParentFolder that the item will be placed in and the second element is a tuple containing an optional ItemId, an optional Item.is_associated boolean, and a Data string returned from an ExportItems. call. :param items: """ uploaditems = create_element('m:%s' % self.SERVICE_NAME) itemselement = create_element('m:Items') uploaditems.append(itemselement) for parent_folder, (item_id, is_associated, data_str) in items: # TODO: The full spec also allows the "UpdateOrCreate" create action. item = create_element('t:Item', attrs=dict(CreateAction='Update' if item_id else 'CreateNew')) if is_associated is not None: item.set('IsAssociated', 'true' if is_associated else 'false') parentfolderid = ParentFolderId(parent_folder.id, parent_folder.changekey) set_xml_value(item, parentfolderid, version=self.account.version) if item_id: itemid = to_item_id(item_id, ItemId, version=self.account.version) set_xml_value(item, itemid, version=self.account.version) add_xml_child(item, 't:Data', data_str) itemselement.append(item) return uploaditems def _elems_to_objs(self, elems): for elem in elems: if isinstance(elem, Exception): yield elem continue yield elem.get(ItemId.ID_ATTR), elem.get(ItemId.CHANGEKEY_ATTR) @classmethod def _get_elements_in_container(cls, container): return [container]
Ancestors
Class variables
var SERVICE_NAME
var element_container_name
Methods
def call(self, items)
-
Expand source code
def call(self, items): # _pool_requests expects 'items', not 'data' return self._elems_to_objs(self._chunked_get_elements(self.get_payload, items=items))
def get_payload(self, items)
-
Upload given items to given account.
'items' is an iterable of tuples where the first element is a Folder instance representing the ParentFolder that the item will be placed in and the second element is a tuple containing an optional ItemId, an optional Item.is_associated boolean, and a Data string returned from an ExportItems. call.
:param items:
Expand source code
def get_payload(self, items): """Upload given items to given account. 'items' is an iterable of tuples where the first element is a Folder instance representing the ParentFolder that the item will be placed in and the second element is a tuple containing an optional ItemId, an optional Item.is_associated boolean, and a Data string returned from an ExportItems. call. :param items: """ uploaditems = create_element('m:%s' % self.SERVICE_NAME) itemselement = create_element('m:Items') uploaditems.append(itemselement) for parent_folder, (item_id, is_associated, data_str) in items: # TODO: The full spec also allows the "UpdateOrCreate" create action. item = create_element('t:Item', attrs=dict(CreateAction='Update' if item_id else 'CreateNew')) if is_associated is not None: item.set('IsAssociated', 'true' if is_associated else 'false') parentfolderid = ParentFolderId(parent_folder.id, parent_folder.changekey) set_xml_value(item, parentfolderid, version=self.account.version) if item_id: itemid = to_item_id(item_id, ItemId, version=self.account.version) set_xml_value(item, itemid, version=self.account.version) add_xml_child(item, 't:Data', data_str) itemselement.append(item) return uploaditems
Inherited members