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
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2010-04-19 03:44:27 +0000
+++ lib/lp/registry/browser/person.py 2010-05-11 12:33:46 +0000
@@ -133,6 +133,7 @@
133from canonical.launchpad.browser.launchpad import get_launchpad_views133from canonical.launchpad.browser.launchpad import get_launchpad_views
134from canonical.launchpad.interfaces.account import IAccount134from canonical.launchpad.interfaces.account import IAccount
135from canonical.launchpad.interfaces.account import AccountStatus135from canonical.launchpad.interfaces.account import AccountStatus
136from lp.soyuz.interfaces.archive import ArchiveStatus
136from lp.soyuz.interfaces.archivesubscriber import (137from lp.soyuz.interfaces.archivesubscriber import (
137 IArchiveSubscriberSet)138 IArchiveSubscriberSet)
138from canonical.launchpad.interfaces.authtoken import LoginTokenType139from canonical.launchpad.interfaces.authtoken import LoginTokenType
@@ -3870,14 +3871,19 @@
38703871
3871 When a user has a PPA renames are prohibited.3872 When a user has a PPA renames are prohibited.
3872 """3873 """
3873 writable = self.context.archive is None3874 active_ppas = [
3874 if not writable:3875 ppa for ppa in self.context.ppas
3876 if ppa.status in (ArchiveStatus.ACTIVE, ArchiveStatus.DELETING)]
3877 num_packages = sum(
3878 ppa.getPublishedSources().count() for ppa in active_ppas)
3879 if num_packages > 0:
3875 # This makes the field's widget display (i.e. read) only.3880 # This makes the field's widget display (i.e. read) only.
3876 self.form_fields['name'].for_display = True3881 self.form_fields['name'].for_display = True
3877 super(PersonEditView, self).setUpWidgets()3882 super(PersonEditView, self).setUpWidgets()
3878 if not writable:3883 if num_packages > 0:
3879 self.widgets['name'].hint = _(3884 self.widgets['name'].hint = _(
3880 'This user has a PPA and may not be renamed.')3885 'This user has an active PPA with packages published and '
3886 'may not be renamed.')
38813887
3882 def validate(self, data):3888 def validate(self, data):
3883 """If the name changed, warn the user about the implications."""3889 """If the name changed, warn the user about the implications."""
38843890
=== modified file 'lib/lp/registry/browser/tests/test_person_view.py'
--- lib/lp/registry/browser/tests/test_person_view.py 2010-04-12 06:03:57 +0000
+++ lib/lp/registry/browser/tests/test_person_view.py 2010-05-11 12:33:46 +0000
@@ -13,8 +13,10 @@
13from lp.registry.interfaces.karma import IKarmaCacheManager13from lp.registry.interfaces.karma import IKarmaCacheManager
14from canonical.launchpad.webapp.servers import LaunchpadTestRequest14from canonical.launchpad.webapp.servers import LaunchpadTestRequest
15from canonical.testing import LaunchpadFunctionalLayer, LaunchpadZopelessLayer15from canonical.testing import LaunchpadFunctionalLayer, LaunchpadZopelessLayer
16from lp.registry.browser.person import PersonView16from lp.registry.browser.person import PersonEditView, PersonView
17from lp.registry.model.karma import KarmaCategory17from lp.registry.model.karma import KarmaCategory
18from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
19from lp.soyuz.interfaces.archive import ArchiveStatus
18from lp.testing import TestCaseWithFactory, login_person20from lp.testing import TestCaseWithFactory, login_person
1921
2022
@@ -168,5 +170,61 @@
168 self.failUnless(person_view.should_show_ppa_section)170 self.failUnless(person_view.should_show_ppa_section)
169171
170172
173class TestPersonEditView(TestCaseWithFactory):
174
175 layer = LaunchpadFunctionalLayer
176
177 def setUp(self):
178 TestCaseWithFactory.setUp(self)
179 self.person = self.factory.makePerson()
180 login_person(self.person)
181 self.ppa = self.factory.makeArchive(owner=self.person)
182 self.view = PersonEditView(
183 self.person, LaunchpadTestRequest())
184
185 def test_can_rename_with_empty_PPA(self):
186 # If a PPA exists but has no packages, we can rename the
187 # person.
188 self.view.initialize()
189 self.assertFalse(self.view.form_fields['name'].for_display)
190
191 def _publishPPAPackage(self):
192 stp = SoyuzTestPublisher()
193 stp.setUpDefaultDistroSeries()
194 stp.getPubSource(archive=self.ppa)
195
196 def test_cannot_rename_with_non_empty_PPA(self):
197 # Publish some packages in the PPA and test that we can't rename
198 # the person.
199 self._publishPPAPackage()
200 self.view.initialize()
201 self.assertTrue(self.view.form_fields['name'].for_display)
202 self.assertEqual(
203 self.view.widgets['name'].hint,
204 "This user has an active PPA with packages published and "
205 "may not be renamed.")
206
207 def test_cannot_rename_with_deleting_PPA(self):
208 # When a PPA is in the DELETING state we should not allow
209 # renaming just yet.
210 self._publishPPAPackage()
211 self.view.initialize()
212 self.ppa.delete(self.person)
213 self.assertEqual(self.ppa.status, ArchiveStatus.DELETING)
214 self.assertTrue(self.view.form_fields['name'].for_display)
215
216 def test_can_rename_with_deleted_PPA(self):
217 # Delete a PPA and test that the person can be renamed.
218 self._publishPPAPackage()
219 # Deleting the PPA will remove the publications, which is
220 # necessary for the renaming check.
221 self.ppa.delete(self.person)
222 # Simulate the external script running and finalising the
223 # DELETED status.
224 self.ppa.status = ArchiveStatus.DELETED
225 self.view.initialize()
226 self.assertFalse(self.view.form_fields['name'].for_display)
227
228
171def test_suite():229def test_suite():
172 return unittest.TestLoader().loadTestsFromName(__name__)230 return unittest.TestLoader().loadTestsFromName(__name__)
173231
=== modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt'
--- lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt 2010-03-26 17:30:33 +0000
+++ lib/lp/soyuz/stories/ppa/xx-ppa-workflow.txt 2010-05-11 12:33:46 +0000
@@ -46,12 +46,13 @@
46text-area.46text-area.
4747
48There is also a message, near the form actions, in which the user is48There is also a message, near the form actions, in which the user is
49warned about the fact the activating this PPA will block renaming of49warned about the fact that if the user has any PPAs with published
50the context launchpad user.50packages then they will not be able to rename their account.
5151
52 >>> print extract_text(52 >>> print extract_text(
53 ... first_tag_by_class(sample_browser.contents, 'actions'))53 ... first_tag_by_class(sample_browser.contents, 'actions'))
54 Activating this PPA will block future renaming of Sample Person54 If you have any PPAs with published packages, you will not be able to
55 rename ... until those PPAs are deleted.
55 ...56 ...
5657
57'PPA name' and 'Displayname' are required fields. For the first activated58'PPA name' and 'Displayname' are required fields. For the first activated
@@ -149,25 +150,6 @@
149 There is 1 error.150 There is 1 error.
150 Required input is missing.151 Required input is missing.
151152
152Once the PPA is activated, the Sample user account cannot be renamed
153anymore. Changing the account name affects the PPA repository paths
154and we don't have infrastructure in place to support that yet. See
155more information about the feature in bug #87326.
156
157 >>> sample_browser.open("http://launchpad.dev/~name12/+edit")
158 >>> sample_browser.getControl(name='field.name').value = 'el-duderino'
159 Traceback (most recent call last):
160 ...
161 LookupError: name 'field.name'
162
163 >>> print extract_text(
164 ... first_tag_by_class(sample_browser.contents, 'form'))
165 Display Name:
166 ...
167 Name: name12
168 This user has a PPA and may not be renamed.
169 ...
170
171153
172== Activating Personal Package Archives for Teams ==154== Activating Personal Package Archives for Teams ==
173155
@@ -215,7 +197,8 @@
215197
216 >>> print extract_text(198 >>> print extract_text(
217 ... first_tag_by_class(sample_browser.contents, 'actions'))199 ... first_tag_by_class(sample_browser.contents, 'actions'))
218 Activating this PPA will block future renaming of Landscape Developers200 If you have any PPAs with published packages, you will not be able to
201 rename ... until those PPAs are deleted.
219 ...202 ...
220203
221That understood, the PPA gets activated.204That understood, the PPA gets activated.
@@ -585,15 +568,6 @@
585 A short description of this PPA. URLs are allowed and will be rendered568 A short description of this PPA. URLs are allowed and will be rendered
586 as links.569 as links.
587570
588Note that, differently than the time when the first PPA was activated,
589this time there is no warning about the fact that the context renaming
590will be blocked. We assumed that, at this point, this is already a
591known aspect.
592
593 >>> print extract_text(
594 ... first_tag_by_class(cprov_browser.contents, 'actions'))
595 or Cancel
596
597The 'PPA name' field is not pre-filled and if Celso does not fill it then571The 'PPA name' field is not pre-filled and if Celso does not fill it then
598an error is raised.572an error is raised.
599573
600574
=== modified file 'lib/lp/soyuz/templates/archive-activate.pt'
--- lib/lp/soyuz/templates/archive-activate.pt 2009-10-12 11:35:06 +0000
+++ lib/lp/soyuz/templates/archive-activate.pt 2010-05-11 12:33:46 +0000
@@ -41,10 +41,11 @@
41 </div>41 </div>
4242
43 <div class="actions" metal:fill-slot="buttons">43 <div class="actions" metal:fill-slot="buttons">
44 <p tal:condition="not: context/ppas">44 <p>
45 <img src="/@@/warning" />45 <img src="/@@/warning" />
46 Activating this PPA <b>will block</b> future renaming of46 If you have any PPAs with published packages, you will not be able to
47 <tal:context replace="structure context/fmt:link" />47 rename <tal:context replace="structure context/fmt:link" /> until
48 those PPAs are deleted.
48 </p>49 </p>
49 <input tal:replace="structure view/actions/field.actions.activate/render" />50 <input tal:replace="structure view/actions/field.actions.activate/render" />
50 or <a tal:attributes="href context/fmt:url">Cancel</a>51 or <a tal:attributes="href context/fmt:url">Cancel</a>