[#286] Merge Foursquare backend and plugin.

Closes: #286
This commit is contained in:
Fabio Manganiello 2024-01-01 22:52:18 +01:00
parent efe46386f4
commit 4aeff10a5d
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
6 changed files with 85 additions and 105 deletions

View file

@ -10,7 +10,6 @@ Backends
platypush/backend/button.flic.rst platypush/backend/button.flic.rst
platypush/backend/camera.pi.rst platypush/backend/camera.pi.rst
platypush/backend/chat.telegram.rst platypush/backend/chat.telegram.rst
platypush/backend/foursquare.rst
platypush/backend/google.fit.rst platypush/backend/google.fit.rst
platypush/backend/google.pubsub.rst platypush/backend/google.pubsub.rst
platypush/backend/gps.rst platypush/backend/gps.rst

View file

@ -1,5 +0,0 @@
``foursquare``
================================
.. automodule:: platypush.backend.foursquare
:members:

View file

@ -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:

View file

@ -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

View file

@ -1,14 +1,19 @@
import datetime import datetime
import requests
from typing import List, Dict, Any, Optional, Union, Tuple 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 <https://developer.foursquare.com/docs/api>`_. Plugin to interact with the `Foursquare Places API <https://developer.foursquare.com/docs/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: In order to enable the Foursquare API on your account you need to:
- Create a new app on the `Foursquare developers website <https://foursquare.com/developers/signup>`_. - Create a new app on the `Foursquare developers website <https://foursquare.com/developers/signup>`_.
@ -24,20 +29,36 @@ class FoursquarePlugin(Plugin):
""" """
api_base_url = 'https://api.foursquare.com/v2' 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. :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.access_token = access_token
self._last_created_at = Variable(self._last_created_at_varname)
def _get_url(self, endpoint): def _get_url(self, endpoint):
return '{url}/{endpoint}?oauth_token={token}&v={version}'.format( return (
url=self.api_base_url, self.api_base_url
endpoint=endpoint, + '/'
token=self.access_token, + endpoint
version=datetime.date.today().strftime('%Y%m%d'), + '?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 @action
@ -46,16 +67,8 @@ class FoursquarePlugin(Plugin):
Get the list of check-ins of the current user. Get the list of check-ins of the current user.
:return: A list of checkins, as returned by the Foursquare API. :return: A list of checkins, as returned by the Foursquare API.
""" """
url = self._get_url('users/self/checkins') return self._get_checkins()
return (
requests.get(url)
.json()
.get('response', {})
.get('checkins', {})
.get('items', [])
)
# noinspection DuplicatedCode
@action @action
def search( def search(
self, self,
@ -67,7 +80,7 @@ class FoursquarePlugin(Plugin):
near: Optional[str] = None, near: Optional[str] = None,
query: Optional[str] = None, query: Optional[str] = None,
limit: Optional[int] = None, limit: Optional[int] = None,
url: Optional[int] = None, url: Optional[str] = None,
categories: Optional[List[str]] = None, categories: Optional[List[str]] = None,
radius: Optional[int] = None, radius: Optional[int] = None,
sw: Optional[Union[Tuple[float], List[float]]] = None, sw: Optional[Union[Tuple[float], List[float]]] = None,
@ -123,12 +136,15 @@ class FoursquarePlugin(Plugin):
if ne: if ne:
args['ne'] = ne args['ne'] = ne
url = self._get_url('venues/search')
return ( 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 @action
def explore( def explore(
self, self,
@ -223,7 +239,10 @@ class FoursquarePlugin(Plugin):
url = self._get_url('venues/explore') url = self._get_url('venues/explore')
return ( 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 @action
@ -263,7 +282,10 @@ class FoursquarePlugin(Plugin):
url = self._get_url('venues/trending') url = self._get_url('venues/trending')
return ( 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 @staticmethod
@ -275,7 +297,7 @@ class FoursquarePlugin(Plugin):
assert isinstance( assert isinstance(
t, datetime.datetime 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 return t
@action @action
@ -306,7 +328,10 @@ class FoursquarePlugin(Plugin):
url = self._get_url('venues/timeseries') url = self._get_url('venues/timeseries')
return ( 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 @action
@ -326,13 +351,16 @@ class FoursquarePlugin(Plugin):
:return: A list of venues, as returned by the Foursquare API. :return: A list of venues, as returned by the Foursquare API.
""" """
args = { args = {
'startAt': self._parse_time(start_at), 'startAt': self._parse_time(start_at).isoformat(),
'endAt': self._parse_time(end_at), '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 ( 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 @action
@ -343,7 +371,7 @@ class FoursquarePlugin(Plugin):
""" """
url = self._get_url('venues/managed') url = self._get_url('venues/managed')
return ( return (
requests.get(url) requests.get(url, timeout=self._http_timeout)
.json() .json()
.get('response', {}) .get('response', {})
.get('venues', []) .get('venues', [])
@ -386,11 +414,11 @@ class FoursquarePlugin(Plugin):
if latitude and longitude: if latitude and longitude:
args['ll'] = ','.join([str(latitude), str(longitude)]) args['ll'] = ','.join([str(latitude), str(longitude)])
if altitude: if altitude:
args['alt'] = altitude args['alt'] = str(altitude)
if latlng_accuracy: if latlng_accuracy:
args['llAcc'] = latlng_accuracy args['llAcc'] = str(latlng_accuracy)
if altitude_accuracy: if altitude_accuracy:
args['altAcc'] = altitude_accuracy args['altAcc'] = str(altitude_accuracy)
if shout: if shout:
args['shout'] = shout args['shout'] = shout
if broadcast: if broadcast:
@ -400,8 +428,27 @@ class FoursquarePlugin(Plugin):
url = self._get_url('checkins/add') url = self._get_url('checkins/add')
return ( 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: # vim:sw=4:ts=4:et:

View file

@ -1,5 +1,6 @@
manifest: manifest:
events: {} events:
- platypush.message.event.foursquare.FoursquareCheckinEvent
install: install:
pip: [] pip: []
package: platypush.plugins.foursquare package: platypush.plugins.foursquare