Skip to content

Commit 3dfe7e3

Browse files
Update fitness to new API
1 parent 6453435 commit 3dfe7e3

7 files changed

Lines changed: 313 additions & 173 deletions

File tree

Pipfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[[source]]
2+
url = "https://pypi.org/simple"
3+
verify_ssl = true
4+
name = "pypi"
5+
6+
[packages]
7+
8+
[dev-packages]
9+
10+
[requires]
11+
python_version = "3.11"

backend/penndata/management/commands/get_fitness_snapshot.py

Lines changed: 39 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import zoneinfo
2+
13
import requests
2-
from bs4 import BeautifulSoup
3-
from dateutil import parser
4+
from django.conf import settings
45
from django.core.management.base import BaseCommand
5-
from django.utils import timezone
6+
from django.utils.dateparse import parse_datetime
7+
from django.utils.timezone import make_aware
68

79
from penndata.models import FitnessRoom, FitnessSnapshot
810

@@ -12,77 +14,59 @@ def cap_string(s):
1214

1315

1416
def get_usages():
15-
16-
# count/capacities default to 0 since spreadsheet number appears blank if no one there
17-
locations = [
18-
"4th Floor Fitness",
19-
"3rd Floor Fitness",
20-
"2nd Floor Strength",
21-
"Basketball Courts",
22-
"MPR",
23-
"Climbing Wall",
24-
"1st Floor Fitness",
25-
"Pool-Shallow",
26-
"Pool-Deep",
27-
]
28-
usages = {location: {"count": 0, "capacity": 0} for location in locations}
29-
30-
date = timezone.localtime() # default if can't get date from spreadsheet
31-
3217
try:
3318
resp = requests.get(
34-
(
35-
"https://docs.google.com/spreadsheets/u/0/d/e/"
36-
"2PACX-1vSX91_MlAjJo5uVLznuy7BFnUgiBOI28oBCReLRKKo76L"
37-
"-k8EFgizAYXpIKPBX_c76wC3aztn3BogD4"
38-
"/pubhtml/sheet?headers=false&gid=0"
39-
)
19+
"https://goboardapi.azurewebsites.net/api/FacilityCount/GetCountsByAccount",
20+
params={"AccountAPIKey": settings.FITNESS_TOKEN},
4021
)
22+
data = resp.json()
4123
except ConnectionError:
4224
return None
43-
44-
html = resp.content.decode("utf8")
45-
soup = BeautifulSoup(html, "html5lib")
46-
if not (embedded_spreadsheet := soup.find("tbody")):
25+
except requests.exceptions.JSONDecodeError:
4726
return None
4827

49-
table_rows = embedded_spreadsheet.findChildren("tr")
50-
for i, row in enumerate(table_rows):
51-
cells = row.findChildren("td")
52-
if i == 0:
53-
date = timezone.make_aware(parser.parse(cells[1].getText()))
54-
elif (location := cap_string(cells[0].getText())) in usages:
55-
try:
56-
count = int(cells[1].getText())
57-
capacity = float(cells[2].getText().strip("%"))
58-
usages[location] = {"count": count, "capacity": capacity}
59-
except ValueError:
60-
pass
61-
else:
62-
print(f"Unknown location: {location}")
63-
return usages, date
28+
def location_aware_datetime(time_str):
29+
date = parse_datetime(time_str)
30+
timezone = zoneinfo.ZoneInfo("America/New_York")
31+
return make_aware(date, timezone=timezone)
32+
33+
usages = {
34+
location["LocationName"]: {
35+
"count": location["LastCount"],
36+
"capacity": location["TotalCapacity"],
37+
"last_updated": location_aware_datetime(location["LastUpdatedDateAndTime"]),
38+
}
39+
for location in data
40+
}
41+
return usages
6442

6543

6644
class Command(BaseCommand):
67-
help = "Captures a new Fitness Snapshot for every Laundry room."
45+
help = "Captures a new Fitness Snapshot for every Fitness room."
6846

6947
def handle(self, *args, **kwargs):
70-
usage_by_location, date = get_usages()
71-
72-
# prevent double creating FitnessSnapshots
73-
if FitnessSnapshot.objects.filter(date=date).exists():
74-
self.stdout.write("FitnessSnapshots already exist for this date!")
75-
return
76-
48+
def exists(record):
49+
(name, usage) = record
50+
try:
51+
room = FitnessRoom.objects.get(name=name)
52+
except FitnessRoom.DoesNotExist:
53+
return False
54+
return not FitnessSnapshot.objects.filter(
55+
date=usage["last_updated"], room=room
56+
).exists()
57+
58+
# Don't update locations for which we already have a room with a matching last_updated date.
59+
# This is also O(n^2), idk how we feel about that chat
60+
usage_by_location = filter(exists, get_usages().items())
7761
FitnessSnapshot.objects.bulk_create(
7862
[
7963
FitnessSnapshot(
8064
room=FitnessRoom.objects.get_or_create(name=room_name)[0],
81-
date=date,
65+
date=room_usage["last_updated"],
8266
count=room_usage["count"],
8367
capacity=room_usage["capacity"],
8468
)
85-
for room_name, room_usage in usage_by_location.items()
69+
for (room_name, room_usage) in usage_by_location
8670
]
8771
)
8872

backend/penndata/management/commands/load_fitness_rooms.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
class Command(BaseCommand):
77
def handle(self, *args, **kwargs):
88
fitness_rooms = [
9-
"4th Floor Fitness",
10-
"3rd Floor Fitness",
11-
"2nd Floor Strength",
12-
"Basketball Courts",
13-
"MPR",
149
"Climbing Wall",
10+
"Rec Lounge",
1511
"1st Floor Fitness",
16-
"Pool-Shallow",
17-
"Pool-Deep",
12+
"Court 1",
13+
"Court 2",
14+
"Court 3",
15+
"Multipurpose Room",
16+
"2nd Floor Weight Room",
17+
"3rd Floor Fitness Room",
18+
"4th Floor Fitness Room",
19+
"Studio 409",
20+
"Sheerr Pool",
1821
]
1922
for room in fitness_rooms:
2023
obj, _ = FitnessRoom.objects.get_or_create(name=room)

backend/pennmobile/settings/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@
180180
LIBCAL_SECRET = os.environ.get("LIBCAL_SECRET", None)
181181
WHARTON_TOKEN = os.environ.get("WHARTON_TOKEN", None)
182182

183+
# Fitness Token
184+
FITNESS_TOKEN = os.environ.get("FITNESS_TOKEN", None)
185+
183186
# Upload file storage
184187
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
185188
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID", None)

backend/tests/penndata/fitness_snapshot.html

Lines changed: 0 additions & 106 deletions
This file was deleted.

0 commit comments

Comments
 (0)