launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26542
[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