def save_presentation(lti=lti): assignment_id = request.values.get('assignment_id', None) if assignment_id is None: return failure("No Assignment ID given!") presentation = request.values.get('introduction', "") parsons = request.values.get('parsons', "false") == "true" importable = request.values.get('importable', "false") == "true" secret = request.values.get('secret', "false") == "true" disable_algorithm_errors = request.values.get('disable_algorithm_errors', 'false') == 'true' disable_timeout = request.values.get('disable_timeout', 'false') == 'true' #text_first = request.values.get('text_first', "false") == "true" mode = request.values.get("initial", None) name = request.values.get('name', "") modules = request.values.get('modules', "") files = request.values.get('files', "") assignment = Assignment.by_id(int(assignment_id)) if not g.user.is_instructor(int(assignment.course_id)): return jsonify( success=False, message="You are not an instructor in this assignments' course.") Assignment.edit(assignment_id=assignment_id, presentation=presentation, name=name, parsons=parsons, mode=mode, modules=modules, importable=importable, disable_algorithm_errors=disable_algorithm_errors, disable_timeout=disable_timeout, files=files, secret=secret) return jsonify(success=True, ip=request.remote_addr)
def remove_assignment(lti=None): assignment_id = request.values.get('assignment_id', None) if assignment_id == None: return jsonify(success=False, message="Need assignment_id.") assignment = Assignment.by_id(int(assignment_id)) if not g.user.is_instructor(assignment.course_id): return jsonify(success=False, message="You are not an instructor in this assignment's course.") Assignment.remove(assignment.id) return jsonify(success=True)
def remove_assignment(lti=lti): assignment_id = request.values.get('assignment_id', None) if assignment_id is None: return jsonify(success=False, message="No assignment id") user, roles, course = ensure_canvas_arguments() if not User.is_lti_instructor(roles): return jsonify(success=False, message="You are not an instructor in this course.") # TODO: Security hole, evil instructors could remove assignments outside of their course Assignment.remove(assignment_id) return jsonify(success=True)
def save_presentation(lti=lti): assignment_id = request.form.get('question_id', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") presentation = request.form.get('presentation', "") name = request.form.get('name', "") if User.is_lti_instructor(session["roles"]): Assignment.edit(assignment_id=assignment_id, presentation=presentation, name=name) return jsonify(success=True) else: return jsonify(success=False, message="You are not an instructor!")
def save_presentation(lti=lti): assignment_id = request.form.get('assignment_id', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") presentation = request.form.get('introduction', "") parsons = request.form.get('parsons', "false") == "true" importable = request.form.get('importable', "false") == "true" text_first = request.form.get('text_first', "false") == "true" name = request.form.get('name', "") modules = request.form.get('modules', "") assignment = Assignment.by_id(int(assignment_id)) if not g.user.is_instructor(int(assignment.course_id)): return jsonify(success=False, message="You are not an instructor in this assignments' course.") Assignment.edit(assignment_id=assignment_id, presentation=presentation, name=name, parsons=parsons, text_first=text_first, modules=modules, importable=importable) return jsonify(success=True)
def submit_explain(lti=lti): assignment_id = request.form.get('question_id', None) lis_result_sourcedid = request.form.get('lis_result_sourcedid', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") user = User.from_lti("canvas", session["pylti_user_id"], session.get("user_email", ""), session.get("lis_person_name_given", ""), session.get("lis_person_name_family", "")) assignment = Assignment.by_id(assignment_id) submission = Submission.save_correct(user.id, assignment_id) code, elements = submission.load_explanation(5) if lis_result_sourcedid is None: return jsonify(success=False, message="Not in a grading context.") hl_lines = [e['line'][0] for e in elements] message = """<h1>Code Annotation</h1> <div>Thank you for submitting. This activity will be graded manually, so please be patient!</div> <div><ul><li>{explanations}</li></ul></div> <div>{code}</div> """.format( code = highlight(code, PythonLexer(), HtmlFormatter(linenos=True, hl_lines=hl_lines, noclasses=True)), explanations = '</li><li>'.join( ['<b>{line} ({type}):</b> {answer}'.format(line=e['line'][0], answer=e['answer'], type=Submission.abbreviate_element_type(e['name'])) for e in sorted(elements, key=lambda e: e['line'][0])]) ) lti.post_grade(0, message, endpoint=lis_result_sourcedid) return jsonify(success=True)
def save_correct(lti=lti): assignment_id = request.form.get('question_id', None) status = float(request.form.get('status', "0.0")) lis_result_sourcedid = request.form.get('lis_result_sourcedid', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") user = User.from_lti("canvas", session["pylti_user_id"], session.get("user_email", ""), session.get("lis_person_name_given", ""), session.get("lis_person_name_family", "")) assignment = Assignment.by_id(assignment_id) if status == 1: submission = Submission.save_correct(user.id, assignment_id) else: submission = assignment.get_submission(user.id) if submission.correct: message = "Success!" else: message = "Incomplete" url = url_for('lti_assignments.get_submission_code', submission_id=submission.id, _external=True) if lis_result_sourcedid is None: return jsonify(success=False, message="Not in a grading context.") if assignment.mode == 'maze': lti.post_grade(float(submission.correct), "<h1>{0}</h1>".format(message), endpoint=lis_result_sourcedid); else: lti.post_grade(float(submission.correct), "<h1>{0}</h1>".format(message)+"<div>Latest work in progress: <a href='{0}' target='_blank'>View</a></div>".format(url)+"<div>Touches: {0}</div>".format(submission.version)+"Last ran code:<br>"+highlight(submission.code, PythonLexer(), HtmlFormatter()), endpoint=lis_result_sourcedid) return jsonify(success=True)
def check_assignments(lti=lti): """ An AJAX endpoint for listing any new assignments. Unused. """ assignments = Assignment.by_course(g.course.id) return jsonify(success=True, assignments=[a.to_dict() for a in assignments])
def get_assignments_from_request(): assignment_id = request.args.get('assignment_id', None) assignment_group_id = request.args.get('assignment_group_id', None) if 'course_id' in request.args: course_id = int(request.args.get('course_id')) if 'course_id' in request.form: course_id = int(request.form.get('course_id')) if 'user' in g and g.user != None: user_id = g.user.id else: user_id = None if 'course' in g: course_id = g.course.id else: course_id = None submission_url = request.form.get('lis_result_sourcedid', '') # Assignment group or individual assignment? if assignment_group_id is not None: group = AssignmentGroup.by_id(int(assignment_group_id) if assignment_group_id != None else None) assignments = natsorted(group.get_assignments(), key = lambda a: a.title()) submissions = [a.get_submission(user_id, course_id=course_id, submission_url=submission_url) for a in assignments] elif assignment_id is not None: assignment = Assignment.by_id(int(assignment_id) if assignment_id != None else None) assignments = [assignment] if assignment else [] submissions = [assignment.get_submission(user_id, course_id=course_id, submission_url=submission_url)] if assignment else [] else: assignments = [] submissions = [] return assignments, submissions
def submit_explain(lti=lti): assignment_id = request.form.get('assignment_id', None) course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") assignment = Assignment.by_id(int(assignment_id)) submission = Submission.save_correct(g.user.id, int(assignment_id), int(course_id)) lis_result_sourcedid = request.form.get('lis_result_sourcedid', submission.url) or None code, elements = submission.load_explanation(4) if lis_result_sourcedid is None or lis_result_sourcedid == "NOT IN SESSION": return jsonify(success=False, message="Not in a grading context.") hl_lines = [e['line'][0] for e in elements] message = """<h1>Code Annotation</h1> <div>Thank you for submitting. This activity will be graded manually, so please be patient!</div> <div><ul><li>{explanations}</li></ul></div> <div>{code}</div> """.format(code=highlight( code, PythonLexer(), HtmlFormatter(linenos=True, hl_lines=hl_lines, noclasses=True)), explanations='</li><li>'.join([ '<b>{line} ({type}):</b> {answer}'.format( line=e['line'][0], answer=e['answer'], type=Submission.abbreviate_element_type(e['name'])) for e in sorted(elements, key=lambda e: e['line'][0]) ])) lti.post_grade(0, message, endpoint=lis_result_sourcedid) return jsonify(success=True)
def index(lti=lti): """ initial access page to the lti provider. This page provides authorization for the user. :param lti: the `lti` object from `pylti` :return: index page for lti provider """ assignment_id = request.args.get('assignment_id', None) assignment_group_id = request.args.get('assignment_group_id', None) user, roles, course = ensure_canvas_arguments() # Assignment group or individual assignment? if assignment_group_id is not None: group = AssignmentGroup.by_id(assignment_group_id) assignments = group.get_assignments() submissions = [a.get_submission(user.id) for a in assignments] elif assignment_id is not None: assignments = [Assignment.by_id(assignment_id)] submissions = [assignments[0].get_submission(user.id)] else: return error() # Use the proper template if assignments[0].mode == 'maze': return render_template('lti/maze.html', lti=lti, assignment= assignments[0], submission= submissions[0], level=assignments[0].name) elif assignments[0].mode == 'explain': return render_template('lti/explain.html', lti=lti, assignment= assignments[0], submission= submissions[0]) else: return render_template('lti/index.html', lti=lti, group=zip(assignments, submissions))
def submit_explain(lti=lti): assignment_id = request.form.get('question_id', None) lis_result_sourcedid = request.form.get('lis_result_sourcedid', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") user = User.from_lti("canvas", session["pylti_user_id"], session.get("user_email", ""), session.get("lis_person_name_given", ""), session.get("lis_person_name_family", "")) assignment = Assignment.by_id(assignment_id) submission = Submission.save_correct(user.id, assignment_id) code, elements = submission.load_explanation(5) if lis_result_sourcedid is None: return jsonify(success=False, message="Not in a grading context.") hl_lines = [e['line'][0] for e in elements] message = """<h1>Code Annotation</h1> <div>Thank you for submitting. This activity will be graded manually, so please be patient!</div> <div><ul><li>{explanations}</li></ul></div> <div>{code}</div> """.format(code=highlight( code, PythonLexer(), HtmlFormatter(linenos=True, hl_lines=hl_lines, noclasses=True)), explanations='</li><li>'.join([ '<b>{line} ({type}):</b> {answer}'.format( line=e['line'][0], answer=e['answer'], type=Submission.abbreviate_element_type(e['name'])) for e in sorted(elements, key=lambda e: e['line'][0]) ])) lti.post_grade(0, message, endpoint=lis_result_sourcedid) return jsonify(success=True)
def new_assignment(lti=lti): user, roles, course = ensure_canvas_arguments() menu = request.values.get('menu', "select") if not User.is_lti_instructor(roles): return "You are not an instructor in this course." assignment = Assignment.new(owner_id=user.id, course_id=course.id) launch_type = 'lti_launch_url' if menu != 'share' else 'iframe' endpoint = 'lti_assignments.index' if menu != 'share' else 'lti_assignments.shared' return jsonify( success=True, redirect=url_for('lti_assignments.edit_assignment', assignment_id=assignment.id), id=assignment.id, name=assignment.name, body=strip_tags(assignment.body)[:255], title=assignment.title(), select=url_quote( url_for(endpoint, assignment_id=assignment.id, _external=True)) + "&return_type=" + launch_type + "&title=" + url_quote(assignment.title()) + "&text=BlockPy%20Exercise&width=100%25&height=600", edit=url_for('lti_assignments.edit_assignment', assignment_id=assignment.id), date_modified=assignment.date_modified.strftime( " %I:%M%p on %a %d, %b %Y").replace(" 0", " "))
def submit_explain(lti=lti): assignment_id = request.form.get('assignment_id', None) course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") assignment = Assignment.by_id(int(assignment_id)) submission = Submission.save_correct(g.user.id, int(assignment_id), int(course_id)) lis_result_sourcedid = request.form.get('lis_result_sourcedid', submission.url) or None code, elements = submission.load_explanation(4) if lis_result_sourcedid is None or lis_result_sourcedid == "NOT IN SESSION": return jsonify(success=False, message="Not in a grading context.") hl_lines = [e['line'][0] for e in elements] message = """<h1>Code Annotation</h1> <div>Thank you for submitting. This activity will be graded manually, so please be patient!</div> <div><ul><li>{explanations}</li></ul></div> <div>{code}</div> """.format( code = highlight(code, PythonLexer(), HtmlFormatter(linenos=True, hl_lines=hl_lines, noclasses=True)), explanations = '</li><li>'.join( ['<b>{line} ({type}):</b> {answer}'.format(line=e['line'][0], answer=e['answer'], type=Submission.abbreviate_element_type(e['name'])) for e in sorted(elements, key=lambda e: e['line'][0])]) ) lti.post_grade(0, message, endpoint=lis_result_sourcedid) return jsonify(success=True)
def save_questions(lti=lti): assignment_id = request.form.get('assignment_id', None) course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") if not g.user.is_instructor(int(course_id)): return jsonify( success=False, message="You are not an instructor in this assignments' course.") body = request.form.get('body', '') Assignment.edit(assignment_id=assignment_id, presentation=body, type='poll') return jsonify(success=True)
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 jsonify(success=False, message="No Course ID given!") if g.user is None or not g.user.is_instructor(int(course_id)): return jsonify(success=False, message="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 = len(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 view_assignments(course_id): #TODO: ensure in course course = Course.by_id(course_id) assignments = Assignment.by_course(course_id) groups = AssignmentGroup.by_course(course_id) return render_template('courses/view_assignments.html', assignments=assignments, groups=groups, course=course, course_id=course_id)
def move_membership(lti=None): # Get the attributes assignment_id = request.values.get('assignment_id', None) old_group_id = request.values.get('old_group_id', None) new_group_id = request.values.get('new_group_id', None) if None in (assignment_id, new_group_id, old_group_id): return jsonify(success=False, message="Need assignment_id, old_group_id, and new_group_id.") # Ensure that the assignment exists and that the user can modify it assignment = Assignment.by_id(int(assignment_id)) if not g.user.is_instructor(assignment.course_id): return jsonify(success=False, message="You are not an instructor in this assignment's course.") # Verify permissions if int(new_group_id) != -1: new_assignment_group = AssignmentGroup.by_id(int(new_group_id)) if not g.user.is_instructor(new_assignment_group.course_id): return jsonify(success=False, message="You are not an instructor in this assignment's course.") if int(old_group_id) != -1: old_assignment_group = AssignmentGroup.by_id(int(old_group_id)) if not g.user.is_instructor(old_assignment_group.course_id): return jsonify(success=False, message="You are not an instructor in this assignment's course.") # Perform action AssignmentGroupMembership.move_assignment(int(assignment_id), int(new_group_id)) # Result return jsonify(success=True)
def shared(lti=lti): """ render the contents of the assignment template :param lti: the `lti` object from `pylti` :return: the staff.html template rendered """ assignment_id = request.args.get('assignment_id', None) assignment_group_id = request.args.get('assignment_group_id', None) user, roles, course = ensure_canvas_arguments() # Assignment group or individual assignment? if assignment_group_id is not None: group = AssignmentGroup.by_id(assignment_group_id) assignments = group.get_assignments() submissions = [a.get_submission(user.id) for a in assignments] elif assignment_id is not None: assignments = [Assignment.by_id(assignment_id)] submissions = [assignments[0].get_submission(user.id)] else: return error() # Use the proper template if assignments[0].mode == 'maze': return render_template('lti/maze.html', lti=lti, assignment= assignments[0], submission= submissions[0], level=assignments[0].name) elif assignments[0].mode == 'explain': return render_template('lti/explain.html', lti=lti, assignment= assignments[0], submission= submissions[0]) else: return render_template('lti/index.html', lti=lti, group=zip(assignments, submissions))
def save_presentation(lti=lti): assignment_id = request.values.get('assignment_id', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") presentation = request.values.get('introduction', "") parsons = request.values.get('parsons', "false") == "true" importable = request.values.get('importable', "false") == "true" disable_algorithm_errors = request.values.get('disable_algorithm_errors', 'false') == 'true' text_first = request.values.get('text_first', "false") == "true" name = request.values.get('name', "") modules = request.values.get('modules', "") assignment = Assignment.by_id(int(assignment_id)) if not g.user.is_instructor(int(assignment.course_id)): return jsonify(success=False, message="You are not an instructor in this assignments' course.") Assignment.edit(assignment_id=assignment_id, presentation=presentation, name=name, parsons=parsons, text_first=text_first, modules=modules, importable=importable, disable_algorithm_errors=disable_algorithm_errors) return jsonify(success=True)
def get_assignment(lti=lti): ''' Returns metadata about the assignment. ''' assignment_id = request.values.get('assignment_id', None) if assignment_id is None: return jsonify(success=False, message="No assignment id") user, roles, course = ensure_canvas_arguments() if not User.is_lti_instructor(roles): return jsonify(success=False, message="You are not an instructor in this course.") # TODO: Security hole, evil instructors could remove assignments outside of their course assignment = Assignment.by_id(assignment_id) return jsonify(success=True, url=assignment.url, name=assignment.name, body=strip_tags(assignment.body)[:255], on_run=assignment.on_run, title=assignment.title(), answer=assignment.answer, type=assignment.type, visibility=assignment.visibility, disabled=assignment.disabled, mode=assignment.mode, version=assignment.version, id=assignment.id, course_id=assignment.course_id, date_modified=assignment.date_modified.strftime( " %I:%M%p on %a %d, %b %Y").replace(" 0", " "))
def get_assignments_from_request(): assignment_id = request.args.get('assignment_id', None) assignment_group_id = request.args.get('assignment_group_id', None) if 'course_id' in request.args: course_id = int(request.args.get('course_id')) if 'course_id' in request.form: course_id = int(request.form.get('course_id')) if 'user' in g and g.user != None: user_id = g.user.id else: user_id = None if 'course' in g: course_id = g.course.id else: course_id = None submission_url = request.form.get('lis_result_sourcedid', '') # Assignment group or individual assignment? if assignment_group_id is not None: group = AssignmentGroup.by_id(int(assignment_group_id) if assignment_group_id != None else None) assignments = group.get_assignments() submissions = [a.get_submission(user_id, course_id=course_id, submission_url=submission_url) for a in assignments] elif assignment_id is not None: assignment = Assignment.by_id(int(assignment_id) if assignment_id != None else None) assignments = [assignment] if assignment else [] submissions = [assignment.get_submission(user_id, course_id=course_id, submission_url=submission_url)] if assignment else [] else: assignments = [] submissions = [] return assignments, submissions
def assignments(course_id): #TODO: ensure in course assignments = Assignment.get_available() groups = AssignmentGroup.query.all() course_groups = Course.get_all_groups() editable_courses = g.user.get_editable_courses() return render_template('courses/assignments.html', assignments=assignments, groups=groups, editable_courses=editable_courses, course_groups=course_groups, course_id=course_id)
def save_presentation(lti=lti): assignment_id = request.form.get('question_id', None) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") presentation = request.form.get('presentation', "") parsons = request.form.get('parsons', "false") == "true" text_first = request.form.get('text_first', "false") == "true" name = request.form.get('name', "") if User.is_lti_instructor(session["roles"]): Assignment.edit(assignment_id=assignment_id, presentation=presentation, name=name, parsons=parsons, text_first=text_first) return jsonify(success=True) else: return jsonify(success=False, message="You are not an instructor!")
def _assignment_obj_from_text(title, text, doc_link, doc_name, course): """ Convert text to Assignment Object @param title: title of assignment @type title: str @param text: description of Assignment @type text: str @param doc_link: url of attachment @type doc_link: str @param doc_name: name of attachment @type doc_name: str @param course: course name @type course: str @return: @rtype: """ assignment = Assignment() assignment.title = title assignment.doc_link = doc_link assignment.doc_name = doc_name assignment.course = course try: info_list = text.split("\n") assignment.due_date = info_list[3].replace("Due date", '').strip() except IndexError as e: logger.error(e) return assignment
def batch_edit(lti=lti): user, roles, course = ensure_canvas_arguments() if not g.user.is_instructor(g.course.id): return jsonify(success=False, message="You are not an instructor in this course.") assignments = Assignment.by_course(course.id) return render_template('lti/batch.html', assignments=assignments, user_id=user.id, context_id=course.id)
def batch_edit(lti=lti): user, roles, course = ensure_canvas_arguments() if not User.is_lti_instructor(roles): return "You are not an instructor in this course." assignments = Assignment.by_course(course.id) return render_template('lti/batch.html', assignments=assignments, user_id=user.id, context_id=course.id)
def load_questions(): assignment_id = request.form.get('assignment_id', None) course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") assignment = Assignment.by_id(assignment_id) return jsonify(success=True, body=assignment.body)
def check_assignments(lti=lti): """ An AJAX endpoint for listing any new assignments. Unused. """ # Store current user_id and context_id user, roles, course = ensure_canvas_arguments() assignments = Assignment.by_course(course.id) return jsonify(success=True, assignments=[a.to_dict() for a in assignments])
def save_correct(lti, lti_exception=None): assignment_id = request.values.get('assignment_id', None) assignment_group_id = request.values.get('group_id', None) status = float(request.values.get('status', "0.0")) image = request.values.get('image', "") hide_correctness = request.values.get('hide_correctness', "false") == "true" force_update = request.values.get('force_update', "false") == "true" course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if course_id == -1 or lti is None: return failure("No Assignment ID or Course ID given!") if None in (assignment_id, course_id): return failure("No Assignment ID or Course ID given!") assignment = Assignment.by_id(assignment_id) if status >= 1: submission = Submission.save_correct(g.user.id, assignment_id, course_id=int(course_id)) else: submission = assignment.get_submission(g.user.id, course_id=course_id) was_changed = submission.set_status(int(100 * status)) if not force_update and not was_changed: return jsonify(success=True, submitted=False, message="No grade change", ip=request.remote_addr) lis_result_sourcedid = request.values.get('lis_result_sourcedid', submission.url) or None if lis_result_sourcedid is None: return jsonify(success=True, submitted=False, message="Not in a grading context.", ip=request.remote_addr) session['lis_result_sourcedid'] = lis_result_sourcedid image_url = submission.save_block_image(image) if assignment_group_id != None and assignment_group_id != '' and assignment_group_id != 'None': score = get_group_score(int(assignment_group_id), g.user.id, int(course_id), hide_correctness) url = url_for('blockpy.view_current_group', group_id=int(assignment_group_id), course_id=int(course_id), user_id=g.user.id, _external=True) report = "<a href='{url}'>View Group</a>".format(url=url) else: score = float(submission.correct) or status url = url_for('blockpy.view_current_assignment', assignment_id=int(assignment_id), course_id=int(course_id), user_id=g.user.id, _external=True) report = "<a href='{url}'>View Assignment</a>".format(url=url) lti.post_grade(score, report, endpoint=lis_result_sourcedid) return jsonify(success=True, submitted=True, ip=request.remote_addr)
def select(lti, menu='select', lti_exception=None): """ Let's the user select from a list of assignments. """ # Store current user_id and context_id assignments = Assignment.get_available() groups = AssignmentGroup.query.all() return_url = get_lti_property('launch_presentation_return_url') course_groups = Course.get_all_groups() editable_courses = g.user.get_editable_courses() return render_template('lti/select.html', assignments=assignments, groups=groups, return_url=return_url, menu=menu, editable_courses=editable_courses, course_groups=course_groups)
def select(lti=lti): """ Let's the user select from a list of assignments. """ # Store current user_id and context_id user, roles, course = ensure_canvas_arguments() assignments = Assignment.by_course(course.id, exclude_builtins=True) groups = [(group, group.get_assignments()) for group in AssignmentGroup.by_course(course.id)] strays = AssignmentGroup.get_ungrouped_assignments(course.id) return_url = session['launch_presentation_return_url'] return render_template('lti/select.html', assignments=assignments, strays=strays, groups=groups, return_url=return_url, menu='select')
def move_course(lti=None): assignment_id = request.values.get('assignment_id', None) new_course_id = request.values.get('new_course_id', None) if None in (assignment_id, new_course_id): return jsonify(success=False, message="Need assignment_id and new_course_id.") assignment = Assignment.by_id(int(assignment_id)) if not g.user.is_instructor(assignment.course_id): return jsonify(success=False, message="You are not an instructor in this assignment's course.") if not g.user.is_instructor(int(new_course_id)): return jsonify(success=False, message="You are not an instructor in the new course.") assignment.move_course(new_course_id) return jsonify(success=True)
def save_code(lti=lti): assignment_id = request.values.get('assignment_id', None) assignment_version = int(request.values.get('version', -1)) course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if None in (assignment_id, course_id) or course_id == "": return failure("No Assignment ID or Course ID given!") code = request.values.get('code', '') timestamp = request.values.get('timestamp', '') filename = request.values.get('filename', '__main__') is_version_correct = True if filename == "__main__": submission, is_version_correct = Submission.save_code( g.user.id, assignment_id, int(course_id), code, assignment_version, timestamp=timestamp) elif g.user.is_instructor(int(course_id)): if filename == "give_feedback": Assignment.edit(assignment_id=assignment_id, give_feedback=code) elif filename == "on_change": Assignment.edit(assignment_id=assignment_id, on_step=code) elif filename == "starting_code": Assignment.edit(assignment_id=assignment_id, starting_code=code) log = Log.new('instructor', filename, assignment_id, g.user.id, body=code, timestamp=timestamp) return jsonify(success=True, is_version_correct=is_version_correct, ip=request.remote_addr)
def decorated_function(course_id, *args, **kwargs): assignment_id = request.values.get('assignment_id', None) # there is an assignment_id if assignment_id is None: return jsonify(success=False, message="No assignment id") # It's an integer value try: assignment_id = int(assignment_id) except ValueError: return jsonify(success=False, message="Assignment ID wasn't an integer") if not Assignment.is_in_course(assignment_id, course_id): return jsonify(success=False, message="That assignment id does not belong to that course.") return f(*args, course_id=course_id, **kwargs)
def edit_assignment(assignment_id, lti=lti): assignment = Assignment.by_id(assignment_id) if not assignment: return "Assignment ID not found" if not g.user.is_instructor(assignment.course_id): return jsonify(success=False, message="You are not an instructor in this course.") submission = assignment.get_submission(g.user.id) return render_template('lti/edit.html', assignment=assignment, submission=submission, user_id=g.user.id, context_id=assignment.course_id)
def save_correct(lti, lti_exception=None): assignment_id = request.form.get('assignment_id', None) status = float(request.form.get('status', "0.0")) image = request.form.get('image', "") course_id = request.form.get('course_id', g.course.id) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") assignment = Assignment.by_id(assignment_id) if status == 1: submission = Submission.save_correct(g.user.id, assignment_id, course_id=int(course_id)) else: submission = assignment.get_submission(g.user.id, course_id=course_id) if submission.correct: message = "Success!" else: message = "Incomplete" sub_blocks_folder = os.path.join(app.config['UPLOADS_DIR'], 'submission_blocks') image_path = os.path.join(sub_blocks_folder, str(submission.id)+'.png') if image != "": converted_image = image[22:].decode('base64') with open(image_path, 'wb') as image_file: image_file.write(converted_image); image_url = url_for('blockpy.get_submission_image', submission_id=submission.id, _external=True) elif os.path.exists(image_path): try: os.remove(image_path) except Exception: app.logger.info("Could not delete") lis_result_sourcedid = request.form.get('lis_result_sourcedid', submission.url) or None url = url_for('blockpy.get_submission_code', submission_id=submission.id, _external=True) print url if lis_result_sourcedid is None: return jsonify(success=False, message="Not in a grading context.") else: session['lis_result_sourcedid'] = lis_result_sourcedid if assignment.mode == 'maze': lti.post_grade(float(submission.correct), "<h1>{0}</h1>".format(message), endpoint=lis_result_sourcedid); else: code = highlight(submission.code, PythonLexer(), HtmlFormatter()) potential_image = "Submitted Blocks:<br><img src='{0}'>".format(image_url) if image else "" body = ''' <h1>{message}</h1> <div>Latest work in progress: <a href='{url}' target='_blank'>View</a></div> <div>Touches: {touches}</div> {potential_image} <br> Submitted code:<br> {code} '''.format(message=message, url=url, touches=submission.version, code=code, potential_image=potential_image) lti.post_grade(float(submission.correct), body, endpoint=lis_result_sourcedid) return jsonify(success=True)
def save_correct(lti, lti_exception=None): assignment_id = request.values.get('assignment_id', None) status = float(request.values.get('status', "0.0")) image = request.values.get('image', "") course_id = request.values.get('course_id', g.course.id if 'course' in g else None) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") assignment = Assignment.by_id(assignment_id) if status == 1: submission = Submission.save_correct(g.user.id, assignment_id, course_id=int(course_id)) else: submission = assignment.get_submission(g.user.id, course_id=course_id) if submission.correct: message = "Success!" else: message = "Incomplete" sub_blocks_folder = os.path.join(app.config['UPLOADS_DIR'], 'submission_blocks') image_path = os.path.join(sub_blocks_folder, str(submission.id)+'.png') if image != "": converted_image = image[22:].decode('base64') with open(image_path, 'wb') as image_file: image_file.write(converted_image); image_url = url_for('blockpy.get_submission_image', submission_id=submission.id, _external=True) elif os.path.exists(image_path): try: os.remove(image_path) except Exception: app.logger.info("Could not delete") lis_result_sourcedid = request.values.get('lis_result_sourcedid', submission.url) or None url = url_for('blockpy.get_submission_code', submission_id=submission.id, _external=True) if lis_result_sourcedid is None: return jsonify(success=False, message="Not in a grading context.") else: session['lis_result_sourcedid'] = lis_result_sourcedid if assignment.mode == 'maze': lti.post_grade(float(submission.correct), "<h1>{0}</h1>".format(message), endpoint=lis_result_sourcedid); else: formatter = HtmlFormatter(linenos=True, noclasses=True) code = highlight(submission.code, PythonLexer(), formatter) potential_image = "Submitted Blocks:<br><img src='{0}'>".format(image_url) if image else "" body = ''' <h1>{message}</h1> <div>Latest work in progress: <a href='{url}' target='_blank'>View</a></div> <div>Touches: {touches}</div> {potential_image} <br> Submitted code:<br> {code} '''.format(message=message, url=url, touches=submission.version, code=code, potential_image=potential_image) lti.post_grade(float(submission.correct), body, endpoint=lis_result_sourcedid) return jsonify(success=True)
def share(lti=lti): """ render the contents of the staff.html template :param lti: the `lti` object from `pylti` :return: the staff.html template rendered """ user, roles, course = ensure_canvas_arguments() assignments = Assignment.by_course(course.id, exclude_builtins=True) groups = [(group, group.get_assignments()) for group in AssignmentGroup.by_course(course.id)] strays = AssignmentGroup.get_ungrouped_assignments(course.id) return_url = session['launch_presentation_return_url'] return render_template('lti/select.html', assignments=assignments, strays=strays, groups=groups, return_url=return_url, menu='share')
def select_builtin_assignment(lti=lti): assignment_type = request.args.get('assignment_type', None) assignment_id = request.args.get('assignment_id', None) user, roles, course = ensure_canvas_arguments() if not User.is_lti_instructor(roles): return "You are not an instructor in this course." assignment = Assignment.by_builtin(assignment_type, assignment_id, owner_id=user.id, course_id=course.id) assignment_url = url_for('lti_assignments.index', assignment_id=assignment.id, _external=True) print assignment_url encoded_url = url_quote(assignment_url) return jsonify(url=encoded_url)
def analyze_load_log(): assignment_id = request.args.get('assignment_id', None) user_id = request.args.get('user_id', None) if None in (assignment_id, user_id): return jsonify(success=False, message="No user_id or assignment_id given") assignment = Assignment.by_id(assignment_id) log_file = str(user_id)+"_"+str(assignment_id)+".log" log_file = os.path.join(app.config['ROOT_DIRECTORY'], 'queued_logs', log_file) if not os.path.isfile(log_file): return jsonify(success=False, message="No log found") with open(log_file) as opened_file: records = [json.loads(line) for line in opened_file] return render_template('analyzer.html', records=json.dumps(records), assignment=assignment)
def edit_assignment(assignment_id, lti=lti): user, roles, course = ensure_canvas_arguments() assignment = Assignment.by_id(assignment_id) if not assignment: return "Assignment ID not found" if not User.is_lti_instructor(roles): return "You are not an instructor in this course." if not assignment.context_is_valid(course.external_id): return "This assignment does not belong to this course." submission = assignment.get_submission(user.id) return render_template('lti/edit.html', assignment=assignment, submission=submission, user_id=user.id, context_id=course.id)
def blockpy_canvas(): assignment_id = request.args.get('assignment_id', None) if assignment_id is not None: assignment = Assignment.by_id(assignment_id) if g.user is not None: submission = assignment.get_submission(g.user.id) else: submission = {} else: assignment = {'presentation': '', 'id': 1} submission = {} user = {'id': 1} course = {'id': 1} return render_template('blockpy.html', assignment=assignment, submission=submission, user=user, course=course)
def new_assignment(lti=lti): user, roles, course = ensure_canvas_arguments() menu = request.values.get('menu', "select") if not User.is_lti_instructor(roles): return "You are not an instructor in this course." assignment = Assignment.new(owner_id=user.id, course_id=course.id) launch_type = 'lti_launch_url' if menu != 'share' else 'iframe' endpoint = 'lti_assignments.index' if menu != 'share' else 'lti_assignments.shared' return jsonify(success=True, redirect=url_for('lti_assignments.edit_assignment', assignment_id=assignment.id), id= assignment.id, name= assignment.name, body= strip_tags(assignment.body)[:255], title= assignment.title(), select = url_quote(url_for(endpoint, assignment_id=assignment.id, _external=True))+"&return_type="+launch_type+"&title="+url_quote(assignment.title())+"&text=BlockPy%20Exercise&width=100%25&height=600", edit= url_for('lti_assignments.edit_assignment', assignment_id=assignment.id), date_modified = assignment.date_modified.strftime(" %I:%M%p on %a %d, %b %Y").replace(" 0", " "))
def index(lti=lti): """ initial access page to the lti provider. This page provides authorization for the user. :param lti: the `lti` object from `pylti` :return: index page for lti provider """ assignment_id = request.args.get('assignment_id', None) assignment_group_id = request.args.get('assignment_group_id', None) user, roles, course = ensure_canvas_arguments() # Assignment group or individual assignment? if assignment_group_id is not None: group = AssignmentGroup.by_id(assignment_group_id) assignments = group.get_assignments() submissions = [a.get_submission(user.id) for a in assignments] elif assignment_id is not None: assignments = [Assignment.by_id(assignment_id)] submissions = [assignments[0].get_submission(user.id)] else: return error() if 'ip_address_found' not in session or session['ip_address_found'] != request.remote_addr: session['ip_address_found'] = request.remote_addr log_user_ip(user.id) # Use the proper template if assignments[0].mode == 'maze': return render_template('lti/maze.html', lti=lti, assignment= assignments[0], submission= submissions[0], level=assignments[0].name, user_id=user.id) elif assignments[0].mode == 'explain': MAX_QUESTIONS = 5 code, elements = submissions[0].load_explanation(MAX_QUESTIONS) return render_template('lti/explain.html', lti=lti, assignment= assignments[0], submission= submissions[0], code = code, elements=elements, user_id=user.id) else: return render_template('lti/index.html', lti=lti, group=zip(assignments, submissions), user_id=user.id)
def get_assignment(lti=lti): ''' Returns metadata about the assignment. ''' assignment_id = request.values.get('assignment_id', None) if assignment_id is None: return jsonify(success=False, message="No assignment id") user, roles, course = ensure_canvas_arguments() if not User.is_lti_instructor(roles): return jsonify(success=False, message="You are not an instructor in this course.") # TODO: Security hole, evil instructors could remove assignments outside of their course assignment = Assignment.by_id(assignment_id) return jsonify(success=True, url=assignment.url, name=assignment.name, body= strip_tags(assignment.body)[:255], on_run=assignment.on_run, title= assignment.title(), answer=assignment.answer, type=assignment.type, visibility=assignment.visibility, disabled=assignment.disabled, mode=assignment.mode, version=assignment.version, id=assignment.id, course_id=assignment.course_id, date_modified = assignment.date_modified.strftime(" %I:%M%p on %a %d, %b %Y").replace(" 0", " "))
def save(): # problem_id if 'question_id' in request.values: question_id = request.values['question_id'] else: return jsonify(success=False, message="No problem ID given.") # user_id if g.user: user_id = g.user.id else: return jsonify(success=False, message="You are not logged in.") # values code = request.values.get('code', '') assignment = Assignment.by_id(question_id) submission = assignment.get_submission(g.user.id) submission.code = code db.session.commit() # Do saving return jsonify(success=True)
def save_code(lti=lti): assignment_id = request.form.get('assignment_id', None) assignment_version = int(request.form.get('version', -1)) course_id = request.form.get('course_id', g.course.id) if None in (assignment_id, course_id): return jsonify(success=False, message="No Assignment ID or Course ID given!") code = request.form.get('code', '') filename = request.form.get('filename', '__main__') is_version_correct = True if filename == "__main__": submission, is_version_correct = Submission.save_code(g.user.id, assignment_id, int(course_id), code, assignment_version) elif g.user.is_instructor(int(course_id)): if filename == "give_feedback": Assignment.edit(assignment_id=assignment_id, give_feedback=code) elif filename == "on_change": Assignment.edit(assignment_id=assignment_id, on_step=code) elif filename == "starting_code": Assignment.edit(assignment_id=assignment_id, starting_code=code) return jsonify(success=True, is_version_correct=is_version_correct)
def save_code(lti=lti): assignment_id = request.form.get('question_id', None) assignment_version = int(request.form.get('version', -1)) if assignment_id is None: return jsonify(success=False, message="No Assignment ID given!") code = request.form.get('code', '') filename = request.form.get('filename', '__main__') user = User.from_lti("canvas", session["pylti_user_id"], session.get("user_email", ""), session.get("lis_person_name_given", ""), session.get("lis_person_name_family", "")) is_version_correct = True if filename == "__main__": submission, is_version_correct = Submission.save_code(user.id, assignment_id, code, assignment_version) elif User.is_lti_instructor(session["roles"]): if filename == "on_run": Assignment.edit(assignment_id=assignment_id, on_run=code) elif filename == "on_change": Assignment.edit(assignment_id=assignment_id, on_step=code) elif filename == "starting_code": Assignment.edit(assignment_id=assignment_id, on_start=code) return jsonify(success=True, is_version_correct=is_version_correct)