Exemple #1
0
 def grade(self,
           request,
           submission,
           no_penalties=False,
           url_name="exercise"):
     """
     Loads the exercise feedback page.
     """
     language = get_language()
     submission_url = update_url_params(
         api_reverse("submission-grader",
                     kwargs={'submission_id': submission.id}),
         get_graderauth_submission_params(submission),
     )
     url = self._build_service_url(language, request,
                                   submission.submitters.all(),
                                   submission.ordinal_number(), url_name,
                                   submission_url)
     try:
         return load_feedback_page(request,
                                   url,
                                   self,
                                   submission,
                                   no_penalties=no_penalties)
     except OSError as error:
         page = ExercisePage(self)
         msg = "Unable to grade the submission. %s: %s" % (
             error.__class__.__name__, error)
         page.errors.append(msg)
         return page
Exemple #2
0
 def __init__(self, *args: Any, **kwargs: Any) -> None:
     self.instance = kwargs.pop('instance')
     super().__init__(*args, **kwargs)
     self.fields['user_profiles'].widget.search_api_url = api_reverse(
         "user-list")
     if self.instance.sis_id:
         self.fields['sis'] = forms.BooleanField(
             required=False,
             label=_('LABEL_ENROLL_FROM_SIS'),
         )
Exemple #3
0
 def __init__(self, *args: Any, **kwargs: Any) -> None:
     course_instance = kwargs.get('instance').exercise.course_instance
     super().__init__(*args, **kwargs)
     self.fields['submitters'].widget.search_api_url = api_reverse(
         "course-students-list",
         kwargs={'course_id': course_instance.id},
     )
     self.fields[
         'submitters'].queryset = course_instance.get_student_profiles()
     self.fields[
         'submitters'].initial_queryset = self.instance.submitters.all()
Exemple #4
0
 def __init__(self, *args, **kwargs):
     course_instance = kwargs.get('instance').exercise.course_instance
     super().__init__(*args, **kwargs)
     self.fields['submitters'].widget.attrs[
         "data-search-api-url"] = api_reverse(
             "course-students-list",
             kwargs={'course_id': course_instance.id})
     self.fields[
         'submitters'].queryset = course_instance.get_student_profiles()
     self.fields[
         'submitters'].initial_queryset = self.instance.submitters.all()
Exemple #5
0
    def __init__(self, service, user, instance, host, title, context_id=None, link_id=None, add=None):
        self.service = service
        course = instance.course

        # Context and resource parameters.
        context_id = context_id or (host + instance.get_absolute_url())
        link_id = link_id or "aplus{:d}".format(service.pk)
        title = title or link_id

        student_id = self.external_student_id(user)

        # Determine user role.
        role = "Student"
        if course.is_teacher(user):
            role = "Instructor"
        elif instance.is_assistant(user):
            role = "TA,TeachingAssistant"

        self.parameters = add or {}
        self.parameters.update({

            "lti_version": "LTI-1p0",
            "lti_message_type": "basic-lti-launch-request",

            "resource_link_id": link_id,
            "resource_link_title": title,

            # User.
            "user_id": student_id,
            "roles": role,
            "lis_person_name_full": "{} {}".format(user.first_name, user.last_name),
            "lis_person_name_given": user.first_name,
            "lis_person_name_family": user.last_name,
            "lis_person_contact_email_primary": user.email,

            # Selected course.
            "context_id": context_id,
            "context_title": course.name,
            "context_label": course.code,

            "launch_presentation_locale": get_language(),

            "tool_consumer_instance_guid": host + "/aplus",
            "tool_consumer_instance_name": "A+ LMS",
        })

        if service.enable_api_access:
            self.parameters.update({
                # FIXME: we need request or full host with protocol here!
                'custom_context_api': '//' + host + api_reverse("course-detail", kwargs={'course_id': instance.id}),
                'custom_context_api_id': str(instance.id),
                'custom_user_api_token': user.userprofile.api_token,
            })
Exemple #6
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.fields['assistants'].initial_queryset = self.instance.assistants.all()
     self.fields['assistants'].widget.attrs["data-search-api-url"] = api_reverse("user-list")
     if self.instance and self.instance.visible_to_students:
         self.fields["url"].widget.attrs["readonly"] = "true"
         self.fields["url"].help_text = _("The URL identifier is locked "
             "while the course is visible to students.")
         self.fields["lifesupport_time"].help_text = _("Removes visibility "
             "of model answers for students.")
         self.fields["archive_time"].help_text = _("Removes possibility "
             "for students to return answers.")
Exemple #7
0
 def __init__(self, *args: Any, **kwargs: Any) -> None:
     course_instance = kwargs.pop('instance')
     super(DeadlineRuleDeviationForm, self).__init__(*args, **kwargs)
     self.fields["module"].queryset = CourseModule.objects.filter(
         course_instance=course_instance)
     self.fields["exercise"].queryset = BaseExercise.objects.filter(
         course_module__course_instance=course_instance)
     self.fields[
         'submitter'].queryset = course_instance.get_student_profiles()
     self.fields['submitter'].widget.search_api_url = api_reverse(
         "course-students-list",
         kwargs={'course_id': course_instance.id},
     )
Exemple #8
0
    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)
        self.fields['teachers'].initial = self.instance.teachers.all()
        self.fields['teachers'].initial_queryset = self.instance.teachers.all()
        self.fields['teachers'].widget.search_api_url = api_reverse(
            "user-list")
        self.fields['assistants'].initial = self.instance.assistants.all()
        self.fields[
            'assistants'].initial_queryset = self.instance.assistants.all()
        self.fields['assistants'].widget.search_api_url = api_reverse(
            "user-list")
        if self.instance and self.instance.visible_to_students:
            self.fields["url"].widget.attrs["readonly"] = "true"
            self.fields["url"].help_text = _(
                'COURSE_URL_IDENTIFIER_LOCKED_WHILE_COURSE_VISIBLE')
            self.fields["lifesupport_time"].help_text = _(
                'COURSE_REMOVES_MODEL_ANSWER_VISIBILITY_STUDENTS')
            self.fields["archive_time"].help_text = _(
                'COURSE_REMOVES_SUBMISSION_POSSIBILITY_STUDENTS')

        # If course is not connected to SIS system, disable the enroll checkbox
        if not self.instance.sis_id:
            self.fields['sis_enroll'].disabled = True
Exemple #9
0
 def __init__(self, *args, **kwargs):
     course_instance = kwargs.get('instance').course_instance
     super().__init__(*args, **kwargs)
     self.fields['members'].widget.attrs[
         "data-search-api-url"] = api_reverse(
             "course-students-list",
             kwargs={'course_id': course_instance.id})
     self.fields["members"].queryset = course_instance.get_student_profiles(
     )
     # Course staff may use this form for modifying and creating student groups.
     # If an existing group is being modified, its current members must be
     # set to the initial queryset.
     if self.instance.id:
         self.fields[
             "members"].initial_queryset = self.instance.members.all()
Exemple #10
0
 def grade(self, request, submission, no_penalties=False, url_name="exercise"):
     """
     Loads the exercise feedback page.
     """
     language = get_language()
     submission_url = update_url_params(
         api_reverse("submission-grader", kwargs={
             'submission_id': submission.id
         }),
         get_graderauth_submission_params(submission),
     )
     url = self._build_service_url(
         language, request, submission.submitters.all(),
         submission.ordinal_number(), url_name, submission_url
     )
     return load_feedback_page(
         request, url, self, submission, no_penalties=no_penalties
     )
Exemple #11
0
 def get_load_url(self, language, request, students, url_name="exercise"):
     if self.id:
         if request.user.is_authenticated:
             user = request.user
             submission_count = self.get_submissions_for_student(
                 user.userprofile, exclude_errors=True).count()
         else:
             user = None
             submission_count = 0
         # Make grader async URL for the currently authenticated user.
         # The async handler will handle group selection at submission time.
         submission_url = update_url_params(
             api_reverse("exercise-grader", kwargs={'exercise_id':
                                                    self.id}),
             get_graderauth_exercise_params(self, user),
         )
         return self._build_service_url(language, request, students,
                                        submission_count + 1, url_name,
                                        submission_url)
     return super().get_load_url(language, request, students, url_name)
Exemple #12
0
 def get_load_url(self, language, request, students, url_name="exercise"):
     if self.id:
         if request.user.is_authenticated():
             user = request.user
             submission_count = self.get_submissions_for_student(user.userprofile).count()
         else:
             user = None
             submission_count = 0
         # Make grader async URL for the currently authenticated user.
         # The async handler will handle group selection at submission time.
         submission_url = update_url_params(
             api_reverse("exercise-grader", kwargs={
                 'exercise_id': self.id
             }),
             get_graderauth_exercise_params(self, user),
         )
         return self._build_service_url(
             language, request, students,
             submission_count + 1, url_name, submission_url
         )
     return super().get_load_url(language, request, students, url_name)
Exemple #13
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.fields['user_profiles'].widget.attrs[
         "data-search-api-url"] = api_reverse("user-list")
Exemple #14
0
 def __init__(self, *args: Any, **kwargs: Any) -> None:
     course_instance = kwargs.pop('instance')
     super(SelectUsersForm, self).__init__(*args, **kwargs)
     self.fields['user'].widget.search_api_url = api_reverse(
         "course-students-list", kwargs={'course_id': course_instance.id})
     self.fields['user'].queryset = course_instance.get_student_profiles()
Exemple #15
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.fields['teachers'].initial_queryset = self.instance.teachers.all()
     self.fields['teachers'].widget.attrs[
         "data-search-api-url"] = api_reverse("user-list")
Exemple #16
0
    def __init__(self,
                 service,
                 user,
                 instance,
                 host,
                 title,
                 context_id=None,
                 link_id=None,
                 add=None):
        self.service = service
        course = instance.course

        # Context and resource parameters.
        context_id = context_id or (host + instance.get_absolute_url())
        link_id = link_id or "aplus{:d}".format(service.pk)
        title = title or link_id

        student_id = self.external_student_id(user)

        # Determine user role.
        role = "Student"
        if course.is_teacher(user):
            role = "Instructor"
        elif instance.is_assistant(user):
            role = "TA,TeachingAssistant"

        self.parameters = add or {}
        self.parameters.update({
            "lti_version":
            "LTI-1p0",
            "lti_message_type":
            "basic-lti-launch-request",
            "resource_link_id":
            link_id,
            "resource_link_title":
            title,

            # User.
            "user_id":
            student_id,
            "roles":
            role,
            "lis_person_name_full":
            "{} {}".format(user.first_name, user.last_name),
            "lis_person_name_given":
            user.first_name,
            "lis_person_name_family":
            user.last_name,
            "lis_person_contact_email_primary":
            user.email,

            # Selected course.
            "context_id":
            context_id,
            "context_title":
            course.name,
            "context_label":
            course.code,
            "launch_presentation_locale":
            get_language(),
            "tool_consumer_instance_guid":
            host + "/aplus",
            "tool_consumer_instance_name":
            "A+ LMS",
        })

        if service.enable_api_access:
            self.parameters.update({
                # FIXME: we need request or full host with protocol here!
                'custom_context_api':
                '//' + host + api_reverse("course-detail",
                                          kwargs={'course_id': instance.id}),
                'custom_context_api_id':
                str(instance.id),
                'custom_user_api_token':
                user.userprofile.api_token,
            })
Exemple #17
0
 def __init__(self, *args, **kwargs):
     course_instance = kwargs.pop('instance')
     super(SelectUsersForm, self).__init__(*args, **kwargs)
     self.fields['user'].widget.attrs["data-search-api-url"] = api_reverse(
         "course-students-list", kwargs={'course_id': course_instance.id})
     self.fields['user'].queryset = course_instance.get_student_profiles()
Exemple #18
0
    def __init__(self, service, user, instance, host, title, context_id=None, link_id=None, add=None):
        self.service = service
        course = instance.course
        # Context and resource parameters.
        context_id = context_id or (host + instance.get_absolute_url())
        link_id = link_id or "aplus{:d}".format(service.pk)
        title = title or link_id

        # Gather user information
        if service.is_anonymous:
            # Anonymize user information
            enrollment = Enrollment.objects.filter(course_instance=instance, user_profile=user.userprofile).first()
            if not enrollment:
                raise PermissionDenied()
            # Creates anon name and id for pre-pseudonymisation Enrollments
            if not (enrollment.anon_name or enrollment.anon_id):
                # the model's post_save functions take care of the creation
                enrollment.save()
            student_id = "a" + enrollment.anon_id # a for anonymous
            full_name = enrollment.anon_name
            given_name, sep, family_name = full_name.rpartition(" ")
            if not given_name:
                given_name = "Anonymous"
            email = "anonymous-{}@aplus.invalid".format(enrollment.anon_id)
        else:
            student_id = "i" + self.external_student_id(user) # i for internal
            full_name = "{} {}".format(user.first_name, user.last_name)
            given_name = user.first_name
            family_name = user.last_name
            email = user.email

        # Determine user role.
        role = "Student"
        if course.is_teacher(user):
            role = "Instructor"
        elif instance.is_assistant(user):
            role = "TA,TeachingAssistant"

        self.parameters = add or {}
        self.parameters.update({

            "lti_version": "LTI-1p0",
            "lti_message_type": "basic-lti-launch-request",

            "resource_link_id": link_id,
            "resource_link_title": title,

            # User.
            "user_id": student_id,
            "roles": role,
            "lis_person_name_full": full_name,
            "lis_person_name_given": given_name,
            "lis_person_name_family": family_name,
            "lis_person_contact_email_primary": email,

            # Selected course.
            "context_id": context_id,
            "context_title": course.name,
            "context_label": course.code,

            "launch_presentation_locale": get_language(),

            "tool_consumer_instance_guid": host + "/aplus",
            "tool_consumer_instance_name": "A+ LMS",
        })

        if service.api_access:
            self.parameters.update({
                # FIXME: we need request or full host with protocol here!
                'custom_context_api': '//' + host + api_reverse("course-detail", kwargs={'course_id': instance.id}),
                'custom_context_api_id': str(instance.id),
                'custom_user_api_token': user.userprofile.api_token,
            })
Exemple #19
0
    def __init__(self, service, user, instance, request, title, context_id=None, link_id=None, add=None, exercise=None):
        self.service = service
        course = instance.course
        # Context and resource parameters.
        context_id = context_id or (request.get_host() + instance.get_absolute_url())
        link_id = link_id or "aplus{:d}".format(service.pk)
        title = title or link_id

        # Gather user information
        user_id, given_name, family_name, full_name, email = self.user_info(instance, user)

        # Determine user role.
        role = "Learner,Student"
        # Student is not a standard role name, but it has been used here before
        if course.is_teacher(user):
            role = "Instructor"
        elif instance.is_assistant(user):
            role = "TA,TeachingAssistant" # "TA" is not a standard role

        self.parameters = add or {}
        self.parameters.update({

            "lti_version": "LTI-1p0",
            "lti_message_type": "basic-lti-launch-request",

            "resource_link_id": link_id,
            "resource_link_title": title,

            # User.
            "user_id": user_id,
            "roles": role,
            "lis_person_name_full": full_name,
            "lis_person_name_given": given_name,
            "lis_person_name_family": family_name,
            "lis_person_contact_email_primary": email,

            # Selected course.
            "context_id": context_id,
            "context_title": course.name,
            "context_label": course.code,

            "launch_presentation_locale": get_language(),
            "launch_presentation_document_target":
                "iframe" if exercise and exercise.open_in_iframe else "window",
            "launch_presentation_return_url": request.scheme + '://' + request.get_host() + instance.get_absolute_url(),

            "tool_consumer_instance_guid": request.get_host() + "/aplus",
            "tool_consumer_instance_name": "A+ LMS",
        })

        if service.api_access:
            self.parameters.update({
                'custom_context_api': request.scheme + '://' + request.get_host() + api_reverse("course-detail", kwargs={'course_id': instance.id}),
                'custom_context_api_id': str(instance.id),
                'custom_user_api_token': user.userprofile.api_token,
            })

        if exercise:
            # LTI 1.1 Tool Provider may return grades to A+ (Tool Consumer)
            self.parameters.update({
                # Outcome Service requests from the LTI Tool Provider include the
                # sourcedid from the launch request. It is used to create new submissions
                # for storing the points of the user.
                "lis_result_sourcedid": "{}-{}".format(exercise.pk, user_id),
                # The LTI Tool Provider posts Outcome Service requests to this URL (i.e., points for a submission)
                "lis_outcome_service_url": reverse('lti-outcomes', request=request,
                                                   kwargs={'version': api_settings.DEFAULT_VERSION}),
            })
Exemple #20
0
    def __init__(self, service, user, instance, request, title, context_id=None, link_id=None, add=None, exercise=None):
        self.service = service
        course = instance.course
        base_url_parts = urlsplit(settings.BASE_URL)
        # Context and resource parameters.
        context_id = context_id or (base_url_parts.netloc + instance.get_absolute_url())
        link_id = link_id or "aplus{:d}".format(service.pk)
        title = title or link_id

        # Gather user information
        user_id, given_name, family_name, full_name, email = self.user_info(instance, user)

        # Determine user role.
        role = "Learner,Student"
        # Student is not a standard role name, but it has been used here before
        if course.is_teacher(user):
            role = "Instructor"
        elif instance.is_assistant(user):
            role = "TA,TeachingAssistant" # "TA" is not a standard role

        self.parameters = add or {}
        self.parameters.update({

            "lti_version": "LTI-1p0",
            "lti_message_type": "basic-lti-launch-request",

            "resource_link_id": link_id,
            "resource_link_title": title,

            # User.
            "user_id": user_id,
            "roles": role,
            "lis_person_name_full": full_name,
            "lis_person_name_given": given_name,
            "lis_person_name_family": family_name,
            "lis_person_contact_email_primary": email,

            # Selected course.
            "context_id": context_id,
            "context_title": course.name,
            "context_label": course.code,

            "launch_presentation_locale": get_language(),
            "launch_presentation_document_target":
                "iframe" if exercise and exercise.open_in_iframe else "window",
            "launch_presentation_return_url": urljoin(settings.BASE_URL, instance.get_absolute_url()),

            "tool_consumer_instance_guid": base_url_parts.netloc + "/aplus",
            "tool_consumer_instance_name": settings.BRAND_NAME,
            "tool_consumer_instance_description": settings.BRAND_DESCRIPTION,
            "tool_consumer_instance_url": settings.BASE_URL,
        })

        if service.api_access:
            self.parameters.update({
                'custom_context_api': settings.BASE_URL + api_reverse("course-detail", kwargs={'course_id': instance.id}),
                'custom_context_api_id': str(instance.id),
                'custom_user_api_token': user.userprofile.api_token,
            })

        if exercise:
            # LTI 1.1 Tool Provider may return grades to A+ (Tool Consumer)
            self.parameters.update({
                # Outcome Service requests from the LTI Tool Provider include the
                # sourcedid from the launch request. It is used to create new submissions
                # for storing the points of the user.
                "lis_result_sourcedid": "{}-{}".format(exercise.pk, user_id),
                # The LTI Tool Provider posts Outcome Service requests to this URL (i.e., points for a submission)
                "lis_outcome_service_url": reverse('lti-outcomes', request=request,
                                                   kwargs={'version': api_settings.DEFAULT_VERSION}),
            })