Skip to content

Commit

Permalink
Finish Initial Testing Suite
Browse files Browse the repository at this point in the history
  • Loading branch information
shiva-menta committed Apr 25, 2024
1 parent 0fafac2 commit 3cbf128
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 47 deletions.
39 changes: 39 additions & 0 deletions backend/courses/migrations/0065_auto_20240424_2243.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 3.2.23 on 2024-04-25 02:43

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('courses', '0064_auto_20240120_1914'),
]

operations = [
migrations.RemoveField(
model_name='comment',
name='course',
),
migrations.RemoveField(
model_name='comment',
name='likes',
),
migrations.AddField(
model_name='comment',
name='downvotes',
field=models.ManyToManyField(help_text='The number of downvotes a comment gets.', related_name='downvotes', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='comment',
name='section',
field=models.ForeignKey(default=None, help_text='\nThe section with which a comment is associated. Section was chosen instead of courses\nfor hosting topics to support lower levels of filtering.\n', on_delete=django.db.models.deletion.CASCADE, to='courses.section'),
),
migrations.AddField(
model_name='comment',
name='upvotes',
field=models.ManyToManyField(help_text='The number of upvotes a comment gets.', related_name='upvotes', to=settings.AUTH_USER_MODEL),
),
]
3 changes: 3 additions & 0 deletions backend/courses/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1510,15 +1510,18 @@ class Comment(models.Model):
)
upvotes = models.ManyToManyField(
get_user_model(),
related_name="upvotes",
help_text="The number of upvotes a comment gets."
)
downvotes = models.ManyToManyField(
get_user_model(),
related_name="downvotes",
help_text="The number of downvotes a comment gets."
)
section = models.ForeignKey(
Section,
on_delete=models.CASCADE,
default=None,
help_text=dedent(
"""
The section with which a comment is associated. Section was chosen instead of courses
Expand Down
19 changes: 15 additions & 4 deletions backend/courses/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import connection
from django.db.models import Q
from django.db.models.aggregates import Count
from django.db.models.expressions import Subquery, Value
from django.db.models.functions.comparison import Coalesce
Expand Down Expand Up @@ -713,12 +714,22 @@ def get_semesters(semesters: str = None) -> list[str]:
raise ValueError(f"Provided semester {s} was not found in the db.")
return sorted(semesters)

def get_section_from_course_professor_semester(course_code, professor, semester):
def get_section_from_course_professor_semester(course_code, professors, semester):
"""
Attempts to return a course section that matches the given parameters.
ValueError is raised if the section does not exist.
"""
# a section has multiple professors
section = Section.objects.annotate("course__full_code").filter(course__full_code=course_code, ).order_by("code").first()
return None
sections = Section.objects.prefetch_related('instructors').filter(
course__full_code=course_code,
course__semester=semester
)

professors_query = Q(instructors__username=professors[0])
for professor in professors[1:]:
professors_query &= Q(instructors__username=professor)
matching_sections = sections.filter(professors_query).distinct()

if matching_sections.count() == 1:
return matching_sections.first()
raise ValueError(f"No section exists with course code ({course_code}), professor ({professor}), semester ({semester})")

14 changes: 10 additions & 4 deletions backend/review/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
instructor_for_course_reviews,
instructor_reviews,
CommentList,
CommentViewSet
CommentViewSet,
handle_vote
)


Expand Down Expand Up @@ -45,13 +46,18 @@
),
path("autocomplete", cache_page(MONTH_IN_SECONDS)(autocomplete), name="review-autocomplete"),
path(
"course_comments/<slug:course_code>",
"<slug:semester>/course_comments/<slug:course_code>",
cache_page(DAY_IN_SECONDS)(CommentList),
name="course-comments"
),
path(
"comments",
"comments/votes/",
handle_vote,
name="comment-votes"
),
path(
"comment",
cache_page(DAY_IN_SECONDS)(CommentViewSet),
name="course-comments"
name="comment"
)
]
39 changes: 27 additions & 12 deletions backend/review/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
Section,
Comment
)
from courses.util import get_current_semester, get_or_create_add_drop_period, prettify_semester
from courses.util import get_current_semester, get_or_create_add_drop_period, prettify_semester, get_section_from_course_professor_semester
from PennCourses.docs_settings import PcxAutoSchema
from PennCourses.settings.base import TIME_ZONE, WAITLIST_DEPARTMENT_CODES
from review.annotations import annotate_average_and_recent, review_averages
Expand Down Expand Up @@ -828,7 +828,9 @@ class CommentList(generics.ListAPIView):
"""
Retrieve a list of all comments for the provided course.
"""

# this needs to be annotated with the users likes
# this also needs to support pagination (query params)
# this also needs to support filtering (query params)
schema = PcxAutoSchema(
response_codes={
"review-coursecomments": {
Expand Down Expand Up @@ -925,30 +927,25 @@ class CommentViewSet(viewsets.ModelViewSet):

serializer_class = CommentSerializer
http_method_names = ["get", "post", "delete", "put"]
# permission_classes = [IsAuthenticated]
permission_classes = [IsAuthenticated]
queryset = Comment.objects.all()

def retrieve(self, request, pk=None):
comment = get_object_or_404(Comment, pk=pk)
return Response(comment, status=status.HTTP_200_SUCCESS)

# we are going to require professor and semseter to be specified, then derive the section from that
def create(self, request):
if Comment.objects.filter(id=request.data.get("id")).exists():
return self.update(request, request.data.get("id"))

if not all(["text", "user", "course_code", "professor", "semester"], lambda x: x in request.data):
if not all(["text", "course_code", "professor", "semester"], lambda x: x in request.data):
return Response(
{"message": "Insufficient fields presented."}, status=status.HTTP_400_BAD_REQUEST
)

# we want to derive section from professor and semester
def get_section_from_course_professor_semester(course_code, professor, semester):
pass

try:
section = get_section_from_course_professor_semester(request.data.get("course_code"), request.data.get("professor"), request.data.get("semester"))
except Section.DoesNotExist:
except Exception:
return Response(
{"message": "Insufficient fields presented."}, status=status.HTTP_400_BAD_REQUEST
)
Expand All @@ -966,7 +963,7 @@ def update(self, request, pk=None):

if request.user != comment.user:
return Response(
{"message": "Not authorized to modify this comment.."}, status=status.HTTP_403_FORBIDDEN
{"message": "Not authorized to modify this comment."}, status=status.HTTP_403_FORBIDDEN
)

if "text" in request.data:
Expand All @@ -987,4 +984,22 @@ def destroy(self, request, pk=None):

comment.delete()
return Response({"message": "Successfully deleted."}, status=status.HTTP_204_NO_CONTENT)


def handle_vote(request):
"""
Handles an incoming request that changes the vote of a comment.
"""
if not all(["id", "vote_type"], lambda x: x in request.data):
return Response(
{"message": "Insufficient fields presented."}, status=status.HTTP_400_BAD_REQUEST
)

user = request.user
comment = get_object_or_404(Comment, request.data.get("id"))
vote_type = request.data.get("vote_type")
if vote_type == "upvote":
comment.downvotes.remove(user)
comment.upvotes.add(user)
if vote_type == "downvote":
comment.upvotes.remove(user)
comment.downvotes.add(user)
Loading

0 comments on commit 3cbf128

Please sign in to comment.