Module exchangelib.services.subscribe

The 'Subscribe' service has two different modes, pull and push, with different signatures. Implement as two distinct classes.

Expand source code
"""The 'Subscribe' service has two different modes, pull and push, with different signatures. Implement as two distinct
classes.
"""
import abc

from ..util import MNS, create_element
from .common import EWSAccountService, add_xml_child, folder_ids_element


class Subscribe(EWSAccountService, metaclass=abc.ABCMeta):
    """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation"""

    SERVICE_NAME = "Subscribe"
    EVENT_TYPES = (
        "CopiedEvent",
        "CreatedEvent",
        "DeletedEvent",
        "ModifiedEvent",
        "MovedEvent",
        "NewMailEvent",
        "FreeBusyChangedEvent",
    )
    subscription_request_elem_tag = None

    def _partial_call(self, payload_func, folders, event_types, **kwargs):
        if set(event_types) - set(self.EVENT_TYPES):
            raise ValueError(f"'event_types' values must consist of values in {self.EVENT_TYPES}")
        return self._elems_to_objs(
            self._get_elements(payload=payload_func(folders=folders, event_types=event_types, **kwargs))
        )

    def _elem_to_obj(self, elem):
        subscription_elem, watermark_elem = elem
        return subscription_elem.text, watermark_elem.text

    @classmethod
    def _get_elements_in_container(cls, container):
        return [(container.find(f"{{{MNS}}}SubscriptionId"), container.find(f"{{{MNS}}}Watermark"))]

    def _partial_payload(self, folders, event_types):
        request_elem = create_element(self.subscription_request_elem_tag)
        folder_ids = folder_ids_element(folders=folders, version=self.account.version, tag="t:FolderIds")
        request_elem.append(folder_ids)
        event_types_elem = create_element("t:EventTypes")
        for event_type in event_types:
            add_xml_child(event_types_elem, "t:EventType", event_type)
        if not len(event_types_elem):
            raise ValueError("'event_types' must not be empty")
        request_elem.append(event_types_elem)
        return request_elem


class SubscribeToPull(Subscribe):
    subscription_request_elem_tag = "m:PullSubscriptionRequest"
    prefer_affinity = True

    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):
        payload = create_element(f"m:{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
        payload.append(request_elem)
        return payload


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):
        payload = create_element(f"m:{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)
        payload.append(request_elem)
        return payload


class SubscribeToStreaming(Subscribe):
    subscription_request_elem_tag = "m:StreamingSubscriptionRequest"
    prefer_affinity = True

    def call(self, folders, event_types):
        yield from self._partial_call(payload_func=self.get_payload, folders=folders, event_types=event_types)

    def _elem_to_obj(self, elem):
        return elem.text

    @classmethod
    def _get_elements_in_container(cls, container):
        return [container.find(f"{{{MNS}}}SubscriptionId")]

    def get_payload(self, folders, event_types):
        payload = create_element(f"m:{self.SERVICE_NAME}")
        payload.append(self._partial_payload(folders=folders, event_types=event_types))
        return payload

Classes

class Subscribe (*args, **kwargs)
Expand source code
class Subscribe(EWSAccountService, metaclass=abc.ABCMeta):
    """MSDN: https://docs.microsoft.com/en-us/exchange/client-developer/web-service-reference/subscribe-operation"""

    SERVICE_NAME = "Subscribe"
    EVENT_TYPES = (
        "CopiedEvent",
        "CreatedEvent",
        "DeletedEvent",
        "ModifiedEvent",
        "MovedEvent",
        "NewMailEvent",
        "FreeBusyChangedEvent",
    )
    subscription_request_elem_tag = None

    def _partial_call(self, payload_func, folders, event_types, **kwargs):
        if set(event_types) - set(self.EVENT_TYPES):
            raise ValueError(f"'event_types' values must consist of values in {self.EVENT_TYPES}")
        return self._elems_to_objs(
            self._get_elements(payload=payload_func(folders=folders, event_types=event_types, **kwargs))
        )

    def _elem_to_obj(self, elem):
        subscription_elem, watermark_elem = elem
        return subscription_elem.text, watermark_elem.text

    @classmethod
    def _get_elements_in_container(cls, container):
        return [(container.find(f"{{{MNS}}}SubscriptionId"), container.find(f"{{{MNS}}}Watermark"))]

    def _partial_payload(self, folders, event_types):
        request_elem = create_element(self.subscription_request_elem_tag)
        folder_ids = folder_ids_element(folders=folders, version=self.account.version, tag="t:FolderIds")
        request_elem.append(folder_ids)
        event_types_elem = create_element("t:EventTypes")
        for event_type in event_types:
            add_xml_child(event_types_elem, "t:EventType", event_type)
        if not len(event_types_elem):
            raise ValueError("'event_types' must not be empty")
        request_elem.append(event_types_elem)
        return request_elem

Ancestors

Subclasses

Class variables

var EVENT_TYPES
var SERVICE_NAME
var subscription_request_elem_tag

Inherited members

class SubscribeToPull (*args, **kwargs)
Expand source code
class SubscribeToPull(Subscribe):
    subscription_request_elem_tag = "m:PullSubscriptionRequest"
    prefer_affinity = True

    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):
        payload = create_element(f"m:{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
        payload.append(request_elem)
        return payload

Ancestors

Class variables

var prefer_affinity
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):
    payload = create_element(f"m:{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
    payload.append(request_elem)
    return payload

Inherited members

class SubscribeToPush (*args, **kwargs)
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):
        payload = create_element(f"m:{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)
        payload.append(request_elem)
        return payload

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):
    payload = create_element(f"m:{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)
    payload.append(request_elem)
    return payload

Inherited members

class SubscribeToStreaming (*args, **kwargs)
Expand source code
class SubscribeToStreaming(Subscribe):
    subscription_request_elem_tag = "m:StreamingSubscriptionRequest"
    prefer_affinity = True

    def call(self, folders, event_types):
        yield from self._partial_call(payload_func=self.get_payload, folders=folders, event_types=event_types)

    def _elem_to_obj(self, elem):
        return elem.text

    @classmethod
    def _get_elements_in_container(cls, container):
        return [container.find(f"{{{MNS}}}SubscriptionId")]

    def get_payload(self, folders, event_types):
        payload = create_element(f"m:{self.SERVICE_NAME}")
        payload.append(self._partial_payload(folders=folders, event_types=event_types))
        return payload

Ancestors

Class variables

var prefer_affinity
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):
    payload = create_element(f"m:{self.SERVICE_NAME}")
    payload.append(self._partial_payload(folders=folders, event_types=event_types))
    return payload

Inherited members