Merge lp:~sinzui/launchpad/get-involved-bug-412649 into lp:launchpad

Proposed by Curtis Hovey
Status: Merged
Merged at revision: not available
Proposed branch: lp:~sinzui/launchpad/get-involved-bug-412649
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~sinzui/launchpad/get-involved-bug-412649
Reviewer Review Type Date Requested Status
Eleanor Berger (community) Approve
Review via email: mp+10201@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

This is my branch to fix the pillar involvement portlet.

    lp:~sinzui/launchpad/get-involved-bug-412649
    Diff size: 322
    Launchpad bug: https://bugs.launchpad.net/bugs/412649
    Test command: ./bin/test -vvt "pillar-views"
    Pre-implementation: no-one
    Target release: 2.2.8

= Fix the pillar involvement portlet =

Currently, that portlet relies on attributes specific to
IProduct/IDistribution, so we can't use it for IProject.

== Rules ==

    * Add rules to use the projectgroups's products to set the link
state.
    * Series and sourcepackages need to be supported to since their
pages
      are being designed now.
    * Project's links are names differently; create a menu to avoid the
      problem.
    * The links are not always going to the correct app. Set the site in
      the link to ensure the host domain is used.

== QA ==

On edge
    * visit https://edge.launchpad.net/launchpad-project
    * Verify that the bugs, answers, translations, and blueprints links
are
      visible in the get involved menu.

== Lint ==

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/icing/style-3-0.css
  lib/lp/registry/browser/configure.zcml
  lib/lp/registry/browser/pillar.py
  lib/lp/registry/browser/tests/pillar-views.txt
  lib/lp/registry/templates/pillar-involvement-portlet.pt
  lib/lp/registry/templates/project-index.pt

== Test ==

    * lib/lp/registry/browser/tests/pillar-views.txt
      * Updated the test to verify the view's official uses and the
enabled
        links
      * Added tests for project, product, distroseries, productseries,
and
        distributionsourcepackage.

== Implementation ==

    * lib/canonical/launchpad/icing/style-3-0.css
      * Fixed broken paths.
      * Renamed the class after the applications to be consistent.
    * lib/lp/registry/browser/configure.zcml
      * Configured the view to work for any object. It may indeed work
for
        for many more objects than it is designed for because the code
        uses nearest() to get the first IPillar in the the traversals.
    * lib/lp/registry/browser/pillar.py
      * Added a menu to support the links independent of the names used
        in other menus
      * Set the site in the links because
      * Added rules to build a set of official uses from an IProject's
        IProducts.
      * Used nearest() to travers to the nearest pillar to make the view
        work for series and distributionsourcepackages.
      * Used the same method to create a list of links as is used by the
        old navigation menu view.
    * lib/lp/registry/templates/pillar-involvement-portlet.pt
      * Simplified the markup to iterate over the list of links provided
        by the view.
    * lib/lp/registry/templates/project-index.pt
      * Updated the project index to use the portlet

Revision history for this message
Eleanor Berger (intellectronica) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
2--- lib/canonical/launchpad/icing/style-3-0.css 2009-08-13 02:24:56 +0000
3+++ lib/canonical/launchpad/icing/style-3-0.css 2009-08-15 04:54:01 +0000
4@@ -546,21 +546,21 @@
5 color: #b9413e;
6 background: url(/@@/bugs-arrow-right.png) right center no-repeat;
7 }
8-.involvement a.question {
9+.involvement a.answers {
10 color: #5265b2;
11 background: url(/@@/answers-arrow-right.png) right center no-repeat;
12 }
13-.involvement a.translate {
14+.involvement a.translations {
15 color: #c5458e;
16 background: url(/@@/translations-arrow-right.png) right center no-repeat;
17 }
18 .involvement a.code {
19 color: #d39f57;
20- background: url(/@@/images/code-arrow-right.png) right center no-repeat;
21+ background: url(/@@/code-arrow-right.png) right center no-repeat;
22 }
23-.involvement a.blueprint {
24+.involvement a.blueprints {
25 color: #5ba4c6;
26- background: url(/@@/images/blueprints-arrow-right.png) right center no-repeat;
27+ background: url(/@@/blueprints-arrow-right.png) right center no-repeat;
28 }
29
30 .announcements li {
31
32=== modified file 'lib/lp/registry/browser/configure.zcml'
33--- lib/lp/registry/browser/configure.zcml 2009-08-14 00:52:28 +0000
34+++ lib/lp/registry/browser/configure.zcml 2009-08-15 04:31:42 +0000
35@@ -561,7 +561,7 @@
36 template="../templates/pillar-listing-simple.pt"/>
37 <browser:page
38 name="+get-involved"
39- for="lp.registry.interfaces.pillar.IPillar"
40+ for="*"
41 class="lp.registry.browser.pillar.PillarView"
42 facet="overview"
43 permission="zope.Public"
44
45=== modified file 'lib/lp/registry/browser/pillar.py'
46--- lib/lp/registry/browser/pillar.py 2009-08-06 18:17:49 +0000
47+++ lib/lp/registry/browser/pillar.py 2009-08-15 04:31:42 +0000
48@@ -10,17 +10,108 @@
49 ]
50
51
52-from canonical.launchpad.webapp.publisher import LaunchpadView
53+from operator import attrgetter
54+
55+from zope.component import provideAdapter
56+from zope.interface import implements, Interface
57+
58+from canonical.launchpad.webapp.interfaces import INavigationMenu
59+from canonical.launchpad.webapp.menu import Link, NavigationMenu
60+from canonical.launchpad.webapp.publisher import LaunchpadView, nearest
61+from canonical.launchpad.webapp.tales import MenuAPI
62+
63+from lp.registry.interfaces.pillar import IPillar
64+from lp.registry.interfaces.project import IProject
65+
66+
67+class IInvolved(Interface):
68+ """A marker interface for getting involved."""
69+
70+
71+class InvolvedMenu(NavigationMenu):
72+ """The get involved menu."""
73+ usedfor = IInvolved
74+ links = [
75+ 'report_bug', 'ask_question', 'help_translate', 'submit_code',
76+ 'register_blueprint']
77+
78+ def report_bug(self):
79+ return Link(
80+ '+filebug', 'Report a bug', site='bugs', icon='bugs',
81+ enabled=self.context.official_malone)
82+
83+ def ask_question(self):
84+ return Link(
85+ '+addquestion', 'Ask a question', site='answers', icon='answers',
86+ enabled=self.context.official_answers)
87+
88+ def help_translate(self):
89+ return Link(
90+ '/', 'Help translate', site='translations', icon='translations',
91+ enabled=self.context.official_rosetta)
92+
93+ def submit_code(self):
94+ return Link(
95+ '+filebug', 'Submit code', site='code', icon='code',
96+ enabled=self.context.official_codehosting)
97+
98+ def register_blueprint(self):
99+ return Link(
100+ '+addbranch', 'Register a blueprint', site='blueprints',
101+ icon='blueprints', enabled=self.context.official_blueprints)
102
103
104 class PillarView(LaunchpadView):
105 """A view for any `IPillar`."""
106+ implements(IInvolved)
107+
108+ def __init__(self, context, request):
109+ super(PillarView, self).__init__(context, request)
110+ self.official_malone = False
111+ self.official_answers = False
112+ self.official_blueprints = False
113+ self.official_rosetta = False
114+ self.official_codehosting = False
115+ pillar = nearest(self.context, IPillar)
116+ if IProject.providedBy(pillar):
117+ for product in pillar.products:
118+ self._set_official_launchpad(product)
119+ # Projectgroups do not support submit code.
120+ self.official_codehosting = False
121+ else:
122+ self._set_official_launchpad(pillar)
123+
124+ def _set_official_launchpad(self, pillar):
125+ """Does the pillar officially use launchpad."""
126+ # This if structure is required because it may be called many
127+ # times to build the complete set of official applications.
128+ if pillar.official_malone:
129+ self.official_malone = True
130+ if pillar.official_answers:
131+ self.official_answers = True
132+ if pillar.official_blueprints:
133+ self.official_blueprints = True
134+ if pillar.official_rosetta:
135+ self.official_rosetta = True
136+ if pillar.official_codehosting:
137+ self.official_codehosting = True
138
139 @property
140 def has_involvement(self):
141 """This `IPillar` uses Launchpad."""
142- pillar = self.context
143 return (
144- pillar.official_codehosting or pillar.official_malone
145- or pillar.official_answers or pillar.official_blueprints
146- or pillar.official_rosetta)
147+ self.official_malone or self.official_answers
148+ or self.official_blueprints or self.official_rosetta
149+ or self.official_codehosting)
150+
151+ @property
152+ def enabled_links(self):
153+ """The enabled involvement links."""
154+ menuapi = MenuAPI(self)
155+ return sorted([
156+ link for link in menuapi.navigation.values() if link.enabled],
157+ key=attrgetter('sort_key'))
158+
159+
160+provideAdapter(
161+ InvolvedMenu, [IInvolved], INavigationMenu, name="overview")
162
163=== modified file 'lib/lp/registry/browser/tests/pillar-views.txt'
164--- lib/lp/registry/browser/tests/pillar-views.txt 2009-08-06 18:17:49 +0000
165+++ lib/lp/registry/browser/tests/pillar-views.txt 2009-08-15 04:31:42 +0000
166@@ -31,15 +31,89 @@
167 >>> view.has_involvement
168 True
169
170+ >>> view.official_malone
171+ True
172+ >>> view.official_answers
173+ True
174+ >>> view.official_rosetta
175+ False
176+ >>> view.official_blueprints
177+ False
178+ >>> view.official_codehosting
179+ False
180+
181+The view provides a list of enabled links that is rendered by the template.
182+
183+ >>> for link in view.enabled_links:
184+ ... print link.name
185+ report_bug ask_question
186+
187 >>> print view.render()
188 <div id="involvement" class="portlet involvement">
189 <h2>Get Involved</h2>
190 <ul>
191 <li>
192- <a class="bugs" href="...">Report a Bug</a>
193+ <a href="..." class="...bugs">Report a bug</a>
194 </li>
195 <li>
196- <a class="question" href="...">Ask a question</a>
197+ <a href="..." class="...answers">Ask a question</a>
198 </li>
199 </ul>
200 </div>
201+
202+Products are are supported.
203+
204+ >>> product = factory.makeProduct(name='bread')
205+ >>> login_person(product.owner)
206+ >>> product.official_blueprints = True
207+ >>> view = create_view(product, '+get-involved')
208+ >>> view.official_blueprints
209+ True
210+
211+Project are supported too, but they only display the applications used by
212+their products.
213+
214+ >>> project_group = factory.makeProject(name='box', owner=product.owner)
215+ >>> product.project = project_group
216+
217+ >>> view = create_view(project_group, '+get-involved')
218+ >>> view.official_blueprints
219+ True
220+
221+Projects cannot make links to register a branch, so official_code is always
222+false.
223+
224+ >>> product.official_codehosting = True
225+ >>> view = create_view(product, '+get-involved')
226+ >>> view.official_codehosting
227+ True
228+
229+ >>> view = create_view(project_group, '+get-involved')
230+ >>> view.official_codehosting
231+ False
232+
233+DistroSeries can use this view. The distribution is used to set the links.
234+
235+ >>> series = factory.makeDistroRelease(distribution=distribution)
236+ >>> view = create_view(series, '+get-involved')
237+ >>> for link in view.enabled_links:
238+ ... print link.name
239+ report_bug ask_question
240+
241+ProductSeries can use this view. The product is used to set the links.
242+
243+ >>> series = factory.makeProductSeries(product=product)
244+ >>> view = create_view(series, '+get-involved')
245+ >>> for link in view.enabled_links:
246+ ... print link.name
247+ submit_code register_blueprint
248+
249+DistributionSourcePackages can use this view. The distribution is used to
250+set the links.
251+
252+ >>> package = factory.makeDistributionSourcePackage(
253+ ... distribution=distribution)
254+ >>> view = create_view(package, '+get-involved')
255+ >>> for link in view.enabled_links:
256+ ... print link.name
257+ report_bug ask_question
258
259=== modified file 'lib/lp/registry/templates/pillar-involvement-portlet.pt'
260--- lib/lp/registry/templates/pillar-involvement-portlet.pt 2009-08-06 19:14:40 +0000
261+++ lib/lp/registry/templates/pillar-involvement-portlet.pt 2009-08-15 04:31:42 +0000
262@@ -6,25 +6,8 @@
263 <h2>Get Involved</h2>
264
265 <ul>
266- <li tal:condition="context/official_malone">
267- <a class="bugs"
268- tal:attributes="href context/menu:bugs/filebug/url">Report a Bug</a>
269- </li>
270- <li tal:condition="context/official_answers">
271- <a class="question"
272- tal:attributes="href context/menu:answers/new/url">Ask a question</a>
273- </li>
274- <li tal:condition="context/official_rosetta">
275- <a class="translate"
276- tal:attributes="href context/menu:translations/overview/url">Help translate</a>
277- </li>
278- <li tal:condition="context/official_codehosting">
279- <a class="code"
280- tal:attributes="href context/menu:branches/branch_add/url">Submit code</a>
281- </li>
282- <li tal:condition="context/official_blueprints">
283- <a class="blueprint"
284- tal:attributes="href context/menu:specications/new/url">Register a Blueprint</a>
285+ <li tal:repeat="link view/enabled_links">
286+ <a tal:replace="structure link/fmt:link" />
287 </li>
288 </ul>
289 </div>
290
291=== modified file 'lib/lp/registry/templates/project-index.pt'
292--- lib/lp/registry/templates/project-index.pt 2009-08-13 18:10:15 +0000
293+++ lib/lp/registry/templates/project-index.pt 2009-08-15 04:31:42 +0000
294@@ -122,24 +122,9 @@
295 <div id="object-actions" class="top-portlet">
296 <tal:menu replace="structure view/@@+global-actions" />
297 </div>
298- <div id="involvement" class="portlet involvement"
299- tal:condition="context/products">
300- <h2>Get Involved</h2>
301- <ul>
302- <li>
303- <a class="bugs"
304- tal:attributes="href context/menu:bugs/new/url">Report a Bug</a>
305- </li>
306- <li>
307- <a class="question"
308- tal:attributes="href context/menu:answers/new/url">Ask a question</a>
309- </li>
310- <li>
311- <a class="translate"
312- tal:attributes="href context/menu:translations/overview/url">Help translate</a>
313- </li>
314- </ul>
315- </div>
316+
317+ <div tal:replace="structure context/@@+get-involved" />
318+
319 <tal:portlet tal:replace="structure context/@@+portlet-latestannouncements" />
320 </tal:side>
321
322