def remove_permission(request): data = json_from_request(request) expected_keys = ["user_id"] check_keys(expected_keys, data) if "permission_id" not in data.keys() and "all" not in data.keys(): raise MissingKeyError("permission_id or all") # Check user specified is in the correct school user = get_record_by_id(data['user_id'], User, CustomError(409, message="Invalid user_id.")) if "all" in data.keys() and data['all'] is True: user.permissions = [] else: # Check the permission specified is in the correct school permission = get_permission_by_id( data['permission_id'], CustomError(409, message="Invalid permission_id.")) # Check the user has the permission if permission.id not in [p.id for p in user.permissions]: raise CustomError( 409, message="User with id: {} does not have permission with id: {}" .format(data['user_id'], data['permission_id'])) user.permissions.remove(permission) db.session.add(user) db.session.commit() # Return success status return jsonify({'success': True}), 200
def grant_permission(request): data = json_from_request(request) expected_keys = ["user_id", "permission_id"] check_keys(expected_keys, data) # Check user specified is in the correct school user = get_record_by_id(data['user_id'], User, CustomError(409, message="Invalid user_id.")) # Check the permission specified is in the correct school permission = get_permission_by_id( data['permission_id'], CustomError(409, message="Invalid permission_id.")) # Check user does not have the permission for p in user.permissions: if p.id == data['permission_id']: raise CustomError( 409, message="User with id: {} already has permission with id: {}". format(data['user_id'], data['permission_id'])) user.permissions.append(permission) db.session.add(user) db.session.commit() # Return success status return jsonify({'success': True}), 201
def validate_permissions(request): data = json_from_request(request) expected_keys = ["user_ids", "permissions"] check_keys(expected_keys, data) check_values_not_blank(expected_keys, data) expected_number_of_rows = len(data['user_ids']) for permission_name in data['permissions']: p = Permission.query.filter_by(school_id=g.user.school_id, name=permission_name).first() if p is None: raise CustomError( 409, message="Invalid permission: {}".format(permission_name)) number_of_rows = db.session.query(user_permissions).filter( user_permissions.c.permission_id == p.id).filter( user_permissions.c.user_id.in_(data['user_ids'])).count() if number_of_rows != expected_number_of_rows: raise CustomError( 409, message="Permission User combinations not valid.") return jsonify({'success': True})
def create_quiz(request): top_level_expected_keys = [ "lesson_id", "title", "description", "date_due", "questions" ] json_data = json_from_request(request) check_keys(top_level_expected_keys, json_data) # Validate lesson resp = services.lesson.get("lessons/lesson/{}".format( json_data['lesson_id']), headers=g.user.headers_dict(), params={'nest-teachers': True}) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if g.user.id not in [t['id'] for t in lesson['teachers']]: raise UnauthorizedError() # Validate date date_due_string = json_data['date_due'] try: date_due = datetime.datetime.strptime(date_due_string, "%d/%m/%Y").date() except ValueError: raise CustomError(409, message="Invalid date_due: {}.".format( json_data['date_due'])) quiz = Quiz(lesson_id=json_data['lesson_id'], title=json_data['title'], description=json_data['description'], date_due=date_due, number_of_questions=len(json_data['questions'])) db.session.add(quiz) db.session.commit() for question_object in json_data['questions']: if 'answer' and 'question_text' not in question_object.keys(): raise CustomError( 409, message= "Invalid object in questions array. Make sure it has a question and a answer." ) question = Question(quiz.id, question_object['question_text'], question_object['answer']) db.session.add(question) quiz.questions.append(question) db.session.add(quiz) db.session.commit() return jsonify(quiz.to_dict()), 201
def create_essay(request): """Function to create an essay from request.""" # List of keys needed to create an Essay top_level_expected_keys = [ "lesson_id", "title", "description", "date_due", ] # Extract JSON from request and check keys are present json_data = json_from_request(request) check_keys(top_level_expected_keys, json_data) # Validate lesson resp = services.lesson.get("lessons/lesson/{}".format( json_data['lesson_id']), headers=g.user.headers_dict(), params={'nest-teachers': True}) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if g.user.id not in [t['id'] for t in lesson['teachers']]: raise UnauthorizedError() # Validate date date_due_string = json_data['date_due'] try: date_due = datetime.datetime.strptime(date_due_string, "%d/%m/%Y").date() except ValueError: raise CustomError(409, message="Invalid date_due: {}.".format( json_data['date_due'])) # Create Essay essay = Essay( lesson_id=json_data['lesson_id'], title=json_data['title'], description=json_data['description'], date_due=date_due, ) db.session.add(essay) db.session.commit() return jsonify(essay.to_dict()), 201
def submit_essay(request, essay_id): # Check essay if valid essay = get_record_by_id(essay_id, Essay, check_school_id=False) # Validate lesson resp = services.lesson.get("lessons/lesson/{}".format(essay.lesson_id), headers=g.user.headers_dict(), params={'nest-students': True}) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if lesson['school_id'] != g.user.school_id: raise UnauthorizedError() top_level_expected_keys = ["content"] json_data = json_from_request(request) check_keys(top_level_expected_keys, json_data) if g.user.id not in [t['id'] for t in lesson['students']]: raise UnauthorizedError() submission = EssaySubmission( essay.id, g.user.id, datetime.datetime.now(), # TODO: Deal with timezones json_data['content']) db.session.add(submission) db.session.commit() return jsonify({'success': True}), 201
def create_token(): """Route to create a JWT token.""" json_data = request.get_json() if json_data is None: raise NoJSONError() expected_keys = ["username", "password"] for key in expected_keys: if key not in json_data.keys(): raise MissingKeyError(key) username = json_data['username'] password = json_data['password'] # Check email and password response = services.user.post('user/authenticate', json={ 'username': username, 'password': password }, headers={'Content-Type': 'application/json'}) if response.status_code != 200: raise CustomError(**response.json()) user_id = response.json()['user']['id'] token = { 'access_token': create_access_token(identity=response.json()['user']), 'user_id': user_id } return jsonify(token)
def view_quiz_submission(submission_id): if not (g.user.has_permissions({'Teacher'}) or g.user.has_permissions({'Student'})): raise UnauthorizedError() submission = get_record_by_id(submission_id, QuizSubmission, check_school_id=False) # Validate lesson resp = services.lesson.get("lessons/lesson/{}".format( submission.homework.lesson_id), headers=g.user.headers_dict(), params={'nest-students': True}) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if lesson['school_id'] != g.user.school_id: raise UnauthorizedError() return jsonify({ 'success': True, 'submission': submission.to_dict(nest_user=True, nest_homework=True, nest_comments=True) })
def lesson_update(request, lesson_id): lesson = get_record_by_id(lesson_id, Lesson) json_data = json_from_request(request) if "name" in json_data.keys(): if json_data['name'] != lesson.name: validate_lesson_name(name=json_data['name'], school_id=g.user.school_id) lesson.name = json_data['name'] if "subject_id" in json_data.keys(): subject = get_record_by_id(json_data['subject_id'], Subject, custom_not_found_error=CustomError( 409, message="Invalid subject_id.")) lesson.subject_id = subject.id if "teacher_ids" in json_data.keys(): lesson.teachers = [] add_teachers(json_data['teacher_ids'], lesson) if "student_ids" in json_data.keys(): lesson.students = [] add_students(json_data['student_ids'], lesson) db.session.add(lesson) db.session.commit() return jsonify({'success': True, 'message': 'Updated.'})
def set_default_permissions(request): """ Create default roles and permissions for school. Uses the currently logged in user as the initial admin. Only works if permissions do not exist yet. """ school_id = g.user.school_id # Check permissions not created yet. if Permission.query.filter_by(school_id=school_id).first() is not None: raise CustomError(401, message='Permissions already setup.') # Create permissions for permission in Permission.default_permissions(school_id): db.session.add(permission) db.session.commit() # Assign user to admin role permission = Permission.query.filter_by(name="Administrator", school_id=school_id).first() g.user.permission.append(permission) db.session.add(g.user) db.session.commit() # Return success status return jsonify({'success': True}), 201
def to_dict(self, nest_teachers=False, nest_students=False, nest_subject=False, nest_homework=False): lesson_as_dict = { 'id': self.id, 'name': self.name, 'school_id': self.school_id, 'subject_id': self.subject_id } if nest_subject: lesson_as_dict['subject'] = self.subject.to_dict() if nest_teachers: response = services.user.get( "user/user", params={'ids': t.user_id for t in self.teachers}, headers=g.user.headers_dict()) if response.status_code != 200: raise CustomError(**response.json()) lesson_as_dict['teachers'] = response.json()['users'] if nest_students: response = services.user.get( "user/user", params={'ids': s.user_id for s in self.students}, headers=g.user.headers_dict()) if response.status_code != 200: raise CustomError(**response.json()) lesson_as_dict['students'] = response.json()['users'] if nest_homework: # lesson_as_dict['homework'] = [] response = services.homework.get("homework/homework", headers=g.user.headers_dict(), params={'lesson_id': self.id}) if response.status_code != 200: raise CustomError(**response.json()) lesson_as_dict['homework'] = response.json()['homework'] # lesson_as_dict['homework'] = [h.to_dict(date_as_string=True) for h in self.homework] return lesson_as_dict
def list_submissions(homework_id): homework = get_record_by_id(homework_id, Homework, check_school_id=False) resp = services.lesson.get('lessons/lesson/{}'.format(homework.lesson_id), headers=g.user.headers_dict()) if resp.status_code != 200: raise CustomError( **resp.json() ) if resp.json()['lesson']['school_id'] != g.user.school_id: raise UnauthorizedError() submissions = Submission.query.filter_by(homework_id=homework.id).all() return jsonify({'success': True, 'submissions': [s.to_dict(nest_user=True) for s in submissions]})
def add_students(student_ids, lesson): response = services.user.post("permissions/validate", json={ 'user_ids': student_ids, 'permissions': ["Student"] }, headers={ 'Content-Type': 'application/json', **g.user.headers_dict() }) if response.status_code != 200: raise CustomError(**response.json()) for student_id in student_ids: lesson.students.append(LessonStudent(lesson.id, student_id))
def add_teachers(teacher_ids, lesson): response = services.user.post("permissions/validate", json={ 'user_ids': teacher_ids, 'permissions': ["Teacher"] }, headers={ 'Content-Type': 'application/json', **g.user.headers_dict() }) if response.status_code != 200: raise CustomError(**response.json()) for teacher_id in teacher_ids: lesson.teachers.append(LessonTeacher(lesson.id, teacher_id))
def homework_due_summary(): params = {'student_ids': g.user.id} resp = services.lesson.get('lessons/lesson', params=params, headers=g.user.headers_dict()) if resp.status_code != 200: raise CustomError( **resp.json() ) lesson_ids = [l['id'] for l in resp.json()['lessons']] homework = Homework.query.filter(Homework.lesson_id.in_(lesson_ids)) nest_lessons = get_boolean_query_param(request, 'nest-lessons') homework_list = [h.to_dict(date_as_string=True, nest_lesson=nest_lessons, has_submitted=True, user_id=g.user.id) for h in homework] return jsonify({'success': True, 'homework': homework_list, 'lessons': resp.url, 'lesson_ids': lesson_ids})
def authenticate(request): # Decode the JSON data data = json_from_request(request) # Validate data expected_keys = ["username", "password"] check_keys(expected_keys, data) check_values_not_blank(expected_keys, data) username = data['username'] password = data['password'] # Check username user = User.query.filter_by(username=username).first() if user is None: raise CustomError(401, message='Username or password were not found.') # Check password if not check_password_hash(user.password, password): raise CustomError(401, message='Username or password were not found.') return jsonify({ 'success': True, 'user': user.to_dict(nest_permissions=True) })
def submit_quiz(request, quiz_id): # Check quiz is valid quiz = get_record_by_id(quiz_id, Quiz, check_school_id=False) # Validate lesson resp = services.lesson.get("lessons/lesson/{}".format(quiz.lesson_id), headers=g.user.headers_dict(), params={'nest-students': True}) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if lesson['school_id'] != g.user.school_id: raise UnauthorizedError() json_data = json_from_request(request) expected_top_keys = ['answers'] expected_inner_keys = ['question_id', 'answer'] check_keys(expected_top_keys, json_data) if g.user.id not in [t['id'] for t in lesson['students']]: raise UnauthorizedError() question_ids = [question.id for question in quiz.questions] submission = QuizSubmission( homework_id=quiz.id, user_id=g.user.id, datetime_submitted=datetime.datetime.now() # TODO: Deal with timezones ) for answer in json_data['answers']: check_keys(expected_inner_keys, answer) question = get_record_by_id(answer['question_id'], Question, check_school_id=False) if question.id not in question_ids: raise UnauthorizedError() answer = QuizAnswer(answer['answer'], submission.id, question.id) submission.answers.append(answer) submission.mark() db.session.add(submission) db.session.commit() return jsonify({'score': submission.total_score})
def quiz_detail(request, quiz_id): # Check quiz if valid quiz = get_record_by_id(quiz_id, Quiz, check_school_id=False) resp = services.lesson.get( "lessons/lesson/{}".format(quiz.lesson_id), headers=g.user.headers_dict(), ) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if lesson['school_id'] != g.user.school_id: raise UnauthorizedError() return jsonify({'success': True, 'quiz': quiz.to_dict()})
def essay_detail(request, essay_id): # Check essay if valid essay = get_record_by_id(essay_id, Essay, check_school_id=False) resp = services.lesson.get( "lessons/lesson/{}".format(essay.lesson_id), headers=g.user.headers_dict(), ) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if lesson['school_id'] != g.user.school_id: raise UnauthorizedError() return jsonify({'success': True, 'essay': essay.to_dict()})
def user_create(request): # Decode the JSON data data = json_from_request(request) # Validate data expected_keys = [ "first_name", "last_name", "password", "username", "email" ] # List of keys which need to in JSON check_keys(expected_keys, data) # Checks keys are in JSON check_values_not_blank( expected_keys, data) # Check that values for the keys are not blank # Check email is not in use. if User.query.filter_by(email=data['email']).first() is not None: raise FieldInUseError("email") # Check username is not in use in that school. if User.query.filter_by(username=data['username'], school_id=g.user.school_id).first() is not None: raise FieldInUseError("username") # Create user user = User(first_name=data['first_name'], last_name=data['last_name'], email=data['email'], password=data['password'], username=data['username'], school_id=g.user.school_id) if "form_id" in data.keys(): # Validate form id form = get_record_by_id(data["form_id"], Form, custom_not_found_error=CustomError( 409, message="Invalid form_id.")) # Set user's form_id user.form_id = form.id # Add user to db db.session.add(user) db.session.commit() # Return JSON return jsonify({"success": True, "user": user.to_dict()}), 201
def user_update(request, user_id): # Get JSON data data = json_from_request(request) # Get User object from id in url user = get_record_by_id(user_id, User) # Check that check_values_not_blank(data.keys(), data) if "first_name" in data.keys(): user.first_name = data['first_name'] if "last_name" in data.keys(): user.first_name = data['first_name'] if "password" in data.keys(): user.password = user.generate_password_hash(data['password']) if "email" in data.keys(): if user.email != data['email'] and User.query.filter_by( email=data['email']).first() is not None: raise FieldInUseError("email") user.email = data['email'] if "username" in data.keys(): if user.username != data['username'] and User.query.filter_by( username=data['username'], school_id=g.user.school_id).first() is not None: raise FieldInUseError("username") user.username = data['username'] if "form_id" in data.keys(): # Validate form id form = get_record_by_id(data["form_id"], Form, custom_not_found_error=CustomError( 409, message="Invalid form_id.")) user.form_id = form.id db.session.add(user) db.session.commit() return jsonify({'success': True, 'message': 'Updated.'})
def comment_delete_view(request, comment_id): """Delete Comment based on id.""" comment = get_record_by_id(comment_id, Comment, check_school_id=False) # Check user teaches the lesson that submission they are commenting on resp = services.lesson.get( "lessons/lesson/{}".format(comment.submission.homework.lesson_id), headers=g.user.headers_dict(), ) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if g.user.id != lesson['school_id']: raise UnauthorizedError() db.session.delete(comment) db.session.commit() return jsonify({'success': True, 'message': 'Deleted.'})
def comment_detail_view(request, comment_id): """Fetch Comment based on id from request.""" comment = get_record_by_id(comment_id, Comment, check_school_id=False) # Check user teaches the lesson that submission they are commenting on resp = services.lesson.get( "lessons/lesson/{}".format(comment.submission.homework.lesson_id), headers=g.user.headers_dict(), ) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if g.user.id != lesson['school_id']: raise UnauthorizedError() return jsonify({ 'success': True, 'comment': comment.to_dict(nest_user=True) })
def lesson_create(request): # Parse JSON from request data = json_from_request(request) # Check JSON has keys needed expected_keys = ['name', 'subject_id'] check_keys(expected_keys=expected_keys, data=data) # Validate subject_id subject = get_record_by_id(data['subject_id'], Subject, custom_not_found_error=CustomError( 409, message="Invalid subject_id.")) # Validate name validate_lesson_name(data['name'], g.user.school_id) # Create lesson lesson = Lesson(name=data['name'], school_id=g.user.school_id, subject_id=subject.id) # db.session.add(lesson) # db.session.commit() # Add teachers (if supplied) if 'teacher_ids' in data.keys(): add_teachers(data['teacher_ids'], lesson) # Add students (if supplied) if 'student_ids' in data.keys(): add_students(data['student_ids'], lesson) db.session.add(lesson) db.session.commit() return jsonify({ 'success': True, 'lesson': lesson.to_dict(nest_teachers=True) }), 201
def comment_create_view(request): """Creates a Comment object from a HTTP request.""" # Keys which need to in JSON from request top_level_expected_keys = [ "submission_id", "text", ] # Get JSON from request and check keys are present json_data = json_from_request(request) check_keys(top_level_expected_keys, json_data) # Fetch submission submission = get_record_by_id(json_data['submission_id'], Submission, check_school_id=False) # Check user teaches the lesson that submission they are commenting on resp = services.lesson.get("lessons/lesson/{}".format( submission.homework.lesson_id), headers=g.user.headers_dict(), params={'nest-teachers': True}) if resp.status_code != 200: raise CustomError(**resp.json()) lesson = resp.json()['lesson'] if g.user.id not in [t['id'] for t in lesson['teachers']]: raise UnauthorizedError() # Create comment comment = Comment(submission.id, json_data['text'], g.user.id) db.session.add(comment) db.session.commit() return jsonify({"success": True, "comment": comment.to_dict()}), 201