Merge lp:~stevenk/launchpad/no-private-registrant-setbranch-redux into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16111
Proposed branch: lp:~stevenk/launchpad/no-private-registrant-setbranch-redux
Merge into: lp:launchpad
Diff against target: 160 lines (+42/-44)
2 files modified
lib/lp/registry/browser/productseries.py (+23/-44)
lib/lp/registry/browser/tests/productseries-setbranch-view.txt (+19/-0)
To merge this branch: bzr merge lp:~stevenk/launchpad/no-private-registrant-setbranch-redux
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve
Review via email: mp+128415@code.launchpad.net

Commit message

Show a field error if we attempt to create a code import owned by a private team in ProductSeries:+setbranch.

Description of the change

While the first branch that attempted to fix this bug was fine in it's own right, it replaced one OOPS with another. This one wasn't deep in the guts of Storm, and was quite easy to ascertain meaning from. Code imports are not allowed to be owned by private teams, so we check for that and set a field error if so.

My CDO prevented me from putting up a branch that wasn't net-negative, so it contains more whitespace cleanups. I also removed a quote function that didn't seem to be called by anything.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Francis reset the squad's Lines when we started Maintenance. Your count is -954 as of today.
    ~/Work/lp-dev-utils/loc-contributions --start-rev=15931 <email address hidden>

Revision history for this message
Ian Booth (wallyworld) wrote :

Looks good

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/productseries.py'
--- lib/lp/registry/browser/productseries.py 2012-10-05 07:10:15 +0000
+++ lib/lp/registry/browser/productseries.py 2012-10-08 05:07:24 +0000
@@ -29,7 +29,6 @@
29 'ProductSeriesView',29 'ProductSeriesView',
30 ]30 ]
3131
32import cgi
33from operator import attrgetter32from operator import attrgetter
3433
35from bzrlib.revision import NULL_REVISION34from bzrlib.revision import NULL_REVISION
@@ -145,11 +144,6 @@
145 )144 )
146145
147146
148def quote(text):
149 """Escape and quote text."""
150 return cgi.escape(text, quote=True)
151
152
153class ProductSeriesNavigation(Navigation, BugTargetTraversalMixin,147class ProductSeriesNavigation(Navigation, BugTargetTraversalMixin,
154 StructuralSubscriptionTargetTraversalMixin):148 StructuralSubscriptionTargetTraversalMixin):
155 """A class to navigate `IProductSeries` URLs."""149 """A class to navigate `IProductSeries` URLs."""
@@ -683,10 +677,7 @@
683 """See `LaunchpadFormView`."""677 """See `LaunchpadFormView`."""
684 return canonical_url(self.context)678 return canonical_url(self.context)
685679
686 @property680 cancel_url = next_url
687 def cancel_url(self):
688 """See `LaunchpadFormView`."""
689 return canonical_url(self.context)
690681
691682
692class ProductSeriesDeleteView(RegistryDeleteViewMixin, LaunchpadEditFormView):683class ProductSeriesDeleteView(RegistryDeleteViewMixin, LaunchpadEditFormView):
@@ -813,9 +804,7 @@
813class SetBranchForm(Interface):804class SetBranchForm(Interface):
814 """The fields presented on the form for setting a branch."""805 """The fields presented on the form for setting a branch."""
815806
816 use_template(807 use_template(ICodeImport, ['cvs_module'])
817 ICodeImport,
818 ['cvs_module'])
819808
820 rcs_type = Choice(title=_("Type of RCS"),809 rcs_type = Choice(title=_("Type of RCS"),
821 required=False, vocabulary=RevisionControlSystems,810 required=False, vocabulary=RevisionControlSystems,
@@ -826,42 +815,27 @@
826 title=_("Branch URL"), required=True,815 title=_("Branch URL"), required=True,
827 description=_("The URL of the branch."),816 description=_("The URL of the branch."),
828 allowed_schemes=["http", "https"],817 allowed_schemes=["http", "https"],
829 allow_userinfo=False,818 allow_userinfo=False, allow_port=True, allow_query=False,
830 allow_port=True,819 allow_fragment=False, trailing_slash=False)
831 allow_query=False,
832 allow_fragment=False,
833 trailing_slash=False)
834820
835 branch_location = copy_field(821 branch_location = copy_field(
836 IProductSeries['branch'],822 IProductSeries['branch'], __name__='branch_location',
837 __name__='branch_location',
838 title=_('Branch'),823 title=_('Branch'),
839 description=_(824 description=_(
840 "The Bazaar branch for this series in Launchpad, "825 "The Bazaar branch for this series in Launchpad, "
841 "if one exists."),826 "if one exists."))
842 )
843827
844 branch_type = Choice(828 branch_type = Choice(
845 title=_('Import type'),829 title=_('Import type'), vocabulary=BRANCH_TYPE_VOCABULARY,
846 vocabulary=BRANCH_TYPE_VOCABULARY,830 description=_("The type of import"), required=True)
847 description=_("The type of import"),
848 required=True)
849831
850 branch_name = copy_field(832 branch_name = copy_field(
851 IBranch['name'],833 IBranch['name'], __name__='branch_name', title=_('Branch name'),
852 __name__='branch_name',834 description=_(''), required=True)
853 title=_('Branch name'),
854 description=_(''),
855 required=True,
856 )
857835
858 branch_owner = copy_field(836 branch_owner = copy_field(
859 IBranch['owner'],837 IBranch['owner'], __name__='branch_owner', title=_('Branch owner'),
860 __name__='branch_owner',838 description=_(''), required=True)
861 title=_('Branch owner'),
862 description=_(''),
863 required=True,
864 )
865839
866840
867class ProductSeriesSetBranchView(ReturnToReferrerMixin, LaunchpadFormView,841class ProductSeriesSetBranchView(ReturnToReferrerMixin, LaunchpadFormView,
@@ -936,9 +910,16 @@
936 rcs_type = data.get('rcs_type')910 rcs_type = data.get('rcs_type')
937 repo_url = data.get('repo_url')911 repo_url = data.get('repo_url')
938912
913 # Private teams are forbidden from owning code imports.
914 branch_owner = data.get('branch_owner')
915 if branch_owner is not None and branch_owner.private:
916 self.setFieldError(
917 'branch_owner', 'Private teams are forbidden from owning '
918 'external imports.')
919
939 if repo_url is None:920 if repo_url is None:
940 self.setFieldError('repo_url',921 self.setFieldError(
941 'You must set the external repository URL.')922 'repo_url', 'You must set the external repository URL.')
942 else:923 else:
943 # Ensure this URL has not been imported before.924 # Ensure this URL has not been imported before.
944 code_import = getUtility(ICodeImportSet).getByURL(repo_url)925 code_import = getUtility(ICodeImportSet).getByURL(repo_url)
@@ -969,12 +950,10 @@
969 """Validate that branch name and owner are set."""950 """Validate that branch name and owner are set."""
970 if 'branch_name' not in data:951 if 'branch_name' not in data:
971 self.setFieldError(952 self.setFieldError(
972 'branch_name',953 'branch_name', 'The branch name must be set.')
973 'The branch name must be set.')
974 if 'branch_owner' not in data:954 if 'branch_owner' not in data:
975 self.setFieldError(955 self.setFieldError(
976 'branch_owner',956 'branch_owner', 'The branch owner must be set.')
977 'The branch owner must be set.')
978957
979 def _setRequired(self, names, value):958 def _setRequired(self, names, value):
980 """Mark the widget field as optional."""959 """Mark the widget field as optional."""
981960
=== modified file 'lib/lp/registry/browser/tests/productseries-setbranch-view.txt'
--- lib/lp/registry/browser/tests/productseries-setbranch-view.txt 2012-10-05 07:29:54 +0000
+++ lib/lp/registry/browser/tests/productseries-setbranch-view.txt 2012-10-08 05:07:24 +0000
@@ -377,3 +377,22 @@
377 http://launchpad.dev/chevy/corvair377 http://launchpad.dev/chevy/corvair
378 >>> for notification in view.request.response.notifications:378 >>> for notification in view.request.response.notifications:
379 ... print notification.message379 ... print notification.message
380
381If the owner is set to a private team, an error is raised.
382
383 >>> from lp.registry.enums import PersonVisibility
384 >>> private_team = factory.makeTeam(
385 ... visibility=PersonVisibility.PRIVATE, members=[driver])
386 >>> form = {
387 ... 'field.branch_type': 'import-external',
388 ... 'field.rcs_type': 'BZR',
389 ... 'field.branch_name': 'sport-branch',
390 ... 'field.branch_owner': private_team.name,
391 ... 'field.repo_url': 'http://bzr.com/sporty',
392 ... 'field.actions.update': 'Update',
393 ... }
394 >>> view = create_initialized_view(
395 ... series, name='+setbranch', principal=driver, form=form)
396 >>> for error in view.errors:
397 ... print error
398 Private teams are forbidden from owning external imports.