Source code for searches.views

# Copyright (C) 2017 Semester.ly Technologies, LLC
#
# Semester.ly is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Semester.ly is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.


import operator

from django.core.paginator import Paginator, EmptyPage
from django.apps import apps
from django.db.models import Q

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from analytics.views import save_analytics_course_search
from courses.serializers import CourseSerializer
from searches.utils import baseline_search
from student.models import Student
from student.utils import get_student
from timetable.models import Semester
from helpers.mixins import ValidateSubdomainMixin, CsrfExemptMixin


[docs]class CourseSearchList(CsrfExemptMixin, ValidateSubdomainMixin, APIView): """Course Search List."""
[docs] def get(self, request, query, sem_name, year): """ Return vectorized search results. """ school = request.subdomain sem = Semester.objects.get_or_create(name=sem_name, year=year)[0] # TODO: use vectorized search after completion. # Use vectorized_search if and only if a valid Searcher object is created, otherwise use baseline_search # if apps.get_app_config('searches').searcher: # course_match_objs = apps.get_app_config('searches').searcher.vectorized_search(request.subdomain, query, sem)[:4] # else: # course_match_objs = baseline_search(request.subdomain, query, sem)[:4] course_match_objs = baseline_search(request.subdomain, query, sem).distinct()[:4] save_analytics_course_search(query[:200], course_match_objs[:2], sem, request.subdomain, get_student(request)) course_matches = [CourseSerializer(course, context={'semester': sem, 'school': school}).data for course in course_match_objs] return Response(course_matches, status=status.HTTP_200_OK)
[docs] def post(self, request, query, sem_name, year): """ Return advanced search results. """ school = request.subdomain page = int(request.query_params.get('page', 1)) sem, _ = Semester.objects.get_or_create(name=sem_name, year=year) # Filter first by the user's search query. # TODO : use vectorized search (change returned obj to be filterable) course_match_objs = baseline_search(school, query, sem) # Filter now by departments, areas, levels, or times if provided. filters = request.data.get('filters', {}) if filters.get('areas'): course_match_objs = course_match_objs.filter(areas__in=filters.get('areas')) if filters.get('departments'): course_match_objs = course_match_objs.filter(department__in=filters.get('departments')) if filters.get('levels'): course_match_objs = course_match_objs.filter(level__in=filters.get('levels')) if filters.get('times'): day_map = {"Monday": "M", "Tuesday": "T", "Wednesday": "W", "Thursday": "R", "Friday": "F"} course_match_objs = course_match_objs.filter( reduce(operator.or_, (Q(section__offering__time_start__gte="{0:0=2d}:00".format(min_max['min']), section__offering__time_end__lte="{0:0=2d}:00".format(min_max['max']), section__offering__day=day_map[min_max['day']], section__semester=sem, section__section_type="L") for min_max in filters.get('times')) ) ) try: paginator = Paginator(course_match_objs.distinct(), 20) course_match_objs = paginator.page(page) except EmptyPage: return Response([]) save_analytics_course_search(query[:200], course_match_objs[:2], sem, school, get_student(request), advanced=True) student = None logged = request.user.is_authenticated() if logged and Student.objects.filter(user=request.user).exists(): student = Student.objects.get(user=request.user) serializer_context = {'semester': sem, 'student': student, 'school': request.subdomain} json_data = [CourseSerializer(course, context=serializer_context).data for course in course_match_objs] return Response(json_data, status=status.HTTP_200_OK)