Skip to content

Commit 773568f

Browse files
committed
refactor(gsr): simplify permission check error handling and add logging
- Add logging to is_wharton() and is_seas() to track API failures - Return False instead of raising errors for failed permission checks - Remove need for try/except boilerplate from views, models, and commands
1 parent 6112d76 commit 773568f

6 files changed

Lines changed: 43 additions & 27 deletions

File tree

backend/gsr_booking/api_wrapper.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import datetime
2+
import logging
23
import re
34
from abc import ABC, abstractmethod
45
from enum import Enum
@@ -21,6 +22,9 @@
2122
from utils.errors import APIError
2223

2324

25+
logger = logging.getLogger(__name__)
26+
27+
2428
User = get_user_model()
2529

2630

@@ -158,17 +162,22 @@ def get_reservations(self, user):
158162
]
159163

160164
def is_wharton(self, user):
165+
"""
166+
Check if user has Wharton privileges.
167+
Returns False if user doesn't have access or if API fails.
168+
Logs errors for monitoring.
169+
"""
161170
url = f"{WHARTON_URL}{user.username}/privileges"
162171
try:
163172
response = self.request("GET", url)
164173
if response.status_code != 200:
165-
return None
174+
logger.error(f"Wharton API error for {user.username}: HTTP {response.status_code}")
175+
return False
166176
res_json = response.json()
167177
return res_json.get("type") == "whartonMBA" or res_json.get("type") == "whartonUGR"
168-
except APIError:
169-
raise
170-
except Exception as e:
171-
raise APIError(f"Wharton: Error checking privileges: {str(e)}")
178+
except APIError as e:
179+
logger.error(f"Wharton API error for {user.username}: {e}")
180+
return False
172181

173182

174183
class PennGroupsBookingWrapper(AbstractBookingWrapper):
@@ -280,12 +289,17 @@ def get_authorized_rooms(self, user):
280289
raise APIError(f"PennGroups: Error accessing API: {str(e)}")
281290

282291
def is_seas(self, user):
283-
"""Check if user has SEAS status"""
292+
"""
293+
Check if user has SEAS status.
294+
Returns False if user doesn't have SEAS access or if API fails.
295+
Logs errors for monitoring.
296+
"""
284297
try:
285298
rooms = self.get_authorized_rooms(user)
286299
return len(rooms) > 0
287-
except APIError:
288-
raise
300+
except APIError as e:
301+
logger.error(f"PennGroups API error for {user.username}: {e}")
302+
return False
289303

290304
def extract_room_number(self, libcal_name):
291305
"""Extract room number from LibCal name like 'AGH 334' -> '334' or 'AGH 300A' -> '300A'"""

backend/gsr_booking/management/commands/add_pennlabs_users.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def handle(self, *args, **options):
3535
except User.DoesNotExist:
3636
self.stdout.write(f"User with PennKey {pennkey} does not exist. Skipping.")
3737
continue
38+
3839
users.append(user)
3940
is_wharton = WhartonGSRBooker.is_wharton(user)
4041
wharton_statuses.append(is_wharton)

backend/gsr_booking/management/commands/update_seas_status.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ class Command(BaseCommand):
1111
def handle(self, *args, **kwargs):
1212
users = GroupMembership.objects.values_list("user__username", flat=True).distinct()
1313
print(f"Checking {len(users)} users...")
14+
penngroups_wrapper = PennGroupsBookingWrapper()
15+
updated = 0
16+
1417
for username in users:
1518
user = get_user_model().objects.get(username=username)
16-
is_seas = PennGroupsBookingWrapper().is_seas(user)
19+
is_seas = penngroups_wrapper.is_seas(user)
1720
memberships = GroupMembership.objects.filter(user__username=user)
1821
for membership in memberships:
1922
if membership.is_seas != is_seas:
2023
membership.is_seas = is_seas
2124
membership.save()
2225
status = "now" if is_seas else "no longer"
2326
print(f"User {user} is {status} a SEAS user.")
24-
print("Done updating SEAS statuses.")
27+
updated += 1
28+
29+
print(f"Done updating SEAS statuses. Updated: {updated} users.")

backend/gsr_booking/management/commands/update_wharton_status.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,19 @@ class Command(BaseCommand):
1111
def handle(self, *args, **kwargs):
1212
users = GroupMembership.objects.values_list("user__username", flat=True).distinct()
1313
print(f"Checking {len(users)} users...")
14+
wharton_wrapper = WhartonBookingWrapper()
15+
updated = 0
16+
1417
for username in users:
1518
user = get_user_model().objects.get(username=username)
16-
is_wharton = WhartonBookingWrapper().is_wharton(user)
19+
is_wharton = wharton_wrapper.is_wharton(user)
1720
memberships = GroupMembership.objects.filter(user__username=user)
1821
for membership in memberships:
1922
if membership.is_wharton != is_wharton:
2023
membership.is_wharton = is_wharton
2124
membership.save()
2225
status = "now" if is_wharton else "no longer"
2326
print(f"User {user} is {status} a Wharton user.")
24-
print("Done updating Wharton statuses.")
27+
updated += 1
28+
29+
print(f"Done updating Wharton statuses. Updated: {updated} users.")

backend/gsr_booking/models.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from django.dispatch import receiver
88
from django.utils import timezone
99

10-
from utils.errors import APIError
11-
1210

1311
User = get_user_model()
1412

@@ -54,16 +52,10 @@ def save(self, *args, **kwargs):
5452
super().save(*args, **kwargs)
5553

5654
def check_wharton(self):
57-
try:
58-
return WhartonGSRBooker.is_wharton(self.user)
59-
except APIError:
60-
return False
55+
return WhartonGSRBooker.is_wharton(self.user)
6156

6257
def check_seas(self):
63-
try:
64-
return PennGroupsGSRBooker.is_seas(self.user)
65-
except APIError:
66-
return False
58+
return PennGroupsGSRBooker.is_seas(self.user)
6759

6860
class Meta:
6961
verbose_name = "Group Membership"

backend/tests/gsr_booking/test_gsr_views.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from django.urls import reverse
88
from rest_framework.test import APIClient
99

10-
from gsr_booking.api_wrapper import APIError
1110
from gsr_booking.models import GSR, Group, GroupMembership, GSRBooking
1211

1312

@@ -211,14 +210,14 @@ def test_get_location_penn_labs_member(self):
211210
self.assertIn(self.agh_gsr.id, gsr_ids, "AGH GSR should be visible")
212211
self.assertIn(self.weigle_gsr.id, gsr_ids, "Weigle GSR should be visible")
213212

214-
@mock.patch("gsr_booking.views.WhartonGSRBooker.is_wharton", side_effect=APIError("API Error"))
215-
@mock.patch("gsr_booking.views.PennGroupsGSRBooker.is_seas", side_effect=APIError("API Error"))
213+
@mock.patch("gsr_booking.views.WhartonGSRBooker.is_wharton", return_value=False)
214+
@mock.patch("gsr_booking.views.PennGroupsGSRBooker.is_seas", return_value=False)
216215
def test_get_location_api_error_handling(self, mock_is_seas, mock_is_wharton):
217-
"""Test that API errors are handled gracefully and users still see LibCal GSRs"""
216+
"""Test that when permission checks return False, users only see LibCal GSRs"""
218217
response = self.client.get(reverse("locations"))
219218
res_json = json.loads(response.content)
220219

221-
# Even if API calls fail, users should still see LibCal GSRs
220+
# When permission checks return False, users should only see LibCal GSRs
222221
for entry in res_json:
223222
self.assertIn("kind", entry)
224223
self.assertEqual(entry["kind"], GSR.KIND_LIBCAL)

0 commit comments

Comments
 (0)