mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Remove Twitch YAML import (#115278)
This commit is contained in:
parent
d2dcf04946
commit
e7c247f1f0
@ -8,17 +8,13 @@ from typing import Any, cast
|
|||||||
|
|
||||||
from twitchAPI.helper import first
|
from twitchAPI.helper import first
|
||||||
from twitchAPI.twitch import Twitch
|
from twitchAPI.twitch import Twitch
|
||||||
from twitchAPI.type import AuthScope, InvalidTokenException
|
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigFlowResult
|
from homeassistant.config_entries import ConfigEntry, ConfigFlowResult
|
||||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_CLIENT_ID, CONF_TOKEN
|
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_TOKEN
|
||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN
|
|
||||||
from homeassistant.data_entry_flow import AbortFlow
|
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
from homeassistant.helpers.config_entry_oauth2_flow import LocalOAuth2Implementation
|
from homeassistant.helpers.config_entry_oauth2_flow import LocalOAuth2Implementation
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
||||||
|
|
||||||
from .const import CONF_CHANNELS, CONF_REFRESH_TOKEN, DOMAIN, LOGGER, OAUTH_SCOPES
|
from .const import CONF_CHANNELS, DOMAIN, LOGGER, OAUTH_SCOPES
|
||||||
|
|
||||||
|
|
||||||
class OAuth2FlowHandler(
|
class OAuth2FlowHandler(
|
||||||
@ -121,77 +117,3 @@ class OAuth2FlowHandler(
|
|||||||
if user_input is None:
|
if user_input is None:
|
||||||
return self.async_show_form(step_id="reauth_confirm")
|
return self.async_show_form(step_id="reauth_confirm")
|
||||||
return await self.async_step_user()
|
return await self.async_step_user()
|
||||||
|
|
||||||
async def async_step_import(self, config: dict[str, Any]) -> ConfigFlowResult:
|
|
||||||
"""Import from yaml."""
|
|
||||||
client = await Twitch(
|
|
||||||
app_id=config[CONF_CLIENT_ID],
|
|
||||||
authenticate_app=False,
|
|
||||||
)
|
|
||||||
client.auto_refresh_auth = False
|
|
||||||
token = config[CONF_TOKEN]
|
|
||||||
try:
|
|
||||||
await client.set_user_authentication(
|
|
||||||
token, validate=True, scope=[AuthScope.USER_READ_SUBSCRIPTIONS]
|
|
||||||
)
|
|
||||||
except InvalidTokenException:
|
|
||||||
async_create_issue(
|
|
||||||
self.hass,
|
|
||||||
DOMAIN,
|
|
||||||
"deprecated_yaml_invalid_token",
|
|
||||||
breaks_in_ha_version="2024.4.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml_invalid_token",
|
|
||||||
translation_placeholders={
|
|
||||||
"domain": DOMAIN,
|
|
||||||
"integration_title": "Twitch",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return self.async_abort(reason="invalid_token")
|
|
||||||
user = await first(client.get_users())
|
|
||||||
assert user
|
|
||||||
await self.async_set_unique_id(user.id)
|
|
||||||
try:
|
|
||||||
self._abort_if_unique_id_configured()
|
|
||||||
except AbortFlow:
|
|
||||||
async_create_issue(
|
|
||||||
self.hass,
|
|
||||||
DOMAIN,
|
|
||||||
"deprecated_yaml_already_imported",
|
|
||||||
breaks_in_ha_version="2024.4.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml_already_imported",
|
|
||||||
translation_placeholders={
|
|
||||||
"domain": DOMAIN,
|
|
||||||
"integration_title": "Twitch",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
raise
|
|
||||||
async_create_issue(
|
|
||||||
self.hass,
|
|
||||||
HOMEASSISTANT_DOMAIN,
|
|
||||||
"deprecated_yaml",
|
|
||||||
breaks_in_ha_version="2024.4.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml",
|
|
||||||
translation_placeholders={
|
|
||||||
"domain": DOMAIN,
|
|
||||||
"integration_title": "Twitch",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return self.async_create_entry(
|
|
||||||
title=user.display_name,
|
|
||||||
data={
|
|
||||||
"auth_implementation": DOMAIN,
|
|
||||||
CONF_TOKEN: {
|
|
||||||
CONF_ACCESS_TOKEN: token,
|
|
||||||
CONF_REFRESH_TOKEN: "",
|
|
||||||
"expires_at": 0,
|
|
||||||
},
|
|
||||||
"imported": True,
|
|
||||||
},
|
|
||||||
options={CONF_CHANNELS: config[CONF_CHANNELS]},
|
|
||||||
)
|
|
||||||
|
@ -10,34 +10,15 @@ from twitchAPI.twitch import (
|
|||||||
TwitchResourceNotFound,
|
TwitchResourceNotFound,
|
||||||
TwitchUser,
|
TwitchUser,
|
||||||
)
|
)
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.application_credentials import (
|
from homeassistant.components.sensor import SensorEntity
|
||||||
ClientCredential,
|
from homeassistant.config_entries import ConfigEntry
|
||||||
async_import_client_credential,
|
|
||||||
)
|
|
||||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
|
||||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_TOKEN
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
|
from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|
||||||
|
|
||||||
from .const import CLIENT, CONF_CHANNELS, DOMAIN, LOGGER, OAUTH_SCOPES, SESSION
|
from .const import CLIENT, CONF_CHANNELS, DOMAIN, LOGGER, OAUTH_SCOPES, SESSION
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_CLIENT_ID): cv.string,
|
|
||||||
vol.Required(CONF_CLIENT_SECRET): cv.string,
|
|
||||||
vol.Required(CONF_CHANNELS): vol.All(cv.ensure_list, [cv.string]),
|
|
||||||
vol.Optional(CONF_TOKEN): cv.string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
ATTR_GAME = "game"
|
ATTR_GAME = "game"
|
||||||
ATTR_TITLE = "title"
|
ATTR_TITLE = "title"
|
||||||
ATTR_SUBSCRIPTION = "subscribed"
|
ATTR_SUBSCRIPTION = "subscribed"
|
||||||
@ -59,40 +40,6 @@ def chunk_list(lst: list, chunk_size: int) -> list[list]:
|
|||||||
return [lst[i : i + chunk_size] for i in range(0, len(lst), chunk_size)]
|
return [lst[i : i + chunk_size] for i in range(0, len(lst), chunk_size)]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
config: ConfigType,
|
|
||||||
async_add_entities: AddEntitiesCallback,
|
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Set up the Twitch platform."""
|
|
||||||
await async_import_client_credential(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
ClientCredential(config[CONF_CLIENT_ID], config[CONF_CLIENT_SECRET]),
|
|
||||||
)
|
|
||||||
if CONF_TOKEN in config:
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
async_create_issue(
|
|
||||||
hass,
|
|
||||||
DOMAIN,
|
|
||||||
"deprecated_yaml_credentials_imported",
|
|
||||||
breaks_in_ha_version="2024.4.0",
|
|
||||||
is_fixable=False,
|
|
||||||
severity=IssueSeverity.WARNING,
|
|
||||||
translation_key="deprecated_yaml_credentials_imported",
|
|
||||||
translation_placeholders={
|
|
||||||
"domain": DOMAIN,
|
|
||||||
"integration_title": "Twitch",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entry: ConfigEntry,
|
entry: ConfigEntry,
|
||||||
|
@ -16,19 +16,5 @@
|
|||||||
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
|
"oauth_unauthorized": "[%key:common::config_flow::abort::oauth2_unauthorized%]",
|
||||||
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]"
|
"oauth_failed": "[%key:common::config_flow::abort::oauth2_failed%]"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"issues": {
|
|
||||||
"deprecated_yaml_invalid_token": {
|
|
||||||
"title": "The {integration_title} YAML configuration is being removed",
|
|
||||||
"description": "Configuring {integration_title} using YAML is being removed.\n\nYour configuration couldn't be imported because the token in the configuration.yaml was invalid.\n\nPlease add Twitch again via the UI.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
|
|
||||||
},
|
|
||||||
"deprecated_yaml_credentials_imported": {
|
|
||||||
"title": "The {integration_title} YAML configuration is being removed",
|
|
||||||
"description": "Configuring {integration_title} using YAML is being removed.\n\nYour application credentials are imported, but a config entry could not be created because there was no access token.\n\nPlease add Twitch again via the UI.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
|
|
||||||
},
|
|
||||||
"deprecated_yaml_already_imported": {
|
|
||||||
"title": "The {integration_title} YAML configuration is being removed",
|
|
||||||
"description": "Configuring {integration_title} using YAML is being removed.\n\nYour application credentials are already imported.\n\nRemove the `{domain}` configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,20 @@
|
|||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from homeassistant.components.twitch.const import (
|
from homeassistant.components.twitch.const import (
|
||||||
CONF_CHANNELS,
|
CONF_CHANNELS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
OAUTH2_AUTHORIZE,
|
OAUTH2_AUTHORIZE,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_REAUTH, SOURCE_USER
|
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
|
||||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_TOKEN
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResult, FlowResultType
|
from homeassistant.data_entry_flow import FlowResult, FlowResultType
|
||||||
from homeassistant.helpers import config_entry_oauth2_flow, issue_registry as ir
|
from homeassistant.helpers import config_entry_oauth2_flow
|
||||||
|
|
||||||
from . import setup_integration
|
from . import setup_integration
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
from tests.components.twitch import TwitchInvalidTokenMock, TwitchMock
|
from tests.components.twitch import TwitchMock
|
||||||
from tests.components.twitch.conftest import CLIENT_ID, TITLE
|
from tests.components.twitch.conftest import CLIENT_ID, TITLE
|
||||||
from tests.typing import ClientSessionGenerator
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
@ -206,91 +203,3 @@ async def test_reauth_wrong_account(
|
|||||||
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
assert result["reason"] == "wrong_account"
|
assert result["reason"] == "wrong_account"
|
||||||
|
|
||||||
|
|
||||||
async def test_import(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
hass_client_no_auth: ClientSessionGenerator,
|
|
||||||
current_request_with_host: None,
|
|
||||||
mock_setup_entry,
|
|
||||||
twitch: TwitchMock,
|
|
||||||
) -> None:
|
|
||||||
"""Test import flow."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={
|
|
||||||
"source": SOURCE_IMPORT,
|
|
||||||
},
|
|
||||||
data={
|
|
||||||
"platform": "twitch",
|
|
||||||
CONF_CLIENT_ID: "1234",
|
|
||||||
CONF_CLIENT_SECRET: "abcd",
|
|
||||||
CONF_TOKEN: "efgh",
|
|
||||||
"channels": ["channel123"],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
||||||
assert result["title"] == "channel123"
|
|
||||||
assert "result" in result
|
|
||||||
assert "token" in result["result"].data
|
|
||||||
assert result["result"].data["token"]["access_token"] == "efgh"
|
|
||||||
assert result["result"].data["token"]["refresh_token"] == ""
|
|
||||||
assert result["result"].unique_id == "123"
|
|
||||||
assert result["options"] == {CONF_CHANNELS: ["channel123"]}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("twitch_mock", [TwitchInvalidTokenMock()])
|
|
||||||
async def test_import_invalid_token(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
hass_client_no_auth: ClientSessionGenerator,
|
|
||||||
current_request_with_host: None,
|
|
||||||
mock_setup_entry,
|
|
||||||
twitch: TwitchMock,
|
|
||||||
) -> None:
|
|
||||||
"""Test import flow."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={
|
|
||||||
"source": SOURCE_IMPORT,
|
|
||||||
},
|
|
||||||
data={
|
|
||||||
"platform": "twitch",
|
|
||||||
CONF_CLIENT_ID: "1234",
|
|
||||||
CONF_CLIENT_SECRET: "abcd",
|
|
||||||
CONF_TOKEN: "efgh",
|
|
||||||
"channels": ["channel123"],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
|
||||||
assert result["reason"] == "invalid_token"
|
|
||||||
issue_registry = ir.async_get(hass)
|
|
||||||
assert len(issue_registry.issues) == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_import_already_imported(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
hass_client_no_auth: ClientSessionGenerator,
|
|
||||||
current_request_with_host: None,
|
|
||||||
config_entry: MockConfigEntry,
|
|
||||||
mock_setup_entry,
|
|
||||||
twitch: TwitchMock,
|
|
||||||
) -> None:
|
|
||||||
"""Test import flow where the config is already imported."""
|
|
||||||
await setup_integration(hass, config_entry)
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={
|
|
||||||
"source": SOURCE_IMPORT,
|
|
||||||
},
|
|
||||||
data={
|
|
||||||
"platform": "twitch",
|
|
||||||
CONF_CLIENT_ID: "1234",
|
|
||||||
CONF_CLIENT_SECRET: "abcd",
|
|
||||||
CONF_TOKEN: "efgh",
|
|
||||||
"channels": ["channel123"],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
|
||||||
assert result["reason"] == "already_configured"
|
|
||||||
issue_registry = ir.async_get(hass)
|
|
||||||
assert len(issue_registry.issues) == 1
|
|
||||||
|
@ -4,12 +4,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
|
||||||
from homeassistant.components.twitch.const import CONF_CHANNELS, DOMAIN
|
|
||||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_TOKEN, Platform
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import issue_registry as ir
|
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
|
|
||||||
from ...common import MockConfigEntry
|
from ...common import MockConfigEntry
|
||||||
from . import (
|
from . import (
|
||||||
@ -23,58 +18,6 @@ from . import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
ENTITY_ID = "sensor.channel123"
|
ENTITY_ID = "sensor.channel123"
|
||||||
CONFIG = {
|
|
||||||
"auth_implementation": "cred",
|
|
||||||
CONF_CLIENT_ID: "1234",
|
|
||||||
CONF_CLIENT_SECRET: "abcd",
|
|
||||||
}
|
|
||||||
|
|
||||||
LEGACY_CONFIG_WITHOUT_TOKEN = {
|
|
||||||
SENSOR_DOMAIN: {
|
|
||||||
"platform": "twitch",
|
|
||||||
CONF_CLIENT_ID: "1234",
|
|
||||||
CONF_CLIENT_SECRET: "abcd",
|
|
||||||
"channels": ["channel123"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LEGACY_CONFIG = {
|
|
||||||
SENSOR_DOMAIN: {
|
|
||||||
"platform": "twitch",
|
|
||||||
CONF_CLIENT_ID: "1234",
|
|
||||||
CONF_CLIENT_SECRET: "abcd",
|
|
||||||
CONF_TOKEN: "efgh",
|
|
||||||
"channels": ["channel123"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTIONS = {CONF_CHANNELS: ["channel123"]}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_legacy_migration(
|
|
||||||
hass: HomeAssistant, twitch: TwitchMock, mock_setup_entry
|
|
||||||
) -> None:
|
|
||||||
"""Test importing legacy yaml."""
|
|
||||||
assert await async_setup_component(hass, Platform.SENSOR, LEGACY_CONFIG)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert len(entries) == 1
|
|
||||||
issue_registry = ir.async_get(hass)
|
|
||||||
assert len(issue_registry.issues) == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_legacy_migration_without_token(
|
|
||||||
hass: HomeAssistant, twitch: TwitchMock
|
|
||||||
) -> None:
|
|
||||||
"""Test importing legacy yaml."""
|
|
||||||
assert await async_setup_component(
|
|
||||||
hass, Platform.SENSOR, LEGACY_CONFIG_WITHOUT_TOKEN
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert len(entries) == 0
|
|
||||||
issue_registry = ir.async_get(hass)
|
|
||||||
assert len(issue_registry.issues) == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_offline(
|
async def test_offline(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user