From cdc157de7452d98b7e9350022229af5d9c53f5b8 Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:29:42 +0200 Subject: [PATCH] Add styled formatting option to Signal Messenger integration - Bump pysignalclirestapi to 0.3.24 (#117148) --- .../components/signal_messenger/manifest.json | 2 +- .../components/signal_messenger/notify.py | 25 ++++-- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../signal_messenger/test_notify.py | 87 +++++++++++++++++++ 5 files changed, 110 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/signal_messenger/manifest.json b/homeassistant/components/signal_messenger/manifest.json index 058b01535ea..217109bfa2c 100644 --- a/homeassistant/components/signal_messenger/manifest.json +++ b/homeassistant/components/signal_messenger/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/signal_messenger", "iot_class": "cloud_push", "loggers": ["pysignalclirestapi"], - "requirements": ["pysignalclirestapi==0.3.23"] + "requirements": ["pysignalclirestapi==0.3.24"] } diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 9c8846b2767..b93e5bb43e2 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -27,18 +27,32 @@ CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES = 52428800 ATTR_FILENAMES = "attachments" ATTR_URLS = "urls" ATTR_VERIFY_SSL = "verify_ssl" +ATTR_TEXTMODE = "text_mode" -DATA_FILENAMES_SCHEMA = vol.Schema({vol.Required(ATTR_FILENAMES): [cv.string]}) +TEXTMODE_OPTIONS = ["normal", "styled"] + +DATA_FILENAMES_SCHEMA = vol.Schema( + { + vol.Required(ATTR_FILENAMES): [cv.string], + vol.Optional(ATTR_TEXTMODE, default="normal"): vol.In(TEXTMODE_OPTIONS), + } +) DATA_URLS_SCHEMA = vol.Schema( { vol.Required(ATTR_URLS): [cv.url], vol.Optional(ATTR_VERIFY_SSL, default=True): cv.boolean, + vol.Optional(ATTR_TEXTMODE, default="normal"): vol.In(TEXTMODE_OPTIONS), } ) DATA_SCHEMA = vol.Any( None, + vol.Schema( + { + vol.Optional(ATTR_TEXTMODE, default="normal"): vol.In(TEXTMODE_OPTIONS), + } + ), DATA_FILENAMES_SCHEMA, DATA_URLS_SCHEMA, ) @@ -100,10 +114,13 @@ class SignalNotificationService(BaseNotificationService): attachments_as_bytes = self.get_attachments_as_bytes( data, CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES, self._hass ) - try: self._signal_cli_rest_api.send_message( - message, self._recp_nrs, filenames, attachments_as_bytes + message, + self._recp_nrs, + filenames, + attachments_as_bytes, + text_mode="normal" if data is None else data.get(ATTR_TEXTMODE), ) except SignalCliRestApiError as ex: _LOGGER.error("%s", ex) @@ -116,7 +133,6 @@ class SignalNotificationService(BaseNotificationService): data = DATA_FILENAMES_SCHEMA(data) except vol.Invalid: return None - return data[ATTR_FILENAMES] @staticmethod @@ -130,7 +146,6 @@ class SignalNotificationService(BaseNotificationService): data = DATA_URLS_SCHEMA(data) except vol.Invalid: return None - urls = data[ATTR_URLS] attachments_as_bytes: list[bytearray] = [] diff --git a/requirements_all.txt b/requirements_all.txt index b05bd04154a..37d3b6e68a0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2167,7 +2167,7 @@ pysesame2==1.0.1 pysiaalarm==3.1.1 # homeassistant.components.signal_messenger -pysignalclirestapi==0.3.23 +pysignalclirestapi==0.3.24 # homeassistant.components.sky_hub pyskyqhub==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8b810078a98..0c565ad79f2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1706,7 +1706,7 @@ pyserial==3.5 pysiaalarm==3.1.1 # homeassistant.components.signal_messenger -pysignalclirestapi==0.3.23 +pysignalclirestapi==0.3.24 # homeassistant.components.sma pysma==0.7.3 diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index 012de07df0e..d0085fd6e21 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -64,6 +64,26 @@ def test_send_message( assert_sending_requests(signal_requests_mock) +def test_send_message_styled( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test send styled message.""" + signal_requests_mock = signal_requests_mock_factory() + with caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ): + data = {"text_mode": "styled"} + signal_notification_service.send_message(MESSAGE, data=data) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + assert "Sending signal message" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 2 + assert post_data["text_mode"] == "styled" + assert_sending_requests(signal_requests_mock) + + def test_send_message_to_api_with_bad_data_throws_error( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, @@ -103,6 +123,27 @@ def test_send_message_with_bad_data_throws_vol_error( assert "extra keys not allowed" in str(exc.value) +def test_send_message_styled_with_bad_data_throws_vol_error( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test sending a styled message with bad data throws an error.""" + with ( + caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ), + pytest.raises(vol.Invalid) as exc, + ): + signal_notification_service.send_message(MESSAGE, data={"text_mode": "test"}) + + assert "Sending signal message" in caplog.text + assert ( + "value must be one of ['normal', 'styled'] for dictionary value @ data['text_mode']" + in str(exc.value) + ) + + def test_send_message_with_attachment( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, @@ -128,6 +169,32 @@ def test_send_message_with_attachment( assert_sending_requests(signal_requests_mock, 1) +def test_send_message_styled_with_attachment( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test send message with attachment.""" + signal_requests_mock = signal_requests_mock_factory() + with ( + caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ), + tempfile.NamedTemporaryFile( + mode="w", suffix=".png", prefix=os.path.basename(__file__) + ) as temp_file, + ): + temp_file.write("attachment_data") + data = {"attachments": [temp_file.name], "text_mode": "styled"} + signal_notification_service.send_message(MESSAGE, data=data) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + assert "Sending signal message" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 2 + assert_sending_requests(signal_requests_mock, 1) + assert post_data["text_mode"] == "styled" + + def test_send_message_with_attachment_as_url( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, @@ -147,6 +214,26 @@ def test_send_message_with_attachment_as_url( assert_sending_requests(signal_requests_mock, 1) +def test_send_message_styled_with_attachment_as_url( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test send message with attachment as URL.""" + signal_requests_mock = signal_requests_mock_factory(True, str(len(CONTENT))) + with caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ): + data = {"urls": [URL_ATTACHMENT], "text_mode": "styled"} + signal_notification_service.send_message(MESSAGE, data=data) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + assert "Sending signal message" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 3 + assert_sending_requests(signal_requests_mock, 1) + assert post_data["text_mode"] == "styled" + + def test_get_attachments( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker,