Skip to content

Commit

Permalink
Testing + new migrations
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-Jess committed Nov 17, 2024
1 parent 946e5f5 commit ce3b77b
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 192 deletions.
37 changes: 21 additions & 16 deletions backend/laundry/api_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ def get_room_url(room_id: int):
return f"{settings.LAUNDRY_URL}/rooms/{room_id}/machines?raw=true"


def get_validated(url):
"""
Makes a request to the given URL and returns the JSON response if the request is successful.
Uses headers specific to the laundry API and should not be used for other requests.
@param url: The URL to make the request to.
@return: The JSON response if the request is successful, otherwise None.
"""
try:
request = requests.get(url, timeout=60, headers=settings.LAUNDRY_HEADERS)
request.raise_for_status()
return request.json()
except HTTPError as e:
print(f"Error: {e}")
return None


def update_machine_object(machine, machine_type_data):
"""
Updates Machine status and time remaining
Expand All @@ -20,7 +36,7 @@ def update_machine_object(machine, machine_type_data):
# TODO: need to update if we identify other codes, especially error
status = machine["currentStatus"]["statusId"]
if status == "IN_USE":
time_remaining = machine[3].getText().split(" ")[0]
time_remaining = machine["currentStatus"]["remainingSeconds"]
machine_type_data["running"] += 1
try:
machine_type_data["time_remaining"].append(int(time_remaining))
Expand Down Expand Up @@ -52,14 +68,10 @@ def parse_a_room(room_request_link):

detailed = []

try:
request = requests.get(room_request_link, timeout=60, headers=settings.LAUNDRY_HEADERS)
request.raise_for_status()
except HTTPError:
request_json = get_validated(room_request_link)
if request_json is None:
return {"washers": washers, "dryers": dryers, "details": detailed}

request_json = request.json()

[
update_machine_object(machine, washers) if machine["isWasher"] else None
for machine in request_json
Expand Down Expand Up @@ -89,15 +101,8 @@ def check_is_working():
Returns True if the wash alert web interface seems to be working properly, or False otherwise.
"""

try:
all_rooms_request = requests.get(
f"{settings.LAUNDRY_URL}/geoBoundaries/5610?raw=true",
timeout=60,
headers=settings.LAUNDRY_HEADERS,
)
all_rooms_request.raise_for_status()

except HTTPError:
all_rooms_request = get_validated(f"{settings.LAUNDRY_URL}/geoBoundaries/5610?raw=true")
if all_rooms_request is None:
return False
return True

Expand Down
26 changes: 18 additions & 8 deletions backend/laundry/management/commands/load_laundry_rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,29 @@

class Command(BaseCommand):
def handle(self, *args, **kwargs):

count = 0
with open("laundry/data/laundry_data.csv") as data:
reader = csv.DictReader(data)

for row in reader:
LaundryRoom.objects.get_or_create(
room_id=int(row["room_id"]),
name=row["room_name"],
location=row["room_description"],
location_id=int(row["room_location"]),
total_washers=int(row["count_washers"]),
total_dryers=int(row["count_dryers"]),
new=True,
defaults={
"name": row["room_name"],
"location": row["room_description"],
"location_id": int(row["room_location"]),
"total_washers": int(row["count_washers"]),
"total_dryers": int(row["count_dryers"]),
},
)
count += 1

self.stdout.write("Uploaded Laundry Rooms!")
(
self.stdout.write(
f"Warning: There are {LaundryRoom.objects.all().count() - count} rooms in the "
f"database but not in the data file. If they are no longer supported by Penn's "
f"servers, consider deleting them."
)
if count < LaundryRoom.objects.all().count()
else None
)
41 changes: 12 additions & 29 deletions backend/laundry/management/commands/update_laundry_rooms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import csv

import requests
from django.conf import settings
from django.core.management.base import BaseCommand
from requests.exceptions import HTTPError

from laundry.api_wrapper import get_validated


def write_file(laundry_rooms):
Expand All @@ -18,29 +18,19 @@ class Command(BaseCommand):

def handle(self, *args, **kwargs):
# Pull initial request with everything
try:
headers = {
"x-api-key": settings.LAUNDRY_X_API_KEY,
"alliancels-auth-token": settings.LAUNDRY_ALLIANCELS_API_KEY,
}
all_rooms_request = requests.get(
f"{settings.LAUNDRY_URL}/geoBoundaries/5610?raw=true", timeout=60, headers=headers
)
all_rooms_request.raise_for_status()

except HTTPError as e:
self.stdout.write(f"Error: {e}")
all_rooms_request_json = get_validated(
f"{settings.LAUNDRY_URL}/geoBoundaries/5610?raw=true"
)
if all_rooms_request_json is None:
return

all_rooms_request_json = all_rooms_request.json()
locations = all_rooms_request_json["geoBoundaries"][0]["geoBoundaries"]

laundry_rooms = [
{
"room_id": room["id"],
"room_id": int(room["id"]),
"room_name": room["roomName"],
"room_description": location["description"],
"room_location": location["id"],
"room_location": int(location["id"]),
}
for location in locations
for room in location["rooms"]
Expand All @@ -49,18 +39,11 @@ def handle(self, *args, **kwargs):
# for each room, send a request to find number of washers and dryers
# TODO: This is really inefficient, but may require change in frontend code to update
for room in laundry_rooms:
try:
room_request = requests.get(
f"{settings.LAUNDRY_URL}/rooms/{room['room_id']}/machines?raw=true",
timeout=60,
headers=headers,
)
room_request.raise_for_status()
except HTTPError as e:
self.stdout.write(f"Error: {e}")
room_request_json = get_validated(
f"{settings.LAUNDRY_URL}/rooms/{room['room_id']}/machines?raw=true"
)
if room_request_json is None:
return

room_request_json = room_request.json()
# count washers and dryers
count_washers = 0
count_dryers = 0
Expand Down
18 changes: 18 additions & 0 deletions backend/laundry/migrations/0004_alter_laundryroom_room_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-11-17 01:04

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("laundry", "0003_rename_hall_id_laundryroom_room_id_and_more"),
]

operations = [
migrations.AlterField(
model_name="laundryroom",
name="room_id",
field=models.IntegerField(default=0, unique=True),
),
]
17 changes: 17 additions & 0 deletions backend/laundry/migrations/0005_remove_laundryroom_new.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.2 on 2024-11-17 09:12

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("laundry", "0004_alter_laundryroom_room_id"),
]

operations = [
migrations.RemoveField(
model_name="laundryroom",
name="new",
),
]
9 changes: 3 additions & 6 deletions backend/laundry/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@


class LaundryRoom(models.Model):
room_id = models.IntegerField(default=0, primary_key=True)
room_id = models.IntegerField(default=0, unique=True)
name = models.CharField(max_length=255)
location = models.CharField(max_length=255)
location_id = models.IntegerField(default=0)
total_washers = models.IntegerField(default=0)
total_dryers = models.IntegerField(default=0)

# laundry api update 9/29/2024; new indicates it is new, added to avoid nuking old info
new = models.BooleanField(default=False)

def __str__(self):
return f"Hall {self.name} | {self.location}"
return f"Room {self.name} | {self.location}"


class LaundrySnapshot(models.Model):
Expand All @@ -24,4 +21,4 @@ class LaundrySnapshot(models.Model):
available_dryers = models.IntegerField()

def __str__(self):
return f"Hall {self.room.name} | {self.date.date()}"
return f"Room {self.room.name} | {self.date.date()}"
5 changes: 4 additions & 1 deletion backend/laundry/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@


class LaundryRoomSerializer(serializers.ModelSerializer):
# tech debt but we're rewriting at some point and this maintains frontend-compatibility
hall_id = serializers.IntegerField(source="room_id")

class Meta:
model = LaundryRoom
fields = ("name", "room_id", "location")
fields = ("name", "hall_id", "location")
6 changes: 3 additions & 3 deletions backend/laundry/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@


urlpatterns = [
path("hall/<hall_id>/", cache_page(Cache.MINUTE)(HallInfo.as_view()), name="hall-info"),
path("usage/<hall_id>/", cache_page(Cache.MINUTE)(HallUsage.as_view()), name="hall-usage"),
path("hall/<room_id>/", cache_page(Cache.MINUTE)(HallInfo.as_view()), name="hall-info"),
path("usage/<room_id>/", cache_page(Cache.MINUTE)(HallUsage.as_view()), name="hall-usage"),
path(
"rooms/<hall_ids>",
"rooms/<room_ids>",
cache_page(Cache.MINUTE)(MultipleHallInfo.as_view()),
name="multiple-hall-info",
),
Expand Down
14 changes: 6 additions & 8 deletions backend/laundry/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ def compute_usage(room_id):

return content

def get(self, request, hall_id):
return Response(HallUsage.compute_usage(hall_id))
def get(self, request, room_id):
return Response(HallUsage.compute_usage(room_id))


class Preferences(APIView):
Expand All @@ -155,9 +155,9 @@ def get(self, request):
cached_preferences = cache.get(key)
if cached_preferences is None:
preferences = request.user.profile.laundry_preferences.all()
cached_preferences = preferences.values_list("hall_id", flat=True)
cached_preferences = preferences.values_list("room_id", flat=True)
# get all laundries with one of these
valid_rooms = LaundryRoom.objects.filter(room_id__in=cached_preferences, new=True)
valid_rooms = LaundryRoom.objects.filter(room_id__in=cached_preferences)
cached_preferences = valid_rooms.values_list("room_id", flat=True)
cache.set(key, cached_preferences, Cache.MONTH)

Expand All @@ -169,12 +169,10 @@ def post(self, request):
preferences = profile.laundry_preferences
if "rooms" not in request.data:
return Response({"success": False, "error": "No rooms provided"}, status=400)

halls = [
get_object_or_404(LaundryRoom, room_id=int(hall_id))
for hall_id in request.data["rooms"]
get_object_or_404(LaundryRoom, room_id=int(room_id))
for room_id in request.data["rooms"]
]

# clears all previous preferences in many-to-many
preferences.clear()
preferences.add(*halls)
Expand Down
4 changes: 2 additions & 2 deletions backend/tests/laundry/mock_geoboundaries_request.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,11 @@
"signupBonusExpirationDate": null,
"maxRedemptions": null,
"ordinalValue": 1
},
}
],
"ordinalValue": 4,
"isRetail": false
},
}
],
"ordinalValue": 0,
"isRetail": false
Expand Down
Loading

0 comments on commit ce3b77b

Please sign in to comment.