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})
Exemple #4
0
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
Exemple #7
0
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)
Exemple #8
0
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)
    })
Exemple #9
0
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
Exemple #11
0
    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
Exemple #12
0
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]})
Exemple #13
0
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))
Exemple #14
0
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))
Exemple #15
0
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})
Exemple #16
0
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)
    })
Exemple #17
0
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})
Exemple #18
0
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()})
Exemple #20
0
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
Exemple #21
0
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.'})
Exemple #22
0
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.'})
Exemple #23
0
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)
    })
Exemple #24
0
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
Exemple #25
0
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