diff --git a/tests/py/test_email.py b/tests/py/test_email.py index d7ae909ec3..5c8b35af1e 100644 --- a/tests/py/test_email.py +++ b/tests/py/test_email.py @@ -3,6 +3,7 @@ import json import sys +import urllib from pytest import raises from gratipay.exceptions import CannotRemovePrimaryEmail, EmailTaken, EmailNotVerified @@ -32,11 +33,21 @@ def add(self, participant, address, _flush=False): class TestEndpoints(Alice): - def hit_email_spt(self, action, address, user='alice', should_fail=False): + def hit_email_spt(self, action, address, user='alice', package_ids=[], should_fail=False): f = self.client.PxST if should_fail else self.client.POST - data = {'action': action, 'address': address} - headers = {b'HTTP_ACCEPT_LANGUAGE': b'en'} - response = f('/~alice/emails/modify.json', data, auth_as=user, **headers) + + # Hack to work around Aspen test client limitations. + data = [ ('action', action) + , ('address', address) + ] + [('package_id', str(p)) for p in package_ids] + body = urllib.urlencode(data) + + response = f( '/~alice/emails/modify.json' + , body=body + , content_type=b'application/x-www-form-urlencoded' + , auth_as=user + , HTTP_ACCEPT_LANGUAGE=b'en' + ) if issubclass(response.__class__, (Throttled, ProblemChangingEmail)): response.render_body({'_': lambda a: a}) return response @@ -58,8 +69,7 @@ def verify_and_change_email(self, old_email, new_email, username='alice', _flush def test_participant_can_start_email_verification(self): response = self.hit_email_spt('add-email', 'alice@gratipay.com') - actual = json.loads(response.body) - assert actual + assert json.loads(response.body) == 'Check your inbox for a verification link.' def test_starting_email_verification_triggers_verification_email(self): self.hit_email_spt('add-email', 'alice@gratipay.com') @@ -229,6 +239,54 @@ def test_remove_email(self): self.hit_email_spt('remove', 'alice@example.com') + def test_participant_can_verify_a_package_along_with_email(self): + foo = self.make_package(name='foo', emails=['alice@gratipay.com']) + response = self.hit_email_spt( 'start-verification' + , 'alice@gratipay.com' + , package_ids=[foo.id] + ) + assert json.loads(response.body) == 'Check your inbox for a verification link.' + assert self.db.all('select package_id from claims order by package_id') == [foo.id] + + def test_participant_cant_verify_packages_with_add_email_or_resend(self): + foo = self.make_package(name='foo', emails=['alice@gratipay.com']) + for action in ('add-email', 'resend'): + assert self.hit_email_spt( action + , 'alice@gratipay.com' + , package_ids=[foo.id] + , should_fail=True + ).code == 400 + + def test_participant_can_verify_multiple_packages_along_with_email(self): + package_ids = [self.make_package(name=name, emails=['alice@gratipay.com']).id + for name in ('foo', 'bar', 'baz', 'buz')] + response = self.hit_email_spt( 'start-verification' + , 'alice@gratipay.com' + , package_ids=package_ids + ) + assert json.loads(response.body) == 'Check your inbox for a verification link.' + assert self.db.all('select package_id from claims order by package_id') == package_ids + + def test_package_verification_fails_if_email_not_listed(self): + foo = self.make_package() + response = self.hit_email_spt( 'start-verification' + , 'bob@gratipay.com' + , package_ids=[foo.id] + , should_fail=True + ) + assert response.code == 400 + assert self.db.all('select package_id from claims order by package_id') == [] + + def test_package_verification_fails_package_id_is_garbage(self): + response = self.hit_email_spt( 'start-verification' + , 'bob@gratipay.com' + , package_ids=['cheese monkey'] + , should_fail=True + ) + assert response.code == 400 + assert self.db.all('select package_id from claims order by package_id') == [] + + class TestFunctions(Alice): def test_cannot_update_email_to_already_verified(self): diff --git a/www/~/%username/emails/modify.json.spt b/www/~/%username/emails/modify.json.spt index be4b4ac8cd..e7d7452dc4 100644 --- a/www/~/%username/emails/modify.json.spt +++ b/www/~/%username/emails/modify.json.spt @@ -27,18 +27,28 @@ if not participant.email_lang: participant.set_email_lang(request.headers.get("Accept-Language")) msg = None -if action in ('add-email', 'resend'): - participant.start_email_verification(address) - msg = _("Check your inbox for a verification email.") +if action in ('add-email', 'resend', 'start-verification'): + packages = [] + if action == 'start-verification': + # work around Aspen limitation + package_ids = request.body.all('package_id') if 'package_id' in request.body else [] + + for package_id in package_ids: + try: + package = Package.from_id(package_id) + assert address in package.emails + except: + raise Response(400) + packages.append(package) + elif 'package_id' in request.body: + raise Response(400) + + participant.start_email_verification(address, *packages) + msg = _("Check your inbox for a verification link.") elif action == 'set-primary': participant.update_email(address) elif action == 'remove': participant.remove_email(address) -elif action == 'add-email-and-claim-package': - package_id = request.body['package_id'] - package = Package.from_id(package_id) - participant.start_email_verification(address) - msg = _("Check {email} for a confirmation link.", email=address) else: raise Response(400, 'unknown action "%s"' % action)