Skip to content

Commit 7a9917a

Browse files
authored
Merge pull request #2096 from freedomofpress/handle-500-autocomplete
Adds full_clean step in autocomplete object creation
2 parents 937a099 + e28f615 commit 7a9917a

5 files changed

Lines changed: 78 additions & 19 deletions

File tree

common/models/pages.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,10 @@ class CommonTag(ClusterableModel):
700700
@classmethod
701701
def autocomplete_create(kls, value):
702702
validate_disallow_comma(value)
703-
return kls.objects.create(title=value)
703+
instance = kls(title=value)
704+
instance.full_clean()
705+
instance.save()
706+
return instance
704707

705708
title = models.CharField(
706709
max_length=255,

common/tests/test_common_tag.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ def test_tags_incident_count_property(self):
2626
def test_validation_autocomplete_tag_creation(self):
2727
with self.assertRaises(ValidationError):
2828
CommonTag.autocomplete_create('hello,world')
29+
30+
CommonTag.autocomplete_create('tag')
31+
with self.assertRaises(ValidationError):
32+
CommonTag.autocomplete_create('tag')

incident/models/items.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ class Journalist(ClusterableModel):
1111
@classmethod
1212
def autocomplete_create(kls, value):
1313
validate_disallow_AND(value)
14-
return kls.objects.create(title=value)
14+
instance = kls(title=value)
15+
instance.full_clean()
16+
instance.save()
17+
return instance
1518

1619
title = models.CharField(max_length=255, validators=[validate_disallow_AND])
1720

@@ -26,7 +29,10 @@ class Institution(ClusterableModel):
2629
@classmethod
2730
def autocomplete_create(kls, value):
2831
validate_disallow_AND(value)
29-
return kls.objects.create(title=value)
32+
instance = kls(title=value)
33+
instance.full_clean()
34+
instance.save()
35+
return instance
3036

3137
title = models.CharField(max_length=255, unique=True, validators=[validate_disallow_AND])
3238

@@ -41,7 +47,10 @@ class GovernmentWorker(ClusterableModel):
4147
@classmethod
4248
def autocomplete_create(kls, value):
4349
validate_disallow_AND(value)
44-
return kls.objects.create(title=value)
50+
instance = kls(title=value)
51+
instance.full_clean()
52+
instance.save()
53+
return instance
4554

4655
title = models.CharField(max_length=255, unique=True, validators=[validate_disallow_AND])
4756

@@ -57,7 +66,10 @@ class Meta:
5766
class LawEnforcementOrganization(ClusterableModel):
5867
@classmethod
5968
def autocomplete_create(kls, value):
60-
return kls.objects.create(title=value)
69+
instance = kls(title=value)
70+
instance.full_clean()
71+
instance.save()
72+
return instance
6173

6274
title = models.CharField(max_length=255, unique=True)
6375

@@ -96,7 +108,10 @@ class Charge(ClusterableModel):
96108
@classmethod
97109
def autocomplete_create(kls, value):
98110
validate_disallow_AND(value)
99-
return kls.objects.create(title=value)
111+
instance = kls(title=value)
112+
instance.full_clean()
113+
instance.save()
114+
return instance
100115

101116
title = models.CharField(
102117
max_length=255,
@@ -115,7 +130,10 @@ class Nationality(ClusterableModel):
115130
@classmethod
116131
def autocomplete_create(kls, value):
117132
validate_disallow_AND(value)
118-
return kls.objects.create(title=value)
133+
instance = kls(title=value)
134+
instance.full_clean()
135+
instance.save()
136+
return instance
119137

120138
title = models.CharField(
121139
max_length=255,
@@ -135,7 +153,10 @@ class PoliticianOrPublic(ClusterableModel):
135153
@classmethod
136154
def autocomplete_create(kls, value):
137155
validate_disallow_AND(value)
138-
return kls.objects.create(title=value)
156+
instance = kls(title=value)
157+
instance.full_clean()
158+
instance.save()
159+
return instance
139160

140161
title = models.CharField(
141162
max_length=255,
@@ -155,7 +176,10 @@ class Meta:
155176
class Venue(ClusterableModel):
156177
@classmethod
157178
def autocomplete_create(kls, value):
158-
return kls.objects.create(title=value)
179+
instance = kls(title=value)
180+
instance.full_clean()
181+
instance.save()
182+
return instance
159183

160184
title = models.CharField(
161185
max_length=255,

incident/models/snippets.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ class Equipment(ClusterableModel):
1010
@classmethod
1111
def autocomplete_create(kls, value):
1212
validate_disallow_AND(value)
13-
return kls.objects.create(name=value)
13+
instance = kls(name=value)
14+
instance.full_clean()
15+
instance.save()
16+
return instance
1417

1518
autocomplete_search_field = 'name'
1619

@@ -37,7 +40,10 @@ def __str__(self):
3740
class State(ClusterableModel):
3841
@classmethod
3942
def autocomplete_create(kls, value):
40-
return kls.objects.create(name=value)
43+
instance = kls(name=value)
44+
instance.full_clean()
45+
instance.save()
46+
return instance
4147

4248
autocomplete_search_field = 'name'
4349

incident/tests/test_category_field_values.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
IncidentPage,
2020
Institution,
2121
Journalist,
22+
LawEnforcementOrganization,
2223
Nationality,
2324
PoliticianOrPublic,
25+
State,
26+
Venue,
2427
choices,
2528
)
2629
from incident.tests.factories import (
@@ -190,18 +193,37 @@ def assert_boolean(self, field_name, render_function):
190193
{field_name: '0'},
191194
)
192195

193-
def assert_validation(self, model_name):
196+
def assert_and_validation(self, model_name):
194197
with self.assertRaises(ValidationError):
195198
model_name.autocomplete_create('hello AND world')
196199

200+
def assert_duplicate_validation(self, model_name):
201+
model_name.autocomplete_create('title')
202+
with self.assertRaises(ValidationError):
203+
model_name.autocomplete_create('title')
204+
197205
def test_validation_autocomplete_field_creation(self):
198-
self.assert_validation(Equipment)
199-
self.assert_validation(Journalist)
200-
self.assert_validation(Institution)
201-
self.assert_validation(GovernmentWorker)
202-
self.assert_validation(Charge)
203-
self.assert_validation(Nationality)
204-
self.assert_validation(PoliticianOrPublic)
206+
self.assert_and_validation(Equipment)
207+
self.assert_and_validation(Journalist)
208+
self.assert_and_validation(Institution)
209+
self.assert_and_validation(GovernmentWorker)
210+
self.assert_and_validation(Charge)
211+
self.assert_and_validation(Nationality)
212+
self.assert_and_validation(PoliticianOrPublic)
213+
214+
self.assert_duplicate_validation(Equipment)
215+
self.assert_duplicate_validation(State)
216+
self.assert_duplicate_validation(Institution)
217+
self.assert_duplicate_validation(GovernmentWorker)
218+
self.assert_duplicate_validation(LawEnforcementOrganization)
219+
self.assert_duplicate_validation(Charge)
220+
self.assert_duplicate_validation(Nationality)
221+
self.assert_duplicate_validation(PoliticianOrPublic)
222+
self.assert_duplicate_validation(Venue)
223+
224+
# Journalist is not unique, so calling same thing should not raise any error
225+
Journalist.autocomplete_create('title')
226+
self.assertEqual(Journalist.autocomplete_create('title').title, 'title')
205227

206228
def test_arrest_status(self):
207229
self.assert_choices(

0 commit comments

Comments
 (0)