Ejemplo n.º 1
0
class SubmissionsListView(SpreadsheetExportMixin, SafePaginateListView):
    """Lists submissions for the provided form page"""

    template_name = "wagtailforms/index_submissions.html"
    context_object_name = "submissions"
    form_page = None
    ordering = ("-submit_time", )
    ordering_csv = ("submit_time", )  # keep legacy CSV ordering
    orderable_fields = (
        "id",
        "submit_time",
    )  # used to validate ordering in URL
    select_date_form = None

    def dispatch(self, request, *args, **kwargs):
        """Check permissions and set the form page"""

        self.form_page = kwargs.get("form_page")

        if not get_forms_for_user(
                request.user).filter(pk=self.form_page.id).exists():
            raise PermissionDenied

        self.is_export = self.request.GET.get("export") in self.FORMATS
        if self.is_export:
            self.paginate_by = None
            data_fields = self.form_page.get_data_fields()
            # Set the export fields and the headings for spreadsheet export
            self.list_export = [field for field, label in data_fields]
            self.export_headings = dict(data_fields)

        return super().dispatch(request, *args, **kwargs)

    def get_queryset(self):
        """Return queryset of form submissions with filter and order_by applied"""
        submission_class = self.form_page.get_submission_class()
        queryset = submission_class._default_manager.filter(
            page=self.form_page)

        filtering = self.get_filtering()
        if filtering and isinstance(filtering, dict):
            queryset = queryset.filter(**filtering)

        ordering = self.get_ordering()
        if ordering:
            if isinstance(ordering, str):
                ordering = (ordering, )
            queryset = queryset.order_by(*ordering)

        return queryset

    def get_paginate_by(self, queryset):
        """Get the number of items to paginate by, or ``None`` for no pagination"""
        if self.is_export:
            return None
        return self.paginate_by

    def get_validated_ordering(self):
        """Return a dict of field names with ordering labels if ordering is valid"""
        orderable_fields = self.orderable_fields or ()
        ordering = {}
        if self.is_export:
            #  Revert to CSV order_by submit_time ascending for backwards compatibility
            default_ordering = self.ordering_csv or ()
        else:
            default_ordering = self.ordering or ()
        if isinstance(default_ordering, str):
            default_ordering = (default_ordering, )
        ordering_strs = self.request.GET.getlist("order_by") or list(
            default_ordering)
        for order in ordering_strs:
            try:
                _, prefix, field_name = order.rpartition("-")
                if field_name in orderable_fields:
                    ordering[field_name] = (
                        prefix,
                        "descending" if prefix == "-" else "ascending",
                    )
            except (IndexError, ValueError):
                continue  # invalid ordering specified, skip it
        return ordering

    def get_ordering(self):
        """Return the field or fields to use for ordering the queryset"""
        ordering = self.get_validated_ordering()
        return [values[0] + name for name, values in ordering.items()]

    def get_filtering(self):
        """Return filering as a dict for submissions queryset"""
        self.select_date_form = SelectDateForm(self.request.GET)
        result = {}
        if self.select_date_form.is_valid():
            date_from = self.select_date_form.cleaned_data.get("date_from")
            date_to = self.select_date_form.cleaned_data.get("date_to")
            if date_to:
                # careful: date_to must be increased by 1 day
                # as submit_time is a time so will always be greater
                date_to += datetime.timedelta(days=1)
                if date_from:
                    result["submit_time__range"] = [date_from, date_to]
                else:
                    result["submit_time__lte"] = date_to
            elif date_from:
                result["submit_time__gte"] = date_from
        return result

    def get_filename(self):
        """Returns the base filename for the generated spreadsheet data file"""
        return "{}-export-{}".format(
            self.form_page.slug,
            datetime.datetime.today().strftime("%Y-%m-%d"))

    def render_to_response(self, context, **response_kwargs):
        if self.is_export:
            return self.as_spreadsheet(context["submissions"],
                                       self.request.GET.get("export"))
        return super().render_to_response(context, **response_kwargs)

    def to_row_dict(self, item):
        """Orders the submission dictionary for spreadsheet writing"""
        row_dict = OrderedDict(
            (field, item.get_data().get(field)) for field in self.list_export)
        return row_dict

    def get_context_data(self, **kwargs):
        """Return context for view"""
        context = super().get_context_data(**kwargs)
        submissions = context[self.context_object_name]
        data_fields = self.form_page.get_data_fields()
        data_rows = []
        context["submissions"] = submissions
        if not self.is_export:
            # Build data_rows as list of dicts containing model_id and fields
            for submission in submissions:
                form_data = submission.get_data()
                data_row = []
                for name, label in data_fields:
                    val = form_data.get(name)
                    if isinstance(val, list):
                        val = ", ".join(val)
                    data_row.append(val)
                data_rows.append({
                    "model_id": submission.id,
                    "fields": data_row
                })
            # Build data_headings as list of dicts containing model_id and fields
            ordering_by_field = self.get_validated_ordering()
            orderable_fields = self.orderable_fields
            data_headings = []
            for name, label in data_fields:
                order_label = None
                if name in orderable_fields:
                    order = ordering_by_field.get(name)
                    if order:
                        order_label = order[1]  # 'ascending' or 'descending'
                    else:
                        order_label = "orderable"  # not ordered yet but can be
                data_headings.append({
                    "name": name,
                    "label": label,
                    "order": order_label,
                })

            context.update({
                "form_page": self.form_page,
                "select_date_form": self.select_date_form,
                "data_headings": data_headings,
                "data_rows": data_rows,
            })

        return context
Ejemplo n.º 2
0
class SubmissionListView(SingleObjectMixin, ListView):
    paginate_by = 25
    page_kwarg = 'p'
    template_name = 'streamforms/submissions.html'
    filter_form = None
    model = BaseForm

    @property
    def permission_helper(self):
        return PermissionHelper(model=self.object.specific_class)

    def dispatch(self, request, *args, **kwargs):
        self.object = self.get_object()
        if not self.permission_helper.user_can_list(self.request.user):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

    def get_object(self, queryset=None):
        pk = self.kwargs.get(self.pk_url_kwarg)
        try:
            return self.model.objects.get(pk=pk).specific
        except self.model.DoesNotExist:
            raise Http404(_("No BaseForm found matching the query"))

    def get(self, request, *args, **kwargs):
        self.filter_form = SelectDateForm(request.GET)

        if request.GET.get('action') == 'CSV':
            return self.csv()

        return super().get(request, *args, **kwargs)

    def csv(self):
        queryset = self.get_queryset()
        data_fields = self.object.get_data_fields()
        data_headings = [smart_str(label) for name, label in data_fields]

        response = HttpResponse(content_type='text/csv; charset=utf-8')
        response['Content-Disposition'] = 'attachment;filename=export.csv'

        writer = csv.writer(response)
        writer.writerow(data_headings)
        for s in queryset:
            data_row = []
            form_data = s.get_data()
            for name, label in data_fields:
                data_row.append(smart_str(form_data.get(name)))
            writer.writerow(data_row)

        return response

    def get_queryset(self):
        submission_class = self.object.get_submission_class()
        self.queryset = submission_class._default_manager.filter(form=self.object)

        # filter the queryset by the required dates
        if self.filter_form.is_valid():
            date_from = self.filter_form.cleaned_data.get('date_from')
            date_to = self.filter_form.cleaned_data.get('date_to')
            if date_from:
                self.queryset = self.queryset.filter(submit_time__gte=date_from)
            if date_to:
                date_to += datetime.timedelta(days=1)
                self.queryset = self.queryset.filter(submit_time__lte=date_to)

        return self.queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        data_fields = self.object.get_data_fields()
        data_headings = [label for name, label in data_fields]

        # populate data rows from paginator
        data_rows = []
        for s in context['page_obj']:
            form_data = s.get_data()
            data_row = [form_data.get(name) for name, label in data_fields]
            data_rows.append({'model_id': s.id, 'fields': data_row})

        context.update({
            'filter_form': self.filter_form,
            'data_rows': data_rows,
            'data_headings': data_headings,
            'has_delete_permission': self.permission_helper.user_can_delete_obj(self.request.user, self.object)
        })

        return context
Ejemplo n.º 3
0
def list_submissions(request, page_id):
    # if not get_forms_for_user(request.user).filter(id=page_id).exists():
    #     raise PermissionDenied

    form_page = get_object_or_404(Form, id=page_id)  #.specific
    form_submission_class = form_page.get_submission_class()

    data_fields = form_page.get_data_fields()

    submissions = form_submission_class.objects.filter(
        form=form_page).order_by('submit_time')
    data_headings = [label for name, label in data_fields]

    select_date_form = SelectDateForm(request.GET)
    if select_date_form.is_valid():
        date_from = select_date_form.cleaned_data.get('date_from')
        date_to = select_date_form.cleaned_data.get('date_to')
        # careful: date_to should be increased by 1 day since the submit_time
        # is a time so it will always be greater
        if date_to:
            date_to += datetime.timedelta(days=1)
        if date_from and date_to:
            submissions = submissions.filter(
                submit_time__range=[date_from, date_to])
        elif date_from and not date_to:
            submissions = submissions.filter(submit_time__gte=date_from)
        elif not date_from and date_to:
            submissions = submissions.filter(submit_time__lte=date_to)

    if request.GET.get('action') == 'CSV':
        # return a CSV instead
        response = HttpResponse(content_type='text/csv; charset=utf-8')
        response['Content-Disposition'] = 'attachment;filename=export.csv'

        # Prevents UnicodeEncodeError for labels with non-ansi symbols
        data_headings = [smart_str(label) for label in data_headings]

        writer = csv.writer(response)
        writer.writerow(data_headings)
        for s in submissions:
            data_row = []
            form_data = s.get_data()
            for name, label in data_fields:
                val = form_data.get(name)
                if isinstance(val, list):
                    val = ', '.join(val)
                data_row.append(smart_str(val))
            writer.writerow(data_row)
        return response

    paginator, submissions = paginate(request, submissions)

    data_rows = []
    for s in submissions:
        form_data = s.get_data()
        data_row = []
        for name, label in data_fields:
            val = form_data.get(name)
            if isinstance(val, list):
                val = ', '.join(val)
            data_row.append(val)
        data_rows.append({"model_id": s.id, "fields": data_row})

    return render(
        request, 'wagtailforms/index_submissions.html', {
            'form_page': form_page,
            'select_date_form': select_date_form,
            'submissions': submissions,
            'data_headings': data_headings,
            'data_rows': data_rows
        })
Ejemplo n.º 4
0
def list_submissions(request, page_id):
    if not get_forms_for_user(request.user).filter(id=page_id).exists():
        raise PermissionDenied

    form_page = get_object_or_404(Page, id=page_id).specific
    form_submission_class = form_page.get_submission_class()

    data_fields = form_page.get_data_fields()

    ordering = form_page.get_field_ordering(request.GET.getlist('order_by'))

    # convert ordering tuples to a list of strings like ['-submit_time']
    ordering_strings = [
        '%s%s' % ('-' if order_str[1] == 'descending' else '', order_str[0])
        for order_str in ordering]

    if request.GET.get('action') == 'CSV':
        #  Revert to CSV being sorted submit_time ascending for backwards compatibility
        submissions = form_submission_class.objects.filter(page=form_page).order_by('submit_time')
    else:
        submissions = form_submission_class.objects.filter(page=form_page).order_by(*ordering_strings)

    data_fields_with_ordering = []
    for name, label in data_fields:
        order = None
        for order_value in [o[1] for o in ordering if o[0] == name]:
            order = order_value
        data_fields_with_ordering.append({
            "name": name,
            "label": label,
            "order": order,
        })

    data_headings = [label for name, label in data_fields]

    select_date_form = SelectDateForm(request.GET)
    if select_date_form.is_valid():
        date_from = select_date_form.cleaned_data.get('date_from')
        date_to = select_date_form.cleaned_data.get('date_to')
        # careful: date_to should be increased by 1 day since the submit_time
        # is a time so it will always be greater
        if date_to:
            date_to += datetime.timedelta(days=1)
        if date_from and date_to:
            submissions = submissions.filter(submit_time__range=[date_from, date_to])
        elif date_from and not date_to:
            submissions = submissions.filter(submit_time__gte=date_from)
        elif not date_from and date_to:
            submissions = submissions.filter(submit_time__lte=date_to)

    if request.GET.get('action') == 'CSV':
        # return a CSV instead
        response = HttpResponse(content_type='text/csv; charset=utf-8')
        response['Content-Disposition'] = 'attachment;filename=export.csv'

        # Prevents UnicodeEncodeError for labels with non-ansi symbols
        data_headings = [smart_str(label) for label in data_headings]

        writer = csv.writer(response)
        writer.writerow(data_headings)
        for s in submissions:
            data_row = []
            form_data = s.get_data()
            for name, label in data_fields:
                val = form_data.get(name)
                if isinstance(val, list):
                    val = ', '.join(val)
                data_row.append(smart_str(val))
            writer.writerow(data_row)
        return response

    paginator, submissions = paginate(request, submissions)

    data_rows = []
    for s in submissions:
        form_data = s.get_data()
        data_row = []
        for name, label in data_fields:
            val = form_data.get(name)
            if isinstance(val, list):
                val = ', '.join(val)
            data_row.append(val)
        data_rows.append({
            "model_id": s.id,
            "fields": data_row
        })

    return render(request, 'wagtailforms/index_submissions.html', {
        'form_page': form_page,
        'select_date_form': select_date_form,
        'submissions': submissions,
        'data_fields_with_ordering': data_fields_with_ordering,
        'data_rows': data_rows
    })
Ejemplo n.º 5
0
def list_submissions(request, page_id):
    if not get_forms_for_user(request.user).filter(id=page_id).exists():
        raise PermissionDenied

    form_page = get_object_or_404(Page, id=page_id).specific
    form_submission_class = form_page.get_submission_class()

    data_fields = form_page.get_data_fields()

    ordering = form_page.get_field_ordering(request.GET.getlist('order_by'))

    # convert ordering tuples to a list of strings like ['-submit_time']
    ordering_strings = [
        '%s%s' % ('-' if order_str[1] == 'descending' else '', order_str[0])
        for order_str in ordering
    ]

    if request.GET.get('action') == 'CSV':
        #  Revert to CSV being sorted submit_time ascending for backwards compatibility
        submissions = form_submission_class.objects.filter(
            page=form_page).order_by('submit_time')
    else:
        submissions = form_submission_class.objects.filter(
            page=form_page).order_by(*ordering_strings)

    data_fields_with_ordering = []
    for name, label in data_fields:
        order = None
        for order_value in [o[1] for o in ordering if o[0] == name]:
            order = order_value
        data_fields_with_ordering.append({
            "name": name,
            "label": label,
            "order": order,
        })

    data_headings = [label for name, label in data_fields]

    select_date_form = SelectDateForm(request.GET)
    if select_date_form.is_valid():
        date_from = select_date_form.cleaned_data.get('date_from')
        date_to = select_date_form.cleaned_data.get('date_to')
        # careful: date_to should be increased by 1 day since the submit_time
        # is a time so it will always be greater
        if date_to:
            date_to += datetime.timedelta(days=1)
        if date_from and date_to:
            submissions = submissions.filter(
                submit_time__range=[date_from, date_to])
        elif date_from and not date_to:
            submissions = submissions.filter(submit_time__gte=date_from)
        elif not date_from and date_to:
            submissions = submissions.filter(submit_time__lte=date_to)

    if request.GET.get('action') == 'CSV':
        # return a CSV instead
        response = HttpResponse(content_type='text/csv; charset=utf-8')
        response['Content-Disposition'] = 'attachment;filename=export.csv'

        # Prevents UnicodeEncodeError for labels with non-ansi symbols
        data_headings = [smart_str(label) for label in data_headings]

        writer = csv.writer(response)
        writer.writerow(data_headings)
        for s in submissions:
            data_row = []
            form_data = s.get_data()
            for name, label in data_fields:
                val = form_data.get(name)
                if isinstance(val, list):
                    val = ', '.join(val)
                data_row.append(smart_str(val))
            writer.writerow(data_row)
        return response

    paginator, submissions = paginate(request, submissions)

    data_rows = []
    for s in submissions:
        form_data = s.get_data()
        data_row = []
        for name, label in data_fields:
            val = form_data.get(name)
            if isinstance(val, list):
                val = ', '.join(val)
            data_row.append(val)
        data_rows.append({"model_id": s.id, "fields": data_row})

    return render(
        request, 'wagtailforms/index_submissions.html', {
            'form_page': form_page,
            'select_date_form': select_date_form,
            'submissions': submissions,
            'data_fields_with_ordering': data_fields_with_ordering,
            'data_rows': data_rows
        })
Ejemplo n.º 6
0
class SubmissionsListView(SafePaginateListView):
    """ Lists submissions for the provided form page """
    template_name = 'wagtailforms/index_submissions.html'
    context_object_name = 'submissions'
    form_page = None
    ordering = ('-submit_time',)
    ordering_csv = ('submit_time',)  # keep legacy CSV ordering
    orderable_fields = ('id', 'submit_time',)  # used to validate ordering in URL
    select_date_form = None

    def dispatch(self, request, *args, **kwargs):
        """ Check permissions and set the form page """

        self.form_page = kwargs.get('form_page')

        if not get_forms_for_user(request.user).filter(pk=self.form_page.id).exists():
            raise PermissionDenied

        self.is_csv_export = (self.request.GET.get('action') == 'CSV')
        if self.is_csv_export:
            self.paginate_by = None

        return super().dispatch(request, *args, **kwargs)

    def get_queryset(self):
        """ Return queryset of form submissions with filter and order_by applied """
        submission_class = self.form_page.get_submission_class()
        queryset = submission_class._default_manager.filter(page=self.form_page)

        filtering = self.get_filtering()
        if filtering and isinstance(filtering, dict):
            queryset = queryset.filter(**filtering)

        ordering = self.get_ordering()
        if ordering:
            if isinstance(ordering, str):
                ordering = (ordering,)
            queryset = queryset.order_by(*ordering)

        return queryset

    def get_paginate_by(self, queryset):
        """ Get the number of items to paginate by, or ``None`` for no pagination """
        if self.is_csv_export:
            return None
        return self.paginate_by

    def get_validated_ordering(self):
        """ Return a dict of field names with ordering labels if ordering is valid """
        orderable_fields = self.orderable_fields or ()
        ordering = dict()
        if self.is_csv_export:
            #  Revert to CSV order_by submit_time ascending for backwards compatibility
            default_ordering = self.ordering_csv or ()
        else:
            default_ordering = self.ordering or ()
        if isinstance(default_ordering, str):
            default_ordering = (default_ordering,)
        ordering_strs = self.request.GET.getlist('order_by') or list(default_ordering)
        for order in ordering_strs:
            try:
                _, prefix, field_name = order.rpartition('-')
                if field_name in orderable_fields:
                    ordering[field_name] = (
                        prefix, 'descending' if prefix == '-' else 'ascending'
                    )
            except (IndexError, ValueError):
                continue  # invalid ordering specified, skip it
        return ordering

    def get_ordering(self):
        """ Return the field or fields to use for ordering the queryset """
        ordering = self.get_validated_ordering()
        return [values[0] + name for name, values in ordering.items()]

    def get_filtering(self):
        """ Return filering as a dict for submissions queryset """
        self.select_date_form = SelectDateForm(self.request.GET)
        result = dict()
        if self.select_date_form.is_valid():
            date_from = self.select_date_form.cleaned_data.get('date_from')
            date_to = self.select_date_form.cleaned_data.get('date_to')
            if date_to:
                # careful: date_to must be increased by 1 day
                # as submit_time is a time so will always be greater
                date_to += datetime.timedelta(days=1)
                if date_from:
                    result['submit_time__range'] = [date_from, date_to]
                else:
                    result['submit_time__lte'] = date_to
            elif date_from:
                result['submit_time__gte'] = date_from
        return result

    def get_csv_filename(self):
        """ Returns the filename for the generated CSV file """
        return 'export-{}.csv'.format(
            datetime.datetime.today().strftime('%Y-%m-%d')
        )

    def get_csv_response(self, context):
        """ Returns a CSV response """
        filename = self.get_csv_filename()
        response = HttpResponse(content_type='text/csv; charset=utf-8')
        response['Content-Disposition'] = 'attachment;filename={}'.format(filename)

        writer = csv.writer(response)
        writer.writerow(context['data_headings'])
        for data_row in context['data_rows']:
            writer.writerow(data_row)
        return response

    def render_to_response(self, context, **response_kwargs):
        if self.is_csv_export:
            return self.get_csv_response(context)
        return super().render_to_response(context, **response_kwargs)

    def get_context_data(self, **kwargs):
        """ Return context for view, handle CSV or normal output """
        context = super().get_context_data(**kwargs)
        submissions = context[self.context_object_name]
        data_fields = self.form_page.get_data_fields()
        data_rows = []

        if self.is_csv_export:
            # Build data_rows as list of lists containing formatted data values
            # Using smart_str prevents UnicodeEncodeError for values with non-ansi symbols
            for submission in submissions:
                form_data = submission.get_data()
                data_row = []
                for name, label in data_fields:
                    val = form_data.get(name)
                    if isinstance(val, list):
                        val = ', '.join(val)
                    data_row.append(smart_str(val))
                data_rows.append(data_row)
            data_headings = [smart_str(label) for name, label in data_fields]
        else:
            # Build data_rows as list of dicts containing model_id and fields
            for submission in submissions:
                form_data = submission.get_data()
                data_row = []
                for name, label in data_fields:
                    val = form_data.get(name)
                    if isinstance(val, list):
                        val = ', '.join(val)
                    data_row.append(val)
                data_rows.append({
                    'model_id': submission.id,
                    'fields': data_row
                })
            # Build data_headings as list of dicts containing model_id and fields
            ordering_by_field = self.get_validated_ordering()
            orderable_fields = self.orderable_fields
            data_headings = []
            for name, label in data_fields:
                order_label = None
                if name in orderable_fields:
                    order = ordering_by_field.get(name)
                    if order:
                        order_label = order[1]  # 'ascending' or 'descending'
                    else:
                        order_label = 'orderable'  # not ordered yet but can be
                data_headings.append({
                    'name': name,
                    'label': label,
                    'order': order_label,
                })

        context.update({
            'form_page': self.form_page,
            'select_date_form': self.select_date_form,
            'data_headings': data_headings,
            'data_rows': data_rows,
            'submissions': submissions,
        })

        return context