Ejemplo n.º 1
0
def assignment(name):
    assign = get_assignment(name)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)
    revision = assign.revision(user_ids)
    scores = assign.scores(user_ids)

    group = Group.lookup(current_user, assign)
    can_invite = assign.max_group_size > 1 and assign.active
    can_remove = group and group.has_status(current_user, 'active')

    if group:
        can_invite = len(group.members) < assign.max_group_size
    has_extension = Extension.get_extension(current_user, assign)

    data = {
        'course': assign.course,
        'assignment': assign,
        'backups': assign.backups(user_ids).limit(5).all(),
        'subms': assign.submissions(user_ids).limit(5).all(),
        'final_submission': fs,
        'flagged': fs and fs.flagged,
        'group': group,
        'revision': revision,
        'scores': scores,
        'can_invite': can_invite,
        'can_remove': can_remove,
        'has_extension': has_extension,
        'csrf_form': CSRFForm()
    }
    return render_template('student/assignment/index.html', **data)
Ejemplo n.º 2
0
    def test_extension_group(self):
        self.set_offset(1) # Allow assignment to be active
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        self.set_offset(-2) # Lock assignment

        ext = self._make_ext(self.assignment, self.user1)
        self.assertEqual(ext, Extension.get_extension(self.user1, self.assignment))
        self.assertEqual(ext, Extension.get_extension(self.user2, self.assignment))
        # User 3 has not accepted yet so does not get an extension
        self.assertFalse(Extension.get_extension(self.user3, self.assignment))

        # If user 2 leaves, they no longer have access to the extension
        self.set_offset(1) # Allow assignment to be active to remove the user.
        group.remove(self.user1, self.user2)
        self.assertFalse(Extension.get_extension(self.user2, self.assignment))
Ejemplo n.º 3
0
    def test_extension_group(self):
        self.set_offset(1)  # Allow assignment to be active
        Group.invite(self.user1, self.user2, self.assignment)
        Group.invite(self.user1, self.user3, self.assignment)
        group = Group.lookup(self.user1, self.assignment)
        group.accept(self.user2)
        self.set_offset(-1)  # Lock assignment

        ext = self._make_ext(self.assignment, self.user1)
        self.assertEqual(ext,
                         Extension.get_extension(self.user1, self.assignment))
        self.assertEqual(ext,
                         Extension.get_extension(self.user2, self.assignment))
        # User 3 has not accepted yet so does not get an extension
        self.assertFalse(Extension.get_extension(self.user3, self.assignment))

        # If user 2 leaves, they no longer have access to the extension
        group.remove(self.user1, self.user2)
        self.assertFalse(Extension.get_extension(self.user2, self.assignment))
Ejemplo n.º 4
0
    def _make_ext(self, assignment, user, custom_time=None):
        if not custom_time:
           custom_time = dt.datetime.utcnow()

        ext = Extension(assignment=assignment, user=user,
                              custom_submission_time=custom_time,
                              expires=dt.datetime.utcnow() + dt.timedelta(days=1),
                              staff=self.staff1)
        db.session.add(ext)
        db.session.commit()
        return ext
Ejemplo n.º 5
0
def get_submission_time(backup, assignment):
    """
    Returns the "time" the backup was submitted.

    If an extension exists and it hasn't expired, use its
    ``custom_submission_time`` instead of the backup's.

    If the extension's ``custom_submission_time`` is None, assume it's right
    before the assignment's due date.
    """
    extension = Extension.get_extension(backup.submitter, assignment, backup.created)
    if extension:
        return extension.custom_submission_time or assignment.due_date
    return backup.submission_time
Ejemplo n.º 6
0
 def test_edit_extension(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.login(self.staff1.email)
     expires = (dt.datetime.utcnow() + dt.timedelta(days=3)).strftime(constants.ISO_DATETIME_FMT)
     custom_submission_time = dt.datetime.utcnow().strftime(constants.ISO_DATETIME_FMT)
     message = 'Sickness'
     data = {
         'assignment_id': self.assignment.id,
         'email': self.user1.email,
         'expires': expires,
         'reason': message,
         'submission_time': 'other',
         'custom_submission_time': custom_submission_time
     }
     self.assert200(self.client.post('/admin/course/{}/extensions/{}'.format(self.course.id, utils.encode_id(ext.id)),
                     data=data, follow_redirects=True))
     extension = Extension.get_extension(self.user1, self.assignment, time=dt.datetime.utcnow())
     self.assertEqual(extension.staff_id, self.staff1.id)
     self.assertEqual(extension.assignment_id, self.assignment.id)
     self.assertEqual(extension.message, message)
     self.assertEqual(utils.local_time_obj(extension.expires, self.course).replace(tzinfo=None), dt.datetime.strptime(expires, '%Y-%m-%d %H:%M:%S'))
     self.assertEqual(utils.local_time_obj(extension.custom_submission_time, self.course).replace(tzinfo=None), dt.datetime.strptime(custom_submission_time, '%Y-%m-%d %H:%M:%S'))
Ejemplo n.º 7
0
 def test_extension_expiry(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.assertEqual(ext, Extension.get_extension(self.user1, self.assignment))
     ext.expires = dt.datetime.utcnow() - dt.timedelta(days=1)
     self.assertFalse(Extension.get_extension(self.user1, self.assignment))
Ejemplo n.º 8
0
 def test_extension_permissions(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.assertFalse(Extension.can(ext, self.user1, 'delete'))
     self.assertTrue(Extension.can(ext, self.staff1, 'delete'))
Ejemplo n.º 9
0
 def test_extension_basic(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.assertEqual(ext, Extension.get_extension(self.user1, self.assignment))
     self.assertFalse(Extension.get_extension(self.user2, self.assignment))
Ejemplo n.º 10
0
 def _make_ext(self, assignment, user, custom_time=None):
     custom_time = custom_time or dt.datetime.utcnow()
     return Extension.create(assignment=assignment, user=user,
             custom_submission_time=custom_time,
             expires=dt.datetime.utcnow() + dt.timedelta(days=1),
             staff=self.staff1)
Ejemplo n.º 11
0
 def test_extension_expiry(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.assertEquals(ext, Extension.get_extension(self.user1, self.assignment))
     ext.expires = dt.datetime.utcnow() - dt.timedelta(days=1)
     self.assertFalse(Extension.get_extension(self.user1, self.assignment))
Ejemplo n.º 12
0
 def test_extension_permissions(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.assertFalse(Extension.can(ext, self.user1, 'delete'))
     self.assertTrue(Extension.can(ext, self.staff1, 'delete'))
Ejemplo n.º 13
0
 def test_extension_basic(self):
     ext = self._make_ext(self.assignment, self.user1)
     self.assertEquals(ext, Extension.get_extension(self.user1, self.assignment))
     self.assertFalse(Extension.get_extension(self.user2, self.assignment))
Ejemplo n.º 14
0
def submit_assignment(name):
    # TODO: Unify student & staff upload.
    assign = get_assignment(name)
    group = Group.lookup(current_user, assign)
    user_ids = assign.active_user_ids(current_user.id)
    fs = assign.final_submission(user_ids)
    if not assign.uploads_enabled:
        flash("This assignment cannot be submitted online", 'warning')
        return redirect(url_for('.assignment', name=assign.name))

    extension = None # No need for an extension
    if not assign.active:
        extension = Extension.get_extension(current_user, assign)
        if not extension:
            flash("It's too late to submit this assignment", 'warning')
            return redirect(url_for('.assignment', name=assign.name))

    if request.method == "POST":
        backup = Backup.create(
            submitter=current_user,
            assignment=assign,
            submit=True,
        )
        assignment = backup.assignment
        if extension:
            backup.custom_submission_time = extension.custom_submission_time

        templates = assignment.files or []
        files = {}

        def extract_file_index(file_ind):
            """ Get the index of of file objects. Used because
            request.files.getlist() does not handle uniquely indexed
            lists.
            >>> extract_file_index('file[12'])
            12
            """
            brace_loc = file_ind.find('[')
            index_str = file_ind[brace_loc+1:-1]
            return int(index_str)


        # A list of one element lists
        sorted_uploads = sorted(list(request.files.items()),
                                key=lambda x: extract_file_index(x[0]))
        uploads = [v[1] for v in sorted_uploads]
        full_path_names = list(request.form.listvalues())[0]

        template_files = assign.files or []
        file_names = [os.path.split(f)[1] for f in full_path_names]
        missing = [t for t in template_files if t not in file_names]
        if missing:
            return jsonify({
                'error': ('Missing files: {}. The following files are required: {}'
                          .format(', '.join(missing), ', '.join(template_files)))
            }), 400

        backup_folder_postfix = time.time()

        for full_path, upload in zip(full_path_names, uploads):
            data = upload.read()
            if len(data) > MAX_UPLOAD_FILE_SIZE:  # file is too large (over 25 MB)
                return jsonify({
                  'error': ('{} is larger than the maximum file size of {} MB'
                            .format(full_path, MAX_UPLOAD_FILE_SIZE/1024/1024))
                }), 400
            try:
                files[full_path] = str(data, 'utf-8')
            except UnicodeDecodeError:
                upload.stream.seek(0) # We've already read data, so reset before uploading
                dest_folder = "uploads/{}/{}/{}/".format(assign.name, current_user.id, backup_folder_postfix)
                bin_file = ExternalFile.upload(upload.stream, current_user.id, full_path,
                                               staff_file=False, prefix=dest_folder,
                                               course_id=assign.course.id,
                                               backup=backup, assignment_id=assign.id)
                db.session.add(bin_file)

        message = Message(kind='file_contents', contents=files)
        backup.messages.append(message)

        db.session.add(backup)
        db.session.commit()

        # Send to continuous autograder
        if assign.autograding_key and assign.continuous_autograding:
            try:
                submit_continuous(backup)
            except ValueError as e:
                flash('Did not send to autograder: {}'.format(e), 'warning')

        return jsonify({
            'backup': backup.hashid,
            'url': url_for('.code', name=assign.name, submit=backup.submit,
                           bid=backup.id)
        })

    return render_template('student/assignment/submit.html', assignment=assign,
                           group=group, course=assign.course)
Ejemplo n.º 15
0
 def _make_ext(self, assignment, user, custom_time=None):
     custom_time = custom_time or dt.datetime.utcnow()
     return Extension.create(assignment=assignment, user=user,
             custom_submission_time=custom_time,
             expires=dt.datetime.utcnow() + dt.timedelta(days=1),
             staff=self.staff1)