Skip to content

Commit 9b1f6c1

Browse files
authored
Send password reset email to the given email (pypi#4583)
1 parent 0faadf0 commit 9b1f6c1

File tree

4 files changed

+54
-16
lines changed

4 files changed

+54
-16
lines changed

tests/unit/accounts/test_views.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -506,14 +506,16 @@ def test_request_password_reset(
506506
pretend.call(pyramid_request.POST, user_service=user_service)
507507
]
508508
assert send_password_reset_email.calls == [
509-
pretend.call(pyramid_request, stub_user)
509+
pretend.call(pyramid_request, (stub_user, None))
510510
]
511511

512512
def test_request_password_reset_with_email(
513513
self, monkeypatch, pyramid_request, pyramid_config, user_service, token_service
514514
):
515515

516-
stub_user = pretend.stub(email=pretend.stub())
516+
stub_user = pretend.stub(
517+
email="[email protected]", emails=[pretend.stub(email="[email protected]")]
518+
)
517519
pyramid_request.method = "POST"
518520
token_service.dumps = pretend.call_recorder(lambda a: "TOK")
519521
user_service.get_user_by_username = pretend.call_recorder(lambda a: None)
@@ -553,26 +555,32 @@ def test_request_password_reset_with_email(
553555
pretend.call(pyramid_request.POST, user_service=user_service)
554556
]
555557
assert send_password_reset_email.calls == [
556-
pretend.call(pyramid_request, stub_user)
558+
pretend.call(pyramid_request, (stub_user, stub_user.emails[0]))
557559
]
558560

559-
def test_request_password_reset_with_wrong_credentials(
561+
def test_request_password_reset_with_non_primary_email(
560562
self, monkeypatch, pyramid_request, pyramid_config, user_service, token_service
561563
):
562564

563-
stub_user = pretend.stub(username=pretend.stub())
565+
stub_user = pretend.stub(
566+
567+
emails=[
568+
pretend.stub(email="[email protected]"),
569+
pretend.stub(email="[email protected]"),
570+
],
571+
)
564572
pyramid_request.method = "POST"
565573
token_service.dumps = pretend.call_recorder(lambda a: "TOK")
566574
user_service.get_user_by_username = pretend.call_recorder(lambda a: None)
567-
user_service.get_user_by_email = pretend.call_recorder(lambda a: None)
575+
user_service.get_user_by_email = pretend.call_recorder(lambda a: stub_user)
568576
pyramid_request.find_service = pretend.call_recorder(
569577
lambda interface, **kw: {
570578
IUserService: user_service,
571579
ITokenService: token_service,
572580
}[interface]
573581
)
574582
form_obj = pretend.stub(
575-
username_or_email=pretend.stub(data=stub_user.username),
583+
username_or_email=pretend.stub(data="[email protected]"),
576584
validate=pretend.call_recorder(lambda: True),
577585
)
578586
form_class = pretend.call_recorder(lambda d, user_service: form_obj)
@@ -588,10 +596,10 @@ def test_request_password_reset_with_wrong_credentials(
588596

589597
assert result == {"n_hours": n_hours}
590598
assert user_service.get_user_by_username.calls == [
591-
pretend.call(stub_user.username)
599+
pretend.call("[email protected]")
592600
]
593601
assert user_service.get_user_by_email.calls == [
594-
pretend.call(stub_user.username)
602+
pretend.call("[email protected]")
595603
]
596604
assert pyramid_request.find_service.calls == [
597605
pretend.call(IUserService, context=None),
@@ -601,7 +609,9 @@ def test_request_password_reset_with_wrong_credentials(
601609
assert form_class.calls == [
602610
pretend.call(pyramid_request.POST, user_service=user_service)
603611
]
604-
assert send_password_reset_email.calls == [pretend.call(pyramid_request, None)]
612+
assert send_password_reset_email.calls == [
613+
pretend.call(pyramid_request, (stub_user, stub_user.emails[1]))
614+
]
605615

606616
def test_redirect_authenticated_user(self):
607617
pyramid_request = pretend.stub(authenticated_userid=1)

tests/unit/email/test_init.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,23 @@ def retry(exc):
235235

236236

237237
class TestSendPasswordResetEmail:
238-
@pytest.mark.parametrize("verified", [True, False])
238+
@pytest.mark.parametrize(
239+
("verified", "email_addr"),
240+
[
241+
(True, None),
242+
(False, None),
243+
(True, "[email protected]"),
244+
(False, "[email protected]"),
245+
],
246+
)
239247
def test_send_password_reset_email(
240-
self, verified, pyramid_request, pyramid_config, token_service, monkeypatch
248+
self,
249+
verified,
250+
email_addr,
251+
pyramid_request,
252+
pyramid_config,
253+
token_service,
254+
monkeypatch,
241255
):
242256

243257
stub_user = pretend.stub(
@@ -249,6 +263,10 @@ def test_send_password_reset_email(
249263
last_login="last_login",
250264
password_date="password_date",
251265
)
266+
if email_addr is None:
267+
stub_email = None
268+
else:
269+
stub_email = pretend.stub(email=email_addr, verified=verified)
252270
pyramid_request.method = "POST"
253271
token_service.dumps = pretend.call_recorder(lambda a: "TOKEN")
254272
pyramid_request.find_service = pretend.call_recorder(
@@ -274,7 +292,9 @@ def test_send_password_reset_email(
274292
pyramid_request.task = pretend.call_recorder(lambda *args, **kwargs: send_email)
275293
monkeypatch.setattr(email, "send_email", send_email)
276294

277-
result = email.send_password_reset_email(pyramid_request, stub_user)
295+
result = email.send_password_reset_email(
296+
pyramid_request, (stub_user, stub_email)
297+
)
278298

279299
assert result == {
280300
"token": "TOKEN",
@@ -300,7 +320,9 @@ def test_send_password_reset_email(
300320
assert pyramid_request.task.calls == [pretend.call(send_email)]
301321
assert send_email.delay.calls == [
302322
pretend.call(
303-
"name_value <" + stub_user.email + ">",
323+
"name_value <"
324+
+ (stub_user.email if email_addr is None else email_addr)
325+
+ ">",
304326
attr.asdict(
305327
EmailMessage(
306328
subject="Email Subject",

warehouse/accounts/views.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import hashlib
1515
import uuid
1616

17+
from first import first
1718
from pyramid.httpexceptions import (
1819
HTTPMovedPermanently,
1920
HTTPSeeOther,
@@ -272,10 +273,14 @@ def request_password_reset(request, _form_class=RequestPasswordResetForm):
272273
form = _form_class(request.POST, user_service=user_service)
273274
if request.method == "POST" and form.validate():
274275
user = user_service.get_user_by_username(form.username_or_email.data)
276+
email = None
275277
if user is None:
276278
user = user_service.get_user_by_email(form.username_or_email.data)
279+
email = first(
280+
user.emails, key=lambda e: e.email == form.username_or_email.data
281+
)
277282

278-
send_password_reset_email(request, user)
283+
send_password_reset_email(request, (user, email))
279284

280285
token_service = request.find_service(ITokenService, name="password")
281286
n_hours = token_service.max_age // 60 // 60

warehouse/email/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ def wrapper(request, user_or_users, **kwargs):
122122

123123

124124
@_email("password-reset", allow_unverified=True)
125-
def send_password_reset_email(request, user):
125+
def send_password_reset_email(request, user_and_email):
126+
user, _ = user_and_email
126127
token_service = request.find_service(ITokenService, name="password")
127128
token = token_service.dumps(
128129
{

0 commit comments

Comments
 (0)