launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #07344
[Merge] lp:~deryck/launchpad/refactor-editemail-doctest-363916 into lp:launchpad
Deryck Hodge has proposed merging lp:~deryck/launchpad/refactor-editemail-doctest-363916 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~deryck/launchpad/refactor-editemail-doctest-363916/+merge/103718
This work was done as part of fixing a security issue. In an earlier branch (not yet up for review), I changed Launchpad to re-authenticate a user when going to edit their settings for email, gpg, ssh, etc. The work broke a ton of tests and rather than spend more time than already lost fixing tests, I decided to refactor the page tests into unit tests. I have a number of reasons that I decided to do this, chief of which are:
* It's hard to test in doctest when login redirects to re-auth the user
* I needed to find some LOC credit for the work
This is a large branch deleting doctests, so I decided to land it independent of the actual bug fix. Everything that was tested in the doctest is either tested already in another place, or I added a new unit tests for it here. There is no real functionality change here.
We are lint free for these changes, too.
--
https://code.launchpad.net/~deryck/launchpad/refactor-editemail-doctest-363916/+merge/103718
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~deryck/launchpad/refactor-editemail-doctest-363916 into lp:launchpad.
=== modified file 'lib/lp/registry/browser/tests/test_person.py'
--- lib/lp/registry/browser/tests/test_person.py 2012-04-17 22:56:29 +0000
+++ lib/lp/registry/browser/tests/test_person.py 2012-04-26 15:25:25 +0000
@@ -3,6 +3,7 @@
__metaclass__ = type
+import email
import doctest
from textwrap import dedent
@@ -16,6 +17,7 @@
)
import transaction
from zope.component import getUtility
+from zope.publisher.interfaces import NotFound
from lp.app.errors import NotFoundError
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
@@ -37,8 +39,11 @@
from lp.registry.model.milestone import milestone_sort_key
from lp.services.config import config
from lp.services.identity.interfaces.account import AccountStatus
+from lp.services.identity.interfaces.emailaddress import IEmailAddressSet
+from lp.services.mail import stub
from lp.services.verification.interfaces.authtoken import LoginTokenType
from lp.services.verification.interfaces.logintoken import ILoginTokenSet
+from lp.services.verification.tests.logintoken import get_token_url_from_email
from lp.services.webapp import canonical_url
from lp.services.webapp.interfaces import ILaunchBag
from lp.services.webapp.servers import LaunchpadTestRequest
@@ -65,7 +70,10 @@
LaunchpadZopelessLayer,
)
from lp.testing.matchers import HasQueryCount
-from lp.testing.pages import extract_text
+from lp.testing.pages import (
+ extract_text,
+ setupBrowserForUser,
+ )
from lp.testing.views import (
create_initialized_view,
create_view,
@@ -355,23 +363,57 @@
self.ppa = self.factory.makeArchive(owner=self.person)
self.view = create_initialized_view(self.person, '+edit')
- def test_add_email_good_data(self):
- email_address = self.factory.getUniqueEmailAddress()
+ def createAddEmailView(self, email_address):
+ """Test helper to create +editemails view."""
form = {
'field.VALIDATED_SELECTED': self.valid_email_address,
'field.VALIDATED_SELECTED-empty-marker': 1,
'field.actions.add_email': 'Add',
'field.newemail': email_address,
}
- create_initialized_view(self.person, "+editemails", form=form)
-
+ return create_initialized_view(self.person, "+editemails", form=form)
+
+ def createSetContactViaAddEmailView(self, email_address):
+ form = {
+ 'field.VALIDATED_SELECTED': email_address,
+ 'field.actions.set_preferred': 'Set as Contact Address',
+ }
+ return create_initialized_view(self.person, '+editemails', form=form)
+
+ def _assertEmailAndError(self, email_str, expected_msg):
+ view = self.createAddEmailView(email_str)
+ error_msg = view.errors[0]
+ if type(error_msg) != unicode:
+ error_msg = error_msg.doc()
+ self.assertEqual(expected_msg, error_msg)
+
+ def test_add_email(self):
+ stub.test_emails = []
+ email_address = self.factory.getUniqueEmailAddress()
+ view = self.createAddEmailView(email_address)
# If everything worked, there should now be a login token to validate
# this email address for this user.
token = getUtility(ILoginTokenSet).searchByEmailRequesterAndType(
email_address,
self.person,
LoginTokenType.VALIDATEEMAIL)
- self.assertTrue(token is not None)
+ self.assertIsNotNone(token)
+ notifications = view.request.response.notifications
+ self.assertEqual(1, len(notifications))
+ expected_msg = (
+ u"A confirmation message has been sent to '%s'."
+ " Follow the instructions in that message to confirm"
+ " that the address is yours. (If the message doesn't arrive in a"
+ " few minutes, your mail provider might use 'greylisting', which"
+ " could delay the message for up to an hour or two.)" %
+ email_address)
+ self.assertEqual(expected_msg, notifications[0].message)
+ transaction.commit()
+ self.assertEqual(2, len(stub.test_emails))
+ to_addrs = [to_addr for from_addr, to_addr, msg in stub.test_emails]
+ # Both the new and old addr should be sent email.
+ self.assertIn([self.valid_email_address], to_addrs)
+ self.assertIn([email_address], to_addrs)
def test_add_email_address_taken(self):
email_address = self.factory.getUniqueEmailAddress()
@@ -380,13 +422,7 @@
displayname='deadaccount',
email=email_address,
account_status=AccountStatus.NOACCOUNT)
- form = {
- 'field.VALIDATED_SELECTED': self.valid_email_address,
- 'field.VALIDATED_SELECTED-empty-marker': 1,
- 'field.actions.add_email': 'Add',
- 'field.newemail': email_address,
- }
- view = create_initialized_view(self.person, "+editemails", form=form)
+ view = self.createAddEmailView(email_address)
error_msg = view.errors[0]
expected_msg = (
"The email address '%s' is already registered to "
@@ -397,6 +433,130 @@
% email_address)
self.assertEqual(expected_msg, error_msg)
+ def test_validate_email(self):
+ stub.test_emails = []
+ added_email = self.factory.getUniqueEmailAddress()
+ view = self.createAddEmailView(added_email)
+ form = {
+ 'field.UNVALIDATED_SELECTED': added_email,
+ 'field.actions.validate': 'Confirm',
+ }
+ view = create_initialized_view(self.person, '+editemails', form=form)
+ notifications = view.request.response.notifications
+ self.assertEqual(1, len(notifications))
+ expected_msg = (
+ u"An e-mail message was sent to '%s' "
+ "with instructions on how to confirm that it belongs to you."
+ % added_email)
+ self.assertEqual(expected_msg, notifications[0].message)
+ # Ensure we sent mail to the right address.
+ transaction.commit()
+ to_addrs = [to_addr for from_addr, to_addr, msg in stub.test_emails]
+ self.assertIn([added_email], to_addrs)
+
+ def test_validate_token(self):
+ # Ensure hitting +validateemail actually validates the email.
+ stub.test_emails = []
+ added_email = self.factory.getUniqueEmailAddress()
+ self.createAddEmailView(added_email)
+ form = {
+ 'field.UNVALIDATED_SELECTED': added_email,
+ 'field.actions.validate': 'Confirm',
+ }
+ create_initialized_view(self.person, '+editemails', form=form)
+ # Get the token from the email msg.
+ transaction.commit()
+ messages = [msg for from_addr, to_addr, msg in stub.test_emails]
+ raw_msg = None
+ for orig_msg in messages:
+ msg = email.message_from_string(orig_msg)
+ if msg.get('to') == added_email:
+ raw_msg = orig_msg
+ token_url = get_token_url_from_email(raw_msg)
+ browser = setupBrowserForUser(user=self.person)
+ browser.open(token_url)
+ expected_msg = u'Confirm e-mail address <code>%s</code>' % added_email
+ self.assertIn(expected_msg, browser.contents)
+ browser.getControl('Continue').click()
+ # Login again to access displayname, since browser logged us out.
+ login_person(self.person)
+ expected_title = u'%s in Launchpad' % self.person.displayname
+ self.assertEqual(expected_title, browser.title)
+
+ def test_remove_unvalidated_email_address(self):
+ added_email = self.factory.getUniqueEmailAddress()
+ view = self.createAddEmailView(added_email)
+ form = {
+ 'field.UNVALIDATED_SELECTED': added_email,
+ 'field.actions.remove_unvalidated': 'Remove',
+ }
+ view = create_initialized_view(self.person, '+editemails', form=form)
+ notifications = view.request.response.notifications
+ self.assertEqual(1, len(notifications))
+ expected_msg = (
+ u"The email address '%s' has been removed." % added_email)
+ self.assertEqual(expected_msg, notifications[0].message)
+
+ def test_cannot_remove_contact_address(self):
+ form = {
+ 'field.VALIDATED_SELECTED': self.valid_email_address,
+ 'field.actions.remove_validated': 'Remove',
+ }
+ view = create_initialized_view(self.person, '+editemails', form=form)
+ error_msg = view.errors[0]
+ expected_msg = (
+ "You can't remove %s because it's your contact email address."
+ % self.valid_email_address)
+ self.assertEqual(expected_msg, error_msg)
+
+ def test_set_contact_address(self):
+ added_email = self.factory.getUniqueEmailAddress()
+ view = self.createAddEmailView(added_email)
+ # We need a commit to make sure person and other data are in DB.
+ transaction.commit()
+ validated_email = getUtility(
+ IEmailAddressSet).new(added_email, self.person)
+ self.person.validateAndEnsurePreferredEmail(validated_email)
+ view = self.createSetContactViaAddEmailView(added_email)
+ notifications = view.request.response.notifications
+ self.assertEqual(1, len(notifications))
+ expected_msg = (
+ u"Your contact address has been changed to: %s" % added_email)
+ self.assertEqual(expected_msg, notifications[0].message)
+
+ def test_set_contact_address_already_set(self):
+ view = self.createSetContactViaAddEmailView(self.valid_email_address)
+ notifications = view.request.response.notifications
+ self.assertEqual(1, len(notifications))
+ expected_msg = (
+ "%s is already set as your contact address."
+ % self.valid_email_address)
+ self.assertEqual(expected_msg, notifications[0].message)
+
+ def test_team_editemails_not_found(self):
+ team = self.factory.makeTeam(owner=self.person, members=[self.person])
+ url = '%s/+editemails' % canonical_url(team)
+ browser = setupBrowserForUser(user=self.person)
+ self.assertRaises(NotFound, browser.open, url)
+
+ def test_email_string_validation_no_email_prodvided(self):
+ no_email = ''
+ expected_msg = u'Required input is missing.'
+ self._assertEmailAndError(no_email, expected_msg)
+
+ def test_email_string_validation_invalid_email(self):
+ not_an_email = 'foo'
+ expected_msg = u"'foo' doesn't seem to be a valid email address."
+ self._assertEmailAndError(not_an_email, expected_msg)
+
+ def test_email_string_validation_is_escaped(self):
+ xss_email = "foo@xxxxxxxxxxx<script>window.alert('XSS')</script>"
+ expected_msg = (
+ u"'foo@xxxxxxxxxxx<script>"
+ "window.alert('XSS')</script>'"
+ " doesn't seem to be a valid email address.")
+ self._assertEmailAndError(xss_email, expected_msg)
+
class PersonAdministerViewTestCase(TestPersonRenameFormMixin,
TestCaseWithFactory):
=== removed file 'lib/lp/registry/stories/person/xx-add-email.txt'
--- lib/lp/registry/stories/person/xx-add-email.txt 2012-04-11 15:48:20 +0000
+++ lib/lp/registry/stories/person/xx-add-email.txt 1970-01-01 00:00:00 +0000
@@ -1,187 +0,0 @@
-= Registering email addresses =
-
-Users can have any number of email addresses registered in their Launchpad
-accounts, although we'll always communicate with them using their preferred
-one. In order to register a new email address users must follow a link sent
-by us to the address they want to add and confirm the registration.
-
-Sample Person will now add a couple email addresses to his account.
-
- >>> from lp.services.mail import stub
-
- >>> orig_email = 'test@xxxxxxxxxxxxx'
- >>> browser = setupBrowser(auth='Basic %s:test' % orig_email)
- >>> browser.open('http://launchpad.dev/~name12')
- >>> browser.getLink(url='+editemails').click()
- >>> browser.url
- 'http://launchpad.dev/~name12/+editemails'
-
- >>> new_email = 'test2@xxxxxxxxxxxxx'
- >>> browser.getControl('Add a new address').value = new_email
- >>> browser.getControl('Add', index=1).click()
-
- >>> browser.url
- 'http://launchpad.dev/%7Ename12/+editemails'
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- A confirmation message has been sent to...
-
-There should be an email for the new address and one for the original
-preferred email address that the change was made to their account. Order gets
-mixed up so you have to check both spots.
-
- >>> to_addrs = [to_addr for from_addr, to_addr, msg in stub.test_emails]
- >>> assert len(to_addrs) == 2
- >>> if orig_email in to_addrs[0][0]:
- ... assert new_email in to_addrs[1][0]
- ... else:
- ... assert new_email in to_addrs[0][0]
- ... assert orig_email in to_addrs[1][0]
- >>> stub.test_emails = []
-
-Trying to add the same email again (while it's unconfirmed) will only cause
-a new email to be sent with a new link. The links in the old and new email are
-still accessible and will confirm the new address if/when the user follows
-them.
-
- >>> browser.getControl('Add a new address').value = 'test2@xxxxxxxxxxxxx'
- >>> browser.getControl('Add', index=1).click()
-
- >>> browser.url
- 'http://launchpad.dev/%7Ename12/+editemails'
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- A confirmation message has been sent to...
-
- # Extract the link (from the email we just sent) the user will have to
- # use to finish the registration process. There will be two emails so we
- # must check them both in order to make sure it's sent.
- >>> from lp.services.verification.tests.logintoken import (
- ... get_token_url_from_email)
- >>> def check_tokenemail_and_reset():
- ... found, url, toaddr = False, None, None
- ... for from_addr, to_addrs, raw_msg in stub.test_emails:
- ... if 'token' in raw_msg:
- ... found = True
- ... url = get_token_url_from_email(raw_msg)
- ... toaddr = to_addrs
- ... assert found
- ... return url, toaddr
- >>> token_url, toaddrs = check_tokenemail_and_reset()
- >>> token_url
- 'http://launchpad.dev/token/...'
- >>> toaddrs
- ['test2@xxxxxxxxxxxxx']
-
-Follow the token link, to confirm the new email address.
-
- >>> browser.open(token_url)
- >>> browser.url
- 'http://launchpad.dev/token/.../+validateemail'
- >>> browser.getControl('Continue').click()
-
- >>> browser.url
- 'http://launchpad.dev/~name12'
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- Email address successfully confirmed.
-
-Now that the address is confirmed he sees it in the list of his confirmed
-addresses.
-
- >>> from lp.testing.pages import strip_label
-
- >>> browser.getLink(url='+editemails').click()
- >>> confirmed = browser.getControl(name="field.VALIDATED_SELECTED")
- >>> [strip_label(option) for option in confirmed.displayOptions]
- ['test@xxxxxxxxxxxxx', 'test2@xxxxxxxxxxxxx', 'testing@xxxxxxxxxxxxx']
-
-If he tries to add it again, he'll get an error message explaining
-that it's already registered.
-
- >>> browser.getControl('Add a new address').value = 'test2@xxxxxxxxxxxxx'
- >>> browser.getControl('Add', index=1).click()
- >>> browser.url
- 'http://launchpad.dev/%7Ename12/+editemails'
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- There is 1 error.
- The email address 'test2@xxxxxxxxxxxxx' is already registered as your
- email address...
-
-
-== Adding a second email address ==
-
- >>> browser.getControl('Add a new address').value = 'sample@xxxxxxxxxx'
- >>> browser.getControl('Add', index=1).click()
-
- >>> browser.url
- 'http://launchpad.dev/%7Ename12/+editemails'
- >>> for tag in find_tags_by_class(browser.contents, 'message'):
- ... print tag.renderContents()
- A confirmation message has been sent to...
-
- # Extract the link (from the email we just sent) the user will have to
- # use to finish the registration process.
- >>> token_url, toaddrs = check_tokenemail_and_reset()
- >>> token_url
- 'http://launchpad.dev/token/...'
- >>> toaddrs
- ['sample@xxxxxxxxxx']
-
-Follow the token link, to confirm the new email address.
-
- >>> browser.open(token_url)
- >>> browser.url
- 'http://launchpad.dev/token/.../+validateemail'
- >>> browser.getControl('Continue').click()
-
- >>> browser.url
- 'http://launchpad.dev/~name12'
-
- >>> for tag in find_tags_by_class(browser.contents, 'informational'):
- ... print tag.renderContents()
- Email address successfully confirmed.
-
-
-== Trying to register an already registered email address ==
-
-Email addresses can not be registered more than once in Launchpad, so if
-a given email address is registered by Joe, then Sample Person won't be
-able to register it for himself. When that happens we tell the user the
-email is already registered and explain he may want to merge the other
-account if that's a duplicate.
-
- >>> login(ANONYMOUS)
- >>> person = factory.makePerson(email='joe@xxxxxxxxxx')
- >>> person_with_hidden_emails = factory.makePerson(
- ... email='joe2@xxxxxxxxxx', hide_email_addresses=True)
- >>> logout()
- >>> browser.open('http://launchpad.dev/~name12/+editemails')
- >>> browser.getControl('Add a new address').value = 'joe@xxxxxxxxxx'
- >>> browser.getControl('Add', index=1).click()
- >>> print "\n".join(get_feedback_messages(browser.contents))
- There is 1 error.
- The email address 'joe@xxxxxxxxxx' is already registered...
- If you think that is a duplicated account, you can merge it...
-
- >>> browser.open('http://launchpad.dev/~name12/+editemails')
- >>> browser.getControl('Add a new address').value = 'joe2@xxxxxxxxxx'
- >>> browser.getControl('Add', index=1).click()
- >>> print "\n".join(get_feedback_messages(browser.contents))
- There is 1 error.
- The email address 'joe2@xxxxxxxxxx' is already registered...
- If you think that is a duplicated account, you can merge it...
-
-If someone tries to add an already registered email address for a team,
-a similar error will be shown.
-
- >>> browser.open(
- ... 'http://launchpad.dev/~landscape-developers/+contactaddress')
- >>> browser.getControl('Another e-mail address').selected = True
- >>> browser.getControl(
- ... name='field.contact_address').value = 'joe2@xxxxxxxxxx'
- >>> browser.getControl('Change').click()
- >>> print "\n".join(get_feedback_messages(browser.contents))
- There is 1 error.
- joe2@xxxxxxxxxx is already registered in Launchpad...
=== removed file 'lib/lp/registry/stories/person/xx-person-delete-email.txt'
--- lib/lp/registry/stories/person/xx-person-delete-email.txt 2008-08-28 13:19:44 +0000
+++ lib/lp/registry/stories/person/xx-person-delete-email.txt 1970-01-01 00:00:00 +0000
@@ -1,23 +0,0 @@
-= Removing an email address =
-
-Any email address other than the preferred one can be removed from
-a person's +editemails page.
-
- >>> browser = setupBrowser(auth='Basic test@xxxxxxxxxxxxx:test')
- >>> browser.open('http://launchpad.dev/~name12/+editemails')
- >>> browser.getControl('test@xxxxxxxxxxxxx').selected = True
- >>> browser.getControl('Remove', index=0).click()
- >>> print "\n".join(get_feedback_messages(browser.contents))
- There is 1 error.
- You can't remove test@xxxxxxxxxxxxx because it's your contact email
- address.
-
- >>> browser.getControl('testing@xxxxxxxxxxxxx').selected = True
- >>> browser.getControl('Remove', index=0).click()
- >>> print "\n".join(get_feedback_messages(browser.contents))
- The email address 'testing@xxxxxxxxxxxxx' has been removed.
-
- >>> browser.getControl('testing@xxxxxxxxxxxxx')
- Traceback (most recent call last):
- ...
- LookupError: label 'testing@xxxxxxxxxxxxx'
=== removed file 'lib/lp/registry/stories/person/xx-set-preferredemail.txt'
--- lib/lp/registry/stories/person/xx-set-preferredemail.txt 2010-06-18 23:25:36 +0000
+++ lib/lp/registry/stories/person/xx-set-preferredemail.txt 1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
-================================
-A person's contact email address
-================================
-
-A person may have many confirmed email address which he may use to
-login with, but only one email address will be the contact email
-address.
-
-
-Setting the contact email address
-=================================
-
-Sample Person chooses to change his contact email address to the
-address he prefers to login with.
-
- >>> browser = setupBrowser(auth='Basic testing@xxxxxxxxxxxxx:test')
- >>> browser.open('http://launchpad.dev/~name12')
- >>> browser.getLink(url='+editemails').click()
- >>> print browser.url
- http://launchpad.dev/~name12/+editemails
- >>> print browser.title
- Change your e-mail settings...
-
-Sample Person has a second browser open to the same page; maybe he is
-absent minded.
-
- >>> second_browser = setupBrowser(auth='Basic testing@xxxxxxxxxxxxx:test')
- >>> second_browser.open('http://launchpad.dev/~name12/+editemails')
-
-His confirmed email addresses are listed for him to manage. His
-contact email address is selected, and always first.
-
- >>> print_radio_button_field(browser.contents, "VALIDATED_SELECTED")
- (*) test@xxxxxxxxxxxxx
- ( ) testing@xxxxxxxxxxxxx
-
-Sample Persons selects his testing email address and submits his choice
-with the "Set as Contact Address" button.
-
- >>> browser.getControl('testing@xxxxxxxxxxxxx').selected = True
- >>> browser.getControl('Set as Contact Address').click()
-
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- Your contact address has been changed to: testing@xxxxxxxxxxxxx
-
-His testing email address is now first in the list and selected
-as his contact address.
-
- >>> print_radio_button_field(browser.contents, "VALIDATED_SELECTED")
- (*) testing@xxxxxxxxxxxxx
- ( ) test@xxxxxxxxxxxxx
-
-In a moment of deja vu, Sample Person returns to his second browser,
-selects his testing email address again, then submits his choice. There
-is no change; he sees a message explaining that testing was already his
-contact address.
-
- >>> second_browser.getControl('testing@xxxxxxxxxxxxx').selected = True
- >>> second_browser.getControl('Set as Contact Address').click()
-
- >>> for msg in get_feedback_messages(second_browser.contents):
- ... print msg
- testing@xxxxxxxxxxxxx is already set as your contact address.
=== removed file 'lib/lp/registry/stories/person/xx-validate-email.txt'
--- lib/lp/registry/stories/person/xx-validate-email.txt 2012-04-11 14:40:02 +0000
+++ lib/lp/registry/stories/person/xx-validate-email.txt 1970-01-01 00:00:00 +0000
@@ -1,150 +0,0 @@
-===========================
-Validating an email address
-===========================
-
-The user 'salgado' has an unvalidated email address that was probably
-added by gina. Now he wants to validate it.
-
- # Workaround for https://launchpad.net/launchpad/+bug/39016
- >>> from lp.services.mail import stub
- >>> stub.test_emails[:] = []
-
- >>> browser = setupBrowser(auth='Basic salgado@xxxxxxxxxx:test')
- >>> browser.open('http://launchpad.dev/~salgado/+editemails')
- >>> print browser.title
- Change your e-mail settings...
-
- >>> browser.getControl(name="field.UNVALIDATED_SELECTED").getControl(
- ... value='salgado@xxxxxxxxxx').selected = True
- >>> browser.getControl('Confirm').click()
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- An e-mail message was sent to 'salgado@xxxxxxxxxx'...
-
-Retrieve the email and make sure it was sent to the right address.
-
- >>> import email
- >>> found = False
- >>> raw_msg = None
- >>> for from_addr, to_addrs, orig_msg in stub.test_emails:
- ... msg = email.message_from_string(orig_msg)
- ... if msg.get('to') == 'salgado@xxxxxxxxxx':
- ... raw_msg = orig_msg
- ... found = True
- >>> assert found
-
-Visit the token URL mentioned in the email, and get redirected to
-+validateemail.
-
- >>> from lp.services.verification.tests.logintoken import (
- ... get_token_url_from_email)
- >>> token_url = get_token_url_from_email(raw_msg)
- >>> browser.open(token_url)
-
- >>> print browser.url
- http://launchpad.dev/token/.../+validateemail
- >>> print browser.title
- Confirm e-mail address
-
- >>> print extract_text(find_main_content(browser.contents))
- Confirm e-mail address
- Confirm e-mail address salgado@xxxxxxxxxx
-
- >>> browser.getControl('Continue').click()
- >>> print browser.title
- Guilherme Salgado in Launchpad
-
-Check that the email address now shows up as validated.
-
- >>> browser.getLink(url='+editemails').click()
- >>> browser.getControl(name="field.VALIDATED_SELECTED").getControl(
- ... value='salgado@xxxxxxxxxx')
- <ItemControl...optionValue='salgado@xxxxxxxxxx'...>
-
- >>> browser.getControl(name="field.UNVALIDATED_SELECTED").getControl(
- ... value='salgado@xxxxxxxxxx')
- Traceback (most recent call last):
- ...
- LookupError...
-
-An email address that the user adds manually should have the same
-validation workflow as an email address guessed by the system and
-added by gina.
-
- >>> browser.getControl('Add a new address').value = 'salgado@xxxxxxxxxxx'
- >>> browser.getControl('Add', index=1).click()
- >>> browser.url
- 'http://launchpad.dev/%7Esalgado/+editemails'
-
- >>> browser.getControl(name="field.UNVALIDATED_SELECTED").getControl(
- ... value='salgado@xxxxxxxxxxx').selected = True
- >>> browser.getControl('Confirm').click()
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- An e-mail message was sent to 'salgado@xxxxxxxxxxx'...
-
-
-Validating the email address string
-===================================
-
-Leaving the email address field blank and hitting the 'Add' button
-should display an error message.
-
- >>> browser.getControl('Add a new address').value
- ''
-
- >>> browser.getControl('Add', index=1).click()
- >>> print browser.title
- Change your e-mail settings...
-
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- There is 1 error.
- Required input is missing.
-
-Entering a string that does not look like an email address causes an
-error to be displayed.
-
- >>> print browser.title
- Change your e-mail settings...
-
- >>> browser.getControl('Add a new address').value = 'foo'
- >>> browser.getControl('Add', index=1).click()
- >>> print browser.title
- Change your e-mail settings...
-
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- There is 1 error.
- 'foo' doesn't seem to be a valid email address.
-
-Markup in new addresses is escaped in error messages so that it cannot
-be interpreted by the browser. Scripts that are embedded in the address
-will not run. A malicious hacker cannot use a XSS vulnerability to gain
-information about Launchpad users.
-
- >>> print browser.title
- Change your e-mail settings...
-
- >>> browser.getControl('Add a new address').value = (
- ... "salgado@xxxxxxxxxxx<br/><script>window.alert('XSS')</script>")
- >>> browser.getControl('Add', index=1).click()
- >>> for msg in get_feedback_messages(browser.contents):
- ... print msg
- There is 1 error.
- 'salgado...com<br/><script>window.alert('XSS')</script>'
- doesn't seem to be a valid email address.
-
-
-+editemails for teams
-=====================
-
-Because people and teams share the same namespace, it used to be possible to
-hack the url to get to a team's +editemails page. This makes no sense, and
-for teams you should use the +contactaddress url. The +editemails page is no
-longer available for teams.
-
- >>> browser.open('http://launchpad.dev/~guadamen/+editemails')
- Traceback (most recent call last):
- ...
- NotFound: Object: <...>, name: u'+editemails'
Follow ups