Beispiel #1
0
    def get(self):
        args = self.get_req_parser.parse_args()
        user_id = g.current_user['id']
        event_id = args['event_id']
        page_number = args['page_number']
        limit = args['limit']
        sort_column = args['sort_column']

        reviewer = user_repository.get_by_id(user_id).is_reviewer(event_id)
        if not reviewer:
            return FORBIDDEN

        reviews = review_repository.get_review_history(user_id, event_id)

        if sort_column == 'review_response_id':
            reviews = reviews.order_by(ReviewResponse.id)

        if sort_column == 'submitted_timestamp':
            reviews = reviews.order_by(ReviewResponse.submitted_timestamp)

        reviews = reviews.slice(page_number * limit,
                                page_number * limit + limit).all()

        num_entries = review_repository.get_review_history_count(
            user_id, event_id)

        total_pages = ceil(float(num_entries) / limit)

        reviews = [ReviewHistoryModel(review) for review in reviews]
        return {
            'reviews': reviews,
            'num_entries': num_entries,
            'current_pagenumber': page_number,
            'total_pages': total_pages
        }
Beispiel #2
0
    def put(self):
        args = self.post_req_parser.parse_args()
        validation_result = self.validate_scores(args['scores'])
        if validation_result is not None:
            return validation_result

        response_id = args['response_id']
        review_form_id = args['review_form_id']
        reviewer_user_id = g.current_user['id']
        scores = args['scores']
        is_submitted = args['is_submitted']

        response_reviewer = review_repository.get_response_reviewer(
            response_id, reviewer_user_id)
        if response_reviewer is None:
            return FORBIDDEN

        review_response = review_repository.get_review_response(
            review_form_id, response_id, reviewer_user_id)
        if review_response is None:
            return REVIEW_RESPONSE_NOT_FOUND

        review_repository.delete_review(review_response)
        review_response.review_scores = self.get_review_scores(scores)
        if is_submitted:
            review_response.submit()
        db.session.commit()

        return review_response, 200
Beispiel #3
0
    def put(self):
        args = self.post_req_parser.parse_args()
        validation_result = self.validate_scores(args['scores'])
        if validation_result is not None:
            return validation_result

        response_id = args['response_id']
        review_form_id = args['review_form_id']
        reviewer_user_id = g.current_user['id']
        scores = args['scores']

        response_reviewer = review_repository.get_response_reviewer(
            response_id, reviewer_user_id)
        if response_reviewer is None:
            return FORBIDDEN

        review_response = review_repository.get_review_response(
            review_form_id, response_id, reviewer_user_id)
        if review_response is None:
            return REVIEW_RESPONSE_NOT_FOUND

        db.session.query(ReviewScore).filter(
            ReviewScore.review_response_id == review_response.id).delete()
        review_response.review_scores = self.get_review_scores(scores)
        db.session.commit()

        return {}, 200
Beispiel #4
0
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('response_id', type=int, required=True)
        parser.add_argument('event_id', type=int, required=True)
        parser.add_argument('language', type=str, required=True)
        args = parser.parse_args()

        response_id = args['response_id']
        event_id = args['event_id']

        review_form = review_repository.get_review_form(event_id)
        if review_form is None:
            return REVIEW_FORM_NOT_FOUND

        response = review_repository.get_response_by_reviewer(
            response_id, g.current_user['id'])

        if response is None:
            return RESPONSE_NOT_FOUND

        review_response = review_repository.get_review_response(
            review_form.id, response_id, g.current_user['id'])

        return ReviewResponseUser(review_form,
                                  response,
                                  0,
                                  args['language'],
                                  review_response=review_response)
Beispiel #5
0
    def post(self):
        args = self.post_req_parser.parse_args()
        validation_result = self.validate_scores(args['scores'])
        if validation_result is not None:
            return validation_result

        response_id = args['response_id']
        review_form_id = args['review_form_id']
        reviewer_user_id = g.current_user['id']
        scores = args['scores']
        language = args['language']
        is_submitted = args['is_submitted']

        response_reviewer = review_repository.get_response_reviewer(
            response_id, reviewer_user_id)
        if response_reviewer is None:
            return FORBIDDEN

        review_response = ReviewResponse(review_form_id, reviewer_user_id,
                                         response_id, language)
        review_response.review_scores = self.get_review_scores(scores)
        if is_submitted:
            review_response.submit()
        review_repository.add_model(review_response)

        return review_response, 201
Beispiel #6
0
    def get(self, event_id):
        req_parser = reqparse.RequestParser()
        req_parser.add_argument('include_unsubmitted', type=inputs.boolean, required=True)
        # Note: Including [] in the question_ids parameter because that gets added by Axios on the front-end
        req_parser.add_argument('question_ids[]', type=int, required=False, action='append')
        req_parser.add_argument('language', type=str, required=True)
        args = req_parser.parse_args()

        include_unsubmitted = args['include_unsubmitted']
        question_ids = args['question_ids[]']
        language = args['language']
        
        print('Include unsubmitted:', include_unsubmitted)

        responses = response_repository.get_all_for_event(event_id, not include_unsubmitted)

        review_config = review_configuration_repository.get_configuration_for_event(event_id)
        required_reviewers = 1 if review_config is None else review_config.num_reviews_required + review_config.num_optional_reviews

        response_reviewers = review_repository.get_response_reviewers_for_event(event_id)
        response_to_reviewers = {
            k: list(g) for k, g in itertools.groupby(response_reviewers, lambda r: r.response_id)
        }

        review_responses = review_repository.get_review_responses_for_event(event_id)
        reviewer_to_review_response = {
            r.reviewer_user_id: r for r in review_responses
        }

        serialized_responses = []
        for response in responses:
            reviewers = [_serialize_reviewer(r, reviewer_to_review_response.get(r.reviewer_user_id, None)) 
                         for r in response_to_reviewers.get(response.id, [])]
            reviewers = _pad_list(reviewers, required_reviewers)
            if question_ids:
                answers = [_serialize_answer(answer, language) for answer in response.answers if answer.question_id in question_ids]
            else:
                answers = []

            serialized = {
                'response_id': response.id,
                'user_title': response.user.user_title,
                'firstname': response.user.firstname,
                'lastname': response.user.lastname,
                'start_date': response.started_timestamp.isoformat(),
                'is_submitted': response.is_submitted,
                'is_withdrawn': response.is_withdrawn,
                'submitted_date': None if response.submitted_timestamp is None else response.submitted_timestamp.isoformat(),
                'language': response.language,
                'answers': answers,
                'reviewers': reviewers,
                'tags': [_serialize_tag(rt.tag, language) for rt in response.response_tags]
            }

            serialized_responses.append(serialized)

        return serialized_responses
Beispiel #7
0
    def get_eligible_response_ids(self, event_id, reviewer_user_id,
                                  num_reviews, reviews_required):
        candidate_responses = review_repository.get_candidate_response_ids(
            event_id, reviewer_user_id, reviews_required)
        candidate_response_ids = set([r.id for r in candidate_responses])

        # Now remove any responses that the reviewer is already assigned to
        already_assigned = review_repository.get_already_assigned(
            reviewer_user_id)
        already_assigned_ids = set([r.response_id for r in already_assigned])
        responses = list(candidate_response_ids - already_assigned_ids)

        return random.sample(responses, min(len(responses), num_reviews))
Beispiel #8
0
    def get(self):
        args = self.get_req_parser.parse_args()
        id = args['id']
        reviewer_user_id = g.current_user['id']

        review_form_response = review_repository.get_review_response_with_form(
            id, reviewer_user_id)

        if review_form_response is None:
            return REVIEW_RESPONSE_NOT_FOUND

        review_form, review_response = review_form_response

        response = review_repository.get_response_by_review_response(
            id, reviewer_user_id, review_form.application_form_id)

        return ReviewResponseUser(review_form, response, 0, review_response)
Beispiel #9
0
    def get(self):
        args = self.req_parser.parse_args()
        event_id = args['event_id']

        review_form = review_repository.get_review_form(event_id)
        if review_form is None:
            return EVENT_NOT_FOUND

        reviews_remaining_count = review_repository.get_remaining_reviews_count(
            g.current_user['id'], review_form.application_form_id)

        skip = self.sanitise_skip(args['skip'], reviews_remaining_count)

        response = review_repository.get_response_to_review(
            skip, g.current_user['id'], review_form.application_form_id)

        return ReviewResponseUser(review_form, response,
                                  reviews_remaining_count)
Beispiel #10
0
def _validate_user_admin_or_reviewer(user_id, event_id, response_id):
    user = user_repository.get_by_id(user_id)
    # Check if the user is an event admin
    permitted = user.is_event_admin(event_id)
    # If they're not an event admin, check if they're a reviewer for the relevant response
    if not permitted and user.is_reviewer(event_id):
        response_reviewer = review_repository.get_response_reviewer(response_id, user.id)
        if response_reviewer is not None:
            permitted = True
    
    return permitted
Beispiel #11
0
    def get(self, event_id):
        parser = reqparse.RequestParser()
        parser.add_argument('language', type=str, required=True)
        args = parser.parse_args()

        review_responses = review_repository.get_all_review_responses_by_event(
            event_id)
        return [
            ReviewResponseDetailListAPI._serialise_review_response(
                review_response, args['language'])
            for review_response in review_responses
        ], 200
Beispiel #12
0
    def get(self):
        args = self.get_req_parser.parse_args()
        event_id = args['event_id']
        user_id = g.current_user['id']

        current_user = user_repository.get_by_id(user_id)
        if not current_user.is_event_admin(event_id):
            return FORBIDDEN

        counts = review_repository.count_reviews_allocated_and_completed_per_reviewer(
            event_id)
        views = [ReviewCountView(count) for count in counts]
        return views
Beispiel #13
0
    def get(self):
        args = self.req_parser.parse_args()
        event_id = args['event_id']

        review_form = review_repository.get_review_form(event_id)
        if review_form is None:
            return EVENT_NOT_FOUND

        reviews_remaining_count = review_repository.get_remaining_reviews_count(
            g.current_user['id'], review_form.application_form_id)
        skip = self.sanitise_skip(args['skip'], reviews_remaining_count)

        response = review_repository.get_response_to_review(
            skip, g.current_user['id'], review_form.application_form_id)

        references = []
        if response is not None:
            reference_requests = reference_repository.get_all_by_response_id(
                response.id)

            for r in reference_requests:
                reference = reference_repository.get_reference_by_reference_request_id(
                    r.id)
                if reference is not None:
                    references.append(
                        ReviewResponseReference(r.title, r.firstname,
                                                r.lastname, r.relation,
                                                reference.uploaded_document))

        review_response = None if response is None else review_repository.get_review_response(
            review_form.id, response.id, g.current_user['id'])
        references = None if len(references) == 0 else references

        return ReviewResponseUser(review_form,
                                  response,
                                  reviews_remaining_count,
                                  args['language'],
                                  reference_responses=references,
                                  review_response=review_response)
Beispiel #14
0
    def delete(self, event_id):
        parser = reqparse.RequestParser()
        parser.add_argument('response_id', type=int, required=True)
        parser.add_argument('reviewer_user_id', type=int, required=True)
        args = parser.parse_args()

        response_id = args['response_id']
        reviewer_user_id = args['reviewer_user_id']

        review_form = review_repository.get_review_form(event_id)
        if not review_form:
            return REVIEW_FORM_NOT_FOUND

        # If the reviewer has already completed the review, action can't be completed
        review_response = review_repository.get_review_response(
            review_form.id, response_id, reviewer_user_id)
        if review_response:
            return REVIEW_ALREADY_COMPLETED

        review_repository.delete_response_reviewer(response_id,
                                                   reviewer_user_id)

        return {}, 200
Beispiel #15
0
    def get(self):
        args = self.get_req_parser.parse_args()
        event_id = args['event_id']
        user_id = g.current_user['id']

        current_user = user_repository.get_by_id(user_id)
        if not current_user.is_event_admin(event_id):
            return FORBIDDEN

        return {
            'reviews_unallocated':
            review_repository.count_unassigned_reviews(event_id,
                                                       REVIEWS_PER_SUBMISSION)
        }
Beispiel #16
0
    def _serialize_reviewer(response_reviewer, review_form_id):
        if review_form_id is None:
            completed = False
        else:
            review_response = review_repository.get_review_response(review_form_id, response_reviewer.response_id, response_reviewer.reviewer_user_id)
            completed = review_response is not None

        return {
            'reviewer_user_id': response_reviewer.user.id,
            'user_title': response_reviewer.user.user_title,
            'firstname': response_reviewer.user.firstname,
            'lastname': response_reviewer.user.lastname,
            'completed': completed
        }
Beispiel #17
0
    def get(self, event_id):
        req_parser = reqparse.RequestParser()
        req_parser.add_argument('stage', type=int, required=False)
        args = req_parser.parse_args()

        stage = args['stage']

        review_form = review_repository.get_review_form(event_id, stage=stage)

        if not review_form:
            return REVIEW_FORM_FOR_STAGE_NOT_FOUND

        review_form.event_id = event_id

        return review_form
Beispiel #18
0
    def _serialise_response(response: Response, review_form: ReviewForm,
                            language: str):
        scores = []
        for review_section in review_form.review_sections:
            for review_question in review_section.review_questions:
                if review_question.weight > 0:
                    review_question_translation = review_question.get_translation(
                        language)
                    if not review_question_translation:
                        review_question_translation = review_question.get_translation(
                            'en')
                        LOGGER.warn(
                            'Could not find {} translation for review question id {}'
                            .format(language, review_score.review_question.id))

                    average_score = review_repository.get_average_score_for_review_question(
                        response.id, review_question.id)

                    score = {
                        "review_question_id": review_question.id,
                        "headline": review_question_translation.headline,
                        "description": review_question_translation.description,
                        "type": review_question.type,
                        "score": average_score,
                        "weight": review_question.weight
                    }
                    scores.append(score)

        response_summary = {
            "response_id":
            response.id,
            "response_user_title":
            response.user.user_title,
            "response_user_firstname":
            response.user.firstname,
            "response_user_lastname":
            response.user.lastname,
            "identifiers": [
                ReviewResponseDetailListAPI._serialise_identifier(
                    answer, response.language) for answer in response.answers
                if answer.question.is_review_identifier()
            ],
            "scores":
            scores,
            "total":
            sum(score['score'] * score['weight'] for score in scores)
        }
        return response_summary
Beispiel #19
0
    def get(self):
        args = self.get_req_parser.parse_args()
        event_id = args['event_id']
        user_id = g.current_user['id']

        current_user = user_repository.get_by_id(user_id)
        if not current_user.is_event_admin(event_id):
            return FORBIDDEN

        config = review_configuration_repository.get_configuration_for_event(
            event_id)

        return {
            'reviews_unallocated':
            review_repository.count_unassigned_reviews(
                event_id, config.num_reviews_required)
        }
Beispiel #20
0
    def get(self, event_id):
        req_parser = reqparse.RequestParser()
        req_parser.add_argument('response_id', type=int, required=True) 
        req_parser.add_argument('language', type=str, required=True) 
        args = req_parser.parse_args()

        response_id = args['response_id']   
        language = args['language']

        response = response_repository.get_by_id(response_id)
        review_form = review_repository.get_review_form(event_id)
        review_form_id = None if review_form is None else review_form.id

        review_config = review_configuration_repository.get_configuration_for_event(event_id)
        num_reviewers = review_config.num_reviews_required + review_config.num_optional_reviews if review_config is not None else 1

        return ResponseDetailAPI._serialize_response(response, language, review_form_id, num_reviewers)
Beispiel #21
0
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('event_id', type=int, required=True)
        args = parser.parse_args()

        event_id = args['event_id']

        review_forms = review_repository.get_all_review_forms_for_event(
            event_id)
        current_form = [r for r in review_forms if r.active]

        if not current_form:
            return NO_ACTIVE_REVIEW_FORM

        current_form = current_form[0]

        return {
            'current_stage': current_form.stage,
            'total_stages': len(review_forms)
        }
Beispiel #22
0
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('event_id', type=int, required=True)
        parser.add_argument('language', type=str, required=True)
        args = parser.parse_args()
        event_id = args['event_id']
        user_id = g.current_user['id']
        language = args['language']

        if not user_repository.get_by_id(user_id).is_reviewer(event_id):
            return FORBIDDEN

        responses_to_review = review_repository.get_review_list(
            user_id, event_id)

        return [
            ReviewListAPI._serialize_response(response, review_response,
                                              language)
            for response, review_response in responses_to_review
        ]
Beispiel #23
0
    def post(self, event_id):
        parser = reqparse.RequestParser()
        parser.add_argument('stage', type=int, required=True)
        args = parser.parse_args()

        stage = args['stage']

        review_forms = review_repository.get_all_review_forms_for_event(
            event_id)
        selected_form = [r for r in review_forms if r.stage == stage]

        if not selected_form:
            return REVIEW_FORM_FOR_STAGE_NOT_FOUND

        selected_form = selected_form[0]

        for form in review_forms:
            form.deactivate()

        selected_form.activate()

        db.session.commit()

        return {}, 201
Beispiel #24
0
    def put(self, event_id):
        dt_format = lambda x: datetime.strptime(x, '%Y-%m-%dT%H:%M:%S')

        req_parser = reqparse.RequestParser()
        req_parser.add_argument('id', type=int, required=True)
        req_parser.add_argument('application_form_id', type=int, required=True)
        req_parser.add_argument('stage', type=int, required=True)
        req_parser.add_argument('is_open', type=bool, required=True)
        req_parser.add_argument('deadline', type=dt_format, required=True)
        req_parser.add_argument('sections',
                                type=dict,
                                required=True,
                                action='append')
        args = req_parser.parse_args()

        id = args['id']
        application_form_id = args['application_form_id']
        stage = args['stage']
        is_open = args['is_open']
        deadline = args['deadline']
        sections_data = args['sections']

        review_form = review_repository.get_review_form_by_id(id)
        if not review_form:
            return REVIEW_FORM_NOT_FOUND

        if application_form_id != review_form.application_form_id:
            return UPDATE_CONFLICT

        if event_id != review_form.application_form.event_id:
            return UPDATE_CONFLICT

        review_form.stage = stage
        review_form.is_open = is_open
        review_form.deadline = deadline

        # Note: we don't update the active property which is controlled by
        # the ReviewStageAPI

        # Delete questions in the review form that no longer exist
        all_question_ids = [
            q["id"] for s in sections_data for q in s["questions"] if "id" in q
        ]
        for section in review_form.review_sections:
            for question in section.review_questions:
                if question.id not in all_question_ids:
                    review_repository.delete_review_question(question)

        all_section_ids = [s["id"] for s in sections_data if "id" in s]
        for section in review_form.review_sections:
            if section.id not in all_section_ids:
                review_repository.delete_review_section(section)

        for section_data in sections_data:
            if 'id' in section_data:
                # If ID is populated, then update the existing section
                section = next((s for s in review_form.review_sections
                                if s.id == section_data['id']),
                               None)  # type: ReviewSection
                if not section:
                    return SECTION_NOT_FOUND

                current_translations = section.translations  # type: Sequence[ReviewSectionTranslation]
                for current_translation in current_translations:
                    current_translation.description = section_data[
                        'description'][current_translation.language]
                    current_translation.headline = section_data['name'][
                        current_translation.language]

                section.order = section_data["order"]
            else:
                # if not populated, then add new section
                section = ReviewSection(review_form.id, section_data["order"])
                review_repository.add_model(section)

                languages = section_data['name'].keys()
                for language in languages:
                    section_translation = ReviewSectionTranslation(
                        section.id, language, section_data['name'][language],
                        section_data['description'][language])
                    review_repository.add_model(section_translation)

            for question_data in section_data["questions"]:
                if "id" in question_data:
                    current_question = next((q
                                             for q in section.review_questions
                                             if q.id == question_data['id']),
                                            None)  # type: ReviewQuestion
                    if not current_question:
                        return QUESTION_NOT_FOUND

                    current_question.question_id = question_data[
                        "question_id"] or None
                    current_question.type = question_data["type"]
                    current_question.order = question_data["order"]
                    current_question.is_required = question_data["is_required"]
                    current_question.weight = question_data["weight"]

                    current_translations = current_question.translations  # type: Sequence[ReviewQuestionTranslation]
                    for current_translation in current_translations:
                        current_translation.description = question_data[
                            'description'][current_translation.language]
                        current_translation.headline = question_data[
                            'headline'][current_translation.language]
                        current_translation.options = question_data['options'][
                            current_translation.language]
                        current_translation.placeholder = question_data[
                            'placeholder'][current_translation.language]
                        current_translation.validation_regex = question_data[
                            'validation_regex'][current_translation.language]
                        current_translation.validation_text = question_data[
                            'validation_text'][current_translation.language]
                else:
                    question = ReviewQuestion(
                        review_section_id=section.id,
                        question_id=question_data["question_id"] or None,
                        type=question_data["type"],
                        is_required=question_data["is_required"],
                        order=question_data["order"],
                        weight=question_data["weight"])

                    review_repository.add_model(question)

                    for language in question_data['headline'].keys():
                        translation = ReviewQuestionTranslation(
                            review_question_id=question.id,
                            language=language,
                            description=question_data["description"][language],
                            headline=question_data["headline"][language],
                            placeholder=question_data["placeholder"][language],
                            options=question_data["options"][language],
                            validation_regex=question_data["validation_regex"]
                            [language],
                            validation_text=question_data["validation_text"]
                            [language])

                        review_repository.add_model(translation)

            db.session.commit()

        review_form = review_repository.get_review_form_by_id(id)
        review_form.event_id = event_id

        return review_form, 200
Beispiel #25
0
    def get(self, event_id):
        event = event_repository.get_by_id(event_id)
        if not event:
            return EVENT_NOT_FOUND

        num_responses = response_repository.get_total_count_by_event(event_id)
        num_submitted_respones = response_repository.get_submitted_count_by_event(
            event_id)
        num_withdrawn_responses = response_repository.get_withdrawn_count_by_event(
            event_id)
        submitted_response_timeseries = _process_timeseries(
            response_repository.get_submitted_timeseries_by_event(event_id))

        review_config = review_config_repository.get_configuration_for_event(
            event_id)
        required_reviews = 1 if review_config is None else review_config.num_reviews_required
        reviews_completed = review_repository.get_count_reviews_completed_for_event(
            event_id)
        reviews_incomplete = review_repository.get_count_reviews_incomplete_for_event(
            event_id)
        reviews_unallocated = review_repository.count_unassigned_reviews(
            event_id, required_reviews)
        reviews_timeseries = _process_timeseries(
            review_repository.get_review_complete_timeseries_by_event(
                event_id))

        offers_allocated = offer_repository.count_offers_allocated(event_id)
        offers_accepted = offer_repository.count_offers_accepted(event_id)
        offers_rejected = offer_repository.count_offers_rejected(event_id)
        offers_timeseries = _process_timeseries(
            offer_repository.timeseries_offers_accepted(event_id))

        num_registrations = registration_repository.count_registrations(
            event_id)
        num_guests = guest_registration_repository.count_guests(event_id)
        num_registered_guests = guest_registration_repository.count_registered_guests(
            event_id)
        registration_timeseries = _process_timeseries(
            registration_repository.timeseries_registrations(event_id))
        guest_registration_timeseries = _process_timeseries(
            guest_registration_repository.timeseries_guest_registrations(
                event_id))
        registration_timeseries = _combine_timeseries(
            registration_timeseries, guest_registration_timeseries)

        return {
            'num_responses': num_responses,
            'num_submitted_responses': num_submitted_respones,
            'num_withdrawn_responses': num_withdrawn_responses,
            'submitted_timeseries': submitted_response_timeseries,
            'reviews_completed': reviews_completed,
            'review_incomplete': reviews_incomplete,
            'reviews_unallocated': reviews_unallocated,
            'reviews_complete_timeseries': reviews_timeseries,
            'offers_allocated': offers_allocated,
            'offers_accepted': offers_accepted,
            'offers_rejected': offers_rejected,
            'offers_accepted_timeseries': offers_timeseries,
            'num_registrations': num_registrations,
            'num_guests': num_guests,
            'num_registered_guests': num_registered_guests,
            'registration_timeseries': registration_timeseries
        }, 200
Beispiel #26
0
    def post(self, event_id):
        dt_format = lambda x: datetime.strptime(x, '%Y-%m-%dT%H:%M:%S')

        req_parser = reqparse.RequestParser()
        req_parser.add_argument('application_form_id', type=int, required=True)
        req_parser.add_argument('stage', type=int, required=True)
        req_parser.add_argument('is_open', type=bool, required=True)
        req_parser.add_argument('deadline', type=dt_format, required=True)
        req_parser.add_argument('active', type=bool, required=True)
        req_parser.add_argument('sections',
                                type=dict,
                                required=True,
                                action='append')
        args = req_parser.parse_args()

        application_form_id = args['application_form_id']
        stage = args['stage']
        is_open = args['is_open']
        deadline = args['deadline']
        active = args['active']
        sections_data = args['sections']

        review_form = review_repository.get_review_form(event_id, stage)
        if review_form is not None:
            return REVIEW_FORM_EXISTS

        other_review_forms = review_repository.get_review_forms(event_id)

        review_form = ReviewForm(
            application_form_id,
            deadline,
            stage,
            # Only make this stage active if there is no other active stage.
            active=not any(o.active for o in other_review_forms))

        review_repository.add_model(review_form)

        for section_data in sections_data:
            section = ReviewSection(review_form.id, section_data['order'])
            review_repository.add_model(section)

            languages = section_data['name'].keys()
            for language in languages:
                section_translation = ReviewSectionTranslation(
                    review_section_id=section.id,
                    language=language,
                    headline=section_data['name'][language],
                    description=section_data['description'][language])
                review_repository.add_model(section_translation)

            for question_data in section_data['questions']:
                question = ReviewQuestion(
                    review_section_id=section.id,
                    question_id=question_data['question_id'] or None,
                    type=question_data['type'],
                    is_required=question_data['is_required'],
                    order=question_data['order'],
                    weight=question_data['weight'])

                review_repository.add_model(question)

                languages = question_data['headline'].keys()
                for language in languages:
                    question_translation = ReviewQuestionTranslation(
                        review_question_id=question.id,
                        language=language,
                        description=question_data["description"][language],
                        headline=question_data["headline"][language],
                        placeholder=question_data["placeholder"][language],
                        options=question_data["options"][language],
                        validation_regex=question_data["validation_regex"]
                        [language],
                        validation_text=question_data["validation_text"]
                        [language])

                    review_repository.add_model(question_translation)

        new_review_form = review_repository.get_review_form_by_id(
            review_form.id)
        new_review_form.event_id = event_id

        return new_review_form, 201