import os import re from functools import wraps from flask import redirect, render_template, jsonify, current_app from flask_login import login_required, current_user from flask import make_response from flask import send_file, url_for, redirect, request from flask_restful.reqparse import RequestParser from bouncer.constants import READ from compair.authorization import require from compair.kaltura import KalturaAPI from compair.models import File from compair.core import event on_get_file = event.signal('GET_FILE') attachment_download_parser = RequestParser() attachment_download_parser.add_argument('name', default=None) def register_api_blueprints(app): # Initialize rest of the api modules from .course import course_api app.register_blueprint( course_api, url_prefix='/api/courses') from .classlist import classlist_api app.register_blueprint( classlist_api, url_prefix='/api/courses/<course_uuid>/users')
nullable=False, help='Course term/semester is required.') duplicate_course_parser.add_argument('sandbox', type=bool, default=False) duplicate_course_parser.add_argument('start_date', required=True, nullable=False, help='Course start date is required.') duplicate_course_parser.add_argument('end_date', default=None) # has to add location parameter, otherwise MultiDict will screw up the list duplicate_course_parser.add_argument('assignments', type=list, default=[], location='json') #only ids and dates # events on_course_modified = event.signal('COURSE_MODIFIED') on_course_get = event.signal('COURSE_GET') on_course_delete = event.signal('COURSE_DELETE') on_course_list_get = event.signal('COURSE_LIST_GET') on_course_create = event.signal('COURSE_CREATE') on_course_duplicate = event.signal('COURSE_DUPLICATE') class CourseListAPI(Resource): @login_required def post(self): """ Create new course """ require( CREATE,
from copy import copy from flask import Blueprint, current_app from flask_login import current_user, login_required from flask_restful import Resource, marshal from compair.models import User from compair.core import abort, impersonation, event from .util import new_restful_api from . import dataformat impersonation_api = Blueprint('impersonation_api', __name__) IMPERSONATION_API_BASE_URL = '/api/impersonate' # events on_impersonation_started = event.signal('IMPERSONATION_STARTED') on_impersonation_stopped = event.signal('IMPERSONATION_STOPPED') class ImpersonationAPI(Resource): @login_required def post(self, user_uuid): if not current_app.config.get('IMPERSONATION_ENABLED', False): abort(404, title="Impersonation not supported", message="Impersonation function not enabled") original_user = User.query.get(current_user.id) impersonate_as_uuid = user_uuid impersonate_as_user = User.get_by_uuid_or_404(impersonate_as_uuid) if not impersonation.can_impersonate(impersonate_as_user.get_id()): abort(400, title="Impersonation Failed", message="Cannot perform impersonation") impersonation_success = impersonation.start_impersonation(impersonate_as_user.get_id())
'displayname': 6, 'group_name': 7 } CAS_OR_SAML_IMPORT = { 'username': 0, 'student_number': 1, 'firstname': 2, 'lastname': 3, 'email': 4, 'displayname': 5, 'group_name': 6 } # events on_classlist_get = event.signal('CLASSLIST_GET') on_classlist_upload = event.signal('CLASSLIST_UPLOAD') on_classlist_enrol = event.signal('CLASSLIST_ENROL') on_classlist_unenrol = event.signal('CLASSLIST_UNENROL') on_classlist_instructor = event.signal('CLASSLIST_INSTRUCTOR_GET') on_classlist_student = event.signal('CLASSLIST_STUDENT_GET') on_classlist_update_users_course_roles = event.signal( 'CLASSLIST_UPDATE_USERS_COURSE_ROLES') def _parse_user_row(import_type, row): length = len(row) columns = COMPAIR_IMPORT if import_type == ThirdPartyType.cas.value or import_type == ThirdPartyType.saml.value: columns = CAS_OR_SAML_IMPORT
from compair.models import Assignment, Course, AssignmentComment from .util import new_restful_api, get_model_changes, pagination_parser assignment_comment_api = Blueprint('assignment_comment_api', __name__) api = new_restful_api(assignment_comment_api) new_assignment_comment_parser = RequestParser() new_assignment_comment_parser.add_argument('content', required=True) existing_assignment_comment_parser = new_assignment_comment_parser.copy() existing_assignment_comment_parser.add_argument('id', required=True, help="Comment id is required.") # events on_assignment_comment_modified = event.signal('ASSIGNMENT_COMMENT_MODIFIED') on_assignment_comment_get = event.signal('ASSIGNMENT_COMMENT_GET') on_assignment_comment_list_get = event.signal('ASSIGNMENT_COMMENT_LIST_GET') on_assignment_comment_create = event.signal('ASSIGNMENT_COMMENT_CREATE') on_assignment_comment_delete = event.signal('ASSIGNMENT_COMMENT_DELETE') # / class AssignmentCommentRootAPI(Resource): # TODO pagination @login_required def get(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) require( READ,
from sqlalchemy import func, and_, or_ from sqlalchemy.orm import undefer, joinedload from . import dataformat from compair.authorization import require from compair.models import Course, Assignment, CourseRole, User, UserCourse, Comparison, \ AnswerComment, Answer, File, AnswerScore, AnswerCommentType, PairingAlgorithm, \ AssignmentGrade, Group from .util import new_restful_api from compair.core import event, abort gradebook_api = Blueprint('gradebook_api', __name__) api = new_restful_api(gradebook_api) # events on_gradebook_get = event.signal('GRADEBOOK_GET') # / class GradebookAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404( assignment_uuid, joinedloads=['assignment_criteria'] ) require(MANAGE, assignment, title="Participation Results Unavailable", message="Sorry, your role in this course does not allow you to view student participation for this assignment.")
from compair.authorization import allow, require from compair.models import Assignment, Course, Answer, ComparisonExample from .util import new_restful_api, get_model_changes comparison_example_api = Blueprint('comparison_example_api', __name__) api = new_restful_api(comparison_example_api) new_comparison_example_parser = RequestParser() new_comparison_example_parser.add_argument('answer1_id', required=True, nullable=False) new_comparison_example_parser.add_argument('answer2_id', required=True, nullable=False) existing_comparison_example_parser = new_comparison_example_parser.copy() existing_comparison_example_parser.add_argument('id', required=True, nullable=False) # events on_comparison_example_modified = event.signal('COMPARISON_EXAMPLE_MODIFIED') on_comparison_example_list_get = event.signal('COMPARISON_EXAMPLE_LIST_GET') on_comparison_example_create = event.signal('COMPARISON_EXAMPLE_CREATE') on_comparison_example_delete = event.signal('COMPARISON_EXAMPLE_DELETE') # /id class ComparisonExampleIdAPI(Resource): @login_required def post(self, course_uuid, assignment_uuid, comparison_example_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) comparison_example = ComparisonExample.get_active_by_uuid_or_404(comparison_example_uuid) require(EDIT, comparison_example, title="Comparison Example Not Saved", message="Sorry, your role in this course does not allow you to save practice answers.")
user_id_course_list_parser = pagination_parser.copy() user_id_course_list_parser.add_argument('search', required=False, default=None) user_id_course_list_parser.add_argument('includeSandbox', type=string_to_bool, required=False, default=None) user_id_course_list_parser.add_argument('orderBy', required=False, default=None) user_id_course_list_parser.add_argument('reverse', type=bool, default=False) user_course_status_list_parser = RequestParser() user_course_status_list_parser.add_argument('ids', required=True, default=None) # events on_user_modified = event.signal('USER_MODIFIED') on_user_get = event.signal('USER_GET') on_user_list_get = event.signal('USER_LIST_GET') on_user_create = event.signal('USER_CREATE') on_user_course_get = event.signal('USER_COURSE_GET') on_user_course_status_get = event.signal('USER_COURSE_STATUS_GET') on_teaching_course_get = event.signal('USER_TEACHING_COURSE_GET') on_user_edit_button_get = event.signal('USER_EDIT_BUTTON_GET') on_user_notifications_update = event.signal('USER_NOTIFICATIONS_UPDATE') on_user_password_update = event.signal('USER_PASSWORD_UPDATE') def check_valid_system_role(system_role): system_roles = [ SystemRole.sys_admin.value, SystemRole.instructor.value, SystemRole.student.value
answer_list_parser.add_argument('orderBy', required=False, default=None) answer_list_parser.add_argument('top', type=bool, required=False, default=None) answer_list_parser.add_argument('ids', required=False, default=None) user_answer_list_parser = RequestParser() user_answer_list_parser.add_argument('draft', type=bool, required=False, default=False) top_answer_parser = RequestParser() top_answer_parser.add_argument( 'top_answer', type=bool, required=True, nullable=False, help="Expected boolean value 'top_answer' is missing." ) # events on_answer_modified = event.signal('ANSWER_MODIFIED') on_answer_get = event.signal('ANSWER_GET') on_answer_list_get = event.signal('ANSWER_LIST_GET') on_answer_create = event.signal('ANSWER_CREATE') on_answer_delete = event.signal('ANSWER_DELETE') on_set_top_answer = event.signal('SET_TOP_ANSWER') on_user_answer_get = event.signal('USER_ANSWER_GET') from compair.api.file import on_attach_file, on_detach_file # / class AnswerRootAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): """ Return a list of answers for a assignment based on search criteria. The
answer_comparison_list_parser.add_argument('author', type=str, required=False, default=None) flag_parser = RequestParser() flag_parser.add_argument('flagged', type=bool, required=True, help="Expected boolean value 'flagged' is missing." ) top_answer_parser = RequestParser() top_answer_parser.add_argument( 'top_answer', type=bool, required=True, help="Expected boolean value 'top_answer' is missing." ) # events on_answer_modified = event.signal('ANSWER_MODIFIED') on_answer_get = event.signal('ANSWER_GET') on_answer_list_get = event.signal('ANSWER_LIST_GET') on_answer_create = event.signal('ANSWER_CREATE') on_answer_delete = event.signal('ANSWER_DELETE') on_answer_flag = event.signal('ANSWER_FLAG') on_set_top_answer = event.signal('SET_TOP_ANSWER') on_user_answer_get = event.signal('USER_ANSWER_GET') on_answer_comparisons_get = event.signal('ANSWER_COMPARISONS_GET') # messages answer_deadline_message = 'Answer deadline has passed.' # / class AnswerRootAPI(Resource): @login_required
'displayname': 6, 'group_name': 7 } CAS_OR_SAML_IMPORT = { 'username': 0, 'student_number': 1, 'firstname': 2, 'lastname': 3, 'email': 4, 'displayname': 5, 'group_name': 6 } # events on_classlist_get = event.signal('CLASSLIST_GET') on_classlist_upload = event.signal('CLASSLIST_UPLOAD') on_classlist_enrol = event.signal('CLASSLIST_ENROL') on_classlist_unenrol = event.signal('CLASSLIST_UNENROL') on_classlist_instructor = event.signal('CLASSLIST_INSTRUCTOR_GET') on_classlist_student = event.signal('CLASSLIST_STUDENT_GET') on_classlist_update_users_course_roles = event.signal('CLASSLIST_UPDATE_USERS_COURSE_ROLES') def _parse_user_row(import_type, row): length = len(row) columns = COMPAIR_IMPORT if import_type == ThirdPartyType.cas.value or import_type == ThirdPartyType.saml.value: columns = CAS_OR_SAML_IMPORT
from compair.models import UserCourse, User, Course, CourseRole, \ ThirdPartyUser, ThirdPartyType from .util import new_restful_api from .file import allowed_file course_group_api = Blueprint('course_group_api', __name__) api = new_restful_api(course_group_api) USER_IDENTIFIER = 0 GROUP_NAME = 1 import_parser = RequestParser() import_parser.add_argument('userIdentifier', type=str, required=True) # events on_course_group_get = event.signal('COURSE_GROUP_GET') on_course_group_import = event.signal('COURSE_GROUP_IMPORT') on_course_group_members_get = event.signal('COURSE_GROUP_MEMBERS_GET') def import_members(course, identifier, members): # initialize list of users and their statuses invalids = [] #invalid entry - eg. no group name user_infile = [] # for catching duplicate users count = 0 # keep track of active groups # require all rows to have two columns if there are a minimum of one entry if len(members) > 0 and len(members[0]) != 2: invalids.append({'member': {}, 'message': 'Only user identifier and group name fields should be in the file.'}) return {'success': count, 'invalids': invalids} elif identifier not in [ThirdPartyType.cas.value, 'username', 'student_number']: invalids.append({'member': {}, 'message': 'A valid user identifier is not given.'})
new_consumer_parser = reqparse.RequestParser() new_consumer_parser.add_argument('oauth_consumer_key', type=str, required=True, nullable=False) new_consumer_parser.add_argument('oauth_consumer_secret', type=str) new_consumer_parser.add_argument('global_unique_identifier_param', type=non_blank_text) new_consumer_parser.add_argument('student_number_param', type=non_blank_text) existing_consumer_parser = new_consumer_parser.copy() existing_consumer_parser.add_argument('id', type=str, required=True, nullable=False) existing_consumer_parser.add_argument('active', type=bool, default=True) consumer_list_parser = pagination_parser.copy() consumer_list_parser.add_argument('orderBy', type=str, required=False, default=None) consumer_list_parser.add_argument('reverse', type=bool, default=False) # events on_consumer_list_get = event.signal('LTI_CONSUMER_LIST_GET') on_consumer_get = event.signal('LTI_CONSUMER_GET') on_consumer_update = event.signal('LTI_CONSUMER_EDIT') on_consumer_create = event.signal('LTI_CONSUMER_CREATE') # / class ConsumerAPI(Resource): @login_required def get(self): require(MANAGE, LTIConsumer, title="Consumers Unavailable", message="Sorry, your system role does not allow you to view LTI consumers.") params = consumer_list_parser.parse_args() query = LTIConsumer.query
from flask_login import current_user from sqlalchemy import and_, or_ from . import dataformat from compair.authorization import require from compair.core import db, event from compair.models import UserCourse, User, Course, CourseRole from .util import new_restful_api user_list_parser = RequestParser() user_list_parser.add_argument("ids", type=list, required=True, default=[], location="json") course_group_user_api = Blueprint("course_group_user_api", __name__) api = new_restful_api(course_group_user_api) on_course_group_user_create = event.signal("COURSE_GROUP_USER_CREATE") on_course_group_user_list_create = event.signal("COURSE_GROUP_USER_LIST_CREATE") on_course_group_user_delete = event.signal("COURSE_GROUP_USER_DELETE") on_course_group_user_list_delete = event.signal("COURSE_GROUP_USER_LIST_CREATE") # /:user_uuid/groups/:group_name class GroupUserIdAPI(Resource): @login_required def post(self, course_uuid, user_uuid, group_name): course = Course.get_active_by_uuid_or_404(course_uuid) user = User.get_by_uuid_or_404(user_uuid) user_course = UserCourse.query.filter( and_( UserCourse.course_id == course.id, UserCourse.user_id == user.id,
type=non_blank_text, required=False, default=None) user_id_course_list_parser.add_argument('orderBy', required=False, default=None) user_id_course_list_parser.add_argument('reverse', type=bool, default=False) user_course_status_list_parser = RequestParser() user_course_status_list_parser.add_argument('ids', required=True, nullable=False, default=None) # events on_user_modified = event.signal('USER_MODIFIED') on_user_get = event.signal('USER_GET') on_user_list_get = event.signal('USER_LIST_GET') on_user_create = event.signal('USER_CREATE') on_user_course_get = event.signal('USER_COURSE_GET') on_user_course_status_get = event.signal('USER_COURSE_STATUS_GET') on_teaching_course_get = event.signal('USER_TEACHING_COURSE_GET') on_user_edit_button_get = event.signal('USER_EDIT_BUTTON_GET') on_user_notifications_update = event.signal('USER_NOTIFICATIONS_UPDATE') on_user_password_update = event.signal('USER_PASSWORD_UPDATE') on_user_lti_users_get = event.signal('USER_LTI_USERS_GET') on_user_lti_user_unlink = event.signal('USER_LTI_USER_UNLINK') on_user_third_party_users_get = event.signal('USER_THIRD_PARTY_USERS_GET') on_user_third_party_user_delete = event.signal('USER_THIRD_PARTY_USER_DELETE')
new_assignment_parser.add_argument('number_of_comparisons', type=int, required=True) new_assignment_parser.add_argument('enable_self_evaluation', type=int, default=None) new_assignment_parser.add_argument('pairing_algorithm', type=str, default=None) new_assignment_parser.add_argument('rank_display_limit', type=int, default=None) new_assignment_parser.add_argument('educators_can_compare', type=bool, default=False) # has to add location parameter, otherwise MultiDict will screw up the list new_assignment_parser.add_argument('criteria', type=list, default=[], location='json') new_assignment_parser.add_argument('answer_grade_weight', type=int, default=1) new_assignment_parser.add_argument('comparison_grade_weight', type=int, default=1) new_assignment_parser.add_argument('self_evaluation_grade_weight', type=int, default=1) existing_assignment_parser = new_assignment_parser.copy() existing_assignment_parser.add_argument('id', type=str, required=True, help="Assignment id is required.") # events on_assignment_modified = event.signal('ASSIGNMENT_MODIFIED') on_assignment_get = event.signal('ASSIGNMENT_GET') on_assignment_list_get = event.signal('ASSIGNMENT_LIST_GET') on_assignment_create = event.signal('ASSIGNMENT_CREATE') on_assignment_delete = event.signal('ASSIGNMENT_DELETE') on_assignment_list_get_status = event.signal('ASSIGNMENT_LIST_GET_STATUS') on_assignment_get_status = event.signal('ASSIGNMENT_GET_STATUS') def check_valid_pairing_algorithm(pairing_algorithm): pairing_algorithms = [ PairingAlgorithm.adaptive.value, PairingAlgorithm.random.value ] if pairing_algorithm not in pairing_algorithms: abort(400)
from flask_login import current_user, login_required, login_user, logout_user from flask_restful import marshal, Resource from compair.core import db, event, abort, impersonation from compair.authorization import get_logged_in_user_permissions from compair.models import User, LTIUser, LTIResourceLink, LTIUserResourceLink, UserCourse, LTIContext, \ ThirdPartyUser, ThirdPartyType from compair.cas import get_cas_login_url, validate_cas_ticket, get_cas_logout_url from compair.saml import get_saml_login_url, get_saml_auth_response, get_saml_logout_url, _get_auth from . import dataformat from .util import new_restful_api login_api = Blueprint("login_api", __name__, url_prefix='/api') # events on_login_with_method = event.signal('USER_LOGGED_IN_WITH_METHOD') on_logout = event.signal('USER_LOGGED_OUT') @login_api.route('/login', methods=['POST']) def login(): if not current_app.config.get('APP_LOGIN_ENABLED'): abort( 403, title="Log In Failed", message= "Please try an alternate way of logging in. The ComPAIR login has been disabled by your system administrator." ) # expecting login params to be in json format param = request.json
# First declare a Flask Blueprint for this module # Then pack the blueprint into a Flask-Restful API comparison_api = Blueprint('comparison_api', __name__) api = new_restful_api(comparison_api) update_comparison_parser = RequestParser() update_comparison_parser.add_argument('comparison_criteria', type=list, required=True, nullable=False, location='json') update_comparison_parser.add_argument('draft', type=bool, default=False) # events on_comparison_get = event.signal('COMPARISON_GET') on_comparison_create = event.signal('COMPARISON_CREATE') on_comparison_update = event.signal('COMPARISON_UPDATE') # / class CompareRootAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): """ Get (or create if needed) a comparison set for assignment. """ course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) require( READ,
new_answer_comment_parser.add_argument('attempt_ended', default=None) existing_answer_comment_parser = new_answer_comment_parser.copy() existing_answer_comment_parser.add_argument('id', required=True, help="Comment id is required.") answer_comment_list_parser = pagination_parser.copy() answer_comment_list_parser.add_argument('self_evaluation', required=False, default='true') answer_comment_list_parser.add_argument('evaluation', required=False, default='true') answer_comment_list_parser.add_argument('draft', required=False, default='false') answer_comment_list_parser.add_argument('ids', required=False, default=None) answer_comment_list_parser.add_argument('answer_ids', required=False, default=None) answer_comment_list_parser.add_argument('assignment_id', required=False, default=None) answer_comment_list_parser.add_argument('user_ids', required=False, default=None) # events on_answer_comment_modified = event.signal('ANSWER_COMMENT_MODIFIED') on_answer_comment_get = event.signal('ANSWER_COMMENT_GET') on_answer_comment_list_get = event.signal('ANSWER_COMMENT_LIST_GET') on_answer_comment_create = event.signal('ANSWER_COMMENT_CREATE') on_answer_comment_delete = event.signal('ANSWER_COMMENT_DELETE') class AnswerCommentListAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid, **kwargs): """ :query string ids: a comma separated comment uuids to query :query string answer_ids: a comma separated answer uuids for answer filter :query string assignment_id: filter the answer comments with a assignment uuid :query string user_ids: a comma separated user uuids that own the comments :query string self_evaluation: indicate whether the result should include self-evaluation comments or self-evaluation only. Possible values: true, false or only. Default true.
from compair.core import db, event, abort from compair.models import UserCourse, User, Course, CourseRole, \ ThirdPartyUser, ThirdPartyType, Group, Answer from .util import new_restful_api, get_model_changes group_api = Blueprint('group_api', __name__) api = new_restful_api(group_api) new_group_parser = RequestParser() new_group_parser.add_argument('name', required=True, nullable=False, help="Group name is required.") existing_group_parser = new_group_parser.copy() existing_group_parser.add_argument('id', required=True, nullable=False, help="Group id is required.") # events on_group_create = event.signal('GROUP_CREATE') on_group_edit = event.signal('GROUP_EDIT') on_group_get = event.signal('GROUP_GET') on_group_delete = event.signal('GROUP_DELETE') # / class GroupRootAPI(Resource): @login_required def post(self, course_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) new_group = Group(course_id=course.id) require(CREATE, new_group, title="Group Not Saved", message="Sorry, your role in this course does not allow you to save groups.")
answer_comment_list_parser.add_argument('draft', required=False, default='false') answer_comment_list_parser.add_argument('ids', required=False, default=None) answer_comment_list_parser.add_argument('answer_ids', required=False, default=None) answer_comment_list_parser.add_argument('assignment_id', required=False, default=None) answer_comment_list_parser.add_argument('user_ids', required=False, default=None) # events on_answer_comment_modified = event.signal('ANSWER_COMMENT_MODIFIED') on_answer_comment_get = event.signal('ANSWER_COMMENT_GET') on_answer_comment_list_get = event.signal('ANSWER_COMMENT_LIST_GET') on_answer_comment_create = event.signal('ANSWER_COMMENT_CREATE') on_answer_comment_delete = event.signal('ANSWER_COMMENT_DELETE') class AnswerCommentListAPI(Resource): @login_required def get(self, **kwargs): """ **Example request**: .. sourcecode:: http GET /api/answer/123/comments HTTP/1.1
import mimetypes import os from functools import wraps from flask import redirect, render_template, jsonify from flask_login import login_required, current_user, current_app from flask import make_response from flask import send_file, url_for, redirect, request from flask_restful.reqparse import RequestParser from bouncer.constants import READ from compair.authorization import require from compair.kaltura import KalturaAPI from compair.models import File from compair.core import event on_get_file = event.signal('GET_FILE') attachment_download_parser = RequestParser() attachment_download_parser.add_argument('name', default=None) def register_api_blueprints(app): # Initialize rest of the api modules from .course import course_api app.register_blueprint( course_api, url_prefix='/api/courses') from .classlist import classlist_api app.register_blueprint( classlist_api, url_prefix='/api/courses/<course_uuid>/users')
user_answer_list_parser = RequestParser() user_answer_list_parser.add_argument('draft', type=bool, required=False, default=False) top_answer_parser = RequestParser() top_answer_parser.add_argument( 'top_answer', type=bool, required=True, nullable=False, help="Expected boolean value 'top_answer' is missing.") # events on_answer_modified = event.signal('ANSWER_MODIFIED') on_answer_get = event.signal('ANSWER_GET') on_answer_list_get = event.signal('ANSWER_LIST_GET') on_answer_create = event.signal('ANSWER_CREATE') on_answer_delete = event.signal('ANSWER_DELETE') on_set_top_answer = event.signal('SET_TOP_ANSWER') on_user_answer_get = event.signal('USER_ANSWER_GET') from compair.api.file import on_attach_file, on_detach_file # / class AnswerRootAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): """
from copy import copy from flask import Blueprint, current_app from flask_login import current_user, login_required from flask_restful import Resource, marshal from compair.models import User from compair.core import abort, impersonation, event from .util import new_restful_api from . import dataformat impersonation_api = Blueprint('impersonation_api', __name__) IMPERSONATION_API_BASE_URL = '/api/impersonate' # events on_impersonation_started = event.signal('IMPERSONATION_STARTED') on_impersonation_stopped = event.signal('IMPERSONATION_STOPPED') class ImpersonationAPI(Resource): @login_required def post(self, user_uuid): if not current_app.config.get('IMPERSONATION_ENABLED', False): abort(404, title="Impersonation not supported", message="Impersonation function not enabled") original_user = User.query.get(current_user.id) impersonate_as_uuid = user_uuid impersonate_as_user = User.get_by_uuid_or_404(impersonate_as_uuid) if not impersonation.can_impersonate(impersonate_as_user.get_id()): abort(400,
from compair.core import db, event from compair.authorization import require, allow from compair.models import Assignment, Course, AssignmentComment from .util import new_restful_api, get_model_changes, pagination_parser assignment_comment_api = Blueprint('assignment_comment_api', __name__) api = new_restful_api(assignment_comment_api) new_assignment_comment_parser = RequestParser() new_assignment_comment_parser.add_argument('content', type=str, required=True) existing_assignment_comment_parser = new_assignment_comment_parser.copy() existing_assignment_comment_parser.add_argument('id', type=str, required=True, help="Comment id is required.") # events on_assignment_comment_modified = event.signal('ASSIGNMENT_COMMENT_MODIFIED') on_assignment_comment_get = event.signal('ASSIGNMENT_COMMENT_GET') on_assignment_comment_list_get = event.signal('ASSIGNMENT_COMMENT_LIST_GET') on_assignment_comment_create = event.signal('ASSIGNMENT_COMMENT_CREATE') on_assignment_comment_delete = event.signal('ASSIGNMENT_COMMENT_DELETE') # / class AssignmentCommentRootAPI(Resource): # TODO pagination @login_required def get(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) require(READ, assignment) restrict_user = not allow(MANAGE, assignment)
from sqlalchemy import func, and_, or_ from sqlalchemy.orm import undefer, joinedload from . import dataformat from compair.authorization import require from compair.models import Course, Assignment, CourseRole, User, UserCourse, Comparison, \ AnswerComment, Answer, File, AnswerScore, AnswerCommentType, PairingAlgorithm, \ AssignmentGrade, Group from .util import new_restful_api from compair.core import event, abort gradebook_api = Blueprint('gradebook_api', __name__) api = new_restful_api(gradebook_api) # events on_gradebook_get = event.signal('GRADEBOOK_GET') # / class GradebookAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404( assignment_uuid, joinedloads=['assignment_criteria']) require( MANAGE, assignment, title="Participation Results Unavailable", message= "Sorry, your role in this course does not allow you to view student participation for this assignment."
from flask_login import login_required, current_user from flask_restful import Resource, marshal from compair.core import allowed_file, random_generator from compair.authorization import allow, require from . import dataformat from compair.core import db, event, abort from compair.models import File, Assignment, KalturaMedia from compair.kaltura import KalturaAPI from .util import new_restful_api file_api = Blueprint('file_api', __name__) api = new_restful_api(file_api) # events on_save_file = event.signal('FILE_CREATE') on_get_kaltura_token = event.signal('FILE_GET_KALTURA_TOKEN') on_save_kaltura_file = event.signal('FILE_CREATE_KALTURA_FILE') on_attach_file = event.signal('FILE_ATTACH') on_detach_file = event.signal('FILE_DETACH') # / class FileAPI(Resource): @login_required def post(self): uploaded_file = request.files.get('file') if not uploaded_file: abort(400, title="File Not Uploaded", message="Sorry, no file was found to upload. Please try uploading again.") elif not allowed_file(uploaded_file.filename, current_app.config['ATTACHMENT_ALLOWED_EXTENSIONS']):
MembershipNoValidContextsException, MembershipNoResultsException, MembershipInvalidRequestException, ) from .util import new_restful_api, get_model_changes, pagination_parser from compair.tasks.lti_membership import update_lti_course_membership from compair.api.classlist import display_name_generator from lti.contrib.flask import FlaskToolProvider from oauthlib.oauth1 import RequestValidator lti_api = Blueprint("lti_api", __name__) api = new_restful_api(lti_api) # events on_lti_course_link = event.signal("LTI_CONTEXT_COURSE_LINKED") on_lti_course_membership_update = event.signal("LTI_CONTEXT_COURSE_MEMBERSHIP_UPDATE") on_lti_course_membership_status_get = event.signal("LTI_CONTEXT_COURSE_MEMBERSHIP_STATUS_GET") # /auth class LTIAuthAPI(Resource): def post(self): """ Kickstarts the LTI integration flow. """ if not current_app.config.get("LTI_LOGIN_ENABLED"): return abort(403) tool_provider = FlaskToolProvider.from_flask_request(request=request) validator = ComPAIRRequestValidator() ok = tool_provider.is_valid_request(validator)
Assignment, UserCourse, CourseRole, AssignmentCriterion from .util import new_restful_api from compair.algorithms import InsufficientObjectsForPairException, \ UserComparedAllObjectsException, UnknownPairGeneratorException # First declare a Flask Blueprint for this module # Then pack the blueprint into a Flask-Restful API comparison_api = Blueprint('comparison_api', __name__) api = new_restful_api(comparison_api) update_comparison_parser = RequestParser() update_comparison_parser.add_argument('comparisons', type=list, required=True, location='json') # events on_comparison_get = event.signal('COMPARISON_GET') on_comparison_create = event.signal('COMPARISON_CREATE') on_comparison_update = event.signal('COMPARISON_UPDATE') #messages comparison_deadline_message = 'Assignment comparison deadline has passed.' educators_can_not_compare_message = 'Only students can compare answers in this assignment.' # / class CompareRootAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): """ Get (or create if needed) a comparison set for assignment. """ course = Course.get_active_by_uuid_or_404(course_uuid)
user_course_list_parser.add_argument('search', required=False, default=None) user_course_list_parser.add_argument('includeSandbox', type=string_to_bool, required=False, default=None) user_course_list_parser.add_argument('period', type=non_blank_text, required=False, default=None) user_id_course_list_parser = pagination_parser.copy() user_id_course_list_parser.add_argument('search', required=False, default=None) user_id_course_list_parser.add_argument('includeSandbox', type=string_to_bool, required=False, default=None) user_id_course_list_parser.add_argument('period', type=non_blank_text, required=False, default=None) user_id_course_list_parser.add_argument('orderBy', required=False, default=None) user_id_course_list_parser.add_argument('reverse', type=bool, default=False) user_course_status_list_parser = RequestParser() user_course_status_list_parser.add_argument('ids', required=True, nullable=False, default=None) # events on_user_modified = event.signal('USER_MODIFIED') on_user_get = event.signal('USER_GET') on_user_list_get = event.signal('USER_LIST_GET') on_user_create = event.signal('USER_CREATE') on_user_course_get = event.signal('USER_COURSE_GET') on_user_course_status_get = event.signal('USER_COURSE_STATUS_GET') on_teaching_course_get = event.signal('USER_TEACHING_COURSE_GET') on_user_edit_button_get = event.signal('USER_EDIT_BUTTON_GET') on_user_notifications_update = event.signal('USER_NOTIFICATIONS_UPDATE') on_user_password_update = event.signal('USER_PASSWORD_UPDATE') on_user_lti_users_get = event.signal('USER_LTI_USERS_GET') on_user_lti_user_unlink = event.signal('USER_LTI_USER_UNLINK') on_user_third_party_users_get = event.signal('USER_THIRD_PARTY_USERS_GET') on_user_third_party_user_delete = event.signal('USER_THIRD_PARTY_USER_DELETE') def check_valid_system_role(system_role):
new_consumer_parser.add_argument('oauth_consumer_key', type=str, required=True, nullable=False) new_consumer_parser.add_argument('oauth_consumer_secret', type=str) new_consumer_parser.add_argument('global_unique_identifier_param', type=non_blank_text) new_consumer_parser.add_argument('student_number_param', type=non_blank_text) new_consumer_parser.add_argument('custom_param_regex_sanitizer', type=non_blank_text) existing_consumer_parser = new_consumer_parser.copy() existing_consumer_parser.add_argument('id', type=str, required=True, nullable=False) existing_consumer_parser.add_argument('active', type=bool, default=True) consumer_list_parser = pagination_parser.copy() consumer_list_parser.add_argument('orderBy', type=str, required=False, default=None) consumer_list_parser.add_argument('reverse', type=bool, default=False) # events on_consumer_list_get = event.signal('LTI_CONSUMER_LIST_GET') on_consumer_get = event.signal('LTI_CONSUMER_GET') on_consumer_update = event.signal('LTI_CONSUMER_EDIT') on_consumer_create = event.signal('LTI_CONSUMER_CREATE') # / class ConsumerAPI(Resource): @login_required def get(self): require(MANAGE, LTIConsumer, title="Consumers Unavailable", message="Sorry, your system role does not allow you to view LTI consumers.") params = consumer_list_parser.parse_args() query = LTIConsumer.query
LTIResourceLink, LTIUser, LTIUserResourceLink, LTINonce from compair.models.lti_models import MembershipNoValidContextsException, \ MembershipNoResultsException, MembershipInvalidRequestException from .util import new_restful_api, get_model_changes, pagination_parser from compair.tasks import update_lti_course_membership lti_course_api = Blueprint('lti_course_api', __name__) api = new_restful_api(lti_course_api) context_list_parser = pagination_parser.copy() context_list_parser.add_argument('orderBy', type=str, required=False, default=None) context_list_parser.add_argument('reverse', type=bool, default=False) context_list_parser.add_argument('search', required=False, default=None) # events on_lti_course_links_get = event.signal('LTI_CONTEXT_COURSE_LINKS') on_lti_course_link_create = event.signal('LTI_CONTEXT_COURSE_LINKED') on_lti_course_unlink = event.signal('LTI_CONTEXT_COURSE_UNLINKED') on_lti_course_membership_update = event.signal('LTI_CONTEXT_COURSE_MEMBERSHIP_UPDATE') on_lti_course_membership_status_get = event.signal('LTI_CONTEXT_COURSE_MEMBERSHIP_STATUS_GET') # /context class LTICourseLinksRootAPI(Resource): @login_required def get(self): require(READ, LTIContext, title="Course Links Unavailable", message="Sorry, your system role does not allow you to view LTI course links.") params = context_list_parser.parse_args()
from flask import Blueprint, request, current_app from bouncer.constants import READ, EDIT, CREATE, DELETE, MANAGE from flask_login import login_required, current_user from flask_restful import Resource, marshal from compair.authorization import allow, require from . import dataformat from compair.core import db, event from compair.models import File, Assignment, Answer from .util import new_restful_api file_api = Blueprint('file_api', __name__) api = new_restful_api(file_api) # events on_save_file = event.signal('FILE_CREATE') on_file_get = event.signal('FILE_GET') on_file_delete = event.signal('FILE_DELETE') def allowed_file(filename, allowed): return '.' in filename and \ filename.rsplit('.', 1)[1] in allowed def random_generator(size=8, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) # / class FileAPI(Resource):
criterion_api = Blueprint('criterion_api', __name__) api = new_restful_api(criterion_api) new_criterion_parser = reqparse.RequestParser() new_criterion_parser.add_argument('name', type=str, required=True) new_criterion_parser.add_argument('description', type=str) new_criterion_parser.add_argument('default', type=bool, default=True) existing_criterion_parser = reqparse.RequestParser() existing_criterion_parser.add_argument('id', type=str, required=True) existing_criterion_parser.add_argument('name', type=str, required=True) existing_criterion_parser.add_argument('description', type=str) existing_criterion_parser.add_argument('default', type=bool, default=True) # events on_criterion_list_get = event.signal('CRITERION_LIST_GET') on_criterion_get = event.signal('CRITERION_GET') on_criterion_update = event.signal('CRITERION_EDIT') on_criterion_create = event.signal('CRITERION_CREATE') # /criteria - public + authored/default # default = want criterion available to all of the author's assignments class CriteriaAPI(Resource): @login_required def get(self): criteria = Criterion.query \ .filter(or_( and_( Criterion.user_id == current_user.id, Criterion.default == True ),
criterion_api = Blueprint('criterion_api', __name__) api = new_restful_api(criterion_api) new_criterion_parser = reqparse.RequestParser() new_criterion_parser.add_argument('name', required=True, nullable=False) new_criterion_parser.add_argument('description') new_criterion_parser.add_argument('default', type=bool, default=True) existing_criterion_parser = reqparse.RequestParser() existing_criterion_parser.add_argument('id', required=True, nullable=False) existing_criterion_parser.add_argument('name', required=True, nullable=False) existing_criterion_parser.add_argument('description') existing_criterion_parser.add_argument('default', type=bool, default=True) # events on_criterion_list_get = event.signal('CRITERION_LIST_GET') on_criterion_get = event.signal('CRITERION_GET') on_criterion_update = event.signal('CRITERION_EDIT') on_criterion_create = event.signal('CRITERION_CREATE') # /criteria - public + authored/default # default = want criterion available to all of the author's assignments class CriteriaAPI(Resource): @login_required def get(self): criteria = Criterion.query \ .filter(or_( and_( Criterion.user_id == current_user.id, Criterion.default == True
from compair.core import event from compair.models import CourseRole, Assignment, UserCourse, Course, Answer, \ AnswerComment, AssignmentCriterion, Comparison, AnswerCommentType from .util import new_restful_api report_api = Blueprint('report_api', __name__) api = new_restful_api(report_api) report_parser = reqparse.RequestParser() report_parser.add_argument('group_name', type=str) # may change 'type' to int report_parser.add_argument('type', type=str, required=True) report_parser.add_argument('assignment', type=str) # events on_export_report = event.signal('EXPORT_REPORT') # should we have a different event for each type of report? def name_generator(course, report_name, group_name, file_type="csv"): date = time.strftime("%Y-%m-%d--%H-%M-%S") group_name_output = "" if group_name: group_name_output = group_name + '-' return course.name + "-" + group_name_output + report_name + "--" + date + "." + file_type class ReportRootAPI(Resource): @login_required def post(self, course_uuid): course = Course.get_active_by_uuid_or_404(course_uuid)
new_assignment_parser.add_argument('educators_can_compare', type=bool, default=False) # has to add location parameter, otherwise MultiDict will screw up the list new_assignment_parser.add_argument('criteria', type=list, default=[], location='json') new_assignment_parser.add_argument('answer_grade_weight', type=int, default=1) new_assignment_parser.add_argument('comparison_grade_weight', type=int, default=1) new_assignment_parser.add_argument('self_evaluation_grade_weight', type=int, default=1) existing_assignment_parser = new_assignment_parser.copy() existing_assignment_parser.add_argument('id', required=True, nullable=False, help="Assignment id is required.") assignment_users_comparison_list_parser = pagination_parser.copy() assignment_users_comparison_list_parser.add_argument('group', required=False, default=None) assignment_users_comparison_list_parser.add_argument('author', required=False, default=None) # events on_assignment_modified = event.signal('ASSIGNMENT_MODIFIED') on_assignment_get = event.signal('ASSIGNMENT_GET') on_assignment_list_get = event.signal('ASSIGNMENT_LIST_GET') on_assignment_create = event.signal('ASSIGNMENT_CREATE') on_assignment_delete = event.signal('ASSIGNMENT_DELETE') on_assignment_list_get_status = event.signal('ASSIGNMENT_LIST_GET_STATUS') on_assignment_get_status = event.signal('ASSIGNMENT_GET_STATUS') on_assignment_user_comparisons_get = event.signal('ASSIGNMENT_USER_COMPARISONS_GET') on_assignment_users_comparisons_get = event.signal('ASSIGNMENT_USERS_COMPARISONS_GET') from compair.api.file import on_attach_file, on_detach_file def check_valid_pairing_algorithm(pairing_algorithm): pairing_algorithms = [ PairingAlgorithm.adaptive.value, PairingAlgorithm.random.value,
from compair.authorization import require from compair.core import db, event, abort from compair.models import UserCourse, User, Course, CourseRole from .util import new_restful_api user_list_parser = RequestParser() user_list_parser.add_argument('ids', type=list, required=True, default=[], location='json') course_group_user_api = Blueprint('course_group_user_api', __name__) api = new_restful_api(course_group_user_api) on_course_group_user_create = event.signal('COURSE_GROUP_USER_CREATE') on_course_group_user_list_create = event.signal( 'COURSE_GROUP_USER_LIST_CREATE') on_course_group_user_delete = event.signal('COURSE_GROUP_USER_DELETE') on_course_group_user_list_delete = event.signal( 'COURSE_GROUP_USER_LIST_CREATE') # /:user_uuid/groups/:group_name class GroupUserIdAPI(Resource): @login_required def post(self, course_uuid, user_uuid, group_name): course = Course.get_active_by_uuid_or_404(course_uuid) user = User.get_by_uuid_or_404(user_uuid) user_course = UserCourse.query \
from bouncer.constants import READ, EDIT, CREATE, DELETE, MANAGE from flask_login import login_required, current_user from flask_restful import Resource, marshal, reqparse, marshal_with from sqlalchemy import or_, and_ from . import dataformat from compair.core import event, db from compair.authorization import require, allow from compair.models import Course, Criterion, Assignment, AssignmentCriterion, Comparison from .util import new_restful_api assignment_criterion_api = Blueprint('assignment_criterion_api', __name__) api = new_restful_api(assignment_criterion_api) # events on_assignment_criterion_get = event.signal('ASSIGNMENT_CRITERION_GET') # / class AssignmentCriterionRootAPI(Resource): @login_required def get(self, course_uuid, assignment_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) assignment = Assignment.get_active_by_uuid_or_404(assignment_uuid) require(READ, course) criteria = Criterion.query \ .join(AssignmentCriterion) \ .filter(and_( AssignmentCriterion.assignment_id == assignment.id, AssignmentCriterion.active == True, Criterion.active == True)
from compair.core import db, event, abort from .util import new_restful_api, get_model_changes, pagination_parser from compair.models import User, SystemRole, UserCourse, CourseRole from compair.api.login import authenticate from .classlist import display_name_generator from .file import random_generator demo_api = Blueprint('demo_api', __name__) api = new_restful_api(demo_api) new_user_demo_parser = RequestParser() new_user_demo_parser.add_argument('system_role', type=str, required=True) # events on_user_demo_create = event.signal('USER_DEMO_CREATE') def check_valid_system_role(system_role): system_roles = [ SystemRole.sys_admin.value, SystemRole.instructor.value, SystemRole.student.value ] if system_role not in system_roles: abort( 400, title="Demo Account Not Saved", message= "Please try again with a system role from the list of roles provided." )
from compair.models import UserCourse, User, Course, CourseRole, \ Group from .util import new_restful_api, get_model_changes user_list_parser = RequestParser() user_list_parser.add_argument('ids', type=list, required=True, nullable=False, default=[], location='json') group_user_api = Blueprint('group_user_api', __name__) api = new_restful_api(group_user_api) on_group_user_list_get = event.signal('GROUP_USERS_GET') on_group_user_get = event.signal('GROUP_USER_GET') on_group_user_create = event.signal('GROUP_USER_CREATE') on_group_user_list_create = event.signal('GROUP_USER_LIST_CREATE') on_group_user_delete = event.signal('GROUP_USER_DELETE') on_group_user_list_delete = event.signal('GROUP_USER_LIST_CREATE') # /<group_uuid>/users/:user_uuid class GroupUserIdAPI(Resource): @login_required def post(self, course_uuid, group_uuid, user_uuid): course = Course.get_active_by_uuid_or_404(course_uuid) group = Group.get_active_by_uuid_or_404(group_uuid) user = User.get_by_uuid_or_404(user_uuid)
from compair.models import User, CourseRole, Assignment, UserCourse, Course, Answer, \ AnswerComment, AssignmentCriterion, Comparison, AnswerCommentType, Group, File, KalturaMedia from compair.kaltura import KalturaAPI from .util import new_restful_api report_api = Blueprint('report_api', __name__) api = new_restful_api(report_api) report_parser = reqparse.RequestParser() report_parser.add_argument('group_id') # may change 'type' to int report_parser.add_argument('type', required=True, nullable=False) report_parser.add_argument('assignment') # events on_export_report = event.signal('EXPORT_REPORT') # should we have a different event for each type of report? def name_generator(course, report_name, group, file_type="csv"): date = time.strftime("%Y-%m-%d--%H-%M-%S") group_name_output = "" if group: group_name_output = group.name + '-' # from https://gist.github.com/seanh/93666 # return a file system safe filename valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) filename = course.name + "-" + group_name_output + report_name + "--" + date + "." + file_type return ''.join(char for char in filename if char in valid_chars)
new_assignment_parser.add_argument('educators_can_compare', type=bool, default=False) # has to add location parameter, otherwise MultiDict will screw up the list new_assignment_parser.add_argument('criteria', type=list, default=[], location='json') new_assignment_parser.add_argument('answer_grade_weight', type=int, default=1) new_assignment_parser.add_argument('comparison_grade_weight', type=int, default=1) new_assignment_parser.add_argument('self_evaluation_grade_weight', type=int, default=1) existing_assignment_parser = new_assignment_parser.copy() existing_assignment_parser.add_argument('id', required=True, help="Assignment id is required.") assignment_users_comparison_list_parser = pagination_parser.copy() assignment_users_comparison_list_parser.add_argument('group', required=False, default=None) assignment_users_comparison_list_parser.add_argument('author', required=False, default=None) # events on_assignment_modified = event.signal('ASSIGNMENT_MODIFIED') on_assignment_get = event.signal('ASSIGNMENT_GET') on_assignment_list_get = event.signal('ASSIGNMENT_LIST_GET') on_assignment_create = event.signal('ASSIGNMENT_CREATE') on_assignment_delete = event.signal('ASSIGNMENT_DELETE') on_assignment_list_get_status = event.signal('ASSIGNMENT_LIST_GET_STATUS') on_assignment_get_status = event.signal('ASSIGNMENT_GET_STATUS') on_assignment_user_comparisons_get = event.signal('ASSIGNMENT_USER_COMPARISONS_GET') on_assignment_users_comparisons_get = event.signal('ASSIGNMENT_USERS_COMPARISONS_GET') def check_valid_pairing_algorithm(pairing_algorithm): pairing_algorithms = [ PairingAlgorithm.adaptive.value, PairingAlgorithm.random.value ] if pairing_algorithm not in pairing_algorithms:
import os from flask import Blueprint, jsonify, request, session as sess, current_app, url_for, redirect, Flask, render_template from flask_login import current_user, login_required, login_user, logout_user from compair import cas from compair.core import db, event from compair.authorization import get_logged_in_user_permissions from compair.models import User, LTIUser, LTIResourceLink, LTIUserResourceLink, UserCourse, LTIContext, \ ThirdPartyUser, ThirdPartyType login_api = Blueprint("login_api", __name__, url_prefix='/api') # events on_login_with_method = event.signal('USER_LOGGED_IN_WITH_METHOD') on_logout = event.signal('USER_LOGGED_OUT') @login_api.route('/login', methods=['POST']) def login(): if not current_app.config.get('APP_LOGIN_ENABLED'): return "", 403 # expecting login params to be in json format param = request.json if param is None: return jsonify({"error": 'Invalid login data format. Expecting json.'}), 400 username = param['username'] password = param['password'] # grab the user from the username user = User.query.filter_by(username=username).first() if not user:
existing_course_parser = new_course_parser.copy() existing_course_parser.add_argument('id', type=str, required=True, help='Course id is required.') duplicate_course_parser = reqparse.RequestParser() duplicate_course_parser.add_argument('name', type=str, required=True, help='Course name is required.') duplicate_course_parser.add_argument('year', type=int, required=True, help='Course year is required.') duplicate_course_parser.add_argument('term', type=str, required=True, help='Course term/semester is required.') duplicate_course_parser.add_argument('start_date', type=str, default=None) duplicate_course_parser.add_argument('end_date', type=str, default=None) # has to add location parameter, otherwise MultiDict will screw up the list duplicate_course_parser.add_argument('assignments', type=list, default=[], location='json') #only ids and dates # events on_course_modified = event.signal('COURSE_MODIFIED') on_course_get = event.signal('COURSE_GET') on_course_delete = event.signal('COURSE_DELETE') on_course_list_get = event.signal('COURSE_LIST_GET') on_course_create = event.signal('COURSE_CREATE') on_course_duplicate = event.signal('COURSE_DUPLICATE') class CourseListAPI(Resource): @login_required def post(self): """ Create new course """ require(CREATE, Course) params = new_course_parser.parse_args()
from flask_login import login_required, current_user from flask_restful import Resource, marshal from compair.core import allowed_file, random_generator from compair.authorization import allow, require from . import dataformat from compair.core import db, event, abort from compair.models import File, Assignment, KalturaMedia from compair.kaltura import KalturaAPI from .util import new_restful_api file_api = Blueprint('file_api', __name__) api = new_restful_api(file_api) # events on_save_file = event.signal('FILE_CREATE') on_get_kaltura_token = event.signal('FILE_GET_KALTURA_TOKEN') on_save_kaltura_file = event.signal('FILE_CREATE_KALTURA_FILE') # / class FileAPI(Resource): @login_required def post(self): uploaded_file = request.files.get('file') if not uploaded_file: abort( 400, title="File Not Uploaded", message=
from sqlalchemy import exc, asc, or_, and_, func from . import dataformat from compair.core import db, event, abort, random_generator, display_name_generator from .util import new_restful_api, get_model_changes, pagination_parser from compair.models import User, SystemRole, UserCourse, CourseRole from compair.api.login import authenticate demo_api = Blueprint('demo_api', __name__) api = new_restful_api(demo_api) new_user_demo_parser = RequestParser() new_user_demo_parser.add_argument('system_role', type=str, required=True, nullable=False) # events on_user_demo_create = event.signal('USER_DEMO_CREATE') def check_valid_system_role(system_role): system_roles = [ SystemRole.sys_admin.value, SystemRole.instructor.value, SystemRole.student.value ] if system_role not in system_roles: abort(400, title="Demo Account Not Saved", message="Please try again with a system role from the list of roles provided.") # / class DemoListAPI(Resource): def post(self): if not current_app.config.get('DEMO_INSTALLATION', False): abort(404, title="Demo Accounts Unavailable", message="Sorry, the system settings do now allow the use of demo accounts.")
update_password_parser = RequestParser() update_password_parser.add_argument('oldpassword', type=str, required=False) update_password_parser.add_argument('newpassword', type=str, required=True) user_list_parser = pagination_parser.copy() user_list_parser.add_argument('search', type=str, required=False, default=None) user_list_parser.add_argument('ids', type=str, required=False, default=None) user_course_list_parser = pagination_parser.copy() user_course_list_parser.add_argument('search', type=str, required=False, default=None) user_course_status_list_parser = RequestParser() user_course_status_list_parser.add_argument('ids', type=str, required=True, default=None) # events on_user_modified = event.signal('USER_MODIFIED') on_user_get = event.signal('USER_GET') on_user_list_get = event.signal('USER_LIST_GET') on_user_create = event.signal('USER_CREATE') on_user_course_get = event.signal('USER_COURSE_GET') on_user_course_status_get = event.signal('USER_COURSE_STATUS_GET') on_teaching_course_get = event.signal('USER_TEACHING_COURSE_GET') on_user_edit_button_get = event.signal('USER_EDIT_BUTTON_GET') on_user_password_update = event.signal('USER_PASSWORD_UPDATE') def check_valid_system_role(system_role): system_roles = [ SystemRole.sys_admin.value, SystemRole.instructor.value, SystemRole.student.value ]