Skip to content

Commit 9c2e63d

Browse files
committed
Don't allow global search of users without login anymore
Apparently login requirement for the user lookup was added to make scraping harder. It doesn't seem like the most interesting data honestly, but this adds the requirement back for global user search. Instead it will allow anonymous searching of users involved in a certain commitfest. Those you could scrape from the commitfest page anyway. Finally this adds a logged in requirement for the global search page. Otherwise people will run into the same problem there as they did on the commitfest page previously: the search box would not autocomplete without giving feedback as to why to the user. Since the global search page is only really useful for power users, having it require a login seems fine.
1 parent 641ae52 commit 9c2e63d

File tree

8 files changed

+390
-55
lines changed

8 files changed

+390
-55
lines changed

pgcommitfest/commitfest/forms.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,17 @@ class CommitFestFilterForm(forms.Form):
2424
reviewer = forms.ChoiceField(required=False, label="Reviewer (type to search)")
2525
sortkey = forms.IntegerField(required=False)
2626

27-
def __init__(self, data, *args, **kwargs):
27+
def __init__(self, data, commitfest=None, *args, **kwargs):
2828
super(CommitFestFilterForm, self).__init__(data, *args, **kwargs)
29+
self.commitfest = commitfest
30+
31+
# Update selectize_fields with cf parameter if commitfest is provided
32+
if commitfest:
33+
self.selectize_fields = {
34+
"author": f"/lookups/user?cf={commitfest.id}",
35+
"reviewer": f"/lookups/user?cf={commitfest.id}",
36+
"tag": None,
37+
}
2938

3039
self.fields["sortkey"].widget = forms.HiddenInput()
3140

pgcommitfest/commitfest/lookups.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,40 @@
11
from django.contrib.auth.models import User
22
from django.db.models import Q
3-
from django.http import Http404, HttpResponse
3+
from django.http import Http404, HttpResponse, HttpResponseForbidden
44

55
import json
66

77

88
def userlookup(request):
99
query = request.GET.get("query", None)
10+
cf = request.GET.get("cf", None)
11+
1012
if not query:
1113
raise Http404()
1214

15+
# Start with base filters for active users matching the query
1316
users = User.objects.filter(
1417
Q(is_active=True),
1518
Q(username__icontains=query)
1619
| Q(first_name__icontains=query)
1720
| Q(last_name__icontains=query),
1821
)
1922

23+
# If no commitfest filter is provided, require login
24+
if not cf:
25+
if not request.user.is_authenticated:
26+
return HttpResponseForbidden(
27+
"Login required when not filtering by commitfest"
28+
)
29+
else:
30+
# Filter users to only those who have participated in the specified commitfest
31+
# This includes authors, reviewers, and committers of patches in that commitfest
32+
users = users.filter(
33+
Q(patch_author__commitfests__id=cf)
34+
| Q(patch_reviewer__commitfests__id=cf)
35+
| Q(committer__patch__commitfests__id=cf)
36+
).distinct()
37+
2038
return HttpResponse(
2139
json.dumps(
2240
{
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""Shared test fixtures for commitfest tests."""
2+
3+
from django.contrib.auth.models import User
4+
5+
from datetime import date
6+
7+
import pytest
8+
9+
from pgcommitfest.commitfest.models import CommitFest
10+
11+
12+
@pytest.fixture
13+
def alice():
14+
"""Create test user Alice."""
15+
return User.objects.create_user(
16+
username="alice",
17+
first_name="Alice",
18+
last_name="Anderson",
19+
email="alice@example.com",
20+
)
21+
22+
23+
@pytest.fixture
24+
def bob():
25+
"""Create test user Bob."""
26+
return User.objects.create_user(
27+
username="bob",
28+
first_name="Bob",
29+
last_name="Brown",
30+
email="bob@example.com",
31+
)
32+
33+
34+
@pytest.fixture
35+
def charlie():
36+
"""Create test user Charlie."""
37+
return User.objects.create_user(
38+
username="charlie",
39+
first_name="Charlie",
40+
last_name="Chen",
41+
email="charlie@example.com",
42+
)
43+
44+
45+
@pytest.fixture
46+
def dave():
47+
"""Create test user Dave."""
48+
return User.objects.create_user(
49+
username="dave",
50+
first_name="Dave",
51+
last_name="Davis",
52+
email="dave@example.com",
53+
)
54+
55+
56+
@pytest.fixture
57+
def users(alice, bob, charlie, dave):
58+
"""Create all test users and return as a dictionary."""
59+
return {
60+
"alice": alice,
61+
"bob": bob,
62+
"charlie": charlie,
63+
"dave": dave,
64+
}
65+
66+
67+
@pytest.fixture
68+
def open_cf():
69+
"""Create an open commitfest."""
70+
return CommitFest.objects.create(
71+
name="2025-01",
72+
status=CommitFest.STATUS_OPEN,
73+
startdate=date(2025, 1, 1),
74+
enddate=date(2025, 1, 31),
75+
draft=False,
76+
)
77+
78+
79+
@pytest.fixture
80+
def in_progress_cf():
81+
"""Create an in-progress commitfest."""
82+
return CommitFest.objects.create(
83+
name="2024-11",
84+
status=CommitFest.STATUS_INPROGRESS,
85+
startdate=date(2024, 11, 1),
86+
enddate=date(2024, 11, 30),
87+
draft=False,
88+
)
89+
90+
91+
@pytest.fixture
92+
def recent_closed_cf():
93+
"""Create a recently closed commitfest."""
94+
return CommitFest.objects.create(
95+
name="2024-09",
96+
status=CommitFest.STATUS_CLOSED,
97+
startdate=date(2024, 9, 1),
98+
enddate=date(2024, 9, 30),
99+
draft=False,
100+
)
101+
102+
103+
@pytest.fixture
104+
def old_closed_cf():
105+
"""Create an old closed commitfest."""
106+
return CommitFest.objects.create(
107+
name="2024-07",
108+
status=CommitFest.STATUS_CLOSED,
109+
startdate=date(2024, 7, 1),
110+
enddate=date(2024, 7, 31),
111+
draft=False,
112+
)
113+
114+
115+
@pytest.fixture
116+
def draft_cf():
117+
"""Create a draft commitfest."""
118+
return CommitFest.objects.create(
119+
name="2025-03-draft",
120+
status=CommitFest.STATUS_OPEN,
121+
startdate=date(2025, 3, 1),
122+
enddate=date(2025, 3, 31),
123+
draft=True,
124+
)
125+
126+
127+
@pytest.fixture
128+
def commitfests(open_cf, in_progress_cf, recent_closed_cf, old_closed_cf, draft_cf):
129+
"""Create all test commitfests and return as a dictionary."""
130+
return {
131+
"open": open_cf,
132+
"in_progress": in_progress_cf,
133+
"recent_previous": recent_closed_cf,
134+
"old_previous": old_closed_cf,
135+
"draft": draft_cf,
136+
}

pgcommitfest/commitfest/tests/test_apiv1.py

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,13 @@
1-
from django.test import override_settings
2-
31
import json
4-
from datetime import date
52

63
import pytest
74

8-
from pgcommitfest.commitfest.models import CommitFest
9-
105
pytestmark = pytest.mark.django_db
116

127

13-
@pytest.fixture
14-
def commitfests():
15-
"""Create test commitfests with various statuses."""
16-
return {
17-
"open": CommitFest.objects.create(
18-
name="2025-01",
19-
status=CommitFest.STATUS_OPEN,
20-
startdate=date(2025, 1, 1),
21-
enddate=date(2025, 1, 31),
22-
draft=False,
23-
),
24-
"in_progress": CommitFest.objects.create(
25-
name="2024-11",
26-
status=CommitFest.STATUS_INPROGRESS,
27-
startdate=date(2024, 11, 1),
28-
enddate=date(2024, 11, 30),
29-
draft=False,
30-
),
31-
"recent_previous": CommitFest.objects.create(
32-
name="2024-09",
33-
status=CommitFest.STATUS_CLOSED,
34-
startdate=date(2024, 9, 1),
35-
enddate=date(2024, 9, 30),
36-
draft=False,
37-
),
38-
"old_previous": CommitFest.objects.create(
39-
name="2024-07",
40-
status=CommitFest.STATUS_CLOSED,
41-
startdate=date(2024, 7, 1),
42-
enddate=date(2024, 7, 31),
43-
draft=False,
44-
),
45-
"draft": CommitFest.objects.create(
46-
name="2025-03-draft",
47-
status=CommitFest.STATUS_OPEN,
48-
startdate=date(2025, 3, 1),
49-
enddate=date(2025, 3, 31),
50-
draft=True,
51-
),
52-
}
53-
54-
558
def test_needs_ci_endpoint(client, commitfests):
569
"""Test the /api/v1/commitfests/needs_ci endpoint returns correct data."""
57-
with override_settings(AUTO_CREATE_COMMITFESTS=False):
58-
response = client.get("/api/v1/commitfests/needs_ci")
10+
response = client.get("/api/v1/commitfests/needs_ci")
5911

6012
# Check response metadata
6113
assert response.status_code == 200

0 commit comments

Comments
 (0)