Add intial property to imap_content event data (#100171)

* Add initial property to imap event data

* Simplify loop

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* MyPy

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Jan Bouwhuis 2023-09-12 18:54:32 +02:00 committed by GitHub
parent 86bccf769e
commit e84a4661b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 15 deletions

View File

@ -110,6 +110,15 @@ class ImapMessage:
header_base[key] += header_instances # type: ignore[assignment]
return header_base
@property
def message_id(self) -> str | None:
"""Get the message ID."""
value: str
for header, value in self.email_message.items():
if header == "Message-ID":
return value
return None
@property
def date(self) -> datetime | None:
"""Get the date the email was sent."""
@ -189,6 +198,7 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
"""Initiate imap client."""
self.imap_client = imap_client
self.auth_errors: int = 0
self._last_message_uid: str | None = None
self._last_message_id: str | None = None
self.custom_event_template = None
_custom_event_template = entry.data.get(CONF_CUSTOM_EVENT_DATA_TEMPLATE)
@ -209,16 +219,22 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
if self.imap_client is None:
self.imap_client = await connect_to_server(self.config_entry.data)
async def _async_process_event(self, last_message_id: str) -> None:
async def _async_process_event(self, last_message_uid: str) -> None:
"""Send a event for the last message if the last message was changed."""
response = await self.imap_client.fetch(last_message_id, "BODY.PEEK[]")
response = await self.imap_client.fetch(last_message_uid, "BODY.PEEK[]")
if response.result == "OK":
message = ImapMessage(response.lines[1])
# Set `initial` to `False` if the last message is triggered again
initial: bool = True
if (message_id := message.message_id) == self._last_message_id:
initial = False
self._last_message_id = message_id
data = {
"server": self.config_entry.data[CONF_SERVER],
"username": self.config_entry.data[CONF_USERNAME],
"search": self.config_entry.data[CONF_SEARCH],
"folder": self.config_entry.data[CONF_FOLDER],
"initial": initial,
"date": message.date,
"text": message.text,
"sender": message.sender,
@ -231,18 +247,20 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
data, parse_result=True
)
_LOGGER.debug(
"imap custom template (%s) for msgid %s rendered to: %s",
"IMAP custom template (%s) for msguid %s (%s) rendered to: %s, initial: %s",
self.custom_event_template,
last_message_id,
last_message_uid,
message_id,
data["custom"],
initial,
)
except TemplateError as err:
data["custom"] = None
_LOGGER.error(
"Error rendering imap custom template (%s) for msgid %s "
"Error rendering IMAP custom template (%s) for msguid %s "
"failed with message: %s",
self.custom_event_template,
last_message_id,
last_message_uid,
err,
)
data["text"] = message.text[
@ -263,10 +281,12 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
self.hass.bus.fire(EVENT_IMAP, data)
_LOGGER.debug(
"Message with id %s processed, sender: %s, subject: %s",
last_message_id,
"Message with id %s (%s) processed, sender: %s, subject: %s, initial: %s",
last_message_uid,
message_id,
message.sender,
message.subject,
initial,
)
async def _async_fetch_number_of_messages(self) -> int | None:
@ -282,20 +302,20 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
f"Invalid response for search '{self.config_entry.data[CONF_SEARCH]}': {result} / {lines[0]}"
)
if not (count := len(message_ids := lines[0].split())):
self._last_message_id = None
self._last_message_uid = None
return 0
last_message_id = (
last_message_uid = (
str(message_ids[-1:][0], encoding=self.config_entry.data[CONF_CHARSET])
if count
else None
)
if (
count
and last_message_id is not None
and self._last_message_id != last_message_id
and last_message_uid is not None
and self._last_message_uid != last_message_uid
):
self._last_message_id = last_message_id
await self._async_process_event(last_message_id)
self._last_message_uid = last_message_uid
await self._async_process_event(last_message_uid)
return count

View File

@ -22,6 +22,7 @@ TEST_MESSAGE_HEADERS2 = (
b"To: notify@example.com\r\n"
b"From: John Doe <john.doe@example.com>\r\n"
b"Subject: Test subject\r\n"
b"Message-ID: <N753P9hLvLw3lYGan11ji9WggPjxtLSpKvFOYgdnE@example.com>"
)
TEST_MESSAGE_HEADERS3 = b""

View File

@ -512,6 +512,7 @@ async def test_reset_last_message(
assert data["sender"] == "john.doe@example.com"
assert data["subject"] == "Test subject"
assert data["text"]
assert data["initial"]
assert (
valid_date
and isinstance(data["date"], datetime)
@ -628,7 +629,7 @@ async def test_message_is_truncated(
[
("{{ subject }}", "Test subject", None),
('{{ "@example.com" in sender }}', True, None),
("{% bad template }}", None, "Error rendering imap custom template"),
("{% bad template }}", None, "Error rendering IMAP custom template"),
],
ids=["subject_test", "sender_filter", "template_error"],
)