Merge lp:~julian-edwards/launchpad/rename-account-with-ppas into lp:launchpad

Proposed by Julian Edwards
Status: Merged
Approved by: Данило Шеган
Approved revision: no longer in the source branch.
Merged at revision: 10848
Proposed branch: lp:~julian-edwards/launchpad/rename-account-with-ppas
Merge into: lp:launchpad
Diff against target: 205 lines (+79/-40)
4 files modified
lib/lp/registry/browser/person.py (+10/-4)
lib/lp/registry/browser/tests/test_person_view.py (+59/-1)
lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt (+6/-32)
lib/lp/soyuz/templates/archive-activate.pt (+4/-3)
To merge this branch: bzr merge lp:~julian-edwards/launchpad/rename-account-with-ppas
Reviewer Review Type Date Requested Status
Данило Шеган (community) Approve
Review via email: mp+25042@code.launchpad.net

Description of the change

= Summary =
Allow account renaming when all PPAs are deleted

== Proposed fix ==
Change the account +edit form so that the account can be renamed if:
a) the user has no PPAs
b) the user has a PPA but it has no packages
c) the user had PPAs but they are all deleted

== Pre-implementation notes ==
This was pair-programmed with noodles!

== Implementation details ==
Fairly simple steps:
1. The browser setupWidgets() was changed to disabled/enable the name field
appropriately
2. I added a new TestPersonEditView that unit tests setupWidgets.
3. Fixed the ppa-workflow doctest to remove unit test stuff therein.
4. Changed the activation template so that it has a slightly different warning
message.

== Tests ==
bin/test -cvvt xx-ppa-workflow.txt -t TestPersonEditView

== Demo and Q/A ==
I can Q/A this on dogfood before it lands using some dummy accounts and PPAs.
It's a pretty high-profile bug so I don't want to QA it on edge after it lands
and the world sees it.

To post a comment you must log in.
Revision history for this message
Данило Шеган (danilo) wrote :

"if has_packages" should probably be "if has_packages > 0", and the variable name should better reflect that it's a count of published packages for the person

In test_can_rename_with_deleted_PPA, I assume ppa.delete() sets the status to DELETING, so you should probably test that case separately (since DELETING is still not DELETED :): keep the existing test, but add another one for 'deleting' state if that makes sense.

For the existing 'deleted' test you most likely don't even need to call ppa.delete() since you hard-code the status to DELETED anyway, right? If I am smoking crack, just ignore this comment.

Nice job switching to a unit test!

review: Needs Fixing
Revision history for this message
Julian Edwards (julian-edwards) wrote :

Thanks for the review!

> "if has_packages" should probably be "if has_packages > 0", and the
> variable name should better reflect that it's a count of published
> packages for the person

Okay, I changed it.

> In test_can_rename_with_deleted_PPA, I assume ppa.delete() sets the status
> to DELETING, so you should probably test that case separately (since
> DELETING is still not DELETED :): keep the existing test, but add another
> one for 'deleting' state if that makes sense.

Good catch! I've added an additional test for this.

> For the existing 'deleted' test you most likely don't even need to call
> ppa.delete() since you hard-code the status to DELETED anyway, right? If
> I am smoking crack, just ignore this comment.

You're smoking crack :)

Deleting a PPA also sets all its publications to DELETED, which is also
necessary to rename your account. I changed a comment to make that clearer in
the test.

> Nice job switching to a unit test!

Thanks!

Partial diff attached.

Cheers
J

Revision history for this message
Данило Шеган (danilo) wrote :

Looks good, thanks for all the fish (and crack).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/person.py'
2--- lib/lp/registry/browser/person.py 2010-04-19 03:44:27 +0000
3+++ lib/lp/registry/browser/person.py 2010-05-11 12:33:46 +0000
4@@ -133,6 +133,7 @@
5 from canonical.launchpad.browser.launchpad import get_launchpad_views
6 from canonical.launchpad.interfaces.account import IAccount
7 from canonical.launchpad.interfaces.account import AccountStatus
8+from lp.soyuz.interfaces.archive import ArchiveStatus
9 from lp.soyuz.interfaces.archivesubscriber import (
10 IArchiveSubscriberSet)
11 from canonical.launchpad.interfaces.authtoken import LoginTokenType
12@@ -3870,14 +3871,19 @@
13
14 When a user has a PPA renames are prohibited.
15 """
16- writable = self.context.archive is None
17- if not writable:
18+ active_ppas = [
19+ ppa for ppa in self.context.ppas
20+ if ppa.status in (ArchiveStatus.ACTIVE, ArchiveStatus.DELETING)]
21+ num_packages = sum(
22+ ppa.getPublishedSources().count() for ppa in active_ppas)
23+ if num_packages > 0:
24 # This makes the field's widget display (i.e. read) only.
25 self.form_fields['name'].for_display = True
26 super(PersonEditView, self).setUpWidgets()
27- if not writable:
28+ if num_packages > 0:
29 self.widgets['name'].hint = _(
30- 'This user has a PPA and may not be renamed.')
31+ 'This user has an active PPA with packages published and '
32+ 'may not be renamed.')
33
34 def validate(self, data):
35 """If the name changed, warn the user about the implications."""
36
37=== modified file 'lib/lp/registry/browser/tests/test_person_view.py'
38--- lib/lp/registry/browser/tests/test_person_view.py 2010-04-12 06:03:57 +0000
39+++ lib/lp/registry/browser/tests/test_person_view.py 2010-05-11 12:33:46 +0000
40@@ -13,8 +13,10 @@
41 from lp.registry.interfaces.karma import IKarmaCacheManager
42 from canonical.launchpad.webapp.servers import LaunchpadTestRequest
43 from canonical.testing import LaunchpadFunctionalLayer, LaunchpadZopelessLayer
44-from lp.registry.browser.person import PersonView
45+from lp.registry.browser.person import PersonEditView, PersonView
46 from lp.registry.model.karma import KarmaCategory
47+from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
48+from lp.soyuz.interfaces.archive import ArchiveStatus
49 from lp.testing import TestCaseWithFactory, login_person
50
51
52@@ -168,5 +170,61 @@
53 self.failUnless(person_view.should_show_ppa_section)
54
55
56+class TestPersonEditView(TestCaseWithFactory):
57+
58+ layer = LaunchpadFunctionalLayer
59+
60+ def setUp(self):
61+ TestCaseWithFactory.setUp(self)
62+ self.person = self.factory.makePerson()
63+ login_person(self.person)
64+ self.ppa = self.factory.makeArchive(owner=self.person)
65+ self.view = PersonEditView(
66+ self.person, LaunchpadTestRequest())
67+
68+ def test_can_rename_with_empty_PPA(self):
69+ # If a PPA exists but has no packages, we can rename the
70+ # person.
71+ self.view.initialize()
72+ self.assertFalse(self.view.form_fields['name'].for_display)
73+
74+ def _publishPPAPackage(self):
75+ stp = SoyuzTestPublisher()
76+ stp.setUpDefaultDistroSeries()
77+ stp.getPubSource(archive=self.ppa)
78+
79+ def test_cannot_rename_with_non_empty_PPA(self):
80+ # Publish some packages in the PPA and test that we can't rename
81+ # the person.
82+ self._publishPPAPackage()
83+ self.view.initialize()
84+ self.assertTrue(self.view.form_fields['name'].for_display)
85+ self.assertEqual(
86+ self.view.widgets['name'].hint,
87+ "This user has an active PPA with packages published and "
88+ "may not be renamed.")
89+
90+ def test_cannot_rename_with_deleting_PPA(self):
91+ # When a PPA is in the DELETING state we should not allow
92+ # renaming just yet.
93+ self._publishPPAPackage()
94+ self.view.initialize()
95+ self.ppa.delete(self.person)
96+ self.assertEqual(self.ppa.status, ArchiveStatus.DELETING)
97+ self.assertTrue(self.view.form_fields['name'].for_display)
98+
99+ def test_can_rename_with_deleted_PPA(self):
100+ # Delete a PPA and test that the person can be renamed.
101+ self._publishPPAPackage()
102+ # Deleting the PPA will remove the publications, which is
103+ # necessary for the renaming check.
104+ self.ppa.delete(self.person)
105+ # Simulate the external script running and finalising the
106+ # DELETED status.
107+ self.ppa.status = ArchiveStatus.DELETED
108+ self.view.initialize()
109+ self.assertFalse(self.view.form_fields['name'].for_display)
110+
111+
112 def test_suite():
113 return unittest.TestLoader().loadTestsFromName(__name__)
114
115=== modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt'
116--- lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt 2010-03-26 17:30:33 +0000
117+++ lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt 2010-05-11 12:33:46 +0000
118@@ -46,12 +46,13 @@
119 text-area.
120
121 There is also a message, near the form actions, in which the user is
122-warned about the fact the activating this PPA will block renaming of
123-the context launchpad user.
124+warned about the fact that if the user has any PPAs with published
125+packages then they will not be able to rename their account.
126
127 >>> print extract_text(
128 ... first_tag_by_class(sample_browser.contents, 'actions'))
129- Activating this PPA will block future renaming of Sample Person
130+ If you have any PPAs with published packages, you will not be able to
131+ rename ... until those PPAs are deleted.
132 ...
133
134 'PPA name' and 'Displayname' are required fields. For the first activated
135@@ -149,25 +150,6 @@
136 There is 1 error.
137 Required input is missing.
138
139-Once the PPA is activated, the Sample user account cannot be renamed
140-anymore. Changing the account name affects the PPA repository paths
141-and we don't have infrastructure in place to support that yet. See
142-more information about the feature in bug #87326.
143-
144- >>> sample_browser.open("http://launchpad.dev/~name12/+edit")
145- >>> sample_browser.getControl(name='field.name').value = 'el-duderino'
146- Traceback (most recent call last):
147- ...
148- LookupError: name 'field.name'
149-
150- >>> print extract_text(
151- ... first_tag_by_class(sample_browser.contents, 'form'))
152- Display Name:
153- ...
154- Name: name12
155- This user has a PPA and may not be renamed.
156- ...
157-
158
159 == Activating Personal Package Archives for Teams ==
160
161@@ -215,7 +197,8 @@
162
163 >>> print extract_text(
164 ... first_tag_by_class(sample_browser.contents, 'actions'))
165- Activating this PPA will block future renaming of Landscape Developers
166+ If you have any PPAs with published packages, you will not be able to
167+ rename ... until those PPAs are deleted.
168 ...
169
170 That understood, the PPA gets activated.
171@@ -585,15 +568,6 @@
172 A short description of this PPA. URLs are allowed and will be rendered
173 as links.
174
175-Note that, differently than the time when the first PPA was activated,
176-this time there is no warning about the fact that the context renaming
177-will be blocked. We assumed that, at this point, this is already a
178-known aspect.
179-
180- >>> print extract_text(
181- ... first_tag_by_class(cprov_browser.contents, 'actions'))
182- or Cancel
183-
184 The 'PPA name' field is not pre-filled and if Celso does not fill it then
185 an error is raised.
186
187
188=== modified file 'lib/lp/soyuz/templates/archive-activate.pt'
189--- lib/lp/soyuz/templates/archive-activate.pt 2009-10-12 11:35:06 +0000
190+++ lib/lp/soyuz/templates/archive-activate.pt 2010-05-11 12:33:46 +0000
191@@ -41,10 +41,11 @@
192 </div>
193
194 <div class="actions" metal:fill-slot="buttons">
195- <p tal:condition="not: context/ppas">
196+ <p>
197 <img src="/@@/warning" />
198- Activating this PPA <b>will block</b> future renaming of
199- <tal:context replace="structure context/fmt:link" />
200+ If you have any PPAs with published packages, you will not be able to
201+ rename <tal:context replace="structure context/fmt:link" /> until
202+ those PPAs are deleted.
203 </p>
204 <input tal:replace="structure view/actions/field.actions.activate/render" />
205 or <a tal:attributes="href context/fmt:url">Cancel</a>