Skip to content

Commit e26efab

Browse files
committed
Merge branch 'master' of https://github.com/pennlabs/office-hours-queue into feature/office-hour-reservation
2 parents bb89cac + 7fdcdae commit e26efab

12 files changed

Lines changed: 33 additions & 2437 deletions

File tree

backend/Dockerfile

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
1-
FROM pennlabs/django-base:b269ea1613686b1ac6370154debbb741b012de1a-3.11
2-
ARG DEPENDENCY_MANAGER="uv"
1+
FROM pennlabs/django-base:11d476546bd11c7a499e0e93be8db6af035d360f-3.11
32

43
LABEL maintainer="Penn Labs"
54

65
# Install uv
76
COPY --from=ghcr.io/astral-sh/uv@sha256:2381d6aa60c326b71fd40023f921a0a3b8f91b14d5db6b90402e65a635053709 /uv /uvx /bin/
87

98
# Copy project dependencies
10-
COPY Pipfile* pyproject.toml uv.lock /app/
11-
12-
# Install dependencies using uv or pipenv depending on DEPENDENCY_MANAGER arg
13-
RUN if [ "$DEPENDENCY_MANAGER" = "uv" ]; then \
14-
uv sync --frozen --no-dev --no-install-project --python $(which python); \
15-
mv /app/.venv/bin/uwsgi /usr/local/bin/uwsgi; \
16-
mv /app/.venv/bin/gunicorn /usr/local/bin/gunicorn; \
17-
else \
18-
pipenv install --system; \
19-
fi
9+
COPY pyproject.toml uv.lock /app/
10+
11+
# Install dependencies
12+
RUN uv sync --frozen --no-dev --no-install-project --python $(which python); \
13+
ln -s /app/.venv/bin/uwsgi /usr/local/bin/uwsgi; \
14+
ln -s /app/.venv/bin/gunicorn /usr/local/bin/gunicorn
2015

2116
# Make installed binaries available for POSIX compliant scripts
2217
ENV PATH="/app/.venv/bin:$PATH"

backend/Pipfile

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

backend/Pipfile.lock

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

backend/ohq/admin.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
Semester,
1414
Tag,
1515
UserStatistic,
16-
Booking,
1716
)
1817

1918

@@ -29,4 +28,3 @@
2928
admin.site.register(Announcement)
3029
admin.site.register(Tag)
3130
admin.site.register(UserStatistic)
32-
admin.site.register(Booking)

backend/ohq/models.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from django.conf import settings
22
from django.core.validators import MaxValueValidator, MinValueValidator
3-
from django.core.exceptions import ValidationError
43
from django.db import models
54
from django.dispatch import receiver
65
from email_tools.emails import send_email
@@ -503,6 +502,18 @@ def __str__(self):
503502
end_str = self.end.strftime("%Y-%m-%d %H:%M:%S")
504503
return f"{start_str} to {end_str}"
505504

506-
OldEvent.add_to_class('location', models.CharField(max_length=255, blank=True))
507-
OldOccurrence.add_to_class('location', models.CharField(max_length=255, blank=True))
508-
OldOccurrence.add_to_class('interval', models.IntegerField(blank=True, null=True))
505+
Event.add_to_class('location', models.CharField(max_length=255, blank=True))
506+
Occurrence.add_to_class('location', models.CharField(max_length=255, blank=True))
507+
Occurrence.add_to_class('interval', models.IntegerField(blank=True, null=True))
508+
509+
def new_occurrence_init(self, *args, **kwargs):
510+
super(Occurrence, self).__init__(*args, **kwargs)
511+
event = kwargs.get("event", None)
512+
if not self.title and event:
513+
self.title = event.title
514+
if not self.description and event:
515+
self.description = event.description
516+
if not self.location and event:
517+
self.location = event.location
518+
519+
Occurrence.__init__ = new_occurrence_init

backend/ohq/permissions.py

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -507,44 +507,3 @@ def has_permission(self, request, view):
507507
return True
508508

509509
return True
510-
511-
class BookingPermission(permissions.BasePermission):
512-
@staticmethod
513-
def get_membership_from_occurrence(request, occurrence):
514-
event_course_relation = EventRelation.objects.filter(event=occurrence.event).first()
515-
membership = Membership.objects.filter(
516-
course_id=event_course_relation.object_id, user=request.user
517-
).first()
518-
return membership
519-
520-
def has_object_permission(self, request, view, obj):
521-
if view.action in ["retrieve"]:
522-
booking = Booking.objects.filter(pk=view.kwargs["pk"]).first()
523-
membership = self.get_membership_from_occurrence(request=request, occurrence=booking.occurrence)
524-
return membership is not None
525-
526-
if view.action in ["update", "partial_update", "destroy"]:
527-
booking = Booking.objects.filter(pk=view.kwargs["pk"]).first()
528-
membership = self.get_membership_from_occurrence(request=request, occurrence=booking.occurrence)
529-
530-
if membership is None:
531-
return False
532-
533-
if membership.is_ta:
534-
return True
535-
536-
return booking.user == request.user
537-
538-
return False
539-
540-
def has_permission(self, request, view):
541-
if not request.user.is_authenticated:
542-
return False
543-
544-
if view.action in ["list", "create"]:
545-
occurrence_id = view.kwargs.get("occurrence_pk")
546-
occurrence = Occurrence.objects.filter(id=occurrence_id).first()
547-
membership = self.get_membership_from_occurrence(request=request, occurrence=occurrence)
548-
return membership is not None
549-
550-
return True

backend/ohq/serializers.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
QueueStatistic,
2222
Semester,
2323
Tag,
24-
Booking,
2524
)
2625
from ohq.sms import sendSMSVerification
2726
from ohq.tasks import sendUpNextNotificationTask
@@ -542,7 +541,7 @@ def update(self, instance, validated_data):
542541
else:
543542
rule, _ = Rule.objects.get_or_create(
544543
frequency=validated_data["rule"]["frequency"],
545-
params=validated_data["rule"].get("params", ""),
544+
params=validated_data["rule"]["params"],
546545
)
547546
validated_data.pop("rule")
548547

@@ -564,7 +563,7 @@ def create(self, validated_data):
564563
course = Course.objects.get(pk=validated_data["course_id"])
565564
rule = None
566565
if "rule" in validated_data and validated_data["rule"] is not None:
567-
rule, _ = Rule.objects.get_or_create(frequency=validated_data["rule"]["frequency"], params = validated_data["rule"].get("params", ""))
566+
rule, _ = Rule.objects.get_or_create(frequency=validated_data["rule"]["frequency"], params = validated_data["rule"]["params"])
568567
validated_data.pop("rule")
569568

570569
validated_data.pop("course_id")
@@ -592,16 +591,4 @@ class OccurrenceSerializer(serializers.ModelSerializer):
592591

593592
class Meta:
594593
model = Occurrence
595-
fields = ("id", "title", "description", "location", "start", "end", "cancelled", "event", "interval")
596-
597-
class BookingSerializer(serializers.ModelSerializer):
598-
"""
599-
Serializer for booking
600-
"""
601-
602-
occurrence = OccurrenceSerializer(read_only=True)
603-
604-
class Meta:
605-
model = Booking
606-
fields = ("id", "occurrence", "user", "start", "end")
607-
594+
fields = ("id", "title", "description", "location", "start", "end", "cancelled", "event")

backend/ohq/urls.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
SemesterViewSet,
2020
TagViewSet,
2121
UserView,
22-
BookingDetailViewSet,
23-
BookingListCreateViewSet,
2422
HealthView,
2523
)
2624

@@ -32,10 +30,6 @@
3230
router.register("courses", CourseViewSet, basename="course")
3331
router.register("events", EventViewSet, basename="event")
3432
router.register("occurrences", OccurrenceViewSet, basename="occurrence")
35-
router.register("bookings", BookingDetailViewSet, basename="booking")
36-
37-
occurrence_router = routers.NestedSimpleRouter(router, "occurrences", lookup="occurrence")
38-
occurrence_router.register("bookings", BookingListCreateViewSet, basename="booking-create")
3933

4034
course_router = routers.NestedSimpleRouter(router, "courses", lookup="course")
4135
course_router.register("queues", QueueViewSet, basename="queue")
@@ -71,4 +65,4 @@
7165
),
7266
]
7367

74-
urlpatterns = router.urls + occurrence_router.urls + course_router.urls + queue_router.urls + additional_urls
68+
urlpatterns = router.urls + course_router.urls + queue_router.urls + additional_urls

backend/ohq/views.py

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
QueueStatistic,
4949
Semester,
5050
Tag,
51-
Booking,
5251
)
5352
from ohq.pagination import QuestionSearchPagination
5453
from ohq.permissions import (
@@ -66,7 +65,6 @@
6665
QueuePermission,
6766
QueueStatisticPermission,
6867
TagPermission,
69-
BookingPermission,
7068
)
7169
from ohq.schemas import EventSchema, MassInviteSchema, OccurrenceSchema
7270
from ohq.serializers import (
@@ -85,7 +83,6 @@
8583
SemesterSerializer,
8684
TagSerializer,
8785
UserPrivateSerializer,
88-
BookingSerializer,
8986
)
9087
from ohq.sms import sendSMSVerification
9188

@@ -746,15 +743,15 @@ class OccurrenceViewSet(
746743
You must specify all of the fields or use a patch request.
747744
748745
partial_update:
749-
Update certain fields in the Occurrence.
746+
Update certain fields in the Occurrece.
750747
"""
751748

752749
serializer_class = OccurrenceSerializer
753750
permission_classes = [OccurrencePermission | IsSuperuser]
754751
schema = OccurrenceSchema()
755752

756753
def list(self, request, *args, **kwargs):
757-
# ensure timezone consistency
754+
# ensure timezone consitency
758755
course_ids = request.GET.getlist("course")
759756
filter_start = datetime.strptime(
760757
request.GET.get("filter_start"), "%Y-%m-%dT%H:%M:%SZ"
@@ -780,60 +777,6 @@ def list(self, request, *args, **kwargs):
780777

781778
def get_queryset(self):
782779
return Occurrence.objects.filter(pk=self.kwargs["pk"])
783-
784-
class BookingDetailViewSet(
785-
mixins.RetrieveModelMixin,
786-
mixins.UpdateModelMixin,
787-
mixins.DestroyModelMixin,
788-
viewsets.GenericViewSet,
789-
):
790-
"""
791-
retrieve:
792-
Return a single booking.
793-
794-
update:
795-
Update all fields in the booking.
796-
You must specify all of the fields or use a patch request.
797-
798-
partial_update:
799-
Update certain fields in the booking.
800-
Only specify the fields that you want to change.
801-
802-
destroy:
803-
Delete a booking.
804-
"""
805-
806-
serializer_class = BookingSerializer
807-
permission_classes = [BookingPermission | IsSuperuser]
808-
809-
def get_queryset(self):
810-
return Booking.objects.filter(pk=self.kwargs["pk"])
811-
812-
class BookingListCreateViewSet(
813-
mixins.ListModelMixin,
814-
mixins.CreateModelMixin,
815-
viewsets.GenericViewSet,
816-
):
817-
"""
818-
list:
819-
Return a list of bookings for a specific occurrence.
820-
821-
create:
822-
Create a booking for a specific occurrence.
823-
"""
824-
825-
serializer_class = BookingSerializer
826-
permission_classes = [BookingPermission | IsSuperuser]
827-
828-
def get_queryset(self):
829-
occurrence_id = self.kwargs.get("occurrence_pk")
830-
return Booking.objects.filter(occurrence=occurrence_id).order_by("start")
831-
832-
def perform_create(self, serializer):
833-
occurrence_id = self.kwargs.get("occurrence_pk")
834-
occurrence = Occurrence.objects.get(pk=occurrence_id)
835-
serializer.save(occurrence=occurrence, user=self.request.user)
836-
837780
class HealthView(View):
838781
def get(self, request):
839782
"""
@@ -852,4 +795,4 @@ def get(self, request):
852795
enum: ["OK"]
853796
---
854797
"""
855-
return JsonResponse({"message": "OK"}, status=HTTPStatus.OK)
798+
return JsonResponse({"message": "OK"}, status=HTTPStatus.OK)

0 commit comments

Comments
 (0)