def watch(): assignment_list = request.values.get('assignments', '') assignments = [int(aid) for aid in assignment_list.split(',') if len(aid) > 0] course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if course_id == None or course_id == "": return ajax_failure("No Course ID given!") if g.user is None or not g.user.is_instructor(int(course_id)): return ajax_failure("You are not an instructor in this assignments' course.") update = request.values.get('update', 'false') == "true" if update: data = [] for aid in assignments: submissions = Submission.by_assignment(aid, int(course_id)) completions = sum([int(sua[0].correct) for sua in submissions]) workings = Submission.get_latest(aid, int(course_id)) histories = [process_history([h['time'] for h in sua[0].get_history()]) for sua in submissions] touches = [int(sua[0].version) for sua in submissions] feedbacks = [l[0] for l in Log.calculate_feedbacks(aid, course_id)] data.append({'id': aid, 'Completions': completions, 'Workings': workings, 'Time': histories, 'Touches': touches, 'Feedbacks': feedbacks}) return jsonify(success=True, data=data) else: assignments = [Assignment.by_id(aid) for aid in assignments] return render_template('blockpy/watch.html', course_id=course_id, assignments=assignments, assignment_list=assignment_list)
def post(self): ''' creates a new submission instance and inserts it into the db. then redirects the user to the blog entry permalink page. both subject and content are required to make a blog entry. ''' subject = self.request.get("subject") content = self.request.get("content") if subject and content: submission = Submission(parent=blog_key(), user=self.user, subject=subject, content=content) submission.put() time.sleep(0.1) self.redirect('/%s' % str(submission.key().id())) else: error = "You must enter both a subject and content" self.render("submissions/new.html", subject=subject, content=content, error=error)
def submissions_filter(course_id): ''' List all the users in the course ''' is_grader = g.user.is_grader(int(course_id)) if not is_grader: return "You are not an instructor or TA in this course!" course_id = int(course_id) course = Course.by_id(course_id) students = natsorted(course.get_students(), key=lambda r: r.name()) assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) criteria = request.values.get("criteria", "none") search_key = int(request.values.get("search_key", "-1")) submissions = [] if criteria == "student": all_subs = Submission.by_student(search_key, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [ all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments ] elif criteria == "assignment": all_subs = Submission.by_assignment(search_key, course_id) all_subs = {s[0].user_id: s for s in all_subs} submissions = [ all_subs.get(student.id, (None, student, None)) for student in students ] return render_template('courses/submissions_filter.html', course_id=course_id, assignments=assignments, students=students, submissions=submissions, criteria=criteria, search_key=search_key, is_instructor=is_grader)
def AssignmentMain(assignment_code): assignment = Assignment.query.filter_by(code=assignment_code).first() if assignment is None: flash("No assignment found!", "danger") return redirect(url_for("home")) user = GetUser(session["email"]) if not assignment.classroom in user.classrooms: flash("Access denied to this assigment!", "warning") return redirect(url_for("home")) file_name = os.path.join(SUBMISSION_FOLDER, assignment.code, f"{user.id}_{user.name}.txt") submission = Submission.query.filter_by(file_name=file_name).first() # print(assignment.classroom.students) if request.method == "POST": if assignment.deadline < datetime.now(): flash("Assignment deadline execeeded!", "danger") else: assignment_program = request.form.get('assignment_program') assignment_lang = request.form.get('assignment_lang') if not os.path.exists( os.path.join(SUBMISSION_FOLDER, assignment.code)): flash("Upload folder not found! Please inform administrator", "danger") else: result = CheckSubmission(assignment_code, assignment_lang, assignment_program) if result is None: flash("Error while submitting assignment!", "warning") else: print(file_name) with open(file_name, "w+") as submission_file: for line in assignment_program.split("\n"): submission_file.write(line + "\n") if submission is None: submission = Submission(file_name, assignment, \ assignment_lang, result, user) else: submission.update(language=assignment_lang, result=result) flash("Assignment submitted successfully!", "success") db.session.add(submission) db.session.commit() submission_program = "" if submission: with open(file_name, "r") as submission_file: for line in submission_file.readlines(): submission_program += line return render_template("assignment/assignment_main.html", assignment=assignment, \ submission_program=submission_program, submission=submission, \ current_time=datetime.now, strftime=lambda x: x.strftime("%a, %d %b %Y at %I:%M %p"), \ os_sep=os.path.sep)
def post(self): data = self.request.get("url") if not data.startswith("data:"): self.error(400) return data = data[5:] try: metadata, body = data.split(",") if not metadata.startswith("image/png"): raise ValueError("Image of wrong MIME type.") imagedata = base64.standard_b64decode(body) if len(imagedata) > 500000: raise ValueError("Image too big.") image = images.Image(imagedata) image.resize(300, 300 / image.width * 300) sub = Submission(submitter=str(self.request.remote_addr) or "") sub.image = db.Blob(image.execute_transforms()) sub.put() except ValueError: self.error(400) return self.response.write("{error:false}")
def add(self): submission = Submission( contents=self.request.body, mime_type=self.request.content_type, submitted_by=users.get_current_user() ) key = submission.put() return webapp2.Response(key.urlsafe())
def dashboard(lti=lti, lti_exception=None): """ :type lti: controllers.pylti.flask.lTI """ force_default_assignment = maybe_bool(request.values.get('force_default_assignment', "false")) if 'user' not in g and not g.user: return "You are not logged in." course_id = get_course_id() user, user_id = get_user() if course_id is None: return "You are not in a course context." is_grader = user.is_grader(course_id) if is_grader and not force_default_assignment: return grader_dashboard(user, course_id) course = Course.by_id(course_id) assignment = course.get_default_assignment() if assignment is not None: return redirect(url_for("blockpy.load", assignment_id=assignment.id, course_id=course_id, user_id=user_id, force_download=False, embed=True)) else: # No default assignment! assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) all_subs = Submission.by_student(user_id, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments] return render_template('courses/dashboard.html', embed=True, course_id=course_id, user=user, is_grader=is_grader, submissions=submissions, criteria='student')
def submissions_user(course_id, owner_id): ''' List all the users in the course ''' course_id = int(course_id) course = Course.by_id(course_id) check_resource_exists(course, "Course", course_id) user, user_id = get_user() if course_id is not None: is_grader = user.is_grader(course_id) else: is_grader = False is_owner = user_id == maybe_int(owner_id) if not is_grader and not is_owner: return "You are not an instructor or the owner of the assignment!" owner = User.by_id(maybe_int(owner_id)) assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) all_subs = Submission.by_student(owner_id, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments] return render_template('courses/submissions_user.html', course_id=course_id, assignments=assignments, submissions=submissions, owner=owner, is_instructor=is_grader)
def dashboard(lti=lti): """ :type lti: controllers.pylti.flask.lTI """ if 'user' not in g and not g.user: return "You are not logged in." course_id = get_course_id() user, user_id = get_user() if course_id is None: return "You are not in a course context." is_grader = user.is_grader(course_id) if is_grader: return grader_dashboard(user, course_id) course = Course.by_id(course_id) assignments = natsorted(course.get_submitted_assignments(), key=lambda r: r.name) all_subs = Submission.by_student(user_id, course_id) all_subs = {s[0].assignment_id: s for s in all_subs} submissions = [ all_subs.get(assignment.id, (None, None, assignment)) for assignment in assignments ] return render_template('courses/dashboard.html', embed=True, course_id=course_id, user=user, is_grader=is_grader, submissions=submissions, criteria='student')
def export_submissions(): assignment_id = int(request.values.get('assignment_id')) assignment = Assignment.by_id(assignment_id) course_id = get_course_id(True) user, user_id = get_user() # Verify exists check_resource_exists(assignment, "Assignment", assignment_id) # Verify permissions assignment = Assignment.by_id(int(assignment_id)) if course_id is None or not user.is_instructor(int(course_id)): return "You are not an instructor or the owner of the assignment!" # Get data suas = Submission.by_assignment(assignment_id, course_id) submissions = [sua[0] for sua in suas] users = [sua[1] for sua in suas] bundle = export_zip(assignments=[assignment], submissions=submissions, users=users) filename = assignment.get_filename(extension='.zip') return Response(bundle, mimetype='application/zip', headers={ 'Content-Disposition': 'attachment;filename={}'.format(filename) })
def get_page_submissions(soup): """Returns the list of all submissions in the given page. Parameters ---------- soup : BeautifulSoup BeautifulSoup object of a page from the hackathon project gallery. Returns ------- list List of Submission objects. """ projects_dirty_url = (soup.findAll( 'a', {'class': 'block-wrapper-link fade link-to-software'})) projects_url = [p.get('href') for p in projects_dirty_url] projects_title = soup.findAll( 'div', {'class': 'software-entry-name entry-body'}) #.find_next('h5').text titles = [p.find_next('h5').text.strip() for p in projects_title] submissions = [] for title, url_project, (url_video, tags) in list( zip(titles, projects_url, map(project_data, projects_url))): submissions.append(Submission(title, url_project, url_video, tags)) return submissions
def update_submission_status(lti, lti_exception=None): # Get parameters submission_id = maybe_int(request.values.get("submission_id")) status = request.values.get('status') course_id = get_course_id() user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user_id and not user.is_grader( submission.course_id): return ajax_failure( "This is not your submission and you are not a grader in its course." ) # Do action success = submission.update_submission_status(status) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "Submit", "answer.py", category=status, message=str(success)) return ajax_success({"success": success})
def dump_logs(): assignment_id = int(request.values.get('assignment_id')) course_id = int(request.values.get('course_id')) assignment = Assignment.by_id(assignment_id) user, user_id = get_user() # Verify exists check_resource_exists(assignment, "Assignment", assignment_id) # Verify permissions if not user.is_grader(course_id): return "You are not a grader in this course." # Get data suas = Submission.by_assignment(assignment_id, course_id) data = { 'assignment': assignment.encode_json(), 'submissions': [{ 'user': u.encode_json(), 'submission': sub.encode_json(), 'history': Log.get_history(course_id, assignment_id, u.id), 'reviews': sub.get_reviews() } for (sub, u, assign) in suas] } filename = assignment.get_filename() + '_submissions.json' return Response(json.dumps(data), mimetype='application/json', headers={ 'Content-Disposition': 'attachment;filename={}'.format(filename) })
def grader_dashboard(user, course_id): pending_review = Submission.by_pending_review(course_id) users = {user.email: user.encode_json() for _, user, _ in pending_review} is_instructor = user.is_instructor(course_id) return render_template('courses/dashboard_grader.html', embed=True, course_id=course_id, user=user, pending_review=pending_review, users=users, is_instructor=is_instructor)
def delete(self, review_id): user, user_id = get_user() review = Review.by_id(review_id) check_resource_exists(review, "Review", review_id) submission = Submission.by_id(review.submission_id) check_resource_exists(submission, "Submission", review.submission_id) require_course_grader(user, submission.course_id) review.delete() return ajax_success(dict(success=True))
def get_one(self, review_id): user, user_id = get_user() review = Review.by_id(review_id) check_resource_exists(review, "Review", review_id) submission = Submission.by_id(review.submission_id) check_resource_exists(submission, "Submission", review.submission_id) if submission.user_id != user_id: require_course_grader(user, submission.course_id) return ajax_success(dict(review=review.encode_json()))
def decorated_function(self, *args, **kwargs): submission_id = args[0] submission = Submission.by_id(submission_id) if submission: kwargs['submission'] = submission return f(self, *args, **kwargs) else: self.error(404) return
def run_test(): cities = Address.get_cities() f = open('voter_test.csv', 'r') rdr = csv.reader(f) submissions = [Submission.from_csv(row, cities, with_contact=False) for row in rdr] lookups = Voter.lookup(submissions) for lookup in lookups: print(str(lookup.name), str(lookup.address)) for match in lookup.matches: print(str(match), str(match.address)) print('\n')
def update_grading_status(lti, lti_exception=None): submission_id = maybe_int(request.values.get("submission_id")) # TODO: Pretty sure multiple assignments are broken for grading assignment_group_id = maybe_int(request.values.get('assignment_group_id')) new_grading_status = request.values.get("new_grading_status") user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if not user.is_grader(submission.course_id): return ajax_failure( "This is not your submission and you are not a grader in its course." ) submission.update_grading_status(new_grading_status) if submission.grading_status != GradingStatuses.FULLY_GRADED: return ajax_success({'new_status': new_grading_status}) # Do action if assignment_group_id is None: assignment_group_id = submission.assignment_group_id error = "Generic LTI Failure - perhaps not logged into LTI session?" try: success, score = lti_post_grade(lti, submission, None, assignment_group_id, submission.user_id, submission.course_id) except LTIPostMessageException as e: success = False error = str(e) if success: make_log_entry(submission.assignment_id, submission.assignment_version, submission.course_id, user_id, "X-Submission.LMS", "answer.py", message=str(score)) return ajax_success({"submitted": True, "new_status": "FullyGraded"}) else: submission.update_grading_status(GradingStatuses.FAILED) make_log_entry(submission.assignment_id, submission.assignment_version, submission.course_id, user_id, "X-Submission.LMS.Failure", "answer.py", message=error) return ajax_failure({ "submitted": False, "message": error, "new_status": "Failed" })
def update_submission_status(): submission_id = maybe_int(request.values.get("submission_id")) new_submission_status = request.values.get("new_submission_status") user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if not user.is_grader(submission.course_id): return ajax_failure( "You are not a grader in this submission's course.") submission.update_submission_status(new_submission_status) return ajax_success({'new_status': new_submission_status})
def get_all(self): submission_id = maybe_int(request.values.get('submission_id')) user, user_id = get_user() if submission_id is None: reviews = Review.get_generic_reviews() else: submission = Submission.by_id(submission_id) check_resource_exists(submission, "Submission", submission_id) reviews = Review.get_for_submission(submission_id) if submission.user_id != user_id: require_course_grader(user, submission.course_id) return ajax_success( dict(reviews=[review.encode_json() for review in reviews]))
def put(self, review_id): user, user_id = get_user() review = Review.by_id(review_id) check_resource_exists(review, "Review", review_id) submission = Submission.by_id(review.submission_id) check_resource_exists(submission, "Submission", review.submission_id) require_course_grader(user, submission.course_id) review_data = request.json.copy() del review_data['id'] fix_nullables(review_data) review_data['author_id'] = user_id edited_review = review.edit(review_data) return ajax_success(dict(review=edited_review.encode_json()))
def run_test(): cities = Address.get_cities() f = open('voter_test.csv', 'r') rdr = csv.reader(f) submissions = [ Submission.from_csv(row, cities, with_contact=False) for row in rdr ] lookups = Voter.lookup(submissions) for lookup in lookups: print(str(lookup.name), str(lookup.address)) for match in lookup.matches: print(str(match), str(match.address)) print('\n')
def mass_close_assignment(): assignment_id = maybe_int(request.values.get("assignment_id")) course_id = maybe_int(request.values.get("course_id")) new_submission_status = request.values.get("new_submission_status") user, user_id = get_user() submissions = Submission.by_assignment(assignment_id=assignment_id, course_id=course_id) # Verify permissions if not user.is_grader(course_id): return ajax_failure("You are not a grader in this course.") # Do action for submission in submissions: submission.update_submission_status(new_submission_status) return ajax_success({'new_status': new_submission_status})
def post(self): user, user_id = get_user() submission_id = maybe_int(request.values.get('submission_id')) submission = Submission.by_id(submission_id) check_resource_exists(submission, "Submission", submission_id) require_course_grader(user, submission.course_id) review_data = request.values.copy() del review_data['id'] review_data['author_id'] = user_id review_data['submission_version'] = submission.version review_data['assignment_version'] = submission.assignment_version fix_nullables(review_data) new_review = Review.new(review_data) return ajax_success(dict(review=new_review.encode_json()))
def csv_import(): from models.turf import Turf from models.submission import Submission if request.method == 'GET': return render_template('voters/voter_import.html', title='Voter Import') data = json.loads(request.form['params'])['data'] cities = Turf.get_cities() submissions = [ Submission.from_web(rec, cities) for rec in data if rec['data0'] ] Voter.batch_lookup(submissions) return jsonify( lookups=[submission.serialize() for submission in submissions])
def post(self, comp_id=None, user_id=None, response=None): args = self.parser.parse_args() submission = args["submission"] if comp_id and user_id is not None: #TODO: Implement Score evaluation. comp = Competition.query.filter_by(id=comp_id).first() public_score = accuracy_score_public(comp.solution, submission, comp.public_ids) private_score = accuracy_score_private(comp.solution, submission) submission = Submission(comp_id, user_id, submission, "Submission", public_score, private_score) data = save_record(submission) response = ("Submission created successfully", 201) return make_response(jsonify({ "message": response[0] }), response[1])
def submissions_specific(submission_id): ''' List all the users in the course ''' submission, user, assignment = Submission.full_by_id(int(submission_id)) if submission is None: return "Submission not found" course_id = submission.course_id if course_id is not None: is_instructor = g.user.is_instructor(int(course_id)) else: is_instructor = False is_owner = g.user.id == submission.user_id if not is_instructor and not is_owner: return "You are not an instructor or the owner of the assignment!" return render_template('courses/submissions_specific.html', submission=submission, assignment=assignment, user=user, course_id=course_id)
def save_image(): # Get parameters submission_id = maybe_int(request.values.get("submission_id")) directory = request.values.get('directory') image = request.values.get('image') course_id = get_course_id() user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user_id and not user.is_grader(submission.course_id): return ajax_failure("This is not your submission and you are not a grader in its course.") # Do action success = submission.save_image(directory, image) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "X-Image.Save", directory) return ajax_success({"success": success})
def new(self, project_path, source_directory): if is_directory(project_path) and self.__isvalid_source(source_directory): self.__reset() self.state['project_path'] = project_path for file in os.listdir(source_directory): current_path = os.path.join(source_directory, file) output_path = os.path.join(project_path, remove_ext(get_uin(file))) # TODO: add support for more file types and change this to account for that if get_ext(file) == '.zip': unzip(current_path, output_path) flatdir(output_path) self.state['submissions'].append(Submission(output_path)) return self.save() and len(self.state['submissions']) > 0 and self.state['project_path'] != None else: return False
def view_submission(): submission_id = request.values.get('submission_id') viewer, viewer_id = get_user() embed = maybe_bool(request.values.get('embed')) submission = Submission.by_id(submission_id) # Check exists check_resource_exists(submission, "Submission", submission_id) # Check permissions if submission.user_id != viewer_id: require_course_grader(viewer, submission.course_id) is_grader = viewer.is_grader(submission.course_id) tags = [] if is_grader: tags = [tag.encode_json() for tag in AssignmentTag.get_all()] # Do action return render_template("reports/alone.html", embed=embed, submission=submission, assignment=submission.assignment, is_grader=is_grader, tags=tags, user_id=submission.user_id, course_id=submission.course_id)
def update_submission(lti, lti_exception=None): # Get parameters submission_id = maybe_int(request.values.get("submission_id")) lis_result_sourcedid = request.values.get('lis_result_sourcedid') assignment_group_id = maybe_int(request.values.get('assignment_group_id')) score = float(request.values.get('score', '0')) correct = maybe_bool(request.values.get("correct")) # TODO: Only send image if the assignment settings starts as Block or Split image = request.values.get('image', "") hidden_override = maybe_bool(request.values.get('hidden_override')) force_update = maybe_bool(request.values.get('force_update')) course_id = get_course_id() user, user_id = get_user() submission = Submission.by_id(submission_id) # Check resource exists check_resource_exists(submission, "Submission", submission_id) # Verify permissions if submission.user_id != user_id and not user.is_grader(submission.course_id): return ajax_failure("This is not your submission and you are not a grader in its course.") # Do action was_changed = submission.update_submission(score, correct) if assignment_group_id is None: assignment_group_id = submission.assignment_group_id # TODO: Document that we currently only pass back grade if it changed # TODO: If failure on previous submission grading, then retry if was_changed or force_update: submission.save_block_image(image) error = "Generic LTI Failure - perhaps not logged into LTI session?" try: success, score = lti_post_grade(lti, submission, lis_result_sourcedid, assignment_group_id, submission.user_id, submission.course_id) except LTIPostMessageException as e: success = False error = str(e) if success: make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "X-Submission.LMS", "answer.py", message=str(score)) else: submission.update_grading_status(GradingStatuses.FAILED) make_log_entry(submission.assignment_id, submission.assignment_version, course_id, user_id, "X-Submission.LMS.Failure", "answer.py", message=error) return ajax_failure({"submitted": False, "changed": was_changed, "message": error}) return ajax_success({"submitted": was_changed or force_update, "changed": was_changed})
def load_submission(lti=lti): submission_id = int(request.args.get('submission_id')) embed = maybe_bool(request.values.get('embed')) course_id = get_course_id(True) user, user_id = get_user() submission = Submission.by_id(submission_id) read_only = maybe_bool(request.values.get('read_only', "true")) # Check that the resource exists check_resource_exists(submission, "Submission", submission_id) # If it is this user's submission, redirect to load the assignment if submission.user_id == user_id: if course_id is None: course_id = submission.course_id return redirect( url_for('blockpy.load', assignment_id=submission.assignment.id, course_id=course_id)) # Check that it is public or you are a grader elif user.is_grader(submission.course_id): role = 'grader' elif not submission.assignment.public: # TODO: Handle this more gracefully return ajax_failure( "Cannot view submission. This is not a public submission, and you do not own the submission, and you are " "not an instructor in its course.") else: role = 'anonymous' # Get the assignment assignment_data = submission.assignment.for_editor(submission.user_id, submission.course_id) return load_editor( lti, { "user": user, "user_id": user_id, "embed": embed, "read_only": read_only, "current_submission_id": submission_id, "course_id": course_id, "role": role, "assignment_group_id": None, "assignment_data": assignment_data })
def load_history(): # Get parameters course_id = maybe_int(request.values.get('course_id')) assignment_id = (request.values.get('assignment_id')) student_id = (request.values.get('user_id')) page_limit = maybe_int(request.values.get('page_limit')) page_offset = maybe_int(request.values.get('page_offset')) with_submission = maybe_bool(request.values.get('with_submission')) user, user_id = get_user() # Verify user can see the submission if str(user_id) != str(student_id) and not user.is_grader(course_id): return ajax_failure("Only graders can see logs for other people.") history = Log.get_history(course_id, assignment_id, student_id, page_offset=page_offset, page_limit=page_limit) history = list(reversed(history)) submissions = [] if with_submission: submissions = Submission.get_submissions(course_id, assignment_id, student_id) return ajax_success({"history": history, "submissions": submissions})
def browse_submissions(): assignment_id = request.values.get('assignment_id', None) if assignment_id is None: return ajax_failure("No Assignment ID given!") assignment_id = int(assignment_id) course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if course_id == None or course_id == "": return ajax_failure("No Course ID given!") if g.user is None or not g.user.is_instructor(int(course_id)): return ajax_failure("You are not an instructor in this assignments' course.") submissions = Submission.by_assignment(assignment_id, int(course_id)) for submission, user, assignment in submissions: submission.highlighted_code = highlight_python_code(submission.code) submission.history = process_history([h['time'] for h in reversed(submission.get_history())]) return render_template('blockpy/browse_submissions.html', course_id=course_id, assignment_id=assignment_id, submissions=submissions, ip=request.remote_addr)