Skip to content

Commit

Permalink
Added sensor for targeting auto-reply
Browse files Browse the repository at this point in the history
  • Loading branch information
RogerSelwyn committed Jan 10, 2023
1 parent 38967f9 commit bdb4e20
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 48 deletions.
3 changes: 3 additions & 0 deletions custom_components/o365/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
CONF_ACCOUNT_NAME,
CONF_ACCOUNTS,
CONF_ALT_AUTH_METHOD,
CONF_AUTO_REPLY_SENSORS,
CONF_CHAT_SENSORS,
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
Expand Down Expand Up @@ -196,6 +197,7 @@ def do_setup(hass, config, account, account_name, conf_type):
status_sensors = config.get(CONF_STATUS_SENSORS, [])
chat_sensors = config.get(CONF_CHAT_SENSORS, [])
todo_sensors = config.get(CONF_TODO_SENSORS, [])
auto_reply_sensors = config.get(CONF_AUTO_REPLY_SENSORS, [])
enable_update = config.get(CONF_ENABLE_UPDATE, True)

account_config = {
Expand All @@ -205,6 +207,7 @@ def do_setup(hass, config, account, account_name, conf_type):
CONF_STATUS_SENSORS: status_sensors,
CONF_CHAT_SENSORS: chat_sensors,
CONF_TODO_SENSORS: todo_sensors,
CONF_AUTO_REPLY_SENSORS: auto_reply_sensors,
CONF_ENABLE_UPDATE: enable_update,
CONF_TRACK_NEW_CALENDAR: config.get(CONF_TRACK_NEW_CALENDAR, True),
CONF_ACCOUNT_NAME: config.get(CONF_ACCOUNT_NAME, ""),
Expand Down
106 changes: 64 additions & 42 deletions custom_components/o365/classes/mailsensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import voluptuous as vol
from homeassistant.components.sensor import SensorEntity

from O365.mailbox import ExternalAudience # pylint: disable=no-name-in-module

from ..const import (
ATTR_ATTRIBUTES,
CONF_ACCOUNT,
Expand All @@ -19,6 +21,7 @@
CONF_SUBJECT_IS,
PERM_MAILBOX_SETTINGS,
PERM_MINIMUM_MAILBOX_SETTINGS,
SENSOR_AUTO_REPLY,
SENSOR_MAIL,
)
from ..utils import build_token_filename, get_permissions, validate_minimum_permission
Expand Down Expand Up @@ -49,48 +52,6 @@ def extra_state_attributes(self):
"""Device state attributes."""
return self.coordinator.data[self.entity_key][ATTR_ATTRIBUTES]

def auto_reply_enable(
self,
external_reply,
internal_reply,
start=None,
end=None,
external_audience=None,
):
"""Enable out of office autoreply."""
if not self._validate_permissions():
return

account = self._config[CONF_ACCOUNT]
mailbox = account.mailbox()
mailbox.set_automatic_reply(
internal_reply, external_reply, start, end, external_audience
)

def auto_reply_disable(self):
"""Disable out of office autoreply."""
if not self._validate_permissions():
return

account = self._config[CONF_ACCOUNT]
mailbox = account.mailbox()
mailbox.set_disable_reply()

def _validate_permissions(self):
permissions = get_permissions(
self.hass,
filename=build_token_filename(
self._config, self._config.get(CONF_CONFIG_TYPE)
),
)
if not validate_minimum_permission(PERM_MINIMUM_MAILBOX_SETTINGS, permissions):
raise vol.Invalid(
"Not authorisied to update auto reply - requires permission: "
+ f"{PERM_MAILBOX_SETTINGS}"
)

return True


class O365QuerySensor(O365MailSensor, SensorEntity):
"""O365 Query sensor processing."""
Expand Down Expand Up @@ -167,3 +128,64 @@ def __init__(
if is_unread is not None:
self.query = self.mail_folder.new_query()
self.query.chain("and").on_attribute("IsRead").equals(not is_unread)


class O365AutoReplySensor(O365Sensor, SensorEntity):
"""O365 Tasks sensor processing."""

def __init__(self, coordinator, name, entity_id, config, unqique_id):
"""Initialise the Tasks Sensor."""
super().__init__(coordinator, name, entity_id, SENSOR_AUTO_REPLY, unqique_id)
self._config = config

@property
def state(self):
"""Sensor state."""
return "TBC"

@property
def icon(self):
"""Entity icon."""
return "mdi:reply-all"

def auto_reply_enable(
self,
external_reply,
internal_reply,
start=None,
end=None,
external_audience=ExternalAudience.ALL,
):
"""Enable out of office autoreply."""
if not self._validate_permissions():
return

account = self._config[CONF_ACCOUNT]
mailbox = account.mailbox()
mailbox.set_automatic_reply(
internal_reply, external_reply, start, end, external_audience
)

def auto_reply_disable(self):
"""Disable out of office autoreply."""
if not self._validate_permissions():
return

account = self._config[CONF_ACCOUNT]
mailbox = account.mailbox()
mailbox.set_disable_reply()

def _validate_permissions(self):
permissions = get_permissions(
self.hass,
filename=build_token_filename(
self._config, self._config.get(CONF_CONFIG_TYPE)
),
)
if not validate_minimum_permission(PERM_MINIMUM_MAILBOX_SETTINGS, permissions):
raise vol.Invalid(
"Not authorisied to update auto reply - requires permission: "
+ f"{PERM_MAILBOX_SETTINGS}"
)

return True
4 changes: 2 additions & 2 deletions custom_components/o365/classes/taskssensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
class O365TasksSensor(O365Sensor, SensorEntity):
"""O365 Tasks sensor processing."""

def __init__(self, coordinator, todo, name, entity_id, config, unqique_id):
def __init__(self, coordinator, todo, name, entity_id, config, unique_id):
"""Initialise the Tasks Sensor."""
super().__init__(coordinator, name, entity_id, SENSOR_TODO, unqique_id)
super().__init__(coordinator, name, entity_id, SENSOR_TODO, unique_id)
self.todo = todo
self.query = self.todo.new_query("status").unequal("completed")
self._config = config
Expand Down
2 changes: 2 additions & 0 deletions custom_components/o365/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class EventResponse(Enum):
CONF_ACCOUNT_NAME = "account_name"
CONF_ALIASES = "aliases"
CONF_ALT_AUTH_METHOD = "alt_auth_method"
CONF_AUTO_REPLY_SENSORS = "auto_reply_sensors"
CONF_BODY_CONTAINS = "body_contains"
CONF_CACHE_PATH = "cache_path"
CONF_CALENDAR_NAME = "calendar_name"
Expand Down Expand Up @@ -175,6 +176,7 @@ class EventResponse(Enum):
[PERM_MAIL_SEND_SHARED],
]

SENSOR_AUTO_REPLY = "auto_reply"
SENSOR_DOMAIN = "sensor"
SENSOR_ENTITY_ID_FORMAT = SENSOR_DOMAIN + ".{}"
SENSOR_MAIL = "inbox"
Expand Down
9 changes: 9 additions & 0 deletions custom_components/o365/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
ATTR_TITLE,
)
from homeassistant.const import CONF_ENABLED, CONF_NAME

from O365.calendar import AttendeeType # pylint: disable=no-name-in-module
from O365.calendar import EventSensitivity # pylint: disable=no-name-in-module
from O365.calendar import EventShowAs # pylint: disable=no-name-in-module
Expand Down Expand Up @@ -46,6 +47,7 @@
CONF_ACCOUNT_NAME,
CONF_ACCOUNTS,
CONF_ALT_AUTH_METHOD,
CONF_AUTO_REPLY_SENSORS,
CONF_BODY_CONTAINS,
CONF_CAL_ID,
CONF_CHAT_SENSORS,
Expand Down Expand Up @@ -98,6 +100,11 @@
vol.Required(CONF_NAME): cv.string,
}
)
AUTO_REPLY_SENSOR = vol.Schema(
{
vol.Required(CONF_NAME): cv.string,
}
)
QUERY_SENSOR = vol.Schema(
{
vol.Required(CONF_NAME): cv.string,
Expand Down Expand Up @@ -131,6 +138,7 @@
vol.Optional(CONF_QUERY_SENSORS): [QUERY_SENSOR],
vol.Optional(CONF_STATUS_SENSORS): [STATUS_SENSOR],
vol.Optional(CONF_CHAT_SENSORS): [CHAT_SENSOR],
vol.Optional(CONF_AUTO_REPLY_SENSORS): [AUTO_REPLY_SENSOR],
}
)
MULTI_ACCOUNT_SCHEMA = vol.Schema(
Expand All @@ -150,6 +158,7 @@
vol.Optional(CONF_STATUS_SENSORS): [STATUS_SENSOR],
vol.Optional(CONF_CHAT_SENSORS): [CHAT_SENSOR],
vol.Optional(CONF_TODO_SENSORS): TODO_SENSOR,
vol.Optional(CONF_AUTO_REPLY_SENSORS): [AUTO_REPLY_SENSOR],
}
]
)
Expand Down
22 changes: 21 additions & 1 deletion custom_components/o365/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
) # UpdateFailed,
from requests.exceptions import HTTPError

from .classes.mailsensor import O365EmailSensor, O365QuerySensor
from .classes.mailsensor import O365AutoReplySensor, O365EmailSensor, O365QuerySensor
from .classes.taskssensor import O365TasksSensor
from .classes.teamssensor import O365TeamsChatSensor, O365TeamsStatusSensor
from .const import (
Expand All @@ -28,6 +28,7 @@
ATTR_TASKS,
CONF_ACCOUNT,
CONF_ACCOUNT_NAME,
CONF_AUTO_REPLY_SENSORS,
CONF_CHAT_SENSORS,
CONF_CONFIG_TYPE,
CONF_EMAIL_SENSORS,
Expand Down Expand Up @@ -122,12 +123,14 @@ async def async_setup_entries(self):
status_entities = self._status_sensors()
chat_entities = self._chat_sensors()
todo_entities = await self._async_todo_sensors()
auto_reply_entities = await self._async_auto_reply_sensors()
self._entities = (
email_entities
+ query_entities
+ status_entities
+ chat_entities
+ todo_entities
+ auto_reply_entities
)
return self._entities

Expand Down Expand Up @@ -280,6 +283,23 @@ async def _async_todo_entities(self, task_lists, config):
)
return entities

async def _async_auto_reply_sensors(self):
auto_reply_sensors = self._config.get(CONF_AUTO_REPLY_SENSORS, [])
entities = []
for sensor_conf in auto_reply_sensors:
name = sensor_conf.get(CONF_NAME)
entity_id = async_generate_entity_id(
SENSOR_ENTITY_ID_FORMAT,
name,
hass=self.hass,
)
unique_id = f"{name}_{self._account_name}"
auto_reply_sensor = O365AutoReplySensor(
self, name, entity_id, self._config, unique_id
)
entities.append(auto_reply_sensor)
return entities

async def _async_get_mail_folder(self, sensor_conf, sensor_type):
"""Get the configured folder."""
mailbox = self._account.mailbox()
Expand Down
13 changes: 10 additions & 3 deletions custom_components/o365/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
import yaml
from bs4 import BeautifulSoup
from homeassistant.const import CONF_ENABLED, CONF_NAME
from O365.calendar import Attendee # pylint: disable=no-name-in-module)
from voluptuous.error import Error as VoluptuousError

from O365.calendar import Attendee # pylint: disable=no-name-in-module)

from .const import (
CONF_ACCOUNT_NAME,
CONF_AUTO_REPLY_SENSORS,
CONF_CAL_ID,
CONF_CHAT_SENSORS,
CONF_CONFIG_TYPE,
Expand Down Expand Up @@ -46,6 +48,7 @@
PERM_MINIMUM_CHAT,
PERM_MINIMUM_GROUP,
PERM_MINIMUM_MAIL,
PERM_MINIMUM_MAILBOX_SETTINGS,
PERM_MINIMUM_PRESENCE,
PERM_MINIMUM_TASKS,
PERM_MINIMUM_USER,
Expand Down Expand Up @@ -87,6 +90,7 @@ def build_minimum_permissions(hass, config, conf_type):
status_sensors = config.get(CONF_STATUS_SENSORS, [])
chat_sensors = config.get(CONF_CHAT_SENSORS, [])
todo_sensors = config.get(CONF_TODO_SENSORS, [])
auto_reply_sensors = config.get(CONF_AUTO_REPLY_SENSORS, [])
minimum_permissions = [PERM_MINIMUM_USER, PERM_MINIMUM_CALENDAR]
if len(email_sensors) > 0 or len(query_sensors) > 0:
minimum_permissions.append(PERM_MINIMUM_MAIL)
Expand All @@ -96,6 +100,8 @@ def build_minimum_permissions(hass, config, conf_type):
minimum_permissions.append(PERM_MINIMUM_CHAT)
if len(todo_sensors) > 0 and todo_sensors.get(CONF_ENABLED, False):
minimum_permissions.append(PERM_MINIMUM_TASKS)
if len(auto_reply_sensors) > 0:
minimum_permissions.append(PERM_MINIMUM_MAILBOX_SETTINGS)

if group_permissions_required(hass, config, conf_type):
minimum_permissions.append(PERM_MINIMUM_GROUP)
Expand All @@ -112,6 +118,7 @@ def build_requested_permissions(config):
todo_sensors = config.get(CONF_TODO_SENSORS, [])
enable_update = config.get(CONF_ENABLE_UPDATE, True)
groups = config.get(CONF_GROUPS, False)
auto_reply_sensors = config.get(CONF_AUTO_REPLY_SENSORS, [])
scope = [PERM_OFFLINE_ACCESS, PERM_USER_READ]
if enable_update:
scope.extend((PERM_MAIL_SEND, PERM_CALENDARS_READWRITE))
Expand All @@ -124,8 +131,8 @@ def build_requested_permissions(config):
scope.append(PERM_GROUP_READ_ALL)
if len(email_sensors) > 0 or len(query_sensors) > 0:
scope.append(PERM_MAIL_READ)
if enable_update:
scope.append(PERM_MAILBOX_SETTINGS)
if len(auto_reply_sensors) > 0:
scope.append(PERM_MAILBOX_SETTINGS)
if len(status_sensors) > 0:
scope.append(PERM_PRESENCE_READ)
if len(chat_sensors) > 0:
Expand Down

0 comments on commit bdb4e20

Please sign in to comment.