From a5323baf009929778386d1d960026fe2ff8e56af Mon Sep 17 00:00:00 2001 From: Fredrik Jonsson <frjo@xdeb.org> Date: Mon, 8 Apr 2019 10:20:52 +0200 Subject: [PATCH] Add seperate dashboard and submissiondetail views for partner and community reviewer roles. --- .../dashboard/community_dashboard.html | 57 ++++++++++++++ .../dashboard/partner_dashboard.html | 57 ++++++++++++++ opentech/apply/dashboard/views.py | 55 +++++++++++++- opentech/apply/determinations/views.py | 4 +- ...applicationsubmission_reviewer_detail.html | 4 - opentech/apply/funds/views.py | 76 ++++++++++++++----- opentech/apply/utils/views.py | 14 +++- 7 files changed, 238 insertions(+), 29 deletions(-) create mode 100644 opentech/apply/dashboard/templates/dashboard/community_dashboard.html create mode 100644 opentech/apply/dashboard/templates/dashboard/partner_dashboard.html diff --git a/opentech/apply/dashboard/templates/dashboard/community_dashboard.html b/opentech/apply/dashboard/templates/dashboard/community_dashboard.html new file mode 100644 index 000000000..122386a8b --- /dev/null +++ b/opentech/apply/dashboard/templates/dashboard/community_dashboard.html @@ -0,0 +1,57 @@ +{% extends "base-apply.html" %} +{% load render_table from django_tables2 %} +{% load static wagtailcore_tags workflow_tags statusbar_tags %} + +{% block title %}Submission Dashboard{% endblock %} + +{% block content %} +<div class="admin-bar"> + <div class="admin-bar__inner wrapper--applicant-dashboard"> + <div> + <h3 class="heading heading--no-margin">Dashboard</h3> + <h5>An overview of active and past submissions</h5> + </div> + <div class="wrapper wrapper--cta-box"> + <h4 class="heading heading--no-margin">Submit a new application</h4> + <h5 class="heading heading--normal">Apply now for our open rounds</h5> + <a class="button button--primary" href="{% pageurl APPLY_SITE.root_page %}" class="button">Apply</a> + </div> + </div> +</div> +<div class="wrapper wrapper--large wrapper--inner-space-medium"> + <h3>Your active submissions</h3> + {% for submission in my_active_submissions %} + <div class="wrapper wrapper--status-bar-outer"> + <div class="wrapper wrapper--status-bar-inner"> + <div> + <h5 class="heading heading--no-margin"><a class="link link--underlined" href="{% url 'funds:submissions:detail' submission.id %}">{{ submission.title }}</a></h5> + <h6 class="heading heading--no-margin heading--submission-meta"><span>Submitted:</span> {{ submission.submit_time.date }} by {{ submission.user.get_full_name }}</h6> + </div> + {% status_bar submission.workflow submission.phase request.user css_class="status-bar--small" %} + </div> + {% if request.user|has_edit_perm:submission %} + <a class="button button--primary" href="{% url 'funds:submissions:edit' submission.id %}"> + {% if submission.status == 'draft_proposal' %} + Start your {{ submission.stage }} application + {% else %} + Edit + {% endif %} + </a> + {% endif %} + </div> + {% empty %} + No active submissions + {% endfor %} +</div> + +{% if table.data %} + <div class="wrapper wrapper--large wrapper--inner-space-medium"> + <h3>Submission history</h3> + {% render_table table %} + </div> +{% endif %} +{% endblock %} + +{% block extra_js %} + <script src="{% static 'js/apply/submission-tooltips.js' %}"></script> +{% endblock %} diff --git a/opentech/apply/dashboard/templates/dashboard/partner_dashboard.html b/opentech/apply/dashboard/templates/dashboard/partner_dashboard.html new file mode 100644 index 000000000..122386a8b --- /dev/null +++ b/opentech/apply/dashboard/templates/dashboard/partner_dashboard.html @@ -0,0 +1,57 @@ +{% extends "base-apply.html" %} +{% load render_table from django_tables2 %} +{% load static wagtailcore_tags workflow_tags statusbar_tags %} + +{% block title %}Submission Dashboard{% endblock %} + +{% block content %} +<div class="admin-bar"> + <div class="admin-bar__inner wrapper--applicant-dashboard"> + <div> + <h3 class="heading heading--no-margin">Dashboard</h3> + <h5>An overview of active and past submissions</h5> + </div> + <div class="wrapper wrapper--cta-box"> + <h4 class="heading heading--no-margin">Submit a new application</h4> + <h5 class="heading heading--normal">Apply now for our open rounds</h5> + <a class="button button--primary" href="{% pageurl APPLY_SITE.root_page %}" class="button">Apply</a> + </div> + </div> +</div> +<div class="wrapper wrapper--large wrapper--inner-space-medium"> + <h3>Your active submissions</h3> + {% for submission in my_active_submissions %} + <div class="wrapper wrapper--status-bar-outer"> + <div class="wrapper wrapper--status-bar-inner"> + <div> + <h5 class="heading heading--no-margin"><a class="link link--underlined" href="{% url 'funds:submissions:detail' submission.id %}">{{ submission.title }}</a></h5> + <h6 class="heading heading--no-margin heading--submission-meta"><span>Submitted:</span> {{ submission.submit_time.date }} by {{ submission.user.get_full_name }}</h6> + </div> + {% status_bar submission.workflow submission.phase request.user css_class="status-bar--small" %} + </div> + {% if request.user|has_edit_perm:submission %} + <a class="button button--primary" href="{% url 'funds:submissions:edit' submission.id %}"> + {% if submission.status == 'draft_proposal' %} + Start your {{ submission.stage }} application + {% else %} + Edit + {% endif %} + </a> + {% endif %} + </div> + {% empty %} + No active submissions + {% endfor %} +</div> + +{% if table.data %} + <div class="wrapper wrapper--large wrapper--inner-space-medium"> + <h3>Submission history</h3> + {% render_table table %} + </div> +{% endif %} +{% endblock %} + +{% block extra_js %} + <script src="{% static 'js/apply/submission-tooltips.js' %}"></script> +{% endblock %} diff --git a/opentech/apply/dashboard/views.py b/opentech/apply/dashboard/views.py index a89fa576a..f6a585156 100644 --- a/opentech/apply/dashboard/views.py +++ b/opentech/apply/dashboard/views.py @@ -154,6 +154,56 @@ class ReviewerDashboardView(TemplateView): return super().get_context_data(**kwargs) +class PartnerDashboardView(SingleTableView): + template_name = 'dashboard/partner_dashboard.html' + model = ApplicationSubmission + table_class = SubmissionsTable + + def get_queryset(self): + return self.model.objects.filter( + user=self.request.user + ).inactive().current().for_table(self.request.user) + + def get_context_data(self, **kwargs): + my_active_submissions = self.model.objects.filter( + user=self.request.user + ).active().current().select_related('draft_revision') + + my_active_submissions = [ + submission.from_draft() for submission in my_active_submissions + ] + + return super().get_context_data( + my_active_submissions=my_active_submissions, + **kwargs, + ) + + +class CommunityDashboardView(SingleTableView): + template_name = 'dashboard/community_dashboard.html' + model = ApplicationSubmission + table_class = SubmissionsTable + + def get_queryset(self): + return self.model.objects.filter( + user=self.request.user + ).inactive().current().for_table(self.request.user) + + def get_context_data(self, **kwargs): + my_active_submissions = self.model.objects.filter( + user=self.request.user + ).active().current().select_related('draft_revision') + + my_active_submissions = [ + submission.from_draft() for submission in my_active_submissions + ] + + return super().get_context_data( + my_active_submissions=my_active_submissions, + **kwargs, + ) + + class ApplicantDashboardView(SingleTableView): template_name = 'dashboard/applicant_dashboard.html' model = ApplicationSubmission @@ -182,7 +232,6 @@ class ApplicantDashboardView(SingleTableView): class DashboardView(ViewDispatcher): admin_view = AdminDashboardView reviewer_view = ReviewerDashboardView + partner_view = PartnerDashboardView + community_view = CommunityDashboardView applicant_view = ApplicantDashboardView - - def reviewer_check(self, request): - return request.user.is_reviewer diff --git a/opentech/apply/determinations/views.py b/opentech/apply/determinations/views.py index 88e6e787d..f99cac379 100644 --- a/opentech/apply/determinations/views.py +++ b/opentech/apply/determinations/views.py @@ -335,5 +335,7 @@ class ApplicantDeterminationDetailView(DetailView): class DeterminationDetailView(ViewDispatcher): admin_view = AdminDeterminationDetailView - applicant_view = ApplicantDeterminationDetailView reviewer_view = ReviewerDeterminationDetailView + partner_view = ApplicantDeterminationDetailView + community_view = None + applicant_view = ApplicantDeterminationDetailView diff --git a/opentech/apply/funds/templates/funds/applicationsubmission_reviewer_detail.html b/opentech/apply/funds/templates/funds/applicationsubmission_reviewer_detail.html index dcc7f795f..b10fa17c7 100644 --- a/opentech/apply/funds/templates/funds/applicationsubmission_reviewer_detail.html +++ b/opentech/apply/funds/templates/funds/applicationsubmission_reviewer_detail.html @@ -13,10 +13,6 @@ </div> {% endblock %} -{% block determination %} - {% include 'determinations/includes/determination_block.html' with submission=object %} -{% endblock %} - {% block related %} {% endblock %} diff --git a/opentech/apply/funds/views.py b/opentech/apply/funds/views.py index f4a638a9b..20291ced2 100644 --- a/opentech/apply/funds/views.py +++ b/opentech/apply/funds/views.py @@ -466,6 +466,24 @@ class ReviewerSubmissionDetailView(ReviewContextMixin, ActivityContextMixin, Del model = ApplicationSubmission form_views = [CommentFormView] + def dispatch(self, request, *args, **kwargs): + submission = self.get_object() + # If the requesting user submitted the application, return the Applicant view. + # Reviewers and partners may somtimes be appliants as well. + if submission.user == request.user: + return ApplicantSubmissionDetailView.as_view()(request, *args, **kwargs) + # Only allow reviewers in the submission they are added as reviewers or has reviewed earlier + reviewer_has_access = submission.reviewers.filter(pk=request.user.pk).exists() or submission.reviews.values('author').filter(author=request.user.pk) + if not reviewer_has_access: + raise PermissionDenied + return super().dispatch(request, *args, **kwargs) + + +class PartnerSubmissionDetailView(ReviewContextMixin, ActivityContextMixin, DelegateableView, DetailView): + template_name_suffix = '_reviewer_detail' + model = ApplicationSubmission + form_views = [CommentFormView] + def dispatch(self, request, *args, **kwargs): submission = self.get_object() # If the requesting user submitted the application, return the Applicant view. @@ -477,12 +495,49 @@ class ReviewerSubmissionDetailView(ReviewContextMixin, ActivityContextMixin, Del partner_has_access = submission.partners.filter(pk=request.user.pk).exists() if not partner_has_access: raise PermissionDenied + return super().dispatch(request, *args, **kwargs) + + +class CommunitySubmissionDetailView(ReviewContextMixin, ActivityContextMixin, DelegateableView, DetailView): + template_name_suffix = '_reviewer_detail' + model = ApplicationSubmission + form_views = [CommentFormView] + + def dispatch(self, request, *args, **kwargs): + submission = self.get_object() + # If the requesting user submitted the application, return the Applicant view. + # Reviewers and partners may somtimes be appliants as well. + if submission.user == request.user: + return ApplicantSubmissionDetailView.as_view()(request, *args, **kwargs) # Only allow community reviewers in submission with a community review state. - if request.user.is_community_reviewer and not submission.community_review: + if not submission.community_review: + raise PermissionDenied + return super().dispatch(request, *args, **kwargs) + + +class ApplicantSubmissionDetailView(ActivityContextMixin, DelegateableView, DetailView): + model = ApplicationSubmission + form_views = [CommentFormView] + + def get_object(self): + return super().get_object().from_draft() + + def dispatch(self, request, *args, **kwargs): + submission = self.get_object() + # This view is only for applicants. + if submission.user != request.user: raise PermissionDenied return super().dispatch(request, *args, **kwargs) +class SubmissionDetailView(ViewDispatcher): + admin_view = AdminSubmissionDetailView + reviewer_view = ReviewerSubmissionDetailView + partner_view = PartnerSubmissionDetailView + community_view = CommunitySubmissionDetailView + applicant_view = ApplicantSubmissionDetailView + + @method_decorator(staff_required, 'dispatch') class SubmissionSealedView(DetailView): template_name = 'funds/submission_sealed.html' @@ -541,25 +596,6 @@ class SubmissionSealedView(DetailView): return HttpResponseRedirect(reverse_lazy('funds:submissions:sealed', args=(submission.id,))) -class ApplicantSubmissionDetailView(ActivityContextMixin, DelegateableView, DetailView): - model = ApplicationSubmission - form_views = [CommentFormView] - - def get_object(self): - return super().get_object().from_draft() - - 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 - reviewer_view = ReviewerSubmissionDetailView - applicant_view = ApplicantSubmissionDetailView - - class BaseSubmissionEditView(UpdateView): """ Converts the data held on the submission into an editable format and knows how to save diff --git a/opentech/apply/utils/views.py b/opentech/apply/utils/views.py index d8968aa8d..95e1509ee 100644 --- a/opentech/apply/utils/views.py +++ b/opentech/apply/utils/views.py @@ -19,13 +19,21 @@ def page_not_found(request, exception=None, template_name='apply/404.html'): class ViewDispatcher(View): admin_view: View = None reviewer_view: View = None + partner_view: View = None + community_view: View = None applicant_view: View = None def admin_check(self, request): return request.user.is_apply_staff def reviewer_check(self, request): - return request.user.is_reviewer or request.user.is_partner or request.user.is_community_reviewer + return request.user.is_reviewer + + def partner_check(self, request): + return request.user.is_partner + + def community_check(self, request): + return request.user.is_community_reviewer def dispatch(self, request, *args, **kwargs): view = self.applicant_view @@ -34,6 +42,10 @@ class ViewDispatcher(View): view = self.admin_view elif self.reviewer_check(request): view = self.reviewer_view + elif self.partner_check(request): + view = self.partner_view + elif self.community_check(request): + view = self.community_view if view: return view.as_view()(request, *args, **kwargs) -- GitLab