Newer
Older
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views.generic import UpdateView
from django_filters.views import FilterView
from django_tables2.views import SingleTableMixin
from opentech.apply.activity.views import (
AllActivityContextMixin,
ActivityContextMixin,
CommentFormView,
DelegatedViewMixin,
)
from opentech.apply.activity.models import Activity
from opentech.apply.users.decorators import staff_required
from opentech.apply.utils.views import DelegateableView, ViewDispatcher
from .blocks import MustIncludeFieldBlock
from .forms import ProgressSubmissionForm, UpdateSubmissionLeadForm
from .tables import AdminSubmissionsTable, SubmissionFilter, SubmissionFilterAndSearch
@method_decorator(staff_required, name='dispatch')
class SubmissionListView(AllActivityContextMixin, SingleTableMixin, FilterView):
template_name = 'funds/submissions.html'
table_class = AdminSubmissionsTable
filterset_class = SubmissionFilter
def get_queryset(self):
return self.filterset_class._meta.model.objects.current()
def get_context_data(self, **kwargs):
active_filters = self.filterset.data
return super().get_context_data(active_filters=active_filters, **kwargs)
@method_decorator(staff_required, name='dispatch')
class SubmissionSearchView(SingleTableMixin, FilterView):
template_name = 'funds/submissions_search.html'
table_class = AdminSubmissionsTable
filterset_class = SubmissionFilterAndSearch
def get_queryset(self):
return self.filterset_class._meta.model.objects.current()
def get_context_data(self, **kwargs):
search_term = self.request.GET.get('query')
# We have more data than just 'query'
active_filters = len(self.filterset.data) > 1
return super().get_context_data(
search_term=search_term,
active_filters=active_filters,
**kwargs,
)
@method_decorator(staff_required, name='dispatch')
class ProgressSubmissionView(DelegatedViewMixin, UpdateView):
model = ApplicationSubmission
form_class = ProgressSubmissionForm
context_name = 'progress_form'
def form_valid(self, form):
old_phase = form.instance.phase.name
response = super().form_valid(form)
new_phase = form.instance.phase.name
user=self.request.user,
submission=self.kwargs['submission'],
message=f'Progressed from {old_phase} to {new_phase}'
)
return response
@method_decorator(staff_required, name='dispatch')
class UpdateLeadView(DelegatedViewMixin, UpdateView):
model = ApplicationSubmission
form_class = UpdateSubmissionLeadForm
context_name = 'lead_form'
def form_valid(self, form):
# Fetch the old lead from the database
old_lead = self.get_object().lead
response = super().form_valid(form)
new_lead = form.instance.lead
Activity.actions.create(
user=self.request.user,
submission=self.kwargs['submission'],
message=f'Lead changed from {old_lead} to {new_lead}'
)
return response
class AdminSubmissionDetailView(ActivityContextMixin, DelegateableView):
template_name_suffix = '_admin_detail'
model = ApplicationSubmission
form_views = {
'progress': ProgressSubmissionView,
'comment': CommentFormView,
def get_context_data(self, **kwargs):
other_submissions = self.model.objects.filter(user=self.object.user).current().exclude(id=self.object.id)
if self.object.next:
other_submissions = other_submissions.exclude(id=self.object.next.id)
return super().get_context_data(
other_submissions=other_submissions,
class ApplicantSubmissionDetailView(ActivityContextMixin, DelegateableView):
model = ApplicationSubmission
form_views = {
'comment': CommentFormView,
}
def dispatch(self, request, *args, **kwargs):
if self.get_object().user != request.user:
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
class SubmissionDetailView(ViewDispatcher):
admin_view = AdminSubmissionDetailView
applicant_view = ApplicantSubmissionDetailView
@method_decorator(login_required, name='dispatch')
class SubmissionEditView(UpdateView):
"""
Converts the data held on the submission into an editable format and knows how to save
that back to the object. Shortcuts the normal update view save approach
"""
def dispatch(self, request, *args, **kwargs):
if request.user != self.get_object().user:
raise PermissionDenied
if not self.get_object().phase.has_perm(request.user, 'edit'):
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
instance = kwargs.pop('instance')
form_data = instance.form_data
for field in self.object.form_fields:
if isinstance(field.block, MustIncludeFieldBlock):
# convert certain data to the correct field id
try:
response = form_data[field.block.name]
except KeyError:
pass
else:
form_data[field.id] = response
kwargs['initial'] = form_data
return kwargs
def get_form_class(self):
return self.object.get_form_class()
def form_valid(self, form):
self.object.form_data = form.cleaned_data
self.object.save()
return HttpResponseRedirect(self.get_success_url())
workflows = [SingleStage, DoubleStage]
class BasicSubmissionForm(forms.Form):
who_are_you = forms.CharField()
def demo_workflow(request, wf_id):
logs = request.session.get('logs', list())
submission = request.session.get('submission', dict())
wf = int(wf_id)
workflow = workflow_class()
forms = [BasicSubmissionForm] * wf
current_phase = request.POST.get('current')
current = workflow.current(current_phase)
if current.stage.name not in submission:
form = forms[workflow.stages.index(current.stage)]
submitted_form = form(request.POST)
submission[current.stage.name] = submitted_form.cleaned_data
phase = current
logs.append(
f'{phase.stage}: Form was submitted'
)
form = None
else:
form = submitted_form
else:
phase = workflow.process(current_phase, request.POST['action'])
logs.append(
f'{current.stage}: {current.name} was updated to {phase.stage}: {phase.name}'
)
submission.clear()
if phase.stage.name not in submission:
form = forms[workflow.stages.index(phase.stage)]
request.session['logs'] = logs
request.session['submission'] = submission
context = {
'workflow': workflow,
'phase': phase,
'data': submission,
'form': form,
return TemplateResponse(request, 'funds/demo_workflow.html', context)