Skip to content

Commit 738448d

Browse files
authored
make dining cache clearable (#415)
* make dining cache clearable * Remove debug print statements Removed debug print statements from test_views.py
1 parent 9f436c1 commit 738448d

6 files changed

Lines changed: 69 additions & 2 deletions

File tree

backend/dining/management/commands/load_next_menu.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.utils import timezone
55

66
from dining.api_wrapper import DiningAPIWrapper
7+
from dining.utils.menu_view_cache import delete_menu_view_cache
78

89

910
class Command(BaseCommand):
@@ -19,6 +20,7 @@ def load_one_menu(self, delta, *args, **kwargs):
1920
"""
2021
d = DiningAPIWrapper()
2122
d.load_menu(timezone.now().date() + datetime.timedelta(days=delta))
23+
delete_menu_view_cache(timezone.now().date() + datetime.timedelta(days=delta))
2224
self.stdout.write(
2325
"Loaded new Dining Menu for "
2426
+ str(timezone.now().date() + datetime.timedelta(days=delta))

backend/dining/utils/__init__.py

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from django.core.cache import cache
2+
from django.utils import timezone
3+
4+
5+
VIEW_CACHE_KEY = "clearable_dining_menu_view_cache"
6+
VIEW_CACHE_TIMEOUT = 60 * 60 * 3 # 3 hours
7+
8+
9+
def _get_key(date_param):
10+
return f"{VIEW_CACHE_KEY}_{date_param if date_param is not None else timezone.now().date()}"
11+
12+
13+
def get_menu_view_cache(date_param):
14+
return cache.get(_get_key(date_param))
15+
16+
17+
def set_menu_view_cache(date_param, data):
18+
cache.set(_get_key(date_param), data, timeout=VIEW_CACHE_TIMEOUT)
19+
20+
21+
def delete_menu_view_cache(date_param):
22+
cache.delete(_get_key(date_param))

backend/dining/views.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from dining.api_wrapper import APIError, DiningAPIWrapper
1616
from dining.models import DiningMenu, Venue
1717
from dining.serializers import DiningMenuSerializer
18+
from dining.utils.menu_view_cache import get_menu_view_cache, set_menu_view_cache
1819
from pennmobile.analytics import LabsAnalytics
1920
from utils.cache import Cache
2021

@@ -77,6 +78,17 @@ def get_queryset(self):
7778

7879
return latest
7980

81+
def get(self, request, *args, **kwargs):
82+
try:
83+
date_param = self.kwargs.get("date")
84+
if get_menu_view_cache(date_param) is not None:
85+
return Response(get_menu_view_cache(date_param))
86+
res = super().get(request, *args, **kwargs)
87+
set_menu_view_cache(date_param, res.data)
88+
return res
89+
except APIError as e:
90+
return Response({"error": str(e)}, status=400)
91+
8092

8193
class Preferences(APIView):
8294
"""

backend/pennmobile/settings/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
import os
1111

1212
import dj_database_url
13+
from dotenv import load_dotenv
14+
15+
16+
load_dotenv()
1317

1418

1519
DOMAINS = os.environ.get("DOMAINS", "example.com").split(",")

backend/tests/dining/test_views.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
from django.contrib.auth import get_user_model
66
from django.core.management import call_command
77
from django.test import TestCase
8+
from django.test.utils import override_settings
89
from django.urls import reverse
10+
from django.utils import timezone
911
from requests.exceptions import ConnectionError
1012
from rest_framework.test import APIClient
1113

1214
from dining.api_wrapper import APIError, DiningAPIWrapper
1315
from dining.models import DiningMenu, Venue
16+
from dining.utils.menu_view_cache import get_menu_view_cache
1417

1518

1619
User = get_user_model()
@@ -35,7 +38,12 @@ def json(self):
3538
raise ValueError
3639

3740
with open(file_path) as data:
38-
return Mock(json.load(data), 200)
41+
if len(args) > 0 and "menus" in args[0]:
42+
res = json.load(data)
43+
res["menus"]["days"][0]["date"] = str(timezone.now().date())
44+
return Mock(res, 200)
45+
else:
46+
return Mock(json.load(data), 200)
3947

4048

4149
def mock_request_raise_error(*args, **kwargs):
@@ -137,7 +145,7 @@ def test_get_default(self):
137145
self.try_structure(response.json())
138146

139147
def test_get_date(self):
140-
response = self.client.get("/dining/menus/2022-10-04/")
148+
response = self.client.get("/dining/menus/" + str(timezone.now().date()) + "/")
141149
self.try_structure(response.json())
142150

143151
@mock.patch("requests.request", mock_dining_requests)
@@ -149,6 +157,25 @@ def test_skip_venue(self):
149157
self.assertEqual(DiningMenu.objects.count(), 0)
150158

151159

160+
@override_settings(
161+
CACHES={
162+
"default": {
163+
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
164+
}
165+
}
166+
)
167+
class TestMenuViewCache(TestCase):
168+
@mock.patch("requests.post", mock_dining_requests)
169+
@mock.patch("requests.request", mock_dining_requests)
170+
def test_cache_cleared_on_load_next_menu(self):
171+
call_command("load_next_menu")
172+
response = self.client.get(reverse("menus-with-date", args=[str(timezone.now().date())]))
173+
self.assertEqual(response.status_code, 200)
174+
self.assertIsNotNone(get_menu_view_cache(str(timezone.now().date())))
175+
call_command("load_next_menu")
176+
self.assertIsNone(get_menu_view_cache(str(timezone.now().date())))
177+
178+
152179
class TestPreferences(TestCase):
153180
def setUp(self):
154181
call_command("load_venues")

0 commit comments

Comments
 (0)