Module exchangelib.services.sync_folder_items
Expand source code
from .common import add_xml_child, create_item_ids_element
from .sync_folder_hierarchy import SyncFolder
from ..properties import ItemId
from ..util import xml_text_to_value, peek, TNS, MNS
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
Classes
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