Skip to content

Views

hypha.apply.review.views

ReviewEditView

Bases: UserPassesTestMixin, BaseStreamForm, UpdateView

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

submission_form_class class-attribute instance-attribute

submission_form_class = ReviewModelForm

model class-attribute instance-attribute

model = Review

template_name class-attribute instance-attribute

template_name = 'review/review_edit_form.html'

raise_exception class-attribute instance-attribute

raise_exception = True

from_db classmethod

from_db(db, field_names, values)
Source code in hypha/apply/stream_forms/models.py
@classmethod
def from_db(cls, db, field_names, values):
    instance = super().from_db(db, field_names, values)
    if "form_data" in field_names:
        instance.form_data = cls.deserialize_form_data(
            instance, instance.form_data, instance.form_fields
        )
    return instance

deserialize_form_data classmethod

deserialize_form_data(instance, form_data, form_fields)
Source code in hypha/apply/stream_forms/models.py
@classmethod
def deserialize_form_data(cls, instance, form_data, form_fields):
    data = form_data.copy()
    # PERFORMANCE NOTE:
    # Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
    # including any sub queries that they do
    for _i, field_data in enumerate(form_fields.raw_data):
        block = form_fields.stream_block.child_blocks[field_data["type"]]
        field_id = field_data.get("id")
        try:
            value = data[field_id]
        except KeyError:
            pass
        else:
            data[field_id] = block.decode(value)
    return data

get_form_fields

get_form_fields(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
def get_form_fields(self, draft=False, form_data=None, user=None):
    if form_data is None:
        form_data = {}

    form_fields = OrderedDict()
    field_blocks = self.get_defined_fields()
    group_counter = 1
    is_in_group = False

    # If true option 1 is selected
    grouped_fields_visible = False
    for struct_child in field_blocks:
        block = struct_child.block
        struct_value = struct_child.value
        if isinstance(block, FormFieldBlock):
            field_from_block = block.get_field(struct_value)
            disabled_help_text = _(
                "You are logged in so this information is fetched from your user account."
            )
            if isinstance(block, FullNameBlock) and user and user.is_authenticated:
                if user.full_name:
                    field_from_block.disabled = True
                    field_from_block.initial = user.full_name
                    field_from_block.help_text = disabled_help_text
                else:
                    field_from_block.help_text = _(
                        "You are logged in but your user account does not have a "
                        "full name. We'll update your user account with the name you provide here."
                    )
            if isinstance(block, EmailBlock) and user and user.is_authenticated:
                field_from_block.disabled = True
                field_from_block.initial = user.email
                field_from_block.help_text = disabled_help_text
            if draft and not issubclass(
                block.__class__, ApplicationMustIncludeFieldBlock
            ):
                field_from_block.required = False
            field_from_block.help_link = struct_value.get("help_link")
            field_from_block.group_number = group_counter if is_in_group else 1
            if isinstance(block, GroupToggleBlock) and not is_in_group:
                field_from_block.group_number = 1
                field_from_block.grouper_for = group_counter + 1
                group_counter += 1
                is_in_group = True
                grouped_fields_visible = (
                    form_data.get(struct_child.id) == field_from_block.choices[0][0]
                )
            if isinstance(block, TextFieldBlock):
                field_from_block.word_limit = struct_value.get("word_limit")
            if isinstance(block, MultiInputCharFieldBlock):
                number_of_inputs = struct_value.get("number_of_inputs")
                for index in range(number_of_inputs):
                    form_fields[struct_child.id + "_" + str(index)] = (
                        field_from_block
                    )
                    field_from_block.multi_input_id = struct_child.id
                    field_from_block.add_button_text = struct_value.get(
                        "add_button_text"
                    )
                    if (
                        index == number_of_inputs - 1
                    ):  # Add button after last input field
                        field_from_block.multi_input_add_button = True
                        # Index for field until which fields will be visible to applicant.
                        # Initially only the first field with id UUID_0 will be visible.
                        field_from_block.visibility_index = 0
                        field_from_block.max_index = index
                    if index != 0:
                        field_from_block.multi_input_field = True
                        field_from_block.required = False
                        field_from_block.initial = None
                    field_from_block = copy.copy(field_from_block)
            else:
                if is_in_group and not isinstance(block, GroupToggleBlock):
                    field_from_block.required_when_visible = (
                        field_from_block.required
                    )
                    field_from_block.required = (
                        field_from_block.required & grouped_fields_visible
                    )
                    field_from_block.visible = grouped_fields_visible
                form_fields[struct_child.id] = field_from_block
        elif isinstance(block, GroupToggleEndBlock):
            # Group toggle end block is used only to group fields and not used in actual form.
            # Todo: Use streamblock to create nested form field blocks, a more elegant method to group form fields.
            is_in_group = False
        else:
            field_wrapper = BlockFieldWrapper(struct_child)
            field_wrapper.group_number = group_counter if is_in_group else 1
            form_fields[struct_child.id] = field_wrapper

    return form_fields

get_form_class

get_form_class(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
def get_form_class(self, draft=False, form_data=None, user=None):
    return type(
        "WagtailStreamForm",
        (self.submission_form_class,),
        self.get_form_fields(draft, form_data, user),
    )

test_func

test_func()
Source code in hypha/apply/review/views.py
def test_func(self):
    review = self.get_object()
    return (
        self.request.user.has_perm("review.change_review")
        or self.request.user == review.author.reviewer
    )

get_context_data

get_context_data(**kwargs)
Source code in hypha/apply/review/views.py
def get_context_data(self, **kwargs):
    review = self.get_object()
    return super().get_context_data(
        submission=review.submission,
        title=_("Edit Review"),
        **kwargs,
    )

get_defined_fields

get_defined_fields()

Retrieve currently stored form_fields, if it exists, else retrieve it from the form configured in the rounds/lab of the submission.

This ensures editing of submitted review is not affected by the changes to the original review forms.

Source code in hypha/apply/review/views.py
def get_defined_fields(self):
    """Retrieve currently stored form_fields, if it exists, else retrieve it from the form configured
    in the rounds/lab of the submission.

    This ensures editing of submitted review is not affected by the changes to the original review forms.
    """
    review = self.get_object()
    return review.form_fields or get_fields_for_stage(
        review.submission, user=self.request.user
    )

get_form_kwargs

get_form_kwargs()
Source code in hypha/apply/review/views.py
def get_form_kwargs(self):
    review = self.get_object()
    kwargs = super().get_form_kwargs()
    kwargs["user"] = self.request.user
    kwargs["submission"] = review.submission

    if self.object:
        kwargs["initial"] = self.object.form_data

    return kwargs

form_valid

form_valid(form)
Source code in hypha/apply/review/views.py
def form_valid(self, form):
    review = self.get_object()
    messenger(
        MESSAGES.EDIT_REVIEW,
        user=self.request.user,
        request=self.request,
        source=review.submission,
        related=review,
    )
    response = super().form_valid(form)

    # Automatic workflow actions.
    review_workflow_actions(self.request, review.submission)

    return response

get_success_url

get_success_url()
Source code in hypha/apply/review/views.py
def get_success_url(self):
    review = self.get_object()
    return reverse_lazy("funds:submissions:detail", args=(review.submission.id,))

ReviewCreateOrUpdateView

Bases: BaseStreamForm, CreateOrUpdateView

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

submission_form_class class-attribute instance-attribute

submission_form_class = ReviewModelForm

model class-attribute instance-attribute

model = Review

template_name class-attribute instance-attribute

template_name = 'review/review_form.html'

get

get(request, *args, **kwargs)
Source code in hypha/apply/utils/views.py
def get(self, request, *args, **kwargs):
    try:
        self.object = self.get_object()
    except self.model.DoesNotExist:
        self.object = None

    return super().get(request, *args, **kwargs)

post

post(request, *args, **kwargs)
Source code in hypha/apply/utils/views.py
def post(self, request, *args, **kwargs):
    try:
        self.object = self.get_object()
    except self.model.DoesNotExist:
        self.object = None

    return super().post(request, *args, **kwargs)

from_db classmethod

from_db(db, field_names, values)
Source code in hypha/apply/stream_forms/models.py
@classmethod
def from_db(cls, db, field_names, values):
    instance = super().from_db(db, field_names, values)
    if "form_data" in field_names:
        instance.form_data = cls.deserialize_form_data(
            instance, instance.form_data, instance.form_fields
        )
    return instance

deserialize_form_data classmethod

deserialize_form_data(instance, form_data, form_fields)
Source code in hypha/apply/stream_forms/models.py
@classmethod
def deserialize_form_data(cls, instance, form_data, form_fields):
    data = form_data.copy()
    # PERFORMANCE NOTE:
    # Do not attempt to iterate over form_fields - that will fully instantiate the form_fields
    # including any sub queries that they do
    for _i, field_data in enumerate(form_fields.raw_data):
        block = form_fields.stream_block.child_blocks[field_data["type"]]
        field_id = field_data.get("id")
        try:
            value = data[field_id]
        except KeyError:
            pass
        else:
            data[field_id] = block.decode(value)
    return data

get_form_fields

get_form_fields(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
def get_form_fields(self, draft=False, form_data=None, user=None):
    if form_data is None:
        form_data = {}

    form_fields = OrderedDict()
    field_blocks = self.get_defined_fields()
    group_counter = 1
    is_in_group = False

    # If true option 1 is selected
    grouped_fields_visible = False
    for struct_child in field_blocks:
        block = struct_child.block
        struct_value = struct_child.value
        if isinstance(block, FormFieldBlock):
            field_from_block = block.get_field(struct_value)
            disabled_help_text = _(
                "You are logged in so this information is fetched from your user account."
            )
            if isinstance(block, FullNameBlock) and user and user.is_authenticated:
                if user.full_name:
                    field_from_block.disabled = True
                    field_from_block.initial = user.full_name
                    field_from_block.help_text = disabled_help_text
                else:
                    field_from_block.help_text = _(
                        "You are logged in but your user account does not have a "
                        "full name. We'll update your user account with the name you provide here."
                    )
            if isinstance(block, EmailBlock) and user and user.is_authenticated:
                field_from_block.disabled = True
                field_from_block.initial = user.email
                field_from_block.help_text = disabled_help_text
            if draft and not issubclass(
                block.__class__, ApplicationMustIncludeFieldBlock
            ):
                field_from_block.required = False
            field_from_block.help_link = struct_value.get("help_link")
            field_from_block.group_number = group_counter if is_in_group else 1
            if isinstance(block, GroupToggleBlock) and not is_in_group:
                field_from_block.group_number = 1
                field_from_block.grouper_for = group_counter + 1
                group_counter += 1
                is_in_group = True
                grouped_fields_visible = (
                    form_data.get(struct_child.id) == field_from_block.choices[0][0]
                )
            if isinstance(block, TextFieldBlock):
                field_from_block.word_limit = struct_value.get("word_limit")
            if isinstance(block, MultiInputCharFieldBlock):
                number_of_inputs = struct_value.get("number_of_inputs")
                for index in range(number_of_inputs):
                    form_fields[struct_child.id + "_" + str(index)] = (
                        field_from_block
                    )
                    field_from_block.multi_input_id = struct_child.id
                    field_from_block.add_button_text = struct_value.get(
                        "add_button_text"
                    )
                    if (
                        index == number_of_inputs - 1
                    ):  # Add button after last input field
                        field_from_block.multi_input_add_button = True
                        # Index for field until which fields will be visible to applicant.
                        # Initially only the first field with id UUID_0 will be visible.
                        field_from_block.visibility_index = 0
                        field_from_block.max_index = index
                    if index != 0:
                        field_from_block.multi_input_field = True
                        field_from_block.required = False
                        field_from_block.initial = None
                    field_from_block = copy.copy(field_from_block)
            else:
                if is_in_group and not isinstance(block, GroupToggleBlock):
                    field_from_block.required_when_visible = (
                        field_from_block.required
                    )
                    field_from_block.required = (
                        field_from_block.required & grouped_fields_visible
                    )
                    field_from_block.visible = grouped_fields_visible
                form_fields[struct_child.id] = field_from_block
        elif isinstance(block, GroupToggleEndBlock):
            # Group toggle end block is used only to group fields and not used in actual form.
            # Todo: Use streamblock to create nested form field blocks, a more elegant method to group form fields.
            is_in_group = False
        else:
            field_wrapper = BlockFieldWrapper(struct_child)
            field_wrapper.group_number = group_counter if is_in_group else 1
            form_fields[struct_child.id] = field_wrapper

    return form_fields

get_form_class

get_form_class(draft=False, form_data=None, user=None)
Source code in hypha/apply/stream_forms/models.py
def get_form_class(self, draft=False, form_data=None, user=None):
    return type(
        "WagtailStreamForm",
        (self.submission_form_class,),
        self.get_form_fields(draft, form_data, user),
    )

get_object

get_object(queryset=None)
Source code in hypha/apply/review/views.py
def get_object(self, queryset=None):
    return self.model.objects.get(
        submission=self.submission, author__reviewer=self.request.user
    )

dispatch

dispatch(request, *args, **kwargs)
Source code in hypha/apply/review/views.py
def dispatch(self, request, *args, **kwargs):
    self.submission = get_object_or_404(
        ApplicationSubmission, id=self.kwargs["submission_pk"]
    )

    if not self.submission.phase.permissions.can_review(
        request.user
    ) or not self.submission.has_permission_to_review(request.user):
        raise PermissionDenied()

    if self.request.POST and self.submission.reviewed_by(request.user):
        return self.get(request, *args, **kwargs)

    return super().dispatch(request, *args, **kwargs)

get_context_data

get_context_data(**kwargs)
Source code in hypha/apply/review/views.py
def get_context_data(self, **kwargs):
    has_submitted_review = self.submission.reviewed_by(self.request.user)
    return super().get_context_data(
        submission=self.submission,
        has_submitted_review=has_submitted_review,
        title=_("Update Review draft") if self.object else _("Create Review"),
        **kwargs,
    )

get_defined_fields

get_defined_fields()
Source code in hypha/apply/review/views.py
def get_defined_fields(self):
    return get_fields_for_stage(self.submission, user=self.request.user)

get_form_kwargs

get_form_kwargs()
Source code in hypha/apply/review/views.py
def get_form_kwargs(self):
    kwargs = super().get_form_kwargs()
    kwargs["user"] = self.request.user
    kwargs["submission"] = self.submission

    if self.object:
        kwargs["initial"] = self.object.form_data

    return kwargs

form_valid

form_valid(form)
Source code in hypha/apply/review/views.py
def form_valid(self, form):
    form.instance.form_fields = self.get_defined_fields()
    form.instance.author, _ = AssignedReviewers.objects.get_or_create_for_user(
        submission=self.submission,
        reviewer=self.request.user,
    )

    response = super().form_valid(form)

    if self.object.is_draft:
        if self.request.user.is_apply_staff:
            add_task_to_user(
                code=REVIEW_DRAFT, user=self.request.user, related_obj=self.object
            )

    if not self.object.is_draft:
        if self.request.user.is_apply_staff:
            remove_tasks_for_user(
                code=REVIEW_DRAFT, user=self.request.user, related_obj=self.object
            )
        messenger(
            MESSAGES.NEW_REVIEW,
            request=self.request,
            user=self.request.user,
            source=self.submission,
            related=self.object,
        )

        # Automatic workflow actions.
        review_workflow_actions(self.request, self.submission)

    return response

get_success_url

get_success_url()
Source code in hypha/apply/review/views.py
def get_success_url(self):
    return self.submission.get_absolute_url()

ReviewDisplay

Bases: UserPassesTestMixin, DetailView

model class-attribute instance-attribute

model = Review

raise_exception class-attribute instance-attribute

raise_exception = True

get_context_data

get_context_data(**kwargs)
Source code in hypha/apply/review/views.py
def get_context_data(self, **kwargs):
    review = self.get_object()
    if review.author.reviewer != self.request.user:
        consensus_form = ReviewOpinionForm(
            instance=review.opinions.filter(
                author__reviewer=self.request.user
            ).first(),
        )
    else:
        consensus_form = None
    return super().get_context_data(
        form=consensus_form,
        **kwargs,
    )

test_func

test_func()
Source code in hypha/apply/review/views.py
def test_func(self):
    review = self.get_object()
    user = self.request.user
    author = review.author.reviewer
    submission = review.submission

    if user.is_apply_staff:
        return True

    if user == author:
        return True

    if user.is_reviewer and review.reviewer_visibility:
        return True

    if (
        user.is_community_reviewer
        and submission.community_review
        and review.reviewer_visibility
        and submission.user != user
    ):
        return True

    return False

dispatch

dispatch(request, *args, **kwargs)
Source code in hypha/apply/review/views.py
def dispatch(self, request, *args, **kwargs):
    review = self.get_object()

    if review.is_draft:
        return HttpResponseRedirect(
            reverse_lazy(
                "apply:submissions:reviews:form", args=(review.submission.id,)
            )
        )

    return super().dispatch(request, *args, **kwargs)

ReviewOpinionFormView

Bases: UserPassesTestMixin, CreateView

template_name class-attribute instance-attribute

template_name = 'review/review_detail.html'

form_class class-attribute instance-attribute

form_class = ReviewOpinionForm

model class-attribute instance-attribute

model = Review

raise_exception class-attribute instance-attribute

raise_exception = True

get_form_kwargs

get_form_kwargs()
Source code in hypha/apply/review/views.py
def get_form_kwargs(self):
    self.object = self.get_object()
    kwargs = super().get_form_kwargs()
    instance = kwargs["instance"]
    kwargs["instance"] = instance.opinions.filter(
        author__reviewer=self.request.user
    ).first()
    return kwargs

test_func

test_func()
Source code in hypha/apply/review/views.py
def test_func(self):
    review = self.get_object()
    user = self.request.user
    author = review.author.reviewer
    submission = review.submission

    if user.is_apply_staff:
        return True

    if user == author:
        return False

    if user.is_reviewer and review.reviewer_visibility:
        return True

    if (
        user.is_community_reviewer
        and submission.community_review
        and review.reviewer_visibility
        and submission.user != user
    ):
        return True

    return False

form_valid

form_valid(form)
Source code in hypha/apply/review/views.py
def form_valid(self, form):
    self.review = self.get_object()
    author, _ = AssignedReviewers.objects.get_or_create_for_user(
        submission=self.review.submission,
        reviewer=self.request.user,
    )
    form.instance.author = author
    form.instance.review = self.review
    response = super().form_valid(form)
    opinion = form.instance

    messenger(
        MESSAGES.REVIEW_OPINION,
        request=self.request,
        user=self.request.user,
        source=self.review.submission,
        related=opinion,
    )

    if opinion.opinion == DISAGREE:
        return HttpResponseRedirect(
            reverse_lazy(
                "apply:submissions:reviews:form", args=(self.review.submission.pk,)
            )
        )
    else:
        return response

get_success_url

get_success_url()
Source code in hypha/apply/review/views.py
def get_success_url(self):
    return self.review.get_absolute_url()

ReviewDetailView

Bases: DetailView

get

get(request, *args, **kwargs)
Source code in hypha/apply/review/views.py
def get(self, request, *args, **kwargs):
    view = ReviewDisplay.as_view()
    return view(request, *args, **kwargs)

post

post(request, *args, **kwargs)
Source code in hypha/apply/review/views.py
def post(self, request, *args, **kwargs):
    view = ReviewOpinionFormView.as_view()
    return view(request, *args, **kwargs)

ReviewListView

Bases: ListView

model class-attribute instance-attribute

model = Review

get_queryset

get_queryset()
Source code in hypha/apply/review/views.py
def get_queryset(self):
    self.submission = get_object_or_404(
        ApplicationSubmission, id=self.kwargs["submission_pk"]
    )
    self.queryset = self.model.objects.filter(
        submission=self.submission, is_draft=False
    )
    return super().get_queryset()

should_display

should_display(field)
Source code in hypha/apply/review/views.py
def should_display(self, field):
    return not isinstance(
        field.block,
        (RecommendationBlock, RecommendationCommentsBlock, RichTextBlock),
    )

get_context_data

get_context_data(**kwargs)
Source code in hypha/apply/review/views.py
def get_context_data(self, **kwargs):
    review_data = {}

    # Add the header rows
    review_data["title"] = {"question": "", "answers": []}
    review_data["opinions"] = {"question": "Opinions", "answers": []}
    review_data["score"] = {"question": "Overall Score", "answers": []}
    review_data["recommendation"] = {"question": "Recommendation", "answers": []}
    review_data["revision"] = {"question": "Revision", "answers": []}
    review_data["comments"] = {"question": "Comments", "answers": []}

    responses = self.object_list.count()
    ordered_reviewers = (
        AssignedReviewers.objects.filter(submission=self.submission)
        .reviewed()
        .review_order()
    )

    reviews = {review.author: review for review in self.object_list}
    for i, reviewer in enumerate(ordered_reviewers):
        review = reviews[reviewer]
        author = '<a href="{}"><span>{}</span></a>'.format(
            review.get_absolute_url(), review.author
        )
        if review.author.role and review.author.role.icon:
            author += generate_image_tag(review.author.role.icon, "12x12")
        author = f"<div>{author}</div>"

        review_data["title"]["answers"].append(author)
        opinions_template = get_template(
            "review/includes/review_opinions_list.html"
        )
        opinions_html = opinions_template.render(
            {"opinions": review.opinions.select_related("author").all()}
        )
        review_data["opinions"]["answers"].append(opinions_html)
        review_data["score"]["answers"].append(review.get_score_display)
        review_data["recommendation"]["answers"].append(
            review.get_recommendation_display()
        )
        review_data["comments"]["answers"].append(
            review.get_comments_display(include_question=False)
        )
        if review.for_latest:
            revision = "Current"
        else:
            revision = '<a href="{}">Compare</a>'.format(review.get_compare_url())
        review_data["revision"]["answers"].append(revision)

        for field_id in review.fields:
            field = review.field(field_id)
            data = review.data(field_id)
            if self.should_display(field):
                question = field.value["field_label"]
                review_data.setdefault(
                    field.id, {"question": question, "answers": [""] * responses}
                )
                review_data[field.id]["answers"][i] = field.block.render(
                    None, {"data": data}
                )

    return super().get_context_data(
        submission=self.submission, review_data=review_data, **kwargs
    )

ReviewDeleteView

Bases: UserPassesTestMixin, DeleteView

model class-attribute instance-attribute

model = Review

raise_exception class-attribute instance-attribute

raise_exception = True

test_func

test_func()
Source code in hypha/apply/review/views.py
def test_func(self):
    review = self.get_object()
    return (
        self.request.user.has_perm("review.delete_review")
        or self.request.user == review.author.reviewer
    )

form_valid

form_valid(form)
Source code in hypha/apply/review/views.py
def form_valid(self, form):
    review = self.get_object()
    messenger(
        MESSAGES.DELETE_REVIEW,
        user=self.request.user,
        request=self.request,
        source=review.submission,
        related=review,
    )
    return super().form_valid(form)

get_success_url

get_success_url()
Source code in hypha/apply/review/views.py
def get_success_url(self):
    review = self.get_object()
    return reverse_lazy("funds:submissions:detail", args=(review.submission.id,))

ReviewOpinionDeleteView

Bases: DeleteView

model class-attribute instance-attribute

model = ReviewOpinion

raise_exception class-attribute instance-attribute

raise_exception = True

dispatch

dispatch(request, *args, **kwargs)
Source code in hypha/apply/review/views.py
def dispatch(self, request, *args, **kwargs):
    self.review_opinion = self.get_object()
    if self.request.user != self.review_opinion.author.reviewer:
        raise PermissionDenied
    return super().dispatch(request, *args, **kwargs)

delete

delete(request, *args, **kwargs)
Source code in hypha/apply/review/views.py
def delete(self, request, *args, **kwargs):
    messenger(
        MESSAGES.DELETE_REVIEW_OPINION,
        user=request.user,
        request=request,
        source=self.review_opinion.review.submission,
        related=self.review_opinion,
    )
    response = super().delete(request, *args, **kwargs)
    return response

get_success_url

get_success_url()
Source code in hypha/apply/review/views.py
def get_success_url(self):
    review = self.review_opinion.review
    return reverse_lazy("funds:submissions:detail", args=(review.submission.id,))

get_fields_for_stage

get_fields_for_stage(submission, user=None)
Source code in hypha/apply/review/views.py
def get_fields_for_stage(submission, user=None):
    forms = submission.get_from_parent("review_forms").all()
    external_review_forms = submission.get_from_parent("external_review_forms").all()

    # Use ExternalReviewForm if submission's stage has external review and external review form is attached to fund.
    # ExternalReviewForm is only for non-staff reviewers(external reviewers)
    if submission.stage.has_external_review and external_review_forms:
        if user and not user.is_apply_staff:
            forms = external_review_forms

    index = submission.workflow.stages.index(submission.stage)
    try:
        return forms[index].form.form_fields
    except IndexError:
        return forms[0].form.form_fields

review_workflow_actions

review_workflow_actions(request, submission)
Source code in hypha/apply/review/views.py
def review_workflow_actions(request, submission):
    submission_stepped_phases = submission.workflow.stepped_phases
    transition_after = settings.TRANSITION_AFTER_REVIEWS
    action = None
    if transition_after and submission.status == INITIAL_STATE:
        # Automatically transition the application to "Internal review".
        action = submission_stepped_phases[2][0].name
    elif transition_after and submission.status == "proposal_discussion":
        # Automatically transition the proposal to "Internal review".
        action = "proposal_internal_review"
    elif (
        transition_after
        and submission.status == submission_stepped_phases[2][0].name
        and submission.reviews.count() >= transition_after
    ):
        # Automatically transition the application to "Ready for discussion".
        action = submission_stepped_phases[3][0].name
    elif (
        transition_after
        and submission.status == "ext_external_review"
        and submission.reviews.by_reviewers().count() >= transition_after
    ):
        # Automatically transition the application to "Ready for discussion".
        action = "ext_post_external_review_discussion"
    elif (
        transition_after
        and submission.status == "com_external_review"
        and submission.reviews.by_reviewers().count() >= transition_after
    ):
        # Automatically transition the application to "Ready for discussion".
        action = "com_post_external_review_discussion"
    elif (
        transition_after
        and submission.status == "external_review"
        and submission.reviews.by_reviewers().count() >= transition_after
    ):
        # Automatically transition the proposal to "Ready for discussion".
        action = "post_external_review_discussion"

    # If action is set run perform_transition().
    if action:
        try:
            submission.perform_transition(
                action,
                request.user,
                request=request,
                notify=False,
            )
        except (PermissionDenied, KeyError):
            pass