From b8dde07141c764f1eba5fd5179fad6e3ad3125b5 Mon Sep 17 00:00:00 2001 From: Drew Winstel Date: Mon, 26 Oct 2020 15:23:22 -0500 Subject: [PATCH] Store updated and last fetched timestamps for venues (#347) * Add nullable fields for last venue update/check times * Add method to base parser to set timestamp based on returned value * Wire in timestamp parsing for beermenus * silence pylint complaining about celery * Wire in timestamp parsing for digitalpour * Wire in timestamp parsing for stem and stein * Wire in timestamp parsing for taphunter * wire in timestamp parsing for taplist.io * Wire in untappd timestamp parsing * run black * drop stray print * mark timestamps as read only in serializer --- beers/admin.py | 1 - tap_list_providers/base.py | 25 +++++++++++++-- .../management/commands/parsebeermenus.py | 4 ++- .../management/commands/parsedigitalpour.py | 5 +-- .../management/commands/parsestemandstein.py | 7 ++--- .../management/commands/parsetaphunter.py | 5 +-- .../management/commands/parsetaplistio.py | 3 +- .../management/commands/parseuntappd.py | 3 +- tap_list_providers/parsers/beermenus.py | 17 +++++++--- tap_list_providers/parsers/digitalpour.py | 12 ++++++- tap_list_providers/parsers/stemandstein.py | 19 +++++++++++- tap_list_providers/parsers/taphunter.py | 8 +++++ tap_list_providers/parsers/taplist_io.py | 1 + tap_list_providers/parsers/untappd.py | 12 +++++-- tap_list_providers/test/test_base.py | 30 ++++++++++++++++++ tap_list_providers/test/test_beermenus.py | 8 +++++ tap_list_providers/test/test_digitalpour.py | 6 ++++ tap_list_providers/test/test_stemandstein.py | 6 ++++ tap_list_providers/test/test_taphunter.py | 6 ++++ tap_list_providers/test/test_taplist_io.py | 6 ++++ tap_list_providers/test/test_untappd.py | 8 ++++- venues/migrations/0028_auto_20201014_1424.py | 31 +++++++++++++++++++ venues/models.py | 6 ++++ venues/serializers.py | 7 ++++- 24 files changed, 211 insertions(+), 25 deletions(-) create mode 100644 venues/migrations/0028_auto_20201014_1424.py diff --git a/beers/admin.py b/beers/admin.py index ae9996f4..ad136c73 100644 --- a/beers/admin.py +++ b/beers/admin.py @@ -78,7 +78,6 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs): "manufacturer": models.Manufacturer.objects.order_by("name"), } order_qs = fields.get(db_field.name) - print(db_field.name, order_qs is not None) if order_qs: kwargs["queryset"] = order_qs diff --git a/tap_list_providers/base.py b/tap_list_providers/base.py index 084ccf74..c2bb644c 100644 --- a/tap_list_providers/base.py +++ b/tap_list_providers/base.py @@ -9,10 +9,12 @@ from decimal import Decimal, InvalidOperation from urllib.parse import urlparse, unquote import logging +import datetime from django.db.models import Prefetch, Q from django.db.models.functions import Length from django.db import transaction +from django.utils.timezone import now from kombu.exceptions import OperationalError from venues.models import Venue @@ -51,12 +53,13 @@ class BaseTapListProvider: def __init__(self): + self.check_timestamp = now() self.styles = {} if not hasattr(self, "provider_name"): # Don't define this attribute if the child does for us self.provider_name = None - def handle_venue(self, venue): + def handle_venue(self, venue: Venue) -> datetime.datetime: raise NotImplementedError("You need to implement this yourself") @classmethod @@ -92,7 +95,23 @@ def get_venues(self): def handle_venues(self, venues): for venue in venues: LOG.debug("Fetching beers at %s", venue) - self.handle_venue(venue) + update_time = self.handle_venue(venue) + self.update_venue_timestamps(venue, update_time) + + def update_venue_timestamps( + self, venue: Venue, update_time: datetime.datetime = None + ) -> None: + """Update the venue last checked and last updated times""" + LOG.debug( + "Setting check time for %s to %s and update time for to %s", + venue, + self.check_timestamp, + update_time, + ) + venue.tap_list_last_check_time = self.check_timestamp + if update_time: + venue.tap_list_last_update_time = update_time + venue.save() def get_style(self, name): name = name.strip() @@ -410,7 +429,7 @@ def get_beer(self, name, manufacturer, pricing=None, venue=None, **defaults): if str(exc).casefold() == "max number of clients reached".casefold(): LOG.error("Reached redis limit!") # fall back to doing it synchronously - look_up_beer(beer.id) + look_up_beer(beer.id) # pylint: disable=no-value-for-parameter else: raise return beer diff --git a/tap_list_providers/management/commands/parsebeermenus.py b/tap_list_providers/management/commands/parsebeermenus.py index 4b3c9938..bfb6aa09 100644 --- a/tap_list_providers/management/commands/parsebeermenus.py +++ b/tap_list_providers/management/commands/parsebeermenus.py @@ -18,5 +18,7 @@ def handle(self, *args, **options): with transaction.atomic(): for venue in tap_list_provider.get_venues(): self.stdout.write("Processing %s" % venue.name) - tap_list_provider.handle_venue(venue) + timestamp = tap_list_provider.handle_venue(venue) + tap_list_provider.update_venue_timestamps(venue, timestamp) + self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/tap_list_providers/management/commands/parsedigitalpour.py b/tap_list_providers/management/commands/parsedigitalpour.py index e90b1a81..b1fec682 100644 --- a/tap_list_providers/management/commands/parsedigitalpour.py +++ b/tap_list_providers/management/commands/parsedigitalpour.py @@ -7,7 +7,7 @@ class Command(BaseCommand): - help = "Populates any venues using the DigitalPour tap list provider with" " beers" + help = "Populates any venues using the DigitalPour tap list provider with beers" def add_arguments(self, parser): # does not take any arguments @@ -18,5 +18,6 @@ def handle(self, *args, **options): with transaction.atomic(): for venue in tap_list_provider.get_venues(): self.stdout.write("Processing %s" % venue.name) - tap_list_provider.handle_venue(venue) + timestamp = tap_list_provider.handle_venue(venue) + tap_list_provider.update_venue_timestamps(venue, timestamp) self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/tap_list_providers/management/commands/parsestemandstein.py b/tap_list_providers/management/commands/parsestemandstein.py index 5305043f..5b7a1f49 100644 --- a/tap_list_providers/management/commands/parsestemandstein.py +++ b/tap_list_providers/management/commands/parsestemandstein.py @@ -7,9 +7,7 @@ class Command(BaseCommand): - help = ( - "Populates any venues using the Stem and Stein tap list provider with" " beers" - ) + help = "Populates any venues using the Stem and Stein tap list provider with beers" def add_arguments(self, parser): # does not take any arguments @@ -20,5 +18,6 @@ def handle(self, *args, **options): with transaction.atomic(): for venue in tap_list_provider.get_venues(): self.stdout.write("Processing %s" % venue.name) - tap_list_provider.handle_venue(venue) + timestamp = tap_list_provider.handle_venue(venue) + tap_list_provider.update_venue_timestamps(venue, timestamp) self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/tap_list_providers/management/commands/parsetaphunter.py b/tap_list_providers/management/commands/parsetaphunter.py index bdcc56d6..b0ec2060 100644 --- a/tap_list_providers/management/commands/parsetaphunter.py +++ b/tap_list_providers/management/commands/parsetaphunter.py @@ -7,7 +7,7 @@ class Command(BaseCommand): - help = "Populates any venues using the TapHunter tap list provider with" " beers" + help = "Populates any venues using the TapHunter tap list provider with beers" def add_arguments(self, parser): # does not take any arguments @@ -18,5 +18,6 @@ def handle(self, *args, **options): with transaction.atomic(): for venue in tap_list_provider.get_venues(): self.stdout.write("Processing %s" % venue.name) - tap_list_provider.handle_venue(venue) + timestamp = tap_list_provider.handle_venue(venue) + tap_list_provider.update_venue_timestamps(venue, timestamp) self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/tap_list_providers/management/commands/parsetaplistio.py b/tap_list_providers/management/commands/parsetaplistio.py index 63749a0b..1bd15b9c 100644 --- a/tap_list_providers/management/commands/parsetaplistio.py +++ b/tap_list_providers/management/commands/parsetaplistio.py @@ -18,5 +18,6 @@ def handle(self, *args, **options): with transaction.atomic(): for venue in tap_list_provider.get_venues(): self.stdout.write("Processing %s" % venue.name) - tap_list_provider.handle_venue(venue) + timestamp = tap_list_provider.handle_venue(venue) + tap_list_provider.update_venue_timestamps(venue, timestamp) self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/tap_list_providers/management/commands/parseuntappd.py b/tap_list_providers/management/commands/parseuntappd.py index 51d969af..7c47cb8c 100644 --- a/tap_list_providers/management/commands/parseuntappd.py +++ b/tap_list_providers/management/commands/parseuntappd.py @@ -18,5 +18,6 @@ def handle(self, *args, **options): with transaction.atomic(): for venue in tap_list_provider.get_venues(): self.stdout.write("Processing %s" % venue.name) - tap_list_provider.handle_venue(venue) + timestamp = tap_list_provider.handle_venue(venue) + tap_list_provider.update_venue_timestamps(venue, timestamp) self.stdout.write(self.style.SUCCESS("Done!")) diff --git a/tap_list_providers/parsers/beermenus.py b/tap_list_providers/parsers/beermenus.py index 855d7abe..320b8db6 100644 --- a/tap_list_providers/parsers/beermenus.py +++ b/tap_list_providers/parsers/beermenus.py @@ -1,4 +1,7 @@ +"""Parser for beermenus dot com""" + from decimal import Decimal +import datetime from dataclasses import dataclass import logging import os @@ -71,6 +74,7 @@ def __init__( self.categories = categories self.soup = None self.save_fetched_data = save_fetched_data + self.updated_date = None super().__init__() def fetch_data(self) -> str: @@ -100,14 +104,14 @@ def parse_html(self, data: str) -> List[BeerData]: )[0] # they just give us a date. I'm going to arbitrarily declare that to be # midnight UTC because who cares if we're off by a day - updated_date = UTC.localize( + self.updated_date = UTC.localize( parse( updated_span.text.split()[1], dayfirst=False, ) ) # TODO save this to the venue - LOG.debug("Last updated: %s", updated_date) + LOG.debug("Last updated: %s", self.updated_date) # the beer lists are in