Skip to content

Commit 3076d21

Browse files
joemullajrbyers
authored andcommitted
feat #4532 Fix bug where search results leaked across journals
1 parent 5f2e455 commit 3076d21

File tree

3 files changed

+161
-3
lines changed

3 files changed

+161
-3
lines changed

src/core/forms/forms.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ def __init__(self, *args, **kwargs):
598598
self.id = 'facet_form'
599599
self.queryset = kwargs.pop('queryset')
600600
self.facets = kwargs.pop('facets')
601+
self.journal_filter_query = kwargs.pop('journal_filter_query', Q())
601602

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

@@ -613,7 +614,10 @@ def __init__(self, *args, **kwargs):
613614
choices = []
614615
for each in choice_queryset:
615616
label = getattr(each, facet["choice_label_field"])
616-
count = self.queryset.filter(Q((facet_key, each.pk))).count()
617+
count = self.queryset.filter(
618+
Q((facet_key, each.pk)),
619+
self.journal_filter_query,
620+
).count()
617621
label_with_count = f'{label} ({count})'
618622
choices.append((each.pk, label_with_count))
619623

src/core/tests/test_views.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
__copyright__ = "Copyright 2024 Birkbeck, University of London"
2+
__author__ = "Open Library of Humanities"
3+
__license__ = "AGPL v3"
4+
__maintainer__ = "Open Library of Humanities"
5+
6+
from mock import patch
7+
from uuid import uuid4
8+
9+
from django.test import Client, TestCase, override_settings
10+
11+
from utils.testing import helpers
12+
13+
from core import models as core_models
14+
from core import views as core_views
15+
16+
17+
class CoreViewTestsWithData(TestCase):
18+
19+
@classmethod
20+
def setUpTestData(cls):
21+
cls.press = helpers.create_press()
22+
cls.journal_one, cls.journal_two = helpers.create_journals()
23+
helpers.create_roles(['author', 'editor', 'reviewer'])
24+
cls.user_email = '[email protected]'
25+
cls.user_password = 'xUMXW1oXn2l8L26Kixi2'
26+
cls.user = core_models.Account.objects.create_user(
27+
cls.user_email,
28+
password=cls.user_password,
29+
)
30+
cls.user.confirmation_code = uuid4()
31+
cls.user.is_active = True
32+
cls.user_orcid = 'https://orcid.org/0000-0001-2345-6789'
33+
cls.user.orcid = cls.user_orcid
34+
cls.orcid_token_uuid = uuid4()
35+
cls.orcid_token = core_models.OrcidToken.objects.create(
36+
token=cls.orcid_token_uuid,
37+
orcid=cls.user_orcid,
38+
)
39+
cls.reset_token_uuid = uuid4()
40+
cls.reset_token = core_models.PasswordResetToken.objects.create(
41+
account=cls.user,
42+
token=cls.reset_token_uuid,
43+
)
44+
cls.user.save()
45+
46+
def setUp(self):
47+
self.client = Client()
48+
49+
50+
class GenericFacetedListViewTests(CoreViewTestsWithData):
51+
"""
52+
A test suite for the core logic in GenericFacetedListView.
53+
Uses JournalUsers and BaseUserList to get access to URLs and facets
54+
as they are actually used, and so to help these tests catch
55+
potential regressions.
56+
"""
57+
58+
@classmethod
59+
def setUpTestData(cls):
60+
super().setUpTestData()
61+
62+
# Journal 1 users
63+
cls.journal_one_authors = []
64+
for num in range(0,30):
65+
cls.journal_one_authors.append(
66+
helpers.create_user(
67+
f'author_{num}[email protected]',
68+
roles=['author'],
69+
journal=cls.journal_one,
70+
)
71+
)
72+
cls.journal_one_editor = helpers.create_user(
73+
74+
roles=['editor'],
75+
journal=cls.journal_one,
76+
)
77+
cls.journal_one_editor.is_active = True
78+
cls.journal_one_editor.save()
79+
cls.journal_one_reviewer = cls.journal_one_authors[0]
80+
cls.journal_one_reviewer.add_account_role('reviewer', cls.journal_one)
81+
82+
# Journal 2 users
83+
cls.journal_two_authors = []
84+
# The first five authors are the same as journal 1
85+
for author in cls.journal_one_authors[:5]:
86+
cls.journal_two_authors.append(
87+
author.add_account_role('author', cls.journal_two)
88+
)
89+
# The next five are new
90+
for num in range(0,5):
91+
cls.journal_two_authors.append(
92+
helpers.create_user(
93+
f'author_{num}[email protected]',
94+
roles=['author'],
95+
journal=cls.journal_two,
96+
)
97+
)
98+
# Journal 2's reviewer is the same as journal 1's 15th author
99+
cls.journal_two_reviewer = cls.journal_one_authors[15]
100+
cls.journal_two_reviewer.add_account_role(
101+
'reviewer',
102+
journal=cls.journal_two,
103+
)
104+
105+
def setUp(self):
106+
super().setUp()
107+
self.client.force_login(self.journal_one_editor)
108+
109+
def test_get_paginate_by_default(self):
110+
url = '/user/all/'
111+
data = {}
112+
response = self.client.get(url, data)
113+
self.assertEqual(response.context['paginate_by'], 25)
114+
self.assertEqual(len(response.context['account_list']), 25)
115+
116+
def test_get_paginate_by_all(self):
117+
url = '/user/all/'
118+
data = {
119+
'paginate_by': 'all',
120+
}
121+
response = self.client.get(url, data)
122+
self.assertGreater(len(response.context['account_list']), 25)
123+
124+
def test_get_facet_form_foreign_key(self):
125+
"""
126+
Checks that only account roles in Journal One
127+
are included in facet counts.
128+
"""
129+
url = '/user/all/'
130+
data = {}
131+
response = self.client.get(url, data)
132+
form = response.context['facet_form']
133+
self.assertEqual(
134+
form.fields['accountrole__role__pk'].choices,
135+
[
136+
(1, 'Author (30)'),
137+
(2, 'Editor (1)'),
138+
(3, 'Reviewer (1)'),
139+
]
140+
)
141+
142+
def test_get_queryset_foreign_key(self):
143+
"""
144+
Checks that only account roles in Journal One
145+
are included in queryset results.
146+
"""
147+
url = '/user/all/'
148+
data = {
149+
'accountrole__role__pk': 3, # filter to reviewers
150+
}
151+
response = self.client.get(url, data)
152+
self.assertEqual(len(response.context['account_list']), 1)

src/core/views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,7 +2456,7 @@ class GenericFacetedListView(generic.ListView):
24562456
model = NotImplementedField
24572457
template_name = NotImplementedField
24582458

2459-
paginate_by = '25'
2459+
paginate_by = 25
24602460
facets = {}
24612461

24622462
# These fields will receive a single initial value, not a list
@@ -2486,6 +2486,7 @@ def get_facet_form(self, queryset):
24862486
GET_data,
24872487
queryset=queryset,
24882488
facets=self.facets,
2489+
journal_filter_query=self.get_journal_filter_query(),
24892490
)
24902491

24912492
return form
@@ -2504,7 +2505,7 @@ def get_context_data(self, **kwargs):
25042505
),
25052506
)
25062507
context['paginate_by'] = params_querydict.get('paginate_by', self.paginate_by)
2507-
context['facet_form'] = self.get_facet_form(queryset)
2508+
context['facet_form'] = form
25082509

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

@@ -2569,6 +2570,7 @@ def get_queryset(self, params_querydict=None):
25692570
for predicate in predicates:
25702571
query |= Q(predicate)
25712572
q_stack.append(query)
2573+
q_stack.append(self.get_journal_filter_query())
25722574
self.queryset = self.queryset.filter(*q_stack).distinct()
25732575
return self.order_queryset(self.queryset)
25742576

0 commit comments

Comments
 (0)