from enum import Enum
from .utils import ApiComponent
[docs]
class CategoryColor(Enum):
RED = 'preset0' # 0
ORANGE = 'preset1' # 1
BROWN = 'preset2' # 2
YELLOW = 'preset3' # 3
GREEN = 'preset4' # 4
TEAL = 'preset5' # 5
OLIVE = 'preset6' # 6
BLUE = 'preset7' # 7
PURPLE = 'preset8' # 8
CRANBERRY = 'preset9' # 9
STEEL = 'preset10' # 10
DARKSTEEL = 'preset11' # 11
GRAY = 'preset12' # 12
DARKGREY = 'preset13' # 13
BLACK = 'preset14' # 14
DARKRED = 'preset15' # 15
DARKORANGE = 'preset16' # 16
DARKBROWN = 'preset17' # 17
DARKYELLOW = 'preset18' # 18
DARKGREEN = 'preset19' # 19
DARKTEAL = 'preset20' # 20
DARKOLIVE = 'preset21' # 21
DARKBLUE = 'preset22' # 22
DARKPURPLE = 'preset23' # 23
DARKCRANBERRY = 'preset24' # 24
[docs]
@classmethod
def get(cls, color):
"""
Gets a color by name or value.
Raises ValueError if not found whithin the collection of colors.
"""
try:
return cls(color.capitalize()) # 'preset0' to 'Preset0'
except ValueError:
pass
try:
return cls[color.upper()] # 'red' to 'RED'
except KeyError:
raise ValueError('color is not a valid color from CategoryColor') from None
[docs]
class Category(ApiComponent):
_endpoints = {
'update': '/outlook/masterCategories/{id}'
}
[docs]
def __init__(self, *, parent=None, con=None, **kwargs):
"""Represents a category by which a user can group Outlook items such as messages and events.
It can be used in conjunction with Event, Message, Contact and Post.
:param parent: parent object
:type parent: Account
:param Connection con: connection to use if no parent specified
:param Protocol protocol: protocol to use if no parent specified
(kwargs)
:param str main_resource: use this resource instead of parent resource
(kwargs)
"""
if parent and con:
raise ValueError('Need a parent or a connection but not both')
self.con = parent.con if parent else con
# Choose the main_resource passed in kwargs over parent main_resource
main_resource = kwargs.pop('main_resource', None) or (
getattr(parent, 'main_resource', None) if parent else None)
super().__init__(
protocol=parent.protocol if parent else kwargs.get('protocol'),
main_resource=main_resource)
cloud_data = kwargs.get(self._cloud_data_key, {})
self.object_id = cloud_data.get('id')
self.name = cloud_data.get(self._cc('displayName'))
color = cloud_data.get(self._cc('color'))
self.color = CategoryColor(color) if color else None
def __str__(self):
return self.__repr__()
def __repr__(self):
return '{} (color: {})'.format(self.name, self.color.name if self.color else None)
[docs]
def update_color(self, color):
"""
Updates this Category color
:param None or str or CategoryColor color: the category color
"""
url = self.build_url(self._endpoints.get('update').format(id=self.object_id))
if color is not None and not isinstance(color, CategoryColor):
color = CategoryColor.get(color)
response = self.con.patch(url, data={'color': color.value if color else None})
if not response:
return False
self.color = color
return True
[docs]
def delete(self):
""" Deletes this Category """
url = self.build_url(self._endpoints.get('update').format(id=self.object_id))
response = self.con.delete(url)
return bool(response)
[docs]
class Categories(ApiComponent):
_endpoints = {
'list': '/outlook/masterCategories',
'get': '/outlook/masterCategories/{id}',
}
category_constructor = Category
[docs]
def __init__(self, *, parent=None, con=None, **kwargs):
""" Object to retrive categories
:param parent: parent object
:type parent: Account
:param Connection con: connection to use if no parent specified
:param Protocol protocol: protocol to use if no parent specified
(kwargs)
:param str main_resource: use this resource instead of parent resource
(kwargs)
"""
if parent and con:
raise ValueError('Need a parent or a connection but not both')
self.con = parent.con if parent else con
# Choose the main_resource passed in kwargs over parent main_resource
main_resource = kwargs.pop('main_resource', None) or (
getattr(parent, 'main_resource', None) if parent else None)
super().__init__(
protocol=parent.protocol if parent else kwargs.get('protocol'),
main_resource=main_resource)
[docs]
def get_categories(self):
""" Returns a list of categories"""
url = self.build_url(self._endpoints.get('list'))
response = self.con.get(url)
if not response:
return []
data = response.json()
return [
self.category_constructor(parent=self, **{self._cloud_data_key: category})
for category in data.get('value', [])
]
[docs]
def get_category(self, category_id):
""" Returns a category by id"""
url = self.build_url(self._endpoints.get('get').format(id=category_id))
response = self.con.get(url)
if not response:
return None
data = response.json()
return self.category_constructor(parent=self, **{self._cloud_data_key: data})
[docs]
def create_category(self, name, color='auto'):
"""
Creates a category.
If the color is not provided it will be choosed from the pool of unused colors.
:param str name: The name of this outlook category. Must be unique.
:param str or CategoryColor color: optional color. If not provided will be assigned automatically.
:return: bool
"""
if color == 'auto':
used_colors = {category.color for category in self.get_categories()}
all_colors = {color for color in CategoryColor}
available_colors = all_colors - used_colors
try:
color = available_colors.pop()
except KeyError:
# re-use a color
color = all_colors.pop()
else:
if color is not None and not isinstance(color, CategoryColor):
color = CategoryColor.get(color)
url = self.build_url(self._endpoints.get('list'))
data = {self._cc('displayName'): name, 'color': color.value if color else None}
response = self.con.post(url, data=data)
if not response:
return None
category = response.json()
return self.category_constructor(parent=self, **{self._cloud_data_key: category})