parent
0de6c1004c
commit
4368ef79d2
1 changed files with 43 additions and 211 deletions
|
@ -1,5 +1,5 @@
|
||||||
import datetime
|
import datetime
|
||||||
from typing import List, Dict, Any, Optional, Union, Tuple
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
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'
|
_last_created_at_varname = '_foursquare_checkin_last_created_at'
|
||||||
_http_timeout = 10
|
_http_timeout = 10
|
||||||
|
# API version to use, see https://docs.foursquare.com/developer/reference/versioning
|
||||||
|
_api_version = '20240101'
|
||||||
|
|
||||||
def __init__(self, access_token: str, poll_interval: float = 120, **kwargs):
|
def __init__(self, access_token: str, poll_interval: float = 120, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -41,20 +43,16 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
self._last_created_at = Variable(self._last_created_at_varname)
|
self._last_created_at = Variable(self._last_created_at_varname)
|
||||||
|
|
||||||
def _get_url(self, endpoint):
|
def _get_url(self, endpoint):
|
||||||
return (
|
return f'{self.api_base_url}/{endpoint}?oauth_token={self.access_token}&v={self._api_version}'
|
||||||
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]]:
|
def _get_checkins(self, limit: int, offset: int) -> List[Dict[str, Any]]:
|
||||||
url = self._get_url('users/self/checkins')
|
url = self._get_url('users/self/checkins')
|
||||||
return (
|
return (
|
||||||
requests.get(url, timeout=self._http_timeout)
|
requests.get(
|
||||||
|
url,
|
||||||
|
json={'limit': limit, 'offset': offset},
|
||||||
|
timeout=self._http_timeout,
|
||||||
|
)
|
||||||
.json()
|
.json()
|
||||||
.get('response', {})
|
.get('response', {})
|
||||||
.get('checkins', {})
|
.get('checkins', {})
|
||||||
|
@ -62,48 +60,42 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_checkins(self) -> List[Dict[str, Any]]:
|
def get_checkins(self, limit: int = 20, offset: int = 0) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
return self._get_checkins()
|
return self._get_checkins(limit=limit, offset=offset)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def search(
|
def search(
|
||||||
self,
|
self,
|
||||||
latitude: Optional[float] = None,
|
latitude: Optional[float] = None,
|
||||||
longitude: Optional[float] = None,
|
longitude: Optional[float] = None,
|
||||||
altitude: Optional[float] = None,
|
|
||||||
latlng_accuracy: Optional[float] = None,
|
|
||||||
altitude_accuracy: Optional[float] = None,
|
|
||||||
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[str] = 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,
|
|
||||||
ne: Optional[Union[Tuple[float], List[float]]] = None,
|
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Search for venues.
|
Search for venues.
|
||||||
|
|
||||||
:param latitude: Search near this latitude. Note either ``latitude, longitude`` or ``near`` should be provided.
|
:param latitude: Search near this latitude. Note either ``latitude,
|
||||||
:param longitude: Search near this latitude. Note either ``latitude, longitude`` or ``near`` should be provided.
|
longitude`` or ``near`` should be provided.
|
||||||
:param near: Search near this place (e.g. "Chicago, IL" or "Amsterdam, NL"). Note either
|
:param longitude: Search near this latitude. Note either ``latitude,
|
||||||
``latitude, longitude`` or ``near`` should be provided.
|
longitude`` or ``near`` should be provided.
|
||||||
:param altitude: Search near this altitude in meters.
|
:param near: Search near this place (e.g. "Chicago, IL" or "Amsterdam,
|
||||||
:param latlng_accuracy: Latitude/longitude accuracy in meters.
|
NL"). Note either ``latitude, longitude`` or ``near`` should be
|
||||||
:param altitude_accuracy: Altitude accuracy in meters.
|
provided.
|
||||||
:param query: Search query (e.g. "coffee shops" or "restaurants").
|
:param query: Search query (e.g. "coffee shops" or "restaurants").
|
||||||
:param limit: Maximum number of results.
|
:param limit: Maximum number of results.
|
||||||
:param url: Venue URL to search.
|
:param url: A 3rd-party URL associated to the venue to be searched.
|
||||||
:param categories: List of `category IDs <https://developer.foursquare.com/docs/resources/categories>`_
|
:param categories: List of `category IDs
|
||||||
to be searched.
|
<https://developer.foursquare.com/docs/resources/categories>`_ to be
|
||||||
|
searched.
|
||||||
:param radius: Search radius in meters.
|
:param radius: Search radius in meters.
|
||||||
:param sw: South/west boundary box as a ``[latitude, longitude]`` pair.
|
|
||||||
:param ne: North/east boundary box as a ``[latitude, longitude]`` pair.
|
|
||||||
:return: A list of venues, as returned by the Foursquare API.
|
:return: A list of venues, as returned by the Foursquare API.
|
||||||
"""
|
"""
|
||||||
assert (
|
assert (
|
||||||
|
@ -115,12 +107,6 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
args['ll'] = ','.join([str(latitude), str(longitude)])
|
args['ll'] = ','.join([str(latitude), str(longitude)])
|
||||||
if near:
|
if near:
|
||||||
args['near'] = near
|
args['near'] = near
|
||||||
if altitude:
|
|
||||||
args['alt'] = altitude
|
|
||||||
if latlng_accuracy:
|
|
||||||
args['llAcc'] = latlng_accuracy
|
|
||||||
if altitude_accuracy:
|
|
||||||
args['altAcc'] = altitude_accuracy
|
|
||||||
if query:
|
if query:
|
||||||
args['query'] = query
|
args['query'] = query
|
||||||
if limit:
|
if limit:
|
||||||
|
@ -131,10 +117,6 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
args['categoryId'] = ','.join(categories)
|
args['categoryId'] = ','.join(categories)
|
||||||
if radius:
|
if radius:
|
||||||
args['radius'] = radius
|
args['radius'] = radius
|
||||||
if sw:
|
|
||||||
args['sw'] = sw
|
|
||||||
if ne:
|
|
||||||
args['ne'] = ne
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
requests.get(
|
requests.get(
|
||||||
|
@ -150,54 +132,28 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
self,
|
self,
|
||||||
latitude: Optional[float] = None,
|
latitude: Optional[float] = None,
|
||||||
longitude: Optional[float] = None,
|
longitude: Optional[float] = None,
|
||||||
altitude: Optional[float] = None,
|
|
||||||
latlng_accuracy: Optional[float] = None,
|
|
||||||
altitude_accuracy: Optional[float] = None,
|
|
||||||
section: Optional[str] = None,
|
|
||||||
near: Optional[str] = None,
|
near: Optional[str] = None,
|
||||||
query: Optional[str] = None,
|
query: Optional[str] = None,
|
||||||
limit: Optional[int] = None,
|
limit: Optional[int] = None,
|
||||||
categories: Optional[List[str]] = None,
|
categories: Optional[List[str]] = None,
|
||||||
radius: Optional[int] = None,
|
radius: Optional[int] = None,
|
||||||
open_now: bool = True,
|
|
||||||
sort_by_distance: Optional[bool] = None,
|
|
||||||
sort_by_popularity: Optional[bool] = None,
|
|
||||||
price: Optional[List[int]] = None,
|
|
||||||
saved: Optional[bool] = None,
|
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Explore venues around a location.
|
Explore venues around a location.
|
||||||
|
|
||||||
:param latitude: Search near this latitude. Note either ``latitude, longitude`` or ``near`` should be provided.
|
:param latitude: Search near this latitude. Note either ``latitude,
|
||||||
:param longitude: Search near this latitude. Note either ``latitude, longitude`` or ``near`` should be provided.
|
longitude`` or ``near`` should be provided.
|
||||||
:param near: Search near this place (e.g. "Chicago, IL" or "Amsterdam, NL"). Note either
|
:param longitude: Search near this latitude. Note either ``latitude,
|
||||||
``latitude, longitude`` or ``near`` should be provided.
|
longitude`` or ``near`` should be provided.
|
||||||
:param altitude: Search near this altitude in meters.
|
:param near: Search near this place (e.g. "Chicago, IL" or "Amsterdam,
|
||||||
:param latlng_accuracy: Latitude/longitude accuracy in meters.
|
NL"). Note either ``latitude, longitude`` or ``near`` should be
|
||||||
:param altitude_accuracy: Altitude accuracy in meters.
|
provided.
|
||||||
:param section: Section to search. Supported values:
|
:param query: Search query (e.g. "coffee shops" or "restaurants").
|
||||||
|
|
||||||
- food
|
|
||||||
- drinks
|
|
||||||
- coffee
|
|
||||||
- shops
|
|
||||||
- arts
|
|
||||||
- outdoors
|
|
||||||
- sights
|
|
||||||
- trending
|
|
||||||
- nextVenues
|
|
||||||
|
|
||||||
:param query: Search query (e.g. "coffee shops" or "restaurants"). The parameter has no effect if
|
|
||||||
``section`` is specified.
|
|
||||||
:param limit: Maximum number of results.
|
:param limit: Maximum number of results.
|
||||||
:param categories: List of `category IDs <https://developer.foursquare.com/docs/resources/categories>`_
|
:param categories: List of `category IDs
|
||||||
to be searched.
|
<https://developer.foursquare.com/docs/resources/categories>`_ to be
|
||||||
|
searched.
|
||||||
:param radius: Search radius in meters.
|
:param radius: Search radius in meters.
|
||||||
:param open_now: Filter by open/not open now.
|
|
||||||
:param sort_by_distance: Sort by distance.
|
|
||||||
:param sort_by_popularity: Sort by popularity
|
|
||||||
:param price: Price ranges, within the range ``[1,2,3,4]``.
|
|
||||||
:param saved: Filter by saved/unsaved venues.
|
|
||||||
|
|
||||||
:return: A list of venues, as returned by the Foursquare API.
|
:return: A list of venues, as returned by the Foursquare API.
|
||||||
"""
|
"""
|
||||||
|
@ -210,14 +166,6 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
args['ll'] = ','.join([str(latitude), str(longitude)])
|
args['ll'] = ','.join([str(latitude), str(longitude)])
|
||||||
if near:
|
if near:
|
||||||
args['near'] = near
|
args['near'] = near
|
||||||
if altitude:
|
|
||||||
args['alt'] = altitude
|
|
||||||
if latlng_accuracy:
|
|
||||||
args['llAcc'] = latlng_accuracy
|
|
||||||
if altitude_accuracy:
|
|
||||||
args['altAcc'] = altitude_accuracy
|
|
||||||
if section:
|
|
||||||
args['section'] = section
|
|
||||||
if query:
|
if query:
|
||||||
args['query'] = query
|
args['query'] = query
|
||||||
if categories:
|
if categories:
|
||||||
|
@ -226,18 +174,8 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
args['limit'] = int(limit)
|
args['limit'] = int(limit)
|
||||||
if radius:
|
if radius:
|
||||||
args['radius'] = radius
|
args['radius'] = radius
|
||||||
if open_now is not None:
|
|
||||||
args['openNow'] = int(open_now)
|
|
||||||
if sort_by_distance is not None:
|
|
||||||
args['sortByDistance'] = int(sort_by_distance)
|
|
||||||
if sort_by_popularity is not None:
|
|
||||||
args['sortByPopularity'] = sort_by_popularity
|
|
||||||
if saved is not None:
|
|
||||||
args['saved'] = int(saved)
|
|
||||||
if price:
|
|
||||||
args['price'] = ','.join([str(p) for p in price])
|
|
||||||
|
|
||||||
url = self._get_url('venues/explore')
|
url = self._get_url('venues/search')
|
||||||
return (
|
return (
|
||||||
requests.get(url, params=args, timeout=self._http_timeout)
|
requests.get(url, params=args, timeout=self._http_timeout)
|
||||||
.json()
|
.json()
|
||||||
|
@ -257,10 +195,13 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
"""
|
"""
|
||||||
Get the trending venues around a location.
|
Get the trending venues around a location.
|
||||||
|
|
||||||
:param latitude: Search near this latitude. Note either ``latitude, longitude`` or ``near`` should be provided.
|
:param latitude: Search near this latitude. Note either ``latitude,
|
||||||
:param longitude: Search near this latitude. Note either ``latitude, longitude`` or ``near`` should be provided.
|
longitude`` or ``near`` should be provided.
|
||||||
:param near: Search near this place (e.g. "Chicago, IL" or "Amsterdam, NL"). Note either
|
:param longitude: Search near this latitude. Note either ``latitude,
|
||||||
``latitude, longitude`` or ``near`` should be provided.
|
longitude`` or ``near`` should be provided.
|
||||||
|
:param near: Search near this place (e.g. "Chicago, IL" or "Amsterdam,
|
||||||
|
NL"). Note either ``latitude, longitude`` or ``near`` should be
|
||||||
|
provided.
|
||||||
:param limit: Maximum number of results.
|
:param limit: Maximum number of results.
|
||||||
:param radius: Search radius in meters.
|
:param radius: Search radius in meters.
|
||||||
|
|
||||||
|
@ -300,131 +241,22 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
), f'Cannot parse object of type {type(t)} into datetime: {t}'
|
), f'Cannot parse object of type {type(t)} into datetime: {t}'
|
||||||
return t
|
return t
|
||||||
|
|
||||||
@action
|
|
||||||
def time_series(
|
|
||||||
self,
|
|
||||||
venue_id: Union[str, List[str]],
|
|
||||||
start_at: Union[int, float, datetime.datetime, str],
|
|
||||||
end_at: Union[int, float, datetime.datetime, str],
|
|
||||||
) -> List[Dict[str, Any]]:
|
|
||||||
"""
|
|
||||||
Get the visitors stats about one or multiple venues over a time range. The user must be a manager of
|
|
||||||
those venues.
|
|
||||||
|
|
||||||
:param venue_id: Venue ID or list of IDs to get the stats for.
|
|
||||||
:param start_at: Stats start time. Can be a UNIX timestamp, a datetime object or an ISO format datetime.
|
|
||||||
:param end_at: Stats end time. Can be a UNIX timestamp, a datetime object or an ISO format datetime.
|
|
||||||
|
|
||||||
:return: A list of venues, as returned by the Foursquare API.
|
|
||||||
"""
|
|
||||||
if isinstance(venue_id, list):
|
|
||||||
venue_id = ','.join(venue_id)
|
|
||||||
|
|
||||||
args = {
|
|
||||||
'venueId': venue_id,
|
|
||||||
'startAt': self._parse_time(start_at),
|
|
||||||
'endAt': self._parse_time(end_at),
|
|
||||||
}
|
|
||||||
|
|
||||||
url = self._get_url('venues/timeseries')
|
|
||||||
return (
|
|
||||||
requests.get(url, params=args, timeout=self._http_timeout)
|
|
||||||
.json()
|
|
||||||
.get('response', {})
|
|
||||||
.get('venues', [])
|
|
||||||
)
|
|
||||||
|
|
||||||
@action
|
|
||||||
def stats(
|
|
||||||
self,
|
|
||||||
venue_id: str,
|
|
||||||
start_at: Union[int, float, datetime.datetime, str],
|
|
||||||
end_at: Union[int, float, datetime.datetime, str],
|
|
||||||
) -> List[Dict[str, Any]]:
|
|
||||||
"""
|
|
||||||
Get the stats about a venue over a time range. The user must be a manager of that venue.
|
|
||||||
|
|
||||||
:param venue_id: Venue ID.
|
|
||||||
:param start_at: Stats start time. Can be a UNIX timestamp, a datetime object or an ISO format datetime.
|
|
||||||
:param end_at: Stats end time. Can be a UNIX timestamp, a datetime object or an ISO format datetime.
|
|
||||||
|
|
||||||
:return: A list of venues, as returned by the Foursquare API.
|
|
||||||
"""
|
|
||||||
args = {
|
|
||||||
'startAt': self._parse_time(start_at).isoformat(),
|
|
||||||
'endAt': self._parse_time(end_at).isoformat(),
|
|
||||||
}
|
|
||||||
|
|
||||||
url = self._get_url(f'venues/{venue_id}/stats')
|
|
||||||
return (
|
|
||||||
requests.get(url, params=args, timeout=self._http_timeout)
|
|
||||||
.json()
|
|
||||||
.get('response', {})
|
|
||||||
.get('venues', [])
|
|
||||||
)
|
|
||||||
|
|
||||||
@action
|
|
||||||
def managed(self) -> List[Dict[str, Any]]:
|
|
||||||
"""
|
|
||||||
Get the list of venues managed by the user.
|
|
||||||
:return: A list of venues, as returned by the Foursquare API.
|
|
||||||
"""
|
|
||||||
url = self._get_url('venues/managed')
|
|
||||||
return (
|
|
||||||
requests.get(url, timeout=self._http_timeout)
|
|
||||||
.json()
|
|
||||||
.get('response', {})
|
|
||||||
.get('venues', [])
|
|
||||||
.get('items', [])
|
|
||||||
)
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def checkin(
|
def checkin(
|
||||||
self,
|
self,
|
||||||
venue_id: str,
|
venue_id: str,
|
||||||
latitude: Optional[float] = None,
|
|
||||||
longitude: Optional[float] = None,
|
|
||||||
altitude: Optional[float] = None,
|
|
||||||
latlng_accuracy: Optional[float] = None,
|
|
||||||
altitude_accuracy: Optional[float] = None,
|
|
||||||
shout: Optional[str] = None,
|
shout: Optional[str] = None,
|
||||||
broadcast: Optional[List[str]] = None,
|
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Create a new check-in.
|
Create a new check-in.
|
||||||
|
|
||||||
:param venue_id: ID of the venue to check-in.
|
:param venue_id: ID of the venue to check-in.
|
||||||
:param latitude: Check-in latitude.
|
|
||||||
:param longitude: Check-in longitude.
|
|
||||||
:param altitude: Check-in altitude.
|
|
||||||
:param latlng_accuracy: Latitude/longitude accuracy in meters.
|
|
||||||
:param altitude_accuracy: Altitude accuracy in meters.
|
|
||||||
:param shout: Add a custom message to the check-in.
|
:param shout: Add a custom message to the check-in.
|
||||||
:param broadcast: List of Visibility/share types of the check-in. Default: ``public``. Possible values are:
|
|
||||||
|
|
||||||
- ``private``
|
|
||||||
- ``public``
|
|
||||||
- ``followers``
|
|
||||||
- ``facebook``
|
|
||||||
- ``twitter``
|
|
||||||
|
|
||||||
:return: Foursquare API response.
|
:return: Foursquare API response.
|
||||||
"""
|
"""
|
||||||
args = {'venueId': venue_id}
|
args = {'venueId': venue_id}
|
||||||
if latitude and longitude:
|
|
||||||
args['ll'] = ','.join([str(latitude), str(longitude)])
|
|
||||||
if altitude:
|
|
||||||
args['alt'] = str(altitude)
|
|
||||||
if latlng_accuracy:
|
|
||||||
args['llAcc'] = str(latlng_accuracy)
|
|
||||||
if altitude_accuracy:
|
|
||||||
args['altAcc'] = str(altitude_accuracy)
|
|
||||||
if shout:
|
if shout:
|
||||||
args['shout'] = shout
|
args['shout'] = shout
|
||||||
if broadcast:
|
|
||||||
args['broadcast'] = (
|
|
||||||
','.join(broadcast) if isinstance(broadcast, list) else broadcast
|
|
||||||
)
|
|
||||||
|
|
||||||
url = self._get_url('checkins/add')
|
url = self._get_url('checkins/add')
|
||||||
return (
|
return (
|
||||||
|
@ -436,7 +268,7 @@ class FoursquarePlugin(RunnablePlugin):
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
while not self.should_stop():
|
while not self.should_stop():
|
||||||
checkins = self._get_checkins()
|
checkins = self._get_checkins(limit=20, offset=0)
|
||||||
if not checkins:
|
if not checkins:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue