Merge ~cjwatson/launchpad:stormify-emailaddress into launchpad:master
- Git
- lp:~cjwatson/launchpad
- stormify-emailaddress
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | b6b3a461db81e8f596f6159b6560ff5d679b781d |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:stormify-emailaddress |
Merge into: | launchpad:master |
Diff against target: |
760 lines (+95/-107) 24 files modified
lib/lp/app/doc/batch-navigation.rst (+4/-1) lib/lp/code/model/revision.py (+1/-1) lib/lp/registry/browser/peoplemerge.py (+1/-1) lib/lp/registry/browser/person.py (+2/-2) lib/lp/registry/doc/person-account.rst (+1/-3) lib/lp/registry/model/mailinglist.py (+7/-7) lib/lp/registry/model/person.py (+12/-20) lib/lp/registry/scripts/closeaccount.py (+2/-2) lib/lp/registry/stories/teammembership/xx-teammembership.rst (+4/-3) lib/lp/registry/tests/test_person_merge_job.py (+1/-2) lib/lp/registry/tests/test_personset.py (+0/-7) lib/lp/registry/tests/test_team.py (+1/-3) lib/lp/registry/vocabularies.py (+4/-2) lib/lp/scripts/garbo.py (+2/-2) lib/lp/services/database/doc/storm.rst (+1/-1) lib/lp/services/identity/configure.zcml (+1/-3) lib/lp/services/identity/interfaces/emailaddress.py (+1/-8) lib/lp/services/identity/model/emailaddress.py (+26/-23) lib/lp/services/verification/browser/logintoken.py (+3/-3) lib/lp/services/webapp/doc/webapp-publication.rst (+1/-1) lib/lp/soyuz/doc/gina-multiple-arch.rst (+4/-2) lib/lp/soyuz/doc/gina.rst (+7/-3) lib/lp/soyuz/model/archivesubscriber.py (+2/-2) lib/lp/soyuz/tests/test_doc.py (+7/-5) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ines Almeida | Approve | ||
Review via email: mp+449757@code.launchpad.net |
Commit message
Convert EmailAddress to Storm
Description of the change
To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) : | # |
Revision history for this message
Ines Almeida (ines-almeida) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/app/doc/batch-navigation.rst b/lib/lp/app/doc/batch-navigation.rst |
2 | index a93b8b8..25274f1 100644 |
3 | --- a/lib/lp/app/doc/batch-navigation.rst |
4 | +++ b/lib/lp/app/doc/batch-navigation.rst |
5 | @@ -64,8 +64,11 @@ Multiple pages |
6 | |
7 | The batch navigator tells us whether multiple pages will be used. |
8 | |
9 | + >>> from lp.services.database.interfaces import IStore |
10 | >>> from lp.services.identity.model.emailaddress import EmailAddress |
11 | - >>> select_results = EmailAddress.select(orderBy="id") |
12 | + >>> select_results = ( |
13 | + ... IStore(EmailAddress).find(EmailAddress).order_by("id") |
14 | + ... ) |
15 | >>> batch_nav = BatchNavigator(select_results, build_request(), size=50) |
16 | >>> batch_nav.has_multiple_pages |
17 | True |
18 | diff --git a/lib/lp/code/model/revision.py b/lib/lp/code/model/revision.py |
19 | index 3777ebd..b47402d 100644 |
20 | --- a/lib/lp/code/model/revision.py |
21 | +++ b/lib/lp/code/model/revision.py |
22 | @@ -235,7 +235,7 @@ class RevisionAuthor(StormBase): |
23 | return False |
24 | # Only accept an email address that is validated. |
25 | if lp_email.status != EmailAddressStatus.NEW: |
26 | - self.person_id = lp_email.personID |
27 | + self.person_id = lp_email.person_id |
28 | return True |
29 | else: |
30 | return False |
31 | diff --git a/lib/lp/registry/browser/peoplemerge.py b/lib/lp/registry/browser/peoplemerge.py |
32 | index 3dffe4e..b89646b 100644 |
33 | --- a/lib/lp/registry/browser/peoplemerge.py |
34 | +++ b/lib/lp/registry/browser/peoplemerge.py |
35 | @@ -166,7 +166,7 @@ class AdminMergeBaseView(ValidatingMergeView): |
36 | # EmailAddress.person is a readonly field, so we need to |
37 | # remove the security proxy here. |
38 | naked_email = removeSecurityProxy(email) |
39 | - naked_email.personID = self.target_person.id |
40 | + naked_email.person = self.target_person |
41 | naked_email.status = EmailAddressStatus.NEW |
42 | getUtility(IPersonSet).mergeAsync( |
43 | self.dupe_person, |
44 | diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py |
45 | index 2ce4be6..5ca39fe 100644 |
46 | --- a/lib/lp/registry/browser/person.py |
47 | +++ b/lib/lp/registry/browser/person.py |
48 | @@ -527,7 +527,7 @@ class PersonNavigation(BranchTraversalMixin, Navigation): |
49 | def traverse_email(self, email): |
50 | """Traverse to this person's emails on the webservice layer.""" |
51 | email = getUtility(IEmailAddressSet).getByEmail(email) |
52 | - if email is None or email.personID != self.context.id: |
53 | + if email is None or email.person != self.context: |
54 | return None |
55 | return email |
56 | |
57 | @@ -1146,7 +1146,7 @@ class BeginTeamClaimView(LaunchpadFormView): |
58 | "generated based on the email address it's " |
59 | "associated with." % self.context.name |
60 | ) |
61 | - elif email.personID != self.context.id: |
62 | + elif email.person != self.context: |
63 | error = structured( |
64 | "This email address is associated with yet another " |
65 | "Launchpad profile, which you seem to have used at " |
66 | diff --git a/lib/lp/registry/doc/person-account.rst b/lib/lp/registry/doc/person-account.rst |
67 | index e4cf997..21bb628 100644 |
68 | --- a/lib/lp/registry/doc/person-account.rst |
69 | +++ b/lib/lp/registry/doc/person-account.rst |
70 | @@ -16,7 +16,6 @@ process. Matsubara's account was created during a code import. |
71 | >>> from lp.services.identity.interfaces.emailaddress import ( |
72 | ... IEmailAddressSet, |
73 | ... ) |
74 | - >>> from lp.registry.interfaces.person import IPersonSet |
75 | |
76 | >>> emailset = getUtility(IEmailAddressSet) |
77 | >>> emailaddress = emailset.getByEmail("matsubara@async.com.br") |
78 | @@ -68,9 +67,8 @@ them, so we'll assign one just to prove that deactivating their account |
79 | will cause this spec to be reassigned. |
80 | |
81 | |
82 | - >>> personset = getUtility(IPersonSet) |
83 | >>> foobar_preferredemail = emailset.getByEmail("foo.bar@canonical.com") |
84 | - >>> foobar = personset.get(foobar_preferredemail.personID) |
85 | + >>> foobar = foobar_preferredemail.person |
86 | >>> foobar.specifications(None).is_empty() |
87 | False |
88 | |
89 | diff --git a/lib/lp/registry/model/mailinglist.py b/lib/lp/registry/model/mailinglist.py |
90 | index c27fbae..fd26b09 100644 |
91 | --- a/lib/lp/registry/model/mailinglist.py |
92 | +++ b/lib/lp/registry/model/mailinglist.py |
93 | @@ -332,7 +332,7 @@ class MailingList(StormBase): |
94 | |
95 | ).status = EmailAddressStatus.VALIDATED |
96 | assert ( |
97 | - email.personID == self.team_id |
98 | + email.person == self.team |
99 | ), "Email already associated with another team." |
100 | |
101 | def _setAndNotifyDateActivated(self): |
102 | @@ -361,7 +361,7 @@ class MailingList(StormBase): |
103 | if email is not None and self.team.preferredemail is not None: |
104 | if email.id == self.team.preferredemail.id: |
105 | self.team.setContactAddress(None) |
106 | - assert email.personID == self.team_id, "Incorrectly linked email." |
107 | + assert email.person == self.team, "Incorrectly linked email." |
108 | # Anyone with permission to deactivate a list can also set the |
109 | # email address status to NEW. |
110 | removeSecurityProxy(email).status = EmailAddressStatus.NEW |
111 | @@ -435,7 +435,7 @@ class MailingList(StormBase): |
112 | raise CannotSubscribe( |
113 | "Teams cannot be mailing list members: %s" % person.displayname |
114 | ) |
115 | - if address is not None and address.personID != person.id: |
116 | + if address is not None and address.person != person: |
117 | raise CannotSubscribe( |
118 | "%s does not own the email address: %s" |
119 | % (person.displayname, address.email) |
120 | @@ -469,7 +469,7 @@ class MailingList(StormBase): |
121 | "%s is not a member of the mailing list: %s" |
122 | % (person.displayname, self.team.displayname) |
123 | ) |
124 | - if address is not None and address.personID != person.id: |
125 | + if address is not None and address.person != person: |
126 | raise CannotChangeSubscription( |
127 | "%s does not own the email address: %s" |
128 | % (person.displayname, address.email) |
129 | @@ -645,7 +645,7 @@ class MailingListSet: |
130 | Team = ClassAlias(Person) |
131 | tables = ( |
132 | EmailAddress, |
133 | - Join(Person, Person.id == EmailAddress.personID), |
134 | + Join(Person, Person.id == EmailAddress.person_id), |
135 | Join(Account, Account.id == Person.account_id), |
136 | Join(TeamParticipation, TeamParticipation.person_id == Person.id), |
137 | Join( |
138 | @@ -702,7 +702,7 @@ class MailingListSet: |
139 | tables = ( |
140 | Person, |
141 | Join(Account, Account.id == Person.account_id), |
142 | - Join(EmailAddress, EmailAddress.personID == Person.id), |
143 | + Join(EmailAddress, EmailAddress.person_id == Person.id), |
144 | Join(TeamParticipation, TeamParticipation.person_id == Person.id), |
145 | Join( |
146 | MailingList, MailingList.team_id == TeamParticipation.team_id |
147 | @@ -728,7 +728,7 @@ class MailingListSet: |
148 | tables = ( |
149 | Person, |
150 | Join(Account, Account.id == Person.account_id), |
151 | - Join(EmailAddress, EmailAddress.personID == Person.id), |
152 | + Join(EmailAddress, EmailAddress.person_id == Person.id), |
153 | Join(MessageApproval, MessageApproval.posted_by_id == Person.id), |
154 | Join( |
155 | MailingList, MailingList.id == MessageApproval.mailing_list_id |
156 | diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py |
157 | index 1aa22bc..4846cd9 100644 |
158 | --- a/lib/lp/registry/model/person.py |
159 | +++ b/lib/lp/registry/model/person.py |
160 | @@ -2109,11 +2109,7 @@ class Person( |
161 | ) |
162 | |
163 | def _getEmailsByStatus(self, status): |
164 | - return Store.of(self).find( |
165 | - EmailAddress, |
166 | - EmailAddress.personID == self.id, |
167 | - EmailAddress.status == status, |
168 | - ) |
169 | + return Store.of(self).find(EmailAddress, person=self, status=status) |
170 | |
171 | def checkInclusiveMembershipPolicyAllowed(self, policy="open"): |
172 | """See `ITeam`""" |
173 | @@ -2258,7 +2254,7 @@ class Person( |
174 | LeftJoin( |
175 | email_table, |
176 | And( |
177 | - email_table.personID == person_table.id, |
178 | + email_table.person_id == person_table.id, |
179 | email_table.status == EmailAddressStatus.PREFERRED, |
180 | ), |
181 | ) |
182 | @@ -3041,10 +3037,8 @@ class Person( |
183 | "Any person's email address must provide the IEmailAddress " |
184 | "interface. %s doesn't." % email |
185 | ) |
186 | - # XXX Steve Alexander 2005-07-05: |
187 | - # This is here because of an SQLobject comparison oddity. |
188 | - assert email.personID == self.id, "Wrong person! %r, %r" % ( |
189 | - email.personID, |
190 | + assert email.person == self, "Wrong person! %r, %r" % ( |
191 | + email.person_id, |
192 | self.id, |
193 | ) |
194 | |
195 | @@ -3056,7 +3050,7 @@ class Person( |
196 | IStore(EmailAddress) |
197 | .find( |
198 | EmailAddress, |
199 | - EmailAddress.personID == self.id, |
200 | + EmailAddress.person == self, |
201 | EmailAddress.status == EmailAddressStatus.PREFERRED, |
202 | ) |
203 | .one() |
204 | @@ -3095,9 +3089,7 @@ class Person( |
205 | ) |
206 | else: |
207 | mailing_list_email = None |
208 | - all_addresses = IStore(EmailAddress).find( |
209 | - EmailAddress, EmailAddress.personID == self.id |
210 | - ) |
211 | + all_addresses = IStore(EmailAddress).find(EmailAddress, person=self) |
212 | for address in all_addresses: |
213 | # Delete all email addresses that are not the preferred email |
214 | # address, or the team's email address. If this method was called |
215 | @@ -3112,7 +3104,7 @@ class Person( |
216 | IStore(EmailAddress) |
217 | .find( |
218 | EmailAddress, |
219 | - personID=self.id, |
220 | + person=self, |
221 | status=EmailAddressStatus.PREFERRED, |
222 | ) |
223 | .one() |
224 | @@ -3143,12 +3135,12 @@ class Person( |
225 | "Any person's email address must provide the IEmailAddress " |
226 | "interface. %s doesn't." % email |
227 | ) |
228 | - assert email.personID == self.id |
229 | + assert email.person == self |
230 | existing_preferred_email = ( |
231 | IStore(EmailAddress) |
232 | .find( |
233 | EmailAddress, |
234 | - personID=self.id, |
235 | + person=self, |
236 | status=EmailAddressStatus.PREFERRED, |
237 | ) |
238 | .one() |
239 | @@ -4520,7 +4512,7 @@ class PersonSet: |
240 | return ( |
241 | IStore(Person) |
242 | .using( |
243 | - Person, Join(EmailAddress, EmailAddress.personID == Person.id) |
244 | + Person, Join(EmailAddress, EmailAddress.person_id == Person.id) |
245 | ) |
246 | .find( |
247 | (EmailAddress, Person), |
248 | @@ -5543,7 +5535,7 @@ def _get_recipients_for_team(team): |
249 | # Find Persons that have a preferred email address and an active |
250 | # account, or are a team, or both. |
251 | intermediate_transitive_results = source.find( |
252 | - (TeamMembership.person_id, EmailAddress.personID), |
253 | + (TeamMembership.person_id, EmailAddress.person_id), |
254 | TeamMembership.status.is_in( |
255 | ( |
256 | TeamMembershipStatus.ADMIN, |
257 | @@ -5553,7 +5545,7 @@ def _get_recipients_for_team(team): |
258 | TeamMembership.team_id.is_in(pending_team_ids), |
259 | Or( |
260 | And( |
261 | - EmailAddress.personID != None, |
262 | + EmailAddress.person != None, |
263 | Account.status == AccountStatus.ACTIVE, |
264 | ), |
265 | Person.teamownerID != None, |
266 | diff --git a/lib/lp/registry/scripts/closeaccount.py b/lib/lp/registry/scripts/closeaccount.py |
267 | index d744b92..c7d4c55 100644 |
268 | --- a/lib/lp/registry/scripts/closeaccount.py |
269 | +++ b/lib/lp/registry/scripts/closeaccount.py |
270 | @@ -60,7 +60,7 @@ def close_account(username, log): |
271 | |
272 | person = ( |
273 | store.using( |
274 | - Person, LeftJoin(EmailAddress, Person.id == EmailAddress.personID) |
275 | + Person, LeftJoin(EmailAddress, Person.id == EmailAddress.person_id) |
276 | ) |
277 | .find( |
278 | Person, |
279 | @@ -218,7 +218,7 @@ def close_account(username, log): |
280 | # people requesting account removal seem to primarily be interested |
281 | # in ensuring we no longer store this information. |
282 | table_notification("EmailAddress") |
283 | - store.find(EmailAddress, EmailAddress.personID == person.id).remove() |
284 | + store.find(EmailAddress, person=person).remove() |
285 | |
286 | # Clean out personal details from the Person table |
287 | table_notification("Person") |
288 | diff --git a/lib/lp/registry/stories/teammembership/xx-teammembership.rst b/lib/lp/registry/stories/teammembership/xx-teammembership.rst |
289 | index 3912580..a7b5a3b 100644 |
290 | --- a/lib/lp/registry/stories/teammembership/xx-teammembership.rst |
291 | +++ b/lib/lp/registry/stories/teammembership/xx-teammembership.rst |
292 | @@ -88,11 +88,12 @@ the team's home page. |
293 | If this was a moderated team, the membership would not have been automatically |
294 | approved, though. |
295 | |
296 | + >>> from storm.locals import Store |
297 | >>> from lp.registry.interfaces.person import TeamMembershipPolicy |
298 | >>> from lp.registry.model.person import Person |
299 | >>> myemail = Person.selectOneBy(name="myemail") |
300 | >>> myemail.membership_policy = TeamMembershipPolicy.MODERATED |
301 | - >>> myemail.syncUpdate() |
302 | + >>> Store.of(myemail).flush() |
303 | |
304 | >>> browser = setupBrowser( |
305 | ... auth="Basic james.blackwell@ubuntulinux.com:test" |
306 | @@ -142,7 +143,7 @@ Delegated teams also require approval of direct membership. |
307 | |
308 | >>> login("test@canonical.com") |
309 | >>> myemail.membership_policy = TeamMembershipPolicy.DELEGATED |
310 | - >>> myemail.syncUpdate() |
311 | + >>> Store.of(myemail).flush() |
312 | >>> logout() |
313 | |
314 | >>> browser = setupBrowser(auth="Basic colin.watson@ubuntulinux.com:test") |
315 | @@ -180,7 +181,7 @@ Delegated teams also require approval of direct membership. |
316 | If it was a restricted team, users wouldn't even see a link to join the team. |
317 | |
318 | >>> myemail.membership_policy = TeamMembershipPolicy.RESTRICTED |
319 | - >>> myemail.syncUpdate() |
320 | + >>> Store.of(myemail).flush() |
321 | |
322 | >>> browser = setupBrowser(auth="Basic jeff.waugh@ubuntulinux.com:test") |
323 | >>> browser.open("http://launchpad.test/~myemail") |
324 | diff --git a/lib/lp/registry/tests/test_person_merge_job.py b/lib/lp/registry/tests/test_person_merge_job.py |
325 | index 319ed86..b3a5f99 100644 |
326 | --- a/lib/lp/registry/tests/test_person_merge_job.py |
327 | +++ b/lib/lp/registry/tests/test_person_merge_job.py |
328 | @@ -48,8 +48,7 @@ def transfer_email(job): |
329 | IPersonSet.merge() does not (yet) promise to do this. |
330 | """ |
331 | from_email = removeSecurityProxy(job.from_person.preferredemail) |
332 | - from_email.personID = job.to_person.id |
333 | - from_email.account_id = job.to_person.account_id |
334 | + from_email.person = job.to_person |
335 | from_email.status = EmailAddressStatus.NEW |
336 | IStore(from_email).flush() |
337 | |
338 | diff --git a/lib/lp/registry/tests/test_personset.py b/lib/lp/registry/tests/test_personset.py |
339 | index dc8f36f..fc8650f 100644 |
340 | --- a/lib/lp/registry/tests/test_personset.py |
341 | +++ b/lib/lp/registry/tests/test_personset.py |
342 | @@ -368,7 +368,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
343 | return self.store.add( |
344 | EmailAddress( |
345 | email=email, |
346 | - account=person.account, |
347 | person=person, |
348 | status=EmailAddressStatus.PREFERRED, |
349 | ) |
350 | @@ -388,7 +387,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
351 | self.assertIs(self.person, found) |
352 | self.assertIs(self.account, found.account) |
353 | self.assertIs(self.email, found.preferredemail) |
354 | - self.assertIs(self.email.account, self.account) |
355 | self.assertIs(self.email.person, self.person) |
356 | self.assertEqual( |
357 | [self.identifier], list(self.account.openid_identifiers) |
358 | @@ -410,7 +408,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
359 | self.assertIs(self.person, found) |
360 | self.assertIs(self.account, found.account) |
361 | self.assertIs(self.email, found.preferredemail) |
362 | - self.assertIs(self.email.account, self.account) |
363 | self.assertIs(self.email.person, self.person) |
364 | self.assertEqual( |
365 | [self.identifier], list(self.account.openid_identifiers) |
366 | @@ -433,7 +430,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
367 | self.assertIs(self.person, found) |
368 | self.assertIs(self.account, found.account) |
369 | self.assertIs(self.email, found.preferredemail) |
370 | - self.assertIs(self.email.account, self.account) |
371 | self.assertIs(self.email.person, self.person) |
372 | |
373 | # Old OpenId Identifier still attached. |
374 | @@ -474,7 +470,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
375 | def testNoAccount(self): |
376 | # EmailAddress is linked to a Person, but there is no Account. |
377 | # Convert this stub into something valid. |
378 | - self.email.account = None |
379 | self.email.status = EmailAddressStatus.NEW |
380 | self.person.account = None |
381 | new_identifier = "new_identifier" |
382 | @@ -503,7 +498,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
383 | self.identifier.account = self.store.find( |
384 | Account, displayname="Foo Bar" |
385 | ).one() |
386 | - email_account = self.email.account |
387 | |
388 | found, updated = self.person_set.getOrCreateByOpenIDIdentifier( |
389 | self.identifier.identifier, |
390 | @@ -519,7 +513,6 @@ class TestPersonSetCreateByOpenId(TestCaseWithFactory): |
391 | |
392 | self.assertIs(found.account, self.identifier.account) |
393 | self.assertIn(self.identifier, list(found.account.openid_identifiers)) |
394 | - self.assertIs(email_account, self.email.account) |
395 | |
396 | def testEmptyOpenIDIdentifier(self): |
397 | self.assertRaises( |
398 | diff --git a/lib/lp/registry/tests/test_team.py b/lib/lp/registry/tests/test_team.py |
399 | index e00db68..5ab0e4f 100644 |
400 | --- a/lib/lp/registry/tests/test_team.py |
401 | +++ b/lib/lp/registry/tests/test_team.py |
402 | @@ -47,9 +47,7 @@ class TestTeamContactAddress(TestCaseWithFactory): |
403 | |
404 | def getAllEmailAddresses(self): |
405 | transaction.commit() |
406 | - all_addresses = self.store.find( |
407 | - EmailAddress, EmailAddress.personID == self.team.id |
408 | - ) |
409 | + all_addresses = self.store.find(EmailAddress, person=self.team) |
410 | return [address for address in all_addresses.order_by("email")] |
411 | |
412 | def createMailingListAndGetAddress(self): |
413 | diff --git a/lib/lp/registry/vocabularies.py b/lib/lp/registry/vocabularies.py |
414 | index 1c1c5f4..a733f84 100644 |
415 | --- a/lib/lp/registry/vocabularies.py |
416 | +++ b/lib/lp/registry/vocabularies.py |
417 | @@ -746,9 +746,11 @@ class ValidPersonOrTeamVocabulary( |
418 | # description so we need to bulk load them for performance, otherwise |
419 | # we get one query per person per attribute. |
420 | def pre_iter_hook(persons): |
421 | - emails = bulk.load_referencing(EmailAddress, persons, ["personID"]) |
422 | + emails = bulk.load_referencing( |
423 | + EmailAddress, persons, ["person_id"] |
424 | + ) |
425 | email_by_person = { |
426 | - email.personID: email |
427 | + email.person_id: email |
428 | for email in emails |
429 | if email.status == EmailAddressStatus.PREFERRED |
430 | } |
431 | diff --git a/lib/lp/scripts/garbo.py b/lib/lp/scripts/garbo.py |
432 | index f27f0b5..ef0a095 100644 |
433 | --- a/lib/lp/scripts/garbo.py |
434 | +++ b/lib/lp/scripts/garbo.py |
435 | @@ -1023,7 +1023,7 @@ class RevisionAuthorEmailLinker(TunableLoop): |
436 | |
437 | emails = dict( |
438 | self.email_store.find( |
439 | - (EmailAddress.email.lower(), EmailAddress.personID), |
440 | + (EmailAddress.email.lower(), EmailAddress.person_id), |
441 | EmailAddress.email.lower().is_in( |
442 | [author.email.lower() for author in authors] |
443 | ), |
444 | @@ -1033,7 +1033,7 @@ class RevisionAuthorEmailLinker(TunableLoop): |
445 | EmailAddressStatus.VALIDATED, |
446 | ] |
447 | ), |
448 | - EmailAddress.personID != None, |
449 | + EmailAddress.person != None, |
450 | ) |
451 | ) |
452 | |
453 | diff --git a/lib/lp/services/database/doc/storm.rst b/lib/lp/services/database/doc/storm.rst |
454 | index e9b84c9..2c38e6c 100644 |
455 | --- a/lib/lp/services/database/doc/storm.rst |
456 | +++ b/lib/lp/services/database/doc/storm.rst |
457 | @@ -162,7 +162,7 @@ Objects not yet flushed to the database also compare equal. |
458 | >>> unflushed = EmailAddress( |
459 | ... email="notflushed@example.com", |
460 | ... status=EmailAddressStatus.NEW, |
461 | - ... personID=1, |
462 | + ... person=getUtility(IPersonSet).get(1), |
463 | ... ) |
464 | >>> unflushed == unflushed |
465 | True |
466 | diff --git a/lib/lp/services/identity/configure.zcml b/lib/lp/services/identity/configure.zcml |
467 | index 66aea4e..b54af81 100644 |
468 | --- a/lib/lp/services/identity/configure.zcml |
469 | +++ b/lib/lp/services/identity/configure.zcml |
470 | @@ -16,9 +16,7 @@ |
471 | attributes=" |
472 | id |
473 | person |
474 | - personID |
475 | - account |
476 | - account_id |
477 | + person_id |
478 | status |
479 | rdf_sha1"/> |
480 | <require |
481 | diff --git a/lib/lp/services/identity/interfaces/emailaddress.py b/lib/lp/services/identity/interfaces/emailaddress.py |
482 | index cbd0198..450c96b 100644 |
483 | --- a/lib/lp/services/identity/interfaces/emailaddress.py |
484 | +++ b/lib/lp/services/identity/interfaces/emailaddress.py |
485 | @@ -120,7 +120,7 @@ class IEmailAddress(IHasOwner): |
486 | title=_("Person"), required=True, readonly=False, schema=Interface |
487 | ) |
488 | ) |
489 | - personID = Int(title=_("PersonID"), required=True, readonly=True) |
490 | + person_id = Int(title=_("Person ID"), required=True, readonly=True) |
491 | |
492 | rdf_sha1 = TextLine( |
493 | title=_("RDF-ready SHA-1 Hash"), |
494 | @@ -139,13 +139,6 @@ class IEmailAddress(IHasOwner): |
495 | preferred one or a hosted mailing list's address. |
496 | """ |
497 | |
498 | - def syncUpdate(): |
499 | - """Write updates made on this object to the database. |
500 | - |
501 | - This should be used when you can't wait until the transaction is |
502 | - committed to have some updates actually written to the database. |
503 | - """ |
504 | - |
505 | |
506 | class IEmailAddressSet(Interface): |
507 | """The set of EmailAddresses.""" |
508 | diff --git a/lib/lp/services/identity/model/emailaddress.py b/lib/lp/services/identity/model/emailaddress.py |
509 | index c80f10e..043a2f6 100644 |
510 | --- a/lib/lp/services/identity/model/emailaddress.py |
511 | +++ b/lib/lp/services/identity/model/emailaddress.py |
512 | @@ -12,15 +12,13 @@ __all__ = [ |
513 | import hashlib |
514 | import operator |
515 | |
516 | -import six |
517 | -from storm.expr import Lower |
518 | +from storm.locals import Int, Reference, Unicode |
519 | from zope.interface import implementer |
520 | |
521 | from lp.app.validators.email import valid_email |
522 | from lp.services.database.enumcol import DBEnum |
523 | from lp.services.database.interfaces import IPrimaryStore, IStore |
524 | -from lp.services.database.sqlbase import SQLBase, sqlvalues |
525 | -from lp.services.database.sqlobject import ForeignKey, StringCol |
526 | +from lp.services.database.stormbase import StormBase |
527 | from lp.services.identity.interfaces.emailaddress import ( |
528 | EmailAddressAlreadyTaken, |
529 | EmailAddressStatus, |
530 | @@ -41,15 +39,21 @@ class HasOwnerMixin: |
531 | |
532 | |
533 | @implementer(IEmailAddress) |
534 | -class EmailAddress(SQLBase, HasOwnerMixin): |
535 | - _table = "EmailAddress" |
536 | - _defaultOrder = ["email"] |
537 | +class EmailAddress(StormBase, HasOwnerMixin): |
538 | + __storm_table__ = "EmailAddress" |
539 | + __storm_order__ = ["email"] |
540 | |
541 | - email = StringCol( |
542 | - dbName="email", notNull=True, unique=True, alternateID=True |
543 | - ) |
544 | + id = Int(primary=True) |
545 | + email = Unicode(name="email", allow_none=False) |
546 | status = DBEnum(name="status", enum=EmailAddressStatus, allow_none=False) |
547 | - person = ForeignKey(dbName="person", foreignKey="Person", notNull=False) |
548 | + person_id = Int(name="person", allow_none=True) |
549 | + person = Reference(person_id, "Person.id") |
550 | + |
551 | + def __init__(self, email, status, person=None): |
552 | + super().__init__() |
553 | + self.email = email |
554 | + self.status = status |
555 | + self.person = person |
556 | |
557 | def __repr__(self): |
558 | return "<EmailAddress <%s> [%s]>" % (self.email, self.status) |
559 | @@ -83,7 +87,7 @@ class EmailAddress(SQLBase, HasOwnerMixin): |
560 | MailingListSubscription, email_address=self |
561 | ): |
562 | store.remove(subscription) |
563 | - super().destroySelf() |
564 | + store.remove(self) |
565 | |
566 | @property |
567 | def rdf_sha1(self): |
568 | @@ -99,18 +103,18 @@ class EmailAddress(SQLBase, HasOwnerMixin): |
569 | class EmailAddressSet: |
570 | def getByPerson(self, person): |
571 | """See `IEmailAddressSet`.""" |
572 | - return EmailAddress.selectBy(person=person, orderBy="email") |
573 | + return ( |
574 | + IStore(EmailAddress) |
575 | + .find(EmailAddress, person=person) |
576 | + .order_by(EmailAddress.email) |
577 | + ) |
578 | |
579 | def getPreferredEmailForPeople(self, people): |
580 | """See `IEmailAddressSet`.""" |
581 | - return EmailAddress.select( |
582 | - """ |
583 | - EmailAddress.status = %s AND |
584 | - EmailAddress.person IN %s |
585 | - """ |
586 | - % sqlvalues( |
587 | - EmailAddressStatus.PREFERRED, [person.id for person in people] |
588 | - ) |
589 | + return IStore(EmailAddress).find( |
590 | + EmailAddress, |
591 | + EmailAddress.status == EmailAddressStatus.PREFERRED, |
592 | + EmailAddress.person_id.is_in([person.id for person in people]), |
593 | ) |
594 | |
595 | def getByEmail(self, email): |
596 | @@ -119,8 +123,7 @@ class EmailAddressSet: |
597 | IStore(EmailAddress) |
598 | .find( |
599 | EmailAddress, |
600 | - Lower(EmailAddress.email) |
601 | - == six.ensure_text(email).strip().lower(), |
602 | + EmailAddress.email.lower() == email.strip().lower(), |
603 | ) |
604 | .one() |
605 | ) |
606 | diff --git a/lib/lp/services/verification/browser/logintoken.py b/lib/lp/services/verification/browser/logintoken.py |
607 | index 8cb3b0c..7bdc469 100644 |
608 | --- a/lib/lp/services/verification/browser/logintoken.py |
609 | +++ b/lib/lp/services/verification/browser/logintoken.py |
610 | @@ -426,7 +426,7 @@ class ValidateEmailView(BaseTokenView, LaunchpadFormView): |
611 | emailset = getUtility(IEmailAddressSet) |
612 | email = emailset.getByEmail(self.context.email) |
613 | if email is not None: |
614 | - if requester is None or email.personID != requester.id: |
615 | + if requester is None or email.person != requester: |
616 | dupe = email.person |
617 | # Yes, hardcoding an autogenerated field name is an evil |
618 | # hack, but if it fails nothing will happen. |
619 | @@ -585,7 +585,7 @@ class MergePeopleView(BaseTokenView, LaunchpadFormView): |
620 | # As a person can have at most one preferred email, ensure |
621 | # that this new email does not have the PREFERRED status. |
622 | email.status = EmailAddressStatus.NEW |
623 | - email.personID = requester.id |
624 | + email.person = requester |
625 | requester.validateAndEnsurePreferredEmail(email) |
626 | |
627 | # Need to flush all changes we made, so subsequent queries we make |
628 | @@ -595,7 +595,7 @@ class MergePeopleView(BaseTokenView, LaunchpadFormView): |
629 | |
630 | # Now we must check if the dupe account still have registered email |
631 | # addresses. If it hasn't we can actually do the merge. |
632 | - if emailset.getByPerson(self.dupe): |
633 | + if not emailset.getByPerson(self.dupe).is_empty(): |
634 | self.mergeCompleted = False |
635 | return |
636 | getUtility(IPersonSet).mergeAsync( |
637 | diff --git a/lib/lp/services/webapp/doc/webapp-publication.rst b/lib/lp/services/webapp/doc/webapp-publication.rst |
638 | index 2473f52..6a54055 100644 |
639 | --- a/lib/lp/services/webapp/doc/webapp-publication.rst |
640 | +++ b/lib/lp/services/webapp/doc/webapp-publication.rst |
641 | @@ -1022,7 +1022,7 @@ be automatically reverted in a GET request. |
642 | ... IPrimaryStore(Person) |
643 | ... .find( |
644 | ... Person, |
645 | - ... Person.id == EmailAddress.personID, |
646 | + ... Person.id == EmailAddress.person_id, |
647 | ... EmailAddress.email == "foo.bar@canonical.com", |
648 | ... ) |
649 | ... .one() |
650 | diff --git a/lib/lp/soyuz/doc/gina-multiple-arch.rst b/lib/lp/soyuz/doc/gina-multiple-arch.rst |
651 | index e2d84b1..86b6820 100644 |
652 | --- a/lib/lp/soyuz/doc/gina-multiple-arch.rst |
653 | +++ b/lib/lp/soyuz/doc/gina-multiple-arch.rst |
654 | @@ -23,7 +23,7 @@ Get the current counts of stuff in the database: |
655 | >>> orig_tp_count = ( |
656 | ... IStore(TeamParticipation).find(TeamParticipation).count() |
657 | ... ) |
658 | - >>> orig_email_count = EmailAddress.select().count() |
659 | + >>> orig_email_count = IStore(EmailAddress).find(EmailAddress).count() |
660 | >>> orig_bpr_count = ( |
661 | ... IStore(BinaryPackageRelease).find(BinaryPackageRelease).count() |
662 | ... ) |
663 | @@ -147,7 +147,9 @@ porridge): |
664 | ... - orig_tp_count |
665 | ... ) |
666 | 2 |
667 | - >>> print(EmailAddress.select().count() - orig_email_count) |
668 | + >>> print( |
669 | + ... IStore(EmailAddress).find(EmailAddress).count() - orig_email_count |
670 | + ... ) |
671 | 2 |
672 | |
673 | There are 4 binary packages generated by the two builds of the two |
674 | diff --git a/lib/lp/soyuz/doc/gina.rst b/lib/lp/soyuz/doc/gina.rst |
675 | index a934313..bea1206 100644 |
676 | --- a/lib/lp/soyuz/doc/gina.rst |
677 | +++ b/lib/lp/soyuz/doc/gina.rst |
678 | @@ -30,7 +30,7 @@ Get the current counts of stuff in the database: |
679 | >>> orig_tp_count = ( |
680 | ... IStore(TeamParticipation).find(TeamParticipation).count() |
681 | ... ) |
682 | - >>> orig_email_count = EmailAddress.select().count() |
683 | + >>> orig_email_count = IStore(EmailAddress).find(EmailAddress).count() |
684 | >>> orig_bpr_count = ( |
685 | ... IStore(BinaryPackageRelease).find(BinaryPackageRelease).count() |
686 | ... ) |
687 | @@ -599,7 +599,9 @@ Kamion, 2 being uploaded by mdz and 2 by doko). |
688 | ... - orig_tp_count |
689 | ... ) |
690 | 13 |
691 | - >>> print(EmailAddress.select().count() - orig_email_count) |
692 | + >>> print( |
693 | + ... IStore(EmailAddress).find(EmailAddress).count() - orig_email_count |
694 | + ... ) |
695 | 13 |
696 | |
697 | |
698 | @@ -695,7 +697,9 @@ changed, etc. |
699 | ... - orig_tp_count |
700 | ... ) |
701 | 13 |
702 | - >>> print(EmailAddress.select().count() - orig_email_count) |
703 | + >>> print( |
704 | + ... IStore(EmailAddress).find(EmailAddress).count() - orig_email_count |
705 | + ... ) |
706 | 13 |
707 | >>> ( |
708 | ... IStore(BinaryPackageRelease).find(BinaryPackageRelease).count() |
709 | diff --git a/lib/lp/soyuz/model/archivesubscriber.py b/lib/lp/soyuz/model/archivesubscriber.py |
710 | index d57cf23..0ff0cc7 100644 |
711 | --- a/lib/lp/soyuz/model/archivesubscriber.py |
712 | +++ b/lib/lp/soyuz/model/archivesubscriber.py |
713 | @@ -116,7 +116,7 @@ class ArchiveSubscriber(StormBase): |
714 | |
715 | # Only return people with preferred email address set. |
716 | preferred_email = Join( |
717 | - EmailAddress, EmailAddress.personID == Person.id |
718 | + EmailAddress, EmailAddress.person_id == Person.id |
719 | ) |
720 | |
721 | # We want to get all participants who are themselves |
722 | @@ -151,7 +151,7 @@ class ArchiveSubscriber(StormBase): |
723 | return store.find( |
724 | (Person, EmailAddress), |
725 | Person.id == self.subscriber_id, |
726 | - EmailAddress.personID == Person.id, |
727 | + EmailAddress.person_id == Person.id, |
728 | EmailAddress.status == EmailAddressStatus.PREFERRED, |
729 | ) |
730 | |
731 | diff --git a/lib/lp/soyuz/tests/test_doc.py b/lib/lp/soyuz/tests/test_doc.py |
732 | index f316ab8..936370b 100644 |
733 | --- a/lib/lp/soyuz/tests/test_doc.py |
734 | +++ b/lib/lp/soyuz/tests/test_doc.py |
735 | @@ -12,6 +12,9 @@ import unittest |
736 | import transaction |
737 | |
738 | from lp.services.config import config |
739 | +from lp.services.database.interfaces import IStore |
740 | +from lp.services.identity.interfaces.emailaddress import EmailAddressStatus |
741 | +from lp.services.identity.model.emailaddress import EmailAddress |
742 | from lp.testing import logout |
743 | from lp.testing.dbuser import switch_dbuser |
744 | from lp.testing.layers import LaunchpadFunctionalLayer, LaunchpadZopelessLayer |
745 | @@ -35,11 +38,10 @@ def lobotomize_stevea(): |
746 | code that did not use the ValidPersonOrTeamCache to determine |
747 | validity. |
748 | """ |
749 | - from lp.services.identity.interfaces.emailaddress import EmailAddressStatus |
750 | - from lp.services.identity.model.emailaddress import EmailAddress |
751 | - |
752 | - stevea_emailaddress = EmailAddress.byEmail( |
753 | - "steve.alexander@ubuntulinux.com" |
754 | + stevea_emailaddress = ( |
755 | + IStore(EmailAddress) |
756 | + .find(EmailAddress, email="steve.alexander@ubuntulinux.com") |
757 | + .one() |
758 | ) |
759 | stevea_emailaddress.status = EmailAddressStatus.NEW |
760 | transaction.commit() |
LGTM