Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed an issue where article list pages could throw an error for invalid filters #4517

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/core/forms/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,6 @@ def __init__(self, *args, **kwargs):
self.id = 'facet_form'
self.queryset = kwargs.pop('queryset')
self.facets = kwargs.pop('facets')
self.fields = {}

super().__init__(*args, **kwargs)

Expand All @@ -619,7 +618,7 @@ def __init__(self, *args, **kwargs):
choices.append((each.pk, label_with_count))

choices = sorted(choices, key=lambda x: x[1])
self.fields[facet_key] = forms.ChoiceField(
self.fields[facet_key] = forms.MultipleChoiceField(
widget=forms.widgets.CheckboxSelectMultiple,
choices=choices,
required=False,
Expand Down
57 changes: 40 additions & 17 deletions src/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from django.views.decorators.csrf import ensure_csrf_cookie
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _
from django.utils.html import mark_safe
from django.utils import translation
from django.db.models import Q, OuterRef, Subquery, Count, Avg
from django.views import generic
Expand Down Expand Up @@ -2451,6 +2452,7 @@ class GenericFacetedListView(generic.ListView):
This is a generic base class for creating filterable list views
with Janeway models.
"""
form_class = forms.CBVFacetForm
model = NotImplementedField
template_name = NotImplementedField

Expand All @@ -2472,25 +2474,37 @@ def get_paginate_by(self, queryset):
paginate_by = self.paginate_by
return paginate_by

def get_facet_form(self, queryset):
GET_data = dict(self.request.GET.copy().lists())

for keyword, values in GET_data.items():
if keyword in self.facets:
if self.facets[keyword]['type'] in self.single_value_fields:
GET_data[keyword] = values[0]

form = self.form_class(
GET_data,
queryset=queryset,
facets=self.facets,
)

return form

def get_context_data(self, **kwargs):
params_querydict = self.request.GET.copy()
context = super().get_context_data(**kwargs)
queryset = self.get_queryset()
form = self.get_facet_form(queryset)
if params_querydict and not form.is_valid():
messages.add_message(
self.request,
messages.ERROR,
mark_safe(_("The form did not validate: ")
+ (f"{form.errors}")
),
)
context['paginate_by'] = params_querydict.get('paginate_by', self.paginate_by)
facets = self.get_facets()

initial = dict(params_querydict.lists())

for keyword, value in initial.items():
if keyword in facets:
if facets[keyword]['type'] in self.single_value_fields:
initial[keyword] = value[0]

context['facet_form'] = forms.CBVFacetForm(
queryset=queryset,
facets=facets,
initial=initial,
)
context['facet_form'] = self.get_facet_form(queryset)

context['actions'] = self.get_actions()

Expand All @@ -2507,6 +2521,7 @@ def get_context_data(self, **kwargs):
return context

def get_queryset(self, params_querydict=None):
self.facets = self.get_facets()
if not params_querydict:
params_querydict = self.request.GET.copy()

Expand All @@ -2517,11 +2532,20 @@ def get_queryset(self, params_querydict=None):
# Clear order_by, since it is handled separately
params_querydict.pop('order_by', '')

facets = self.facets
self.queryset = super().get_queryset()
q_stack = []
facets = self.get_facets()

for facet in facets.values():
self.queryset = self.queryset.annotate(**facet.get('annotations', {}))
self.queryset = self.queryset.filter(self.get_journal_filter_query())

# Validate params against form ahead of filtering
if params_querydict:
form = self.get_facet_form(self.queryset)
if not form.is_valid():
return self.queryset

q_stack = []
for keyword, value_list in params_querydict.lists():
# The following line prevents the user from passing any parameters
# other than those specified in the facets.
Expand All @@ -2545,7 +2569,6 @@ def get_queryset(self, params_querydict=None):
for predicate in predicates:
query |= Q(predicate)
q_stack.append(query)
q_stack.append(self.get_journal_filter_query())
self.queryset = self.queryset.filter(*q_stack).distinct()
return self.order_queryset(self.queryset)

Expand Down