mirror of
https://github.com/home-assistant/core.git
synced 2025-09-09 14:51:34 +02:00
Remove deprecated notify platform from Mastodon (#149735)
This commit is contained in:
@@ -8,12 +8,11 @@ from homeassistant.const import (
|
|||||||
CONF_ACCESS_TOKEN,
|
CONF_ACCESS_TOKEN,
|
||||||
CONF_CLIENT_ID,
|
CONF_CLIENT_ID,
|
||||||
CONF_CLIENT_SECRET,
|
CONF_CLIENT_SECRET,
|
||||||
CONF_NAME,
|
|
||||||
Platform,
|
Platform,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers import config_validation as cv, discovery
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ from .coordinator import MastodonConfigEntry, MastodonCoordinator, MastodonData
|
|||||||
from .services import setup_services
|
from .services import setup_services
|
||||||
from .utils import construct_mastodon_username, create_mastodon_client
|
from .utils import construct_mastodon_username, create_mastodon_client
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [Platform.NOTIFY, Platform.SENSOR]
|
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
|
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
|
||||||
|
|
||||||
@@ -53,26 +52,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: MastodonConfigEntry) ->
|
|||||||
|
|
||||||
entry.runtime_data = MastodonData(client, instance, account, coordinator)
|
entry.runtime_data = MastodonData(client, instance, account, coordinator)
|
||||||
|
|
||||||
await discovery.async_load_platform(
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
hass,
|
|
||||||
Platform.NOTIFY,
|
|
||||||
DOMAIN,
|
|
||||||
{CONF_NAME: entry.title, "client": client},
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(
|
|
||||||
entry, [platform for platform in PLATFORMS if platform != Platform.NOTIFY]
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: MastodonConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: MastodonConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
return await hass.config_entries.async_unload_platforms(
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
entry, [platform for platform in PLATFORMS if platform != Platform.NOTIFY]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_migrate_entry(hass: HomeAssistant, entry: MastodonConfigEntry) -> bool:
|
async def async_migrate_entry(hass: HomeAssistant, entry: MastodonConfigEntry) -> bool:
|
||||||
|
@@ -1,152 +0,0 @@
|
|||||||
"""Mastodon platform for notify component."""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from typing import Any, cast
|
|
||||||
|
|
||||||
from mastodon import Mastodon
|
|
||||||
from mastodon.Mastodon import MastodonAPIError, MediaAttachment
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.notify import (
|
|
||||||
ATTR_DATA,
|
|
||||||
PLATFORM_SCHEMA as NOTIFY_PLATFORM_SCHEMA,
|
|
||||||
BaseNotificationService,
|
|
||||||
)
|
|
||||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers import config_validation as cv, issue_registry as ir
|
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
||||||
|
|
||||||
from .const import (
|
|
||||||
ATTR_CONTENT_WARNING,
|
|
||||||
ATTR_MEDIA_WARNING,
|
|
||||||
CONF_BASE_URL,
|
|
||||||
DEFAULT_URL,
|
|
||||||
DOMAIN,
|
|
||||||
)
|
|
||||||
from .utils import get_media_type
|
|
||||||
|
|
||||||
ATTR_MEDIA = "media"
|
|
||||||
ATTR_TARGET = "target"
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = NOTIFY_PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_ACCESS_TOKEN): cv.string,
|
|
||||||
vol.Required(CONF_CLIENT_ID): cv.string,
|
|
||||||
vol.Required(CONF_CLIENT_SECRET): cv.string,
|
|
||||||
vol.Optional(CONF_BASE_URL, default=DEFAULT_URL): cv.string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
INTEGRATION_TITLE = "Mastodon"
|
|
||||||
|
|
||||||
|
|
||||||
async def async_get_service(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
|
||||||
) -> MastodonNotificationService | None:
|
|
||||||
"""Get the Mastodon notification service."""
|
|
||||||
if discovery_info is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
client = cast(Mastodon, discovery_info.get("client"))
|
|
||||||
|
|
||||||
return MastodonNotificationService(hass, client)
|
|
||||||
|
|
||||||
|
|
||||||
class MastodonNotificationService(BaseNotificationService):
|
|
||||||
"""Implement the notification service for Mastodon."""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
hass: HomeAssistant,
|
|
||||||
client: Mastodon,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize the service."""
|
|
||||||
|
|
||||||
self.client = client
|
|
||||||
|
|
||||||
def send_message(self, message: str = "", **kwargs: Any) -> None:
|
|
||||||
"""Toot a message, with media perhaps."""
|
|
||||||
|
|
||||||
ir.create_issue(
|
|
||||||
self.hass,
|
|
||||||
DOMAIN,
|
|
||||||
"deprecated_notify_action_mastodon",
|
|
||||||
breaks_in_ha_version="2025.9.0",
|
|
||||||
is_fixable=False,
|
|
||||||
issue_domain=DOMAIN,
|
|
||||||
severity=ir.IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_notify_action",
|
|
||||||
)
|
|
||||||
|
|
||||||
target = None
|
|
||||||
if (target_list := kwargs.get(ATTR_TARGET)) is not None:
|
|
||||||
target = cast(list[str], target_list)[0]
|
|
||||||
|
|
||||||
data = kwargs.get(ATTR_DATA)
|
|
||||||
|
|
||||||
media = None
|
|
||||||
mediadata = None
|
|
||||||
sensitive = False
|
|
||||||
content_warning = None
|
|
||||||
|
|
||||||
if data:
|
|
||||||
media = data.get(ATTR_MEDIA)
|
|
||||||
if media:
|
|
||||||
if not self.hass.config.is_allowed_path(media):
|
|
||||||
raise HomeAssistantError(
|
|
||||||
translation_domain=DOMAIN,
|
|
||||||
translation_key="not_whitelisted_directory",
|
|
||||||
translation_placeholders={"media": media},
|
|
||||||
)
|
|
||||||
mediadata = self._upload_media(media)
|
|
||||||
|
|
||||||
sensitive = data.get(ATTR_MEDIA_WARNING)
|
|
||||||
content_warning = data.get(ATTR_CONTENT_WARNING)
|
|
||||||
|
|
||||||
if mediadata:
|
|
||||||
try:
|
|
||||||
self.client.status_post(
|
|
||||||
message,
|
|
||||||
visibility=target,
|
|
||||||
spoiler_text=content_warning,
|
|
||||||
media_ids=mediadata.id,
|
|
||||||
sensitive=sensitive,
|
|
||||||
)
|
|
||||||
except MastodonAPIError as err:
|
|
||||||
raise HomeAssistantError(
|
|
||||||
translation_domain=DOMAIN,
|
|
||||||
translation_key="unable_to_send_message",
|
|
||||||
) from err
|
|
||||||
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self.client.status_post(
|
|
||||||
message, visibility=target, spoiler_text=content_warning
|
|
||||||
)
|
|
||||||
except MastodonAPIError as err:
|
|
||||||
raise HomeAssistantError(
|
|
||||||
translation_domain=DOMAIN,
|
|
||||||
translation_key="unable_to_send_message",
|
|
||||||
) from err
|
|
||||||
|
|
||||||
def _upload_media(self, media_path: Any = None) -> MediaAttachment:
|
|
||||||
"""Upload media."""
|
|
||||||
with open(media_path, "rb"):
|
|
||||||
media_type = get_media_type(media_path)
|
|
||||||
try:
|
|
||||||
mediadata: MediaAttachment = self.client.media_post(
|
|
||||||
media_path, mime_type=media_type
|
|
||||||
)
|
|
||||||
except MastodonAPIError as err:
|
|
||||||
raise HomeAssistantError(
|
|
||||||
translation_domain=DOMAIN,
|
|
||||||
translation_key="unable_to_upload_image",
|
|
||||||
translation_placeholders={"media_path": media_path},
|
|
||||||
) from err
|
|
||||||
|
|
||||||
return mediadata
|
|
@@ -26,10 +26,7 @@ rules:
|
|||||||
unique-config-entry: done
|
unique-config-entry: done
|
||||||
|
|
||||||
# Silver
|
# Silver
|
||||||
action-exceptions:
|
action-exceptions: done
|
||||||
status: todo
|
|
||||||
comment: |
|
|
||||||
Awaiting legacy Notify deprecation.
|
|
||||||
config-entry-unloading: done
|
config-entry-unloading: done
|
||||||
docs-configuration-parameters:
|
docs-configuration-parameters:
|
||||||
status: exempt
|
status: exempt
|
||||||
@@ -39,19 +36,12 @@ rules:
|
|||||||
entity-unavailable: done
|
entity-unavailable: done
|
||||||
integration-owner: done
|
integration-owner: done
|
||||||
log-when-unavailable: done
|
log-when-unavailable: done
|
||||||
parallel-updates:
|
parallel-updates: done
|
||||||
status: todo
|
|
||||||
comment: |
|
|
||||||
Awaiting legacy Notify deprecation.
|
|
||||||
reauthentication-flow:
|
reauthentication-flow:
|
||||||
status: todo
|
status: todo
|
||||||
comment: |
|
comment: |
|
||||||
Waiting to move to oAuth.
|
Waiting to move to oAuth.
|
||||||
test-coverage:
|
test-coverage: done
|
||||||
status: todo
|
|
||||||
comment: |
|
|
||||||
Awaiting legacy Notify deprecation.
|
|
||||||
|
|
||||||
# Gold
|
# Gold
|
||||||
devices: done
|
devices: done
|
||||||
diagnostics: done
|
diagnostics: done
|
||||||
|
@@ -42,12 +42,6 @@
|
|||||||
"message": "{media} is not a whitelisted directory."
|
"message": "{media} is not a whitelisted directory."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"issues": {
|
|
||||||
"deprecated_notify_action": {
|
|
||||||
"title": "Deprecated Notify action used for Mastodon",
|
|
||||||
"description": "The Notify action for Mastodon is deprecated.\n\nUse the `mastodon.post` action instead."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"entity": {
|
"entity": {
|
||||||
"sensor": {
|
"sensor": {
|
||||||
"followers": {
|
"followers": {
|
||||||
|
@@ -1,65 +0,0 @@
|
|||||||
"""Tests for the Mastodon notify platform."""
|
|
||||||
|
|
||||||
from unittest.mock import AsyncMock
|
|
||||||
|
|
||||||
from mastodon.Mastodon import MastodonAPIError
|
|
||||||
import pytest
|
|
||||||
from syrupy.assertion import SnapshotAssertion
|
|
||||||
|
|
||||||
from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
|
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
|
||||||
from homeassistant.helpers import entity_registry as er
|
|
||||||
|
|
||||||
from . import setup_integration
|
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
|
||||||
|
|
||||||
|
|
||||||
async def test_notify(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
snapshot: SnapshotAssertion,
|
|
||||||
entity_registry: er.EntityRegistry,
|
|
||||||
mock_mastodon_client: AsyncMock,
|
|
||||||
mock_config_entry: MockConfigEntry,
|
|
||||||
) -> None:
|
|
||||||
"""Test sending a message."""
|
|
||||||
await setup_integration(hass, mock_config_entry)
|
|
||||||
|
|
||||||
assert hass.services.has_service(NOTIFY_DOMAIN, "trwnh_mastodon_social")
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
|
||||||
NOTIFY_DOMAIN,
|
|
||||||
"trwnh_mastodon_social",
|
|
||||||
{
|
|
||||||
"message": "test toot",
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
return_response=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert mock_mastodon_client.status_post.assert_called_once
|
|
||||||
|
|
||||||
|
|
||||||
async def test_notify_failed(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
mock_mastodon_client: AsyncMock,
|
|
||||||
mock_config_entry: MockConfigEntry,
|
|
||||||
) -> None:
|
|
||||||
"""Test the notify raising an error."""
|
|
||||||
mock_config_entry.add_to_hass(hass)
|
|
||||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
mock_mastodon_client.status_post.side_effect = MastodonAPIError
|
|
||||||
|
|
||||||
with pytest.raises(HomeAssistantError, match="Unable to send message"):
|
|
||||||
await hass.services.async_call(
|
|
||||||
NOTIFY_DOMAIN,
|
|
||||||
"trwnh_mastodon_social",
|
|
||||||
{
|
|
||||||
"message": "test toot",
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
return_response=False,
|
|
||||||
)
|
|
Reference in New Issue
Block a user