Feature/google calendar read only support (#52790)
* feat(google): Added support for read only access in google calendar. By default the current read/write access will be given, but the user has the option to set read only access which stops the add event service from registering * fix(google): Updated documentation link * docs(google-calendar): Added style fixes * feat(calendar-google): Updated scopes to be defined on enum property. This was done as a MR suggestion to simplify the code. * feat(calendar-google):Removed constants no longer needed. * feat(calendar-google): Reduced scope check to minimum. * style: Fixed style issues
This commit is contained in:
parent
5e6853b9e1
commit
f3ba71748b
2 changed files with 42 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
|||
"""Support for Google - Calendar Event Devices."""
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
@ -41,6 +42,7 @@ CONF_TRACK = "track"
|
|||
CONF_SEARCH = "search"
|
||||
CONF_IGNORE_AVAILABILITY = "ignore_availability"
|
||||
CONF_MAX_RESULTS = "max_results"
|
||||
CONF_CALENDAR_ACCESS = "calendar_access"
|
||||
|
||||
DEFAULT_CONF_TRACK_NEW = True
|
||||
DEFAULT_CONF_OFFSET = "!!"
|
||||
|
@ -70,10 +72,26 @@ SERVICE_ADD_EVENT = "add_event"
|
|||
DATA_INDEX = "google_calendars"
|
||||
|
||||
YAML_DEVICES = f"{DOMAIN}_calendars.yaml"
|
||||
SCOPES = "https://www.googleapis.com/auth/calendar"
|
||||
|
||||
TOKEN_FILE = f".{DOMAIN}.token"
|
||||
|
||||
|
||||
class FeatureAccess(Enum):
|
||||
"""Class to represent different access scopes."""
|
||||
|
||||
read_only = "https://www.googleapis.com/auth/calendar.readonly"
|
||||
read_write = "https://www.googleapis.com/auth/calendar"
|
||||
|
||||
def __init__(self, scope: str) -> None:
|
||||
"""Init instance."""
|
||||
self._scope = scope
|
||||
|
||||
@property
|
||||
def scope(self) -> str:
|
||||
"""Google calendar scope for the feature."""
|
||||
return self._scope
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
|
@ -81,6 +99,9 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
vol.Required(CONF_CLIENT_ID): cv.string,
|
||||
vol.Required(CONF_CLIENT_SECRET): cv.string,
|
||||
vol.Optional(CONF_TRACK_NEW): cv.boolean,
|
||||
vol.Optional(CONF_CALENDAR_ACCESS, default="read_write"): cv.enum(
|
||||
FeatureAccess
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
|
@ -139,7 +160,7 @@ def do_authentication(hass, hass_config, config):
|
|||
oauth = OAuth2WebServerFlow(
|
||||
client_id=config[CONF_CLIENT_ID],
|
||||
client_secret=config[CONF_CLIENT_SECRET],
|
||||
scope="https://www.googleapis.com/auth/calendar",
|
||||
scope=config[CONF_CALENDAR_ACCESS].scope,
|
||||
redirect_uri="Home-Assistant.io",
|
||||
)
|
||||
try:
|
||||
|
@ -213,7 +234,7 @@ def setup(hass, config):
|
|||
if not os.path.isfile(token_file):
|
||||
do_authentication(hass, config, conf)
|
||||
else:
|
||||
if not check_correct_scopes(token_file):
|
||||
if not check_correct_scopes(token_file, conf):
|
||||
do_authentication(hass, config, conf)
|
||||
else:
|
||||
do_setup(hass, config, conf)
|
||||
|
@ -221,16 +242,22 @@ def setup(hass, config):
|
|||
return True
|
||||
|
||||
|
||||
def check_correct_scopes(token_file):
|
||||
def check_correct_scopes(token_file, config):
|
||||
"""Check for the correct scopes in file."""
|
||||
with open(token_file) as tokenfile:
|
||||
if "readonly" in tokenfile.read():
|
||||
contents = tokenfile.read()
|
||||
|
||||
# Check for quoted scope as our scopes can be subsets of other scopes
|
||||
target_scope = f'"{config.get(CONF_CALENDAR_ACCESS).scope}"'
|
||||
if target_scope not in contents:
|
||||
_LOGGER.warning("Please re-authenticate with Google")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def setup_services(hass, hass_config, track_new_found_calendars, calendar_service):
|
||||
def setup_services(
|
||||
hass, hass_config, config, track_new_found_calendars, calendar_service
|
||||
):
|
||||
"""Set up the service listeners."""
|
||||
|
||||
def _found_calendar(call):
|
||||
|
@ -312,9 +339,11 @@ def setup_services(hass, hass_config, track_new_found_calendars, calendar_servic
|
|||
service_data = {"calendarId": call.data[EVENT_CALENDAR_ID], "body": event}
|
||||
event = service.events().insert(**service_data).execute()
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_ADD_EVENT, _add_event, schema=ADD_EVENT_SERVICE_SCHEMA
|
||||
)
|
||||
# Only expose the add event service if we have the correct permissions
|
||||
if config.get(CONF_CALENDAR_ACCESS) is FeatureAccess.read_write:
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_ADD_EVENT, _add_event, schema=ADD_EVENT_SERVICE_SCHEMA
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
@ -327,7 +356,9 @@ def do_setup(hass, hass_config, config):
|
|||
track_new_found_calendars = convert(
|
||||
config.get(CONF_TRACK_NEW), bool, DEFAULT_CONF_TRACK_NEW
|
||||
)
|
||||
setup_services(hass, hass_config, track_new_found_calendars, calendar_service)
|
||||
setup_services(
|
||||
hass, hass_config, config, track_new_found_calendars, calendar_service
|
||||
)
|
||||
|
||||
for calendar in hass.data[DATA_INDEX].values():
|
||||
discovery.load_platform(hass, "calendar", DOMAIN, calendar, hass_config)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"domain": "google",
|
||||
"name": "Google Calendars",
|
||||
"documentation": "https://www.home-assistant.io/integrations/google",
|
||||
"documentation": "https://www.home-assistant.io/integrations/calendar.google/",
|
||||
"requirements": [
|
||||
"google-api-python-client==1.6.4",
|
||||
"httplib2==0.19.0",
|
||||
|
|
Loading…
Add table
Reference in a new issue