Skip to content

Manage emails #2898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Feb 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dev/environment
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ MAIL_SSL=false
STATUSPAGE_URL=https://2p66nmmycsj3.statuspage.io

TOKEN_PASSWORD_SECRET="an insecure password reset secret key"
TOKEN_EMAIL_SECRET="an insecure email verification secret key"
1 change: 1 addition & 0 deletions tests/common/db/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ class Meta:
user = factory.SubFactory(UserFactory)
email = FuzzyEmail()
verified = True
primary = True
10 changes: 0 additions & 10 deletions tests/unit/accounts/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,6 @@ def test_update_user(self, user_service):
assert password != user_from_db.password
assert user_service.hasher.verify(password, user_from_db.password)

def test_verify_email(self, user_service):
user = UserFactory.create()
EmailFactory.create(user=user, primary=True,
verified=False)
EmailFactory.create(user=user, primary=False,
verified=False)
user_service.verify_email(user.id, user.emails[0].email)
assert user.emails[0].verified
assert not user.emails[1].verified

def test_find_by_email(self, user_service):
user = UserFactory.create()
EmailFactory.create(user=user, primary=True, verified=False)
Expand Down
163 changes: 162 additions & 1 deletion tests/unit/accounts/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
import pytest

from pyramid.httpexceptions import HTTPMovedPermanently, HTTPSeeOther
from sqlalchemy.orm.exc import NoResultFound

from warehouse.accounts import views
from warehouse.accounts.interfaces import (
IUserService, ITokenService, TokenExpired, TokenInvalid, TokenMissing,
TooManyFailedLogins
)

from ...common.db.accounts import UserFactory
from ...common.db.accounts import EmailFactory, UserFactory


class TestFailedLoginView:
Expand Down Expand Up @@ -695,6 +696,166 @@ def test_reset_password_password_date_changed(self, pyramid_request):
]


class TestVerifyEmail:

def test_verify_email(self, db_request, user_service, token_service):
user = UserFactory(is_active=False)
email = EmailFactory(user=user, verified=False)
db_request.user = user
db_request.GET.update({"token": "RANDOM_KEY"})
db_request.route_path = pretend.call_recorder(lambda name: "/")
token_service.loads = pretend.call_recorder(
lambda token: {
'action': 'email-verify',
'email.id': str(email.id),
}
)
db_request.find_service = pretend.call_recorder(
lambda *a, **kwargs: token_service,
)
db_request.session.flash = pretend.call_recorder(
lambda *a, **kw: None
)

result = views.verify_email(db_request)

db_request.db.flush()
assert email.verified
assert user.is_active
assert isinstance(result, HTTPSeeOther)
assert result.headers["Location"] == "/"
assert db_request.route_path.calls == [pretend.call('manage.profile')]
assert token_service.loads.calls == [pretend.call('RANDOM_KEY')]
assert db_request.session.flash.calls == [
pretend.call(
f"Email address {email.email} verified. " +
"You can now set this email as your primary address.",
queue="success"
),
]
assert db_request.find_service.calls == [
pretend.call(ITokenService, name="email"),
]

@pytest.mark.parametrize(
("exception", "message"),
[
(
TokenInvalid,
"Invalid token - Request a new verification link",
), (
TokenExpired,
"Expired token - Request a new verification link",
), (
TokenMissing,
"Invalid token - No token supplied"
),
],
)
def test_verify_email_loads_failure(
self, pyramid_request, exception, message):

def loads(token):
raise exception

pyramid_request.find_service = (
lambda *a, **kw: pretend.stub(loads=loads)
)
pyramid_request.params = {"token": "RANDOM_KEY"}
pyramid_request.route_path = pretend.call_recorder(lambda name: "/")
pyramid_request.session.flash = pretend.call_recorder(
lambda *a, **kw: None
)

views.verify_email(pyramid_request)

assert pyramid_request.route_path.calls == [
pretend.call('manage.profile'),
]
assert pyramid_request.session.flash.calls == [
pretend.call(message, queue='error'),
]

def test_verify_email_invalid_action(self, pyramid_request):
data = {
'action': 'invalid-action',
}
pyramid_request.find_service = (
lambda *a, **kw: pretend.stub(loads=lambda a: data)
)
pyramid_request.params = {"token": "RANDOM_KEY"}
pyramid_request.route_path = pretend.call_recorder(lambda name: "/")
pyramid_request.session.flash = pretend.call_recorder(
lambda *a, **kw: None
)

views.verify_email(pyramid_request)

assert pyramid_request.route_path.calls == [
pretend.call('manage.profile'),
]
assert pyramid_request.session.flash.calls == [
pretend.call(
"Invalid token - Not an email verification token",
queue='error',
),
]

def test_verify_email_not_found(self, pyramid_request):
data = {
'action': 'email-verify',
'email.id': 'invalid',
}
pyramid_request.find_service = (
lambda *a, **kw: pretend.stub(loads=lambda a: data)
)
pyramid_request.params = {"token": "RANDOM_KEY"}
pyramid_request.route_path = pretend.call_recorder(lambda name: "/")
pyramid_request.session.flash = pretend.call_recorder(
lambda *a, **kw: None
)

def raise_no_result(*a):
raise NoResultFound

pyramid_request.db = pretend.stub(query=raise_no_result)

views.verify_email(pyramid_request)

assert pyramid_request.route_path.calls == [
pretend.call('manage.profile'),
]
assert pyramid_request.session.flash.calls == [
pretend.call('Email not found', queue='error')
]

def test_verify_email_already_verified(self, db_request):
user = UserFactory()
email = EmailFactory(user=user, verified=True)
data = {
'action': 'email-verify',
'email.id': email.id,
}
db_request.user = user
db_request.find_service = (
lambda *a, **kw: pretend.stub(loads=lambda a: data)
)
db_request.params = {"token": "RANDOM_KEY"}
db_request.route_path = pretend.call_recorder(lambda name: "/")
db_request.session.flash = pretend.call_recorder(
lambda *a, **kw: None
)

views.verify_email(db_request)

assert db_request.route_path.calls == [
pretend.call('manage.profile'),
]
assert db_request.session.flash.calls == [
pretend.call('Email already verified', queue='error')
]


class TestProfileCallout:

def test_profile_callout_returns_user(self):
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/manage/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,12 @@ def test_validate_role_name_fails(self, value, expected):

assert not form.validate()
assert form.role_name.errors == [expected]


class TestAddEmailForm:

def test_creation(self):
user_service = pretend.stub()
form = forms.AddEmailForm(user_service=user_service)

assert form.user_service is user_service
Loading