mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 12:47:08 +00:00
Catch PermissionDenied(Route API disabled) in google_travel_time (#145722)
Catch PermissionDenied(Route API disabled)
This commit is contained in:
parent
376008940b
commit
481639bcf9
@ -50,7 +50,12 @@ from .const import (
|
||||
UNITS_IMPERIAL,
|
||||
UNITS_METRIC,
|
||||
)
|
||||
from .helpers import InvalidApiKeyException, UnknownException, validate_config_entry
|
||||
from .helpers import (
|
||||
InvalidApiKeyException,
|
||||
PermissionDeniedException,
|
||||
UnknownException,
|
||||
validate_config_entry,
|
||||
)
|
||||
|
||||
RECONFIGURE_SCHEMA = vol.Schema(
|
||||
{
|
||||
@ -188,6 +193,8 @@ async def validate_input(
|
||||
user_input[CONF_ORIGIN],
|
||||
user_input[CONF_DESTINATION],
|
||||
)
|
||||
except PermissionDeniedException:
|
||||
return {"base": "permission_denied"}
|
||||
except InvalidApiKeyException:
|
||||
return {"base": "invalid_auth"}
|
||||
except TimeoutError:
|
||||
|
@ -7,6 +7,7 @@ from google.api_core.exceptions import (
|
||||
Forbidden,
|
||||
GatewayTimeout,
|
||||
GoogleAPIError,
|
||||
PermissionDenied,
|
||||
Unauthorized,
|
||||
)
|
||||
from google.maps.routing_v2 import (
|
||||
@ -19,10 +20,18 @@ from google.maps.routing_v2 import (
|
||||
from google.type import latlng_pb2
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.issue_registry import (
|
||||
IssueSeverity,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
)
|
||||
from homeassistant.helpers.location import find_coordinates
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -67,6 +76,9 @@ async def validate_config_entry(
|
||||
await client.compute_routes(
|
||||
request, metadata=[("x-goog-fieldmask", field_mask)]
|
||||
)
|
||||
except PermissionDenied as permission_error:
|
||||
_LOGGER.error("Permission denied: %s", permission_error.message)
|
||||
raise PermissionDeniedException from permission_error
|
||||
except (Unauthorized, Forbidden) as unauthorized_error:
|
||||
_LOGGER.error("Request denied: %s", unauthorized_error.message)
|
||||
raise InvalidApiKeyException from unauthorized_error
|
||||
@ -84,3 +96,30 @@ class InvalidApiKeyException(Exception):
|
||||
|
||||
class UnknownException(Exception):
|
||||
"""Unknown API Error."""
|
||||
|
||||
|
||||
class PermissionDeniedException(Exception):
|
||||
"""Permission Denied Error."""
|
||||
|
||||
|
||||
def create_routes_api_disabled_issue(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Create an issue for the Routes API being disabled."""
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
f"routes_api_disabled_{entry.entry_id}",
|
||||
learn_more_url="https://www.home-assistant.io/integrations/google_travel_time#setup",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.ERROR,
|
||||
translation_key="routes_api_disabled",
|
||||
translation_placeholders={
|
||||
"entry_title": entry.title,
|
||||
"enable_api_url": "https://cloud.google.com/endpoints/docs/openapi/enable-api",
|
||||
"api_key_restrictions_url": "https://cloud.google.com/docs/authentication/api-keys#adding-api-restrictions",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def delete_routes_api_disabled_issue(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Delete the issue for the Routes API being disabled."""
|
||||
async_delete_issue(hass, DOMAIN, f"routes_api_disabled_{entry.entry_id}")
|
||||
|
@ -7,7 +7,7 @@ import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from google.api_core.client_options import ClientOptions
|
||||
from google.api_core.exceptions import GoogleAPIError
|
||||
from google.api_core.exceptions import GoogleAPIError, PermissionDenied
|
||||
from google.maps.routing_v2 import (
|
||||
ComputeRoutesRequest,
|
||||
Route,
|
||||
@ -58,7 +58,11 @@ from .const import (
|
||||
TRAVEL_MODES_TO_GOOGLE_SDK_ENUM,
|
||||
UNITS_TO_GOOGLE_SDK_ENUM,
|
||||
)
|
||||
from .helpers import convert_to_waypoint
|
||||
from .helpers import (
|
||||
convert_to_waypoint,
|
||||
create_routes_api_disabled_issue,
|
||||
delete_routes_api_disabled_issue,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -274,6 +278,11 @@ class GoogleTravelTimeSensor(SensorEntity):
|
||||
_LOGGER.debug("Received response: %s", response)
|
||||
if response is not None and len(response.routes) > 0:
|
||||
self._route = response.routes[0]
|
||||
delete_routes_api_disabled_issue(self.hass, self._config_entry)
|
||||
except PermissionDenied:
|
||||
_LOGGER.error("Routes API is disabled for this API key")
|
||||
create_routes_api_disabled_issue(self.hass, self._config_entry)
|
||||
self._route = None
|
||||
except GoogleAPIError as ex:
|
||||
_LOGGER.error("Error getting travel time: %s", ex)
|
||||
self._route = None
|
||||
|
@ -21,6 +21,7 @@
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"permission_denied": "The Routes API is not enabled for this API key. Please see the setup instructions for detailed information.",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"timeout_connect": "[%key:common::config_flow::error::timeout_connect%]"
|
||||
@ -100,5 +101,11 @@
|
||||
"fewer_transfers": "Fewer transfers"
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"routes_api_disabled": {
|
||||
"title": "The Routes API must be enabled",
|
||||
"description": "Your Google Travel Time integration `{entry_title}` uses an API key which does not have the Routes API enabled.\n\n Please follow the instructions to [enable the API for your project]({enable_api_url}) and make sure your [API key restrictions]({api_key_restrictions_url}) allow access to the Routes API.\n\n After enabling the API this issue will be resolved automatically."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,12 @@
|
||||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from google.api_core.exceptions import GatewayTimeout, GoogleAPIError, Unauthorized
|
||||
from google.api_core.exceptions import (
|
||||
GatewayTimeout,
|
||||
GoogleAPIError,
|
||||
PermissionDenied,
|
||||
Unauthorized,
|
||||
)
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.google_travel_time.const import (
|
||||
@ -98,6 +103,12 @@ async def test_minimum_fields(hass: HomeAssistant) -> None:
|
||||
(GoogleAPIError("test"), "cannot_connect"),
|
||||
(GatewayTimeout("Timeout error."), "timeout_connect"),
|
||||
(Unauthorized("Invalid API key."), "invalid_auth"),
|
||||
(
|
||||
PermissionDenied(
|
||||
"Requests to this API routes.googleapis.com method google.maps.routing.v2.Routes.ComputeRoutes are blocked."
|
||||
),
|
||||
"permission_denied",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_errors(
|
||||
|
@ -3,7 +3,7 @@
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from google.api_core.exceptions import GoogleAPIError
|
||||
from google.api_core.exceptions import GoogleAPIError, PermissionDenied
|
||||
from google.maps.routing_v2 import Units
|
||||
import pytest
|
||||
|
||||
@ -20,6 +20,7 @@ from homeassistant.components.google_travel_time.const import (
|
||||
from homeassistant.components.google_travel_time.sensor import SCAN_INTERVAL
|
||||
from homeassistant.const import CONF_MODE, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
from homeassistant.util.unit_system import (
|
||||
METRIC_SYSTEM,
|
||||
US_CUSTOMARY_SYSTEM,
|
||||
@ -170,3 +171,26 @@ async def test_sensor_exception(
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("sensor.google_travel_time").state == STATE_UNKNOWN
|
||||
assert "Error getting travel time" in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("data", "options"),
|
||||
[(MOCK_CONFIG, DEFAULT_OPTIONS)],
|
||||
)
|
||||
async def test_sensor_routes_api_disabled(
|
||||
hass: HomeAssistant,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
routes_mock: AsyncMock,
|
||||
mock_config: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
) -> None:
|
||||
"""Test that exception gets caught and issue created."""
|
||||
routes_mock.compute_routes.side_effect = PermissionDenied("Errormessage")
|
||||
freezer.tick(SCAN_INTERVAL)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("sensor.google_travel_time").state == STATE_UNKNOWN
|
||||
assert "Routes API is disabled for this API key" in caplog.text
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user