Skip to content

Views

hypha.apply.api.v1.determination.views

SubmissionDeterminationViewSet

Bases: BaseStreamForm, WagtailSerializer, SubmissionNestedMixin, GenericViewSet

submission_form_class class-attribute instance-attribute

submission_form_class = PageStreamBaseForm

wagtail_reference_index_ignore class-attribute instance-attribute

wagtail_reference_index_ignore = True

permission_classes class-attribute instance-attribute

permission_classes = (IsAuthenticated, IsApplyStaffUser)

permission_classes_by_action class-attribute instance-attribute

permission_classes_by_action = {'create': [IsAuthenticated, HasDeterminationCreatePermission, IsApplyStaffUser], 'draft': [IsAuthenticated, HasDeterminationDraftPermission, IsApplyStaffUser]}

serializer_class class-attribute instance-attribute

get_submission_object

get_submission_object()
Source code in hypha/apply/api/v1/mixin.py
def get_submission_object(self):
    return get_object_or_404(ApplicationSubmission, id=self.kwargs["submission_pk"])

get_serializer_fields

get_serializer_fields(draft=False)

Get the respective serializer fields for all the form fields.

Source code in hypha/apply/api/v1/stream_serializers.py
def get_serializer_fields(self, draft=False):
    """
    Get the respective serializer fields for all the form fields.
    """
    serializer_fields = OrderedDict()
    form_fields = self.get_form_fields()
    for field_id, field in form_fields.items():
        serializer_fields[field_id] = self._get_field(
            field, self.get_serializer_field_class(field), draft
        )
    return serializer_fields

find_function_args

find_function_args(func)

Get the list of parameter names which function accepts.

Source code in hypha/apply/api/v1/stream_serializers.py
def find_function_args(self, func):
    """
    Get the list of parameter names which function accepts.
    """
    try:
        spec = (
            inspect.getfullargspec(func)
            if hasattr(inspect, "getfullargspec")
            else inspect.getargspec(func)
        )
        return [i for i in spec[0] if i not in IGNORE_ARGS]
    except TypeError:
        return []

find_class_args

find_class_args(klass)

Find all class arguments (parameters) which can be passed in __init__.

Source code in hypha/apply/api/v1/stream_serializers.py
def find_class_args(self, klass):
    """
    Find all class arguments (parameters) which can be passed in ``__init__``.
    """
    args = set()
    for i in klass.mro():
        if i is object or not hasattr(i, "__init__"):
            continue
        args |= set(self.find_function_args(i.__init__))

    return list(args)

find_matching_class_kwargs

find_matching_class_kwargs(reference_object, klass)
Source code in hypha/apply/api/v1/stream_serializers.py
def find_matching_class_kwargs(self, reference_object, klass):
    return {
        i: getattr(reference_object, i)
        for i in self.find_class_args(klass)
        if hasattr(reference_object, i)
    }

get_serializer_field_class

get_serializer_field_class(field)

Assumes that a serializer field exist with the same name as form field.

TODO: In case there are form fields not existing in serializer fields, we would have to create mapping b/w form fields and serializer fields to get the respective classes. But for now this works.

Source code in hypha/apply/api/v1/stream_serializers.py
def get_serializer_field_class(self, field):
    """
    Assumes that a serializer field exist with the same name as form field.

    TODO:
    In case there are form fields not existing in serializer fields, we would
    have to create mapping b/w form fields and serializer fields to get the
    respective classes. But for now this works.
    """
    if isinstance(field, BlockFieldWrapper):
        return serializers.CharField
    if isinstance(field, ScoredAnswerField):
        return ScoredAnswerListField
    if isinstance(field, TypedChoiceField):
        return serializers.ChoiceField
    class_name = field.__class__.__name__
    return getattr(serializers, class_name)

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_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_permissions

get_permissions()
Source code in hypha/apply/api/v1/determination/views.py
def get_permissions(self):
    try:
        # return permission_classes depending on `action`
        return [
            permission()
            for permission in self.permission_classes_by_action[self.action]
        ]
    except KeyError:
        # action is not set return default permission_classes
        return [permission() for permission in self.permission_classes]

get_defined_fields

get_defined_fields()

Get form fields created for determining this submission.

These form fields will be used to get respective serializer fields.

Source code in hypha/apply/api/v1/determination/views.py
def get_defined_fields(self):
    """
    Get form fields created for determining this submission.

    These form fields will be used to get respective serializer fields.
    """
    if self.action in ["retrieve", "update"]:
        # For detail and edit api form fields used while submitting
        # determination should be used.
        determination = self.get_object()
        return determination.form_fields
    submission = self.get_submission_object()
    return get_fields_for_stage(submission)

get_serializer_class

get_serializer_class()

Override get_serializer_class to send draft parameter if the request is to save as draft or the determination submitted is saved as draft.

Source code in hypha/apply/api/v1/determination/views.py
def get_serializer_class(self):
    """
    Override get_serializer_class to send draft parameter
    if the request is to save as draft or the determination submitted
    is saved as draft.
    """
    if self.action == "retrieve":
        determination = self.get_object()
        draft = determination.is_draft
    elif self.action == "draft":
        draft = True
    else:
        draft = self.request.data.get("is_draft", False)
    return super().get_serializer_class(draft)

get_queryset

get_queryset()
Source code in hypha/apply/api/v1/determination/views.py
def get_queryset(self):
    submission = self.get_submission_object()
    return Determination.objects.filter(submission=submission, is_draft=False)

get_object

get_object()

Get the determination object by id. If not found raise 404.

Source code in hypha/apply/api/v1/determination/views.py
def get_object(self):
    """
    Get the determination object by id. If not found raise 404.
    """
    queryset = self.get_queryset()
    obj = get_object_or_404(queryset, id=self.kwargs["pk"])
    self.check_object_permissions(self.request, obj)
    return obj

get_determination_data

get_determination_data(determination)

Get determination data which will be used for determination detail api.

Source code in hypha/apply/api/v1/determination/views.py
def get_determination_data(self, determination):
    """
    Get determination data which will be used for determination detail api.
    """
    determination_data = determination.form_data
    field_blocks = determination.form_fields
    for field_block in field_blocks:
        if isinstance(field_block.block, DeterminationBlock):
            determination_data[field_block.id] = determination.outcome
        if isinstance(field_block.block, RichTextBlock):
            determination_data[field_block.id] = field_block.value.source
    determination_data["id"] = determination.id
    determination_data["is_draft"] = determination.is_draft
    return determination_data

retrieve

retrieve(request, *args, **kwargs)

Get details of a determination on a submission

Source code in hypha/apply/api/v1/determination/views.py
def retrieve(self, request, *args, **kwargs):
    """
    Get details of a determination on a submission
    """
    determination = self.get_object()
    ser = self.get_serializer(self.get_determination_data(determination))
    return Response(ser.data)

get_form_fields

get_form_fields()
Source code in hypha/apply/api/v1/determination/views.py
def get_form_fields(self):
    form_fields = super(SubmissionDeterminationViewSet, self).get_form_fields()
    submission = self.get_submission_object()
    field_blocks = self.get_defined_fields()
    for field_block in field_blocks:
        if isinstance(field_block.block, DeterminationBlock):
            outcome_choices = outcome_choices_for_phase(
                submission, self.request.user
            )
            if self.action == "update":
                # Outcome can not be edited after being set once, so we do not
                # need to render this field.
                # form_fields.pop(field_block.id)
                form_fields[field_block.id].widget = forms.TextInput(
                    attrs={"readonly": "readonly"}
                )
            else:
                # Outcome field choices need to be set according to the phase.
                form_fields[field_block.id].choices = outcome_choices
    return form_fields

fields

fields(request, *args, **kwargs)

List details of all the form fields that were created by admin for adding determinations.

These field details will be used in frontend to render the determination form.

Source code in hypha/apply/api/v1/determination/views.py
@action(detail=False, methods=["get"])
def fields(self, request, *args, **kwargs):
    """
    List details of all the form fields that were created by admin for adding determinations.

    These field details will be used in frontend to render the determination form.
    """
    form_fields = self.get_form_fields()
    fields = FieldSerializer(form_fields.items(), many=True)
    return Response(fields.data)

get_draft_determination

get_draft_determination()
Source code in hypha/apply/api/v1/determination/views.py
def get_draft_determination(self):
    submission = self.get_submission_object()
    try:
        determination = Determination.objects.get(
            submission=submission, is_draft=True
        )
    except Determination.DoesNotExist:
        return
    else:
        return determination

draft

draft(request, *args, **kwargs)

Returns the draft determination submitted on a submission by current user.

Source code in hypha/apply/api/v1/determination/views.py
@action(detail=False, methods=["get"])
def draft(self, request, *args, **kwargs):
    """
    Returns the draft determination submitted on a submission by current user.
    """
    determination = self.get_draft_determination()
    if not determination:
        return Response({})
    ser = self.get_serializer(self.get_determination_data(determination))
    return Response(ser.data)

create

create(request, *args, **kwargs)

Create a determination on a submission.

Accept a post data in form of {field_id: value}. field_id is same id which you get from the /fields api. value should be submitted with html tags, so that response can be displayed with correct formatting, e.g. in case of rich text field, we need to show the data with same formatting user has submitted.

Accepts optional parameter is_draft when a determination is to be saved as draft.

Raise ValidationError if a determination is already submitted by the user.

Source code in hypha/apply/api/v1/determination/views.py
def create(self, request, *args, **kwargs):
    """
    Create a determination on a submission.

    Accept a post data in form of `{field_id: value}`.
    `field_id` is same id which you get from the `/fields` api.
    `value` should be submitted with html tags, so that response can
    be displayed with correct formatting, e.g. in case of rich text field,
    we need to show the data with same formatting user has submitted.

    Accepts optional parameter `is_draft` when a determination is to be saved as draft.

    Raise ValidationError if a determination is already submitted by the user.
    """
    submission = self.get_submission_object()
    ser = self.get_serializer(data=request.data)
    ser.is_valid(raise_exception=True)
    if has_final_determination(submission):
        return ValidationError(
            {"detail": "A final determination has already been submitted."}
        )
    determination = self.get_draft_determination()
    if determination is None:
        determination = Determination.objects.create(
            submission=submission, author=request.user
        )
    determination.form_fields = self.get_defined_fields()
    determination.save()
    ser.update(determination, ser.validated_data)
    if determination.is_draft:
        ser = self.get_serializer(self.get_determination_data(determination))
        return Response(ser.data, status=status.HTTP_201_CREATED)
    with transaction.atomic():
        messenger(
            MESSAGES.DETERMINATION_OUTCOME,
            request=self.request,
            user=determination.author,
            submission=submission,
            related=determination,
        )
        proposal_form = ser.validated_data.get("proposal_form")
        transition = transition_from_outcome(int(determination.outcome), submission)

        if determination.outcome == NEEDS_MORE_INFO:
            # We keep a record of the message sent to the user in the comment
            Activity.comments.create(
                message=determination.stripped_message,
                timestamp=timezone.now(),
                user=self.request.user,
                source=submission,
                related_object=determination,
            )
        submission.perform_transition(
            transition,
            self.request.user,
            request=self.request,
            notify=False,
            proposal_form=proposal_form,
        )

        if submission.accepted_for_funding and settings.PROJECTS_AUTO_CREATE:
            Project.create_from_submission(submission)

    messenger(
        MESSAGES.DETERMINATION_OUTCOME,
        request=self.request,
        user=determination.author,
        source=submission,
        related=determination,
    )
    ser = self.get_serializer(self.get_determination_data(determination))
    return Response(ser.data, status=status.HTTP_201_CREATED)

update

update(request, *args, **kwargs)

Update a determination submitted on a submission.

Source code in hypha/apply/api/v1/determination/views.py
def update(self, request, *args, **kwargs):
    """
    Update a determination submitted on a submission.
    """
    determination = self.get_object()
    ser = self.get_serializer(data=request.data)
    ser.is_valid(raise_exception=True)
    ser.update(determination, ser.validated_data)

    messenger(
        MESSAGES.DETERMINATION_OUTCOME,
        request=self.request,
        user=determination.author,
        source=determination.submission,
        related=determination,
    )
    ser = self.get_serializer(self.get_determination_data(determination))
    return Response(ser.data)