def __init__(self, request, course_identifier, flow_identifier, flow_session=None): CoursePageContext.__init__(self, request, course_identifier) self.flow_session = flow_session self.flow_identifier = flow_identifier from course.content import get_flow_commit_sha from django.core.exceptions import ObjectDoesNotExist # Fetch 'current' version of the flow to compute permissions # and versioning rules. # Fall back to 'old' version if current git version does not # contain this flow any more. try: current_flow_desc_sha = self.course_commit_sha current_flow_desc = get_flow_desc(self.repo, self.course, flow_identifier, current_flow_desc_sha) except ObjectDoesNotExist: if self.flow_session is None: raise http.Http404() current_flow_desc_sha = self.flow_session.active_git_commit_sha.encode() current_flow_desc = get_flow_desc(self.repo, self.course, flow_identifier, current_flow_desc_sha) self.flow_commit_sha = get_flow_commit_sha( self.course, self.participation, current_flow_desc, self.flow_session) if self.flow_commit_sha == current_flow_desc_sha: self.flow_desc = current_flow_desc else: self.flow_desc = get_flow_desc(self.repo, self.course, flow_identifier, self.flow_commit_sha) # {{{ figure out permissions from course.views import get_now_or_fake_time self.permissions, self.stipulations = get_flow_permissions( self.course, self.participation, self.role, flow_identifier, current_flow_desc, get_now_or_fake_time(request))
def __init__(self, repo, course, flow_identifier, participation=None, flow_session=None): """*participation* and *flow_session* are not stored and only used to figure out versioning of the flow content. """ self.repo = repo self.course = course self.flow_identifier = flow_identifier from course.content import get_flow_commit_sha from django.core.exceptions import ObjectDoesNotExist # Fetch 'current' version of the flow to compute permissions # and versioning rules. # Fall back to 'old' version if current git version does not # contain this flow any more. self.course_commit_sha = get_course_commit_sha( self.course, participation) try: current_flow_desc_sha = self.course_commit_sha self.current_flow_desc = get_flow_desc(self.repo, self.course, flow_identifier, current_flow_desc_sha) except ObjectDoesNotExist: if flow_session is None: raise http.Http404() current_flow_desc_sha = flow_session.active_git_commit_sha.encode() self.current_flow_desc = get_flow_desc(self.repo, self.course, flow_identifier, current_flow_desc_sha) self.flow_commit_sha = get_flow_commit_sha( self.course, participation, self.current_flow_desc, flow_session) if self.flow_commit_sha == current_flow_desc_sha: self.flow_desc = self.current_flow_desc else: self.flow_desc = get_flow_desc(self.repo, self.course, flow_identifier, self.flow_commit_sha)
def grade_page_visit(visit, visit_grade_model=FlowPageVisitGrade, grade_data=None, graded_at_git_commit_sha=None): if not visit.is_graded_answer: raise RuntimeError("cannot grade ungraded answer") flow_session = visit.flow_session course = flow_session.course page_data = visit.page_data from course.content import ( get_course_repo, get_course_commit_sha, get_flow_commit_sha, get_flow_desc, get_flow_page_desc, instantiate_flow_page) repo = get_course_repo(course) course_commit_sha = get_course_commit_sha( course, flow_session.participation) flow_desc_pre = get_flow_desc(repo, course, flow_session.flow_id, course_commit_sha) flow_commit_sha = get_flow_commit_sha( course, flow_session.participation, flow_desc_pre, visit.flow_session) flow_desc = get_flow_desc(repo, course, flow_session.flow_id, flow_commit_sha) page_desc = get_flow_page_desc( flow_session.flow_id, flow_desc, page_data.group_id, page_data.page_id) page = instantiate_flow_page( location="flow '%s', group, '%s', page '%s'" % (flow_session.flow_id, page_data.group_id, page_data.page_id), repo=repo, page_desc=page_desc, commit_sha=flow_commit_sha) from course.page import PageContext grading_page_context = PageContext( course=course, repo=repo, commit_sha=flow_commit_sha) answer_feedback = page.grade( grading_page_context, visit.page_data.data, visit.answer, grade_data=grade_data) grade = visit_grade_model() grade.visit = visit grade.grade_data = grade_data grade.max_points = page.max_points(visit.page_data) grade.graded_at_git_commit_sha = graded_at_git_commit_sha if answer_feedback is not None: grade.correctness = answer_feedback.correctness grade.feedback = answer_feedback.as_json() grade.save()
def page_analytics(pctx, flow_identifier, group_id, page_id): if pctx.role not in [ participation_role.teaching_assistant, participation_role.instructor, participation_role.observer, ]: raise PermissionDenied("must be at least TA to view analytics") flow_desc = get_flow_desc(pctx.repo, pctx.course, flow_identifier, pctx.course_commit_sha) is_multiple_submit = is_flow_multiple_submit(flow_desc) page_cache = PageInstanceCache(pctx.repo, pctx.course, flow_identifier) visits = (FlowPageVisit.objects .filter( flow_session__flow_id=flow_identifier, page_data__group_id=group_id, page_data__page_id=page_id, is_graded_answer=True, )) if is_multiple_submit and connection.features.can_distinct_on_fields: visits = (visits .distinct("page_data", "visit_time") .order_by("page_data", "-visit_time")) visits = (visits .prefetch_related("flow_session") .prefetch_related("page_data")) normalized_answer_and_correctness_to_count = {} title = None body = None total_count = 0 for visit in visits: flow_commit_sha = get_flow_commit_sha( pctx.course, pctx.participation, flow_desc, visit.flow_session) page = page_cache.get_page(group_id, page_id, flow_commit_sha) from course.page import PageContext grading_page_context = PageContext( course=pctx.course, repo=pctx.repo, commit_sha=flow_commit_sha) title = page.title(grading_page_context, visit.page_data.data) body = page.body(grading_page_context, visit.page_data.data) answer_feedback = visit.get_most_recent_feedback() if answer_feedback is not None: key = (answer_feedback.normalized_answer, answer_feedback.correctness) normalized_answer_and_correctness_to_count[key] = \ normalized_answer_and_correctness_to_count.get(key, 0) + 1 total_count += 1 answer_stats = [] for (normalized_answer, correctness), count in \ normalized_answer_and_correctness_to_count.iteritems(): answer_stats.append( AnswerStats( normalized_answer=normalized_answer, correctness=correctness, count=count, percentage=safe_div(100 * count, total_count))) answer_stats = sorted( answer_stats, key=lambda astats: astats.percentage, reverse=True) return render_course_page(pctx, "course/analytics-page.html", { "flow_identifier": flow_identifier, "group_id": group_id, "page_id": page_id, "title": title, "body": body, "answer_stats_list": answer_stats, })
def make_page_answer_stats_list(pctx, flow_identifier): flow_desc = get_flow_desc(pctx.repo, pctx.course, flow_identifier, pctx.course_commit_sha) is_multiple_submit = is_flow_multiple_submit(flow_desc) page_cache = PageInstanceCache(pctx.repo, pctx.course, flow_identifier) page_info_list = [] for group_desc in flow_desc.groups: for page_desc in group_desc.pages: points = 0 count = 0 visits = (FlowPageVisit.objects .filter( flow_session__flow_id=flow_identifier, page_data__group_id=group_desc.id, page_data__page_id=page_desc.id, is_graded_answer=True, )) if is_multiple_submit and connection.features.can_distinct_on_fields: visits = (visits .distinct("page_data") .order_by("page_data", "-visit_time")) visits = (visits .prefetch_related("flow_session") .prefetch_related("page_data")) title = None for visit in visits: flow_commit_sha = get_flow_commit_sha( pctx.course, pctx.participation, flow_desc, visit.flow_session) page = page_cache.get_page(group_desc.id, page_desc.id, flow_commit_sha) from course.page import PageContext grading_page_context = PageContext( course=pctx.course, repo=pctx.repo, commit_sha=flow_commit_sha) title = page.title(grading_page_context, visit.page_data.data) answer_feedback = visit.get_most_recent_feedback() if (answer_feedback is not None and answer_feedback.correctness is not None): count += 1 points += answer_feedback.correctness page_info_list.append( PageAnswerStats( group_id=group_desc.id, page_id=page_desc.id, title=title, average_correctness=safe_div(points, count), answer_count=count, url=reverse( "course.analytics.page_analytics", args=( pctx.course_identifier, flow_identifier, group_desc.id, page_desc.id, )))) return page_info_list