From bc0dc2d22c45df9d8a2bfb292a89b73e92a39063 Mon Sep 17 00:00:00 2001 From: Stefan Tomas <1898211+shtefko@users.noreply.github.com> Date: Wed, 5 Aug 2026 16:44:53 +0200 Subject: [PATCH] Fixes #173399 Seerr webhook registration (#177201) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../components/overseerr/__init__.py | 3 +- homeassistant/components/overseerr/const.py | 67 +++++++++++++------ .../overseerr/fixtures/webhook_config.json | 2 +- .../fixtures/webhook_issue_reported.json | 8 ++- ...ebhook_request_automatically_approved.json | 7 +- .../overseerr/snapshots/test_event.ambr | 6 ++ .../components/overseerr/test_config_flow.py | 3 +- tests/components/overseerr/test_init.py | 11 ++- 8 files changed, 77 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/overseerr/__init__.py b/homeassistant/components/overseerr/__init__.py index 87299859bb8c..44466ad4a51f 100644 --- a/homeassistant/components/overseerr/__init__.py +++ b/homeassistant/components/overseerr/__init__.py @@ -1,6 +1,5 @@ """The Overseerr integration.""" -import json from typing import cast from aiohttp.hdrs import METH_POST @@ -133,7 +132,7 @@ class OverseerrWebhookManager: return ( not current_config.enabled or current_config.options.webhook_url not in self.webhook_urls - or current_config.options.json_payload != json.loads(JSON_PAYLOAD) + or current_config.options.json_payload != JSON_PAYLOAD or current_config.types != REGISTERED_NOTIFICATIONS ) diff --git a/homeassistant/components/overseerr/const.py b/homeassistant/components/overseerr/const.py index a48ac7669b41..8a87aacd9aee 100644 --- a/homeassistant/components/overseerr/const.py +++ b/homeassistant/components/overseerr/const.py @@ -32,25 +32,48 @@ REGISTERED_NOTIFICATIONS = ( | NotificationType.ISSUE_RESOLVED | NotificationType.ISSUE_REOPENED ) -JSON_PAYLOAD = ( - '"{\\"notification_type\\":\\"{{notification_type}}\\",\\"subject\\":\\"{{subject}' - '}\\",\\"message\\":\\"{{message}}\\",\\"image\\":\\"{{image}}\\",\\"{{media}}\\":' - '{\\"media_type\\":\\"{{media_type}}\\",\\"tmdb_id\\":\\"{{media_tmdbid}}\\",\\"t' - 'vdb_id\\":\\"{{media_tvdbid}}\\",\\"status\\":\\"{{media_status}}\\",\\"status4k' - '\\":\\"{{media_status4k}}\\"},\\"{{request}}\\":{\\"request_id\\":\\"{{request_id' - '}}\\",\\"requested_by_email\\":\\"{{requestedBy_email}}\\",\\"requested_by_userna' - 'me\\":\\"{{requestedBy_username}}\\",\\"requested_by_avatar\\":\\"{{requestedBy_a' - 'vatar}}\\",\\"requested_by_settings_discord_id\\":\\"{{requestedBy_settings_disco' - 'rdId}}\\",\\"requested_by_settings_telegram_chat_id\\":\\"{{requestedBy_settings_' - 'telegramChatId}}\\"},\\"{{issue}}\\":{\\"issue_id\\":\\"{{issue_id}}\\",\\"issue_' - 'type\\":\\"{{issue_type}}\\",\\"issue_status\\":\\"{{issue_status}}\\",\\"reporte' - 'd_by_email\\":\\"{{reportedBy_email}}\\",\\"reported_by_username\\":\\"{{reported' - 'By_username}}\\",\\"reported_by_avatar\\":\\"{{reportedBy_avatar}}\\",\\"reported' - '_by_settings_discord_id\\":\\"{{reportedBy_settings_discordId}}\\",\\"reported_by' - '_settings_telegram_chat_id\\":\\"{{reportedBy_settings_telegramChatId}}\\"},\\"{{' - 'comment}}\\":{\\"comment_message\\":\\"{{comment_message}}\\",\\"commented_by_ema' - 'il\\":\\"{{commentedBy_email}}\\",\\"commented_by_username\\":\\"{{commentedBy_us' - 'ername}}\\",\\"commented_by_avatar\\":\\"{{commentedBy_avatar}}\\",\\"commented_b' - 'y_settings_discord_id\\":\\"{{commentedBy_settings_discordId}}\\",\\"commented_by' - '_settings_telegram_chat_id\\":\\"{{commentedBy_settings_telegramChatId}}\\"}}"' -) +JSON_PAYLOAD = """\ +{ + "notification_type": "{{notification_type}}", + "event": "{{event}}", + "subject": "{{subject}}", + "message": "{{message}}", + "image": "{{image}}", + "{{media}}": { + "media_type": "{{media_type}}", + "imdb_id": "{{media_imdbid}}", + "tmdb_id": "{{media_tmdbid}}", + "tvdb_id": "{{media_tvdbid}}", + "jellyfin_media_id": "{{media_jellyfinMediaId}}", + "status": "{{media_status}}", + "status4k": "{{media_status4k}}" + }, + "{{request}}": { + "request_id": "{{request_id}}", + "requested_by_email": "{{requestedBy_email}}", + "requested_by_username": "{{requestedBy_username}}", + "requested_by_avatar": "{{requestedBy_avatar}}", + "requested_by_jellyfin_user_id": "{{requestedBy_jellyfinUserId}}", + "requested_by_settings_discord_id": "{{requestedBy_settings_discordIds}}", + "requested_by_settings_telegram_chat_id": "{{requestedBy_settings_telegramChatId}}" + }, + "{{issue}}": { + "issue_id": "{{issue_id}}", + "issue_type": "{{issue_type}}", + "issue_status": "{{issue_status}}", + "reported_by_email": "{{reportedBy_email}}", + "reported_by_username": "{{reportedBy_username}}", + "reported_by_avatar": "{{reportedBy_avatar}}", + "reported_by_settings_discord_id": "{{reportedBy_settings_discordIds}}", + "reported_by_settings_telegram_chat_id": "{{reportedBy_settings_telegramChatId}}" + }, + "{{comment}}": { + "comment_message": "{{comment_message}}", + "commented_by_email": "{{commentedBy_email}}", + "commented_by_username": "{{commentedBy_username}}", + "commented_by_avatar": "{{commentedBy_avatar}}", + "commented_by_settings_discord_id": "{{commentedBy_settings_discordIds}}", + "commented_by_settings_telegram_chat_id": "{{commentedBy_settings_telegramChatId}}" + }, + "{{extra}}": [] +}""" diff --git a/tests/components/overseerr/fixtures/webhook_config.json b/tests/components/overseerr/fixtures/webhook_config.json index 48619a41ba72..38c01e703208 100644 --- a/tests/components/overseerr/fixtures/webhook_config.json +++ b/tests/components/overseerr/fixtures/webhook_config.json @@ -2,7 +2,7 @@ "enabled": true, "types": 4062, "options": { - "jsonPayload": "{\"notification_type\":\"{{notification_type}}\",\"subject\":\"{{subject}}\",\"message\":\"{{message}}\",\"image\":\"{{image}}\",\"{{media}}\":{\"media_type\":\"{{media_type}}\",\"tmdb_id\":\"{{media_tmdbid}}\",\"tvdb_id\":\"{{media_tvdbid}}\",\"status\":\"{{media_status}}\",\"status4k\":\"{{media_status4k}}\"},\"{{request}}\":{\"request_id\":\"{{request_id}}\",\"requested_by_email\":\"{{requestedBy_email}}\",\"requested_by_username\":\"{{requestedBy_username}}\",\"requested_by_avatar\":\"{{requestedBy_avatar}}\",\"requested_by_settings_discord_id\":\"{{requestedBy_settings_discordId}}\",\"requested_by_settings_telegram_chat_id\":\"{{requestedBy_settings_telegramChatId}}\"},\"{{issue}}\":{\"issue_id\":\"{{issue_id}}\",\"issue_type\":\"{{issue_type}}\",\"issue_status\":\"{{issue_status}}\",\"reported_by_email\":\"{{reportedBy_email}}\",\"reported_by_username\":\"{{reportedBy_username}}\",\"reported_by_avatar\":\"{{reportedBy_avatar}}\",\"reported_by_settings_discord_id\":\"{{reportedBy_settings_discordId}}\",\"reported_by_settings_telegram_chat_id\":\"{{reportedBy_settings_telegramChatId}}\"},\"{{comment}}\":{\"comment_message\":\"{{comment_message}}\",\"commented_by_email\":\"{{commentedBy_email}}\",\"commented_by_username\":\"{{commentedBy_username}}\",\"commented_by_avatar\":\"{{commentedBy_avatar}}\",\"commented_by_settings_discord_id\":\"{{commentedBy_settings_discordId}}\",\"commented_by_settings_telegram_chat_id\":\"{{commentedBy_settings_telegramChatId}}\"}}", + "jsonPayload": "{\n \"notification_type\": \"{{notification_type}}\",\n \"event\": \"{{event}}\",\n \"subject\": \"{{subject}}\",\n \"message\": \"{{message}}\",\n \"image\": \"{{image}}\",\n \"{{media}}\": {\n \"media_type\": \"{{media_type}}\",\n \"imdb_id\": \"{{media_imdbid}}\",\n \"tmdb_id\": \"{{media_tmdbid}}\",\n \"tvdb_id\": \"{{media_tvdbid}}\",\n \"jellyfin_media_id\": \"{{media_jellyfinMediaId}}\",\n \"status\": \"{{media_status}}\",\n \"status4k\": \"{{media_status4k}}\"\n },\n \"{{request}}\": {\n \"request_id\": \"{{request_id}}\",\n \"requested_by_email\": \"{{requestedBy_email}}\",\n \"requested_by_username\": \"{{requestedBy_username}}\",\n \"requested_by_avatar\": \"{{requestedBy_avatar}}\",\n \"requested_by_jellyfin_user_id\": \"{{requestedBy_jellyfinUserId}}\",\n \"requested_by_settings_discord_id\": \"{{requestedBy_settings_discordIds}}\",\n \"requested_by_settings_telegram_chat_id\": \"{{requestedBy_settings_telegramChatId}}\"\n },\n \"{{issue}}\": {\n \"issue_id\": \"{{issue_id}}\",\n \"issue_type\": \"{{issue_type}}\",\n \"issue_status\": \"{{issue_status}}\",\n \"reported_by_email\": \"{{reportedBy_email}}\",\n \"reported_by_username\": \"{{reportedBy_username}}\",\n \"reported_by_avatar\": \"{{reportedBy_avatar}}\",\n \"reported_by_settings_discord_id\": \"{{reportedBy_settings_discordIds}}\",\n \"reported_by_settings_telegram_chat_id\": \"{{reportedBy_settings_telegramChatId}}\"\n },\n \"{{comment}}\": {\n \"comment_message\": \"{{comment_message}}\",\n \"commented_by_email\": \"{{commentedBy_email}}\",\n \"commented_by_username\": \"{{commentedBy_username}}\",\n \"commented_by_avatar\": \"{{commentedBy_avatar}}\",\n \"commented_by_settings_discord_id\": \"{{commentedBy_settings_discordIds}}\",\n \"commented_by_settings_telegram_chat_id\": \"{{commentedBy_settings_telegramChatId}}\"\n },\n \"{{extra}}\": []\n}", "webhookUrl": "http://10.10.10.10:8123/api/webhook/test-webhook-id" } } diff --git a/tests/components/overseerr/fixtures/webhook_issue_reported.json b/tests/components/overseerr/fixtures/webhook_issue_reported.json index 425e27529424..727e5f8e94e9 100644 --- a/tests/components/overseerr/fixtures/webhook_issue_reported.json +++ b/tests/components/overseerr/fixtures/webhook_issue_reported.json @@ -1,15 +1,19 @@ { "notification_type": "ISSUE_REPORTED", + "event": "Issue was reported", "subject": "New Issue Reported", "message": "A new video issue has been reported for Interstellar", "image": "https://image.tmdb.org/t/p/w600_and_h900_bestv2/gEU2QniE6E77NI6lCU6MxlNBvIx.jpg", "media": { "media_type": "movie", + "imdb_id": "tt1234567", "tmdb_id": "157336", "tvdb_id": "", + "jellyfin_media_id": "", "status": "available", "status4k": "unknown" }, + "request": null, "issue": { "issue_id": "1", "issue_type": "video", @@ -19,5 +23,7 @@ "reported_by_avatar": "/os_logo_square.png", "reported_by_settings_discord_id": "", "reported_by_settings_telegram_chat_id": "" - } + }, + "comment": null, + "extra": [] } diff --git a/tests/components/overseerr/fixtures/webhook_request_automatically_approved.json b/tests/components/overseerr/fixtures/webhook_request_automatically_approved.json index 75059bcaf966..9a3685a72b3f 100644 --- a/tests/components/overseerr/fixtures/webhook_request_automatically_approved.json +++ b/tests/components/overseerr/fixtures/webhook_request_automatically_approved.json @@ -1,12 +1,15 @@ { "notification_type": "MEDIA_AUTO_APPROVED", + "event": "Request was auto-approved", "subject": "Something (2024)", "message": "Here is an interesting Linux ISO that was automatically approved.", "image": "https://image.tmdb.org/t/p/w600_and_h900_bestv2/something.jpg", "media": { "media_type": "movie", + "imdb_id": "tt1234567", "tmdb_id": "123", "tvdb_id": "", + "jellyfin_media_id": "", "status": "PENDING", "status4k": "UNKNOWN" }, @@ -15,9 +18,11 @@ "requested_by_email": "my@email.com", "requested_by_username": "henk", "requested_by_avatar": "https://plex.tv/users/abc/avatar?c=123", + "requested_by_jellyfin_user_id": "", "requested_by_settings_discord_id": "123", "requested_by_settings_telegram_chat_id": "" }, "issue": null, - "comment": null + "comment": null, + "extra": [] } diff --git a/tests/components/overseerr/snapshots/test_event.ambr b/tests/components/overseerr/snapshots/test_event.ambr index f11e8d17d675..d9d01fbaab83 100644 --- a/tests/components/overseerr/snapshots/test_event.ambr +++ b/tests/components/overseerr/snapshots/test_event.ambr @@ -49,6 +49,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'https://image.tmdb.org/t/p/w600_and_h900_bestv2/something.jpg', + 'event': 'Request was auto-approved', : 'auto_approved', : list([ 'pending', @@ -58,8 +59,12 @@ 'declined', 'auto_approved', ]), + 'extra': list([ + ]), : 'Overseerr Last media event', 'media': dict({ + 'imdb_id': 'tt1234567', + 'jellyfin_media_id': '', 'media_type': 'movie', 'status': 'pending', 'status4k': 'unknown', @@ -71,6 +76,7 @@ 'request_id': 16, 'requested_by_avatar': 'https://plex.tv/users/abc/avatar?c=123', 'requested_by_email': 'my@email.com', + 'requested_by_jellyfin_user_id': '', 'requested_by_settings_discord_id': '123', 'requested_by_settings_telegram_chat_id': '', 'requested_by_username': 'henk', diff --git a/tests/components/overseerr/test_config_flow.py b/tests/components/overseerr/test_config_flow.py index 7f3b3150b358..e0108b1ecb66 100644 --- a/tests/components/overseerr/test_config_flow.py +++ b/tests/components/overseerr/test_config_flow.py @@ -1,5 +1,6 @@ """Tests for the Overseerr config flow.""" +from collections.abc import Generator from unittest.mock import AsyncMock, patch import pytest @@ -27,7 +28,7 @@ from tests.common import MockConfigEntry @pytest.fixture(autouse=True) -def patch_webhook_id() -> None: +def patch_webhook_id() -> Generator[None]: """Patch webhook ID generation.""" with patch( "homeassistant.components.overseerr.config_flow.async_generate_id", diff --git a/tests/components/overseerr/test_init.py b/tests/components/overseerr/test_init.py index 5a63df170aae..0b3021ab9613 100644 --- a/tests/components/overseerr/test_init.py +++ b/tests/components/overseerr/test_init.py @@ -1,5 +1,6 @@ """Tests for the Overseerr integration.""" +import json from typing import Any from unittest.mock import AsyncMock, patch @@ -91,7 +92,7 @@ async def test_proper_webhook_configuration( { "return_value.options": WebhookNotificationOptions( webhook_url="http://10.10.10.10:8123/api/webhook/test-webhook-id", - json_payload='"{\\"message\\": \\"{{title}}\\"}"', + json_payload='{"message": "{{title}}"}', ) }, ], @@ -130,7 +131,7 @@ async def test_webhook_configuration_need_update( { "return_value.options": WebhookNotificationOptions( webhook_url="http://10.10.10.10:8123/api/webhook/test-webhook-id", - json_payload='"{\\"message\\": \\"{{title}}\\"}"', + json_payload='{"message": "{{title}}"}', ) }, ], @@ -157,6 +158,12 @@ async def test_webhook_failing_test( mock_overseerr_client.set_webhook_notification_config.assert_not_called() +async def test_webhook_json_payload_formatting() -> None: + """Test the webhook JSON payload formatting.""" + + assert json.loads(JSON_PAYLOAD)["notification_type"] == "{{notification_type}}" + + async def test_prefer_internal_ip( hass: HomeAssistant, mock_config_entry: MockConfigEntry,