def post(self, request): """Generate best timetables given the user's selected courses""" school = request.subdomain params = request.data student = get_student(request) course_ids = list(params["courseSections"].keys()) courses = [Course.objects.get(id=cid) for cid in course_ids] locked_sections = params["courseSections"] self.set_params_semester(params) save_analytics_timetable(courses, params["semester"], school, get_student(request)) self.update_courses_and_locked_sections(params, course_ids, courses, locked_sections) opt_course_ids = params.get("optionCourses", []) max_optional = params.get("numOptionCourses", len(opt_course_ids)) optional_courses = [ Course.objects.get(id=cid) for cid in opt_course_ids ] optional_course_subsets = [ subset for subset_size in range(max_optional, -1, -1) for subset in itertools.combinations(optional_courses, subset_size) ] custom_events = params.get("customSlots", []) preferences = params["preferences"] with_conflicts = preferences.get("try_with_conflicts", False) sort_metrics = [(m["metric"], m["order"]) for m in preferences.get("sort_metrics", []) if m["selected"]] timetables = [ timetable for opt_courses in optional_course_subsets for timetable in courses_to_timetables( courses + list(opt_courses), locked_sections, params["semester"], sort_metrics, params["school"], custom_events, with_conflicts, opt_course_ids, ) ] context = self.create_context(request, params, student) courses = list(courses + optional_courses) response = self.create_response(courses, locked_sections, timetables, context) return Response(response, status=status.HTTP_200_OK)
def post(self, request): """ Creates a :obj:`SharedTimetable` and returns the hashed database id as the slug for the url which students then share and access. """ school = request.subdomain timetable = request.data['timetable'] has_conflict = timetable.get('has_conflict', False) semester, _ = Semester.objects.get_or_create(**request.data['semester']) student = get_student(request) shared_timetable = SharedTimetable.objects.create( student=student, school=school, semester=semester, has_conflict=has_conflict) shared_timetable.save() added_courses = set() for slot in timetable['slots']: course_id, section_id = slot['course'], slot['section'] if course_id not in added_courses: course_obj = Course.objects.get(id=course_id) shared_timetable.courses.add(course_obj) added_courses.add(course_id) section_obj = Section.objects.get(id=section_id) shared_timetable.sections.add(section_obj) if section_obj.course.id not in added_courses: return Response(status=status.HTTP_400_BAD_REQUEST) shared_timetable.save() response = {'slug': hashids.encrypt(shared_timetable.id)} return Response(response, status=status.HTTP_200_OK)
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] # sorts queries by course number through a comparator def course_comparator(course1, course2): #isolate course number from XX0000 c1=int(str(course1)[2:6]) c2=int(str(course2)[2:6]) if c1 < c2: return -1 elif c1 > c2: return 1 else: return 0 course_match_objs = baseline_search(request.subdomain, query, sem).distinct() #only sort if results is less than 100 for efficiency sake if len(course_match_objs) < 100: course_match_objs = sorted(course_match_objs, key=cmp_to_key(course_comparator)) #display only 12 courses to avoid displaying too many. course_match_objs = course_match_objs[:12] 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)
def student_info(request): if request.method == 'POST': return redirect('pilot:pilotcourses') else: student = get_student(request) context = {'student': student} return render(request, 'pilot/student_info.html/', context=context)
def meetings(request, courseList): student = get_student(request) semester = Semester.objects.filter(name='Spring', year='2020') course_list = courseList.split("_") if request.method == 'POST': sections = "" for course in course_list: section = request.POST.getlist(course) sections += str(section[0]) + "_" sections = sections[0:-1] return redirect('pilot:offerings', sectionList=sections) else: decoded_list = {} for course in course_list: course_decode = Course.objects.get(id=int(course)) sections = list( Section.objects.filter(course=course_decode, semester=semester)) sections_offerings = {} for section in sections: offerings = list( PilotOffering.objects.filter(sections=section)) sections_offerings[section] = offerings decoded_list[course_decode] = sections_offerings context = { 'courses': decoded_list, 'courseList': courseList, 'student': student, 'id': student.id } return render(request, 'pilot/meetings.html/', context=context)
def get_feature_flow(self, request, slug): """ Overrides :obj:`FeatureFlowView` *get_feature_flow* method. Takes the slug, decrypts the hashed database id, and either retrieves the corresponding timetable or hits a 404. """ timetable_id = hashids.decrypt(slug)[0] shared_timetable = get_object_or_404(SharedTimetable, id=timetable_id, school=request.subdomain) context = { "semester": shared_timetable.semester, "school": request.subdomain, "student": get_student(request), } return { "semester": shared_timetable.semester, "courses": CourseSerializer(shared_timetable.courses, context=context, many=True).data, "sharedTimetable": DisplayTimetableSerializer.from_model(shared_timetable).data, }
def post(self, request): new_link = FinalExamShare.objects.create(school=request.subdomain, student=get_student(request), exam_json=request.data) new_link.save() response = {'slug': hashids.encrypt(new_link.id)} return Response(response, status.HTTP_200_OK)
def save_analytic(self, request, query, course_matches, sem, advanced=False): save_analytics_course_search( query[:200], course_matches[:2], sem, request.subdomain, get_student(request), advanced, )
def post(self, request): new_link = FinalExamShare.objects.create( school=request.subdomain, student=get_student(request), exam_json=request.data ) new_link.save() response = {'slug': hashids.encrypt(new_link.id)} return Response(response, status.HTTP_200_OK)
def get(self, request, *args, **kwargs): if not self.allow_unauthenticated and not request.user.is_authenticated: return HttpResponseRedirect("/") self.school = request.subdomain self.student = get_student(request) feature_flow = self.get_feature_flow(request, *args, **kwargs) # take semester provided by feature flow if available, otherwise the first available sem all_semesters = get_current_semesters(self.school) if "semester" in feature_flow: sem = feature_flow.pop("semester") sem_dict = {"name": sem.name, "year": sem.year} if sem_dict not in all_semesters: all_semesters.append(sem_dict) curr_sem_index = all_semesters.index(sem_dict) else: curr_sem_index = 0 sem = Semester.objects.get(**all_semesters[curr_sem_index]) integrations = [] if self.student and self.student.user.is_authenticated: self.student.school = self.school self.student.save() for i in self.student.integrations.all(): integrations.append(i.name) final_exams = [] if SCHOOLS_MAP[self.school].final_exams is None: final_exams = [] else: for year, terms in SCHOOLS_MAP[self.school].final_exams.items(): for term in terms: final_exams.append({"name": term, "year": str(year)}) init_data = { "school": self.school, "currentUser": get_student_dict(self.school, self.student, sem), "currentSemester": curr_sem_index, "allSemesters": all_semesters, # 'oldSemesters': get_old_semesters(self.school), "uses12HrTime": SCHOOLS_MAP[self.school].ampm, "studentIntegrations": integrations, "latestAgreement": AgreementSerializer(Agreement.objects.latest()).data, "registrar": SCHOOLS_MAP[self.school].registrar, "examSupportedSemesters": list(map(all_semesters.index, final_exams)), "timeUpdatedTos": Agreement.objects.latest().last_updated.isoformat(), "featureFlow": dict(feature_flow, name=self.feature_name), } return render(request, "timetable.html", {"init_data": json.dumps(init_data)})
def get(self, request, *args, **kwargs): if not self.allow_unauthenticated and not request.user.is_authenticated: return HttpResponseRedirect('/') self.school = request.subdomain self.student = get_student(request) feature_flow = self.get_feature_flow(request, *args, **kwargs) # take semester provided by feature flow if available, otherwise the first available sem all_semesters = get_current_semesters(self.school) if 'semester' in feature_flow: sem = feature_flow.pop('semester') sem_dict = {'name': sem.name, 'year': sem.year} if sem_dict not in all_semesters: all_semesters.append(sem_dict) curr_sem_index = all_semesters.index(sem_dict) else: curr_sem_index = 0 sem = Semester.objects.get(**all_semesters[curr_sem_index]) integrations = [] if self.student and self.student.user.is_authenticated: self.student.school = self.school self.student.save() for i in self.student.integrations.all(): integrations.append(i.name) final_exams = [] if SCHOOLS_MAP[self.school].final_exams is None: final_exams = [] else: for year, terms in SCHOOLS_MAP[self.school].final_exams.items(): for term in terms: final_exams.append({'name': term, 'year': str(year)}) init_data = { 'school': self.school, 'currentUser': get_student_dict(self.school, self.student, sem), 'currentSemester': curr_sem_index, 'allSemesters': all_semesters, # 'oldSemesters': get_old_semesters(self.school), 'uses12HrTime': SCHOOLS_MAP[self.school].ampm, 'studentIntegrations': integrations, 'latestAgreement': AgreementSerializer(Agreement.objects.latest()).data, 'registrar': SCHOOLS_MAP[self.school].registrar, 'examSupportedSemesters': list(map(all_semesters.index, final_exams)), 'timeUpdatedTos': Agreement.objects.latest().last_updated.isoformat(), 'featureFlow': dict(feature_flow, name=self.feature_name) } return render(request, 'timetable.html', {'init_data': json.dumps(init_data)})
def get(self, request, *args, **kwargs): self.school = request.subdomain self.student = get_student(request) feature_flow = self.get_feature_flow(request, *args, **kwargs) # take semester provided by feature flow if available, otherwise the first available sem all_semesters = get_current_semesters(self.school) if 'semester' in feature_flow: sem = feature_flow.pop('semester') sem_dict = {'name': sem.name, 'year': sem.year} if sem_dict not in all_semesters: all_semesters.append(sem_dict) curr_sem_index = all_semesters.index(sem_dict) else: curr_sem_index = 0 sem = Semester.objects.get(**all_semesters[curr_sem_index]) integrations = [] if self.student and self.student.user.is_authenticated(): self.student.school = self.school self.student.save() for i in self.student.integrations.all(): integrations.append(i.name) final_exams = [] if SCHOOLS_MAP[self.school].final_exams is None: final_exams = [] else: for year, terms in SCHOOLS_MAP[self.school].final_exams.items(): for term in terms: final_exams.append({ 'name': term, 'year': str(year) }) init_data = { 'school': self.school, 'currentUser': get_student_dict(self.school, self.student, sem), 'currentSemester': curr_sem_index, 'allSemesters': all_semesters, # 'oldSemesters': get_old_semesters(self.school), 'uses12HrTime': SCHOOLS_MAP[self.school].ampm, 'studentIntegrations': integrations, 'examSupportedSemesters': map(all_semesters.index, final_exams), 'timeUpdatedTos': Agreement.objects.latest().last_updated.isoformat(), 'featureFlow': dict(feature_flow, name=self.feature_name) } return render(request, 'timetable.html', {'init_data': json.dumps(init_data)})
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__contains=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')) ) ) course_match_objs = course_match_objs.order_by('id') 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)
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)
def pilotcourses(request): student = get_student(request) if request.method == 'POST': course_list = request.POST.getlist('course_list') courses_selected = "" for course in course_list: courses_selected += str(course) + "_" courses_selected = courses_selected[0:-1] return redirect('pilot:meetings', courseList=courses_selected) else: COURSE_LIST = [] for courseint in CourseIntegration.objects.filter(integration_id=3): if Course.objects.filter(id=courseint.course_id).exists(): COURSE_LIST.append(Course.objects.get(id=courseint.course_id)) context = {'courses': COURSE_LIST, 'student': student} return render(request, 'pilot/courses.html/', context=context)
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)
def put(self, request): """ Creates a notification token for the user. """ token = request.data school = request.subdomain student = get_student(request) token, _ = RegistrationToken.objects.update_or_create(auth=token['auth'], p256dh=token['p256dh'], endpoint=token['endpoint']) if student: token.student = student token.save() student.school = school student.save() return Response(model_to_dict(token), status=status.HTTP_201_CREATED)
def get_feature_flow(self, request, slug): """ Overrides :obj:`FeatureFlowView` *get_feature_flow* method. Takes the slug, decrypts the hashed database id, and either retrieves the corresponding timetable or hits a 404. """ timetable_id = hashids.decrypt(slug)[0] shared_timetable = get_object_or_404(SharedTimetable, id=timetable_id, school=request.subdomain) context = {'semester': shared_timetable.semester, 'school': request.subdomain, 'student': get_student(request)} return { 'semester': shared_timetable.semester, 'courses': CourseSerializer(shared_timetable.courses, context=context, many=True).data, 'sharedTimetable': DisplayTimetableSerializer.from_model(shared_timetable).data }
def put(self, request): """ Creates a notification token for the user. """ token = request.data school = request.subdomain student = get_student(request) token, _ = RegistrationToken.objects.update_or_create( auth=token['auth'], p256dh=token['p256dh'], endpoint=token['endpoint']) if student: token.student = student token.save() student.school = school student.save() return Response(model_to_dict(token), status=status.HTTP_201_CREATED)
def post(self, request, query, sem_name, year): """Return advanced search results.""" school = request.subdomain sem, _ = Semester.objects.get_or_create(name=sem_name, year=year) filters = request.data.get("filters", {}) course_matches = search(school, query, sem) course_matches = self.filter_course_matches(course_matches, filters, sem) course_matches = course_matches.distinct()[:100] # prevent timeout self.save_analytic(request, query, course_matches, sem, True) student = get_student(request) serializer_context = { "semester": sem, "student": student, "school": request.subdomain, } course_match_data = [ CourseSerializer(course, context=serializer_context).data for course in course_matches ] return Response(course_match_data, status=status.HTTP_200_OK)
def post(self, request): """ Creates a :obj:`SharedTimetable` and returns the hashed database id as the slug for the url which students then share and access. """ school = request.subdomain timetable = request.data["timetable"] has_conflict = timetable.get("has_conflict", False) semester, _ = Semester.objects.get_or_create( **request.data["semester"]) student = get_student(request) shared_timetable = SharedTimetable.objects.create( student=student, school=school, semester=semester, has_conflict=has_conflict) shared_timetable.save() self.save_courses(timetable, shared_timetable) response = {"slug": hashids.encrypt(shared_timetable.id)} return Response(response, status=status.HTTP_200_OK)
def get(self, request, *args, **kwargs): self.school = request.subdomain self.student = get_student(request) feature_flow = self.get_feature_flow(request, *args, **kwargs) # take semester provided by feature flow if available, otherwise the first available sem all_semesters = get_current_semesters(self.school) if 'semester' in feature_flow: sem = feature_flow.pop('semester') sem_dict = {'name': sem.name, 'year': sem.year} if sem_dict not in all_semesters: all_semesters.append(sem_dict) curr_sem_index = all_semesters.index(sem_dict) else: curr_sem_index = 0 sem = Semester.objects.get(**all_semesters[curr_sem_index]) integrations = [] if self.student and self.student.user.is_authenticated(): self.student.school = self.school self.student.save() for i in self.student.integrations.all(): integrations.append(i.name) init_data = { 'school': self.school, 'currentUser': get_student_dict(self.school, self.student, sem), 'currentSemester': curr_sem_index, 'allSemesters': all_semesters, 'oldSemesters': get_old_semesters(self.school), 'uses12HrTime': self.school in AM_PM_SCHOOLS, 'studentIntegrations': integrations, 'examSupportedSemesters': map(all_semesters.index, final_exams_available.get(self.school, [])), 'timeUpdatedTos': Agreement.objects.latest().last_updated.isoformat(), 'featureFlow': dict(feature_flow, name=self.feature_name) } return render(request, 'timetable.html', {'init_data': json.dumps(init_data)})
def offerings(request, sectionList): student = get_student(request) section_list = sectionList.split("_") if request.method == 'POST': return redirect('pilot:semlyhome') else: vacant = [] full = [] message = "" for section in section_list: with transaction.atomic(): pilot_offering = PilotOffering.objects.get(id=int(section)) signedup = False for person in pilot_offering.students.all(): if person == student: signedup = True message = 'You are already enrolled in this course' for person in pilot_offering.wait_students.all(): if person == student: signedup = True message = 'You are already on the waitlist for this course' if not signedup: if pilot_offering.enrolment < pilot_offering.size: vacant.append(pilot_offering) pilot_offering.students.add(student) pilot_offering.enrolment = len( pilot_offering.students.all()) else: full.append(pilot_offering) pilot_offering.wait_students.add(student) pilot_offering.waitlist = len( pilot_offering.wait_students.all()) pilot_offering.save() context = { 'student': student, 'enrolled': vacant, 'waitlisted': full, 'sections': section_list, 'message': message } return render(request, 'pilot/offerings.html/', context=context)
def info(request): if request.method == 'POST': form = StudentForm(request.POST) student_object = get_student(request) if form.is_valid(): student_object.user.first_name = form.cleaned_data['first_name'] student_object.user.last_name = form.cleaned_data['last_name'] student_object.hopid = form.cleaned_data['hopid'] student_object.jhed = form.cleaned_data['jhed'] student_object.class_year = form.cleaned_data['class_year'] student_object.major = form.cleaned_data['major'] pre_h = form.cleaned_data['pre_health'] pre_h = {'True': True, 'False': False, 'None': None}[pre_h] student_object.pre_health = pre_h diss = form.cleaned_data['diss'] diss = {'True': True, 'False': False, 'None': None}[diss] student_object.disabilities = diss student_object.save() return redirect('pilot:studentinfo') else: return render(request, 'pilot/get_info.html/')
def view_analytics_dashboard(request): student = get_student(request) if student and student.user.is_staff: # Number of time tables by school total_timetables_by_school = {} # timetables_per_hour = {} # shared_timetables_per_hour = {} for school in ACTIVE_SCHOOLS: total_timetables_by_school[school] = number_timetables(school=school) # timetables_per_hour[school] = number_timetables_per_hour(school=school) # shared_timetables_per_hour[school] = number_timetables_per_hour(Timetable=SharedTimetable, school=school) # Number of users by permission # TODO: Moves this array to somewhere else (like ACTIVE_SCHOOLS) total_signups = number_timetables(Timetable=Student) permissions = ["social_courses", "social_offerings", "social_all"] num_users_by_permission = {} for permission in permissions: # TODO: hacky way of passing in permission as an identifier for parameter. # Also have to use tuple for template to easily access %. args = {"Timetable": Student, permission: True} num_users = number_timetables(**args) percent_users = format(float(num_users) / total_signups * 100, '.2f') num_users_by_permission[permission] = (num_users, percent_users) total_calendar_exports = number_timetables(Timetable=CalendarExport) google_calendar_exports = number_timetables(Timetable=CalendarExport, is_google_calendar=True) ics_calendar_exports = total_calendar_exports - google_calendar_exports unique_users_calendar_exports = number_timetables(Timetable=CalendarExport, distinct="student") total_final_exam_views = number_timetables(Timetable=FinalExamModalView) unique_users_final_exam_views = number_timetables(Timetable=FinalExamModalView, distinct="student") total_shared_timetable_views = number_timetables(Timetable=SharedTimetableView) total_shared_course_views = number_timetables(Timetable=SharedCourseView) fb_alert_views = number_timetables(Timetable=FacebookAlertView) unique_users_fb_alert_views = number_timetables(Timetable=FacebookAlertView, distinct="student") fb_alert_clicks = number_timetables(Timetable=FacebookAlertClick) unique_users_fb_alert_clicks = number_timetables(Timetable=FacebookAlertClick, distinct="student") return render_to_response('analytics_dashboard.html', { "signups_per_hour": number_timetables_per_hour( Timetable=Student,start_delta_days=7, interval_delta_hours=24), "total_timetables_by_school": json.dumps(total_timetables_by_school), "total_timetables_by_semester": json.dumps(number_timetables_per_semester()), "total_timetables": number_timetables(), "total_shared_timetables": number_timetables(Timetable=SharedTimetable), "total_personal_timetables": number_timetables(Timetable=PersonalTimetable), "total_signups": total_signups, "num_users_chrome_notifs": number_user_chrome_notifs(), "num_users_by_permission": num_users_by_permission, "num_users_by_class_year": json.dumps(number_students_by_year()), "num_users_by_school": json.dumps(number_students_by_school()), "number_of_reactions": json.dumps(number_of_reactions()), "total_calendar_exports": total_calendar_exports, "google_calendar_exports": google_calendar_exports, "ics_calendar_exports": ics_calendar_exports, "unique_users_calendar_exports": unique_users_calendar_exports, "total_final_exam_views": total_final_exam_views, "unique_users_final_exam_views": unique_users_final_exam_views, "fb_alert_views": fb_alert_views, "unique_users_fb_alert_views": unique_users_fb_alert_views, "fb_alert_clicks": fb_alert_clicks, "unique_users_fb_alert_clicks": unique_users_fb_alert_clicks, "total_shared_timetable_views":total_shared_timetable_views, "total_shared_course_views":total_shared_course_views, "calendar_exports_by_type": json.dumps({"ics": ics_calendar_exports, "google": google_calendar_exports}), "jhu_most_popular_courses": [], # needs to be refactored; was causing timeout on server because too slow "uoft_most_popular_courses": [], # needs to be refactored; was causing timeout on server because too slow "umd_most_popular_courses": [], # needs to be refactored; was causing timeout on server because too slow "itcr_most_popular_courses": [] }, context_instance=RequestContext(request)) else: raise Http404
def post(self, request): """Generate best timetables given the user's selected courses""" school = request.subdomain params = request.data student = get_student(request) try: params['semester'] = Semester.objects.get_or_create(**params['semester'])[0] except TypeError: # handle deprecated cached semesters from frontend params['semester'] = Semester.objects.get(name="Fall", year="2016") \ if params['semester'] == "F" \ else Semester.objects.get(name="Spring", year="2017") course_ids = params['courseSections'].keys() courses = [Course.objects.get(id=cid) for cid in course_ids] locked_sections = params['courseSections'] save_analytics_timetable(courses, params['semester'], school, get_student(request)) for updated_course in params.get('updated_courses', []): cid = str(updated_course['course_id']) locked_sections[cid] = locked_sections.get(cid, {}) if cid not in course_ids: courses.append(Course.objects.get(id=int(cid))) for locked_section in filter(bool, updated_course['section_codes']): update_locked_sections(locked_sections, cid, locked_section, params['semester']) # temp optional course implementation opt_course_ids = params.get('optionCourses', []) max_optional = params.get('numOptionCourses', len(opt_course_ids)) optional_courses = [Course.objects.get(id=cid) for cid in opt_course_ids] optional_course_subsets = [subset for subset_size in range(max_optional, -1, -1) for subset in itertools.combinations(optional_courses, subset_size)] custom_events = params.get('customSlots', []) preferences = params['preferences'] with_conflicts = preferences.get('try_with_conflicts', False) sort_metrics = [(m['metric'], m['order']) for m in preferences.get('sort_metrics', []) if m['selected']] # TODO move sorting to view level so that result is sorted timetables = [timetable for opt_courses in optional_course_subsets for timetable in courses_to_timetables(courses + list(opt_courses), locked_sections, params['semester'], sort_metrics, params['school'], custom_events, with_conflicts, opt_course_ids)] context = {'semester': params['semester'], 'school': request.subdomain, 'student': student} courses = [course for course in courses + optional_courses] response = { 'timetables': DisplayTimetableSerializer(timetables, many=True).data, 'new_c_to_s': locked_sections, 'courses': CourseSerializer(courses, context=context, many=True).data } return Response(response, status=status.HTTP_200_OK)