Merge lp:~canonical-isd-hackers/canonical-identity-provider/862944-preferred-email-constraint into lp:canonical-identity-provider/release

Proposed by Simon Davy
Status: Merged
Approved by: Ricardo Kirkner
Approved revision: no longer in the source branch.
Merged at revision: 238
Proposed branch: lp:~canonical-isd-hackers/canonical-identity-provider/862944-preferred-email-constraint
Merge into: lp:canonical-identity-provider/release
Diff against target: 130 lines (+55/-12)
2 files modified
identityprovider/models/account.py (+25/-9)
identityprovider/tests/test_models_account.py (+30/-3)
To merge this branch: bzr merge lp:~canonical-isd-hackers/canonical-identity-provider/862944-preferred-email-constraint
Reviewer Review Type Date Requested Status
Ricardo Kirkner (community) Approve
Review via email: mp+83053@code.launchpad.net

Commit message

Fixes 862944 by also looking for old LP emails to use for the preferred email

Description of the change

Fix for bug https://bugs.launchpad.net/canonical-identity-provider/+bug/862944

Problem arising from SSO model identity crisis:
  - user has account '1' with no PREFERRED emails
  - account '1' is linked to person 'A'
  - person 'A' also has links to account '2'
  - there is a preferred email for set for person 'A' for account '2'
  - when attempting to log in to account '1', code attempts to set the latest account '1' email to PREFERRED
  - but there is a constraint that a Person can only have one preferred email - see bug

This fixes the issue by checking both Account and Person for preferred emails.

The only question I have is whether it is valid to use a Person-based email (from another account) as the preferred email? Should we also be changing/removing the additional constraint?

To post a comment you must log in.
Revision history for this message
Simon Davy (bloodearnest) wrote :

hmm - I don't think this is ready yet. Need to add some tests and think through implications of using an email that is the preferred email for to a different account for the same person

Revision history for this message
Simon Davy (bloodearnest) wrote :

> hmm - I don't think this is ready yet. Need to add some tests and think
> through implications of using an email that is the preferred email for to a
> different account for the same person

Done!

Revision history for this message
Ricardo Kirkner (ricardokirkner) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'identityprovider/models/account.py'
2--- identityprovider/models/account.py 2011-08-25 14:10:04 +0000
3+++ identityprovider/models/account.py 2011-11-24 13:59:26 +0000
4@@ -1,18 +1,21 @@
5 # Copyright 2010 Canonical Ltd. This software is licensed under the
6 # GNU Affero General Public License version 3 (see the file LICENSE).
7-
8+import logging
9 from datetime import date, datetime, timedelta
10
11 from django.conf import settings
12 from django.contrib.auth import get_backends
13 from django.contrib.auth.models import User
14 from django.db import models
15+from django.db.models import Q
16 from django.utils.translation import ugettext_lazy as _
17
18 from oauth_backend.models import Consumer
19
20 from identityprovider.models.const import (AccountCreationRationale,
21 AccountStatus, EmailStatus)
22+
23+
24 from identityprovider.utils import (
25 encrypt_launchpad_password,
26 generate_openid_identifier,
27@@ -130,22 +133,35 @@
28 return sites.order_by('-date_last_used')
29
30 def _get_preferredemail(self):
31+ # import here to avoid circular dependancy issue
32+ from identityprovider.models.emailaddress import EmailAddress
33 if not hasattr(self, '_preferredemail'):
34 try:
35- self._preferredemail = self.emailaddress_set.filter(
36- status=EmailStatus.PREFERRED)[0]
37- except IndexError:
38- # Try to determine a suitable address, and mark it as preferred
39- try:
40+ # note emails coming via self.person are legacy pre-sso
41+ # launchpad emails
42+ account_emails = self.emailaddress_set.filter(
43+ status=EmailStatus.PREFERRED)
44+ if account_emails.count() > 0:
45+ self._preferredemail = account_emails[0]
46+ elif self.person:
47+ self._preferredemail = self.person.emailaddress_set.filter(
48+ status=EmailStatus.PREFERRED)[0]
49+ logging.warn("Old LP email used as preferred email, "
50+ "needs migrating. Account id: %s" % self.id)
51+ else:
52+ # Try to determine a suitable address, and mark it as preferred
53+ # note: we don't try to make a person-based email preferred
54 emails = self.emailaddress_set.filter(
55 status=EmailStatus.VALIDATED)
56 email = emails.order_by('date_created')[0]
57 email.status = EmailStatus.PREFERRED
58 email.save()
59+ logging.info(
60+ "Updating preferred email for account %s" % self.id)
61 self._preferredemail = email
62- except IndexError:
63- # Now we really don't have anything
64- self._preferredemail = None
65+ except IndexError:
66+ # Now we really don't have anything
67+ self._preferredemail = None
68 return self._preferredemail
69
70 def _set_preferredemail(self, email):
71
72=== modified file 'identityprovider/tests/test_models_account.py'
73--- identityprovider/tests/test_models_account.py 2011-07-27 13:00:22 +0000
74+++ identityprovider/tests/test_models_account.py 2011-11-24 13:59:26 +0000
75@@ -11,9 +11,10 @@
76 from oauth_backend.models import Consumer
77
78 from identityprovider.models.account import (Account, AccountPassword,
79- AccountStatus)
80+ AccountStatus, LPOpenIdIdentifier)
81 from identityprovider.models import account as a
82 from identityprovider.models.emailaddress import EmailAddress
83+from identityprovider.models.person import Person
84 from identityprovider.models.const import AccountCreationRationale, EmailStatus
85 from identityprovider.readonly import ReadOnlyManager
86 from identityprovider.utils import encrypt_launchpad_password, generate_salt
87@@ -194,8 +195,6 @@
88
89 def test_validated_email_address_is_preferred_email_by_default(self):
90 account = self.create_account()
91- EmailAddress.objects.filter(
92- email__iexact='foobar@canonical.com').delete()
93 email_address = account.emailaddress_set.create(
94 email='foobar@canonical.com',
95 status=EmailStatus.VALIDATED)
96@@ -204,6 +203,34 @@
97 email_address = EmailAddress.objects.get(pk=email_address.id)
98 self.assertEqual(email_address.status, EmailStatus.PREFERRED)
99
100+ def test_person_email_address_is_preferred_email(self):
101+ account = self.create_account()
102+ account.emailaddress_set.create(
103+ email='foobar@canonical.com',
104+ status=EmailStatus.VALIDATED)
105+ # account is set up with validated email
106+
107+ # now set up person with preferred email, but no account
108+ person = Person.objects.create(
109+ name="Sample",
110+ lp_account=100)
111+
112+ # link person to account
113+ LPOpenIdIdentifier.objects.create(
114+ identifier=account.openid_identifier,
115+ lp_account=person.lp_account)
116+
117+ # add an address to the person, but NOT the account
118+ EmailAddress.objects.create(
119+ email='pref@bar.com',
120+ account=None,
121+ lp_person=person,
122+ status=EmailStatus.PREFERRED
123+ )
124+
125+ self.assertEqual(account.preferredemail.email, 'pref@bar.com')
126+
127+
128 def test_verified_emails_has_preferred_first(self):
129 account = Account.objects.get_by_email('test@canonical.com')
130 emails = account.verified_emails()