Merge lp:~jcsackett/launchpad/merge-ppas-697685 into lp:launchpad

Proposed by j.c.sackett
Status: Merged
Approved by: j.c.sackett
Approved revision: no longer in the source branch.
Merged at revision: 12195
Proposed branch: lp:~jcsackett/launchpad/merge-ppas-697685
Merge into: lp:launchpad
Diff against target: 183 lines (+106/-53)
2 files modified
lib/lp/registry/browser/peoplemerge.py (+77/-53)
lib/lp/registry/browser/tests/test_peoplemerge.py (+29/-0)
To merge this branch: bzr merge lp:~jcsackett/launchpad/merge-ppas-697685
Reviewer Review Type Date Requested Status
Abel Deuring (community) code Approve
Review via email: mp+45450@code.launchpad.net

Commit message

[r=adeuring][ui=none][bug=697685] Adds validation to RequestPeopleMergeView so that persons with PPAs cannot be merged.

Description of the change

Summary
=======

For a merge to happen, the duplicate entity (team or person) being merged can't have PPAs. This was already prevented from happening in the AdminMerge views, but not in the RequestPeopleMergeView, which is generally used by a person trying to merge another person into their account. The RequestPeopleMergeView needs to have the same validation checks as the AdminMerge views.

Proposed Fix
============

Add the validation step used in AdminMerge views to the other view.

Preimplementation Talk
======================

Spoke with Curtis Hovey about the validation needs.

Implementation
==============

lib/lp/registry/browser/peoplemerge.py
--------------------------------------

A new class, ValidatingMergeView was created that contains the validation step used in AdminMergeBaseView. AdminMergeBaseView and RequestPeopleMergeView both now inherit from this, instead of directly from LaunchpadFormView.

Additionally, the step in validation checking for PPAs now first checks that the dupe person is not None; if the dupe is None, the error is handled by the vocabularies governing merges, so this is safe to do, and prevents an error when the validator tries to find PPAs for NoneType.

Lastly, RequestPeopleMergeView has been grouped with the other RequestPeople merge views, so it's clear in a read through that there are related classes.

lib/lp/registry/browser/tests/test_peoplemerge.py
-------------------------------------------------

Create a new test case to test that duplicate people with ppas cause an error on the RequestPeopleMergeView.

Tests
=====

bin/test -t peoplemerge

Demo & QA
=========

Attempt to merge a person with a PPA into the account you're logged into through +requestmerge. It should provide an error saying you need to delete the PPA.

Obviously, do this on qastaging or launchpad.dev :-P

Lint
====

make lint output:

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/registry/browser/peoplemerge.py
  lib/lp/registry/browser/tests/test_peoplemerge.py

To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/registry/browser/peoplemerge.py'
--- lib/lp/registry/browser/peoplemerge.py 2011-01-05 01:19:24 +0000
+++ lib/lp/registry/browser/peoplemerge.py 2011-01-13 15:51:12 +0000
@@ -52,59 +52,31 @@
52from lp.soyuz.interfaces.archive import IArchiveSet52from lp.soyuz.interfaces.archive import IArchiveSet
5353
5454
55class RequestPeopleMergeView(LaunchpadFormView):55class ValidatingMergeView(LaunchpadFormView):
56 """The view for the page where the user asks a merge of two accounts.56
5757 def validate(self, data):
58 If the dupe account have only one email address we send a message to that58 """Check that user is not attempting to merge a person into itself."""
59 address and then redirect the user to other page saying that everything59 dupe_person = data.get('dupe_person')
60 went fine. Otherwise we redirect the user to another page where we list60 target_person = data.get('target_person')
61 all email addresses owned by the dupe account and the user selects which61
62 of those (s)he wants to claim.62 if dupe_person == target_person and dupe_person is not None:
63 """63 self.addError(_("You can't merge ${name} into itself.",
6464 mapping=dict(name=dupe_person.name)))
65 label = 'Merge Launchpad accounts'65 # We cannot merge if there is a PPA with published
66 page_title = label66 # packages on the duplicate, unless that PPA is removed.
67 schema = IRequestPeopleMerge67 if dupe_person is not None:
6868 dupe_person_ppas = getUtility(IArchiveSet).getPPAOwnedByPerson(
69 @property69 dupe_person, statuses=[ArchiveStatus.ACTIVE,
70 def cancel_url(self):70 ArchiveStatus.DELETING])
71 return canonical_url(getUtility(IPersonSet))71 if dupe_person_ppas is not None:
7272 self.addError(_(
73 @action('Continue', name='continue')73 "${name} has a PPA that must be deleted before it "
74 def continue_action(self, action, data):74 "can be merged. It may take ten minutes to remove the "
75 dupeaccount = data['dupe_person']75 "deleted PPA's files.",
76 if dupeaccount == self.user:76 mapping=dict(name=dupe_person.name)))
77 # Please, don't try to merge you into yourself.77
78 return78
7979class AdminMergeBaseView(ValidatingMergeView):
80 emails = getUtility(IEmailAddressSet).getByPerson(dupeaccount)
81 emails_count = emails.count()
82 if emails_count > 1:
83 # The dupe account have more than one email address. Must redirect
84 # the user to another page to ask which of those emails (s)he
85 # wants to claim.
86 self.next_url = '+requestmerge-multiple?dupe=%d' % dupeaccount.id
87 return
88
89 assert emails_count == 1
90 email = emails[0]
91 login = getUtility(ILaunchBag).login
92 logintokenset = getUtility(ILoginTokenSet)
93 # Need to remove the security proxy because the dupe account may have
94 # hidden email addresses.
95 token = logintokenset.new(
96 self.user, login, removeSecurityProxy(email).email,
97 LoginTokenType.ACCOUNTMERGE)
98
99 # XXX: SteveAlexander 2006-03-07: An experiment to see if this
100 # improves problems with merge people tests.
101 import canonical.database.sqlbase
102 canonical.database.sqlbase.flush_database_updates()
103 token.sendMergeRequestEmail()
104 self.next_url = './+mergerequest-sent?dupe=%d' % dupeaccount.id
105
106
107class AdminMergeBaseView(LaunchpadFormView):
108 """Base view for the pages where admins can merge people/teams."""80 """Base view for the pages where admins can merge people/teams."""
10981
110 page_title = 'Merge Launchpad accounts'82 page_title = 'Merge Launchpad accounts'
@@ -507,3 +479,55 @@
507 def email_hidden(self):479 def email_hidden(self):
508 """Does the duplicate account hide email addresses?"""480 """Does the duplicate account hide email addresses?"""
509 return self.dupe.hide_email_addresses481 return self.dupe.hide_email_addresses
482
483
484class RequestPeopleMergeView(ValidatingMergeView):
485 """The view for the page where the user asks a merge of two accounts.
486
487 If the dupe account have only one email address we send a message to that
488 address and then redirect the user to other page saying that everything
489 went fine. Otherwise we redirect the user to another page where we list
490 all email addresses owned by the dupe account and the user selects which
491 of those (s)he wants to claim.
492 """
493
494 label = 'Merge Launchpad accounts'
495 page_title = label
496 schema = IRequestPeopleMerge
497
498 @property
499 def cancel_url(self):
500 return canonical_url(getUtility(IPersonSet))
501
502 @action('Continue', name='continue')
503 def continue_action(self, action, data):
504 dupeaccount = data['dupe_person']
505 if dupeaccount == self.user:
506 # Please, don't try to merge you into yourself.
507 return
508
509 emails = getUtility(IEmailAddressSet).getByPerson(dupeaccount)
510 emails_count = emails.count()
511 if emails_count > 1:
512 # The dupe account have more than one email address. Must redirect
513 # the user to another page to ask which of those emails (s)he
514 # wants to claim.
515 self.next_url = '+requestmerge-multiple?dupe=%d' % dupeaccount.id
516 return
517
518 assert emails_count == 1
519 email = emails[0]
520 login = getUtility(ILaunchBag).login
521 logintokenset = getUtility(ILoginTokenSet)
522 # Need to remove the security proxy because the dupe account may have
523 # hidden email addresses.
524 token = logintokenset.new(
525 self.user, login, removeSecurityProxy(email).email,
526 LoginTokenType.ACCOUNTMERGE)
527
528 # XXX: SteveAlexander 2006-03-07: An experiment to see if this
529 # improves problems with merge people tests.
530 import canonical.database.sqlbase
531 canonical.database.sqlbase.flush_database_updates()
532 token.sendMergeRequestEmail()
533 self.next_url = './+mergerequest-sent?dupe=%d' % dupeaccount.id
510534
=== modified file 'lib/lp/registry/browser/tests/test_peoplemerge.py'
--- lib/lp/registry/browser/tests/test_peoplemerge.py 2010-12-21 19:42:00 +0000
+++ lib/lp/registry/browser/tests/test_peoplemerge.py 2011-01-13 15:51:12 +0000
@@ -30,6 +30,35 @@
30 )30 )
3131
3232
33class TestRequestPeopleMergeView(TestCaseWithFactory):
34
35 layer = DatabaseFunctionalLayer
36
37 def setUp(self):
38 super(TestRequestPeopleMergeView, self).setUp()
39 self.person_set = getUtility(IPersonSet)
40 self.dupe = self.factory.makePerson(name='dupe')
41 self.target = self.factory.makeTeam(name='target')
42
43 def test_cannot_merge_person_with_ppas(self):
44 # A team with a PPA cannot be merged.
45 login_celebrity('admin')
46 archive = self.dupe.createPPA()
47 login_celebrity('registry_experts')
48 form = {
49 'field.dupe_person': self.dupe.name,
50 'field.target_person': self.target.name,
51 'field.actions.continue': 'Continue',
52 }
53 view = create_initialized_view(
54 self.person_set, '+requestmerge', form=form)
55 self.assertEqual(
56 [u"dupe has a PPA that must be deleted before it can be "
57 "merged. It may take ten minutes to remove the deleted PPA's "
58 "files."],
59 view.errors)
60
61
33class TestRequestPeopleMergeMultipleEmailsView(TestCaseWithFactory):62class TestRequestPeopleMergeMultipleEmailsView(TestCaseWithFactory):
34 """Test the RequestPeopleMergeMultipleEmailsView rules."""63 """Test the RequestPeopleMergeMultipleEmailsView rules."""
3564