Merge lp:~canonical-isd-hackers/canonical-identity-provider/sql-limit-for-openid-transactions into lp:canonical-identity-provider/release
- sql-limit-for-openid-transactions
- Merge into trunk
Proposed by
Łukasz Czyżykowski
Status: | Merged |
---|---|
Approved by: | Ricardo Kirkner |
Approved revision: | no longer in the source branch. |
Merged at revision: | 225 |
Proposed branch: | lp:~canonical-isd-hackers/canonical-identity-provider/sql-limit-for-openid-transactions |
Merge into: | lp:canonical-identity-provider/release |
Diff against target: |
446 lines (+120/-71) 10 files modified
identityprovider/auth.py (+1/-1) identityprovider/forms.py (+8/-11) identityprovider/models/account.py (+21/-15) identityprovider/models/openidmodels.py (+33/-11) identityprovider/models/team.py (+15/-15) identityprovider/tests/test_models_openidmodels.py (+5/-9) identityprovider/tests/test_views_server.py (+16/-1) identityprovider/tests/test_views_ui.py (+4/-0) identityprovider/views/server.py (+1/-1) identityprovider/views/utils.py (+16/-7) |
To merge this branch: | bzr merge lp:~canonical-isd-hackers/canonical-identity-provider/sql-limit-for-openid-transactions |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Canonical ISD hackers | Pending | ||
Review via email:
|
Commit message
Database access improvements during OpenID transaction.
Description of the change
Overview
========
This branch limits number of SQL queries executed while processing OpenID transaction.
Improvement
===========
During an OpenID request, with all possible SReg fields and Teams extension, before this branch, there are 28 SQL queries executed. With this branch, that number is down to 12. The raw speed improvement is hard to quantify, as it requires database configured in very similar way as the production one.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'identityprovider/auth.py' | |||
2 | --- identityprovider/auth.py 2011-07-27 13:00:22 +0000 | |||
3 | +++ identityprovider/auth.py 2011-09-06 14:43:24 +0000 | |||
4 | @@ -11,7 +11,7 @@ | |||
5 | 11 | 11 | ||
6 | 12 | from identityprovider.models import Account, AccountPassword | 12 | from identityprovider.models import Account, AccountPassword |
7 | 13 | from identityprovider.models.api import APIUser | 13 | from identityprovider.models.api import APIUser |
9 | 14 | from identityprovider.models.const import EmailStatus, AccountStatus | 14 | from identityprovider.models.const import EmailStatus |
10 | 15 | from identityprovider.utils import ( | 15 | from identityprovider.utils import ( |
11 | 16 | validate_launchpad_password, get_object_or_none) | 16 | validate_launchpad_password, get_object_or_none) |
12 | 17 | 17 | ||
13 | 18 | 18 | ||
14 | === modified file 'identityprovider/forms.py' | |||
15 | --- identityprovider/forms.py 2011-08-25 13:26:06 +0000 | |||
16 | +++ identityprovider/forms.py 2011-09-06 14:43:24 +0000 | |||
17 | @@ -418,7 +418,7 @@ | |||
18 | 418 | """Get the list of teams actually approved by the user for the request. | 418 | """Get the list of teams actually approved by the user for the request. |
19 | 419 | """ | 419 | """ |
20 | 420 | if self.request_method == 'POST': | 420 | if self.request_method == 'POST': |
22 | 421 | return [t for t in self.data if t in self.request.POST] | 421 | return [t for t in self.memberships if t in self.request.POST] |
23 | 422 | else: | 422 | else: |
24 | 423 | return [] | 423 | return [] |
25 | 424 | 424 | ||
26 | @@ -428,16 +428,13 @@ | |||
27 | 428 | self.teams_request = teams_request | 428 | self.teams_request = teams_request |
28 | 429 | self.rpconfig = rpconfig | 429 | self.rpconfig = rpconfig |
29 | 430 | self.approved_data = approved_data | 430 | self.approved_data = approved_data |
40 | 431 | self.data = self._get_teams_for_user(request.user, | 431 | self.memberships = self._get_teams_for_user( |
41 | 432 | rpconfig and rpconfig.can_query_any_team) | 432 | request.user, rpconfig and rpconfig.can_query_any_team) |
42 | 433 | 433 | ||
43 | 434 | super(TeamsRequestForm, self).__init__(self.data) | 434 | super(TeamsRequestForm, self).__init__(self.memberships) |
44 | 435 | self._init_fields(self.data) | 435 | |
45 | 436 | all_teams = self.teams_request.allRequestedTeams() | 436 | self._init_fields(self.memberships) |
46 | 437 | membership = TeamMembership.get_team_memberships_for_user( | 437 | self.should_display = len(self.memberships) > 0 |
37 | 438 | all_teams, self.request.user, | ||
38 | 439 | self.rpconfig and self.rpconfig.can_query_any_team) | ||
39 | 440 | self.should_display = len(membership) > 0 | ||
47 | 441 | 438 | ||
48 | 442 | def _get_teams_for_user(self, user, include_private=False): | 439 | def _get_teams_for_user(self, user, include_private=False): |
49 | 443 | """Get the list of teams to ask about in the form based on the user's | 440 | """Get the list of teams to ask about in the form based on the user's |
50 | 444 | 441 | ||
51 | === modified file 'identityprovider/models/account.py' | |||
52 | --- identityprovider/models/account.py 2011-07-27 13:00:22 +0000 | |||
53 | +++ identityprovider/models/account.py 2011-09-06 14:43:24 +0000 | |||
54 | @@ -130,20 +130,23 @@ | |||
55 | 130 | return sites.order_by('-date_last_used') | 130 | return sites.order_by('-date_last_used') |
56 | 131 | 131 | ||
57 | 132 | def _get_preferredemail(self): | 132 | def _get_preferredemail(self): |
63 | 133 | try: | 133 | if not hasattr(self, '_preferredemail'): |
59 | 134 | return self.emailaddress_set.filter( | ||
60 | 135 | status=EmailStatus.PREFERRED)[0] | ||
61 | 136 | except IndexError: | ||
62 | 137 | # Try to determine a suitable address, and mark it as preferred | ||
64 | 138 | try: | 134 | try: |
70 | 139 | email = self.emailaddress_set.filter( | 135 | self._preferredemail = self.emailaddress_set.filter( |
71 | 140 | status=EmailStatus.VALIDATED).order_by('date_created')[0] | 136 | status=EmailStatus.PREFERRED)[0] |
67 | 141 | email.status = EmailStatus.PREFERRED | ||
68 | 142 | email.save() | ||
69 | 143 | return email | ||
72 | 144 | except IndexError: | 137 | except IndexError: |
75 | 145 | # Now we really don't have anything | 138 | # Try to determine a suitable address, and mark it as preferred |
76 | 146 | return None | 139 | try: |
77 | 140 | emails = self.emailaddress_set.filter( | ||
78 | 141 | status=EmailStatus.VALIDATED) | ||
79 | 142 | email = emails.order_by('date_created')[0] | ||
80 | 143 | email.status = EmailStatus.PREFERRED | ||
81 | 144 | email.save() | ||
82 | 145 | self._preferredemail = email | ||
83 | 146 | except IndexError: | ||
84 | 147 | # Now we really don't have anything | ||
85 | 148 | self._preferredemail = None | ||
86 | 149 | return self._preferredemail | ||
87 | 147 | 150 | ||
88 | 148 | def _set_preferredemail(self, email): | 151 | def _set_preferredemail(self, email): |
89 | 149 | current = self.preferredemail | 152 | current = self.preferredemail |
90 | @@ -152,6 +155,7 @@ | |||
91 | 152 | current.save() | 155 | current.save() |
92 | 153 | email.status = EmailStatus.PREFERRED | 156 | email.status = EmailStatus.PREFERRED |
93 | 154 | email.save() | 157 | email.save() |
94 | 158 | self._preferredemail = email | ||
95 | 155 | 159 | ||
96 | 156 | preferredemail = property(_get_preferredemail, _set_preferredemail) | 160 | preferredemail = property(_get_preferredemail, _set_preferredemail) |
97 | 157 | 161 | ||
98 | @@ -166,9 +170,11 @@ | |||
99 | 166 | lp_account = open_ids[0].lp_account | 170 | lp_account = open_ids[0].lp_account |
100 | 167 | # Importing it here to prevent cyclic import issue | 171 | # Importing it here to prevent cyclic import issue |
101 | 168 | from .person import Person | 172 | from .person import Person |
105 | 169 | persons = Person.objects.filter(lp_account=lp_account) | 173 | try: |
106 | 170 | if len(persons) > 0: | 174 | self._person = Person.objects.select_related( |
107 | 171 | self._person = persons[0] | 175 | 'personlocation').get(lp_account=lp_account) |
108 | 176 | except Person.DoesNotExist: | ||
109 | 177 | pass | ||
110 | 172 | return getattr(self, '_person', None) | 178 | return getattr(self, '_person', None) |
111 | 173 | 179 | ||
112 | 174 | @property | 180 | @property |
113 | 175 | 181 | ||
114 | === modified file 'identityprovider/models/openidmodels.py' | |||
115 | --- identityprovider/models/openidmodels.py 2011-07-27 13:00:22 +0000 | |||
116 | +++ identityprovider/models/openidmodels.py 2011-09-06 14:43:24 +0000 | |||
117 | @@ -2,14 +2,19 @@ | |||
118 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
119 | 3 | 3 | ||
120 | 4 | import base64 | 4 | import base64 |
121 | 5 | import hashlib | ||
122 | 5 | import time | 6 | import time |
123 | 7 | |||
124 | 6 | from datetime import datetime | 8 | from datetime import datetime |
125 | 7 | from openid.association import Association | 9 | from openid.association import Association |
126 | 10 | |||
127 | 8 | import openid.store | 11 | import openid.store |
128 | 9 | import openid.store.nonce | 12 | import openid.store.nonce |
129 | 13 | |||
130 | 10 | from openid.store.interface import OpenIDStore | 14 | from openid.store.interface import OpenIDStore |
131 | 11 | 15 | ||
132 | 12 | from django.conf import settings | 16 | from django.conf import settings |
133 | 17 | from django.core.cache import cache | ||
134 | 13 | from django.db import models | 18 | from django.db import models |
135 | 14 | from django.utils import simplejson as json | 19 | from django.utils import simplejson as json |
136 | 15 | from django.utils.translation import ugettext_lazy as _ | 20 | from django.utils.translation import ugettext_lazy as _ |
137 | @@ -167,6 +172,16 @@ | |||
138 | 167 | def __unicode__(self): | 172 | def __unicode__(self): |
139 | 168 | return self.displayname | 173 | return self.displayname |
140 | 169 | 174 | ||
141 | 175 | @classmethod | ||
142 | 176 | def cache_key(cls, trust_root): | ||
143 | 177 | # Need to calculate digest of the url to make it work with long trust_root | ||
144 | 178 | # values when caching in memcached | ||
145 | 179 | return 'rpconfig-' + hashlib.md5(trust_root.rstrip('/')).hexdigest() | ||
146 | 180 | |||
147 | 181 | def save(self, *args, **kwargs): | ||
148 | 182 | cache.delete(self.cache_key(self.trust_root)) | ||
149 | 183 | return super(OpenIDRPConfig, self).save(*args, **kwargs) | ||
150 | 184 | |||
151 | 170 | @property | 185 | @property |
152 | 171 | def logo_url(self): | 186 | def logo_url(self): |
153 | 172 | if self.logo: | 187 | if self.logo: |
154 | @@ -186,19 +201,30 @@ | |||
155 | 186 | return None | 201 | return None |
156 | 187 | if openid_identifier is None: | 202 | if openid_identifier is None: |
157 | 188 | openid_identifier = account.openid_identity_url | 203 | openid_identifier = account.openid_identity_url |
158 | 204 | if approved_data: | ||
159 | 205 | approved_data = json.dumps(approved_data) | ||
160 | 189 | try: | 206 | try: |
161 | 190 | summary = OpenIDRPSummary.objects.get( | 207 | summary = OpenIDRPSummary.objects.get( |
162 | 191 | account=account, | 208 | account=account, |
163 | 192 | trust_root=trust_root, | 209 | trust_root=trust_root, |
164 | 193 | openid_identifier=openid_identifier) | 210 | openid_identifier=openid_identifier) |
166 | 194 | summary.increment() | 211 | update_bits = dict( |
167 | 212 | total_logins=models.F('total_logins') + 1, | ||
168 | 213 | date_last_used=datetime.utcnow(), | ||
169 | 214 | ) | ||
170 | 215 | if approved_data: | ||
171 | 216 | update_bits['approved_data'] = approved_data | ||
172 | 217 | # Using update is not causing Django to select the record once | ||
173 | 218 | # again from the database, it's one less SELECT. | ||
174 | 219 | OpenIDRPSummary.objects.filter(pk=summary.pk).update(**update_bits) | ||
175 | 195 | except OpenIDRPSummary.DoesNotExist: | 220 | except OpenIDRPSummary.DoesNotExist: |
177 | 196 | summary = OpenIDRPSummary.objects.create( | 221 | summary = OpenIDRPSummary( |
178 | 197 | account=account, | 222 | account=account, |
179 | 198 | trust_root=trust_root, | 223 | trust_root=trust_root, |
180 | 199 | openid_identifier=openid_identifier) | 224 | openid_identifier=openid_identifier) |
183 | 200 | if approved_data: | 225 | if approved_data: |
184 | 201 | summary.set_approved_data(approved_data) | 226 | summary.approved_data = approved_data |
185 | 227 | summary.save() | ||
186 | 202 | return summary | 228 | return summary |
187 | 203 | 229 | ||
188 | 204 | 230 | ||
189 | @@ -220,11 +246,6 @@ | |||
190 | 220 | db_table = u'openidrpsummary' | 246 | db_table = u'openidrpsummary' |
191 | 221 | unique_together = ('account', 'trust_root', 'openid_identifier') | 247 | unique_together = ('account', 'trust_root', 'openid_identifier') |
192 | 222 | 248 | ||
193 | 223 | def increment(self): | ||
194 | 224 | self.total_logins += 1 | ||
195 | 225 | self.date_last_used = datetime.utcnow() | ||
196 | 226 | self.save() | ||
197 | 227 | |||
198 | 228 | def get_approved_data(self): | 249 | def get_approved_data(self): |
199 | 229 | try: | 250 | try: |
200 | 230 | data = json.loads(self.approved_data) | 251 | data = json.loads(self.approved_data) |
201 | @@ -233,8 +254,9 @@ | |||
202 | 233 | return data | 254 | return data |
203 | 234 | 255 | ||
204 | 235 | def set_approved_data(self, approved_data): | 256 | def set_approved_data(self, approved_data): |
207 | 236 | self.approved_data = json.dumps(approved_data) | 257 | if not isinstance(approved_data, basestring): |
208 | 237 | self.save() | 258 | approved_data = json.dumps(approved_data) |
209 | 259 | self.approved_data = approved_data | ||
210 | 238 | 260 | ||
211 | 239 | 261 | ||
212 | 240 | class DjangoOpenIDStore(OpenIDStore): | 262 | class DjangoOpenIDStore(OpenIDStore): |
213 | 241 | 263 | ||
214 | === modified file 'identityprovider/models/team.py' | |||
215 | --- identityprovider/models/team.py 2011-07-01 19:47:04 +0000 | |||
216 | +++ identityprovider/models/team.py 2011-09-06 14:43:24 +0000 | |||
217 | @@ -50,21 +50,21 @@ | |||
218 | 50 | 50 | ||
219 | 51 | @staticmethod | 51 | @staticmethod |
220 | 52 | def get_team_memberships_for_user(team_names, user, include_private=False): | 52 | def get_team_memberships_for_user(team_names, user, include_private=False): |
236 | 53 | memberships = [] | 53 | teams = Person.objects.filter( |
237 | 54 | for team_name in team_names: | 54 | name__in=team_names, # All team names provided |
238 | 55 | try: | 55 | teamowner__isnull=False, # Only teams |
239 | 56 | team = Person.objects.get(name=team_name) | 56 | ) |
240 | 57 | except Person.DoesNotExist: | 57 | if not include_private: |
241 | 58 | team = None | 58 | teams = teams.filter( |
242 | 59 | if team is None or not team.is_team(): | 59 | visibility=PERSON_VISIBILITY_PUBLIC) |
243 | 60 | continue | 60 | # Only teams in which the user is a member, which can be either through |
244 | 61 | # Control access to private teams | 61 | # direct membership or by being a team owner. |
245 | 62 | if (team.visibility != PERSON_VISIBILITY_PUBLIC and | 62 | teams = teams.filter( |
246 | 63 | not include_private): | 63 | models.Q(team_participations__person=user.person) | |
247 | 64 | continue | 64 | models.Q(teamowner__id=models.F('id')), |
248 | 65 | if user.person_in_team(team): | 65 | ) |
249 | 66 | memberships.append(team_name) | 66 | # By default it's a query set result, not a true list |
250 | 67 | return memberships | 67 | return list(teams.values_list('name', flat=True)) |
251 | 68 | 68 | ||
252 | 69 | 69 | ||
253 | 70 | class TeamParticipation(models.Model): | 70 | class TeamParticipation(models.Model): |
254 | 71 | 71 | ||
255 | === modified file 'identityprovider/tests/test_models_openidmodels.py' | |||
256 | --- identityprovider/tests/test_models_openidmodels.py 2011-07-27 13:00:22 +0000 | |||
257 | +++ identityprovider/tests/test_models_openidmodels.py 2011-09-06 14:43:24 +0000 | |||
258 | @@ -253,6 +253,7 @@ | |||
259 | 253 | summary = OpenIDRPSummary.objects.create(account=self.account, | 253 | summary = OpenIDRPSummary.objects.create(account=self.account, |
260 | 254 | trust_root=self.trust_root, openid_identifier='oid') | 254 | trust_root=self.trust_root, openid_identifier='oid') |
261 | 255 | summary.set_approved_data(self.approved_data) | 255 | summary.set_approved_data(self.approved_data) |
262 | 256 | summary.save() | ||
263 | 256 | return summary | 257 | return summary |
264 | 257 | 258 | ||
265 | 258 | def test_record_when_readonly(self): | 259 | def test_record_when_readonly(self): |
266 | @@ -281,6 +282,7 @@ | |||
267 | 281 | summary1 = self.create_summary() | 282 | summary1 = self.create_summary() |
268 | 282 | summary2 = OpenIDRPSummary.objects.record(self.account, | 283 | summary2 = OpenIDRPSummary.objects.record(self.account, |
269 | 283 | self.trust_root, openid_identifier='oid') | 284 | self.trust_root, openid_identifier='oid') |
270 | 285 | summary2 = OpenIDRPSummary.objects.get(pk=summary2.pk) | ||
271 | 284 | self.assertEqual(summary2.total_logins, 2) | 286 | self.assertEqual(summary2.total_logins, 2) |
272 | 285 | self.assertEqual(summary1, summary2) | 287 | self.assertEqual(summary1, summary2) |
273 | 286 | 288 | ||
274 | @@ -294,23 +296,17 @@ | |||
275 | 294 | self.assertNotEqual(summary1, summary2) | 296 | self.assertNotEqual(summary1, summary2) |
276 | 295 | 297 | ||
277 | 296 | def test_record_not_existing(self): | 298 | def test_record_not_existing(self): |
280 | 297 | summary1 = OpenIDRPSummary.objects.record(self.account, self.trust_root, | 299 | summary1 = OpenIDRPSummary.objects.record( |
281 | 298 | openid_identifier='oid') | 300 | self.account, self.trust_root, openid_identifier='oid') |
282 | 299 | self.assertEqual(summary1.total_logins, 1) | 301 | self.assertEqual(summary1.total_logins, 1) |
283 | 300 | summary2 = OpenIDRPSummary.objects.get(account=self.account, | 302 | summary2 = OpenIDRPSummary.objects.get(account=self.account, |
284 | 301 | trust_root=self.trust_root, openid_identifier='oid') | 303 | trust_root=self.trust_root, openid_identifier='oid') |
285 | 302 | self.assertEqual(summary1, summary2) | 304 | self.assertEqual(summary1, summary2) |
286 | 303 | 305 | ||
287 | 304 | def test_increment(self): | ||
288 | 305 | summary = self.create_summary() | ||
289 | 306 | self.assertEqual(summary.total_logins, 1) | ||
290 | 307 | |||
291 | 308 | summary.increment() | ||
292 | 309 | self.assertEqual(summary.total_logins, 2) | ||
293 | 310 | |||
294 | 311 | def test_approved_data(self): | 306 | def test_approved_data(self): |
295 | 312 | summary = self.create_summary() | 307 | summary = self.create_summary() |
296 | 313 | summary.set_approved_data(self.approved_data) | 308 | summary.set_approved_data(self.approved_data) |
297 | 309 | summary.save() | ||
298 | 314 | summary2 = OpenIDRPSummary.objects.get(account=self.account, | 310 | summary2 = OpenIDRPSummary.objects.get(account=self.account, |
299 | 315 | trust_root=self.trust_root, openid_identifier='oid') | 311 | trust_root=self.trust_root, openid_identifier='oid') |
300 | 316 | self.assertEqual(summary2.get_approved_data(), self.approved_data) | 312 | self.assertEqual(summary2.get_approved_data(), self.approved_data) |
301 | 317 | 313 | ||
302 | === modified file 'identityprovider/tests/test_views_server.py' | |||
303 | --- identityprovider/tests/test_views_server.py 2011-07-27 13:00:22 +0000 | |||
304 | +++ identityprovider/tests/test_views_server.py 2011-09-06 14:43:24 +0000 | |||
305 | @@ -7,6 +7,7 @@ | |||
306 | 7 | 7 | ||
307 | 8 | from django.conf import settings | 8 | from django.conf import settings |
308 | 9 | from django.contrib.auth.models import AnonymousUser | 9 | from django.contrib.auth.models import AnonymousUser |
309 | 10 | from django.core.cache import cache | ||
310 | 10 | from django.http import HttpRequest | 11 | from django.http import HttpRequest |
311 | 11 | from django.test import TestCase | 12 | from django.test import TestCase |
312 | 12 | from mock import Mock | 13 | from mock import Mock |
313 | @@ -67,6 +68,11 @@ | |||
314 | 67 | self.META = {} | 68 | self.META = {} |
315 | 68 | 69 | ||
316 | 69 | 70 | ||
317 | 71 | def delete_rpconfig_cache_entry(trust_root): | ||
318 | 72 | cache.delete(OpenIDRPConfig.cache_key(trust_root)) | ||
319 | 73 | |||
320 | 74 | |||
321 | 75 | |||
322 | 70 | class HandleOpenIDErrorTestCase(SSOBaseTestCase): | 76 | class HandleOpenIDErrorTestCase(SSOBaseTestCase): |
323 | 71 | 77 | ||
324 | 72 | # tests for the _handle_openid_error method | 78 | # tests for the _handle_openid_error method |
325 | @@ -418,6 +424,8 @@ | |||
326 | 418 | # create multiple matching OpenIDRPSummary objects | 424 | # create multiple matching OpenIDRPSummary objects |
327 | 419 | account = Account.objects.get_by_email(self.login_email) | 425 | account = Account.objects.get_by_email(self.login_email) |
328 | 420 | trust_root = 'http://localhost/' | 426 | trust_root = 'http://localhost/' |
329 | 427 | delete_rpconfig_cache_entry(trust_root) | ||
330 | 428 | |||
331 | 421 | OpenIDRPSummary.objects.create(account=account, trust_root=trust_root, | 429 | OpenIDRPSummary.objects.create(account=account, trust_root=trust_root, |
332 | 422 | openid_identifier='http://localhost/~openid1') | 430 | openid_identifier='http://localhost/~openid1') |
333 | 423 | OpenIDRPSummary.objects.create(account=account, trust_root=trust_root, | 431 | OpenIDRPSummary.objects.create(account=account, trust_root=trust_root, |
334 | @@ -427,6 +435,7 @@ | |||
335 | 427 | self.assertEqual(r.status_code, 200) | 435 | self.assertEqual(r.status_code, 200) |
336 | 428 | self.assertTemplateUsed(r, 'decide.html') | 436 | self.assertTemplateUsed(r, 'decide.html') |
337 | 429 | 437 | ||
338 | 438 | |||
339 | 430 | def test_decide_team_membership_with_auto_authorize(self): | 439 | def test_decide_team_membership_with_auto_authorize(self): |
340 | 431 | # make sure rpconfig is set to auto authorize | 440 | # make sure rpconfig is set to auto authorize |
341 | 432 | self.client.login(username='mark@example.com', | 441 | self.client.login(username='mark@example.com', |
342 | @@ -537,10 +546,14 @@ | |||
343 | 537 | password='test') | 546 | password='test') |
344 | 538 | 547 | ||
345 | 539 | # create a trusted rpconfig | 548 | # create a trusted rpconfig |
347 | 540 | rpconfig = OpenIDRPConfig(trust_root='http://untrusted/', | 549 | trust_root = 'http://untrusted/' |
348 | 550 | rpconfig = OpenIDRPConfig(trust_root=trust_root, | ||
349 | 541 | can_query_any_team=True, | 551 | can_query_any_team=True, |
350 | 542 | description="Some description", | 552 | description="Some description", |
351 | 543 | ) | 553 | ) |
352 | 554 | |||
353 | 555 | delete_rpconfig_cache_entry("http://localhost/") | ||
354 | 556 | |||
355 | 544 | rpconfig.save() | 557 | rpconfig.save() |
356 | 545 | param_overrides = { | 558 | param_overrides = { |
357 | 546 | 'openid.sreg.required': 'nickname,email,fullname', | 559 | 'openid.sreg.required': 'nickname,email,fullname', |
358 | @@ -1048,6 +1061,8 @@ | |||
359 | 1048 | session[token] = signed.dumps(DummyORequest()) | 1061 | session[token] = signed.dumps(DummyORequest()) |
360 | 1049 | session.save() | 1062 | session.save() |
361 | 1050 | 1063 | ||
362 | 1064 | delete_rpconfig_cache_entry("http://localhost/") | ||
363 | 1065 | |||
364 | 1051 | r = self.client.get('/%s/+decide' % token) | 1066 | r = self.client.get('/%s/+decide' % token) |
365 | 1052 | self.assertContains(r, '<em>not</em>') | 1067 | self.assertContains(r, '<em>not</em>') |
366 | 1053 | 1068 | ||
367 | 1054 | 1069 | ||
368 | === modified file 'identityprovider/tests/test_views_ui.py' | |||
369 | --- identityprovider/tests/test_views_ui.py 2011-08-25 13:25:51 +0000 | |||
370 | +++ identityprovider/tests/test_views_ui.py 2011-09-06 14:43:24 +0000 | |||
371 | @@ -522,10 +522,13 @@ | |||
372 | 522 | # make sure the account is deactivated and preferred email is removed | 522 | # make sure the account is deactivated and preferred email is removed |
373 | 523 | _preferred_email = account.preferredemail | 523 | _preferred_email = account.preferredemail |
374 | 524 | account.status = AccountStatus.DEACTIVATED | 524 | account.status = AccountStatus.DEACTIVATED |
375 | 525 | # Blow out the cached value | ||
376 | 525 | account.save() | 526 | account.save() |
377 | 526 | for email_obj in account.emailaddress_set.all(): | 527 | for email_obj in account.emailaddress_set.all(): |
378 | 527 | email_obj.status = EmailStatus.NEW | 528 | email_obj.status = EmailStatus.NEW |
379 | 528 | email_obj.save() | 529 | email_obj.save() |
380 | 530 | |||
381 | 531 | account = Account.objects.get_by_email('test@canonical.com') | ||
382 | 529 | self.assertEqual(account.preferredemail, None) | 532 | self.assertEqual(account.preferredemail, None) |
383 | 530 | 533 | ||
384 | 531 | r = self.client.post('/+forgot_password', | 534 | r = self.client.post('/+forgot_password', |
385 | @@ -539,6 +542,7 @@ | |||
386 | 539 | r = self.client.post(self._token_url('+resetpassword'), data) | 542 | r = self.client.post(self._token_url('+resetpassword'), data) |
387 | 540 | self.assertRedirects(r, '/') | 543 | self.assertRedirects(r, '/') |
388 | 541 | 544 | ||
389 | 545 | account = Account.objects.get_by_email('test@canonical.com') | ||
390 | 542 | self.assertEqual(account.preferredemail.email, 'test@canonical.com') | 546 | self.assertEqual(account.preferredemail.email, 'test@canonical.com') |
391 | 543 | 547 | ||
392 | 544 | for email_obj in account.emailaddress_set.all(): | 548 | for email_obj in account.emailaddress_set.all(): |
393 | 545 | 549 | ||
394 | === modified file 'identityprovider/views/server.py' | |||
395 | --- identityprovider/views/server.py 2011-07-27 19:20:16 +0000 | |||
396 | +++ identityprovider/views/server.py 2011-09-06 14:43:24 +0000 | |||
397 | @@ -504,7 +504,7 @@ | |||
398 | 504 | team_names = team_names.split(',') | 504 | team_names = team_names.split(',') |
399 | 505 | teams_form = TeamsRequestForm(request, | 505 | teams_form = TeamsRequestForm(request, |
400 | 506 | TeamsRequest.fromOpenIDRequest(orequest), | 506 | TeamsRequest.fromOpenIDRequest(orequest), |
402 | 507 | utils.get_rpconfig(orequest.trust_root)) | 507 | rpconfig) |
403 | 508 | approved_data['teams'] = { | 508 | approved_data['teams'] = { |
404 | 509 | 'requested': team_names, | 509 | 'requested': team_names, |
405 | 510 | 'approved': teams_form.teams_approved_by_user} | 510 | 'approved': teams_form.teams_approved_by_user} |
406 | 511 | 511 | ||
407 | === modified file 'identityprovider/views/utils.py' | |||
408 | --- identityprovider/views/utils.py 2011-07-13 14:30:29 +0000 | |||
409 | +++ identityprovider/views/utils.py 2011-09-06 14:43:24 +0000 | |||
410 | @@ -1,7 +1,9 @@ | |||
411 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
412 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
413 | 3 | import hashlib | ||
414 | 3 | 4 | ||
415 | 4 | from django.conf import settings | 5 | from django.conf import settings |
416 | 6 | from django.core.cache import cache | ||
417 | 5 | 7 | ||
418 | 6 | from identityprovider.models import OpenIDRPConfig | 8 | from identityprovider.models import OpenIDRPConfig |
419 | 7 | 9 | ||
420 | @@ -24,12 +26,19 @@ | |||
421 | 24 | 26 | ||
422 | 25 | 27 | ||
423 | 26 | def get_rpconfig(trust_root): | 28 | def get_rpconfig(trust_root): |
430 | 27 | alternatives = [trust_root] | 29 | cache_key = OpenIDRPConfig.cache_key(trust_root) |
431 | 28 | 30 | ||
432 | 29 | if trust_root.endswith('/'): | 31 | default = object() |
433 | 30 | alternatives.append(trust_root[:-1]) | 32 | rpconfig = cache.get(cache_key, default) |
434 | 31 | else: | 33 | if rpconfig is not default: |
435 | 32 | alternatives.append(trust_root + '/') | 34 | return rpconfig |
436 | 35 | |||
437 | 36 | alternatives = [ | ||
438 | 37 | trust_root, | ||
439 | 38 | trust_root[:-1] if trust_root.endswith('/') else (trust_root + '/'), | ||
440 | 39 | ] | ||
441 | 33 | 40 | ||
442 | 34 | rpconfig = OpenIDRPConfig.objects.filter(trust_root__in=alternatives) | 41 | rpconfig = OpenIDRPConfig.objects.filter(trust_root__in=alternatives) |
444 | 35 | return rpconfig and rpconfig[0] or None | 42 | rpconfig = rpconfig and rpconfig[0] or None |
445 | 43 | cache.set(cache_key, rpconfig, 60 * 60 * 24) | ||
446 | 44 | return rpconfig |