Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions elementary/messages/messaging_integrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .file_system import FileSystemMessagingIntegration
from .slack_webhook import SlackWebhookMessagingIntegration
from .teams_webhook import TeamsWebhookMessagingIntegration

__all__ = [
"FileSystemMessagingIntegration",
"TeamsWebhookMessagingIntegration",
"SlackWebhookMessagingIntegration",
]
73 changes: 73 additions & 0 deletions elementary/messages/messaging_integrations/file_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import json
from datetime import datetime
from pathlib import Path

from elementary.messages.message_body import MessageBody
from elementary.messages.messaging_integrations.base_messaging_integration import (
BaseMessagingIntegration,
MessageSendResult,
)
from elementary.messages.messaging_integrations.empty_message_context import (
EmptyMessageContext,
)
from elementary.messages.messaging_integrations.exceptions import (
MessagingIntegrationError,
)
from elementary.utils.log import get_logger

logger = get_logger(__name__)


class FileSystemMessagingIntegration(
BaseMessagingIntegration[str, EmptyMessageContext]
):
def __init__(self, directory: str, create_if_missing: bool = True) -> None:
self.directory = Path(directory).expanduser().resolve()
self._create_if_missing = create_if_missing

if not self.directory.exists():
if self._create_if_missing:
logger.info(
f"Creating directory for FileSystemMessagingIntegration: {self.directory}"
)
self.directory.mkdir(parents=True, exist_ok=True)
else:
raise MessagingIntegrationError(
f"Directory {self.directory} does not exist and create_if_missing is False"
)

def supports_reply(self) -> bool:
return False

def send_message(
self, destination: str, body: MessageBody
) -> MessageSendResult[EmptyMessageContext]:
channel_dir = self.directory / destination
if not channel_dir.exists():
if self._create_if_missing:
channel_dir.mkdir(parents=True, exist_ok=True)
else:
raise MessagingIntegrationError(
f"Channel directory {channel_dir} does not exist and create_if_missing is False"
)

filename = datetime.utcnow().strftime("%Y%m%dT%H%M%S_%fZ.json")
file_path = channel_dir / filename

try:
json_str = json.dumps(body.dict(), indent=2)
file_path.write_text(json_str, encoding="utf-8")
except Exception as exc:
logger.error(
f"Failed to write alert message to file {file_path}: {exc}",
exc_info=True,
)
raise MessagingIntegrationError(
f"Failed writing alert message to file {file_path}"
) from exc

return MessageSendResult(
timestamp=datetime.utcnow(),
message_format="json",
message_context=EmptyMessageContext(),
)
59 changes: 59 additions & 0 deletions tests/unit/messages/messaging_integrations/test_file_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import json
from pathlib import Path

import pytest

from elementary.messages.blocks import LineBlock, LinesBlock, TextBlock
from elementary.messages.message_body import MessageBody
from elementary.messages.messaging_integrations.exceptions import (
MessagingIntegrationError,
)
from elementary.messages.messaging_integrations.file_system import (
FileSystemMessagingIntegration,
)


def _build_body() -> MessageBody:
return MessageBody(
blocks=[LinesBlock(lines=[LineBlock(inlines=[TextBlock(text="hello")])])]
)


def test_send_message_creates_file_in_channel_dir(tmp_path: Path) -> None:
root_dir = tmp_path / "alerts"
integ = FileSystemMessagingIntegration(directory=str(root_dir))
body = _build_body()

integ.send_message("channel", body)

channel_dir = root_dir / "channel"
files = list(channel_dir.glob("*.json"))
assert len(files) == 1, "Expected exactly one file in the channel directory"

message_json = files[0].read_text()
assert json.loads(message_json) == json.loads(body.json())


def test_send_multiple_messages_creates_multiple_files(tmp_path: Path) -> None:
root_dir = tmp_path / "alerts"
integ = FileSystemMessagingIntegration(directory=str(root_dir))
body1 = _build_body()
body2 = _build_body()

integ.send_message("channel", body1)
integ.send_message("channel", body2)

channel_dir = root_dir / "channel"
files = sorted(channel_dir.glob("*.json"))

assert len(files) == 2
assert json.loads(files[0].read_text()) == json.loads(body1.json())
assert json.loads(files[1].read_text()) == json.loads(body2.json())


def test_send_message_no_create_flag(tmp_path: Path) -> None:
directory = tmp_path / "alerts-no-create"
with pytest.raises(MessagingIntegrationError):
FileSystemMessagingIntegration(
directory=str(directory), create_if_missing=False
)