def general_times_overview_course(request): """ Return total of seconds viewed on a course """ roles = recoverUserCourseRoles(request) allowed_list = [r['course_id'].replace( "course", "block") for r in roles['roles'] if r['role'] in settings.BACKEND_ALLOWED_ROLES] try: course, time__gte, time__lte = verify_time_range_course_params(request) except Exception as e: return Response(status=status.HTTP_400_BAD_REQUEST, data=str(e)) # Check that user has permissions if course not in allowed_list: return Response(status=status.HTTP_403_FORBIDDEN, data="No tiene permisos para ver los datos en los cursos solicitados") total_course_time = TimeOnPage.objects.filter( vertical__is_active=True, vertical__course__icontains=course, time__lte=time__lte, time__gte=time__gte, ) total_course_time = total_course_time.values("vertical__course").annotate(total=Sum("delta_time_float")) if total_course_time.count() != 0: total_course_time= total_course_time[0]['total'] else: total_course_time = 0 return JsonResponse({ 'total_time': total_course_time, })
def detailed_visits_overview_course(request): """ Compact visits on a course for date, chapter and sequential within a date period. """ roles = recoverUserCourseRoles(request) allowed_list = [ r['course_id'].replace("course", "block") for r in roles['roles'] if r['role'] in settings.BACKEND_ALLOWED_ROLES ] try: course, time__gte, time__lte = verify_time_range_course_params(request) except Exception as e: return Response(status=status.HTTP_400_BAD_REQUEST, data=str(e)) # Check that user has permissions if course not in allowed_list: return Response( status=status.HTTP_403_FORBIDDEN, data= "No tiene permisos para ver los datos en los cursos solicitados") total_visits = VisitOnPage.objects.filter( vertical__is_active=True, vertical__course__icontains=course, time__lte=time__lte, time__gte=time__gte, ) detailed_visits = {} #groupedBy fecha date_visits = total_visits.values("time").annotate(total=Sum("count")) detailed_visits['date'] = list(date_visits) #groupedBy modulo module_visits = total_visits.values("vertical__chapter").annotate( total=Sum("count"), name=F("vertical__chapter_name")) detailed_visits['module'] = list(module_visits) #groupedBy unidad seq_visits = total_visits.values("vertical__sequential").annotate( total=Sum("count"), name=F("vertical__sequential_name"), chap_number=F("vertical__chapter_number"), seq_number=F("vertical__sequential_number"), ) detailed_visits['seq'] = list(seq_visits) total_visits = detailed_visits return JsonResponse({'total_visits': total_visits})
def general_visits_overview_course(request): """ Recover general visits overview for course. Recover total visits on period and total students """ roles = recoverUserCourseRoles(request) allowed_list = [ r['course_id'].replace("course", "block") for r in roles['roles'] if r['role'] in settings.BACKEND_ALLOWED_ROLES ] try: course, time__gte, time__lte = verify_time_range_course_params(request) except Exception as e: return Response(status=status.HTTP_400_BAD_REQUEST, data=str(e)) # Check that user has permissions if course not in allowed_list: return Response( status=status.HTTP_403_FORBIDDEN, data= "No tiene permisos para ver los datos en los cursos solicitados") total_visits = VisitOnPage.objects.filter( vertical__is_active=True, vertical__course__icontains=course, time__lte=time__lte, time__gte=time__gte, ) total_visits = total_visits.values("vertical__course").annotate( total=Sum("count")) if total_visits.count() != 0: total_visits = total_visits[0]['total'] else: total_visits = 0 total_users = VisitOnPage.objects.filter( vertical__is_active=True, vertical__course__icontains=course, time__lte=time__lte, time__gte=time__gte, ).values("username").distinct("username").count() return JsonResponse({ 'total_visits': total_visits, 'total_users': total_users, })
def manage_standard_request(request, query): roles = recoverUserCourseRoles(request) allowed_list = [r['course_id'].replace( "course", "block") for r in roles['roles'] if r['role'] in settings.BACKEND_ALLOWED_ROLES] try: course, time__gte, time__lte = verify_time_range_course_params(request) except Exception as e: return Response(status=status.HTTP_400_BAD_REQUEST, data=str(e)) # Check that user has permissions if course not in allowed_list: return Response(status=status.HTTP_403_FORBIDDEN, data="No tiene permisos para ver los datos en los cursos solicitados") visits = query(course, time__lte, time__gte) if len(visits) == 0: return Response(status=status.HTTP_204_NO_CONTENT) return Response(visits)
def get_course_structure(request): """ Map a course structure using the recovered Verticals from the Edx API """ roles = recoverUserCourseRoles(request) allowed_list = [r['course_id'].replace( "course", "block") for r in roles['roles'] if r['role'] in settings.BACKEND_ALLOWED_ROLES] if "search" not in request.query_params: return Response(status=status.HTTP_400_BAD_REQUEST, data="Search field required") # Look on course name and course code verticals = CourseVertical.objects.filter( Q(course_name__icontains=request.query_params["search"]) | Q(course__icontains=request.query_params["search"].replace("course-v1", "block-v1"))) if len(verticals) == 0: return Response(status=status.HTTP_204_NO_CONTENT) courses = dict() # Gather unique keys for v in verticals: if v.course not in courses: # Correct course id name course_id = v.course.split("+type@")[0] courses[v.course] = dict( {"name": v.course_name, "course_id": course_id, "chapters": {}}) chapter = courses[v.course]["chapters"] # Check that sections exists if v.chapter_number not in chapter: chapter[v.chapter_number] = dict( {"name": v.chapter_name, "id": v.chapter}) if v.sequential_number not in chapter[v.chapter_number]: chapter[v.chapter_number][v.sequential_number] = dict( {"name": v.sequential_name}) if v.vertical_number not in chapter[v.chapter_number][v.sequential_number]: chapter[v.chapter_number][v.sequential_number][v.vertical_number] = dict( {"name": v.vertical_name, "block_id": v.block_id, "block_type": v.block_type, "block_url": v.student_view_url, "vertical_id": v.vertical}) # Parse keys as arrays courses_names = courses.keys() mapped_courses = [] for course in courses_names: current_course = courses[course] # Remove courses that are not on the allowed list if current_course["course_id"] not in allowed_list: continue chapter_list = [] chapter_indexes = [int(k) for k in current_course["chapters"].keys()] chapter_indexes.sort() for chapter in chapter_indexes: current_chapter = current_course["chapters"][chapter] sequential_list = [] sequential_indexes = [ int(k) for k in current_chapter.keys() if k != 'name' and k != 'id'] sequential_indexes.sort() for seq in sequential_indexes: current_seq = current_chapter[seq] vertical_list = [] vertical_indexes = [int(k) for k in current_seq.keys() if k != 'name'] vertical_indexes.sort() for vert in vertical_indexes: # Add vertical object vertical_list.append(current_seq[vert]) # Save sequential with verticals sequential_list.append( {"name": current_seq["name"], "verticals": vertical_list}) # Save chapter with sequentials chapter_list.append( {"name": current_chapter["name"], "sequentials": sequential_list, "id": current_chapter["id"]}) mapped_courses.append( {"name": current_course["name"], "id": current_course["course_id"], "chapters": chapter_list}) # If values where filtered then the user has no permissions if len(mapped_courses) == 0: return Response(status=status.HTTP_403_FORBIDDEN, data="No tiene permisos para ver los cursos solicitados") return Response({"courses": mapped_courses})
def times_on_course(request): """ Compact user time sessions for verticals Expects 3 query parameters - search: course id in course-block format - llimit (lower limit): a string datetime in isoformat - rlimit (upper limit): a string datetime in isoformat both timestamps are included on the query. Timezone is added on runtime """ roles = recoverUserCourseRoles(request) allowed_list = [ r['course_id'].replace("course", "block") for r in roles['roles'] if r['role'] in settings.BACKEND_ALLOWED_ROLES ] if "search" not in request.query_params: return Response(status=status.HTTP_400_BAD_REQUEST, data="Search field required") if "llimit" not in request.query_params: return Response(status=status.HTTP_400_BAD_REQUEST, data="Lower limit field required") if "ulimit" not in request.query_params: return Response(status=status.HTTP_400_BAD_REQUEST, data="Upper limit field required") tz = pytz.timezone(settings.TIME_ZONE) try: llimit = tz.localize( datetime.fromisoformat(request.query_params["llimit"].replace( "Z", ""))) ulimit = tz.localize( datetime.fromisoformat(request.query_params["ulimit"].replace( "Z", ""))) except Exception as time_error: return Response( status=status.HTTP_400_BAD_REQUEST, data="Error while formating time limits. Expects isoformat.") if llimit > ulimit: return Response(status=status.HTTP_400_BAD_REQUEST, data="lower limit does not preceed upper limit") # Check that user has permissions if request.query_params["search"] not in allowed_list: return Response( status=status.HTTP_403_FORBIDDEN, data= "No tiene permisos para ver los datos en los cursos solicitados") # Course will arrive in format block-v1:COURSE without +type@course-block@course # hence we do a icontains query times = TimeOnPage.objects.filter( course__icontains=request.query_params["search"], time__lte=ulimit, time__gte=llimit).values("username", "event_type_vertical").order_by( "username", "event_type_vertical").annotate(total=Sum("delta_time_float")) if len(times) == 0: return Response(status=status.HTTP_204_NO_CONTENT) return Response(times)