-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Fix] Laundry Rewrite to Account For New SpeedQueen API (#308)
* Laundry rewrite for new Penn API sans tests * Make PR changes * Rewrite laundry mocks * Laundry testing * Comment out tests - approved by team lead * Lint * Testing + new migrations * Reflect model change to penndata * Make changes * Squash migrations * Lint
- Loading branch information
Showing
22 changed files
with
2,327 additions
and
325 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,88 +1,91 @@ | ||
import requests | ||
from bs4 import BeautifulSoup | ||
from django.conf import settings | ||
from django.utils import timezone | ||
from requests.exceptions import ConnectTimeout, HTTPError, ReadTimeout | ||
from requests.exceptions import HTTPError | ||
|
||
from laundry.models import LaundryRoom, LaundrySnapshot | ||
|
||
|
||
HALL_URL = f"{settings.LAUNDRY_URL}/?location=" | ||
def get_room_url(room_id: int): | ||
return f"{settings.LAUNDRY_URL}/rooms/{room_id}/machines?raw=true" | ||
|
||
|
||
def update_machine_object(cols, machine_object): | ||
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 | ||
""" | ||
|
||
if cols[2].getText() in ["In use", "Almost done"]: | ||
time_remaining = cols[3].getText().split(" ")[0] | ||
machine_object["running"] += 1 | ||
# TODO: Early stage in update 9/29/2024, known status codes are | ||
# TODO: "IN_USE", "AVAILABLE", "COMPLETE"; | ||
# TODO: need to update if we identify other codes, especially error | ||
status = machine["currentStatus"]["statusId"] | ||
if status == "IN_USE": | ||
time_remaining = machine["currentStatus"]["remainingSeconds"] | ||
machine_type_data["running"] += 1 | ||
try: | ||
machine_object["time_remaining"].append(int(time_remaining)) | ||
machine_type_data["time_remaining"].append(int(time_remaining)) | ||
except ValueError: | ||
pass | ||
elif cols[2].getText() == "Out of order": | ||
machine_object["out_of_order"] += 1 | ||
elif cols[2].getText() == "Not online": | ||
machine_object["offline"] += 1 | ||
elif status in ["AVAILABLE", "COMPLETE"]: | ||
machine_type_data["open"] += 1 | ||
# TODO: Verify there are no other statuses | ||
else: | ||
machine_object["open"] += 1 | ||
machine_type_data["offline"] += 1 | ||
|
||
# edge case that handles machine not sending time data | ||
diff = int(machine_object["running"]) - len(machine_object["time_remaining"]) | ||
# TODO: I don't think we need this? | ||
diff = int(machine_type_data["running"]) - len(machine_type_data["time_remaining"]) | ||
while diff > 0: | ||
machine_object["time_remaining"].append(-1) | ||
machine_type_data["time_remaining"].append(-1) | ||
diff = diff - 1 | ||
|
||
return machine_object | ||
return machine_type_data | ||
|
||
|
||
def parse_a_hall(hall_link): | ||
def parse_a_room(room_request_link): | ||
""" | ||
Return names, hall numbers, and the washers/dryers available for a certain hall_id | ||
Return names, hall numbers, and the washers/dryers available for a certain room_id | ||
""" | ||
|
||
washers = {"open": 0, "running": 0, "out_of_order": 0, "offline": 0, "time_remaining": []} | ||
dryers = {"open": 0, "running": 0, "out_of_order": 0, "offline": 0, "time_remaining": []} | ||
|
||
detailed = [] | ||
|
||
try: | ||
page = requests.get( | ||
hall_link, | ||
timeout=60, | ||
headers={"Authorization": "Basic Sure-Nothing-Could-Go-Wrong-With-This-HaHa-Not"}, | ||
) | ||
# page = requests.get(hall_link, timeout=60) | ||
except (ConnectTimeout, ReadTimeout): | ||
request_json = get_validated(room_request_link) | ||
if request_json is None: | ||
return {"washers": washers, "dryers": dryers, "details": detailed} | ||
|
||
soup = BeautifulSoup(page.content, "html.parser") | ||
soup.prettify() | ||
|
||
rows = soup.find_all("tr") | ||
for row in rows: | ||
cols = row.find_all("td") | ||
if len(cols) > 1: | ||
machine_type = cols[1].getText() | ||
if machine_type == "Washer": | ||
washers = update_machine_object(cols, washers) | ||
elif machine_type == "Dryer": | ||
dryers = update_machine_object(cols, dryers) | ||
if machine_type in ["Washer", "Dryer"]: | ||
try: | ||
time = int(cols[3].getText().split(" ")[0]) | ||
except ValueError: | ||
time = 0 | ||
detailed.append( | ||
{ | ||
"id": int(cols[0].getText().split(" ")[1][1:]), | ||
"type": cols[1].getText().lower(), | ||
"status": cols[2].getText(), | ||
"time_remaining": time, | ||
} | ||
) | ||
for machine in request_json: | ||
if machine["isWasher"]: | ||
update_machine_object(machine, washers) | ||
elif machine["isDryer"]: | ||
update_machine_object(machine, dryers) | ||
detailed = [ | ||
{ | ||
"id": machine["id"], | ||
"type": "washer" if machine["isWasher"] else "dryer", | ||
"status": machine["currentStatus"]["statusId"], | ||
"time_remaining": machine["currentStatus"]["remainingSeconds"], | ||
} | ||
for machine in request_json | ||
if machine["isWasher"] or machine["isDryer"] | ||
] | ||
|
||
return {"washers": washers, "dryers": dryers, "details": detailed} | ||
|
||
|
@@ -92,26 +95,8 @@ def check_is_working(): | |
Returns True if the wash alert web interface seems to be working properly, or False otherwise. | ||
""" | ||
|
||
try: | ||
r = requests.post( | ||
"{}/".format(settings.LAUNDRY_URL), | ||
timeout=60, | ||
headers={"Authorization": "Basic Sure-Nothing-Could-Go-Wrong-With-This-HaHa-Not"}, | ||
data={ | ||
"locationid": "5faec7e9-a4aa-47c2-a514-950c03fac460", | ||
"email": "[email protected]", | ||
"washers": 0, | ||
"dryers": 0, | ||
"locationalert": "OK", | ||
}, | ||
) | ||
r.raise_for_status() | ||
return ( | ||
"The transaction log for database 'QuantumCoin' is full due to 'LOG_BACKUP'." | ||
not in r.text | ||
) | ||
except HTTPError: | ||
return False | ||
all_rooms_request = get_validated(f"{settings.LAUNDRY_URL}/geoBoundaries/5610?raw=true") | ||
return all_rooms_request is not None | ||
|
||
|
||
def all_status(): | ||
|
@@ -120,16 +105,16 @@ def all_status(): | |
""" | ||
|
||
return { | ||
room.name: parse_a_hall(HALL_URL + str(room.uuid)) for room in LaundryRoom.objects.all() | ||
room.name: parse_a_room(get_room_url(room.room_id)) for room in LaundryRoom.objects.all() | ||
} | ||
|
||
|
||
def hall_status(room): | ||
def room_status(room): | ||
""" | ||
Return the status of each specific washer/dryer in a particular hall_id | ||
""" | ||
|
||
machines = parse_a_hall(HALL_URL + str(room.uuid)) | ||
machines = parse_a_room(get_room_url(room.room_id)) | ||
|
||
return {"machines": machines, "hall_name": room.name, "location": room.location} | ||
|
||
|
@@ -145,7 +130,6 @@ def save_data(): | |
data = all_status() | ||
|
||
for name, room in data.items(): | ||
|
||
laundry_room = LaundryRoom.objects.get(name=name) | ||
|
||
LaundrySnapshot.objects.create( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,54 @@ | ||
0,Bishop White,Quad,5faec7e9-a4aa-47c2-a514-950c03fac460,9,9 | ||
1,Chestnut Butcher,Quad,7dfa4b34-f44a-4a38-a6b9-44cdb968a915,11,11 | ||
2,Class of 1928 Fisher,Quad,e6697dca-d164-4980-8843-ea0a29b1cf49,8,8 | ||
3,Craig,Quad,37d661ce-3e50-4746-ab68-a5c61cd0bd0a,3,3 | ||
4,DuBois,DuBois,3ffa8978-e742-4076-9bcb-4a3e5c0eca92,6,6 | ||
5,English House,KCEH,b655a5be-1287-4ce2-b693-e9c1ae526f38,3,3 | ||
6,Harnwell Floor 02,Harnwell,1c7a9fb3-a938-4756-83c6-42d601d46036,3,3 | ||
7,Harnwell Floor 04,Harnwell,fba67cc0-336e-42f7-9603-c0b8a0e5030c,3,3 | ||
8,Harnwell Floor 06,Harnwell,87195ec7-eb3d-42fd-84aa-d63f4e45e285,3,3 | ||
9,Harnwell Floor 08,Harnwell,1bbb2ff6-d5e6-406d-a3a2-96c7972cceeb,3,3 | ||
10,Harnwell Floor 10,Harnwell,987bf30b-e8e1-4a9e-b842-c9cd8aeafddc,3,3 | ||
11,Harnwell Floor 12,Harnwell,dcb76f10-0137-4783-8604-bece4111b6dd,3,3 | ||
12,Harnwell Floor 14,Harnwell,941b2fcb-2b1b-4afd-8e8e-c100fbcbe0f2,3,3 | ||
13,Harnwell Floor 16,Harnwell,c74b2798-2d09-42a6-b65c-a5834219be59,3,3 | ||
14,Harnwell Floor 18,Harnwell,f30af904-72ad-49f6-aecf-f44c8301fb6b,3,3 | ||
15,Harnwell Floor 20,Harnwell,80a413fd-e0fa-456d-b922-f1576ded1f98,3,3 | ||
16,Harnwell Floor 22,Harnwell,35119e5e-92c0-45fb-bfeb-f2059196f644,3,3 | ||
17,Harnwell Floor 24,Harnwell,5880b051-8216-4cf4-92d6-5c7475f43eea,3,3 | ||
18,Harrison Floor 04,Harrison,447b5682-4c3c-441d-ab49-5f45aee6991f,3,3 | ||
19,Harrison Floor 06,Harrison,f77f7c68-f719-4843-8987-d64dabc0abff,3,3 | ||
20,Harrison Floor 08,Harrison,6561bb14-634f-437d-84fd-a0837ef991e7,3,3 | ||
21,Harrison Floor 10,Harrison,2dd7a63d-7d13-48e5-b038-98054b4f039f,3,3 | ||
22,Harrison Floor 12,Harrison,fdb607c7-63eb-4d55-a312-0c16b682cbe7,3,3 | ||
23,Harrison Floor 14,Harrison,53fdd440-e887-49e1-9ca9-7bb3cb4ab541,3,3 | ||
24,Harrison Floor 16,Harrison,8cedf60a-8f87-4128-89dd-4c75343ca64a,3,3 | ||
25,Harrison Floor 18,Harrison,116a8d6f-045b-47a5-b3f7-af31f4e661eb,3,3 | ||
26,Harrison Floor 20,Harrison,f6a8b303-1302-49e6-be53-c8e345316ed8,3,3 | ||
27,Harrison Floor 22,Harrison,b21c78af-1ebf-418c-a73b-85dc5ff49763,3,3 | ||
28,Harrison Floor 24,Harrison,9b95c471-053c-46ea-bc3b-d23bcad7a3a1,3,3 | ||
29,Hill House,Hill,82a00eb7-f70d-4a4c-9f0a-c2dafa4b67ea,16,16 | ||
30,Magee Amhurst,Quad,f6825dac-5a5a-4e4b-b66f-ea8226cbe78e,12,12 | ||
31,Mayer,Stouffer,6e3531d1-eebd-48b4-ad04-cf5983d42b02,8,8 | ||
32,Morgan,Quad,f249ca9f-ef84-4a35-9477-449b14612057,2,2 | ||
33,Rodin Floor 02,Rodin,7f25802d-31ad-4f80-ba26-d68a3f403aa8,3,3 | ||
34,Rodin Floor 04,Rodin,49e560fb-c1aa-4c98-a88a-cc9564481ec0,3,3 | ||
35,Rodin Floor 06,Rodin,701ce966-aa3c-4063-b3db-548ad89cb643,3,3 | ||
36,Rodin Floor 08,Rodin,4998a8a2-fb86-4900-bcb7-9d7cc6d9b938,3,3 | ||
37,Rodin Floor 10,Rodin,030c81c4-2300-4e8e-ae3a-303397a2e216,3,3 | ||
38,Rodin Floor 12,Rodin,c561f889-5898-41ba-99f5-2e6d4243e4d3,3,3 | ||
39,Rodin Floor 14,Rodin,2d211700-5b59-4c61-8922-991c0f7d7c15,3,3 | ||
40,Rodin Floor 16,Rodin,a10ede1d-044d-4852-87c7-eba7588c2497,3,3 | ||
41,Rodin Floor 18,Rodin,c3d3f9ae-792c-401c-8bd5-8c61fffe2ab1,3,3 | ||
42,Rodin Floor 20,Rodin,e88d3561-dce7-4188-89e7-b72cff7d69d6,3,3 | ||
43,Rodin Floor 22,Rodin,6b7dcd18-fe4e-4dc2-893f-35f0d7939c3c,3,3 | ||
44,Rodin Floor 24,Rodin,18397cd6-202e-4680-b82e-33ccd9ded1a7,3,3 | ||
45,Sansom East,Sansom,ad980c78-bf6d-429a-9a08-1b0899f83d62,16,16 | ||
46,Sansom West,Sansom,d1637690-098b-4eca-b48b-6d137207a38e,16,16 | ||
47,Stouffer Commons,Stouffer,d4848e7d-fdd0-4faa-b6bd-dc152842cf84,6,6 | ||
48,New College House,New College House,14b91b75-563b-4a7f-8b80-4efed338c29b,10,10 | ||
49,Harrison Floor 02,Harrison,78568718-85eb-420b-bc10-77154a685699,3,3 | ||
50,Van Pelt,Gregory,5d9b0588-c987-4d2c-9842-2ce3e9101577,6,6 | ||
51,Class of 1925,Gregory,78f20171-ab32-4650-a1ce-28ace7095790,4,4 | ||
52,Kings Court,KCEH,fdbd6c5f-cb26-486f-86cc-f0b95a7f2a8a,5,6 | ||
room_id,room_name,room_description,room_location,count_washers,count_dryers | ||
14089,English House,English House,14146,3,3 | ||
14082,"Gregory College House: Class of 1925""",Gregory College House: Class of 1925,14138,4,4 | ||
14085,Gregory College House: Van Pelt,Gregory College House: Van Pelt,14141,6,6 | ||
5249,Gutmann College House,Gutmann College House,5611,18,18 | ||
14099,Harnwell 10th Floor,Harnwell College House,14150,3,3 | ||
14100,Harnwell 12th Floor,Harnwell College House,14150,3,3 | ||
14101,Harnwell 14th Floor,Harnwell College House,14150,3,3 | ||
14102,Harnwell 16th Floor,Harnwell College House,14150,3,3 | ||
14103,Harnwell 18th Floor,Harnwell College House,14150,3,3 | ||
14104,Harnwell 20th Floor,Harnwell College House,14150,3,3 | ||
14105,Harnwell 22nd Floor,Harnwell College House,14150,3,3 | ||
14106,Harnwell 24th Floor,Harnwell College House,14150,3,3 | ||
14094,Harnwell 2nd Floor,Harnwell College House,14150,3,3 | ||
14095,Harnwell 4th Floor,Harnwell College House,14150,3,3 | ||
14096,Harnwell 6th Floor,Harnwell College House,14150,3,3 | ||
14098,Harnwell 8th Floor,Harnwell College House,14150,3,3 | ||
14111,Harrison 10th Floor,Harrison College House,14153,3,3 | ||
14112,Harrison 12th Floor ,Harrison College House,14153,3,3 | ||
14113,Harrison 14th Floor,Harrison College House,14153,3,3 | ||
14114,Harrison 16th Floor,Harrison College House,14153,3,3 | ||
14115,Harrison 18th Floor ,Harrison College House,14153,3,3 | ||
14116,Harrison 20th Floor,Harrison College House,14153,3,3 | ||
14117,Harrison 22nd Floor,Harrison College House,14153,3,3 | ||
14118,Harrison 24th Floor,Harrison College House,14153,3,3 | ||
14107,Harrison 2nd Floor,Harrison College House,14153,3,3 | ||
14108,Harrison 4th Floor,Harrison College House,14153,3,3 | ||
14109,Harrison 6th Floor,Harrison College House,14153,3,3 | ||
14110,Harrison 8th Floor,Harrison College House,14153,3,3 | ||
14090,Hill College House,Hill College House,14147,16,16 | ||
14091,King's Court,King's Court,14148,5,6 | ||
14092,Lauder,Lauder,14149,10,10 | ||
14078,Class of 28,Quad: Fisher College House,14655,0,0 | ||
14079,Craig,Quad: Fisher College House,14655,0,0 | ||
14080,Ashhurst - Magee,Quad: Riepe College House,14137,12,12 | ||
14076,Birthday - Bishop White,Quad: Riepe College House,14137,9,9 | ||
14077,Butcher - Chestnut,Quad: Ware College House,14656,0,0 | ||
14081,Morgan,Quad: Ware College House,14656,0,0 | ||
14123,Rodin 10th Floor,Rodin College House,14154,3,3 | ||
14124,Rodin 12th Floor,Rodin College House,14154,3,3 | ||
14125,Rodin 14th Floor,Rodin College House,14154,3,3 | ||
14126,Rodin 16th Floor,Rodin College House,14154,3,3 | ||
14127,Rodin 18th Floor,Rodin College House,14154,3,3 | ||
14128,Rodin 20th Floor,Rodin College House,14154,3,3 | ||
14129,Rodin 22nd Floor,Rodin College House,14154,3,3 | ||
14130,Rodin 24th Floor,Rodin College House,14154,3,3 | ||
14119,Rodin 2nd Floor,Rodin College House,14154,3,3 | ||
14120,Rodin 4th Floor,Rodin College House,14154,3,3 | ||
14121,Rodin 6th Floor,Rodin College House,14154,3,3 | ||
14122,Rodin 8th Floor,Rodin College House,14154,3,3 | ||
14084,Samson West,Samson West,14140,16,16 | ||
11373,Stouffer Commons,Stouffer College House,11693,4,4 | ||
14093,Stouffer Mayer,Stouffer College House,11693,8,8 | ||
14083,W.E.B. Du Bois College House,W.E.B. Du Bois College House,14139,6,6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.