示例#1
0
    def password(self, request):
        """Change the password of a user.

        Arguments:
        request -- request data
            new_password -- new password of the user
            old_password -- current password of the user

        Returns
        On failure:
            unauthorized -- when the user is not logged in
            bad request -- when the password is invalid
        On success:
            success -- with a success description
        """
        new_password, old_password = utils.required_params(request.data, 'new_password', 'old_password')

        if not request.user.check_password(old_password):
            return response.bad_request('Wrong password.')

        if validators.validate_password(new_password):
            return response.bad_request(validators.validate_password(new_password))

        request.user.set_password(new_password)
        request.user.save()
        return response.success(description='Successfully changed the password.')
示例#2
0
    def partial_update(self, request, *args, **kwargs):
        """Update an existing course.

        Arguments:
        request -- request data
            data -- the new data for the course
        pk -- course ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the course does not exist
            forbidden -- when the user is not in the course
            unauthorized -- when the user is unauthorized to edit the course
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new course data
        """
        course_id, = utils.required_typed_params(kwargs, (int, 'pk'))
        course = Course.objects.get(pk=course_id)

        request.user.check_permission('can_edit_course_details', course)

        data = request.data
        if 'lti_id' in data:
            factory.make_lti_ids(lti_id=data['lti_id'],
                                 for_model=Lti_ids.COURSE,
                                 course=course)

        serializer = self.serializer_class(course, data=data, partial=True)
        if not serializer.is_valid():
            response.bad_request()
        serializer.save()
        return response.success({'course': serializer.data})
示例#3
0
    def partial_update(self, request, *args, **kwargs):
        """Update instance details.

        Arguments:
        request -- request data
            data -- the new data for the journal

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            forbidden -- User not allowed to edit instance
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new instance details
        """
        if not request.user.is_superuser:
            return response.forbidden(
                'You are not allowed to edit instance details.')

        try:
            instance = Instance.objects.get(pk=1)
        except Instance.DoesNotExist:
            instance = factory.make_instance()

        req_data = request.data
        serializer = InstanceSerializer(instance, data=req_data, partial=True)
        if not serializer.is_valid():
            response.bad_request()
        serializer.save()

        return response.success({'instance': serializer.data})
示例#4
0
    def partial_update(self, request, *args, **kwargs):
        """Update an existing course group.

        Arguments:
        request -- request data
            name -- group name
        pk -- group ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the course does not exists
            forbidden -- when the user is not in the course
            unauthorized -- when the user is unauthorized to edit the course
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new course data
        """
        name, = utils.required_params(request.data, 'name')

        group_id, = utils.required_typed_params(kwargs, (int, 'pk'))
        group = Group.objects.get(pk=group_id)
        course = group.course

        request.user.check_permission('can_edit_course_user_group', course)

        if not name:
            return response.bad_request('Group name is not allowed to be empty.')

        serializer = GroupSerializer(group, data={'name': name}, partial=True)
        if not serializer.is_valid():
            return response.bad_request()

        serializer.save()
        return response.success({'group': serializer.data})
示例#5
0
    def partial_update(self, request, *args, **kwargs):
        """Update an existing assignment.

        Arguments:
        request -- request data
            data -- the new data for the assignment
        pk -- assignment ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the assignment does not exist
            forbidden -- User not allowed to edit this assignment
            unauthorized -- when the user is unauthorized to edit the assignment
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new assignment data

        """
        # Get data
        pk, = utils.required_typed_params(kwargs, (int, 'pk'))
        assignment = Assignment.objects.get(pk=pk)
        published, = utils.optional_params(request.data, 'published')

        # Remove data that must not be changed by the serializer
        req_data = request.data
        req_data.pop('published', None)
        if not (request.user.is_superuser or request.user == assignment.author):
            req_data.pop('author', None)

        response_data = {}

        # Publish is possible and asked for
        if published:
            request.user.check_permission('can_publish_grades', assignment)
            self.publish(request, assignment)
            response_data['published'] = published

        # Update assignment data is possible and asked for
        if req_data:
            if 'lti_id' in req_data:
                factory.make_lti_ids(lti_id=req_data['lti_id'], for_model=Lti_ids.ASSIGNMENT, assignment=assignment)

            # If a entry has been submitted to one of the journals of the journal it cannot be unpublished
            if assignment.is_published and 'is_published' in req_data and not req_data['is_published'] and \
               Entry.objects.filter(node__journal__assignment=assignment).exists():
                return response.bad_request(
                    'You are not allowed to unpublish an assignment that already has submissions.')

            serializer = AssignmentSerializer(assignment, data=req_data, context={'user': request.user}, partial=True)
            if not serializer.is_valid():
                response.bad_request()
            serializer.save()
            response_data['assignment'] = serializer.data

        return response.success(response_data)
示例#6
0
    def upload(self, request):
        """Upload a user file.

        Checks available space for the user and max file size.
        If the file is intended for an entry, checks if the user can edit the entry.
        At the time of creation, the UserFile is uploaded but not attached to an entry yet. This UserFile is treated
        as temporary untill the actual entry is created and the node and content are updated.

        Arguments:
        request -- request data
            file -- filelike data
            assignment_id -- assignment ID
            content_id -- content ID, should be null when creating a NEW entry.

        Returns
        On failure:
            unauthorized -- when the user is not logged in
            bad_request -- when the file, assignment was not found or the validation failed.
        On success:
            success -- name of the file.
        """
        assignment_id, content_id = utils.required_params(
            request.POST, 'assignment_id', 'content_id')
        assignment = Assignment.objects.get(pk=assignment_id)

        request.user.check_can_view(assignment)

        if not (request.FILES and 'file' in request.FILES):
            return response.bad_request(
                'No accompanying file found in the request.')
        validators.validate_user_file(request.FILES['file'], request.user)

        if content_id == 'null':
            factory.make_user_file(request.FILES['file'], request.user,
                                   assignment)
        else:
            try:
                content = Content.objects.get(
                    pk=int(content_id),
                    entry__node__journal__user=request.user)
            except Content.DoesNotExist:
                return response.bad_request(
                    'Content with id {:s} was not found.'.format(content_id))

            request.user.check_can_edit(content.entry)
            factory.make_user_file(request.FILES['file'],
                                   request.user,
                                   assignment,
                                   content=content)

        return response.success(description='Successfully uploaded {:s}.'.
                                format(request.FILES['file'].name))
示例#7
0
    def create(self, request):
        """Create course role.

        Arguments:
        request -- request data
            course_id -- course ID
            name -- role name
            permissions -- permissions to change (default everything is false)

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the course does not exist
            forbidden -- when the user is not in the course
            forbidden -- when the user is unauthorized to edit its roles
        On success:
            success -- newly created course

        """
        course_id, name, permissions = utils.required_params(
            request.data, 'course_id', 'name', 'permissions')
        course = Course.objects.get(pk=course_id)

        # TODO: P Is this the right permission
        request.user.check_permission('can_edit_course_roles', course)

        try:
            role = factory.make_role_default_no_perms(name, course,
                                                      **permissions)
        except Exception:
            return response.bad_request()

        serializer = RoleSerializer(role, many=False)
        return response.created({'role': serializer.data})
示例#8
0
    def partial_update(self, request, *args, **kwargs):
        """Update the preferences of a user.

        Arguments:
        request -- request data
        pk -- user ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            forbidden -- when the user is not superuser or pk is not the same as the logged in user
            not found -- when the user doesnt exist
            bad request -- when the data is invalid
        On success:
            success -- with the updated preferences
        """
        pk, = utils.required_typed_params(kwargs, (int, 'pk'))
        if not (request.user.pk == pk or request.user.is_superuser):
            return response.forbidden('You are not allowed to change this users preferences.')

        preferences = Preferences.objects.get(user=pk)
        serializer = PreferencesSerializer(preferences, data=request.data, partial=True)

        if not serializer.is_valid():
            return response.bad_request('Invalid preference data provided.')

        serializer.save()

        return response.success({'preferences': serializer.data})
示例#9
0
    def create(self, request):
        """Create a new course group.

        Arguments:
        request -- the request that was send with
            name -- name of the course group
            course_id -- course ID of the course
            lti_id -- (optional) lti_id to link the course to

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            forbidden -- when the user has no permission to create new groups
        On success, with the course group.
        """
        name, course_id = utils.required_params(request.data, "name", "course_id")
        lti_id, = utils.optional_params(request.data, 'lti_id')

        course = Course.objects.get(pk=course_id)

        request.user.check_permission('can_add_course_user_group', course)

        if lti_id and Group.objects.filter(lti_id=lti_id, course=course).exists():
            return response.bad_request('Course group with the desired name already exists.')

        course_group = factory.make_course_group(name, course, lti_id)
        serializer = GroupSerializer(course_group, many=False)
        return response.created({'group': serializer.data})
示例#10
0
def recover_password(request):
    """Handles a reset password request.

    Arguments:
        username -- User claimed username.
        recovery_token -- Django stateless token, invalidated after password change or after a set time
            (by default three days).
        new_password -- The new user desired password.

    Updates password if the recovery_token is valid.
    """
    username, recovery_token, new_password = utils.required_params(
        request.data, 'username', 'recovery_token', 'new_password')

    user = User.objects.get(username=username)

    recovery_token, = utils.required_params(request.data, 'recovery_token')
    token_generator = PasswordResetTokenGenerator()
    if not token_generator.check_token(user, recovery_token):
        return response.bad_request('Invalid recovery token.')

    validators.validate_password(new_password)

    user.set_password(new_password)
    user.save()

    return response.success(
        description='Successfully changed the password, you can now log in.')
示例#11
0
    def destroy(self, request, pk):
        """Delete course role.

        Arguments:
        request -- request data
            name -- role name
        pk -- course ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            forbidden -- when the user is not in the course
            forbidden -- when the user is unauthorized to edit its roles
        On success:
            success -- newly created course

        """
        name, = utils.required_typed_params(request.query_params,
                                            (str, 'name'))
        course = Course.objects.get(pk=pk)

        # Users can only delete course roles with can_edit_course_roles
        request.user.check_permission('can_edit_course_roles', course)

        if name in ['Student', 'TA', 'Teacher']:
            return response.bad_request(
                'Default roles "Student", "TA" and "Teacher" cannot be deleted.'
            )

        Role.objects.get(name=name, course=pk).delete()
        return response.success(
            description='Successfully deleted role from course.')
示例#12
0
def forgot_password(request):
    """Handles a forgot password request.

    Arguments:
        username -- User claimed username.
        email -- User claimed email.
        token -- Django stateless token, invalidated after password change or after a set time (by default three days).

    Generates a recovery token if a matching user can be found by either the prodived username or email.
    """
    username, email = utils.optional_params(request.data, 'username', 'email')

    # We are retrieving the username based on either the username or email
    try:
        user = User.objects.get(username=username)
        email = 'your recovery address'
    except User.DoesNotExist:
        if email is None or email == '':
            return response.not_found('Invalid email address provided.')
        user = User.objects.get(email=email)

    if not user.email:
        return response.bad_request(
            description='The provided account has no known email address.')

    send_password_recovery_link.delay(user.pk)
    return response.success(
        description='An email was sent to {}, please check your inbox for further instructions.'.format(email))
示例#13
0
    def download(self, request, pk):
        """Get a user file by name if it exists.

        Arguments:
        request -- the request that was sent
            file_name -- filename to download
        pk -- user ID

        Returns
        On failure:
            unauthorized -- when the user is not logged in
            bad_request -- when the file was not found
            forbidden -- when its not a superuser nor their own data
        On success:
            success -- a zip file of all the userdata with all their files
        """
        if int(pk) == 0:
            pk = request.user.id

        file_name, entry_id, node_id, content_id = utils.required_typed_params(
            request.query_params, (str, 'file_name'), (int, 'entry_id'), (int, 'node_id'), (int, 'content_id'))

        try:
            user_file = UserFile.objects.get(author=pk, file_name=file_name, entry=entry_id, node=node_id,
                                             content=content_id)

            if user_file.author != request.user:
                request.user.check_permission('can_view_all_journals', user_file.assignment)

        except (UserFile.DoesNotExist, ValueError):
            return response.bad_request(file_name + ' was not found.')

        return response.file(user_file)
示例#14
0
    def destroy(self, request, pk):
        """Delete a user.

        Arguments:
        request -- request data
        pk -- user ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the user does not exist
        On success:
            success -- deleted message
        """
        if not request.user.is_superuser:
            return response.forbidden('You are not allowed to delete a user.')

        if int(pk) == 0:
            pk = request.user.id

        user = User.objects.get(pk=pk)

        if len(User.objects.filter(is_superuser=True)) == 1:
            return response.bad_request('There is only 1 superuser left and therefore cannot be deleted')

        user.delete()
        return response.deleted(description='Sucesfully deleted user.')
示例#15
0
    def process_exception(self, request, exception):
        # Generic exception
        if isinstance(exception, VLEBadRequest):
            return response.bad_request(str(exception))

        # Django exceptions
        elif isinstance(exception, ObjectDoesNotExist):
            return response.not_found('{0} does not exist.'.format(
                str(exception).split()[0]))
        elif isinstance(exception, ValidationError):
            return response.validation_error(exception)

        # Variable exceptions
        elif isinstance(exception, VLEMissingRequiredKey):
            return response.key_error(*exception.keys)
        elif isinstance(exception, VLEMissingRequiredField):
            return response.bad_request(str(exception))
        elif isinstance(exception, VLEParamWrongType):
            return response.value_error(str(exception))

        # Permission exceptions
        elif isinstance(exception, VLEParticipationError):
            return response.forbidden(str(exception))
        elif isinstance(exception, VLEPermissionError):
            return response.forbidden(str(exception))
        elif isinstance(exception, VLEUnverifiedEmailError):
            return response.forbidden(str(exception))

        # Programming exceptions
        elif isinstance(exception, VLEProgrammingError):
            return response.internal_server_error(str(exception))
        elif isinstance(exception, SMTPAuthenticationError):
            return response.internal_server_error(
                'Mailserver is not configured correctly, please contact a server admin.'
            )

        # LTI exceptions
        elif isinstance(exception, jwt.exceptions.ExpiredSignatureError):
            return response.forbidden(
                'The LTI instance link has expired, 15 minutes have passed. Please try again.'
            )
        elif isinstance(exception, jwt.exceptions.InvalidSignatureError):
            return response.unauthorized(
                'Invalid LTI parameters given. Please retry from your LTI instance or notify a server admin.'
            )
示例#16
0
    def admin_update(self, request, journal):
        req_data = request.data
        if 'published' in req_data:
            del req_data['published']
        serializer = JournalSerializer(journal, data=req_data, partial=True)
        if not serializer.is_valid():
            return response.bad_request()
        serializer.save()

        return response.success({'journal': serializer.data})
示例#17
0
    def partial_update(self, request, *args, **kwargs):
        """Update an existing journal.

        Arguments:
        request -- request data
            data -- the new data for the journal
        pk -- journal ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the journal does not exist
            forbidden -- User not allowed to edit this journal
            unauthorized -- when the user is unauthorized to edit the journal
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new journal data

        """
        pk, = utils.required_typed_params(kwargs, (int, 'pk'))
        journal = Journal.objects.get(pk=pk)

        request.user.check_can_view(journal)

        published, = utils.optional_params(request.data, 'published')
        if published:
            request.user.check_permission('can_publish_grades',
                                          journal.assignment)
            return self.publish(request, journal)

        if not request.user.is_superuser:
            return response.forbidden(
                'You are not allowed to edit this journal.')

        req_data = request.data
        if 'published' in req_data:
            del req_data['published']
        serializer = JournalSerializer(journal, data=req_data, partial=True)
        if not serializer.is_valid():
            response.bad_request()
        serializer.save()

        return response.success({'journal': serializer.data})
示例#18
0
def request_email_verification(request):
    """Request an email with a verifcation link for the users email address."""
    if request.user.verified_email:
        return response.bad_request(
            description='Email address already verified.')

    email_handling.send_email_verification_link(request.user)
    return response.success(
        description=
        'An email was sent to {}, please follow the email for instructions.'.
        format(request.user.email))
示例#19
0
    def destroy(self, request, *args, **kwargs):
        """Delete an existing assignment from a course.

        Arguments:
        request -- request data
            course_id -- the course ID of course this assignment belongs to
        pk -- assignment ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the assignment or course does not exist
            unauthorized -- when the user is not logged in
            forbidden -- when the user cannot delete the assignment
        On success:
            success -- with a message that the course was deleted

        """
        assignment_id, = utils.required_typed_params(kwargs, (int, 'pk'))
        course_id, = utils.required_typed_params(request.query_params,
                                                 (int, 'course_id'))
        assignment = Assignment.objects.get(pk=assignment_id)
        course = Course.objects.get(pk=course_id)

        request.user.check_permission('can_delete_assignment', course)

        intersecting_assignment_lti_id = assignment.get_course_lti_id(course)
        if intersecting_assignment_lti_id:
            if assignment.active_lti_id == intersecting_assignment_lti_id and len(
                    assignment.lti_id_set) > 1:
                return response.bad_request(
                    'This assignment cannot be removed from this course, since it is'
                    + ' currently configured for grade passback to the LMS')
            course.assignment_lti_id_set.remove(intersecting_assignment_lti_id)
            assignment.lti_id_set.remove(intersecting_assignment_lti_id)
            course.save()

        assignment.courses.remove(course)
        assignment.save()

        if assignment.active_lti_id is not None and assignment.active_lti_id in course.assignment_lti_id_set:
            course.assignment_lti_id_set.remove(assignment.active_lti_id)
            course.save()

        # If the assignment is only connected to one course, delete it completely
        if assignment.courses.count() == 0:
            assignment.delete()
            return response.success(
                description='Successfully deleted the assignment.')
        else:
            return response.success(
                description='Successfully removed the assignment from {}.'.
                format(str(course)))
示例#20
0
    def partial_update(self, request, pk):
        """Updates course roles.

        Arguments:
        request -- request data
            roles -- each role of the course that needs to be updated
        pk -- course ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the course does not exist
            forbidden -- when the user is not in the course
            forbidden -- when the user is unauthorized to edit its roles
            bad_request -- if
        On success:
            success -- list of all the roles in the course

        """
        course = Course.objects.get(pk=pk)

        request.user.check_permission('can_edit_course_roles', course)

        roles_response = []
        roles, = utils.required_params(request.data, 'roles')
        for new_role in roles:
            try:
                role = Role.objects.get(name=new_role['name'], course=course)
            except Role.DoesNotExist:
                role = factory.make_role_default_no_perms(
                    new_role['name'], course)

            serializer = RoleSerializer(role, data=new_role, partial=True)
            if not serializer.is_valid():
                response.bad_request()
            serializer.save()

            roles_response.append(serializer.data)
        return response.success({'roles': roles_response})
示例#21
0
def update_lti_groups(request, jwt_params):
    user = request.user
    lti_params = decode_lti_params(jwt_params)
    if user != User.objects.get(lti_id=lti_params['user_id']):
        return response.forbidden(
            "The user specified that should be logged in according to the request is not the logged in user."
        )

    role = lti.roles_to_list(lti_params)
    course = lti.update_lti_course_if_exists(lti_params, user, role)
    if course:
        return response.success()
    else:
        return response.bad_request('Course not found')
示例#22
0
    def partial_update(self, request, *args, **kwargs):
        """Update an existing comment.

        Arguments:
        request -- request data
            text -- comment text
        pk -- comment ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the comment does not exist
            forbidden -- when the user is not allowed to comment
            unauthorized -- when the user is unauthorized to edit the assignment
        On success:
            success -- with the updated comment

        """
        comment_id, = utils.required_typed_params(kwargs, (int, 'pk'))

        comment = Comment.objects.get(pk=comment_id)
        journal = comment.entry.node.journal
        assignment = journal.assignment

        request.user.check_permission('can_comment', assignment)
        request.user.check_can_view(journal)

        if not (comment.author.id == request.user.id or request.user.is_superuser):
            return response.forbidden('You are not allowed to edit this comment.')

        text, = utils.required_params(request.data, 'text')
        serializer = CommentSerializer(
            comment, data={'text': text}, partial=True)
        if not serializer.is_valid():
            response.bad_request()
        serializer.save()
        return response.success({'comment': serializer.data})
示例#23
0
    def create(self, request):
        """Set a new grade for an entry.

        Arguments:
        request -- request data
            entry_id -- entry ID
            grade -- grade
            published -- published state

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            key_error -- missing keys
            not_found -- could not find the entry, author or assignment

        On success:
            success -- with the assignment data
        """
        entry_id, grade, published = utils.required_typed_params(
            request.data, (int, 'entry_id'), (float, 'grade'),
            (bool, 'published'))

        entry = Entry.objects.get(pk=entry_id)
        journal = entry.node.journal
        assignment = journal.assignment

        request.user.check_permission('can_grade', assignment)

        if published:
            request.user.check_permission('can_publish_grades', assignment)

        if grade is not None and grade < 0:
            return response.bad_request(
                'Grade must be greater than or equal to zero.')

        grade = factory.make_grade(entry, request.user.pk, grade, published)

        if published:
            Comment.objects.filter(entry=entry).update(published=True)

        # TODO: Is the lti flag ever used? Else move replace_result to celery
        return response.created({
            'entry':
            EntrySerializer(entry, context={
                'user': request.user
            }).data,
            'lti':
            lti_grade.replace_result(journal)
        })
示例#24
0
    def create(self, request):
        """Add a user to a course.

        Arguments:
        request -- request data
            user_id -- user ID
            course_id -- course ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when course or user is not found
            forbidden -- when the logged in user is not connected to the course
            bad request -- when the new user is already connected to the course
            not found -- when the role doesnt exist
        On success:
            success -- success message
        """
        user_id, course_id = utils.required_typed_params(
            request.data, (int, 'user_id'), (int, 'course_id'))
        role_name = 'Student'

        user = User.objects.get(pk=user_id)
        course = Course.objects.get(pk=course_id)

        request.user.check_permission('can_add_course_users', course)

        if user.is_participant(course):
            return response.bad_request(
                'User already participates in the course.')

        role = Role.objects.get(name=role_name, course=course)

        factory.make_participation(user, course, role)

        assignments = course.assignment_set.all()
        for assignment in assignments:
            if not Journal.objects.filter(assignment=assignment,
                                          user=user).exists():
                factory.make_journal(assignment, user)

        serializer = UserSerializer(user, context={'course': course})
        return response.created(
            {'participant': serializer.data},
            description='Successfully added student to course.')
示例#25
0
def request_email_verification(request):
    """Request an email with a verifcation link for the user's email address."""
    if request.user.verified_email:
        return response.success(description='Email address already verified.')

    email, = utils.optional_params(request.data, 'email')

    if not email and not request.user.email:
        return response.bad_request(description='Please provide an email address.')

    if email and request.user.email != email:
        request.user.email = email
        request.user.verified_email = False
        request.user.save()

    send_email_verification_link.delay(request.user.pk)
    return response.success(
        description='An email was sent to {}, please check your inbox for further \
                     instructions.'.format(request.user.email))
示例#26
0
def verify_email(request):
    """Handles an email verification request.

    Arguments:
        token -- User claimed email verification token.

    Updates the email verification status.
    """
    if request.user.verified_email:
        return response.success(description='Email address already verified.')

    token, = utils.required_params(request.data, 'token')
    token_generator = PasswordResetTokenGenerator()
    if not token_generator.check_token(request.user, token):
        return response.bad_request(
            description='Invalid email recovery token.')

    request.user.verified_email = True
    request.user.save()
    return response.success(
        description='Successfully verified your email address.')
示例#27
0
 def publish(self, request, journal):
     grading.publish_all_journal_grades(journal, request.user)
     if journal.sourcedid:
         payload = lti_grade.replace_result(journal)
         if payload and 'code_mayor' in payload and payload[
                 'code_mayor'] == 'success':
             return response.success({
                 'lti_info':
                 payload,
                 'journal':
                 JournalSerializer(journal).data
             })
         else:
             return response.bad_request({
                 'lti_info':
                 payload,
                 'journal':
                 JournalSerializer(journal).data
             })
     else:
         return response.success(
             {'journal': JournalSerializer(journal).data})
示例#28
0
    def partial_update(self, request, *args, **kwargs):
        """Update an existing assignment.

        Arguments:
        request -- request data
            data -- the new data for the assignment
        pk -- assignment ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the assignment does not exist
            forbidden -- User not allowed to edit this assignment
            unauthorized -- when the user is unauthorized to edit the assignment
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new assignment data

        """
        pk, = utils.required_typed_params(kwargs, (int, 'pk'))
        assignment = Assignment.objects.get(pk=pk)

        request.user.check_permission('can_edit_assignment', assignment)

        response_data = {}

        # Remove data that must not be changed by the serializer
        req_data = request.data
        if not (request.user.is_superuser
                or request.user == assignment.author):
            req_data.pop('author', None)

        # Check if the assignment can be unpublished
        is_published, = utils.optional_params(request.data, 'is_published')
        if not assignment.can_unpublish() and is_published is False:
            return response.bad_request(
                'You cannot unpublish an assignment that already has submissions.'
            )

        active_lti_course, = utils.optional_typed_params(
            request.data, (int, 'active_lti_course'))
        if active_lti_course is not None:
            course = Course.objects.get(pk=active_lti_course)
            active_lti_id = assignment.get_course_lti_id(course)
            if active_lti_id:
                assignment.active_lti_id = active_lti_id
                assignment.save()

        # Rename lti id key for serializer
        if 'lti_id' in req_data:
            course_id, = utils.required_params(request.data, 'course_id')
            course = Course.objects.get(pk=course_id)
            request.user.check_permission('can_add_assignment', course)
            if course in assignment.courses.all():
                return response.bad_request(
                    'Assignment already used in course.')
            course.set_assignment_lti_id_set(req_data['lti_id'])
            course.save()
            assignment.courses.add(course)
            assignment.save()
            for user in User.objects.filter(
                    participation__course=course).exclude(
                        journal__assignment=assignment):
                factory.make_journal(assignment, user)
            req_data['active_lti_id'] = req_data.pop('lti_id')

        # Update the other data
        serializer = AssignmentSerializer(assignment,
                                          data=req_data,
                                          context={'user': request.user},
                                          partial=True)
        if not serializer.is_valid():
            return response.bad_request()
        serializer.save()
        response_data['assignment'] = serializer.data

        return response.success(response_data)
示例#29
0
    def partial_update(self, request, pk):
        """Update an existing journal format.

        Arguments:
        request -- request data
            templates -- the list of templates to bind to the format
            presets -- the list of presets to bind to the format
            unused_templates -- the list of templates that are bound to the template
                                deck, but are not used in presets nor the entry templates.
            removed_presets -- presets to be removed
            removed_templates -- templates to be removed
        pk -- assignment ID

        Returns:
        On failure:
            unauthorized -- when the user is not logged in
            not found -- when the assignment does not exist
            forbidden -- User not allowed to edit this assignment
            unauthorized -- when the user is unauthorized to edit the assignment
            bad_request -- when there is invalid data in the request
        On success:
            success -- with the new assignment data

        """
        assignment_id = pk
        assignment_details, templates, presets, unused_templates, removed_presets, removed_templates \
            = utils.required_params(request.data, "assignment_details", "templates", "presets",
                                    "unused_templates", "removed_presets", "removed_templates")

        assignment = Assignment.objects.get(pk=assignment_id)
        format = assignment.format

        # If a entry has been submitted to one of the journals of the journal it cannot be unpublished
        if assignment.is_published and 'is_published' in assignment_details and not assignment_details['is_published'] \
           and Entry.objects.filter(node__journal__assignment=assignment).exists():
            return response.bad_request('You are not allowed to unpublish an assignment that already has submissions.')

        request.user.check_permission('can_edit_assignment', assignment)

        serializer = AssignmentSerializer(assignment, data=assignment_details,
                                          context={'user': request.user}, partial=True)
        if not serializer.is_valid():
            return response.bad_request('Invalid data.')

        serializer.save()

        format.save()
        template_map = {}
        utils.update_presets(assignment, presets, template_map)
        utils.update_templates(format.available_templates, templates, template_map)
        utils.update_templates(format.unused_templates, unused_templates, template_map)

        # Swap templates from lists if they occur in the other:
        # If a template was previously unused, but is now used, swap it to available templates, and vice versa.
        utils.swap_templates(format.available_templates, unused_templates, format.unused_templates)
        utils.swap_templates(format.unused_templates, templates, format.available_templates)

        utils.delete_presets(format.presetnode_set, removed_presets)
        utils.delete_templates(format.available_templates, removed_templates)
        utils.delete_templates(format.unused_templates, removed_templates)

        serializer = FormatSerializer(format)
        assignment_details = AssignmentDetailsSerializer(assignment)

        return response.success({'format': serializer.data, 'assignment_details': assignment_details.data})
示例#30
0
    def add_bonus_points(self, request, *args, **kwargs):
        """Give students bonus points though file submission.

        This will scan over the included file, and give all the users the bonus points supplied.
        Format:
        [username1], [bonus_points1]
        [username2], [bonus_points2]

        Arguments:
        request
            file -- list of all the bonus points
        pk -- assignment ID
        """
        assignment_id, = utils.required_typed_params(kwargs, (int, 'pk'))
        assignment = Assignment.objects.get(pk=assignment_id)

        request.user.check_permission('can_grade', assignment)

        if not (request.FILES and 'file' in request.FILES):
            return response.bad_request(
                'No accompanying file found in the request.')

        validators.validate_user_file(request.FILES['file'], request.user)

        bonuses = dict()
        incorrect_format_lines = dict()
        unknown_users = dict()
        duplicates = dict()
        non_participants = dict()

        for line_nr, line in enumerate(request.FILES['file'], 1):
            try:
                decoded_line = line.decode()

                # Ignore empty lines.
                if not decoded_line.strip():
                    continue

                username, bonus = decoded_line[:-1].split(',')[:2]
                bonus = float(bonus)
                user = User.objects.get(username=str(username))
                journal = Journal.objects.get(assignment=assignment, user=user)
                if journal in bonuses:
                    duplicates[line_nr] = line.decode().split(',')[0]
                else:
                    bonuses[journal] = bonus
            except UnicodeDecodeError:
                return response.bad_request(
                    {'general': 'Not a valid csv file.'})
            except ValueError:
                incorrect_format_lines[line_nr] = line.decode()
            except User.DoesNotExist:
                unknown_users[line_nr] = line.decode().split(',')[0]
            except Journal.DoesNotExist:
                non_participants[line_nr] = line.decode().split(',')[0]

        if unknown_users or incorrect_format_lines or duplicates:
            errors = dict()

            if incorrect_format_lines:
                errors['incorrect_format_lines'] = incorrect_format_lines
            if duplicates:
                errors['duplicates'] = duplicates
            if unknown_users:
                errors['unknown_users'] = unknown_users
            if non_participants:
                errors['non_participants'] = non_participants

            return response.bad_request(errors)

        for j, b in bonuses.items():
            j.bonus_points = b
            j.save()
            lti_grade.replace_result(journal)

        return response.success()