Skip to content

Commit

Permalink
Unset primary schedule, fix PCx docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mureytasroc committed Oct 26, 2023
1 parent 40563b6 commit 6be84c2
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 87 deletions.
5 changes: 4 additions & 1 deletion backend/PennCourses/docs_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,10 @@


def get_url_by_name(name):
path = get_resolver().reverse_dict[name][0][0][0]
reverse = get_resolver().reverse_dict
if name not in reverse:
raise ValueError(f"Tried to get URL by name '{reverse}', but no such URL exists.")
path = reverse[name][0][0][0]
path = path.replace(r"%(pk)s", r"{id}")
return "/" + re.sub(r"%\(([^)]+)\)s", r"{\1}", path)

Expand Down
2 changes: 1 addition & 1 deletion backend/plan/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ class PrimaryScheduleSerializer(serializers.ModelSerializer):

class Meta:
model = PrimarySchedule
fields = ["user", "user_id", "schedule_id", "schedule"]
fields = ["user", "schedule"]
76 changes: 53 additions & 23 deletions backend/plan/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,53 +190,83 @@ class PrimaryScheduleViewSet(viewsets.ModelViewSet):
list: Get the primary schedule for the current user as well as primary
schedules of the user's friends.
update: Create or update the primary schedule for the current user.
create: Create/update/delete the primary schedule for the current user.
"""

model = PrimarySchedule
queryset = PrimarySchedule.objects.none()
http_method_names = ["get", "put"]
http_method_names = ["get", "post"]
permission_classes = [IsAuthenticated]
serializer_class = PrimaryScheduleSerializer

def get_queryset(self):
return PrimarySchedule.objects.filter(
Q(user=self.request.user)
| Q(user_id__in=Subquery(get_accepted_friends(self.request.user).values("id")))
).prefetch_related(
Prefetch("schedule__sections", Section.with_reviews.all()),
"schedule__sections__associated_sections",
"schedule__sections__instructors",
"schedule__sections__meetings",
"schedule__sections__meetings__room",
)

schema = PcxAutoSchema(
response_codes={
"primary-schedule": {
"primary-schedules-list": {
"GET": {
200: "Primary schedule (and friend's schedules) retrieved successfully.",
200: "[DESCRIBE_RESPONSE_SCHEMA]Primary schedule (and friend's schedules) "
"retrieved successfully.",
},
"PUT": {
200: "Primary schedule updated successfully.",
"POST": {
201: "Primary schedule updated successfully.",
400: "Invalid schedule in request.",
},
},
}
},
override_request_schema={
"primary-schedules-list": {
"POST": {
"type": "object",
"properties": {
"schedule_id": {
"type": "integer",
"description": (
"The ID of the schedule you want to make primary "
"(or null to unset)."
),
},
},
}
}
},
)

def put(self, request):
def create(self, request):
res = {}
user = request.user
schedule = Schedule.objects.filter(
person_id=user.id, id=request.data.get("schedule_id")
).first()
if not schedule:
res["message"] = "Schedule does not exist"
return JsonResponse(res, status=status.HTTP_400_BAD_REQUEST)

primary_schedule_entry = self.get_queryset().filter(user=user).first()
if primary_schedule_entry:
primary_schedule_entry.schedule = schedule
primary_schedule_entry.save()
res["message"] = "Primary schedule successfully updated"
schedule_id = request.data.get("schedule_id")
if not schedule_id:
# Delete primary schedule
primary_schedule_entry = self.get_queryset().filter(user=user).first()
if primary_schedule_entry:
primary_schedule_entry.delete()
res["message"] = "Primary schedule successfully unset"
res["message"] = "Primary schedule was already unset"
else:
PrimarySchedule.objects.create(user=user, schedule=schedule)
res["message"] = "Primary schedule successfully created"
schedule = Schedule.objects.filter(person_id=user.id, id=schedule_id).first()
if not schedule:
res["message"] = "Schedule does not exist"
return JsonResponse(res, status=status.HTTP_400_BAD_REQUEST)

primary_schedule_entry = self.get_queryset().filter(user=user).first()
if primary_schedule_entry:
primary_schedule_entry.schedule = schedule
primary_schedule_entry.save()
res["message"] = "Primary schedule successfully updated"
else:
PrimarySchedule.objects.create(user=user, schedule=schedule)
res["message"] = "Primary schedule successfully created"

return JsonResponse(res, status=status.HTTP_200_OK)

Expand Down Expand Up @@ -367,7 +397,7 @@ def check_semester(data, sections):
)

def update(self, request, pk=None):
if not Schedule.objects.filter(id=pk).exists():
if not pk or not Schedule.objects.filter(id=pk).exists():
return Response({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND)
try:
schedule = self.get_queryset().get(id=pk)
Expand Down
86 changes: 55 additions & 31 deletions backend/tests/plan/test_primary_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from rest_framework.test import APIClient

from courses.models import Friendship
from plan.models import Schedule
from plan.models import PrimarySchedule, Schedule
from tests.alert.test_alert import TEST_SEMESTER, set_semester
from tests.courses.util import create_mock_data_with_reviews

Expand Down Expand Up @@ -39,31 +39,60 @@ def setUp(self):
self.s2.save()
self.s2.sections.set([self.cis121])

to_delete = Schedule(
person=self.u1,
semester=TEST_SEMESTER,
name="My Test Schedule To Delete",
)
to_delete.save()
self.deleted_schedule_id = to_delete.id
to_delete.delete()

self.client = APIClient()
self.client.login(username="jacobily", password="top_secret")

def test_put_primary_schedule(self):
response = self.client.put(primary_schedule_url, {"schedule_id": self.s.id})
def assert_primary_schedule_id(self, client, user, schedule_id, num_primary=None):
if schedule_id is None:
self.assertEqual(PrimarySchedule.objects.filter(user=user).count(), 0)
else:
self.assertEqual(PrimarySchedule.objects.get(user=user).schedule_id, schedule_id)
response = client.get(primary_schedule_url)
self.assertEqual(response.status_code, 200)
# self.assertEqual(response.json()["id"], self.s.id)
# self.assertEqual(response.json()["name"], self.s.name)
# self.assertEqual(response.json()["sections"][0]["id"], self.cis120.id)
# self.assertEqual(response.json()["sections"][0]["course"]["id"], self.cis120.course.id)
if num_primary is not None:
self.assertEqual(len(response.json()), num_primary)
if schedule_id is not None:
self.assertIn(schedule_id, [p["schedule"]["id"] for p in response.json()])

def test_post_primary_schedule(self):
response = self.client.post(primary_schedule_url, {"schedule_id": self.s.id})
self.assertEqual(response.status_code, 200)
self.assert_primary_schedule_id(self.client, self.u1, self.s.id, num_primary=1)

def test_invalid_schedule_id(self):
response = self.client.post(primary_schedule_url, {"schedule_id": self.deleted_schedule_id})
self.assertEqual(response.status_code, 400)
self.assert_primary_schedule_id(self.client, self.u1, None, num_primary=0)

def test_replace_primary_schedule(self):
response = self.client.put(primary_schedule_url, {"schedule_id": 123}) # invalid ID
# self.assertEqual(response.status_code, 200) # todo: should be 400
response = self.client.post(primary_schedule_url, {"schedule_id": self.s.id})
self.assertEqual(response.status_code, 200)
self.assert_primary_schedule_id(self.client, self.u1, self.s.id, num_primary=1)

response = self.client.put(primary_schedule_url, {"schedule_id": self.s.id})
response = self.client.post(primary_schedule_url, {"schedule_id": self.s2.id})
self.assertEqual(response.status_code, 200)
# self.assertEqual(response.data["id"], self.s.id)
self.assert_primary_schedule_id(self.client, self.u1, self.s2.id, num_primary=1)

response = self.client.put(primary_schedule_url, {"schedule_id": self.s2.id})
def test_unset_primary_schedule(self):
response = self.client.post(primary_schedule_url, {"schedule_id": self.s.id})
self.assertEqual(response.status_code, 200)
# self.assertEqual(response.data["id"], self.s2.id)
self.assert_primary_schedule_id(self.client, self.u1, self.s.id, num_primary=1)

response = self.client.post(primary_schedule_url, {"schedule_id": ""})
self.assertEqual(response.status_code, 200)
self.assert_primary_schedule_id(self.client, self.u1, None, num_primary=0)

def test_primary_schedule_friends(self):
response = self.client.put(primary_schedule_url, {"schedule_id": self.s.id})
response = self.client.post(primary_schedule_url, {"schedule_id": self.s.id})

u2 = User.objects.create_user(
username="jacob2", email="[email protected]", password="top_secret"
Expand All @@ -84,16 +113,15 @@ def test_primary_schedule_friends(self):
)
u2_s.save()
u2_s.sections.set([self.cis120])
response = self.client2.put(primary_schedule_url, {"schedule_id": u2_s.id})
# self.assertEqual(response.status_code, 200)
# self.assertEqual(response.data["id"], u2_s.id)
response = self.client2.post(primary_schedule_url, {"schedule_id": u2_s.id})
self.assertEqual(response.status_code, 200)
self.assert_primary_schedule_id(self.client2, u2, u2_s.id, num_primary=2)

response = self.client.get(primary_schedule_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 2)
# print("1", response.json())
# self.assertEqual(response.data[0]["id"], self.s.id)
# self.assertEqual(response.data[1]["id"], u2_s.id)
self.assertIn(self.s.id, [p["schedule"]["id"] for p in response.json()])
self.assertIn(u2_s.id, [p["schedule"]["id"] for p in response.json()])

Friendship.objects.create(sender=self.u1, recipient=u3, status=Friendship.Status.ACCEPTED)
u3_s = Schedule(
Expand All @@ -110,22 +138,18 @@ def test_primary_schedule_friends(self):
self.assertEqual(len(response.json()), 2)

# add a primary schedule for u3
response = self.client3.put(primary_schedule_url, {"schedule_id": u3_s.id})
response = self.client3.post(primary_schedule_url, {"schedule_id": u3_s.id})
self.assertEqual(response.status_code, 200)
# self.assertEqual(response.data["id"], u3_s.id)
self.assert_primary_schedule_id(self.client3, u3, u3_s.id, num_primary=2)

# should have all 3 now
response = self.client.get(primary_schedule_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 3)
# u1 should have all 3 now
self.assert_primary_schedule_id(self.client, self.u1, self.s.id, num_primary=3)

# remove u2 as a friend
friendshipu2 = Friendship.objects.get(sender=self.u1, recipient=u2)
friendshipu2.delete()

# only have u1 and u3 now
response = self.client.get(primary_schedule_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 2)
# self.assertEqual(response.data[0]["id"], self.s.id)
# self.assertEqual(response.data[1]["id"], u3_s.id)
self.assert_primary_schedule_id(self.client, self.u1, self.s.id, num_primary=2)
self.assert_primary_schedule_id(self.client2, u2, u2_s.id, num_primary=1)
self.assert_primary_schedule_id(self.client3, u3, u3_s.id, num_primary=2)
12 changes: 4 additions & 8 deletions frontend/plan/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -677,13 +677,9 @@ export const findOwnPrimarySchedule = (user) => (dispatch) => {
);
})
.then((foundSched) => {
if (foundSched) {
dispatch(
setPrimaryScheduleIdOnFrontend(foundSched.schedule_id)
);
} else {
dispatch(setPrimaryScheduleIdOnFrontend("-1"));
}
dispatch(
setPrimaryScheduleIdOnFrontend(foundSched?.schedule.id)
);
})
.catch((error) => {
console.log(error);
Expand All @@ -698,7 +694,7 @@ export const setCurrentUserPrimarySchedule = (user, scheduleId) => (
schedule_id: scheduleId,
};
const init = {
method: "PUT",
method: "POST",
credentials: "include",
mode: "same-origin",
headers: {
Expand Down
5 changes: 2 additions & 3 deletions frontend/plan/components/schedule/Schedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,12 @@ interface ScheduleProps {
) => void;
};
schedulesMutator: {
setPrimary: (user: User, scheduleId: string) => void;
setPrimary: (user: User, scheduleId: string | null) => void;
copy: (scheduleName: string) => void;
download: (scheduleName: string) => void;
remove: (user: User, scheduleName: string, scheduleId: string) => void;
rename: (oldName: string) => void;

// NOT IN ORIGINAL PROPS
createSchedule: () => void;
addFriend: () => void;
showRequests: () => void;
Expand Down Expand Up @@ -162,7 +161,7 @@ const mapDispatchToProps = (dispatch: ThunkDispatch<any, any, any>) => ({
),
},
schedulesMutator: {
setPrimary: (user: User, scheduleId: string) =>
setPrimary: (user: User, scheduleId: string | null) =>
dispatch(setCurrentUserPrimarySchedule(user, scheduleId)),
copy: (scheduleName: string) =>
dispatch(createScheduleOnBackend(scheduleName)),
Expand Down
Loading

0 comments on commit 6be84c2

Please sign in to comment.