← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~ilasc/launchpad:person-oci-registry-credentials-view into launchpad:master

 

Ioana Lasc has proposed merging ~ilasc/launchpad:person-oci-registry-credentials-view into launchpad:master.

Commit message:
Add view for OCIRegistryCredentials on person page

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

Added view to display the current set of OCI registry credentials on person page.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilasc/launchpad:person-oci-registry-credentials-view into launchpad:master.
diff --git a/lib/lp/registry/browser/configure.zcml b/lib/lp/registry/browser/configure.zcml
index 3991dd5..5e1489b 100644
--- a/lib/lp/registry/browser/configure.zcml
+++ b/lib/lp/registry/browser/configure.zcml
@@ -1231,6 +1231,13 @@
         template="../templates/person-oauth-tokens.pt"
         />
     <browser:page
+        name="+oci-registry-credentials"
+        for="lp.registry.interfaces.person.IPerson"
+        class="lp.registry.browser.person.PersonOCIRegistryCredentialsView"
+        permission="launchpad.Edit"
+        template="../templates/person-ociregistrycredentials.pt"
+        />
+    <browser:page
         name="+livefs"
         for="lp.registry.interfaces.person.IPerson"
         class="lp.registry.browser.person.PersonLiveFSView"
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index d512b7b..f4ea957 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -30,6 +30,7 @@ __all__ = [
     'PersonLiveFSView',
     'PersonNavigation',
     'PersonOAuthTokensView',
+    'PersonOCIRegistryCredentialsView',
     'PersonOverviewMenu',
     'PersonOwnedTeamsView',
     'PersonRdfContentsView',
@@ -133,6 +134,9 @@ from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
 from lp.code.errors import InvalidNamespace
 from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
 from lp.code.interfaces.gitlookup import IGitTraverser
+from lp.oci.interfaces.ociregistrycredentials import (
+    IOCIRegistryCredentialsSet,
+    )
 from lp.registry.browser import BaseRdfView
 from lp.registry.browser.branding import BrandingChangeView
 from lp.registry.browser.menu import (
@@ -570,6 +574,14 @@ class PersonNavigation(BranchTraversalMixin, Navigation):
             return None
         return irc_nick
 
+    @stepthrough('+oci-registry-credential')
+    def traverse_oci_registry_credential(self, id):
+        """Traverse to this person's OCI registry credentials."""
+        oci_credentials = getUtility(IOCIRegistryCredentialsSet).get(id)
+        if oci_credentials is None or oci_credentials.person != self.context:
+            return None
+        return oci_credentials
+
     @stepto('+archivesubscriptions')
     def traverse_archive_subscription(self):
         """Traverse to the archive subscription for this person."""
@@ -802,6 +814,7 @@ class PersonOverviewMenu(ApplicationMenu, PersonMenuMixin,
         'view_ppa_subscriptions',
         'ppa',
         'oauth_tokens',
+        'oci_registry_credentials',
         'related_software_summary',
         'view_recipes',
         'view_snaps',
@@ -824,6 +837,12 @@ class PersonOverviewMenu(ApplicationMenu, PersonMenuMixin,
         return Link(target, text, enabled=enabled, icon='info')
 
     @enabled_with_permission('launchpad.Edit')
+    def oci_registry_credentials(self):
+        target = '+oci-registry-credentials'
+        text = 'OCI registry credentials'
+        return Link(target, text, icon='info')
+
+    @enabled_with_permission('launchpad.Edit')
     def editlanguages(self):
         target = '+editlanguages'
         text = 'Set preferred languages'
@@ -3621,6 +3640,23 @@ class PersonOAuthTokensView(LaunchpadView):
             canonical_url(self.context, view_name='+oauth-tokens'))
 
 
+class PersonOCIRegistryCredentialsView(LaunchpadView):
+    """View for Person:+oci-registry-credentials."""
+
+    @cachedproperty
+    def oci_registry_credentials(self):
+        return list(getUtility(
+            IOCIRegistryCredentialsSet).findByOwner(self.context))
+
+    @property
+    def page_title(self):
+        return "OCI registry credentials"
+
+    @property
+    def has_credentials(self):
+        return len(self.oci_registry_credentials) > 0
+
+
 class PersonLiveFSView(LaunchpadView):
     """Default view for the list of live filesystems owned by a person."""
     page_title = 'LiveFS'
diff --git a/lib/lp/registry/browser/tests/test_person.py b/lib/lp/registry/browser/tests/test_person.py
index 10bbba7..685526e 100644
--- a/lib/lp/registry/browser/tests/test_person.py
+++ b/lib/lp/registry/browser/tests/test_person.py
@@ -34,6 +34,11 @@ from lp.app.errors import NotFoundError
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.blueprints.enums import SpecificationImplementationStatus
 from lp.buildmaster.enums import BuildStatus
+from lp.oci.interfaces.ocirecipe import OCI_RECIPE_ALLOW_CREATE
+from lp.oci.interfaces.ociregistrycredentials import (
+    IOCIRegistryCredentialsSet,
+    )
+from lp.oci.tests.helpers import OCIConfigHelperMixin
 from lp.registry.browser.person import PersonView
 from lp.registry.browser.team import TeamInvitationView
 from lp.registry.enums import PersonVisibility
@@ -365,6 +370,30 @@ class TestPersonIndexView(BrowserTestCase):
         view = create_initialized_view(person, '+index')
         self.assertTrue(view.should_show_gpgkeys_section)
 
+    def test_show_oci_registry_credentials_link(self):
+        person = self.factory.makePerson()
+        view = create_initialized_view(person, '+index', principal=person)
+        with person_logged_in(person):
+            markup = self.get_markup(view, person)
+        link_match = soupmatchers.HTMLContains(
+            soupmatchers.Tag(
+                'OCIRegistryCredentials link', 'a',
+                attrs={
+                    'href':
+                        'http://launchpad.test/~%s/+oci-registry-credentials'
+                        % person.name},
+                text='OCI registry credentials'))
+        self.assertThat(markup, link_match)
+
+        link_match = soupmatchers.HTMLContains(
+            soupmatchers.Tag(
+                'OCIRegistryCredentials missing link', 'a',
+                text='OCI registry credentials'))
+
+        login(ANONYMOUS)
+        markup = self.get_markup(view, person)
+        self.assertNotIn(link_match, markup)
+
     def test_ppas_query_count(self):
         owner = self.factory.makePerson()
 
@@ -1281,6 +1310,50 @@ class TestPersonRelatedProjectsView(TestCaseWithFactory):
         self.assertThat(view(), next_match)
 
 
+class TestPersonOCIRegistryCredentialsView(BrowserTestCase,
+                                           OCIConfigHelperMixin):
+
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestPersonOCIRegistryCredentialsView, self).setUp()
+        self.setConfig()
+        self.person = self.factory.makePerson(
+            name="test-person", displayname="Test Person")
+        self.ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
+        self.distroseries = self.factory.makeDistroSeries(
+            distribution=self.ubuntu, name="shiny", displayname="Shiny")
+        self.useFixture(FeatureFixture({
+            OCI_RECIPE_ALLOW_CREATE: "on",
+            "oci.build_series.%s" % self.distroseries.distribution.name:
+                self.distroseries.name,
+        }))
+        oci_project = self.factory.makeOCIProject(
+            pillar=self.distroseries.distribution)
+        self.recipe = self.factory.makeOCIRecipe(
+            registrant=self.person, owner=self.person,
+            oci_project=oci_project)
+
+    def test_view_oci_registry_credentials_on_person_page(self):
+        # Verify view helper attributes.
+        url = unicode(self.factory.getUniqueURL())
+        credentials = {'username': 'foo', 'password': 'bar'}
+        getUtility(IOCIRegistryCredentialsSet).new(
+            owner=self.user,
+            url=url,
+            credentials=credentials)
+        view = create_initialized_view(self.user, '+oci-registry-credentials')
+        self.assertEqual('OCI registry credentials', view.page_title)
+        with person_logged_in(self.user):
+            self.assertEqual(
+                credentials.get('username'),
+                view.oci_registry_credentials[0].getCredentials()['username'])
+            self.assertEqual(url, view.oci_registry_credentials[0].url)
+            self.assertEqual(
+                self.user.display_name,
+                view.oci_registry_credentials[0].owner.display_name)
+
+
 class TestPersonLiveFSView(BrowserTestCase):
     layer = DatabaseFunctionalLayer
 
diff --git a/lib/lp/registry/templates/person-index.pt b/lib/lp/registry/templates/person-index.pt
index 4cfee46..4933c09 100644
--- a/lib/lp/registry/templates/person-index.pt
+++ b/lib/lp/registry/templates/person-index.pt
@@ -82,6 +82,10 @@
         tal:define="link context/menu:overview/oauth_tokens"
         tal:condition="link/enabled"
         tal:content="structure link/fmt:link" />
+      <li
+        tal:define="link context/menu:overview/oci_registry_credentials"
+        tal:condition="link/enabled"
+        tal:content="structure link/fmt:link" />
     </ul>
 
     <div class="yui-g">
diff --git a/lib/lp/registry/templates/person-ociregistrycredentials.pt b/lib/lp/registry/templates/person-ociregistrycredentials.pt
new file mode 100644
index 0000000..882e1cb
--- /dev/null
+++ b/lib/lp/registry/templates/person-ociregistrycredentials.pt
@@ -0,0 +1,33 @@
+<html
+  xmlns="http://www.w3.org/1999/xhtml";
+  xmlns:tal="http://xml.zope.org/namespaces/tal";
+  xmlns:metal="http://xml.zope.org/namespaces/metal";
+  xmlns:i18n="http://xml.zope.org/namespaces/i18n";
+  metal:use-macro="view/macro:page/main_only"
+  i18n:domain="launchpad"
+>
+<body>
+<div metal:fill-slot="main">
+    <p id="no-participation" tal:condition="not: view/has_credentials">
+        <span tal:replace="context/title"/>
+        has not set any credentials yet.
+    </p>
+    <table id="oci-credentials" class="listing" tal:condition="view/has_credentials">
+    <thead>
+        <tr>
+            <th>Registry URL</th>
+            <th>Owner</th>
+            <th>Username</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr tal:repeat="oci_credentials view/oci_registry_credentials">
+            <td tal:content="oci_credentials/url"/>
+            <td tal:content="oci_credentials/owner/display_name"/>
+            <td tal:content="oci_credentials/username"/>
+        </tr>
+    </tbody>
+    </table>
+</div>
+</body>
+</html>