diff --git a/opentech/apply/dashboard/templates/dashboard/applicant_dashboard.html b/opentech/apply/dashboard/templates/dashboard/applicant_dashboard.html index 70d5e07fc88b28d3e4aa03ea927ad20b64c1aa4d..aff8d288c9311678d68add784caf61f51bcf1bf4 100644 --- a/opentech/apply/dashboard/templates/dashboard/applicant_dashboard.html +++ b/opentech/apply/dashboard/templates/dashboard/applicant_dashboard.html @@ -25,6 +25,8 @@ <a href="{% url 'funds:submission' submission.id %}">{{ submission.title }}</a> {% include "funds/includes/status_bar.html" with workflow=submission.workflow status=submission.status %} </div> + {% empty %} + No active submissions {% endfor %} </div> <div class="wrapper wrapper--large wrapper--inner-space-medium"> diff --git a/opentech/apply/dashboard/views.py b/opentech/apply/dashboard/views.py index f77a5ab61c073a9987cc00278cde62706cea0fe1..a00bb37c1bb4e8b27360bdd9a2f491c3ae92246e 100644 --- a/opentech/apply/dashboard/views.py +++ b/opentech/apply/dashboard/views.py @@ -19,7 +19,7 @@ class ApplicantDashboardView(SingleTableView): return self.model.objects.filter(user=self.request.user) def get_context_data(self, **kwargs): - my_active_submissions = self.object_list + my_active_submissions = self.object_list.active() return super().get_context_data( my_active_submissions=my_active_submissions, diff --git a/opentech/apply/funds/models.py b/opentech/apply/funds/models.py index c36510831779e8db5128b3da927b7a8b58fbf82e..975199d7d7d0bbbc5b417900e97e6cdfcb990ffb 100644 --- a/opentech/apply/funds/models.py +++ b/opentech/apply/funds/models.py @@ -39,7 +39,8 @@ from opentech.apply.users.groups import STAFF_GROUP_NAME from .blocks import CustomFormFieldsBlock, MustIncludeFieldBlock, REQUIRED_BLOCK_NAMES from .edit_handlers import FilteredFieldPanel, ReadOnlyPanel, ReadOnlyInlinePanel from .admin_forms import WorkflowFormAdminForm -from .workflow import SingleStage, DoubleStage +from .forms import WorkflowFormAdminForm +from .workflow import SingleStage, DoubleStage, active_statuses WORKFLOW_CLASS = { @@ -417,6 +418,8 @@ class LabForm(AbstractRelatedForm): class JSONOrderable(models.QuerySet): + json_field = None + def order_by(self, *field_names): def build_json_order_by(field): if field.replace('-', '') not in REQUIRED_BLOCK_NAMES: @@ -427,12 +430,19 @@ class JSONOrderable(models.QuerySet): field = field[1:] else: descending = False - return OrderBy(RawSQL("LOWER(form_data->>%s)", (field,)), descending=descending) + return OrderBy(RawSQL(f'LOWER({self.json_field}->>%s)', (field,)), descending=descending) field_ordering = [build_json_order_by(field) for field in field_names] return super().order_by(*field_ordering) +class ApplicationSubmissionQueryset(JSONOrderable): + json_field = 'form_data' + + def active(self): + return self.filter(status__in=active_statuses) + + class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): field_template = 'funds/includes/submission_field.html' @@ -447,7 +457,7 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): # Workflow inherited from WorkflowHelpers status = models.CharField(max_length=254) - objects = JSONOrderable.as_manager() + objects = ApplicationSubmissionQueryset.as_manager() @property def status_name(self): @@ -461,6 +471,10 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission): def phase(self): return self.workflow.current(self.status) + @property + def active(self): + return self.status in active_statuses + def ensure_user_has_account(self): if self.user and self.user.is_authenticated(): self.form_data['email'] = self.user.email diff --git a/opentech/apply/funds/tables.py b/opentech/apply/funds/tables.py index abe2f37c08f4407421c2c67001da1c8f8132b903..486902e8e0eb3db21aee24504b295365b0d946c4 100644 --- a/opentech/apply/funds/tables.py +++ b/opentech/apply/funds/tables.py @@ -30,8 +30,9 @@ class SubmissionsTable(tables.Table): def render_user(self, value): return value.get_full_name() - def render_status_name(self, value): - return mark_safe(f'<span>{ value }</span>') + def render_status_name(self, value, record): + state = 'class="not-active"' if not record.active else '' + return mark_safe(f'<span { state }>{ value }</span>') def get_used_rounds(request): diff --git a/opentech/apply/funds/workflow.py b/opentech/apply/funds/workflow.py index 1f621ec609ed66a582b416f3ec84f94fcc3b7e8d..c275f57d593ad9b9e031b15199c3f96ad381ee7f 100644 --- a/opentech/apply/funds/workflow.py +++ b/opentech/apply/funds/workflow.py @@ -1,5 +1,6 @@ from collections import defaultdict import copy +import itertools from typing import Dict, Iterable, Iterator, List, Sequence, Type, Union @@ -226,10 +227,12 @@ class Phase: name: str = '' public_name: str = '' - def __init__(self, name: str='', public_name: str ='') -> None: + def __init__(self, name: str='', public_name: str ='', active: bool=True) -> None: if name: self.name = name + self.active = active + if public_name: self.public_name = public_name elif not self.public_name: @@ -329,9 +332,9 @@ class DiscussionWithNextPhase(Phase): actions = [NextPhaseAction('Open Review'), reject_action] -rejected = Phase(name='Rejected') +rejected = Phase(name='Rejected', active=False) -accepted = Phase(name='Accepted') +accepted = Phase(name='Accepted', active=False) class RequestStage(Stage): @@ -377,3 +380,7 @@ class DoubleStage(Workflow): statuses = set(phase.name for phase in Phase.__subclasses__()) status_options = [(slugify(opt), opt) for opt in statuses] + +active_statuses = set( + str(phase) for phase in itertools.chain(SingleStage([None]), DoubleStage([None, None])) if phase.active +)