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
s
beers = []
@@ -218,7 +222,7 @@ def parse_beers(self, beers: List[BeerData]) -> None:
beer.brewery_name = brewery_a.text
beer.brewery_location = brewery_p.text.split(MIDDOT)[1].strip()
- def handle_venue(self, venue: Venue) -> None:
+ def handle_venue(self, venue: Venue) -> datetime.datetime:
self.categories = venue.api_configuration.beermenus_categories
self.location_url = self.URL.format(venue.api_configuration.beermenus_slug)
data = self.fetch_data()
@@ -261,6 +265,7 @@ def handle_venue(self, venue: Venue) -> None:
tap_number,
beer,
)
+ return self.updated_date
def parse_beer_tag(tag: Tag) -> BeerData:
@@ -289,7 +294,7 @@ def parse_beer_tag(tag: Tag) -> BeerData:
)
-if __name__ == "__main__":
+def main():
import argparse
LOCATIONS = {
@@ -319,3 +324,7 @@ def parse_beer_tag(tag: Tag) -> BeerData:
for beer in beers:
print(f"{beer.name} by {beer.brewery_name} ({beer.abv}%, {beer.style})")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tap_list_providers/parsers/digitalpour.py b/tap_list_providers/parsers/digitalpour.py
index 93c3d3f6..88ff95d0 100644
--- a/tap_list_providers/parsers/digitalpour.py
+++ b/tap_list_providers/parsers/digitalpour.py
@@ -1,3 +1,6 @@
+"""Parser for DigitalPour"""
+
+import datetime
from decimal import Decimal
import logging
import os
@@ -8,6 +11,7 @@
import configurations
from django.utils.timezone import now
from django.core.exceptions import ImproperlyConfigured, AppRegistryNotReady
+from pytz import UTC
# boilerplate code necessary for launching outside manage.py
try:
@@ -19,6 +23,7 @@
from ..base import BaseTapListProvider
from taps.models import Tap
+from venues.models import Venue
LOG = logging.getLogger(__name__)
@@ -34,16 +39,18 @@ class DigitalPourParser(BaseTapListProvider):
def __init__(self, location=None):
"""Constructor."""
self.url = None
+ self.update_date = None
if location:
self.url = self.URL.format(location[0], location[1], self.APIKEY)
super().__init__()
- def handle_venue(self, venue):
+ def handle_venue(self, venue: Venue) -> datetime.datetime:
venue_id = venue.api_configuration.digital_pour_venue_id
location_number = venue.api_configuration.digital_pour_location_number
self.url = self.URL.format(venue_id, location_number, self.APIKEY)
data = self.fetch()
taps = {tap.tap_number: tap for tap in venue.taps.all()}
+ self.update_date = UTC.localize(datetime.datetime(1970, 1, 1, 0, 0, 0))
manufacturers = {}
for entry in data:
if not entry["Active"]:
@@ -57,6 +64,8 @@ def handle_venue(self, venue):
tap = Tap(venue=venue, tap_number=tap_info["tap_number"])
tap.time_added = tap_info["added"]
tap.time_updated = tap_info["updated"]
+ if tap.time_updated and tap.time_updated > self.update_date:
+ self.update_date = tap.time_updated
tap.estimated_percent_remaining = tap_info["percent_full"]
if tap_info["gas_type"] in [i[0] for i in Tap.GAS_CHOICES]:
tap.gas_type = tap_info["gas_type"]
@@ -116,6 +125,7 @@ def handle_venue(self, venue):
# 4. assign the beer to the tap
tap.beer = beer
tap.save()
+ return self.update_date
def parse_beer(self, entry):
"""Parse beer info from JSON entry."""
diff --git a/tap_list_providers/parsers/stemandstein.py b/tap_list_providers/parsers/stemandstein.py
index 22ed848e..dc63b786 100644
--- a/tap_list_providers/parsers/stemandstein.py
+++ b/tap_list_providers/parsers/stemandstein.py
@@ -1,4 +1,5 @@
"""HTML scraper for The Stem & Stein"""
+import datetime
from urllib.parse import parse_qsl
from html.parser import HTMLParser
from decimal import Decimal
@@ -8,6 +9,8 @@
from bs4 import BeautifulSoup
import requests
import configurations
+import pytz
+from dateutil.parser import parse
from django.db.models import Q
from django.core.exceptions import ImproperlyConfigured, AppRegistryNotReady
@@ -24,6 +27,7 @@
from taps.models import Tap
+CENTRAL_TIME = pytz.timezone("America/Chicago")
LOG = logging.getLogger(__name__)
@@ -133,6 +137,8 @@ def fill_in_beer_details(self, beer):
).text
beer_parser = BeautifulSoup(beer_html, "html.parser")
jumbotron = beer_parser.find("div", {"class": "jumbotron"})
+ tap_table = beer_parser.find("table", {"id": "tapList"})
+ tap_body = tap_table.find("tbody")
image_div = jumbotron.find(
"div",
{"style": "display:table-cell;vertical-align:top;width:17px;"},
@@ -190,6 +196,12 @@ def fill_in_beer_details(self, beer):
beer=beer,
defaults={"price": price},
)
+ time_tapped = None
+ for row in tap_body.find_all("tr"):
+ cells = list(row.find_all("td"))
+ if cells[-1].text.endswith("(so far)"):
+ time_tapped = CENTRAL_TIME.localize(parse(cells[0].text))
+ return time_tapped
def handle_venue(self, venue):
self.venue = venue
@@ -199,8 +211,11 @@ def handle_venue(self, venue):
existing_taps = {i.tap_number: i for i in venue.taps.all()}
LOG.debug("existing taps %s", existing_taps)
taps_hit = []
+ latest_time = CENTRAL_TIME.localize(datetime.datetime(1970, 1, 1, 0))
for tap_number, beer in taps.items():
- self.fill_in_beer_details(beer)
+ time_tapped = self.fill_in_beer_details(beer)
+ if time_tapped > latest_time:
+ latest_time = time_tapped
try:
tap = existing_taps[tap_number]
except KeyError:
@@ -209,9 +224,11 @@ def handle_venue(self, venue):
tap_number=tap_number,
)
tap.beer = beer
+ tap.time_added = time_tapped
tap.save()
taps_hit.append(tap.tap_number)
LOG.debug("Deleting all taps except %s", taps_hit)
Tap.objects.filter(venue=venue,).exclude(
tap_number__in=taps_hit,
).delete()
+ return latest_time
diff --git a/tap_list_providers/parsers/taphunter.py b/tap_list_providers/parsers/taphunter.py
index 23107ee6..42020b3b 100644
--- a/tap_list_providers/parsers/taphunter.py
+++ b/tap_list_providers/parsers/taphunter.py
@@ -1,5 +1,6 @@
"""Parse beers from TapHunter"""
import argparse
+import datetime
import decimal
import logging
import os
@@ -7,7 +8,9 @@
import configurations
import requests
+from dateutil.parser import parse
from django.core.exceptions import ImproperlyConfigured, AppRegistryNotReady
+from pytz import UTC
# boilerplate code necessary for launching outside manage.py
try:
@@ -49,6 +52,7 @@ def handle_venue(self, venue):
use_sequential_taps = any(
(tap_info["serving_info"]["tap_number"] == "" for tap_info in data["taps"])
)
+ latest_timestamp = UTC.localize(datetime.datetime(1970, 1, 1, 12))
for index, entry in enumerate(data["taps"]):
# 1. parse the tap
tap_info = self.parse_tap(entry)
@@ -73,6 +77,9 @@ def handle_venue(self, venue):
tap = Tap(venue=venue, tap_number=tap_number)
tap.time_added = tap_info["added"]
tap.time_updated = tap_info["updated"]
+ parsed_time = parse(tap_info["updated"])
+ if parsed_time > latest_timestamp:
+ latest_timestamp = parsed_time
if "percent_full" in tap_info:
tap.estimated_percent_remaining = tap_info["percent_full"]
else:
@@ -123,6 +130,7 @@ def handle_venue(self, venue):
# 4. assign the beer to the tap
tap.beer = beer
tap.save()
+ return latest_timestamp
def parse_beer(self, tap):
beer = {
diff --git a/tap_list_providers/parsers/taplist_io.py b/tap_list_providers/parsers/taplist_io.py
index 9a9d00c8..b1576a02 100644
--- a/tap_list_providers/parsers/taplist_io.py
+++ b/tap_list_providers/parsers/taplist_io.py
@@ -72,6 +72,7 @@ def handle_venue(self, venue):
if current_tap.time_updated != timestamp:
current_tap.time_updated = timestamp
current_tap.save()
+ return timestamp
def parse_tap(self, tap_dict):
if tap_dict["current_keg"] is None:
diff --git a/tap_list_providers/parsers/untappd.py b/tap_list_providers/parsers/untappd.py
index 6931f592..552f22b1 100644
--- a/tap_list_providers/parsers/untappd.py
+++ b/tap_list_providers/parsers/untappd.py
@@ -1,5 +1,6 @@
"""Parse data from untappd"""
import argparse
+import datetime
from decimal import Decimal
from pprint import PrettyPrinter
import logging
@@ -12,6 +13,7 @@
import configurations
from django.core.exceptions import ImproperlyConfigured, AppRegistryNotReady
from django.db.models import Q
+from pytz import UTC
# boilerplate code necessary for launching outside manage.py
try:
@@ -69,6 +71,7 @@ def handle_venue(self, venue):
use_sequential_taps = any(
tap_info["tap_number"] is None for tap_info in tap_list
)
+ latest_timestamp = UTC.localize(datetime.datetime(1970, 1, 1, 12))
for index, tap_info in enumerate(tap_list):
# 1. get the tap
# if the venue doesn't give tap numbers, just use a 1-based
@@ -82,9 +85,13 @@ def handle_venue(self, venue):
except KeyError:
tap = Tap(venue=venue, tap_number=tap_number)
if tap_info["added"]:
- tap.time_added = tap_info["added"]
+ tap.time_added = dateutil.parser.parse(tap_info["added"])
+ if tap.time_added > latest_timestamp:
+ latest_timestamp = tap.time_added
if tap_info["updated"]:
- tap.time_updated = tap_info["updated"]
+ tap.time_updated = dateutil.parser.parse(tap_info["updated"])
+ if tap.time_updated > latest_timestamp:
+ latest_timestamp = tap.time_updated
# 2. parse the manufacturer
try:
manufacturer = manufacturers[tap_info["manufacturer"]["name"]]
@@ -112,6 +119,7 @@ def handle_venue(self, venue):
# 4. assign the beer to the tap
tap.beer = beer
tap.save()
+ return latest_timestamp
def parse_html_and_js(self, data):
# Pull the relevant HTML from the JS.
diff --git a/tap_list_providers/test/test_base.py b/tap_list_providers/test/test_base.py
index 692732b8..96a18cb5 100644
--- a/tap_list_providers/test/test_base.py
+++ b/tap_list_providers/test/test_base.py
@@ -1,7 +1,11 @@
+import datetime
+
from django.test import TestCase
+from django.utils.timezone import now
from unittest import TestCase as UnittestTestCase
from tap_list_providers.base import fix_urls, BaseTapListProvider
+from venues.test.factories import VenueFactory
from beers.test.factories import ManufacturerFactory, StyleFactory
from beers.models import Manufacturer, ManufacturerAlternateName
@@ -91,3 +95,29 @@ def test_yazoo(self):
provider = BaseTapListProvider()
name = provider.reformat_beer_name("Yazoo Brewing Company Hefeweizen", "Yazoo")
self.assertEqual(name, "Hefeweizen")
+
+
+class TimestampTestCase(TestCase):
+ def setUp(self):
+ self.venue = VenueFactory()
+ self.provider = BaseTapListProvider()
+
+ def test_initial_conditions(self):
+ self.assertIsNone(self.venue.tap_list_last_check_time)
+ self.assertIsNone(self.venue.tap_list_last_update_time)
+ self.assertIsNotNone(self.provider.check_timestamp)
+
+ def test_timestamp_no_time(self):
+ self.provider.update_venue_timestamps(self.venue, None)
+ self.assertIsNone(self.venue.tap_list_last_update_time)
+ self.assertEqual(
+ self.venue.tap_list_last_check_time, self.provider.check_timestamp
+ )
+
+ def test_with_time(self):
+ timestamp = now() - datetime.timedelta(days=1)
+ self.provider.update_venue_timestamps(self.venue, timestamp)
+ self.assertEqual(self.venue.tap_list_last_update_time, timestamp)
+ self.assertEqual(
+ self.venue.tap_list_last_check_time, self.provider.check_timestamp
+ )
diff --git a/tap_list_providers/test/test_beermenus.py b/tap_list_providers/test/test_beermenus.py
index 3c7dd97c..2fabe763 100644
--- a/tap_list_providers/test/test_beermenus.py
+++ b/tap_list_providers/test/test_beermenus.py
@@ -4,6 +4,7 @@
from django.core.management import call_command
from django.test import TestCase
+from django.utils.timezone import now
import responses
from beers.models import Beer, Manufacturer, ManufacturerAlternateName
@@ -71,6 +72,9 @@ def beer_menu_callback(self, request):
@responses.activate
def test_import_beermenus_data(self):
"""Test parsing the HTML and JS data"""
+ timestamp = now()
+ self.assertIsNone(self.venue.tap_list_last_check_time)
+ self.assertIsNone(self.venue.tap_list_last_update_time)
for url, name, html in self.locations:
responses.add(
responses.GET,
@@ -152,3 +156,7 @@ def test_import_beermenus_data(self):
tap.beer.manufacturer.name,
"Rocket Republic Brewing Company",
)
+ self.venue.refresh_from_db()
+ self.assertIsNotNone(self.venue.tap_list_last_check_time)
+ self.assertGreater(self.venue.tap_list_last_check_time, timestamp)
+ self.assertIsNotNone(self.venue.tap_list_last_update_time)
diff --git a/tap_list_providers/test/test_digitalpour.py b/tap_list_providers/test/test_digitalpour.py
index b9124a67..fd11c1cc 100644
--- a/tap_list_providers/test/test_digitalpour.py
+++ b/tap_list_providers/test/test_digitalpour.py
@@ -5,6 +5,7 @@
from django.core.management import call_command
from django.test import TestCase
+from django.utils.timezone import now
import responses
from beers.models import Beer, Manufacturer
@@ -40,6 +41,7 @@ def setUpTestData(cls):
@responses.activate
def test_import_digitalpour_data(self):
"""Test parsing the JSON data"""
+ timestamp = now()
responses.add(
responses.GET,
DigitalPourParser.URL.format(
@@ -146,6 +148,10 @@ def test_import_digitalpour_data(self):
"https://s3.amazonaws.com/digitalpourproducerlogos/"
"57ac9c3c5e002c172c8a6ede.jpg",
)
+ self.venue.refresh_from_db()
+ self.assertIsNotNone(self.venue.tap_list_last_check_time)
+ self.assertGreater(self.venue.tap_list_last_check_time, timestamp)
+ self.assertIsNotNone(self.venue.tap_list_last_update_time)
def test_digital_pour_mead(self):
tap = {
diff --git a/tap_list_providers/test/test_stemandstein.py b/tap_list_providers/test/test_stemandstein.py
index 6f861434..dbe858c0 100644
--- a/tap_list_providers/test/test_stemandstein.py
+++ b/tap_list_providers/test/test_stemandstein.py
@@ -4,6 +4,7 @@
from django.core.management import call_command
from django.test import TestCase
+from django.utils.timezone import now
import responses
from beers.models import (
@@ -80,6 +81,7 @@ def setUpTestData(cls):
@responses.activate
def test_import_stemandstein_data(self):
"""Test parsing the JSON data"""
+ timestamp = now()
for pk, html_data in self.html_data.items():
if pk == "root":
url = "https://thestemandstein.com/"
@@ -159,6 +161,10 @@ def test_import_stemandstein_data(self):
# style is set to Fruit Ale but the beer name is preserved
self.assertEqual(tap.beer.style_id, style.id)
self.assertTrue(tap.beer.name.endswith("Fruit Ale"))
+ self.venue.refresh_from_db()
+ self.assertIsNotNone(self.venue.tap_list_last_check_time)
+ self.assertGreater(self.venue.tap_list_last_check_time, timestamp)
+ self.assertIsNotNone(self.venue.tap_list_last_update_time)
def test_guess_manufacturer_good_people(self):
mfg_names = [
diff --git a/tap_list_providers/test/test_taphunter.py b/tap_list_providers/test/test_taphunter.py
index fc720309..18d7d69f 100644
--- a/tap_list_providers/test/test_taphunter.py
+++ b/tap_list_providers/test/test_taphunter.py
@@ -4,6 +4,7 @@
from django.core.management import call_command
from django.test import TestCase
+from django.utils.timezone import now
import responses
from beers.models import Beer, Manufacturer
@@ -38,6 +39,7 @@ def setUpTestData(cls):
@responses.activate
def test_import_taphunter_data(self):
"""Test parsing the JSON data"""
+ timestamp = now()
responses.add(
responses.GET,
TaphunterParser.URL.format(self.venue_cfg.taphunter_location),
@@ -132,3 +134,7 @@ def test_import_taphunter_data(self):
3,
price_instance,
)
+ self.venue.refresh_from_db()
+ self.assertIsNotNone(self.venue.tap_list_last_check_time)
+ self.assertGreater(self.venue.tap_list_last_check_time, timestamp)
+ self.assertIsNotNone(self.venue.tap_list_last_update_time)
diff --git a/tap_list_providers/test/test_taplist_io.py b/tap_list_providers/test/test_taplist_io.py
index 554f2467..20b759ce 100644
--- a/tap_list_providers/test/test_taplist_io.py
+++ b/tap_list_providers/test/test_taplist_io.py
@@ -5,6 +5,7 @@
from dateutil.parser import parse
from django.core.management import call_command
from django.test import TestCase
+from django.utils.timezone import now
import responses
from beers.models import Beer, Manufacturer, ManufacturerAlternateName
@@ -42,6 +43,7 @@ def setUpTestData(cls):
@responses.activate
def test_import_taplist_io_data(self):
"""Test parsing the JSON data"""
+ timestamp = now()
responses.add(
responses.GET,
TaplistDotIOParser.URL.format(
@@ -103,3 +105,7 @@ def test_import_taplist_io_data(self):
# NOTE: Yes, really.
self.assertEqual(tap.beer.style.name, "An elusive IPA")
self.assertEqual(tap.time_updated, self.timestamp)
+ self.venue.refresh_from_db()
+ self.assertIsNotNone(self.venue.tap_list_last_check_time)
+ self.assertGreater(self.venue.tap_list_last_check_time, timestamp)
+ self.assertIsNotNone(self.venue.tap_list_last_update_time)
diff --git a/tap_list_providers/test/test_untappd.py b/tap_list_providers/test/test_untappd.py
index 40d567bc..2a3c191d 100644
--- a/tap_list_providers/test/test_untappd.py
+++ b/tap_list_providers/test/test_untappd.py
@@ -5,6 +5,7 @@
from django.core.management import call_command
from django.test import TestCase
+from django.utils.timezone import now
import responses
from beers.models import Beer, Manufacturer
@@ -42,7 +43,8 @@ def setUpTestData(cls):
@responses.activate
@mock.patch("tap_list_providers.base.look_up_beer")
def test_import_untappd_data(self, mock_beer_lookup):
- """Test parsing the JSON data"""
+ """Test parsing the HTML data"""
+ timestamp = now()
responses.add(
responses.GET,
UntappdParser.URL.format(
@@ -116,6 +118,10 @@ def test_import_untappd_data(self, mock_beer_lookup):
price_instance,
)
mock_beer_lookup.delay.assert_called_with(tap.beer.id)
+ self.venue.refresh_from_db()
+ self.assertIsNotNone(self.venue.tap_list_last_check_time)
+ self.assertGreater(self.venue.tap_list_last_check_time, timestamp)
+ self.assertIsNotNone(self.venue.tap_list_last_update_time)
class StyleParsingTestCase(TestCase):
diff --git a/venues/migrations/0028_auto_20201014_1424.py b/venues/migrations/0028_auto_20201014_1424.py
new file mode 100644
index 00000000..4a117f67
--- /dev/null
+++ b/venues/migrations/0028_auto_20201014_1424.py
@@ -0,0 +1,31 @@
+# Generated by Django 3.0.8 on 2020-10-14 14:24
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("venues", "0027_auto_20200124_2059"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="venue",
+ name="tap_list_last_check_time",
+ field=models.DateTimeField(
+ blank=True,
+ null=True,
+ verbose_name="The last time the venue's tap list was refreshed",
+ ),
+ ),
+ migrations.AddField(
+ model_name="venue",
+ name="tap_list_last_update_time",
+ field=models.DateTimeField(
+ blank=True,
+ null=True,
+ verbose_name="The last time the venue's tap list was updated",
+ ),
+ ),
+ ]
diff --git a/venues/models.py b/venues/models.py
index b92a8020..947ac8ae 100644
--- a/venues/models.py
+++ b/venues/models.py
@@ -65,6 +65,12 @@ class Venue(models.Model):
max_length=25,
blank=True,
)
+ tap_list_last_check_time = models.DateTimeField(
+ "The last time the venue's tap list was refreshed", blank=True, null=True
+ )
+ tap_list_last_update_time = models.DateTimeField(
+ "The last time the venue's tap list was updated", blank=True, null=True
+ )
def __str__(self):
return self.name
diff --git a/venues/serializers.py b/venues/serializers.py
index e4907e62..21697e1b 100644
--- a/venues/serializers.py
+++ b/venues/serializers.py
@@ -45,7 +45,12 @@ class Meta:
# also marking the on_downtown_craft_beer_trail field as read-only
# to protect us from ourselves
- read_only_fields = ["untappd_url", "on_downtown_craft_beer_trail"]
+ read_only_fields = [
+ "untappd_url",
+ "on_downtown_craft_beer_trail",
+ "tap_list_last_check_time",
+ "tap_list_last_update_time",
+ ]
class VenueBySlugSerializer(VenueSerializer):