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
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
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
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
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
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)
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
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})
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"})
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