Refactored Google plugins with support multiple scopes and a simpler API and added Google Fit plugin

This commit is contained in:
Fabio Manganiello 2019-03-14 01:12:39 +01:00
parent 022262eb78
commit 55c0896b31
6 changed files with 84 additions and 50 deletions

View File

@ -33,7 +33,7 @@ class GooglePlugin(Plugin):
* **google-api-python-client** (``pip install google-api-python-client``) * **google-api-python-client** (``pip install google-api-python-client``)
""" """
def __init__(self, scopes, *args, **kwargs): def __init__(self, scopes=None, *args, **kwargs):
""" """
Initialized the Google plugin with the required scopes. Initialized the Google plugin with the required scopes.
@ -42,11 +42,25 @@ class GooglePlugin(Plugin):
""" """
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.credentials = {} self._scopes = scopes or []
for scope in scopes: scopes = ' '.join(sorted(self._scopes))
self.credentials[scope] = get_credentials(scope) self.credentials = {
scopes: get_credentials(scopes)
}
def get_service(self, service, version, scopes=None):
import httplib2
from apiclient import discovery
if scopes is None:
scopes = getattr(self, 'scopes') if hasattr(self, 'scopes') else []
scopes = ' '.join(sorted(scopes))
credentials = self.credentials[scopes]
http = credentials.authorize(httplib2.Http())
return discovery.build(service, version, http=http, cache_discovery=False)
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -4,11 +4,8 @@
import base64 import base64
import datetime import datetime
import httplib2
import os import os
from apiclient import discovery
from platypush.plugins import action from platypush.plugins import action
from platypush.plugins.google import GooglePlugin from platypush.plugins.google import GooglePlugin
from platypush.plugins.calendar import CalendarInterface from platypush.plugins.calendar import CalendarInterface
@ -33,7 +30,7 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
""" """
now = datetime.datetime.utcnow().isoformat() + 'Z' now = datetime.datetime.utcnow().isoformat() + 'Z'
service = self._get_service() service = self.get_service('calendar', 'v3')
result = service.events().list(calendarId='primary', timeMin=now, result = service.events().list(calendarId='primary', timeMin=now,
maxResults=max_results, singleEvents=True, maxResults=max_results, singleEvents=True,
orderBy='startTime').execute() orderBy='startTime').execute()
@ -42,14 +39,5 @@ class GoogleCalendarPlugin(GooglePlugin, CalendarInterface):
return events return events
def _get_service(self, scope=None):
if scope is None:
scope = self.scopes[0]
credentials = self.credentials[scope]
http = credentials.authorize(httplib2.Http())
return discovery.build('calendar', 'v3', http=http, cache_discovery=False)
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -8,21 +8,19 @@ from oauth2client import tools
from oauth2client.file import Storage from oauth2client.file import Storage
def get_credentials_filename(scope): def get_credentials_filename(*scopes):
from platypush.config import Config from platypush.config import Config
scope_name = scope.split('/')[-1] scope_name = '-'.join([scope.split('/')[-1] for scope in scopes])
credentials_dir = os.path.join( credentials_dir = os.path.join(
Config.get('workdir'), 'credentials', 'google') Config.get('workdir'), 'credentials', 'google')
if not os.path.exists(credentials_dir): os.makedirs(credentials_dir, exist_ok=True)
os.makedirs(credentials_dir)
return os.path.join(credentials_dir, scope_name + '.json') return os.path.join(credentials_dir, scope_name + '.json')
def get_credentials(scope): def get_credentials(scope):
credentials_file = get_credentials_filename(scope) credentials_file = get_credentials_filename(*sorted(scope.split(' ')))
if not os.path.exists(credentials_file): if not os.path.exists(credentials_file):
raise RuntimeError(('Credentials file {} not found. Generate it through:\n' + raise RuntimeError(('Credentials file {} not found. Generate it through:\n' +
'\tpython -m platypush.plugins.google.credentials "{}" ' + '\tpython -m platypush.plugins.google.credentials "{}" ' +
@ -43,7 +41,7 @@ def get_credentials(scope):
def generate_credentials(client_secret_path, scope): def generate_credentials(client_secret_path, scope):
credentials_file = get_credentials_filename(scope) credentials_file = get_credentials_filename(*sorted(scope.split(' ')))
store = Storage(credentials_file) store = Storage(credentials_file)
flow = client.flow_from_clientsecrets(client_secret_path, scope) flow = client.flow_from_clientsecrets(client_secret_path, scope)
@ -62,7 +60,7 @@ def main():
""" """
scope = sys.argv.pop(1) if len(sys.argv) > 1 \ scope = sys.argv.pop(1) if len(sys.argv) > 1 \
else input('Comma separated list of OAuth scopes: ') else input('Space separated list of OAuth scopes: ')
client_secret_path = os.path.expanduser( client_secret_path = os.path.expanduser(
sys.argv.pop(1) if len(sys.argv) > 1 sys.argv.pop(1) if len(sys.argv) > 1

View File

@ -0,0 +1,55 @@
from apiclient import discovery
from platypush.plugins import action
from platypush.plugins.google import GooglePlugin
class GoogleFitPlugin(GooglePlugin):
"""
Google Fit plugin
"""
scopes = ['https://www.googleapis.com/auth/fitness.activity.read',
'https://www.googleapis.com/auth/fitness.body.read',
'https://www.googleapis.com/auth/fitness.body_temperature.read',
'https://www.googleapis.com/auth/fitness.location.read']
def __init__(self, user_id='me', *args, **kwargs):
"""
:param user_id: Default Google user_id (default: 'me', default
configured account user)
:type user_id: str or int
"""
super().__init__(scopes=self.scopes, *args, **kwargs)
self.user_id = user_id
@action
def get_data_sources(self, user_id=None):
"""
Get the available data sources for the specified user_id
"""
service = self.get_service(service='fitness', version='v1')
sources = service.users().dataSources(). \
list(userId=user_id or self.user_id).execute()
return sources['dataSource']
@action
def get_data(self, data_source_id, user_id=None):
"""
Get raw data for the specified data_source_id
:param data_source_id: Data source ID, see `get_data_sources`
:type data_source_id: str
"""
service = self.get_service(service='fitness', version='v1')
return service.users().dataSources().dataPointChanges() \
.list(dataSourceId=data_source_id, userId=user_id or self.user_id) \
.execute().get('insertedDataPoint', [])
# vim:sw=4:ts=4:et:

View File

@ -87,7 +87,7 @@ class GoogleMailPlugin(GooglePlugin):
msg.add_header('Content-Disposition', 'attachment', filename=filename) msg.add_header('Content-Disposition', 'attachment', filename=filename)
message.attach(msg) message.attach(msg)
service = self._get_service() service = self.get_service('gmail', 'v1')
body = { 'raw': base64.urlsafe_b64encode(message.as_bytes()).decode() } body = { 'raw': base64.urlsafe_b64encode(message.as_bytes()).decode() }
message = (service.users().messages().send( message = (service.users().messages().send(
userId='me', body=body).execute()) userId='me', body=body).execute())
@ -100,18 +100,10 @@ class GoogleMailPlugin(GooglePlugin):
""" """
Returns the available labels on the GMail account Returns the available labels on the GMail account
""" """
service = self._get_service() service = self.get_service('gmail', 'v1')
results = service.users().labels().list(userId='me').execute() results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', []) labels = results.get('labels', [])
return labels return labels
def _get_service(self):
scope = self.scopes[0]
credentials = self.credentials[scope]
http = credentials.authorize(httplib2.Http())
return discovery.build('gmail', 'v1', http=http, cache_discovery=False)
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View File

@ -4,11 +4,8 @@
import base64 import base64
import datetime import datetime
import httplib2
import os import os
from apiclient import discovery
from platypush.plugins import action from platypush.plugins import action
from platypush.plugins.google import GooglePlugin from platypush.plugins.google import GooglePlugin
from platypush.plugins.calendar import CalendarInterface from platypush.plugins.calendar import CalendarInterface
@ -62,7 +59,7 @@ class GoogleYoutubePlugin(GooglePlugin, CalendarInterface):
if isinstance(types, list): if isinstance(types, list):
types = ','.join(types) types = ','.join(types)
service = self._get_service() service = self.get_service('youtube', 'v3')
result = service.search().list(part=parts, q=query, type=types, result = service.search().list(part=parts, q=query, type=types,
maxResults=max_results, maxResults=max_results,
**kwargs).execute() **kwargs).execute()
@ -71,14 +68,4 @@ class GoogleYoutubePlugin(GooglePlugin, CalendarInterface):
return events return events
def _get_service(self, scope=None):
if scope is None:
scope = self.scopes[0]
credentials = self.credentials[scope]
http = credentials.authorize(httplib2.Http())
return discovery.build('youtube', 'v3', http=http, cache_discovery=False)
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et: