← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~ilasc/launchpad:add-person-livefs-index-view into launchpad:master

 

Ioana Lasc has proposed merging ~ilasc/launchpad:add-person-livefs-index-view into launchpad:master.

Commit message:
Add Person:+livefs index view

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1332479 in Launchpad itself: "Cannot view +livefs page"
  https://bugs.launchpad.net/launchpad/+bug/1332479

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

Added livefs index view to provide the UI list of all the live filesystems owned by a given person.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilasc/launchpad:add-person-livefs-index-view into launchpad:master.
diff --git a/lib/lp/registry/browser/configure.zcml b/lib/lp/registry/browser/configure.zcml
index b8dc1bb..669d444 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="+livefs"
+        for="lp.registry.interfaces.person.IPerson"
+        class="lp.registry.browser.person.PersonLiveFSView"
+        permission="launchpad.View"
+        template="../templates/livefs-index.pt"
+        />
+    <browser:page
         name="+index"
         for="lp.registry.interfaces.person.ITeam"
         class="lp.registry.browser.team.TeamIndexView"
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 8677ecd..3e3c92b 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -27,6 +27,7 @@ __all__ = [
     'PersonIndexView',
     'PersonKarmaView',
     'PersonLanguagesView',
+    'PersonLiveFSView',
     'PersonNavigation',
     'PersonOAuthTokensView',
     'PersonOverviewMenu',
@@ -3620,6 +3621,32 @@ class PersonOAuthTokensView(LaunchpadView):
             canonical_url(self.context, view_name='+oauth-tokens'))
 
 
+class PersonLiveFSView(LaunchpadView):
+    """Default view for the list of live filesystems owned by a person."""
+    page_title = 'LiveFS'
+
+    @property
+    def label(self):
+        return 'Live filesystems for %s' % self.context.name
+
+    @property
+    def title(self):
+        return self.context.name
+
+    @property
+    def livefs(self):
+        livefs = getUtility(ILiveFSSet).getByPerson(self.context)
+        return livefs.order_by('name')
+
+    @property
+    def livefs_navigator(self):
+        return BatchNavigator(self.livefs, self.request)
+
+    @cachedproperty
+    def count(self):
+        return self.livefs_navigator.batch.total()
+
+
 class PersonTimeZoneForm(Interface):
 
     time_zone = Choice(
diff --git a/lib/lp/registry/browser/tests/test_person.py b/lib/lp/registry/browser/tests/test_person.py
index 626cab4..9b5f7be 100644
--- a/lib/lp/registry/browser/tests/test_person.py
+++ b/lib/lp/registry/browser/tests/test_person.py
@@ -1,10 +1,14 @@
-# Copyright 2009-2017 Canonical Ltd.  This software is licensed under the
+# -*- coding: utf-8 -*-
+# Copyright 2009-2020 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
+from __future__ import unicode_literals
+
 __metaclass__ = type
 
 import doctest
 import email
+from operator import attrgetter
 import re
 from textwrap import dedent
 
@@ -43,6 +47,7 @@ from lp.registry.model.karma import KarmaCategory
 from lp.registry.model.milestone import milestone_sort_key
 from lp.scripts.garbo import PopulateLatestPersonSourcePackageReleaseCache
 from lp.services.config import config
+from lp.services.features.testing import FeatureFixture
 from lp.services.identity.interfaces.account import AccountStatus
 from lp.services.identity.interfaces.emailaddress import IEmailAddressSet
 from lp.services.log.logger import DevNullLogger
@@ -61,6 +66,7 @@ from lp.soyuz.enums import (
     ArchiveStatus,
     PackagePublishingStatus,
     )
+from lp.soyuz.interfaces.livefs import LIVEFS_FEATURE_FLAG
 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
 from lp.testing import (
     ANONYMOUS,
@@ -85,6 +91,7 @@ from lp.testing.layers import (
 from lp.testing.matchers import HasQueryCount
 from lp.testing.pages import (
     extract_text,
+    find_main_content,
     find_tag_by_id,
     setupBrowserForUser,
     )
@@ -1274,6 +1281,60 @@ class TestPersonRelatedProjectsView(TestCaseWithFactory):
         self.assertThat(view(), next_match)
 
 
+class TestPersonLiveFSView(BrowserTestCase, TestCaseWithFactory):
+    layer = DatabaseFunctionalLayer
+
+    def setUp(self):
+        super(TestPersonLiveFSView, self).setUp()
+        self.useFixture(FeatureFixture({LIVEFS_FEATURE_FLAG: "on"}))
+        self.person = self.factory.makePerson(
+                        name="test-person", displayname="Test Person")
+
+    def makeLiveFS(self, count=1):
+        with person_logged_in(self.person):
+            return [self.factory.makeLiveFS(
+                registrant=self.person, owner=self.person)
+                for _ in range(count)]
+
+    def test_displays_live_filesystem(self):
+        livefs = self.factory.makeLiveFS(
+            registrant=self.person, owner=self.person)
+        browser = self.getViewBrowser(self.person, "+livefs", user=self.person)
+        main_text = extract_text(find_main_content(browser.contents))
+
+        with person_logged_in(self.person):
+            self.assertIn(livefs.name, main_text)
+
+    def test_displays_no_livefs_system(self):
+        browser = self.getViewBrowser(self.person, "+livefs", user=self.person)
+        main_text = extract_text(find_main_content(browser.contents))
+        with person_logged_in(self.person):
+            self.assertIn(
+                "There are no live filesystems for %s"
+                % self.person.name,
+                main_text)
+
+    def test_paginates_live_filesystems(self):
+        batch_size = 5
+        self.pushConfig("launchpad", default_batch_size=batch_size)
+        livefs = self.makeLiveFS(10)
+        browser = self.getViewBrowser(self.person, "+livefs", user=self.person)
+        main_text = extract_text(find_main_content(browser.contents))
+        no_wrap_main_text = main_text.replace('\n', ' ')
+        with person_logged_in(self.person):
+            self.assertIn(
+                "There are 10 live filesystems registered for %s"
+                % self.person.name,
+                no_wrap_main_text)
+            self.assertIn("1 → 5 of 10 results", no_wrap_main_text)
+            self.assertIn("First • Previous • Next • Last", no_wrap_main_text)
+
+            # Assert we're listing the first set of live filesystems
+            items = sorted(livefs, key=attrgetter('name'))
+            for lfs in items[:batch_size]:
+                self.assertIn(lfs.name, main_text)
+
+
 class TestPersonRelatedPackagesFailedBuild(TestCaseWithFactory):
     """The related packages views display links to failed builds."""
 
diff --git a/lib/lp/registry/templates/livefs-index.pt b/lib/lp/registry/templates/livefs-index.pt
new file mode 100644
index 0000000..345397f
--- /dev/null
+++ b/lib/lp/registry/templates/livefs-index.pt
@@ -0,0 +1,55 @@
+<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_side"
+  i18n:domain="launchpad"
+>
+
+<body>
+  <metal:side fill-slot="side">
+    <div tal:replace="structure context/@@+global-actions"/>
+  </metal:side>
+
+  <div metal:fill-slot="main">
+      <div class="main-portlet">
+        <p tal:define="count view/count"
+           tal:condition="count">
+          <span tal:condition="python: count == 1">
+            There is <strong>1</strong> live filesystem</span>
+          <span tal:condition="python: count != 1">
+            There are <strong tal:content="count" /> live filesystems
+          </span>
+          registered for <tal:context replace="view/title" />.
+        </p>
+        <p tal:condition="not: view/count">
+           There are no live filesystems for <tal:context replace="view/title" />.
+        </p>
+      </div>
+
+      <table class="listing" id="mirrors_list" tal:condition="view/count">
+        <tbody>
+          <tr class="head">
+            <th>Name</th>
+            <th>Owner</th>
+            <th>Date created</th>
+          </tr>
+
+          <tr tal:repeat="filesystem view/livefs">
+            <td>
+              <a tal:content="filesystem/name"
+                 tal:attributes="href filesystem/fmt:url" />
+            </td>
+            <td tal:content="structure filesystem/owner/fmt:link" />
+            <td tal:content="filesystem/date_created/fmt:displaydate" />
+          </tr>
+        </tbody>
+      </table>
+
+       <tal:navigation
+          replace="structure view/livefs_navigator/@@+navigation-links-lower" />
+  </div>
+
+</body>
+</html>