From 4aeff10a5d1ef417746a4689dc67c4a1f4960c24 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Mon, 1 Jan 2024 22:52:18 +0100 Subject: [PATCH] [#286] Merge Foursquare backend and plugin. Closes: #286 --- docs/source/backends.rst | 1 - docs/source/platypush/backend/foursquare.rst | 5 - platypush/backend/foursquare/__init__.py | 54 --------- platypush/backend/foursquare/manifest.yaml | 8 -- platypush/plugins/foursquare/__init__.py | 119 +++++++++++++------ platypush/plugins/foursquare/manifest.yaml | 3 +- 6 files changed, 85 insertions(+), 105 deletions(-) delete mode 100644 docs/source/platypush/backend/foursquare.rst delete mode 100644 platypush/backend/foursquare/__init__.py delete mode 100644 platypush/backend/foursquare/manifest.yaml diff --git a/docs/source/backends.rst b/docs/source/backends.rst index 1347f2e3..4b9c06aa 100644 --- a/docs/source/backends.rst +++ b/docs/source/backends.rst @@ -10,7 +10,6 @@ Backends platypush/backend/button.flic.rst platypush/backend/camera.pi.rst platypush/backend/chat.telegram.rst - platypush/backend/foursquare.rst platypush/backend/google.fit.rst platypush/backend/google.pubsub.rst platypush/backend/gps.rst diff --git a/docs/source/platypush/backend/foursquare.rst b/docs/source/platypush/backend/foursquare.rst deleted file mode 100644 index 34f0af8e..00000000 --- a/docs/source/platypush/backend/foursquare.rst +++ /dev/null @@ -1,5 +0,0 @@ -``foursquare`` -================================ - -.. automodule:: platypush.backend.foursquare - :members: diff --git a/platypush/backend/foursquare/__init__.py b/platypush/backend/foursquare/__init__.py deleted file mode 100644 index 29f2122a..00000000 --- a/platypush/backend/foursquare/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -from typing import Optional - -from platypush.backend import Backend -from platypush.context import get_plugin -from platypush.message.event.foursquare import FoursquareCheckinEvent - - -class FoursquareBackend(Backend): - """ - This backend polls for new check-ins on the user's Foursquare account and triggers an event when a new check-in - occurs. - - Requires: - - * The :class:`platypush.plugins.foursquare.FoursquarePlugin` plugin configured and enabled. - - """ - - _last_created_at_varname = '_foursquare_checkin_last_created_at' - - def __init__(self, poll_seconds: Optional[float] = 60.0, *args, **kwargs): - """ - :param poll_seconds: How often the backend should check for new check-ins (default: one minute). - """ - super().__init__(*args, poll_seconds=poll_seconds, **kwargs) - self._last_created_at = None - - def __enter__(self): - self._last_created_at = int( - get_plugin('variable') - .get(self._last_created_at_varname) - .output.get(self._last_created_at_varname) - or 0 - ) - self.logger.info('Started Foursquare backend') - - def loop(self): - checkins = get_plugin('foursquare').get_checkins().output - if not checkins: - return - - last_checkin = checkins[0] - last_checkin_created_at = last_checkin.get('createdAt', 0) - if self._last_created_at and last_checkin_created_at <= self._last_created_at: - return - - self.bus.post(FoursquareCheckinEvent(checkin=last_checkin)) - self._last_created_at = last_checkin_created_at - get_plugin('variable').set( - **{self._last_created_at_varname: self._last_created_at} - ) - - -# vim:sw=4:ts=4:et: diff --git a/platypush/backend/foursquare/manifest.yaml b/platypush/backend/foursquare/manifest.yaml deleted file mode 100644 index 0690cc93..00000000 --- a/platypush/backend/foursquare/manifest.yaml +++ /dev/null @@ -1,8 +0,0 @@ -manifest: - events: - platypush.message.event.foursquare.FoursquareCheckinEvent: when a new check-in - occurs. - install: - pip: [] - package: platypush.backend.foursquare - type: backend diff --git a/platypush/plugins/foursquare/__init__.py b/platypush/plugins/foursquare/__init__.py index 79d4b572..06ba0b1b 100644 --- a/platypush/plugins/foursquare/__init__.py +++ b/platypush/plugins/foursquare/__init__.py @@ -1,14 +1,19 @@ import datetime -import requests from typing import List, Dict, Any, Optional, Union, Tuple -from platypush.plugins import Plugin, action +import requests + +from platypush.context import Variable +from platypush.message.event.foursquare import FoursquareCheckinEvent +from platypush.plugins import RunnablePlugin, action -class FoursquarePlugin(Plugin): +class FoursquarePlugin(RunnablePlugin): """ Plugin to interact with the `Foursquare Places API `_. + It also raises events when a new check-in occurs on the user's account. + In order to enable the Foursquare API on your account you need to: - Create a new app on the `Foursquare developers website `_. @@ -24,20 +29,36 @@ class FoursquarePlugin(Plugin): """ api_base_url = 'https://api.foursquare.com/v2' + _last_created_at_varname = '_foursquare_checkin_last_created_at' + _http_timeout = 10 - def __init__(self, access_token: str, **kwargs): + def __init__(self, access_token: str, poll_interval: float = 120, **kwargs): """ :param access_token: The access token to use to authenticate to the Foursquare API. """ - super().__init__(**kwargs) + super().__init__(poll_interval=poll_interval, **kwargs) self.access_token = access_token + self._last_created_at = Variable(self._last_created_at_varname) def _get_url(self, endpoint): - return '{url}/{endpoint}?oauth_token={token}&v={version}'.format( - url=self.api_base_url, - endpoint=endpoint, - token=self.access_token, - version=datetime.date.today().strftime('%Y%m%d'), + return ( + self.api_base_url + + '/' + + endpoint + + '?oauth_token=' + + self.access_token + + '&v=' + + datetime.date.today().strftime('%Y%m%d') + ) + + def _get_checkins(self) -> List[Dict[str, Any]]: + url = self._get_url('users/self/checkins') + return ( + requests.get(url, timeout=self._http_timeout) + .json() + .get('response', {}) + .get('checkins', {}) + .get('items', []) ) @action @@ -46,16 +67,8 @@ class FoursquarePlugin(Plugin): Get the list of check-ins of the current user. :return: A list of checkins, as returned by the Foursquare API. """ - url = self._get_url('users/self/checkins') - return ( - requests.get(url) - .json() - .get('response', {}) - .get('checkins', {}) - .get('items', []) - ) + return self._get_checkins() - # noinspection DuplicatedCode @action def search( self, @@ -67,7 +80,7 @@ class FoursquarePlugin(Plugin): near: Optional[str] = None, query: Optional[str] = None, limit: Optional[int] = None, - url: Optional[int] = None, + url: Optional[str] = None, categories: Optional[List[str]] = None, radius: Optional[int] = None, sw: Optional[Union[Tuple[float], List[float]]] = None, @@ -123,12 +136,15 @@ class FoursquarePlugin(Plugin): if ne: args['ne'] = ne - url = self._get_url('venues/search') return ( - requests.get(url, params=args).json().get('response', {}).get('venues', []) + requests.get( + self._get_url('venues/search'), params=args, timeout=self._http_timeout + ) + .json() + .get('response', {}) + .get('venues', []) ) - # noinspection DuplicatedCode @action def explore( self, @@ -223,7 +239,10 @@ class FoursquarePlugin(Plugin): url = self._get_url('venues/explore') return ( - requests.get(url, params=args).json().get('response', {}).get('venues', []) + requests.get(url, params=args, timeout=self._http_timeout) + .json() + .get('response', {}) + .get('venues', []) ) @action @@ -263,7 +282,10 @@ class FoursquarePlugin(Plugin): url = self._get_url('venues/trending') return ( - requests.get(url, params=args).json().get('response', {}).get('venues', []) + requests.get(url, params=args, timeout=self._http_timeout) + .json() + .get('response', {}) + .get('venues', []) ) @staticmethod @@ -275,7 +297,7 @@ class FoursquarePlugin(Plugin): assert isinstance( t, datetime.datetime - ), 'Cannot parse object of type {} into datetime: {}'.format(type(t), t) + ), f'Cannot parse object of type {type(t)} into datetime: {t}' return t @action @@ -306,7 +328,10 @@ class FoursquarePlugin(Plugin): url = self._get_url('venues/timeseries') return ( - requests.get(url, params=args).json().get('response', {}).get('venues', []) + requests.get(url, params=args, timeout=self._http_timeout) + .json() + .get('response', {}) + .get('venues', []) ) @action @@ -326,13 +351,16 @@ class FoursquarePlugin(Plugin): :return: A list of venues, as returned by the Foursquare API. """ args = { - 'startAt': self._parse_time(start_at), - 'endAt': self._parse_time(end_at), + 'startAt': self._parse_time(start_at).isoformat(), + 'endAt': self._parse_time(end_at).isoformat(), } - url = self._get_url('venues/{}/stats'.format(venue_id)) + url = self._get_url(f'venues/{venue_id}/stats') return ( - requests.get(url, params=args).json().get('response', {}).get('venues', []) + requests.get(url, params=args, timeout=self._http_timeout) + .json() + .get('response', {}) + .get('venues', []) ) @action @@ -343,7 +371,7 @@ class FoursquarePlugin(Plugin): """ url = self._get_url('venues/managed') return ( - requests.get(url) + requests.get(url, timeout=self._http_timeout) .json() .get('response', {}) .get('venues', []) @@ -386,11 +414,11 @@ class FoursquarePlugin(Plugin): if latitude and longitude: args['ll'] = ','.join([str(latitude), str(longitude)]) if altitude: - args['alt'] = altitude + args['alt'] = str(altitude) if latlng_accuracy: - args['llAcc'] = latlng_accuracy + args['llAcc'] = str(latlng_accuracy) if altitude_accuracy: - args['altAcc'] = altitude_accuracy + args['altAcc'] = str(altitude_accuracy) if shout: args['shout'] = shout if broadcast: @@ -400,8 +428,27 @@ class FoursquarePlugin(Plugin): url = self._get_url('checkins/add') return ( - requests.post(url, data=args).json().get('response', {}).get('checkin', {}) + requests.post(url, data=args, timeout=self._http_timeout) + .json() + .get('response', {}) + .get('checkin', {}) ) + def main(self): + while not self.should_stop(): + checkins = self._get_checkins() + if not checkins: + return + + last_checkin = checkins[0] + last_checkin_created_at = last_checkin.get('createdAt', 0) + last_created_at = self._last_created_at.get() or 0 + if last_created_at and last_checkin_created_at <= last_created_at: + return + + self._bus.post(FoursquareCheckinEvent(checkin=last_checkin)) + self._last_created_at.set(last_checkin_created_at) + self.wait_stop(self.poll_interval) + # vim:sw=4:ts=4:et: diff --git a/platypush/plugins/foursquare/manifest.yaml b/platypush/plugins/foursquare/manifest.yaml index 35acebd0..f9b8cd0f 100644 --- a/platypush/plugins/foursquare/manifest.yaml +++ b/platypush/plugins/foursquare/manifest.yaml @@ -1,5 +1,6 @@ manifest: - events: {} + events: + - platypush.message.event.foursquare.FoursquareCheckinEvent install: pip: [] package: platypush.plugins.foursquare