~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
Pillar views
============

Pillar views are used to display IPillar objects link distributions and
products in a consistent fashion.

The +get-involved presentation creates a portlet of links to encourage
project involvement. Only links to official applications are rendered.


    >>> distribution = factory.makeDistribution(name='umbra')
    >>> login_person(distribution.owner)
    >>> view = create_view(
    ...     distribution, '+get-involved', principal=distribution.owner)

The has_involvement property is used to determine if the portlet should
be rendered. The newly created pillar does not use any launchpad applications.

    >>> view.has_involvement
    False

    >>> print view.render()
    <BLANKLINE>

Pillars that do use launchpad applications have an involvement menu.

    >>> from lp.app.enums import ServiceUsage
    >>> distribution.answers_usage = ServiceUsage.LAUNCHPAD
    >>> distribution.official_malone = True
    >>> view = create_view(
    ...     distribution, '+get-involved', principal=distribution.owner)
    >>> view.has_involvement
    True

    >>> view.official_malone
    True
    >>> print view.answers_usage.name
    LAUNCHPAD
    >>> print view.translations_usage.name
    UNKNOWN
    >>> print view.blueprints_usage.name
    UNKNOWN
    >>> print view.codehosting_usage.name
    UNKNOWN

The view provides a list of enabled links that is rendered by the template.

    >>> for link in view.enabled_links:
    ...     print link.name
    report_bug ask_question

    >>> print view.render()
    <div id="involvement" class="portlet">
      <h2>Get Involved</h2>
      <ul class="involvement">
        <li>
          <a href=... class="...bugs">Report a bug</a>...
        </li>
        <li>
          <a href=... class="...answers">Ask a question</a>...
        </li>
      </ul>
    ...

Products are supported.

    >>> product = factory.makeProduct(name='bread')
    >>> login_person(product.owner)
    >>> product.blueprints_usage = ServiceUsage.LAUNCHPAD
    >>> view = create_view(product, '+get-involved')
    >>> print view.blueprints_usage.name
    LAUNCHPAD
    >>> for link in view.enabled_links:
    ...     print link.name
    register_blueprint

Products subclass the view to display disabled links to encourage
configuring that service in Launchpad for the project. The product
also has configuration links that make it easy to figure out where
to configure each service.

    >>> for link in view.visible_disabled_links:
    ...     print link.name
    report_bug
    ask_question
    help_translate
    submit_code

    >>> for link in view.configuration_links:
    ...     print link['link'].name
    configure_bugtracker
    configure_answers
    configure_translations
    set_branch

The registration status is determined with the 'configuration_states'
property.  Notice that blueprints are not included in the
configuration links nor the completeness computation as the use of
blueprints is not promoted.

    >>> for key in sorted(view.configuration_states.keys()):
    ...     print key, view.configuration_states[key]
    configure_answers False
    configure_bugtracker False
    configure_codehosting False
    configure_translations False

The percentage of the registration completed can be determined by
using the 'registration_completeness' property, which returns a
dictionary, which makes it easy for use in the page template.

    >>> print pretty(view.registration_completeness)
    {'done': 0,
     'undone': 100}

Changing the product's usage is reflected in the view properties.

    >>> product.translations_usage = ServiceUsage.LAUNCHPAD
    >>> view = create_view(product, '+get-involved')
    >>> for key in sorted(view.configuration_states.keys()):
    ...     print key, view.configuration_states[key]
    configure_answers False
    configure_bugtracker False
    configure_codehosting False
    configure_translations True

    >>> print pretty(view.registration_completeness)
    {'done': 25,
     'undone': 75}

The progress bar is shown as a green bar.

    >>> from canonical.launchpad.testing.pages import find_tag_by_id
    >>> rendered = view.render()
    >>> print find_tag_by_id(rendered, 'progressbar')
    <div ... id="progressbar">
    ...
    <img src="/@@/green-bar" ... width="25".../>
    ...

Each application is displayed (except for blueprints) with an
indicator showing whether it has been configured or not.

    >>> print find_tag_by_id(rendered, 'configuration_links')
    <table...
    <a href="http://launchpad.dev/bread/+configure-bugtracker"...
    <span class="sprite no">...
    <a href="http://launchpad.dev/bread/+configure-answers"...
    <span class="sprite no">...
    <a href="http://launchpad.dev/bread/+configure-translations"...
    <span class="sprite yes">...
    <a href="http://launchpad.dev/bread/trunk/+setbranch"...
    <span class="sprite no">...
    </table>

Project groups are supported too, but they only display the
applications used by their products.

    >>> project_group = factory.makeProject(name='box', owner=product.owner)
    >>> product.project = project_group

    >>> view = create_view(project_group, '+get-involved')
    >>> print view.blueprints_usage.name
    LAUNCHPAD

The offical_codehosting for a project is based on whether the project's
development focus series has a branch.

    >>> print product.development_focus.branch
    None
    >>> product.official_codehosting
    False
    >>> view = create_view(product, '+get-involved')
    >>> print view.codehosting_usage.name
    UNKNOWN

    >>> product.development_focus.branch = factory.makeBranch(
    ...     product=product)
    >>> product.official_codehosting
    True
    >>> view = create_view(product, '+get-involved')
    >>> print view.codehosting_usage.name
    LAUNCHPAD

    >>> from lp.code.enums import BranchType
    >>> remote = factory.makeProduct()
    >>> branch = factory.makeProductBranch(product=remote,
    ...                                    branch_type=BranchType.REMOTE)
    >>> remote.official_codehosting
    False
    >>> view = create_view(remote, '+get-involved')
    >>> print view.codehosting_usage.name
    UNKNOWN


Project groups cannot make links to register a branch, so
official_codehosting is always false.

    >>> view = create_view(project_group, '+get-involved')
    >>> print view.codehosting_usage.name
    NOT_APPLICABLE

Project groups ignore products translations_usage setting if none of the
products are fully configured as translatable.

    >>> product.translations_usage = ServiceUsage.LAUNCHPAD
    >>> project_group.has_translatable()
    False

    >>> view = create_view(project_group, '+get-involved')
    >>> print view.translations_usage.name
    UNKNOWN

If a product is translatable, translations is enabled in the involvment menu.

    >>> series = factory.makeProductSeries(product=product)
    >>> pot = factory.makePOTemplateAndPOFiles(
    ...     productseries=series,
    ...     language_codes=['es'])
    >>> product.translations_usage = ServiceUsage.LAUNCHPAD
    >>> project_group.has_translatable()
    True

    >>> view = create_view(project_group, '+get-involved')
    >>> print view.translations_usage.name
    LAUNCHPAD

DistroSeries can use this view. The distribution is used to set the links.

    >>> series = factory.makeDistroSeries(distribution=distribution)
    >>> view = create_view(series, '+get-involved')
    >>> for link in view.enabled_links:
    ...     print link.name
    report_bug

DistributionSourcePackages can use this view. The distribution is used to
set the links.  Despite the fact that the distribution uses blueprints,
and translations those links are not enabled for DistributionSourcePackages.

    >>> from lp.app.enums import ServiceUsage
    >>> login_person(distribution.owner)
    >>> distribution.blueprints_usage = ServiceUsage.LAUNCHPAD
    >>> distribution.translations_usage = ServiceUsage.LAUNCHPAD
    >>> package = factory.makeDistributionSourcePackage(
    ...     sourcepackagename="box",
    ...     distribution=distribution)
    >>> view = create_view(package, '+get-involved')
    >>> for link in view.enabled_links:
    ...     print link.name
    report_bug ask_question


Involvement links
-----------------

The pillar involvement view uses the InvolvedMenu when rendering links.

    >>> from lp.app.browser.tales import MenuAPI
    >>> from operator import attrgetter

The menu when viewed from a product page.

    >>> view = create_view(product, '+get-involved')
    >>> menuapi = MenuAPI(view)
    >>> for link in sorted(
    ...     menuapi.navigation.values(), key=attrgetter('sort_key')):
    ...     print link.url
    http://bugs.launchpad.dev/bread/+filebug
    http://answers.launchpad.dev/bread/+addquestion
    http://translations.launchpad.dev/bread
    http://code.launchpad.dev/bread/+addbranch
    http://blueprints.launchpad.dev/bread/+addspec

    >>> from lp.registry.browser.pillar import InvolvedMenu
    >>> from lp.testing.menu import check_menu_links
    >>> check_menu_links(InvolvedMenu(product))
    True

The menu when viewed from a distribution page.

    >>> view = create_view(distribution, '+get-involved')
    >>> menuapi = MenuAPI(view)
    >>> for link in sorted(
    ...     menuapi.navigation.values(), key=attrgetter('sort_key')):
    ...     if link.enabled:
    ...         print link.url
    http://bugs.launchpad.dev/umbra/+filebug
    http://answers.launchpad.dev/umbra/+addquestion
    http://translations.launchpad.dev/umbra
    http://blueprints.launchpad.dev/umbra/+addspec

The menu when viewed from a distribution source package page.

    >>> view = create_view(package, '+get-involved')
    >>> menuapi = MenuAPI(view)
    >>> for link in sorted(
    ...     menuapi.navigation.values(), key=attrgetter('sort_key')):
    ...     if link.enabled:
    ...         print link.url
    http://bugs.launchpad.dev/umbra/+source/box/+filebug
    http://answers.launchpad.dev/umbra/+source/box/+addquestion