Skip to content

Commit

Permalink
🎊 Merge remote-tracking branch 'origin/master' into add-mypy
Browse files Browse the repository at this point in the history
  • Loading branch information
ashleyzhang01 committed Nov 14, 2024
2 parents f6034f9 + 44965e9 commit e3b7262
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 109 deletions.
33 changes: 1 addition & 32 deletions backend/gsr_booking/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from rest_framework import serializers

from gsr_booking.models import GSR, Group, GroupMembership, GSRBooking
from utils.types import UserType


ValidatedData: TypeAlias = dict[str, Any]
Expand All @@ -24,14 +23,7 @@ def get_is_wharton(self, obj: ValidatedData) -> bool:
return obj["lid"] == 1


class MiniUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["username", "first_name", "last_name"]


class GroupMembershipSerializer(serializers.ModelSerializer):
user = MiniUserSerializer(read_only=True)
group: serializers.SlugRelatedField = serializers.SlugRelatedField(
slug_field="name", queryset=Group.objects.all()
)
Expand All @@ -41,7 +33,7 @@ class GroupMembershipSerializer(serializers.ModelSerializer):

class Meta:
model = GroupMembership
fields = ["user", "group", "type", "pennkey_allow", "notifications", "id", "color"]
fields = ["group", "type", "pennkey_allow", "notifications", "id", "color"]


class GroupSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -73,29 +65,6 @@ def to_internal_value(self, data: ValidatedData) -> None:
return None # TODO: If you want to update based on BookingField, implement this.


class UserSerializer(serializers.ModelSerializer):
booking_groups = serializers.SerializerMethodField()

def get_booking_groups(self, obj: UserType) -> list[dict[str, Any]]:
result = []
for membership in GroupMembership.objects.filter(accepted=True, user=obj):
result.append(
{
"name": membership.group.name,
"id": membership.group.id,
"color": membership.group.color,
"pennkey_allow": membership.pennkey_allow,
"notifications": membership.notifications,
}
)

return result

class Meta:
model = User
fields = ["username", "booking_groups"]


class GSRSerializer(serializers.ModelSerializer):
class Meta:
model = GSR
Expand Down
4 changes: 2 additions & 2 deletions backend/gsr_booking/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
GroupMembershipViewSet,
GroupViewSet,
Locations,
MyMembershipViewSet,
RecentGSRs,
ReservationsView,
UserViewSet,
)
from utils.cache import Cache


router = routers.DefaultRouter()

router.register(r"users", UserViewSet)
router.register(r"mymemberships", MyMembershipViewSet, "mymemberships")
router.register(r"membership", GroupMembershipViewSet)
router.register(r"groups", GroupViewSet)

Expand Down
59 changes: 11 additions & 48 deletions backend/gsr_booking/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from typing import Optional

from django.contrib.auth import get_user_model
from django.db.models import Manager, Prefetch, Q, QuerySet
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404
Expand All @@ -14,68 +13,32 @@

from gsr_booking.api_wrapper import GSRBooker, WhartonGSRBooker
from gsr_booking.models import GSR, Group, GroupMembership, GSRBooking
from gsr_booking.serializers import (
GroupMembershipSerializer,
GroupSerializer,
GSRSerializer,
UserSerializer,
)
from gsr_booking.serializers import GroupMembershipSerializer, GroupSerializer, GSRSerializer
from pennmobile.analytics import Metric, record_analytics
from utils.errors import APIError
from utils.types import UserType, get_user
from utils.types import get_user


User = get_user_model()


# TODO: user model doesn't have a `booking_groups` attribute, so placing Any type for now
class UserViewSet(viewsets.ReadOnlyModelViewSet[UserType]):
"""
Can specify `me` instead of the `username` to retrieve details on the current user.
"""

queryset = User.objects.all().prefetch_related(
Prefetch("booking_groups", Group.objects.filter(memberships__accepted=True))
)
class MyMembershipViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = [IsAuthenticated]
serializer_class = UserSerializer
lookup_field = "username"
filter_backends = [DjangoFilterBackend]
filterset_fields = ["username", "first_name", "last_name"]

def get_object(self) -> UserType:
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
param = self.kwargs[lookup_url_kwarg]
if param == "me":
return get_user(self.request)
return super().get_object()

def get_queryset(self) -> QuerySet[UserType, Manager[UserType]]:
if not self.request.user.is_authenticated:
return User.objects.none()
serializer_class = GroupMembershipSerializer

user = get_user(self.request)
queryset = User.objects.all()
queryset = queryset.prefetch_related(
Prefetch(
"memberships",
GroupMembership.objects.filter(group__in=user.booking_groups.all(), accepted=True),
)
)
return queryset
def get_queryset(self) -> QuerySet[GroupMembership, Manager[GroupMembership]]:
return GroupMembership.objects.filter(user=self.request.user, accepted=True)

@action(detail=True, methods=["get"])
def invites(self, request: Request, username: Optional[str] = None) -> Response:
@action(detail=False, methods=["get"])
def invites(self, request: Request) -> Response:
"""
Retrieve all invites for a given user.
"""

user = get_object_or_404(User, username=username)
request_user = get_user(self.request)
return Response(
GroupMembershipSerializer(
GroupMembership.objects.filter(
user=user, accepted=False, group__in=request_user.booking_groups.all()
user=get_user(request),
accepted=False,
group__in=request_user.booking_groups.all(),
),
many=True,
).data
Expand Down
41 changes: 18 additions & 23 deletions backend/tests/gsr_booking/test_gsr_booking.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from typing import cast

from django.test import TestCase
from rest_framework.test import APIClient

from gsr_booking.models import Group, GroupMembership
from utils.types import DjangoUserModel, UserType


class UserViewTestCase(TestCase):
class MyMembershipViewTestCase(TestCase):
def setUp(self) -> None:
self.user1: UserType = DjangoUserModel.objects.create_user(
username="user1", password="password", first_name="user", last_name="one"
Expand All @@ -16,28 +14,25 @@ def setUp(self) -> None:
username="user2", password="password", first_name="user", last_name="two"
)

self.group = Group.objects.create(owner=self.user1, name="g1", color="blue")
self.group.members.add(self.user1)
memship = self.group.memberships.all()[0]
memship.accepted = True
memship.save()
self.client: APIClient = APIClient()
Group.objects.create(
owner=self.user1, name="g1", color="blue"
) # creating group also adds user
group2 = Group.objects.create(owner=self.user2, name="g2", color="blue")
GroupMembership.objects.create(user=self.user1, group=group2, accepted=True)
group3 = Group.objects.create(owner=self.user2, name="g3", color="blue")
GroupMembership.objects.create(user=self.user1, group=group3)
self.client = APIClient()
self.client.login(username="user1", password="password")

def test_user_list(self) -> None:
response = self.client.get("/gsr/users/")
self.assertTrue(200, response.status_code)
self.assertEqual(2, len(response.data))

def test_user_detail_in_group(self) -> None:
response = self.client.get("/gsr/users/user1/")
def test_user_memberships(self) -> None:
response = self.client.get("/gsr/mymemberships/")
self.assertTrue(200, response.status_code)
self.assertEqual(2, len(response.data["booking_groups"]))
self.assertEqual(2, len(response.data)) # type: ignore[attr-defined]

def test_me_user_detail_in_group(self) -> None:
response = self.client.get("/gsr/users/me/")
def test_user_invites(self) -> None:
response = self.client.get("/gsr/mymemberships/invites/")
self.assertTrue(200, response.status_code)
self.assertEqual(2, len(response.data["booking_groups"]))
self.assertEqual(1, len(response.data)) # type: ignore[attr-defined]


class MembershipViewTestCase(TestCase):
Expand Down Expand Up @@ -166,7 +161,7 @@ def setUp(self) -> None:
def test_get_groups(self) -> None:
response = self.client.get("/gsr/groups/")
self.assertEqual(200, response.status_code)
self.assertEqual(2, len(response.data))
self.assertEqual(1, len(response.data))

def test_get_groups_includes_invites(self) -> None:
GroupMembership.objects.create(user=self.user1, group=self.group2, accepted=False)
Expand All @@ -180,8 +175,8 @@ def test_get_group_not_involved_fails(self) -> None:
def test_make_group(self) -> None:
response = self.client.post("/gsr/groups/", {"name": "gx", "color": "blue"})
self.assertEqual(201, response.status_code, response.data)
self.assertEqual(5, Group.objects.count())
self.assertEqual("user1", cast(UserType, Group.objects.get(name="gx").owner).username)
self.assertEqual(3, Group.objects.count())
self.assertEqual("user1", Group.objects.get(name="gx").owner.username)

def test_only_accepted_memberships(self) -> None:
gm = GroupMembership.objects.create(user=self.user2, group=self.group, accepted=False)
Expand Down
3 changes: 1 addition & 2 deletions backend/tests/user/test_notifs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from identity.identity import attest, container, get_platform_jwks
from rest_framework.test import APIClient

from gsr_booking.models import GSR, Group, GSRBooking, Reservation
from gsr_booking.models import GSR, GSRBooking, Reservation
from user.models import NotificationSetting, NotificationToken
from utils.types import DjangoUserModel, UserType

Expand Down Expand Up @@ -360,7 +360,6 @@ def setUp(self) -> None:
start=g.start,
end=g.end,
creator=self.test_user,
group=Group.objects.get(owner=self.test_user),
)

g.reservation = r
Expand Down
2 changes: 0 additions & 2 deletions backend/user/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from django.db.models.signals import post_save
from django.dispatch import receiver

from gsr_booking.models import Group
from laundry.models import LaundryRoom
from penndata.models import FitnessRoom
from utils.types import UserType
Expand Down Expand Up @@ -78,7 +77,6 @@ def create_or_update_user_profile(
object exists for that User, it will create one
"""
Profile.objects.get_or_create(user=instance)
Group.objects.get_or_create(owner=instance, name="Me", color="#14f7d1")

# notifications
token, _ = NotificationToken.objects.get_or_create(user=instance)
Expand Down

0 comments on commit e3b7262

Please sign in to comment.