Skip to content

Commit d347537

Browse files
committed
fix(2447): avoid failed validation of a section form to clear the rest of forms
1 parent 8c87149 commit d347537

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

users/tests/test_v3_profile_edit.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,12 @@ def test_v3_update_details_blank_country_clears_it(user, tp):
146146

147147
@waffle.testutils.override_flag("v3", active=True)
148148
def test_v3_update_details_duplicate_username_shows_inline_error(user, tp):
149+
"""Only the details section is submitted, so hide_github (owned by a
150+
different section's form) is absent from the POST. A validation failure
151+
here must not blank out that other section's displayed state."""
149152
baker.make("users.User", display_name="taken-name")
153+
user.hide_github_activity = True
154+
user.save()
150155
with tp.login(user):
151156
response = tp.post(
152157
f"{tp.reverse('profile-account')}?edit=true",
@@ -159,6 +164,7 @@ def test_v3_update_details_duplicate_username_shows_inline_error(user, tp):
159164
tp.response_200(response)
160165
form = response.context["user_profile_form"]
161166
assert "This username is already taken" in form.errors["username"]
167+
assert form["hide_github"].value() is True
162168
user.refresh_from_db()
163169
assert user.display_name != "taken-name"
164170

users/views.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,11 +587,39 @@ def post_v3(self, request, *args, **kwargs):
587587
return HttpResponseRedirect(edit_url)
588588
section_fields, save_method_name = self.V3_EDIT_SECTIONS[section_key]
589589

590+
# Each section is submitted independently, so request.POST only
591+
# carries this section's fields; every other field on the shared
592+
# form would otherwise be treated as blank/unchecked when
593+
# re-rendering after a validation error. Fill those in from the
594+
# user's current values so a failed save on one section doesn't
595+
# wipe the displayed state of the others.
596+
initial = self.get_v3_edit_initial()
597+
data = request.POST.copy()
598+
for field_name, value in initial.items():
599+
if field_name in data or field_name in section_fields:
600+
continue
601+
if value is True:
602+
data[field_name] = "on"
603+
elif value in (False, None):
604+
continue
605+
elif isinstance(value, (list, tuple)):
606+
valid_choices = {
607+
choice
608+
for choice, _ in getattr(
609+
V3UserProfileForm.base_fields.get(field_name), "choices", []
610+
)
611+
}
612+
values = [v for v in value if v in valid_choices]
613+
if values:
614+
data.setlist(field_name, values)
615+
else:
616+
data[field_name] = value
617+
590618
form = V3UserProfileForm(
591-
request.POST,
619+
data,
592620
user=request.user,
593621
user_links=request.user.profile_links,
594-
initial=self.get_v3_edit_initial(),
622+
initial=initial,
595623
)
596624
# Only the submitted section's fields are validated; the other fields
597625
# share this form but have no save handler yet, so neither their

0 commit comments

Comments
 (0)