123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- from django.contrib.admin import SimpleListFilter
- from django.contrib.admin.utils import quote
- from django.shortcuts import redirect
- from django.urls import path, reverse
- from django.utils.translation import gettext_lazy as _
- from wagtail.contrib.modeladmin.helpers import (
- PermissionHelper, PagePermissionHelper, PageAdminURLHelper, AdminURLHelper,
- ButtonHelper)
- from wagtail.contrib.modeladmin.options import ModelAdmin
- from wagtail.contrib.modeladmin.views import IndexView, InstanceSpecificView
- from wagtail.admin import messages
- from wagtail import hooks
- from wagtail.models import Page
- from wagtail.contrib.forms.utils import get_forms_for_user
- from .models import SessionFormSubmission
- class FormIndexView(IndexView):
- page_title = _('Forms')
- class FormPermissionHelper(PagePermissionHelper):
- def user_can_list(self, user):
- return get_forms_for_user(user).exists()
- def user_can_create(self, user):
- return False
- def user_can_edit_obj(self, user, obj):
- return False
- def user_can_delete_obj(self, user, obj):
- return False
- def user_can_publish_obj(self, user, obj):
- return False
- def user_can_unpublish_obj(self, user, obj):
- return False
- def user_can_copy_obj(self, user, obj):
- return False
- def user_can_inspect_obj(self, user, obj):
- return False
- class FormURLHelper(PageAdminURLHelper):
- def _get_action_url_pattern(self, action):
- if action == 'index':
- return r'^stream_forms/$'
- return r'^stream_forms/%s/$' % action
- class FormAdmin(ModelAdmin):
- model = Page
- menu_label = _('Forms')
- menu_icon = 'form'
- list_display = ('title', 'unprocessed_submissions_link',
- 'all_submissions_link', 'edit_link')
- index_view_class = FormIndexView
- permission_helper_class = FormPermissionHelper
- url_helper_class = FormURLHelper
- def get_queryset(self, request):
- return get_forms_for_user(request.user)
- def all_submissions_link(self, obj, label=_('See all submissions'),
- url_suffix=''):
- return '<a href="%s?page_id=%s%s">%s</a>' % (
- reverse(SubmissionAdmin().url_helper.get_action_url_name('index')),
- obj.pk, url_suffix, label)
- all_submissions_link.short_description = ''
- all_submissions_link.allow_tags = True
- def unprocessed_submissions_link(self, obj):
- return self.all_submissions_link(
- obj, _('See unprocessed submissions'),
- '&status=%s' % SubmissionStatusFilter.unprocessed_status)
- unprocessed_submissions_link.short_description = ''
- unprocessed_submissions_link.allow_tags = True
- def edit_link(self, obj):
- return '<a href="%s">%s</a>' % (
- reverse('wagtailadmin_pages:edit', args=(obj.pk,)),
- _('Edit this form page'))
- edit_link.short_description = ''
- edit_link.allow_tags = True
- class SubmissionStatusFilter(SimpleListFilter):
- title = _('status')
- parameter_name = 'status'
- unprocessed_status = ','.join((SessionFormSubmission.COMPLETE,
- SessionFormSubmission.REVIEWED))
- def lookups(self, request, model_admin):
- yield (self.unprocessed_status, _('Complete or reviewed'))
- for status, verbose_status in SessionFormSubmission.STATUSES:
- if status != SessionFormSubmission.INCOMPLETE:
- yield status, verbose_status
- def queryset(self, request, queryset):
- status = self.value()
- if not status:
- return queryset
- if ',' in status:
- return queryset.filter(status__in=status.split(','))
- return queryset.filter(status=status)
- class SubmissionPermissionHelper(PermissionHelper):
- def user_can_list(self, user):
- return get_forms_for_user(user).exists()
- def user_can_create(self, user):
- return False
- def user_can_edit_obj(self, user, obj):
- return False
- def user_can_inspect_obj(self, user, obj):
- return False
- def user_can_set_status_obj(self, user, obj):
- return user.can_set_status()
- class SubmissionURLHelper(AdminURLHelper):
- def _get_action_url_pattern(self, action):
- if action == 'index':
- return r'^%s/%s/$' % (self.opts.app_label, 'submissions')
- return r'^%s/%s/%s/$' % (self.opts.app_label, 'submissions', action)
- def _get_object_specific_action_url_pattern(self, action):
- return r'^%s/%s/%s/(?P<instance_pk>[-\w]+)/$' % (
- self.opts.app_label, 'submissions', action)
- class SubmissionButtonHelper(ButtonHelper):
- def set_status_button(self, pk, status, label, title, classnames_add=None,
- classnames_exclude=None):
- if classnames_add is None:
- classnames_add = []
- if classnames_exclude is None:
- classnames_exclude = []
- classnames = self.finalise_classname(classnames_add,
- classnames_exclude)
- url = self.url_helper.get_action_url('set_status', quote(pk))
- url += '?status=' + status
- return {
- 'url': url,
- 'label': label,
- 'classname': classnames,
- 'title': title,
- }
- def reviewed_button(self, pk, classnames_add=None,
- classnames_exclude=None):
- if classnames_add is None:
- classnames_add = []
- return self.set_status_button(pk, self.model.REVIEWED,
- _('mark as reviewed'),
- _('Mark this submission as reviewed'),
- classnames_add=classnames_add,
- classnames_exclude=classnames_exclude)
- def approve_button(self, pk, classnames_add=None,
- classnames_exclude=None):
- if classnames_add is None:
- classnames_add = []
- if 'button-secondary' in classnames_add:
- classnames_add.remove('button-secondary')
- classnames_add = ['yes'] + classnames_add
- return self.set_status_button(pk, self.model.APPROVED, _('approve'),
- _('Approve this submission'),
- classnames_add=classnames_add,
- classnames_exclude=classnames_exclude)
- def reject_button(self, pk, classnames_add=None,
- classnames_exclude=None):
- if classnames_add is None:
- classnames_add = []
- if 'button-secondary' in classnames_add:
- classnames_add.remove('button-secondary')
- classnames_add = ['no'] + classnames_add
- return self.set_status_button(pk, self.model.REJECTED, _('reject'),
- _('Reject this submission'),
- classnames_add=classnames_add,
- classnames_exclude=classnames_exclude)
- def get_buttons_for_obj(self, obj, exclude=None, classnames_add=None,
- classnames_exclude=None):
- buttons = super().get_buttons_for_obj(
- obj, exclude=exclude, classnames_add=classnames_add,
- classnames_exclude=classnames_exclude)
- pk = getattr(obj, self.opts.pk.attname)
- status_buttons = []
- if obj.status != obj.REVIEWED:
- status_buttons.append(self.reviewed_button(
- pk, classnames_add=classnames_add,
- classnames_exclude=classnames_exclude))
- if obj.status != obj.APPROVED:
- status_buttons.append(self.approve_button(
- pk, classnames_add=classnames_add,
- classnames_exclude=classnames_exclude))
- if obj.status != obj.REJECTED:
- status_buttons.append(self.reject_button(
- pk, classnames_add=classnames_add,
- classnames_exclude=classnames_exclude))
- return status_buttons + buttons
- class SetStatusView(InstanceSpecificView):
- def check_action_permitted(self, user):
- return self.permission_helper.user_can_set_status_obj(user,
- self.instance)
- def get(self, request, *args, **kwargs):
- status = request.GET.get('status')
- if status in dict(self.model.STATUSES):
- previous_status = self.instance.status
- self.instance.status = status
- self.instance.save()
- verbose_label = self.instance.get_status_display()
- if 'revert' in request.GET:
- messages.success(request, 'Reverted to the “%s” status.'
- % verbose_label)
- else:
- revert_url = (self.url_helper.get_action_url('set_status',
- self.instance_pk)
- + '?revert&status=' + previous_status)
- messages.success(
- request,
- 'Successfully changed the status to “%s”.' % verbose_label,
- buttons=[messages.button(revert_url, _('Revert'))])
- url = request.META.get('HTTP_REFERER')
- if url is None:
- url = (self.url_helper.get_action_url('index')
- + '?page_id=%s' % self.instance.page_id)
- return redirect(url)
- class SubmissionAdmin(ModelAdmin):
- model = SessionFormSubmission
- menu_icon = 'form'
- permission_helper_class = SubmissionPermissionHelper
- url_helper_class = SubmissionURLHelper
- button_helper_class = SubmissionButtonHelper
- set_status_view_class = SetStatusView
- list_display = ('status', 'user', 'submit_time', 'last_modification')
- list_filter = (SubmissionStatusFilter, 'submit_time', 'last_modification')
- search_fields = ('user__first_name', 'user__last_name')
- def register_with_wagtail(self):
- @hooks.register('register_permissions')
- def register_permissions():
- return self.get_permissions_for_registration()
- @hooks.register('register_admin_urls')
- def register_admin_urls():
- return self.get_admin_urls_for_registration()
- def get_queryset(self, request):
- qs = super().get_queryset(request)
- form_pages = get_forms_for_user(request.user)
- return (qs.filter(page__in=form_pages)
- .exclude(status=self.model.INCOMPLETE))
- def get_form_page(self, request):
- form_pages = get_forms_for_user(request.user)
- try:
- return form_pages.get(pk=int(request.GET['page_id'])).specific
- except (KeyError, TypeError, ValueError, Page.DoesNotExist):
- pass
- # TODO: Find a cleaner way to display data from dynamic fields.
- def add_data_bridge(self, name, label):
- def data_bridge(obj):
- return obj.get_data().get(name)
- data_bridge.short_description = label
- setattr(self, name, data_bridge)
- def get_list_display(self, request):
- form_page = self.get_form_page(request)
- if form_page is None:
- return self.list_display
- fields = []
- for name, label in form_page.get_data_fields():
- fields.append(name)
- self.add_data_bridge(name, label)
- return fields
- def set_status_view(self, request, instance_pk):
- kwargs = {'model_admin': self, 'instance_pk': instance_pk}
- view_class = self.set_status_view_class
- return view_class.as_view(**kwargs)(request)
- def get_admin_urls_for_registration(self):
- urls = super().get_admin_urls_for_registration()
- urls += (
- path(
- self.url_helper.get_action_url_pattern('set_status'),
- self.set_status_view,
- name=self.url_helper.get_action_url_name('set_status')
- ),
- )
- return urls
- # @hooks.register('construct_main_menu')
- # def hide_old_forms_module(request, menu_items):
- # from wagtail.contrib.forms.wagtail_hooks import FormsMenuItem
- # for menu_item in menu_items:
- # if isinstance(menu_item, FormsMenuItem):
- # menu_items.remove(menu_item)
- # modeladmin_register(FormAdmin)
- # modeladmin_register(SubmissionAdmin)
|