Beispiel #1
0
def user_fidel(db):
    orm_thing = User.find_by_name(db, "fidel")
    if not orm_thing:
        orm_thing = User(name="fidel", org_id=2)
        db.add(orm_thing)
        db.commit()
    return orm_thing
Beispiel #2
0
def user_rur(db):
    orm_thing = User.find_by_name(db, "🌈 🦄 🌹")
    if not orm_thing:
        orm_thing = User(name="🌈 🦄 🌹", org_id=2)
        db.add(orm_thing)
        db.commit()
    return orm_thing
Beispiel #3
0
def user_johaannes(db):
    orm_thing = User.find_by_name(db, "Johaannes")
    if not orm_thing:
        orm_thing = User(name="Johaannes", org_id=1)
        db.add(orm_thing)
        db.commit()
    return orm_thing
Beispiel #4
0
def user_kaylee(db):
    orm_thing = User.find_by_name(db, "kaylee")
    if not orm_thing:
        orm_thing = User(name="kaylee", org_id=1)
        db.add(orm_thing)
        db.commit()
    return orm_thing
Beispiel #5
0
def test_user_find_by_org(db, user_johaannes, user_fidel):
    # uiser_kaylee already in db
    users = User.find_by_org(db, 1)
    assert len(users) == 2
    users = User.find_by_org(db, 2)
    assert len(users) == 1
    users = User.find_by_org(db, 3)
    assert len(users) == 0
Beispiel #6
0
def test_user_params(db, user_kaylee):
    # confirm named arguments work even when reversed
    # test for named parameters, and alternating positions
    found_1 = User.find_by_pk(db, user_kaylee.id)
    found_2 = User.find_by_pk(db=db, pk=user_kaylee.id)
    assert found_2.name == found_1.name
    found_3 = User.find_by_pk(pk=user_kaylee.id, db=db)
    assert found_3.name == found_1.name

    # test for unbexpected param
    with pytest.raises(TypeError):
        found_1 = User.find_by_pk(primary_key=user_kaylee.id, db=db)
    with pytest.raises(TypeError):
        found_1 = User.find_by_name(username=user_kaylee.name, db=db)
    with pytest.raises(TypeError):
        found_1 = User.find_by_org(id=user_kaylee.org_id, db=db)
Beispiel #7
0
def test_user(db, user_kaylee):
    assert user_kaylee.name == "kaylee"
    assert user_kaylee.org_id == 1

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

    found_by_pk = User.find_by_pk(db, user_kaylee.id)
    assert found_by_pk.id == user_kaylee.id
    found_by_pk = User.find_by_pk(db, user_kaylee.id + 10)
    assert found_by_pk is None

    with pytest.raises(ValueError):
        found_by_name = User.find_by_name(db, None)
    found_by_name = User.find_by_name(db, "kaylee")
    assert found_by_name.name == user_kaylee.name
    assert str(found_by_name) == f"User/{found_by_name.name}"
    found_by_name = User.find_by_name(db, "badger")
    assert found_by_name is None
Beispiel #8
0
    def nbex_user(self):

        hub_user = self.get_current_user()
        hub_username = hub_user.get("name")

        full_name = hub_user.get("full_name")
        current_course = hub_user.get("course_id")
        current_role = hub_user.get("course_role")
        course_title = hub_user.get("course_title", "no_title")
        org_id = hub_user.get("org_id", 1)

        # Raising an error appears to have no detrimental affect when running.
        if not (current_course and current_role):
            note = f"Both current_course ('{current_course}') and current_role ('{current_role}') must have values. User was '{hub_username}'"  # noqa: E501
            self.log.info(note)
            raise ValueError(note)

        self.org_id = org_id

        with scoped_session() as session:
            user = User.find_by_name(db=session,
                                     name=hub_username,
                                     log=self.log)
            if user is None:
                self.log.debug(
                    f"New user details: name:{hub_username}, org_id:{org_id}")
                user = User(name=hub_username, org_id=org_id)
                session.add(user)
            if user.full_name != full_name:
                user.full_name = full_name

            course = Course.find_by_code(db=session,
                                         code=current_course,
                                         org_id=org_id,
                                         log=self.log)
            if course is None:
                self.log.debug(
                    f"New course details: code:{current_course}, org_id:{org_id}"
                )
                course = Course(org_id=org_id, course_code=current_course)
                if course_title:
                    self.log.debug(f"Adding title {course_title}")
                    course.course_title = course_title
                session.add(course)

            # Check to see if we have a subscription (for this course)
            self.log.debug(
                f"Looking for subscription for: user:{user.id}, course:{course.id}, role:{current_role}"
            )

            subscription = Subscription.find_by_set(db=session,
                                                    user_id=user.id,
                                                    course_id=course.id,
                                                    role=current_role)
            if subscription is None:
                self.log.debug(
                    f"New subscription details: user:{user.id}, course:{course.id}, role:{current_role}"
                )
                subscription = Subscription(user_id=user.id,
                                            course_id=course.id,
                                            role=current_role)
                session.add(subscription)

            courses = {}

            for subscription in user.courses:
                if subscription.course.course_code not in courses:
                    courses[subscription.course.course_code] = {}
                courses[subscription.course.course_code][subscription.role] = 1

            model = {
                "kind": "user",
                "id": user.id,
                "name": user.name,
                "org_id": user.org_id,
                "current_course": current_course,
                "current_role": current_role,
                "courses": courses,
            }
        return model
Beispiel #9
0
    def get(self):

        [course_id,
         assignment_id] = self.get_params(["course_id", "assignment_id"])

        if not assignment_id or not course_id:
            note = "Feedback call requires an assignment id and a course id"
            self.log.info(note)
            self.finish({"success": False, "note": note})
            return

        self.log.debug(
            f"checking for feedback for {assignment_id} on {course_id}")

        this_user = self.nbex_user

        with scoped_session() as session:

            course = Course.find_by_code(db=session,
                                         code=course_id,
                                         org_id=this_user["org_id"],
                                         log=self.log)
            if not course:
                note = f"Course {course_id} not found"
                self.log.info(note)
                # self.finish({"success": False, "note": note, "value": []})
                # return
                raise web.HTTPError(404, note)

            assignment = AssignmentModel.find_by_code(db=session,
                                                      code=assignment_id,
                                                      course_id=course.id,
                                                      log=self.log)
            if not assignment:
                note = f"Assignment {assignment_id} for Course {course_id} not found"
                self.log.info(note)
                # self.finish({"success": False, "note": note, "value": []})
                # return
                raise web.HTTPError(404, note)

            student = User.find_by_name(db=session,
                                        name=this_user["name"],
                                        log=self.log)

            res = Feedback.find_all_for_student(
                db=session,
                student_id=student.id,
                assignment_id=assignment.id,
                log=self.log,
            )
            feedbacks = []
            for r in res:
                f = {}
                notebook = Notebook.find_by_pk(db=session,
                                               pk=r.notebook_id,
                                               log=self.log)
                if notebook is not None:
                    feedback_name = "{0}.html".format(notebook.name)
                else:
                    feedback_name = os.path.basename(r.location)
                with open(r.location, "r+b") as fp:
                    f["content"] = base64.b64encode(fp.read()).decode("utf-8")
                f["filename"] = feedback_name
                # This matches self.timestamp_format
                f["timestamp"] = r.timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S.%f %Z")
                f["checksum"] = r.checksum
                feedbacks.append(f)

                # Add action
                action = Action(
                    user_id=this_user["id"],
                    assignment_id=assignment.id,
                    action=AssignmentActions.feedback_fetched,
                    location=r.location,
                )
                session.add(action)
            self.finish({"success": True, "feedback": feedbacks})
Beispiel #10
0
    def post(self):
        """
        This endpoint accepts feedback files for a notebook.
        It requires a notebook id, student id, feedback timestamp and
        a checksum.

        The endpoint return {'success': true} for all successful feedback releases.
        """

        [
            course_id,
            assignment_id,
            notebook_id,
            student_id,
            timestamp,
            checksum,
        ] = self.get_params([
            "course_id",
            "assignment_id",
            "notebook",
            "student",
            "timestamp",
            "checksum",
        ])

        if not (course_id and assignment_id and notebook_id and student_id
                and timestamp and checksum):
            note = "Feedback call requires a course id, assignment id, notebook name, student id, checksum and timestamp."
            self.log.debug(note)
            self.finish({"success": False, "note": note})
            return

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

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

        with scoped_session() as session:

            # Start building feedback object

            course = Course.find_by_code(db=session,
                                         code=course_id,
                                         org_id=this_user["org_id"],
                                         log=self.log)

            if not course:
                self.log.info(
                    f"Could not find requested resource course {course_id}")
                raise web.HTTPError(
                    404,
                    f"Could not find requested resource course {course_id}")

            assignment = AssignmentModel.find_by_code(
                db=session,
                code=assignment_id,
                course_id=course.id,
                action=AssignmentActions.released.value,
            )

            if not assignment:
                note = f"Could not find requested resource assignment {assignment_id}"
                self.log.info(note)
                raise web.HTTPError(404, note)

            notebook = Notebook.find_by_name(db=session,
                                             name=notebook_id,
                                             assignment_id=assignment.id,
                                             log=self.log)
            if not notebook:
                note = f"Could not find requested resource notebook {notebook_id}"
                self.log.info(note)
                raise web.HTTPError(404, note)

            student = User.find_by_name(db=session,
                                        name=student_id,
                                        log=self.log)

            if not student:
                note = f"Could not find requested resource student {student_id}"
                self.log.info(note)
                raise web.HTTPError(404, note)

            # # raise Exception(f"{res}")
            # self.log.info(f"Notebook: {notebook}")
            # self.log.info(f"Student: {student}")
            # self.log.info(f"Instructor: {this_user}")

            # TODO: check access. Is the user an instructor on the course to which the notebook belongs

            # Check whether there is an HTML file attached to the request
            if not self.request.files:
                self.log.warning(f"Error: No file supplied in upload"
                                 )  # TODO: improve error message
                raise web.HTTPError(412)  # precondition failed

            try:
                # Grab the file
                file_info = self.request.files["feedback"][0]
                filename, content_type = (
                    file_info["filename"],
                    file_info["content_type"],
                )
                note = f"Received file {filename}, of type {content_type}"
                self.log.info(note)
                fbfile = tempfile.NamedTemporaryFile()
                fbfile.write(file_info["body"])
                fbfile.seek(0)

            except Exception as e:
                # Could not grab the feedback file
                self.log.error(f"Error: {e}")
                raise web.HTTPError(412)
            # TODO: should we check the checksum?
            # unique_key = make_unique_key(
            #     course_id,
            #     assignment_id,
            #     notebook_id,
            #     student_id,
            #     str(timestamp).strip(),
            # )
            # check_checksum = notebook_hash(fbfile.name, unique_key)
            #
            # if check_checksum != checksum:
            #     self.log.info(f"Checksum {checksum} does not match {check_checksum}")
            #     raise web.HTTPError(403, f"Checksum {checksum} does not match {check_checksum}")

            # TODO: What is file of the original notebook we are getting the feedback for?
            # assignment_dir = "collected/student_id/assignment_name"
            # nbfile = os.path.join(assignment_dir, "{}.ipynb".format(notebook.name))
            # calc_checksum = notebook_hash(nbfile.name, unique_key)
            # if calc_checksum != checksum:
            #     self.log.info(f"Mismatched checksums {calc_checksum} and {checksum}.")
            #     raise web.HTTPError(412)

            location = "/".join([
                self.base_storage_location,
                str(this_user["org_id"]),
                "feedback",
                notebook.assignment.course.course_code,
                notebook.assignment.assignment_code,
                str(int(time.time())),
            ])

            # This should be abstracted, so it can be overloaded to store in other manners (eg AWS)
            feedback_file = location + "/" + checksum + ".html"

            try:
                # Ensure the directory exists
                os.makedirs(os.path.dirname(feedback_file), exist_ok=True)
                with open(feedback_file, "w+b") as handle:
                    handle.write(file_info["body"])
            except Exception as e:
                self.log.error(f"Could not save file. \n {e}")
                raise web.HTTPError(500)

            feedback = Feedback(
                notebook_id=notebook.id,
                checksum=checksum,
                location=feedback_file,
                student_id=student.id,
                instructor_id=this_user.get("id"),
                timestamp=parser.parse(timestamp),
            )

            session.add(feedback)

            # Add action
            action = Action(
                user_id=this_user["id"],
                assignment_id=notebook.assignment.id,
                action=AssignmentActions.feedback_released,
                location=feedback_file,
            )
            session.add(action)

        self.finish({"success": True, "note": "Feedback released"})
Beispiel #11
0
    def nbex_user(self):

        hub_user = self.get_current_user()
        hub_username = hub_user.get("name")

        full_name = hub_user.get("full_name")
        current_course = hub_user.get("course_id")
        current_role = hub_user.get("course_role")
        course_title = hub_user.get("course_title", "no_title")
        org_id = hub_user.get("org_id", 1)

        if not (current_course and current_role):
            return

        self.org_id = org_id

        with scoped_session() as session:
            user = User.find_by_name(db=session,
                                     name=hub_username,
                                     log=self.log)
            if user is None:
                self.log.debug(
                    f"New user details: name:{hub_username}, org_id:{org_id}")
                user = User(name=hub_username, org_id=org_id)
                session.add(user)
            if user.full_name != full_name:
                user.full_name = full_name

            course = Course.find_by_code(db=session,
                                         code=current_course,
                                         org_id=org_id,
                                         log=self.log)
            if course is None:
                self.log.debug(
                    f"New course details: code:{current_course}, org_id:{org_id}"
                )
                course = Course(org_id=org_id, course_code=current_course)
                if course_title:
                    self.log.debug(f"Adding title {course_title}")
                    course.course_title = course_title
                session.add(course)

            # Check to see if we have a subscription (for this course)
            self.log.debug(
                f"Looking for subscription for: user:{user.id}, course:{course.id}, role:{current_role}"
            )

            subscription = Subscription.find_by_set(db=session,
                                                    user_id=user.id,
                                                    course_id=course.id,
                                                    role=current_role)
            if subscription is None:
                self.log.debug(
                    f"New subscription details: user:{user.id}, course:{course.id}, role:{current_role}"
                )
                subscription = Subscription(user_id=user.id,
                                            course_id=course.id,
                                            role=current_role)
                session.add(subscription)

            courses = {}

            for subscription in user.courses:
                if not subscription.course.course_code in courses:
                    courses[subscription.course.course_code] = {}
                courses[subscription.course.course_code][subscription.role] = 1

            model = {
                "kind": "user",
                "id": user.id,
                "name": user.name,
                "org_id": user.org_id,
                "current_course": current_course,
                "current_role": current_role,
                "courses": courses,
            }
        return model