Skip to content

Commit

Permalink
add support for json and generic responses
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesejr committed Dec 23, 2024
1 parent 7ae5671 commit c92f69c
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 3 deletions.
17 changes: 14 additions & 3 deletions flask_security/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,10 +1160,21 @@ def recover_username():
if user:
send_username_recovery_email(user)

do_flash(*get_message("USERNAME_RECOVERY_REQUEST", email=form.email.data))
if not _security._want_json(request):
do_flash(*get_message("USERNAME_RECOVERY_REQUEST", email=form.email.data))
elif request.method == "POST" and cv("RETURN_GENERIC_RESPONSES"):
rinfo = dict(email=dict())
form_errors_munge(form, rinfo)
if not form.errors:
if not _security._want_json(request):
do_flash(
*get_message("USERNAME_RECOVERY_REQUEST", email=form.email.data)
)

if _security._want_json(request):
return base_render_json(form, include_auth_token=True)
if _security._want_json(request):
return base_render_json(form, include_user=False)

if form.validate_on_submit():
return redirect(url_for_security("login"))

return _security.render_template(
Expand Down
2 changes: 2 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ def app(request: pytest.FixtureRequest) -> SecurityFixture:
# Make this hex_md5 for token tests
app.config["SECURITY_HASHING_SCHEMES"] = ["hex_md5"]
app.config["SECURITY_DEPRECATED_HASHING_SCHEMES"] = []
# Enable username recovery for tests
app.config["SECURITY_USERNAME_RECOVERY"] = True

for opt in [
"changeable",
Expand Down
73 changes: 73 additions & 0 deletions tests/test_recoverable.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,14 @@ def on_email_sent(app, **kwargs):
email = app.mail.outbox[1]
assert "Your username is: joe" in email.body

# Test JSON responses
response = clients.post(
"/recover-username",
json=dict(email="joe@lp.com"),
headers={"Content-Type": "application/json"},
)
assert response.status_code == 200


def test_username_recovery_invalid_email(app, clients):
response = clients.post(
Expand All @@ -844,3 +852,68 @@ def test_username_recovery_invalid_email(app, clients):

assert not app.mail.outbox
assert response.status_code == 200

# Test JSON responses
response = clients.post(
"/recover-username",
json=dict(email="bogus@lp.com"),
headers={"Content-Type": "application/json"},
)
assert response.status_code == 400


@pytest.mark.settings(return_generic_responses=True)
def test_username_recovery_generic_responses(app, clients, get_message):
recorded_recovery_sent = []

@username_recovery_email_sent.connect_via(app)
def on_email_sent(app, **kwargs):
recorded_recovery_sent.append(kwargs["user"])

# Test with valid email
with capture_flashes() as flashes:
response = clients.post(
"/recover-username",
data=dict(email="joe@lp.com"),
follow_redirects=True,
)
assert len(flashes) == 1
assert get_message("USERNAME_RECOVERY_REQUEST") == flashes[0]["message"].encode(
"utf-8"
)
assert len(recorded_recovery_sent) == 1
assert len(app.mail.outbox) == 1
assert response.status_code == 200

# Test with non-existant email (should still return 200)
with capture_flashes() as flashes:
response = clients.post(
"/recover-username",
data=dict(email="bogus@lp.com"),
follow_redirects=True,
)
assert len(flashes) == 1
assert get_message("USERNAME_RECOVERY_REQUEST") == flashes[0]["message"].encode(
"utf-8"
)
# Validate no email was sent (there should only be one from the previous test)
assert len(recorded_recovery_sent) == 1
assert len(app.mail.outbox) == 1
assert response.status_code == 200

# Test JSON responses - valid email
response = clients.post(
"/recover-username",
json=dict(email="joe@lp.com"),
headers={"Content-Type": "application/json"},
)
assert response.status_code == 200

# Test JSON responses - invalid email
response = clients.post(
"/recover-username",
json=dict(email="bogus@lp.com"),
headers={"Content-Type": "application/json"},
)
assert response.status_code == 200
assert not any(e in response.json["response"].keys() for e in ["error", "errors"])

0 comments on commit c92f69c

Please sign in to comment.