Beispiel #1
0
    def __init__(self, request, course_identifier):
        # type: (http.HttpRequest, Text) -> None

        self.request = request
        self.course_identifier = course_identifier
        self._permissions_cache = None  # type: Optional[FrozenSet[Tuple[Text, Optional[Text]]]]  # noqa
        self._role_identifiers_cache = None  # type: Optional[List[Text]]
        self.old_language = None

        # using this to prevent nested using as context manager
        self._is_in_context_manager = False

        from course.models import Course  # noqa
        self.course = get_object_or_404(Course, identifier=course_identifier)

        from course.enrollment import get_participation_for_request
        self.participation = get_participation_for_request(
            request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.participation)

        self.course_commit_sha = get_course_commit_sha(self.course,
                                                       self.participation)

        self.repo = get_course_repo(self.course)

        # logic duplicated in course.content.get_course_commit_sha
        sha = self.course.active_git_commit_sha.encode()

        if self.participation is not None:
            if self.participation.preview_git_commit_sha:
                preview_sha = self.participation.preview_git_commit_sha.encode(
                )

                with get_course_repo(self.course) as repo:
                    from relate.utils import SubdirRepoWrapper
                    if isinstance(repo, SubdirRepoWrapper):
                        true_repo = repo.repo
                    else:
                        true_repo = cast(dulwich.repo.Repo, repo)

                    try:
                        true_repo[preview_sha]
                    except KeyError:
                        from django.contrib import messages
                        messages.add_message(
                            request, messages.ERROR,
                            _("Preview revision '%s' does not exist--"
                              "showing active course content instead.") %
                            preview_sha.decode())

                        preview_sha = None
                    finally:
                        true_repo.close()

                if preview_sha is not None:
                    sha = preview_sha

        self.course_commit_sha = sha
Beispiel #2
0
    def __init__(self, request, course_identifier):
        # type: (http.HttpRequest, Text) -> None

        self.request = request
        self.course_identifier = course_identifier
        self._permissions_cache = None  # type: Optional[FrozenSet[Tuple[Text, Optional[Text]]]]  # noqa
        self._role_identifiers_cache = None  # type: Optional[List[Text]]
        self.old_language = None

        # using this to prevent nested using as context manager
        self._is_in_context_manager = False

        from course.models import Course  # noqa
        self.course = get_object_or_404(Course, identifier=course_identifier)

        from course.enrollment import get_participation_for_request
        self.participation = get_participation_for_request(
                request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.participation)

        self.course_commit_sha = get_course_commit_sha(
                self.course, self.participation)

        self.repo = get_course_repo(self.course)

        # logic duplicated in course.content.get_course_commit_sha
        sha = self.course.active_git_commit_sha.encode()

        if self.participation is not None:
            if self.participation.preview_git_commit_sha:
                preview_sha = self.participation.preview_git_commit_sha.encode()

                with get_course_repo(self.course) as repo:
                    from relate.utils import SubdirRepoWrapper
                    if isinstance(repo, SubdirRepoWrapper):
                        true_repo = repo.repo
                    else:
                        true_repo = cast(dulwich.repo.Repo, repo)

                    try:
                        true_repo[preview_sha]
                    except KeyError:
                        from django.contrib import messages
                        messages.add_message(request, messages.ERROR,
                                _("Preview revision '%s' does not exist--"
                                "showing active course content instead.")
                                % preview_sha.decode())

                        preview_sha = None
                    finally:
                        true_repo.close()

                if preview_sha is not None:
                    sha = preview_sha

        self.course_commit_sha = sha
Beispiel #3
0
def get_current_repo_file(request, course_identifier, path):
    course = get_object_or_404(Course, identifier=course_identifier)
    role, participation = get_role_and_participation(
            request, course)

    from course.views import check_course_state
    check_course_state(course, role)

    from course.content import get_course_commit_sha
    commit_sha = get_course_commit_sha(course, participation)

    role, participation = get_role_and_participation(request, course)

    repo = get_course_repo(course)

    from course.content import is_repo_file_public
    if not is_repo_file_public(repo, commit_sha, path):
        raise PermissionDenied()

    from course.content import get_repo_blob_data_cached

    try:
        data = get_repo_blob_data_cached(
                repo, path, commit_sha.encode())
    except ObjectDoesNotExist:
        raise http.Http404()

    from mimetypes import guess_type
    content_type, _ = guess_type(path)

    return http.HttpResponse(data, content_type=content_type)
Beispiel #4
0
def finish_in_progress_sessions(self, course_id, flow_id, rule_tag, now_datetime,
        past_due_only):
    course = Course.objects.get(id=course_id)
    repo = get_course_repo(course)

    sessions = (FlowSession.objects
            .filter(
                course=course,
                flow_id=flow_id,
                participation__isnull=False,
                access_rules_tag=rule_tag,
                in_progress=True,
                ))

    count = 0
    nsessions = sessions.count()

    from course.flow import finish_flow_session_standalone
    for i, session in enumerate(sessions):
        from course.flow import adjust_flow_session_page_data
        adjust_flow_session_page_data(repo, session, course.identifier,
                respect_preview=False)

        if finish_flow_session_standalone(repo, course, session,
                now_datetime=now_datetime, past_due_only=past_due_only):
            count += 1

        self.update_state(
                state='PROGRESS',
                meta={'current': i, 'total': nsessions})

    repo.close()

    return {"message": _("%d sessions ended.") % count}
Beispiel #5
0
def git_endpoint(api_ctx, course_identifier, git_path):
    # type: (APIContext, Text, Text) -> http.HttpResponse

    course = api_ctx.course
    request = api_ctx.request

    if not api_ctx.has_permission(pperm.use_git_endpoint):
        raise PermissionDenied("insufficient privileges")

    from course.content import get_course_repo
    repo = get_course_repo(course)

    from course.content import SubdirRepoWrapper
    if isinstance(repo, SubdirRepoWrapper):
        true_repo = repo.repo
    else:
        true_repo = cast(dulwich.repo.Repo, repo)

    base_path = reverse(git_endpoint, args=(course_identifier, ""))
    assert base_path.endswith("/")
    base_path = base_path[:-1]

    import dulwich.web as dweb
    backend = dweb.DictBackend({"/": true_repo})
    app = dweb.make_wsgi_chain(backend)

    return call_wsgi_app(app, request, base_path)
Beispiel #6
0
def home(request):
    courses_and_descs_and_invalid_flags = []
    for course in Course.objects.all():
        repo = get_course_repo(course)
        desc = get_course_desc(repo, course, course.active_git_commit_sha.encode())

        role, participation = get_role_and_participation(request, course)

        show = True
        if course.hidden:
            if role not in [participation_role.teaching_assistant,
                    participation_role.instructor]:
                show = False

        if not course.valid:
            if role != participation_role.instructor:
                show = False

        if show:
            courses_and_descs_and_invalid_flags.append(
                    (course, desc, not course.valid))

    def course_sort_key(entry):
        course, desc, invalid_flag = entry
        return course.identifier

    courses_and_descs_and_invalid_flags.sort(key=course_sort_key)

    return render(request, "course/home.html", {
        "courses_and_descs_and_invalid_flags": courses_and_descs_and_invalid_flags
        })
Beispiel #7
0
def finish_in_progress_sessions(self, course_id, flow_id, rule_tag,
                                now_datetime, past_due_only):
    course = Course.objects.get(id=course_id)
    repo = get_course_repo(course)

    sessions = (FlowSession.objects.filter(
        course=course,
        flow_id=flow_id,
        participation__isnull=False,
        access_rules_tag=rule_tag,
        in_progress=True,
    ))

    count = 0
    nsessions = sessions.count()

    from course.flow import finish_flow_session_standalone
    for i, session in enumerate(sessions):
        if finish_flow_session_standalone(repo,
                                          course,
                                          session,
                                          now_datetime=now_datetime,
                                          past_due_only=past_due_only):
            count += 1

        self.update_state(state='PROGRESS',
                          meta={
                              'current': i,
                              'total': nsessions
                          })

    repo.close()

    return {"message": _("%d sessions ended.") % count}
Beispiel #8
0
def get_media(request, course_identifier, commit_sha, media_path):
    course = get_object_or_404(Course, identifier=course_identifier)

    role, participation = get_role_and_participation(request, course)

    repo = get_course_repo(course)
    return get_repo_file_response(repo, "media/" + media_path, commit_sha)
Beispiel #9
0
def regrade_flow_sessions(self, course_id, flow_id, access_rules_tag,
                          inprog_value):
    course = Course.objects.get(id=course_id)
    repo = get_course_repo(course)

    sessions = (FlowSession.objects.filter(course=course,
                                           participation__isnull=False,
                                           flow_id=flow_id))

    if access_rules_tag:
        sessions = sessions.filter(access_rules_tag=access_rules_tag)

    if inprog_value is not None:
        sessions = sessions.filter(in_progress=inprog_value)

    nsessions = sessions.count()
    count = 0

    from course.flow import regrade_session
    for session in sessions:
        regrade_session(repo, course, session)
        count += 1

        self.update_state(state='PROGRESS',
                          meta={
                              'current': count,
                              'total': nsessions
                          })

    repo.close()

    return {"message": _("%d sessions regraded.") % count}
Beispiel #10
0
def get_media(request, course_identifier, commit_sha, media_path):
    course = get_object_or_404(Course, identifier=course_identifier)

    role, participation = get_role_and_participation(request, course)

    repo = get_course_repo(course)
    return get_repo_file_response(repo, "media/" + media_path, commit_sha.encode())
Beispiel #11
0
def get_repo_file_backend(request, course, role, participation,
                          commit_sha, path):
    """
    Check if a file should be accessible.  Then call for it if
    the permission is not denied.

    Order is important here.  An in-exam request takes precedence.

    Note: an access_role of "public" is equal to "unenrolled"
    """

    # check to see if the course is hidden
    from course.views import check_course_state
    check_course_state(course, role)

    # retrieve local path for the repo for the course
    repo = get_course_repo(course)

    # set access to public (or unenrolled), student, etc
    access_kind = role
    if request.relate_exam_lockdown:
        access_kind = "in_exam"

    from course.content import is_repo_file_accessible_as
    if not is_repo_file_accessible_as(access_kind, repo, commit_sha, path):
        raise PermissionDenied()

    return get_repo_file_response(repo, path, commit_sha)
Beispiel #12
0
def home(request):
    courses_and_descs_and_invalid_flags = []
    for course in Course.objects.filter(listed=True):
        repo = get_course_repo(course)
        desc = get_course_desc(repo, course,
                               course.active_git_commit_sha.encode())

        role, participation = get_role_and_participation(request, course)

        show = True
        if course.hidden:
            if role not in [
                    participation_role.teaching_assistant,
                    participation_role.instructor
            ]:
                show = False

        if not course.valid:
            if role != participation_role.instructor:
                show = False

        if show:
            courses_and_descs_and_invalid_flags.append(
                (course, desc, not course.valid))

    def course_sort_key(entry):
        course, desc, invalid_flag = entry
        return course.identifier

    courses_and_descs_and_invalid_flags.sort(key=course_sort_key)

    return render(request, "course/home.html", {
        "courses_and_descs_and_invalid_flags":
        courses_and_descs_and_invalid_flags
    })
Beispiel #13
0
def get_current_repo_file(request, course_identifier, path):
    course = get_object_or_404(Course, identifier=course_identifier)
    role, participation = get_role_and_participation(request, course)

    from course.views import check_course_state
    check_course_state(course, role)

    from course.content import get_course_commit_sha
    commit_sha = get_course_commit_sha(course, participation)

    role, participation = get_role_and_participation(request, course)

    repo = get_course_repo(course)

    from course.content import is_repo_file_public
    if not is_repo_file_public(repo, commit_sha, path):
        raise PermissionDenied()

    from course.content import get_repo_blob_data_cached

    try:
        data = get_repo_blob_data_cached(repo, path, commit_sha.encode())
    except ObjectDoesNotExist:
        raise http.Http404()

    from mimetypes import guess_type
    content_type, _ = guess_type(path)

    return http.HttpResponse(data, content_type=content_type)
Beispiel #14
0
def recalculate_ended_sessions(self, course_id, flow_id, rule_tag):
    course = Course.objects.get(id=course_id)
    repo = get_course_repo(course)

    sessions = (FlowSession.objects.filter(
        course=course,
        flow_id=flow_id,
        participation__isnull=False,
        access_rules_tag=rule_tag,
        in_progress=False,
    ))

    nsessions = sessions.count()
    count = 0

    from course.flow import recalculate_session_grade
    for session in sessions:
        recalculate_session_grade(repo, course, session)
        count += 1

        self.update_state(state='PROGRESS',
                          meta={
                              'current': count,
                              'total': nsessions
                          })

    repo.close()

    return {"message": _("Grades recalculated for %d sessions.") % count}
Beispiel #15
0
def recalculate_ended_sessions(self, course_id, flow_id, rule_tag):
    course = Course.objects.get(id=course_id)
    repo = get_course_repo(course)

    sessions = (FlowSession.objects
            .filter(
                course=course,
                flow_id=flow_id,
                participation__isnull=False,
                access_rules_tag=rule_tag,
                in_progress=False,
                ))

    nsessions = sessions.count()
    count = 0

    from course.flow import recalculate_session_grade
    for session in sessions:
        recalculate_session_grade(repo, course, session)
        count += 1

        self.update_state(
                state='PROGRESS',
                meta={'current': count, 'total': nsessions})

    repo.close()

    return {"message": _("Grades recalculated for %d sessions.") % count}
Beispiel #16
0
def regrade_flow_sessions(self, course_id, flow_id, access_rules_tag, inprog_value):
    course = Course.objects.get(id=course_id)
    repo = get_course_repo(course)

    sessions = (FlowSession.objects
            .filter(
                course=course,
                participation__isnull=False,
                flow_id=flow_id))

    if access_rules_tag:
        sessions = sessions.filter(access_rules_tag=access_rules_tag)

    if inprog_value is not None:
        sessions = sessions.filter(in_progress=inprog_value)

    nsessions = sessions.count()
    count = 0

    from course.flow import regrade_session
    for session in sessions:
        regrade_session(repo, course, session)
        count += 1

        self.update_state(
                state='PROGRESS',
                meta={'current': count, 'total': nsessions})

    repo.close()

    return {"message": _("%d sessions regraded.") % count}
Beispiel #17
0
    def __init__(self, request, course_identifier):
        self.request = request
        self.course_identifier = course_identifier

        from course.models import Course
        self.course = get_object_or_404(Course, identifier=course_identifier)

        from course.views import get_role_and_participation
        self.role, self.participation = get_role_and_participation(
                request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.role)

        self.course_commit_sha = get_course_commit_sha(
                self.course, self.participation)

        self.repo = get_course_repo(self.course)

        # logic duplicated in course.content.get_course_commit_sha
        sha = self.course.active_git_commit_sha.encode()

        if (self.participation is not None
                and self.participation.preview_git_commit_sha):
            preview_sha = self.participation.preview_git_commit_sha.encode()

            repo = get_course_repo(self.course)

            from course.content import SubdirRepoWrapper
            if isinstance(repo, SubdirRepoWrapper):
                repo = repo.repo

            try:
                repo[preview_sha]
            except KeyError:
                from django.contrib import messages
                messages.add_message(request, messages.ERROR,
                        _("Preview revision '%s' does not exist--"
                        "showing active course content instead.")
                        % preview_sha.decode())

                preview_sha = None

            if preview_sha is not None:
                sha = preview_sha

        self.course_commit_sha = sha
def set_course_metadata(apps, schema_editor):
    Course = apps.get_model("course", "Course")  # noqa
    for course in Course.objects.all():
        from course.content import get_course_repo, get_course_desc, get_course_commit_sha

        repo = get_course_repo(course)
        course_desc = get_course_desc(repo, course, get_course_commit_sha(course, participation=None))

        course.name = course_desc.name
        course.number = course_desc.number
        course.time_period = course_desc.run

        repo.close()
        course.save()
Beispiel #19
0
    def clean(self):
        super(FlowRuleException, self).clean()

        if (self.kind == flow_rule_kind.grading
                and self.expiration is not None):
            raise ValidationError(_("grading rules may not expire"))

        from course.validation import (
                ValidationError as ContentValidationError,
                validate_session_start_rule,
                validate_session_access_rule,
                validate_session_grading_rule,
                ValidationContext)
        from course.content import (get_course_repo,
                get_course_commit_sha,
                get_flow_desc)

        from relate.utils import dict_to_struct
        rule = dict_to_struct(self.rule)

        repo = get_course_repo(self.participation.course)
        commit_sha = get_course_commit_sha(
                self.participation.course, self.participation)
        ctx = ValidationContext(
                repo=repo,
                commit_sha=commit_sha)

        flow_desc = get_flow_desc(repo,
                self.participation.course,
                self.flow_id, commit_sha)

        tags = None
        if hasattr(flow_desc, "rules"):
            tags = getattr(flow_desc.rules, "tags", None)

        try:
            if self.kind == flow_rule_kind.start:
                validate_session_start_rule(ctx, unicode(self), rule, tags)
            elif self.kind == flow_rule_kind.access:
                validate_session_access_rule(ctx, unicode(self), rule, tags)
            elif self.kind == flow_rule_kind.grading:
                validate_session_grading_rule(ctx, unicode(self), rule, tags)
            else:
                # the rule refers to FlowRuleException rule
                raise ValidationError(_("invalid rule kind: ")+self.kind)

        except ContentValidationError as e:
            # the rule refers to FlowRuleException rule
            raise ValidationError(_("invalid existing_session_rules: ")+str(e))
Beispiel #20
0
    def __init__(self, request, course_identifier):
        self.request = request
        self.course_identifier = course_identifier

        self.course = get_object_or_404(Course, identifier=course_identifier)
        self.role, self.participation = get_role_and_participation(
                request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.role)

        self.course_commit_sha = get_course_commit_sha(
                self.course, self.participation)

        self.repo = get_course_repo(self.course)
Beispiel #21
0
    def __init__(self, request, course_identifier):
        self.request = request
        self.course_identifier = course_identifier

        self.course = get_object_or_404(Course, identifier=course_identifier)
        self.role, self.participation = get_role_and_participation(
            request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.role)

        self.course_commit_sha = get_course_commit_sha(self.course,
                                                       self.participation)

        self.repo = get_course_repo(self.course)
Beispiel #22
0
def get_repo_file_backend(request, course, role, participation, commit_sha, path):
    from course.views import check_course_state
    check_course_state(course, role)

    repo = get_course_repo(course)

    access_kind = "public"
    if request.relate_exam_lockdown:
        access_kind = "in_exam"

    from course.content import is_repo_file_accessible_as
    if not is_repo_file_accessible_as(access_kind, repo, commit_sha, path):
        raise PermissionDenied()

    return get_repo_file_response(repo, path, commit_sha)
Beispiel #23
0
def get_repo_file_backend(request, course, role, participation, commit_sha,
                          path):
    from course.views import check_course_state
    check_course_state(course, role)

    repo = get_course_repo(course)

    access_kind = "public"
    if request.relate_exam_lockdown:
        access_kind = "in_exam"

    from course.content import is_repo_file_accessible_as
    if not is_repo_file_accessible_as(access_kind, repo, commit_sha, path):
        raise PermissionDenied()

    return get_repo_file_response(repo, path, commit_sha)
Beispiel #24
0
    def test_repo_is_in_subdir(self):
        self.course.course_root_path = "/subdir"
        self.course.save()

        from course.content import get_course_repo, SubdirRepoWrapper
        self.assertIsInstance(get_course_repo(self.course), SubdirRepoWrapper)

        with mock.patch("course.versioning.run_course_update_command"
                        ) as mock_run_update:
            self.post_update_course_content(self.course.active_git_commit_sha,
                                            command="update")

            self.assertEqual(mock_run_update.call_count, 1)

            from course.content import SubdirRepoWrapper
            from dulwich.repo import Repo
            self.assertIsInstance(mock_run_update.call_args[0][1], Repo)
Beispiel #25
0
def get_media(request, course_identifier, commit_sha, media_path):
    course = get_object_or_404(Course, identifier=course_identifier)

    role, participation = get_role_and_participation(request, course)

    repo = get_course_repo(course)

    from course.content import get_repo_blob_data_cached
    try:
        data = get_repo_blob_data_cached(
                repo, "media/"+media_path, commit_sha.encode())
    except ObjectDoesNotExist:
        raise http.Http404()

    from mimetypes import guess_type
    content_type = guess_type(media_path)

    return http.HttpResponse(data, content_type=content_type)
Beispiel #26
0
    def test_repo_is_in_subdir(self):
        self.course.course_root_path = "/subdir"
        self.course.save()

        from course.content import get_course_repo, SubdirRepoWrapper
        self.assertIsInstance(get_course_repo(self.course), SubdirRepoWrapper)

        with mock.patch(
            "course.versioning.run_course_update_command"
        ) as mock_run_update:
            self.post_update_course_content(
                self.course.active_git_commit_sha, command="update")

            self.assertEqual(mock_run_update.call_count, 1)

            from course.content import SubdirRepoWrapper
            from dulwich.repo import Repo
            self.assertIsInstance(mock_run_update.call_args[0][1], Repo)
Beispiel #27
0
def set_course_metadata(apps, schema_editor):
    Course = apps.get_model("course", "Course")  # noqa
    for course in Course.objects.all():
        from course.content import (
                get_course_repo, get_course_desc,
                get_course_commit_sha)

        repo = get_course_repo(course)
        course_desc = get_course_desc(
                repo, course,
                get_course_commit_sha(course, participation=None))

        course.name = course_desc.name
        course.number = course_desc.number
        course.time_period = course_desc.run

        repo.close()
        course.save()
Beispiel #28
0
def get_media(request, course_identifier, commit_sha, media_path):
    course = get_object_or_404(Course, identifier=course_identifier)

    role, participation = get_role_and_participation(request, course)

    repo = get_course_repo(course)

    from course.content import get_repo_blob_data_cached
    try:
        data = get_repo_blob_data_cached(repo, "media/" + media_path,
                                         commit_sha.encode())
    except ObjectDoesNotExist:
        raise http.Http404()

    from mimetypes import guess_type
    content_type, _ = guess_type(media_path)

    return http.HttpResponse(data, content_type=content_type)
Beispiel #29
0
    def clean(self):
        if (self.kind == flow_rule_kind.grading
                and self.expiration is not None):
            raise ValidationError("grading rules may not expire")

        from course.validation import (ValidationError as
                                       ContentValidationError,
                                       validate_session_start_rule,
                                       validate_session_access_rule,
                                       validate_session_grading_rule,
                                       ValidationContext)
        from course.content import (get_course_repo, get_course_commit_sha,
                                    get_flow_desc)

        from relate.utils import dict_to_struct
        rule = dict_to_struct(self.rule)

        repo = get_course_repo(self.participation.course)
        commit_sha = get_course_commit_sha(self.participation.course,
                                           self.participation)
        ctx = ValidationContext(repo=repo, commit_sha=commit_sha)

        flow_desc = get_flow_desc(repo, self.participation.course,
                                  self.flow_id, commit_sha)

        tags = None
        if hasattr(flow_desc, "rules"):
            tags = getattr(flow_desc.rules, "tags", None)

        try:
            if self.kind == flow_rule_kind.start:
                validate_session_start_rule(ctx, unicode(self), rule, tags)
            elif self.kind == flow_rule_kind.access:
                validate_session_access_rule(ctx, unicode(self), rule, tags)
            elif self.kind == flow_rule_kind.grading:
                validate_session_grading_rule(ctx, unicode(self), rule, tags)
            else:
                raise ValidationError("invalid rule kind: " + self.kind)

        except ContentValidationError as e:
            raise ValidationError("invalid existing_session_rules: " + str(e))
Beispiel #30
0
def get_repo_file_backend(
        request,  # type: http.HttpRequest
        course,  # type: Course
        participation,  # type: Optional[Participation]
        commit_sha,  # type: bytes
        path,  # type: str
):
    # type: (...) -> http.HttpResponse  # noqa
    """
    Check if a file should be accessible.  Then call for it if
    the permission is not denied.

    Order is important here.  An in-exam request takes precedence.

    Note: an access_role of "public" is equal to "unenrolled"
    """

    # check to see if the course is hidden
    check_course_state(course, participation)

    # set access to public (or unenrolled), student, etc
    if request.relate_exam_lockdown:
        access_kinds = ["in_exam"]
    else:
        from course.enrollment import get_participation_permissions
        access_kinds = [
            arg for perm, arg in get_participation_permissions(
                course, participation)
            if perm == pperm.access_files_for and arg is not None
        ]

    from course.content import is_repo_file_accessible_as

    # retrieve local path for the repo for the course
    with get_course_repo(course) as repo:
        if not is_repo_file_accessible_as(access_kinds, repo, commit_sha,
                                          path):
            raise PermissionDenied()

        return get_repo_file_response(repo, path, commit_sha)
Beispiel #31
0
def get_repo_file_backend(
        request,  # type: http.HttpRequest
        course,  # type: Course
        participation,  # type: Optional[Participation]
        commit_sha,  # type: bytes
        path,  # type: str
        ):
    # type: (...) -> http.HttpResponse  # noqa
    """
    Check if a file should be accessible.  Then call for it if
    the permission is not denied.

    Order is important here.  An in-exam request takes precedence.

    Note: an access_role of "public" is equal to "unenrolled"
    """

    # check to see if the course is hidden
    check_course_state(course, participation)

    # retrieve local path for the repo for the course
    repo = get_course_repo(course)

    # set access to public (or unenrolled), student, etc
    if request.relate_exam_lockdown:
        access_kinds = ["in_exam"]
    else:
        from course.enrollment import get_participation_permissions
        access_kinds = [
                arg
                for perm, arg in get_participation_permissions(course, participation)
                if perm == pperm.access_files_for
                and arg is not None]

    from course.content import is_repo_file_accessible_as
    if not is_repo_file_accessible_as(access_kinds, repo, commit_sha, path):
        raise PermissionDenied()

    return get_repo_file_response(repo, path, commit_sha)
Beispiel #32
0
    def __init__(self, request, course_identifier):
        # type: (http.HttpRequest, Text) -> None

        self.request = request
        self.course_identifier = course_identifier
        self._permissions_cache = None  # type: Optional[FrozenSet[Tuple[Text, Optional[Text]]]]  # noqa
        self._role_identifiers_cache = None  # type: Optional[List[Text]]
        self.old_language = None

        # using this to prevent nested using as context manager
        self._is_in_context_manager = False

        from course.models import Course  # noqa
        self.course = get_object_or_404(Course, identifier=course_identifier)

        from course.enrollment import get_participation_for_request
        self.participation = get_participation_for_request(
            request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.participation)

        self.repo = get_course_repo(self.course)

        try:
            sha = get_course_commit_sha(
                self.course,
                self.participation,
                repo=self.repo,
                raise_on_nonexistent_preview_commit=True)
        except CourseCommitSHADoesNotExist as e:
            from django.contrib import messages
            messages.add_message(request, messages.ERROR, str(e))

            sha = self.course.active_git_commit_sha.encode()

        self.course_commit_sha = sha
Beispiel #33
0
    def __init__(self, request, course_identifier):
        # type: (http.HttpRequest, Text) -> None

        self.request = request
        self.course_identifier = course_identifier
        self._permissions_cache = None  # type: Optional[FrozenSet[Tuple[Text, Optional[Text]]]]  # noqa
        self._role_identifiers_cache = None  # type: Optional[List[Text]]
        self.old_language = None

        # using this to prevent nested using as context manager
        self._is_in_context_manager = False

        from course.models import Course  # noqa
        self.course = get_object_or_404(Course, identifier=course_identifier)

        from course.enrollment import get_participation_for_request
        self.participation = get_participation_for_request(
                request, self.course)

        from course.views import check_course_state
        check_course_state(self.course, self.participation)

        self.repo = get_course_repo(self.course)

        try:
            sha = get_course_commit_sha(
                self.course, self.participation,
                repo=self.repo,
                raise_on_nonexistent_preview_commit=True)
        except CourseCommitSHADoesNotExist as e:
            from django.contrib import messages
            messages.add_message(request, messages.ERROR, str(e))

            sha = self.course.active_git_commit_sha.encode()

        self.course_commit_sha = sha
Beispiel #34
0
def _get_current_access_rule(participation, flow_id):
    course = participation.course

    from course.content import (
            get_course_repo,
            get_course_commit_sha,
            get_flow_desc)

    repo = get_course_repo(course)

    course_commit_sha = get_course_commit_sha(course, participation)

    try:
        flow_desc = get_flow_desc(repo, course,
                flow_id.encode(), course_commit_sha)
    except ObjectDoesNotExist:
        return None
    else:
        from course.utils import get_current_flow_access_rule
        from django.utils.timezone import now

        return get_current_flow_access_rule(course, participation,
                participation.role, flow_id, flow_desc,
                now(), rule_id=None, use_exceptions=False)
Beispiel #35
0
def get_flow_session_content(api_ctx, course_identifier):
    # type: (APIContext, Text) -> http.HttpResponse

    if not api_ctx.has_permission(pperm.view_gradebook):
        raise PermissionDenied("token role does not have required permissions")

    try:
        session_id_str = api_ctx.request.GET["flow_session_id"]
    except KeyError:
        raise APIError("must specify flow_id GET parameter")

    session_id = int(session_id_str)

    flow_session = get_object_or_404(FlowSession, id=session_id)

    if flow_session.course != api_ctx.course:
        raise PermissionDenied(
                "session's course does not match auth context")

    from course.content import get_course_repo
    from course.flow import adjust_flow_session_page_data, assemble_answer_visits

    with get_course_repo(api_ctx.course) as repo:
        from course.utils import FlowContext, instantiate_flow_page_with_ctx
        fctx = FlowContext(repo, api_ctx.course, flow_session.flow_id)

        adjust_flow_session_page_data(repo, flow_session, api_ctx.course.identifier,
                fctx.flow_desc)

        from course.flow import get_all_page_data
        all_page_data = get_all_page_data(flow_session)
        answer_visits = assemble_answer_visits(flow_session)

        pages = []
        for i, page_data in enumerate(all_page_data):
            page = instantiate_flow_page_with_ctx(fctx, page_data)

            assert i == page_data.page_ordinal

            page_data_json = dict(
                    ordinal=i,
                    page_type=page_data.page_type,
                    group_id=page_data.group_id,
                    page_id=page_data.page_id,
                    page_data=page_data.data,
                    title=page_data.title,
                    bookmarked=page_data.bookmarked,
                    )
            answer_json = None
            grade_json = None

            visit = answer_visits[i]
            if visit is not None:
                from course.page.base import PageContext
                pctx = PageContext(api_ctx.course, repo, fctx.course_commit_sha,
                        flow_session)
                norm_bytes_answer_tup = page.normalized_bytes_answer(
                        pctx, page_data.data, visit.answer)

                # norm_answer needs to be JSON-encodable
                norm_answer = None  # type: Any

                if norm_bytes_answer_tup is not None:
                    answer_file_ext, norm_bytes_answer = norm_bytes_answer_tup

                    if answer_file_ext in [".txt", ".py"]:
                        norm_answer = norm_bytes_answer.decode("utf-8")
                    elif answer_file_ext == ".json":
                        import json
                        norm_answer = json.loads(norm_bytes_answer)
                    else:
                        from base64 import b64encode
                        norm_answer = [answer_file_ext,
                                       b64encode(norm_bytes_answer).decode("utf-8")]

                answer_json = dict(
                    visit_time=visit.visit_time.isoformat(),
                    remote_address=repr(visit.remote_address),
                    user=visit.user.username if visit.user is not None else None,
                    impersonated_by=(visit.impersonated_by.username
                        if visit.impersonated_by is not None else None),
                    is_synthetic_visit=visit.is_synthetic,
                    answer_data=visit.answer,
                    answer=norm_answer,
                    )

                grade = visit.get_most_recent_grade()
                if grade is not None:
                    grade_json = dict(
                        grader=(grade.grader.username
                                if grade.grader is not None else None),
                        grade_time=grade.grade_time.isoformat(),
                        graded_at_git_commit_sha=grade.graded_at_git_commit_sha,
                        max_points=grade.max_points,
                        correctness=grade.correctness,
                        feedback=grade.feedback)

            pages.append({
                "page": page_data_json,
                "answer": answer_json,
                "grade": grade_json,
                })

    result = {
        "session": flow_session_to_json(flow_session),
        "pages": pages,
        }

    return http.JsonResponse(result, safe=False)
Beispiel #36
0
def get_media(request, course_identifier, commit_sha, media_path):
    course = get_object_or_404(Course, identifier=course_identifier)

    with get_course_repo(course) as repo:
        return get_repo_file_response(repo, "media/" + media_path,
                                      commit_sha.encode())
Beispiel #37
0
def get_flow_session_content(api_ctx, course_identifier):
    # type: (APIContext, Text) -> http.HttpResponse

    if not api_ctx.has_permission(pperm.view_gradebook):
        raise PermissionDenied("token role does not have required permissions")

    try:
        session_id_str = api_ctx.request.GET["flow_session_id"]
    except KeyError:
        raise APIError("must specify flow_id GET parameter")

    session_id = int(session_id_str)

    flow_session = get_object_or_404(FlowSession, id=session_id)

    if flow_session.course != api_ctx.course:
        raise PermissionDenied(
                "session's course does not match auth context")

    from course.content import get_course_repo
    from course.flow import adjust_flow_session_page_data, assemble_answer_visits

    with get_course_repo(api_ctx.course) as repo:
        from course.utils import FlowContext, instantiate_flow_page_with_ctx
        fctx = FlowContext(repo, api_ctx.course, flow_session.flow_id)

        adjust_flow_session_page_data(repo, flow_session, api_ctx.course.identifier,
                fctx.flow_desc)

        from course.flow import get_all_page_data
        all_page_data = get_all_page_data(flow_session)
        answer_visits = assemble_answer_visits(flow_session)

        pages = []
        for i, page_data in enumerate(all_page_data):
            page = instantiate_flow_page_with_ctx(fctx, page_data)

            assert i == page_data.page_ordinal

            page_data_json = dict(
                    ordinal=i,
                    page_type=page_data.page_type,
                    group_id=page_data.group_id,
                    page_id=page_data.page_id,
                    page_data=page_data.data,
                    title=page_data.title,
                    bookmarked=page_data.bookmarked,
                    )
            answer_json = None
            grade_json = None

            visit = answer_visits[i]
            if visit is not None:
                from course.page.base import PageContext
                pctx = PageContext(api_ctx.course, repo, fctx.course_commit_sha,
                        flow_session)
                norm_bytes_answer_tup = page.normalized_bytes_answer(
                        pctx, page_data.data, visit.answer)

                # norm_answer needs to be JSON-encodable
                norm_answer = None  # type: Any

                if norm_bytes_answer_tup is not None:
                    answer_file_ext, norm_bytes_answer = norm_bytes_answer_tup

                    if answer_file_ext in [".txt", ".py"]:
                        norm_answer = norm_bytes_answer.decode("utf-8")
                    elif answer_file_ext == ".json":
                        import json
                        norm_answer = json.loads(norm_bytes_answer)
                    else:
                        from base64 import b64encode
                        norm_answer = [answer_file_ext, b64encode(norm_bytes_answer)]

                answer_json = dict(
                    visit_time=visit.visit_time.isoformat(),
                    remote_address=repr(visit.remote_address),
                    user=visit.user.username if visit.user is not None else None,
                    impersonated_by=(visit.impersonated_by.username
                        if visit.impersonated_by is not None else None),
                    is_synthetic_visit=visit.is_synthetic,
                    answer_data=visit.answer,
                    answer=norm_answer,
                    )

                grade = visit.get_most_recent_grade()
                if grade is not None:
                    grade_json = dict(
                        grader=grade.grader,
                        grade_time=grade.grade_time.isoformat(),
                        graded_at_git_commit_sha=grade.graded_at_git_commit_sha,
                        max_points=grade.max_points,
                        correctness=grade.correctness,
                        feedback=grade.feedback)

            pages.append({
                "page": page_data_json,
                "answer": answer_json,
                "grade": grade_json,
                })

    result = {
        "session": flow_session_to_json(flow_session),
        "pages": pages,
        }

    return http.JsonResponse(result, safe=False)
Beispiel #38
0
def convert_flow_page_visit(stderr, fpv):
    course = fpv.flow_session.course

    from course.content import (get_course_repo, get_flow_desc,
                                get_flow_page_desc, instantiate_flow_page)
    repo = get_course_repo(course)
    flow_id = fpv.flow_session.flow_id
    commit_sha = course.active_git_commit_sha.encode()
    try:
        flow_desc = get_flow_desc(repo,
                                  course,
                                  flow_id,
                                  commit_sha,
                                  tolerate_tabs=True)
    except ObjectDoesNotExist:
        stderr.write("warning: no flow yaml file found for '%s' in '%s'" %
                     (flow_id, course.identifier))
        return

    try:
        page_desc = get_flow_page_desc(fpv.flow_session.flow_id, flow_desc,
                                       fpv.page_data.group_id,
                                       fpv.page_data.page_id)
    except ObjectDoesNotExist:
        stderr.write(
            f"warning: flow page visit {fpv.id}: no page yaml desc "
            "found for "
            f"'{flow_id}:{fpv.page_data.group_id}/{fpv.page_data.page_id}' "
            f"in '{course.identifier}'")
        return

    page = instantiate_flow_page(
        location="flow '%s', group, '%s', page '%s'" %
        (flow_id, fpv.page_data.group_id, fpv.page_data.page_id),
        repo=repo,
        page_desc=page_desc,
        commit_sha=commit_sha)

    from course.page.base import PageContext
    pctx = PageContext(course=course,
                       repo=repo,
                       commit_sha=commit_sha,
                       flow_session=fpv.flow_session,
                       page_uri=None)

    from course.page.upload import FileUploadQuestion
    from course.page.code import CodeQuestion

    if isinstance(page, FileUploadQuestion):
        content, mime_type = page.get_content_from_answer_data(fpv.answer)

        from django.core.files.base import ContentFile
        answer_data = page.file_to_answer_data(pctx, ContentFile(content),
                                               mime_type)
        fpv.answer = answer_data
        fpv.save()

        return True

    elif isinstance(page, CodeQuestion):
        code = page.get_code_from_answer_data(fpv.answer)
        answer_data = page.code_to_answer_data(pctx, code)
        fpv.answer = answer_data
        fpv.save()

        return True
    else:
        return False

    assert False
Beispiel #39
0
def grade_page_visit(visit, visit_grade_model=FlowPageVisitGrade, grade_data=None, graded_at_git_commit_sha=None):
    if not visit.is_submitted_answer:
        raise RuntimeError(_("cannot grade ungraded answer"))

    flow_session = visit.flow_session
    course = flow_session.course
    page_data = visit.page_data

    most_recent_grade = visit.get_most_recent_grade()
    if most_recent_grade is not None and grade_data is None:
        grade_data = most_recent_grade.grade_data

    from course.content import (
        get_course_repo,
        get_course_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 = get_flow_desc(repo, course, flow_session.flow_id, course_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=course_commit_sha,
    )

    assert page.expects_answer()
    if not page.is_answer_gradable():
        return

    from course.page import PageContext

    grading_page_context = PageContext(
        course=course, repo=repo, commit_sha=course_commit_sha, flow_session=flow_session
    )

    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

    bulk_feedback_json = None
    if answer_feedback is not None:
        grade.correctness = answer_feedback.correctness
        grade.feedback, bulk_feedback_json = answer_feedback.as_json()

    grade.save()

    update_bulk_feedback(page_data, grade, bulk_feedback_json)
Beispiel #40
0
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()