← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~pappacena/launchpad:snap-pillar-edit into launchpad:master

 

Thiago F. Pappacena has proposed merging ~pappacena/launchpad:snap-pillar-edit into launchpad:master with ~pappacena/launchpad:snap-pillar-list-filters as a prerequisite.

Commit message:
Moving information_type and project to snap create/edit pages

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/399121

For the browser tests, it might be better to review them by looking at the code directly. The diff got a bit hard to read after removing a few tests and adding new ones in the same place.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:snap-pillar-edit into launchpad:master.
diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py
index bd3926c..d4ba8bd 100644
--- a/lib/lp/snappy/browser/snap.py
+++ b/lib/lp/snappy/browser/snap.py
@@ -138,6 +138,49 @@ class SnapNavigation(WebhookTargetNavigationMixin, Navigation):
             return self.context.getSubscription(person)
 
 
+class SnapInformationTypeMixin:
+    def getPossibleInformationTypes(self, snap, user):
+        """Get the information types to display on the edit form.
+
+        We display a customised set of information types: anything allowed
+        by the repository's model, plus the current type.
+        """
+        allowed_types = set(snap.getAllowedInformationTypes(user))
+        allowed_types.add(snap.information_type)
+        return allowed_types
+
+    def validateInformationType(self, data, snap=None):
+        """Validates the information_type and project on data dictionary.
+
+        The possible information types are defined by the given `snap`.
+        When creating a new snap, `snap` should be None and the possible
+        information types will be calculated based on the project.
+        """
+        info_type = data.get('information_type')
+        project = data.get('project')
+        if info_type is None and project is None:
+            # Nothing to validate here. Move on.
+            return
+        if project is None and info_type in PRIVATE_INFORMATION_TYPES:
+            self.setFieldError(
+                'information_type',
+                'Private snap recipes must be associated with a project.')
+        elif project is not None:
+            if snap is None:
+                snap_set = getUtility(ISnapSet)
+                possible_types = snap_set.getPossibleSnapInformationTypes(
+                    project)
+            else:
+                possible_types = self.getPossibleInformationTypes(
+                    snap, self.user)
+            if info_type not in possible_types:
+                msg = ('Project %s only accepts the following information '
+                       'types: %s.')
+                msg %= (project.name,
+                        ", ".join(i.title for i in possible_types))
+                self.setFieldError('information_type', msg)
+
+
 class SnapBreadcrumb(NameBreadcrumb):
 
     @property
@@ -430,8 +473,8 @@ class SnapAuthorizeMixin:
             log_oops(e, self.request)
 
 
-class SnapAddView(
-        LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin):
+class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin,
+                  SnapInformationTypeMixin):
     """View for creating snap packages."""
 
     page_title = label = 'Create a new snap package'
@@ -440,6 +483,8 @@ class SnapAddView(
     field_names = [
         'owner',
         'name',
+        'project',
+        'information_type',
         'store_distro_series',
         'build_source_tarball',
         'auto_build',
@@ -559,12 +604,6 @@ class SnapAddView(
             kwargs = {'git_ref': self.context}
         else:
             kwargs = {'branch': self.context}
-        # XXX pappacena 2021-03-01: We should consider the pillar's branch
-        # sharing policy when setting the information_type.
-        # Once we move the information_type and pillar edition from the
-        # admin view to the create/edit views, we should change this.
-        information_type = getUtility(ISnapSet).getSnapSuggestedPrivacy(
-            data['owner'], **kwargs)
         if not data.get('auto_build', False):
             data['auto_build_archive'] = None
             data['auto_build_pocket'] = None
@@ -575,7 +614,8 @@ class SnapAddView(
             auto_build_archive=data['auto_build_archive'],
             auto_build_pocket=data['auto_build_pocket'],
             auto_build_channels=data['auto_build_channels'],
-            information_type=information_type,
+            information_type=data['information_type'],
+            project=data['project'],
             processors=data['processors'],
             build_source_tarball=data['build_source_tarball'],
             store_upload=data['store_upload'],
@@ -597,27 +637,19 @@ class SnapAddView(
                     'name',
                     'There is already a snap package owned by %s with this '
                     'name.' % owner.displayname)
+        self.validateInformationType(data)
 
 
-class BaseSnapEditView(LaunchpadEditFormView, SnapAuthorizeMixin):
+class BaseSnapEditView(LaunchpadEditFormView, SnapAuthorizeMixin,
+                       SnapInformationTypeMixin):
 
     schema = ISnapEditSchema
 
-    def getInformationTypesToShow(self):
-        """Get the information types to display on the edit form.
-
-        We display a customised set of information types: anything allowed
-        by the repository's model, plus the current type.
-        """
-        allowed_types = set(self.context.getAllowedInformationTypes(self.user))
-        allowed_types.add(self.context.information_type)
-        return allowed_types
-
     @property
     def cancel_url(self):
         return canonical_url(self.context)
 
-    def setUpWidgets(self):
+    def setUpWidgets(self, context=None):
         """See `LaunchpadFormView`."""
         super(BaseSnapEditView, self).setUpWidgets()
         widget = self.widgets.get('vcs')
@@ -689,13 +721,8 @@ class BaseSnapEditView(LaunchpadEditFormView, SnapAuthorizeMixin):
                     self.setFieldError(
                         'information_type' if editing_info_type else 'git_ref',
                         'A public snap cannot have a private repository.')
-        else:
-            # Requirements for private snaps.
-            project = data.get('project', self.context.project)
-            if project is None:
-                msg = ('Private snap recipes must be associated '
-                       'with a project.')
-                self.setFieldError('project', msg)
+        self.validateInformationType(data, snap=self.context)
+
 
     def _needStoreReauth(self, data):
         """Does this change require reauthorizing to the store?"""
@@ -767,11 +794,6 @@ class SnapAdminView(BaseSnapEditView):
     field_names = [
         'project', 'information_type', 'require_virtualized', 'allow_internet']
 
-    # See `setUpWidgets` method.
-    custom_widget_information_type = CustomWidgetFactory(
-        LaunchpadRadioWidgetWithDescription,
-        vocabulary=InformationTypeVocabulary(types=[]))
-
     @property
     def initial_values(self):
         """Set initial values for the form."""
@@ -781,27 +803,11 @@ class SnapAdminView(BaseSnapEditView):
         # be removed once we back fill snap.information_type.
         return {'information_type': self.context.information_type}
 
-    def setUpWidgets(self):
-        super(SnapAdminView, self).setUpWidgets()
-        info_type_widget = self.widgets['information_type']
-        info_type_widget.vocabulary = InformationTypeVocabulary(
-            types=self.getInformationTypesToShow())
-
-    def validate(self, data):
-        super(SnapAdminView, self).validate(data)
-        # BaseSnapEditView.validate checks the rules for 'private' in
-        # combination with other attributes.
-        if data.get('information_type', None) in PRIVATE_INFORMATION_TYPES:
-            if not getFeatureFlag(SNAP_PRIVATE_FEATURE_FLAG):
-                self.setFieldError(
-                    'information_type',
-                    'You do not have permission to create private snaps.')
-
     def updateContextFromData(self, data, context=None, notify_modified=True):
         if 'project' in data:
             project = data.pop('project')
             self.context.setProject(project)
-        super(SnapAdminView, self).updateContextFromData(
+        super(BaseSnapEditView, self).updateContextFromData(
             data, context, notify_modified)
 
 
@@ -817,6 +823,8 @@ class SnapEditView(BaseSnapEditView, EnableProcessorsMixin):
     field_names = [
         'owner',
         'name',
+        'project',
+        'information_type',
         'store_distro_series',
         'vcs',
         'branch',
@@ -838,6 +846,10 @@ class SnapEditView(BaseSnapEditView, EnableProcessorsMixin):
     custom_widget_auto_build_pocket = LaunchpadDropdownWidget
     custom_widget_auto_build_channels = SnapBuildChannelsWidget
     custom_widget_store_channels = StoreChannelsWidget
+    # See `setUpWidgets` method.
+    custom_widget_information_type = CustomWidgetFactory(
+        LaunchpadRadioWidgetWithDescription,
+        vocabulary=InformationTypeVocabulary(types=[]))
 
     help_links = {
         "auto_build_pocket": "/+help-snappy/snap-build-pocket.html",
@@ -852,6 +864,12 @@ class SnapEditView(BaseSnapEditView, EnableProcessorsMixin):
             "architectures are restricted and may only be enabled or "
             "disabled by administrators.")
 
+    def setUpWidgets(self, context=None):
+        super(SnapEditView, self).setUpWidgets(context)
+        info_type_widget = self.widgets['information_type']
+        info_type_widget.vocabulary = InformationTypeVocabulary(
+            types=self.getPossibleInformationTypes(self.context, self.user))
+
     @property
     def initial_values(self):
         initial_values = {}
@@ -862,6 +880,11 @@ class SnapEditView(BaseSnapEditView, EnableProcessorsMixin):
         if self.context.auto_build_pocket is None:
             initial_values['auto_build_pocket'] = (
                 PackagePublishingPocket.UPDATES)
+        # XXX pappacena 2021-02-12: Until we back fill information_type
+        # database column, it will be NULL, but snap.information_type
+        # property has a fallback to check "private" property. This should
+        # be removed once we back fill snap.information_type.
+        initial_values['information_type'] = self.context.information_type
         return initial_values
 
     def validate(self, data):
@@ -892,6 +915,13 @@ class SnapEditView(BaseSnapEditView, EnableProcessorsMixin):
                         # enabled. Leave it untouched.
                         data['processors'].append(processor)
 
+    def updateContextFromData(self, data, context=None, notify_modified=True):
+        if 'project' in data:
+            project = data.pop('project')
+            self.context.setProject(project)
+        super(BaseSnapEditView, self).updateContextFromData(
+            data, context, notify_modified)
+
 
 class SnapAuthorizeView(LaunchpadEditFormView):
     """View for authorizing snap package uploads to the store."""
diff --git a/lib/lp/snappy/browser/tests/test_snap.py b/lib/lp/snappy/browser/tests/test_snap.py
index 7b8981b..be39333 100644
--- a/lib/lp/snappy/browser/tests/test_snap.py
+++ b/lib/lp/snappy/browser/tests/test_snap.py
@@ -65,6 +65,7 @@ from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.config import config
 from lp.services.database.constants import UTC_NOW
+from lp.services.database.interfaces import IStore
 from lp.services.features.testing import FeatureFixture
 from lp.services.job.interfaces.job import JobStatus
 from lp.services.propertycache import get_property_cache
@@ -85,6 +86,7 @@ from lp.snappy.interfaces.snap import (
     )
 from lp.snappy.interfaces.snappyseries import ISnappyDistroSeriesSet
 from lp.snappy.interfaces.snapstoreclient import ISnapStoreClient
+from lp.snappy.model.snap import Snap
 from lp.testing import (
     admin_logged_in,
     BrowserTestCase,
@@ -384,87 +386,92 @@ class TestSnapAddView(BaseTestSnapView):
             browser.getLink("Create snap package")
 
     def test_create_new_snap_private(self):
-        # Private teams will automatically create private snaps.
-        self.useFixture(BranchHostingFixture(blob=b""))
+        # Creates a private snap for a private project.
         login_person(self.person)
-        self.factory.makeTeam(
-            name='super-private', owner=self.person,
-            membership_policy=TeamMembershipPolicy.MODERATED,
-            visibility=PersonVisibility.PRIVATE)
-        branch = self.factory.makeAnyBranch()
+        self.factory.makeProduct(
+            name='private-project',
+            owner=self.person, registrant=self.person,
+            information_type=InformationType.PROPRIETARY,
+            branch_sharing_policy=BranchSharingPolicy.PROPRIETARY)
+        [git_ref] = self.factory.makeGitRefs()
 
         browser = self.getViewBrowser(
-            branch, view_name="+new-snap", user=self.person)
+            git_ref, view_name="+new-snap", user=self.person)
         browser.getControl(name="field.name").value = "private-snap"
-        browser.getControl("Owner").value = ['super-private']
+        browser.getControl(name="field.information_type").value = "PROPRIETARY"
+        browser.getControl(name="field.project").value = "private-project"
         browser.getControl("Create snap package").click()
 
         content = find_main_content(browser.contents)
         self.assertEqual("private-snap", extract_text(content.h1))
         self.assertEqual(
             'This snap contains Private information',
-            extract_text(find_tag_by_id(browser.contents, "privacy"))
-        )
+            extract_text(find_tag_by_id(browser.contents, "privacy")))
+        login_admin()
+        snap = getUtility(ISnapSet).getByName(self.person, 'private-snap')
+        self.assertEqual(
+            InformationType.PROPRIETARY, snap.information_type)
 
-    def test_create_new_snap_private_team_with_private_branch(self):
-        # Creating snaps from private branch should make the snap follow its
-        # privacy setting.
-        self.useFixture(BranchHostingFixture(blob=b""))
+    def test_create_new_snap_private_without_project_fails(self):
+        # It should not not be possible to create a private snap with
+        # information_type not matching project's branch_sharing_policy.
         login_person(self.person)
-        private_team = self.factory.makeTeam(
-            name='super-private', owner=self.person,
-            membership_policy=TeamMembershipPolicy.MODERATED,
-            visibility=PersonVisibility.PRIVATE)
-        branch = self.factory.makeAnyBranch(
-            owner=self.person, registrant=self.person,
-            information_type=InformationType.PRIVATESECURITY)
+        [git_ref] = self.factory.makeGitRefs()
 
         browser = self.getViewBrowser(
-            branch, view_name="+new-snap", user=self.person)
+            git_ref, view_name="+new-snap", user=self.person)
         browser.getControl(name="field.name").value = "private-snap"
-        browser.getControl("Owner").value = ['super-private']
+        browser.getControl(name="field.information_type").value = "PROPRIETARY"
         browser.getControl("Create snap package").click()
 
         content = find_main_content(browser.contents)
-        self.assertEqual("private-snap", extract_text(content.h1))
+        self.assertEqual("Create a new snap package", extract_text(content.h1))
+        messages = find_tags_by_class(browser.contents, "message")
+        self.assertEqual(2, len(messages))
+        top_msg, field_msg = messages
         self.assertEqual(
-            'This snap contains Private information',
-            extract_text(find_tag_by_id(browser.contents, "privacy"))
-        )
-        login_admin()
-        snap = getUtility(ISnapSet).getByName(private_team, 'private-snap')
+            'There is 1 error.', extract_text(top_msg))
         self.assertEqual(
-            InformationType.PRIVATESECURITY, snap.information_type)
+            'Private snap recipes must be associated with a project.',
+            extract_text(field_msg))
+        login_admin()
+        snap = IStore(Snap).find(Snap, Snap.name == 'private-snap').one()
+        self.assertIsNone(snap)
 
-    def test_create_new_snap_private_team_with_private_git_repo(self):
-        # Creating snaps from private repos should make the snap follow its
-        # privacy setting.
-        self.useFixture(BranchHostingFixture(blob=b""))
+    def test_create_new_snap_private_with_invalid_information_type_fails(self):
+        # It should not not be possible to create a private snap without
+        # setting a project.
         login_person(self.person)
-        private_team = self.factory.makeTeam(
-            name='super-private', owner=self.person,
-            membership_policy=TeamMembershipPolicy.MODERATED,
-            visibility=PersonVisibility.PRIVATE)
-        [git_ref] = self.factory.makeGitRefs(
+        # The project is proprietary, with branch policy beign proprietary
+        # too. We can only create proprietary snaps.
+        self.factory.makeProduct(
+            name='private-project',
             owner=self.person, registrant=self.person,
-            information_type=InformationType.PRIVATESECURITY)
+            information_type=InformationType.PROPRIETARY,
+            branch_sharing_policy=BranchSharingPolicy.PROPRIETARY)
+        [git_ref] = self.factory.makeGitRefs()
 
         browser = self.getViewBrowser(
             git_ref, view_name="+new-snap", user=self.person)
         browser.getControl(name="field.name").value = "private-snap"
-        browser.getControl("Owner").value = ['super-private']
+        browser.getControl(name="field.information_type").value = "PUBLIC"
+        browser.getControl(name="field.project").value = "private-project"
         browser.getControl("Create snap package").click()
 
         content = find_main_content(browser.contents)
-        self.assertEqual("private-snap", extract_text(content.h1))
+        self.assertEqual("Create a new snap package", extract_text(content.h1))
+        messages = find_tags_by_class(browser.contents, "message")
+        self.assertEqual(2, len(messages))
+        top_msg, field_msg = messages
         self.assertEqual(
-            'This snap contains Private information',
-            extract_text(find_tag_by_id(browser.contents, "privacy"))
-        )
+            'There is 1 error.', extract_text(top_msg))
+        expected_msg = (
+            'Project private-project only accepts the following information '
+            'types: Proprietary.')
+        self.assertEqual(expected_msg, extract_text(field_msg))
         login_admin()
-        snap = getUtility(ISnapSet).getByName(private_team, 'private-snap')
-        self.assertEqual(
-            InformationType.PRIVATESECURITY, snap.information_type)
+        snap = IStore(Snap).find(Snap, Snap.name == 'private-snap').one()
+        self.assertIsNone(snap)
 
     def test_create_new_snap_build_source_tarball(self):
         # We can create a new snap and ask for it to build a source tarball.
@@ -755,7 +762,7 @@ class TestSnapAdminView(BaseTestSnapView):
         private = InformationType.PRIVATESECURITY.name
         browser = self.getViewBrowser(snap, user=commercial_admin)
         browser.getLink("Administer snap package").click()
-        browser.getControl(name='field.project').value = ''
+        browser.getControl(name='field.project').value = None
         browser.getControl(name="field.information_type").value = private
         browser.getControl("Update snap package").click()
         self.assertEqual(
@@ -996,6 +1003,92 @@ class TestSnapEditView(BaseTestSnapView):
             "name.",
             extract_text(find_tags_by_class(browser.contents, "message")[1]))
 
+    def test_edit_snap_project_and_info_type(self):
+        series = self.factory.makeUbuntuDistroSeries()
+        with admin_logged_in():
+            snappy_series = self.factory.makeSnappySeries(
+                usable_distro_series=[series])
+        login_person(self.person)
+        initial_project = self.factory.makeProduct(
+            name='initial-project',
+            owner=self.person, registrant=self.person,
+            information_type=InformationType.PUBLIC,
+            branch_sharing_policy=BranchSharingPolicy.PUBLIC_OR_PROPRIETARY)
+        snap = self.factory.makeSnap(
+            registrant=self.person, owner=self.person, project=initial_project,
+            distroseries=series, store_series=snappy_series,
+            information_type=InformationType.PUBLIC)
+        final_project = self.factory.makeProduct(
+            name='final-project',
+            owner=self.person, registrant=self.person,
+            information_type=InformationType.PROPRIETARY,
+            branch_sharing_policy=BranchSharingPolicy.PROPRIETARY)
+        browser = self.getViewBrowser(snap, user=self.person)
+        browser.getLink("Edit snap package").click()
+        browser.getControl(name="field.project").value = "final-project"
+        browser.getControl(name="field.information_type").value = "PROPRIETARY"
+        browser.getControl("Update snap package").click()
+        login_admin()
+        self.assertEqual(canonical_url(snap), browser.url)
+        snap = IStore(Snap).find(Snap, Snap.name == snap.name).one()
+        self.assertEqual(final_project, snap.project)
+        self.assertEqual(InformationType.PROPRIETARY, snap.information_type)
+
+    def test_edit_snap_private_without_project(self):
+        series = self.factory.makeUbuntuDistroSeries()
+        with admin_logged_in():
+            snappy_series = self.factory.makeSnappySeries(
+                usable_distro_series=[series])
+        login_person(self.person)
+        private_project = self.factory.makeProduct(
+            name='private-project',
+            owner=self.person, registrant=self.person,
+            information_type=InformationType.PROPRIETARY,
+            branch_sharing_policy=BranchSharingPolicy.PROPRIETARY)
+        snap = self.factory.makeSnap(
+            name='foo-snap', registrant=self.person, owner=self.person,
+            distroseries=series, store_series=snappy_series,
+            information_type=InformationType.PROPRIETARY,
+            project=private_project)
+        browser = self.getViewBrowser(snap, user=self.person)
+        browser.getLink("Edit snap package").click()
+        browser.getControl(name="field.project").value = ''
+        browser.getControl(name="field.information_type").value = (
+            "PROPRIETARY")
+        browser.getControl("Update snap package").click()
+
+        messages = find_tags_by_class(browser.contents, "message")
+        self.assertEqual(2, len(messages))
+        top_msg, field_msg = messages
+        self.assertEqual(
+            'There is 1 error.', extract_text(top_msg))
+        self.assertEqual(
+            'Private snap recipes must be associated with a project.',
+            extract_text(field_msg))
+
+    def test_edit_snap_private_information_type_matches_project(self):
+        series = self.factory.makeUbuntuDistroSeries()
+        with admin_logged_in():
+            snappy_series = self.factory.makeSnappySeries(
+                usable_distro_series=[series])
+        login_person(self.person)
+        private_project = self.factory.makeProduct(
+            name='private-project',
+            owner=self.person, registrant=self.person,
+            information_type=InformationType.PROPRIETARY,
+            branch_sharing_policy=BranchSharingPolicy.PROPRIETARY)
+        snap = self.factory.makeSnap(
+            name='foo-snap', registrant=self.person, owner=self.person,
+            distroseries=series, store_series=snappy_series,
+            information_type=InformationType.PROPRIETARY,
+            project=private_project)
+        browser = self.getViewBrowser(snap, user=self.person)
+        browser.getLink("Edit snap package").click()
+
+        # Make sure we are only showing valid information type options:
+        info_type_selector = browser.getControl(name="field.information_type")
+        self.assertEqual(['PROPRIETARY'], info_type_selector.options)
+
     def test_edit_public_snap_private_owner(self):
         series = self.factory.makeUbuntuDistroSeries()
         with admin_logged_in():
diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py
index c33ea82..9b8e5db 100644
--- a/lib/lp/snappy/interfaces/snap.py
+++ b/lib/lp/snappy/interfaces/snap.py
@@ -708,6 +708,16 @@ class ISnapEditableAttributes(IHasOwner):
         schema=IProduct, vocabulary='Product',
         required=False, readonly=False)
 
+    private = exported(Bool(
+        title=_("Private"), required=False, readonly=False,
+        description=_("Whether or not this snap is private.")))
+
+    information_type = exported(Choice(
+        title=_("Information type"), vocabulary=InformationType,
+        required=True, readonly=False, default=InformationType.PUBLIC,
+        description=_(
+            "The type of information contained in this Snap recipe.")))
+
     distro_series = exported(Reference(
         IDistroSeries, title=_("Distro Series"),
         required=False, readonly=False,
@@ -874,16 +884,6 @@ class ISnapAdminAttributes(Interface):
     These attributes need launchpad.View to see, and launchpad.Admin to change.
     """
 
-    private = exported(Bool(
-        title=_("Private"), required=False, readonly=False,
-        description=_("Whether or not this snap is private.")))
-
-    information_type = exported(Choice(
-        title=_("Information type"), vocabulary=InformationType,
-        required=True, readonly=False, default=InformationType.PUBLIC,
-        description=_(
-            "The type of information contained in this Snap recipe.")))
-
     require_virtualized = exported(Bool(
         title=_("Require virtualized builders"), required=True, readonly=False,
         description=_("Only build this snap package on virtual builders.")))
@@ -947,8 +947,10 @@ class ISnapSet(Interface):
     def exists(owner, name):
         """Check to see if a matching snap exists."""
 
-    def getSnapSuggestedPrivacy(owner, branch=None, git_ref=None):
-        """Which privacy a Snap should have based on its creation params."""
+    def getPossibleSnapInformationTypes(project):
+        """Returns the list of possible InformationTypes for snaps based on
+        the given project.
+        """
 
     def findByIds(snap_ids):
         """Return all snap packages with the given ids."""
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index b101e18..2ee8802 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -1388,20 +1388,10 @@ class SnapSet:
 
         return snap
 
-    def getSnapSuggestedPrivacy(self, owner, branch=None, git_ref=None):
+    def getPossibleSnapInformationTypes(self, project):
         """See `ISnapSet`."""
-        # Public snaps with private sources are not allowed.
-        source = branch or git_ref
-        if source is not None and source.private:
-            return source.information_type
-
-        # Public snaps owned by private teams are not allowed.
-        if owner is not None and owner.private:
-            return InformationType.PROPRIETARY
+        return BRANCH_POLICY_ALLOWED_TYPES[project.branch_sharing_policy]
 
-        # XXX pappacena 2021-03-02: We need to consider the pillar's branch
-        # sharing policy here instead of suggesting PUBLIC.
-        return InformationType.PUBLIC
 
     def isValidInformationType(self, information_type, owner, branch=None,
                                git_ref=None):
diff --git a/lib/lp/snappy/templates/snap-edit.pt b/lib/lp/snappy/templates/snap-edit.pt
index 3c9ac00..eb9bc9e 100644
--- a/lib/lp/snappy/templates/snap-edit.pt
+++ b/lib/lp/snappy/templates/snap-edit.pt
@@ -25,6 +25,12 @@
         <tal:widget define="widget nocall:view/widgets/name">
           <metal:block use-macro="context/@@launchpad_form/widget_row" />
         </tal:widget>
+        <tal:widget define="widget nocall:view/widgets/project">
+          <metal:block use-macro="context/@@launchpad_form/widget_row" />
+        </tal:widget>
+        <tal:widget define="widget nocall:view/widgets/information_type">
+          <metal:block use-macro="context/@@launchpad_form/widget_row" />
+        </tal:widget>
         <tal:widget define="widget nocall:view/widgets/store_distro_series">
           <metal:block use-macro="context/@@launchpad_form/widget_row" />
         </tal:widget>
diff --git a/lib/lp/snappy/templates/snap-new.pt b/lib/lp/snappy/templates/snap-new.pt
index ada07ae..5334bee 100644
--- a/lib/lp/snappy/templates/snap-new.pt
+++ b/lib/lp/snappy/templates/snap-new.pt
@@ -30,6 +30,12 @@
         <tal:widget define="widget nocall:view/widgets/owner">
           <metal:block use-macro="context/@@launchpad_form/widget_row" />
         </tal:widget>
+        <tal:widget define="widget nocall:view/widgets/project">
+          <metal:block use-macro="context/@@launchpad_form/widget_row" />
+        </tal:widget>
+        <tal:widget define="widget nocall:view/widgets/information_type">
+          <metal:block use-macro="context/@@launchpad_form/widget_row" />
+        </tal:widget>
         <tal:widget define="widget nocall:view/widgets/store_distro_series">
           <metal:block use-macro="context/@@launchpad_form/widget_row" />
         </tal:widget>

Follow ups