Merge lp:~matiasb/canonical-identity-provider/add-verified-manager into lp:canonical-identity-provider/release

Proposed by Matias Bordese
Status: Merged
Approved by: Ricardo Kirkner
Approved revision: no longer in the source branch.
Merged at revision: 689
Proposed branch: lp:~matiasb/canonical-identity-provider/add-verified-manager
Merge into: lp:canonical-identity-provider/release
Diff against target: 187 lines (+66/-6)
5 files modified
identityprovider/models/account.py (+11/-3)
identityprovider/models/emailaddress.py (+9/-2)
identityprovider/tests/unit/test_models_account.py (+24/-0)
identityprovider/tests/unit/test_models_emailaddress.py (+21/-1)
requirements/config-manager.txt (+1/-0)
To merge this branch: bzr merge lp:~matiasb/canonical-identity-provider/add-verified-manager
Reviewer Review Type Date Requested Status
Ricardo Kirkner (community) Approve
Review via email: mp+151062@code.launchpad.net

Commit message

Added verified queryset option to Account and EmailAddress managers.

Description of the change

Added verified queryset option to Account and EmailAddress managers.
Added model-utils requirement.

To post a comment you must log in.
Revision history for this message
Ricardo Kirkner (ricardokirkner) wrote :

LGTM, except that the new dependency needs to be added for production. As this dependency is not packaged in Ubuntu yet, we need to add it as a sourcedep.

review: Needs Fixing
Revision history for this message
Matias Bordese (matiasb) wrote :

> LGTM, except that the new dependency needs to be added for production. As this
> dependency is not packaged in Ubuntu yet, we need to add it as a sourcedep.

Added django-model-utils as sourcedep.
Just notice that I needed to fall back to previous stable version (1.1, revno 110) because there was a bug in 1.2 that breaks our code (solved in master ~17 days ago, https://github.com/carljm/django-model-utils/issues/24).

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 2013-02-27 21:03:58 +0000
3+++ identityprovider/models/account.py 2013-02-28 21:28:19 +0000
4@@ -13,6 +13,7 @@
5 from django.db import models
6 from django.db.models.query import EmptyQuerySet
7 from django.utils.translation import ugettext_lazy as _
8+from model_utils.managers import PassThroughManager
9 from oauth_backend.models import Consumer
10 from south.modelsinspector import add_introspection_rules
11
12@@ -44,7 +45,14 @@
13 ]
14
15
16-class AccountManager(models.Manager):
17+class AccountQuerySet(models.query.QuerySet):
18+ def verified(self):
19+ return self.filter(
20+ emailaddress__status__in=(EmailStatus.VALIDATED,
21+ EmailStatus.PREFERRED)).distinct()
22+
23+
24+class AccountManager(PassThroughManager):
25 """Extend the default manager.
26
27 Add a method that takes care of creating an Account, and the necessary
28@@ -109,7 +117,7 @@
29 account = get_account(user)
30 if account is None:
31 try:
32- account = Account.objects.get(openid_identifier=user.username)
33+ account = self.get(openid_identifier=user.username)
34 except Account.DoesNotExist:
35 pass
36 return account
37@@ -149,7 +157,7 @@
38 twofactor_attempts = models.SmallIntegerField(default=0, null=True)
39 warn_about_backup_device = models.BooleanField(default=True)
40
41- objects = AccountManager()
42+ objects = AccountManager.for_queryset_class(AccountQuerySet)()
43
44 class Meta:
45 app_label = 'identityprovider'
46
47=== modified file 'identityprovider/models/emailaddress.py'
48--- identityprovider/models/emailaddress.py 2013-02-18 16:36:33 +0000
49+++ identityprovider/models/emailaddress.py 2013-02-28 21:28:19 +0000
50@@ -10,6 +10,7 @@
51 from django.db import models
52 from django.template.defaultfilters import force_escape
53 from django.utils.translation import ugettext_lazy as _
54+from model_utils.managers import PassThroughManager
55
56 from identityprovider.models import Account
57 from identityprovider.models.const import EmailStatus
58@@ -24,7 +25,13 @@
59 re.IGNORECASE)
60
61
62-class EmailAddressManager(models.Manager):
63+class EmailAddressQuerySet(models.query.QuerySet):
64+ def verified(self):
65+ return self.filter(
66+ status__in=(EmailStatus.VALIDATED, EmailStatus.PREFERRED))
67+
68+
69+class EmailAddressManager(PassThroughManager):
70
71 def _generate_email_from_phone_id(self, phone_id):
72 # replace chars not validated by django validate_email by #
73@@ -54,7 +61,7 @@
74 account = models.ForeignKey(
75 Account, db_column='account', blank=True, null=True)
76
77- objects = EmailAddressManager()
78+ objects = EmailAddressManager.for_queryset_class(EmailAddressQuerySet)()
79
80 class Meta:
81 app_label = 'identityprovider'
82
83=== modified file 'identityprovider/tests/unit/test_models_account.py'
84--- identityprovider/tests/unit/test_models_account.py 2013-02-27 21:03:58 +0000
85+++ identityprovider/tests/unit/test_models_account.py 2013-02-28 21:28:19 +0000
86@@ -25,6 +25,7 @@
87 from identityprovider.models.account import (
88 Account,
89 AccountPassword,
90+ AccountQuerySet,
91 )
92 from identityprovider.models import account as a
93 from identityprovider.models.emailaddress import EmailAddress
94@@ -54,6 +55,19 @@
95 return self.value
96
97
98+class AccountQuerySetTestCase(SSOBaseTestCase):
99+
100+ def setUp(self):
101+ super(AccountQuerySetTestCase, self).setUp()
102+ self.qs = AccountQuerySet(model=Account)
103+
104+ def test_verified_list_only_verified_accounts(self):
105+ accounts = self.qs.verified()
106+ for account in accounts:
107+ emails = account.emailaddress_set.all()
108+ self.assertTrue(any([email.is_verified() for email in emails]))
109+
110+
111 class AccountManagerTestCase(SSOBaseTestCase):
112
113 def test_objects_get_by_email_fails(self):
114@@ -179,6 +193,16 @@
115 else:
116 self.assertIsNone(result)
117
118+ def test_verified_list_only_verified_accounts(self):
119+ accounts = Account.objects.verified()
120+ for account in accounts:
121+ emails = account.emailaddress_set.all()
122+ self.assertTrue(any([email.is_verified() for email in emails]))
123+
124+ def test_verified_no_duplicates(self):
125+ accounts = Account.objects.verified()
126+ self.assertEqual(accounts.count(), accounts.distinct().count())
127+
128
129 class AccountTestCase(SSOBaseTestCase):
130
131
132=== modified file 'identityprovider/tests/unit/test_models_emailaddress.py'
133--- identityprovider/tests/unit/test_models_emailaddress.py 2013-02-14 20:55:54 +0000
134+++ identityprovider/tests/unit/test_models_emailaddress.py 2013-02-28 21:28:19 +0000
135@@ -2,10 +2,25 @@
136
137 from identityprovider.models import Account, EmailAddress
138 from identityprovider.models.const import EmailStatus
139-from identityprovider.models.emailaddress import PHONE_EMAIL_DOMAIN
140+from identityprovider.models.emailaddress import (
141+ PHONE_EMAIL_DOMAIN,
142+ EmailAddressQuerySet,
143+)
144 from identityprovider.tests.utils import SSOBaseTestCase
145
146
147+class EmailAddressQuerySetTestCase(SSOBaseTestCase):
148+
149+ def setUp(self):
150+ super(EmailAddressQuerySetTestCase, self).setUp()
151+ self.qs = EmailAddressQuerySet(model=EmailAddress)
152+
153+ def test_verified_list_only_verified_emails(self):
154+ emails = self.qs.verified()
155+ for email in emails:
156+ self.assertTrue(email.is_verified())
157+
158+
159 class EmailAddressManagerTestCase(SSOBaseTestCase):
160 fixtures = ['test']
161
162@@ -29,6 +44,11 @@
163 EmailAddress.DoesNotExist,
164 EmailAddress.objects.get_from_phone_id, 'tel:+123')
165
166+ def test_verified(self):
167+ emails = EmailAddress.objects.verified()
168+ for email in emails:
169+ self.assertTrue(email.is_verified())
170+
171
172 class EmailAddressTestCase(SSOBaseTestCase):
173 fixtures = ['test']
174
175=== added symlink 'lib/model_utils'
176=== target is u'../branches/django-model-utils/model_utils'
177=== modified file 'requirements/config-manager.txt'
178--- requirements/config-manager.txt 2013-02-22 12:16:54 +0000
179+++ requirements/config-manager.txt 2013-02-28 21:28:19 +0000
180@@ -4,6 +4,7 @@
181 ./branches/django-pgtools bzr+ssh://bazaar.launchpad.net/~canonical-isd-hackers/django-pgtools/trunk;revno=7
182
183 # Upstream dependencies
184+./branches/django-model-utils bzr+ssh://bazaar.launchpad.net/~ubuntuone-pqm-team/django-model-utils/stable;revno=110
185 ./branches/django-modeldict bzr+ssh://bazaar.launchpad.net/~ubuntuone-pqm-team/django-modeldict/stable;revno=1.4.1
186 ./branches/oauthlib bzr+ssh://bazaar.launchpad.net/~ubuntuone-pqm-team/oauthlib/stable;revno=0.3.7
187 ./branches/requests bzr+ssh://bazaar.launchpad.net/~ubuntuone-pqm-team/requests/stable;revno=v1.1.0