diff --git a/core/daos/courses.py b/core/daos/courses.py index 23783ae..b4c08b4 100644 --- a/core/daos/courses.py +++ b/core/daos/courses.py @@ -1,4 +1,4 @@ -from .utils import to_where, fetchone_as_dict, fetchone, fetchall +from .utils import to_where, fetchone_as_dict, fetchone, fetchall, insert def course_select_summary(dept, course_number): @@ -6,6 +6,10 @@ def course_select_summary(dept, course_number): return fetchone_as_dict(query, dept, course_number) +def course_insert_view(dept, course_number): + insert("courses_visits", {"course_number": course_number, "department": dept}) + + def course_select_paginated_reviews(dept, course_number, limit, page, tags=[]): query = """ SELECT r.*, u.name AS reviewer_name, u.username AS reviewer_username, p.id AS professor_id, p.name AS professor_name, p.email AS professor_email @@ -251,3 +255,19 @@ def course_search_by_similarity_count( full_query, *([query, *list(filter(lambda x: x is not None, args.values()))] * 2), ) + + +def course_select_most_visited(limit: int, start_time: str): + """ + Select the most visited courses that were visited after + start_time + """ + query = f""" + SELECT course_number, department, COUNT(*) AS visits FROM courses_visits + WHERE created_at > %s + GROUP BY (course_number, department) + ORDER BY COUNT(*) DESC + LIMIT %s + """ + + return fetchall(query, start_time, limit) diff --git a/core/daos/professors.py b/core/daos/professors.py index 60629b7..7a56304 100644 --- a/core/daos/professors.py +++ b/core/daos/professors.py @@ -1,4 +1,4 @@ -from .utils import fetchone, fetchone_as_dict, fetchall +from .utils import fetchone, fetchone_as_dict, fetchall, insert # SUMMARY @@ -7,6 +7,10 @@ def professor_select_summary(professor_id): return fetchone_as_dict(query, professor_id) +def professor_insert_view(professor_id): + insert("professor_visits", {"professor_id": professor_id}) + + # STATS def professor_select_average_grade(professor_id): query = "SELECT get_professor_average_grade(%s)" @@ -122,3 +126,19 @@ def professor_search_by_last_name_count(last_name_start: str): name ~ ' {last_name_start}[^\\s]*$' """ return fetchone(sql_query)[0] + + +def professor_select_most_visited(limit: int, start_time: str): + """ + Select the most visited professors that were visited after + start_time + """ + query = f""" + SELECT professor_id, COUNT(*) AS visits FROM professor_visits + WHERE created_at > %s + GROUP BY (professor_id) + ORDER BY COUNT(*) DESC + LIMIT %s + """ + + return fetchall(query, start_time, limit) diff --git a/core/services/courses.py b/core/services/courses.py index 25a7570..49ca523 100644 --- a/core/services/courses.py +++ b/core/services/courses.py @@ -1,3 +1,4 @@ +from datetime import datetime, timedelta from core.daos import ( course_select_average_rating, course_select_average_quality, @@ -13,9 +14,39 @@ course_search_by_filters_count, course_search_by_similarity, course_search_by_similarity_count, + course_select_summary, + course_insert_view, + course_select_most_visited, ) +def get_course_most_visited(): + last_month = datetime.now() - timedelta(weeks=4) + most_visited = course_select_most_visited( + 3, last_month.isoformat(sep=" ", timespec="seconds") + ) + if len(most_visited) == 0: + # no one visited our site in the past month... + # so just return the most visited overall (starting from epoch) + most_visited = course_select_most_visited(3, "1970-01-01 00:00:00") + return { + "most_visited": [ + get_course_reviews_stats(el["department"], el["course_number"]) + | course_select_summary(el["department"], el["course_number"]) + | {"visits": el["visits"]} + for el in most_visited + ] + } + + +def get_course_summary(dept, course_number): + """ + Inserts a visit into courses_visits and returns the summary + """ + course_insert_view(dept, course_number) + return course_select_summary(dept, course_number) + + def get_course_reviews_stats(dept, course_number): return { "department": dept, diff --git a/core/services/professors.py b/core/services/professors.py index 5712e5a..bbc756e 100644 --- a/core/services/professors.py +++ b/core/services/professors.py @@ -1,3 +1,5 @@ +from datetime import datetime, timedelta + from core.daos import ( professor_select_average_rating, professor_select_average_quality, @@ -17,9 +19,36 @@ professor_search_by_similarity_tags, professor_search_by_last_name, professor_search_by_last_name_count, + professor_insert_view, + professor_select_summary, + professor_select_most_visited, ) +def get_professor_most_visited(): + last_month = datetime.now() - timedelta(weeks=4) + most_visited = professor_select_most_visited( + 3, last_month.isoformat(sep=" ", timespec="seconds") + ) + if len(most_visited) == 0: + # no one visited our site in the past month... + # so just return the most visited overall (starting from epoch) + most_visited = professor_select_most_visited(3, "1970-01-01 00:00:00") + return { + "most_visited": [ + get_professor_reviews_stats(el["professor_id"]) + | professor_select_summary(el["professor_id"]) + | {"visits": el["visits"]} + for el in most_visited + ] + } + + +def get_professor_summary(professor_id: str): + professor_insert_view(professor_id) + return professor_select_summary(professor_id) + + def get_professor_reviews_stats(professor_id: str): return { "avg_rating": professor_select_average_rating(professor_id), diff --git a/core/urls.py b/core/urls.py index 2e88f86..f4fcf30 100644 --- a/core/urls.py +++ b/core/urls.py @@ -22,6 +22,7 @@ "courses/-/reviews", views.course_reviews_view, ), + path("courses/most_visited", views.course_most_visited_view), # path('courses//reviews/comments', views.review_comments), # ############### professor paths ################### path("professors//summary", views.professor_summary_view), @@ -32,6 +33,7 @@ ), path("professors//reviews", views.professor_reviews_view), path("professors/search", views.professor_search_view), + path("professors/most_visited", views.professor_most_visited_view), # ############## schedule search #################### path("schedules/search", views.schedule_search_view), # ############## departments paths #################### diff --git a/core/views/courses.py b/core/views/courses.py index 393ef18..d991d4f 100644 --- a/core/views/courses.py +++ b/core/views/courses.py @@ -1,12 +1,13 @@ from django.http.response import JsonResponse from rest_framework.decorators import api_view -from core.daos import course_select_summary from core.services import ( get_paginated_reviews_by_course, get_paginated_schedules_by_course, get_course_reviews_stats, get_course_search_results, + get_course_summary, + get_course_most_visited, ) from .utils import validate_user, validate_page_limit, try_response @@ -14,7 +15,7 @@ @api_view(["GET"]) @try_response def course_summary_view(request, department: str, course_number: str): - json_data = course_select_summary(department.upper(), course_number) + json_data = get_course_summary(department.upper(), course_number) return JsonResponse(json_data) @@ -47,7 +48,7 @@ def course_reviews_view(request, department: str, course_number: str): course_number, **validate_page_limit(request), tags=request.GET.getlist("tags"), - user_id=validate_user(request) + user_id=validate_user(request), ) return JsonResponse(json_data) @@ -65,3 +66,9 @@ def course_search_view(request): ) return JsonResponse(json_data) + + +@api_view(["GET"]) +@try_response +def course_most_visited_view(request): + return JsonResponse(get_course_most_visited()) diff --git a/core/views/professors.py b/core/views/professors.py index 5dcd204..1132e01 100644 --- a/core/views/professors.py +++ b/core/views/professors.py @@ -1,12 +1,13 @@ from django.http.response import JsonResponse from rest_framework.decorators import api_view -from core.daos import professor_select_summary from core.services import ( get_paginated_schedules_by_professor, get_professor_reviews_stats, get_paginated_reviews_by_professor, get_professor_search_results, + get_professor_summary, + get_professor_most_visited, ) from .utils import validate_user, validate_page_limit, try_response @@ -25,7 +26,7 @@ def professor_schedules_view(request, professor_id): @api_view(["GET"]) @try_response def professor_summary_view(request, professor_id): - json_data = professor_select_summary(professor_id=professor_id) + json_data = get_professor_summary(professor_id=professor_id) return JsonResponse(json_data) @@ -43,7 +44,7 @@ def professor_reviews_view(request, professor_id): professor_id=professor_id, **validate_page_limit(request), tags=request.GET.getlist("tags"), - user_id = validate_user(request) + user_id=validate_user(request), ) return JsonResponse(json_data) @@ -59,3 +60,9 @@ def professor_search_view(request): ) return JsonResponse(json_data) + + +@api_view(["GET"]) +@try_response +def professor_most_visited_view(request): + return JsonResponse(get_professor_most_visited())