diff --git a/opentech/apply/determinations/templates/determinations/determination_detail.html b/opentech/apply/determinations/templates/determinations/determination_detail.html new file mode 100644 index 0000000000000000000000000000000000000000..02737f68c84ce039866db200d6f84a41ea52a34b --- /dev/null +++ b/opentech/apply/determinations/templates/determinations/determination_detail.html @@ -0,0 +1,25 @@ +{% extends "base-apply.html" %} +{% load bleach_tags %} + +{% block content %} +<div class="wrapper wrapper--breakout wrapper--admin"> + <div class="wrapper wrapper--large"> + <h2 class="heading heading--no-margin">Determination</h2> + <h5>For <a href="{% url "funds:submission" determination.submission.id %}">{{ determination.submission.title }}</a></h5> + </div> +</div> + +<div class="grid"> + <div> + <h5>Determination</h5> + <p>{{ determination.determination }}</p> + </div> +</div> + +<div class="rich-text rich-text--answers"> + {% for question, answer in determination_data.items %} + <h5>{{ question }}</h5> + {{ answer|bleach }} + {% endfor %} +</div> +{% endblock %} diff --git a/opentech/apply/determinations/templates/determinations/determination_form.html b/opentech/apply/determinations/templates/determinations/determination_form.html new file mode 100644 index 0000000000000000000000000000000000000000..172e6fc9582b39c991519b9ed27b955045271886 --- /dev/null +++ b/opentech/apply/determinations/templates/determinations/determination_form.html @@ -0,0 +1,41 @@ +{% extends "base-apply.html" %} +{% block title %}Create a determination{% endblock %} +{% block content %} +<div class="wrapper wrapper--breakout wrapper--admin"> + <div class="wrapper wrapper--medium"> + <h2 class="heading heading--no-margin">{{ title|default:"Create Determination" }}</h2> + <h5>For <a href="{% url "funds:submission" submission.id %}">{{ submission.title }}</a></h5> + </div> +</div> + +<div class="wrapper wrapper--medium wrapper--inner-space-medium"> +{% if not has_submitted_determination %} + <form class="form form--with-p-tags" action="" method="post" novalidate> + {{ form.media }} + {% csrf_token %} + {% for field in form %} + {# to be replaced with better logic when we use stream form #} + {% ifchanged field.field.group %} + {% for key, value in form.titles.items %} + {% if key == field.field.group %} + <h2>{{ value }}</h2> + {% endif %} + {% endfor %} + {% endifchanged %} + + {% if field.field %} + {% include "funds/includes/field.html" %} + {% else %} + {{ field }} + {% endif %} + {% endfor %} + <input class="button button--primary" type="submit" value="Send Determination" name="submit" /> + {% if not object.id or object.is_draft %} + <input class="button button--secondary button--white" type="submit" value="Save Draft" name="{{ form.draft_button_name }}" /> + {% endif %} + </form> +{% else %} + <p>You have already added a determination for this submission</p> +{% endif %} +</div> +{% endblock %} diff --git a/opentech/apply/determinations/templates/determinations/includes/determination_button.html b/opentech/apply/determinations/templates/determinations/includes/determination_button.html new file mode 100644 index 0000000000000000000000000000000000000000..f0bd1512925229872d5379034eff6bb06c829a74 --- /dev/null +++ b/opentech/apply/determinations/templates/determinations/includes/determination_button.html @@ -0,0 +1,12 @@ +{% load determination_tags workflow_tags %} +{% if request.user.is_apply_staff %} + {% if request.user|has_draft:submission or request.user|can_add_determination:submission %} + <a href="{% url 'apply:determinations:form' submission_pk=submission.id %}" class="button button--primary button--half-width"> + {% if request.user|has_draft:submission %} + Update determination draft + {% elif request.user|can_add_determination:submission %} + Add determination + {% endif %} + </a> + {% endif %} +{% endif %} diff --git a/opentech/apply/determinations/templatetags/__init__.py b/opentech/apply/determinations/templatetags/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/opentech/apply/determinations/templatetags/determination_tags.py b/opentech/apply/determinations/templatetags/determination_tags.py new file mode 100644 index 0000000000000000000000000000000000000000..f65cd2403f7ebae2abca25780c2112ccbff1ba9e --- /dev/null +++ b/opentech/apply/determinations/templatetags/determination_tags.py @@ -0,0 +1,21 @@ +from django import template +from django.core.exceptions import ObjectDoesNotExist + +register = template.Library() + + +@register.filter +def can_add_determination(user, submission): + try: + has_determination = submission.determination + except ObjectDoesNotExist: + has_determination = False + return submission.has_permission_to_add_determination(user) and not has_determination + + +@register.filter +def has_draft(user, submission): + try: + return submission.has_permission_to_add_determination(user) and submission.determination.is_draft + except ObjectDoesNotExist: + return False diff --git a/opentech/apply/determinations/urls.py b/opentech/apply/determinations/urls.py index 7e11903e56dcc093c948b45b0ac2a3a74cdad6f9..0cb98c4eb90de681848601a82a2584ee5e75456b 100644 --- a/opentech/apply/determinations/urls.py +++ b/opentech/apply/determinations/urls.py @@ -6,4 +6,5 @@ app_name = 'determinations' urlpatterns = [ path('determination/', DeterminationCreateOrUpdateView.as_view(), name="form"), + path('determination/<int:pk>', DeterminationDetailView.as_view(), name="determination"), ] diff --git a/opentech/apply/determinations/views.py b/opentech/apply/determinations/views.py new file mode 100644 index 0000000000000000000000000000000000000000..11e2f4278c4db513a6e5ea993fd1411d3acdd801 --- /dev/null +++ b/opentech/apply/determinations/views.py @@ -0,0 +1,138 @@ +from django.core.exceptions import PermissionDenied, ObjectDoesNotExist +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.urls import reverse_lazy +from django.utils.decorators import method_decorator +from django.views.generic import DetailView +from django.views.generic.detail import SingleObjectTemplateResponseMixin +from django.views.generic.edit import ProcessFormView, ModelFormMixin + +from opentech.apply.funds.models import ApplicationSubmission +from opentech.apply.users.decorators import staff_required + +from .forms import ConceptDeterminationForm, ProposalDeterminationForm +from .models import Determination + + +def get_form_for_stage(submission): + forms = [ConceptDeterminationForm, ProposalDeterminationForm] + index = [ + i for i, stage in enumerate(submission.workflow.stages) + if submission.stage.name == stage.name + ][0] + return forms[index] + + +class CreateOrUpdateView(SingleObjectTemplateResponseMixin, ModelFormMixin, ProcessFormView): + + 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) + + 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) + + +class DeterminationCreateOrUpdateView(CreateOrUpdateView): + model = Determination + template_name = 'determinations/determination_form.html' + + def get_object(self, queryset=None): + return self.model.objects.get(submission=self.submission, author=self.request.user) + + def dispatch(self, request, *args, **kwargs): + self.submission = get_object_or_404(ApplicationSubmission, id=self.kwargs['submission_pk']) + + # TODO add proper permission + # if not self.submission.phase.has_perm(request.user, 'add_determination') or \ + if not self.submission.has_permission_to_add_determination(request.user): + raise PermissionDenied() + + if self.request.POST: + return self.get(request, *args, **kwargs) + + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + try: + has_submitted_determination = not self.submission.determination.is_draft + except ObjectDoesNotExist: + has_submitted_determination = False + + return super().get_context_data( + submission=self.submission, + has_submitted_determination=has_submitted_determination, + title="Update Determination draft" if self.object else 'Add Determination', + **kwargs + ) + + def get_form_class(self): + return get_form_for_stage(self.submission) + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs['request'] = self.request + kwargs['submission'] = self.submission + + if self.object: + kwargs['initial'] = self.object.determination_data + kwargs['initial']['determination'] = self.object.determination + + return kwargs + + def get_success_url(self): + return self.submission.get_absolute_url() + + +@method_decorator(staff_required, name='dispatch') +class DeterminationDetailView(DetailView): + model = Determination + + def dispatch(self, request, *args, **kwargs): + determination = self.get_object() + + if request.user != determination.submission.lead and not request.user.is_superuser: + raise PermissionDenied + + if determination.is_draft: + return HttpResponseRedirect(reverse_lazy('apply:determinations:form', args=(determination.submission.id,))) + + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + determination = self.get_object().determination + form_used = get_form_for_stage(self.get_object().submission) + determination_data = {} + + for name, field in form_used.base_fields.items(): + try: + # Add titles which exist + title = form_used.titles[field.group] + determination_data.setdefault(title, []) + except AttributeError: + pass + + value = determination[name] + try: + choices = dict(field.choices) + except AttributeError: + pass + else: + # Update the stored value to the display value + value = choices[int(value)] + + determination_data.setdefault(field.label, str(value)) + + return super().get_context_data( + determination_data=determination_data, + **kwargs + ) diff --git a/opentech/apply/funds/templates/funds/applicationsubmission_admin_detail.html b/opentech/apply/funds/templates/funds/applicationsubmission_admin_detail.html index fc0040d5357688221a47691328793be9f0317555..e9cabb5f6674d6b3edb9a19aa50893bae707f1f8 100644 --- a/opentech/apply/funds/templates/funds/applicationsubmission_admin_detail.html +++ b/opentech/apply/funds/templates/funds/applicationsubmission_admin_detail.html @@ -12,6 +12,16 @@ {% include "funds/includes/update_reviewer_form.html" %} {% endblock %} +{% block determination %} + <div class="sidebar__inner"> + <h5>Determination</h5> + {% if object.determination %} + {{ object.determination.determination }} | {{ object.determination.author }} + {% endif %} + {% include 'determinations/includes/determination_button.html' with submission=object %} + </div> +{% endblock %} + {% block reviews %} <div class="sidebar__inner"> <h5>Reviews & assignees</h5> diff --git a/opentech/apply/funds/templates/funds/applicationsubmission_detail.html b/opentech/apply/funds/templates/funds/applicationsubmission_detail.html index d121c37ba6c4101ee0be692016c36a99f740b851..3038b522eed26efa518405fa69caaff51103ce82 100644 --- a/opentech/apply/funds/templates/funds/applicationsubmission_detail.html +++ b/opentech/apply/funds/templates/funds/applicationsubmission_detail.html @@ -88,6 +88,9 @@ {% endblock %} {% endif %} + {% block determination %} + {% endblock %} + {% block reviews %} {% endblock %} diff --git a/opentech/apply/funds/templatetags/workflow_tags.py b/opentech/apply/funds/templatetags/workflow_tags.py index b2923a6dad371fa6ddcab1cb297837e65fdc2e6c..928d47dd1a214226596f2dc0e2b0469d9c69c030 100644 --- a/opentech/apply/funds/templatetags/workflow_tags.py +++ b/opentech/apply/funds/templatetags/workflow_tags.py @@ -16,3 +16,8 @@ def has_edit_perm(user, submission): @register.filter def has_review_perm(user, submission): return check_permission(user, 'review', submission) + + +@register.filter +def has_determination_perm(user, submission): + return check_permission(user, 'create_determination', submission)