Exemplo n.º 1
0
def test_notebook_find_by_name(db, assignment_tree):

    orm_notebook = Notebook(
        name="Exam 2",
        assignment_id=assignment_tree.id,
    )
    db.add(orm_notebook)
    db.commit()

    with pytest.raises(TypeError):
        found_by_name = Notebook.find_by_name()
    with pytest.raises(TypeError):
        found_by_name = Notebook.find_by_name(db)
    with pytest.raises(TypeError):
        found_by_name = Notebook.find_by_name(db, None)
    with pytest.raises(TypeError):
        found_by_name = Notebook.find_by_name(db, "abc")
    with pytest.raises(TypeError):
        found_by_name = Notebook.find_by_name(db, "abc", "foo")

    found_by_name = Notebook.find_by_name(db, "Exam 2", assignment_tree.id)
    assert found_by_name.id == orm_notebook.id
    found_by_name = Notebook.find_by_name(db, "Exam 3", assignment_tree.id)
    assert found_by_name is None
    found_by_name = Notebook.find_by_name(db, assignment_id=assignment_tree.id, name="Exam 2")
    assert found_by_name.id == orm_notebook.id
Exemplo n.º 2
0
def test_notebook_base_mathods_and_find_by_pk(db, assignment_tree):

    # name is required
    orm_notebook = Notebook(
        # name="Test 1",
        assignment_id=assignment_tree.id,
    )
    db.add(orm_notebook)
    with pytest.raises(IntegrityError):
        db.commit()
    db.rollback()

    orm_notebook = Notebook(
        name="Test 1",
        assignment_id=assignment_tree.id,
    )
    db.add(orm_notebook)
    db.commit()

    assert orm_notebook.name == "Test 1"
    assert orm_notebook.assignment.assignment_code == assignment_tree.assignment_code

    with pytest.raises(TypeError):
        found_by_pk = Notebook.find_by_pk()
    with pytest.raises(TypeError):
        found_by_pk = Notebook.find_by_pk(db)
    with pytest.raises(ValueError):
        found_by_pk = Notebook.find_by_pk(db, None)
    with pytest.raises(TypeError):
        found_by_pk = Notebook.find_by_pk(db, "abc")

    found_by_pk = Notebook.find_by_pk(db, orm_notebook.id)
    assert found_by_pk.id == orm_notebook.id

    # # relationships
    assert found_by_pk.assignment.id == assignment_tree.id

    found_by_pk = Notebook.find_by_pk(db, orm_notebook.id + 10)
    assert found_by_pk is None
Exemplo n.º 3
0
    def post(self):

        # Do a content-length check, before we go any further
        if "Content-Length" in self.request.headers and int(
            self.request.headers["Content-Length"]
        ) > int(self.max_buffer_size):
            note = "File upload oversize, and rejected. Please reduce the contents of the assignment, re-generate, and re-release"
            self.log.info(note)
            self.finish({"success": False, "note": note})
            return

        [course_code, assignment_code] = self.get_params(["course_id", "assignment_id"])
        self.log.debug(
            f"Called POST /assignment with arguments: course {course_code} and  assignment {assignment_code}"
        )
        if not (course_code and assignment_code):
            note = f"Posting an Assigment requires a course code and an assignment code"
            self.log.info(note)
            self.finish({"success": False, "note": note})
            return

        this_user = self.nbex_user
        if not course_code in this_user["courses"]:
            note = f"User not subscribed to course {course_code}"
            self.log.info(note)
            self.finish({"success": False, "note": note})
            return

        if (
            not "instructor" == this_user["current_role"].casefold()
        ):  # we may need to revisit this
            note = f"User not an instructor to course {course_code}"
            self.log.info(note)
            self.finish({"success": False, "note": note})
            return

        # The course will exist: the user object creates it if it doesn't exist
        #  - and we know the user is subscribed to the course as an instructor (above)
        with scoped_session() as session:
            course = Course.find_by_code(
                db=session, code=course_code, org_id=this_user["org_id"], log=self.log
            )

            # We need to find this assignment, or make a new one.
            assignment = AssignmentModel.find_by_code(
                db=session, code=assignment_code, course_id=course.id
            )

            if assignment is None:
                # Look for inactive assignments
                assignment = AssignmentModel.find_by_code(
                    db=session, code=assignment_code, course_id=course.id, active=False
                )

            if assignment is None:
                self.log.info(
                    f"New Assignment details: assignment_code:{assignment_code}, course_id:{course.id}"
                )
                # defaults active
                assignment = AssignmentModel(
                    assignment_code=assignment_code, course_id=course.id
                )
                session.add(assignment)
                # deliberately no commit: we need to be able to roll-back if there's no data!

            # Set assignment to active
            assignment.active = True

            # storage is dynamically in $path/release/$course_code/$assignment_code/<timestamp>/
            # Note - this means we can have multiple versions of the same release on the system
            release_file = "/".join(
                [
                    self.base_storage_location,
                    str(this_user["org_id"]),
                    AssignmentActions.released.value,
                    course_code,
                    assignment_code,
                    str(int(time.time())),
                ]
            )

            if not self.request.files:
                self.log.warning(
                    f"Error: No file supplies in upload"
                )  # TODO: improve error message
                raise web.HTTPError(412)  # precondition failed

            try:
                # Write the uploaded file to the desired location
                file_info = self.request.files["assignment"][0]

                filename, content_type = (
                    file_info["filename"],
                    file_info["content_type"],
                )
                note = f"Received file {filename}, of type {content_type}"
                self.log.info(note)
                extn = os.path.splitext(filename)[1]
                cname = str(uuid.uuid4()) + extn

                # store to disk.
                # This should be abstracted, so it can be overloaded to store in other manners (eg AWS)
                release_file = release_file + "/" + cname
                # Ensure the directory exists
                os.makedirs(os.path.dirname(release_file), exist_ok=True)
                with open(release_file, "w+b") as handle:
                    handle.write(file_info["body"])

            except Exception as e:  # TODO: exception handling
                self.log.warning(f"Error: {e}")  # TODO: improve error message

                self.log.info(f"Upload failed")
                # error 500??
                raise Exception

            # Check the file exists on disk
            if not (
                os.path.exists(release_file)
                and os.access(release_file, os.R_OK)
                and os.path.getsize(release_file) > 0
            ):
                note = "File upload failed."
                self.log.info(note)
                self.finish({"success": False, "note": note})
                return

            # We shouldn't get here, but a double-check is good
            if os.path.getsize(release_file) > self.max_buffer_size:
                os.remove(release_file)
                note = "File upload oversize, and rejected. Please reduce the contents of the assignment, re-generate, and re-release"
                self.log.info(note)
                self.finish({"success": False, "note": note})
                return

            # now commit the assignment, and get it back to find the id
            assignment = AssignmentModel.find_by_code(
                db=session, code=assignment_code, course_id=course.id
            )

            # Record the notebooks associated with this assignment
            notebooks = self.get_arguments("notebooks")

            for notebook in notebooks:
                self.log.debug(f"Adding notebook {notebook}")
                new_notebook = Notebook(name=notebook)
                assignment.notebooks.append(new_notebook)

            # Record the action.
            # Note we record the path to the files.
            self.log.info(
                f"Adding action {AssignmentActions.released.value} for user {this_user['id']} against assignment {assignment.id}"
            )
            action = Action(
                user_id=this_user["id"],
                assignment_id=assignment.id,
                action=AssignmentActions.released,
                location=release_file,
            )
            session.add(action)
            self.finish({"success": True, "note": "Released"})