~launchpad-pqm/launchpad/devel

12293.1.11 by Curtis Hovey
Updated copyright.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.17 by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
3
4436.2.5 by Curtis Hovey
Fixed long lines.
4
"""Browser views for distributions."""
5
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
6
__metaclass__ = type
7
2071 by Canonical.com Patch Queue Manager
[trivial] add more __all__ statements, other minor tidyings-up
8
__all__ = [
9437.1.3 by Curtis Hovey
Added DerivativeDistributionOverviewMenu because links have different permissions.
9
    'DerivativeDistributionOverviewMenu',
6767.6.8 by Maris Fogels
Migrated the Distribution breadcrumbs to the new system interface.
10
    'DistributionAddView',
11
    'DistributionArchiveMirrorsRSSView',
12
    'DistributionArchiveMirrorsView',
7434.3.3 by Michael Nelson
Initial commit of all front-end-only changes from larger branch. Still
13
    'DistributionArchivesView',
9116.5.7 by Curtis Hovey
Added missing class to __all__
14
    'DistributionChangeMembersView',
9116.5.4 by Curtis Hovey
Converted the +selectmirroradmins to UI 3.0
15
    'DistributionChangeMirrorAdminView',
6767.6.8 by Maris Fogels
Migrated the Distribution breadcrumbs to the new system interface.
16
    'DistributionCountryArchiveMirrorsView',
17
    'DistributionDisabledMirrorsView',
18
    'DistributionEditView',
19
    'DistributionFacets',
1716.1.190 by Christian Reis
Merge from RF, again, this time for real
20
    'DistributionNavigation',
9184.3.1 by Barry Warsaw
Convert /distros to UI 3.0
21
    'DistributionPPASearchView',
7310.5.1 by Michael Nelson
Implementing cprovs suggested cleanup so the searches for Distribution,
22
    'DistributionPackageSearchView',
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
23
    'DistributionPendingReviewMirrorsView',
7675.1063.2 by Julian Edwards
s/DistributionPublisherConfig/DistributionPublisherConfigView/
24
    'DistributionPublisherConfigView',
12552.2.9 by Raphaël Badin
Fixed reassign page display. Added tests.
25
    'DistributionReassignmentView',
9418.2.3 by Curtis Hovey
Converted the distro +series page to UI 3.0. Copied product +series formating.
26
    'DistributionSeriesView',
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
27
    'DistributionDerivativesView',
6767.8.33 by Maris Fogels
Merge from RF. Resolved 8 conflicts (oh joy.)
28
    'DistributionSeriesMirrorsRSSView',
4285.2.1 by Mark Shuttleworth
Massive renaming of distrorelease to distroseries
29
    'DistributionSeriesMirrorsView',
9184.3.1 by Barry Warsaw
Convert /distros to UI 3.0
30
    'DistributionSetActionNavigationMenu',
9209.4.5 by Guilherme Salgado
Update all existing breadcrumb adapters to use Breadcrumb rather than BreadcrumbBuilder. Also rename them all
31
    'DistributionSetBreadcrumb',
6767.6.8 by Maris Fogels
Migrated the Distribution breadcrumbs to the new system interface.
32
    'DistributionSetContextMenu',
3847.2.11 by Mark Shuttleworth
Improve headings of structural object containers (/products/, /people/) etc
33
    'DistributionSetFacets',
34
    'DistributionSetNavigation',
6767.6.8 by Maris Fogels
Migrated the Distribution breadcrumbs to the new system interface.
35
    'DistributionSetView',
6767.8.33 by Maris Fogels
Merge from RF. Resolved 8 conflicts (oh joy.)
36
    'DistributionSpecificationsMenu',
6767.6.8 by Maris Fogels
Migrated the Distribution breadcrumbs to the new system interface.
37
    'DistributionUnofficialMirrorsView',
38
    'DistributionView',
2071 by Canonical.com Patch Queue Manager
[trivial] add more __all__ statements, other minor tidyings-up
39
    ]
40
12208.2.5 by j.c.sackett
Updated the getOverallFreshness method to use cachedproperties that are prepopulated when archive mirrors are queried for.
41
from collections import defaultdict
3973.1.19 by Steve Alexander
make milestones dynmenu show only fairly recent milestones
42
import datetime
3691.93.33 by Christian Reis
Various random cleanups, including swapping lambdas for operator.attrgetter
43
1452 by Canonical.com Patch Queue Manager
fix the distribution bugs listing so that it shows new/accepted bugs by default, respects privacy and orders the tasks in a sane way
44
from zope.component import getUtility
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
45
from zope.event import notify
7675.1063.1 by Julian Edwards
basic implementation of +pubconf page, sans tests. So sue me for not doing TDD, I don't care.
46
from zope.formlib import form
6495.2.3 by Julian Edwards
Add nav menus
47
from zope.interface import implements
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
48
from zope.lifecycleevent import ObjectCreatedEvent
2090 by Canonical.com Patch Queue Manager
[r=SteveA] another round of import fascism and other cleanups
49
from zope.security.interfaces import Unauthorized
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
50
5309.1.3 by Edwin Grubbs
The <link> tag for referencing atom feeds in other web pages is now
51
from canonical.launchpad.browser.feeds import FeedsMixin
8399.3.8 by Michael Nelson
Updated so that source packages will be searched instead when indicated or dictated by distribution.has_binary_packages.
52
from canonical.launchpad.components.decoratedresultset import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
53
    DecoratedResultSet,
54
    )
55
from canonical.launchpad.helpers import english_list
2344 by Canonical.com Patch Queue Manager
[not r=kiko] specification tracker
56
from canonical.launchpad.webapp import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
57
    ApplicationMenu,
58
    canonical_url,
59
    ContextMenu,
60
    enabled_with_permission,
61
    GetitemNavigation,
62
    LaunchpadView,
63
    Link,
64
    Navigation,
65
    NavigationMenu,
66
    redirection,
67
    StandardLaunchpadFacets,
68
    stepthrough,
69
    )
1716.3.67 by Christian Reis
Move the batching code from canonical.lp to canonical.launchpad.webapp
70
from canonical.launchpad.webapp.batching import BatchNavigator
9209.4.5 by Guilherme Salgado
Update all existing breadcrumb adapters to use Breadcrumb rather than BreadcrumbBuilder. Also rename them all
71
from canonical.launchpad.webapp.breadcrumb import Breadcrumb
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
72
from canonical.launchpad.webapp.interfaces import ILaunchBag
73
from lp.answers.browser.faqtarget import FAQTargetNavigationMixin
74
from lp.answers.browser.questiontarget import (
75
    QuestionTargetFacetMixin,
76
    QuestionTargetTraversalMixin,
77
    )
11929.9.1 by Tim Penhey
Move launchpadform into lp.app.browser.
78
from lp.app.browser.launchpadform import (
79
    action,
80
    custom_widget,
81
    LaunchpadFormView,
82
    )
11270.1.3 by Tim Penhey
Changed NotFoundError imports - gee there were a lot of them.
83
from lp.app.errors import NotFoundError
12293.1.10 by Curtis Hovey
Formatted imports.
84
from lp.app.widgets.image import ImageChangeWidget
7675.1063.1 by Julian Edwards
basic implementation of +pubconf page, sans tests. So sue me for not doing TDD, I don't care.
85
from lp.archivepublisher.interfaces.publisherconfig import (
86
    IPublisherConfig,
87
    IPublisherConfigSet,
88
    )
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
89
from lp.blueprints.browser.specificationtarget import (
90
    HasSpecificationsMenuMixin,
91
    )
92
from lp.bugs.browser.bugtask import BugTargetTraversalMixin
7675.1025.1 by Gary Poster
structural subscriptions are moved from registry to bugs. moved tests pass.
93
from lp.bugs.browser.structuralsubscription import (
12393.30.1 by Brad Crittenden
Add structural subscription link to all IStructuralSubscriptionTargets
94
    expose_structural_subscription_data_to_js,
12393.30.14 by Brad Crittenden
Updated tests for distributions. Handle 'official_malone' where needed. Follow the rules for distributions with bug supervisors.
95
    StructuralSubscriptionMenuMixin,
7675.1025.1 by Gary Poster
structural subscriptions are moved from registry to bugs. moved tests pass.
96
    StructuralSubscriptionTargetTraversalMixin,
97
    )
12688.1.5 by Brad Crittenden
Fixed issues from review. Created add_subscribe_link.
98
from lp.registry.browser import (
99
    add_subscribe_link,
100
    RegistryEditFormView,
101
    )
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
102
from lp.registry.browser.announcement import HasAnnouncementsView
103
from lp.registry.browser.menu import (
104
    IRegistryCollectionNavigationMenu,
105
    RegistryCollectionActionMenuBase,
106
    )
107
from lp.registry.browser.pillar import PillarBugsMenu
12552.2.9 by Raphaël Badin
Fixed reassign page display. Added tests.
108
from lp.registry.browser.objectreassignment import ObjectReassignmentView
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
109
from lp.registry.interfaces.distribution import (
110
    IDerivativeDistribution,
111
    IDistribution,
112
    IDistributionMirrorMenuMarker,
113
    IDistributionSet,
114
    )
115
from lp.registry.interfaces.distributionmirror import (
116
    IDistributionMirrorSet,
117
    MirrorContent,
118
    MirrorSpeed,
119
    )
120
from lp.registry.interfaces.series import SeriesStatus
11532.7.3 by Curtis Hovey
Moved request_country to lp.services.geoip.
121
from lp.services.geoip.helpers import (
122
    ipaddress_from_request,
123
    request_country,
124
    )
11382.6.34 by Gavin Panella
Reformat imports in all files touched so far.
125
from lp.services.propertycache import cachedproperty
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
126
from lp.soyuz.browser.packagesearch import PackageSearchViewBase
11411.6.2 by Julian Edwards
Change code imports for ArchivePurpose and ArchiveStatus
127
from lp.soyuz.enums import ArchivePurpose
11382.6.44 by Gavin Panella
Fix and reformat imports.
128
from lp.soyuz.interfaces.archive import IArchiveSet
9116.5.3 by Curtis Hovey
Added a RegistryEditForm that provides the common features for Edit forms.
129
2705 by Canonical.com Patch Queue Manager
r=spiv, mark's soyuz loving.
130
3691.188.5 by Francis J. Lacoste
Refactor common tickettarget support facet link and traversal into common mixins
131
class DistributionNavigation(
4319.2.19 by Francis J. Lacoste
Add minimal FAQ view.
132
    GetitemNavigation, BugTargetTraversalMixin, QuestionTargetTraversalMixin,
9206.2.1 by William Grant
Add a URL and traversal mixin for IStructuralSubscription. Mix it into all targets.
133
    FAQTargetNavigationMixin, StructuralSubscriptionTargetTraversalMixin):
1716.1.190 by Christian Reis
Merge from RF, again, this time for real
134
135
    usedfor = IDistribution
136
2890.1.4 by Dafydd Harries
fix typo, add pagetest, move shipit test to correct location
137
    @redirection('+source', status=301)
2890.1.3 by Dafydd Harries
use new redirection decorator
138
    def redirect_source(self):
139
        return canonical_url(self.context)
2890.1.1 by Dafydd Harries
Fix bug #2230 by adding a redirect from '+source' to '..'.
140
2908.4.1 by Guilherme Salgado
First round of implementation of MirrorManagement.
141
    @stepthrough('+mirror')
142
    def traverse_mirrors(self, name):
143
        return self.context.getMirrorByName(name)
144
2705 by Canonical.com Patch Queue Manager
r=spiv, mark's soyuz loving.
145
    @stepthrough('+source')
1716.1.190 by Christian Reis
Merge from RF, again, this time for real
146
    def traverse_sources(self, name):
2705 by Canonical.com Patch Queue Manager
r=spiv, mark's soyuz loving.
147
        return self.context.getSourcePackage(name)
1716.1.190 by Christian Reis
Merge from RF, again, this time for real
148
149
    @stepthrough('+milestone')
150
    def traverse_milestone(self, name):
151
        return self.context.getMilestone(name)
152
5151.1.5 by Mark Shuttleworth
Allow editing of announcement details
153
    @stepthrough('+announcement')
154
    def traverse_announcement(self, name):
155
        return self.context.getAnnouncement(name)
156
1716.1.190 by Christian Reis
Merge from RF, again, this time for real
157
    @stepthrough('+spec')
158
    def traverse_spec(self, name):
159
        return self.context.getSpecification(name)
160
7026.4.3 by Julian Edwards
Add navigation for distribution archives, ready for API exposure.
161
    @stepthrough('+archive')
162
    def traverse_archive(self, name):
10861.2.1 by William Grant
Move traverse_distro_archive to Distribution.getArchive, and export it.
163
        return self.context.getArchive(name)
7026.4.3 by Julian Edwards
Add navigation for distribution archives, ready for API exposure.
164
2630 by Canonical.com Patch Queue Manager
[trivial] lots of tidying up. converting all database classes to use NotFoundError consistently, and to import it from launchpad.interfaces in preparation for the move to a new zope3. Also, introduced a NameNotAvailable error. removed browser:traverse rdirective. commented out shipit test that fails sometimes.
165
3691.417.1 by Tim Penhey
Removing the RedirectionNavigation class
166
class DistributionSetNavigation(Navigation):
2628 by Canonical.com Patch Queue Manager
[trivial] converted a bunch of browser:traverse into navigation
167
168
    usedfor = IDistributionSet
169
3691.267.4 by Stuart Bishop
Traversal and redirects done
170
    def traverse(self, name):
171
        # Raise a 404 on an invalid distribution name
3691.417.1 by Tim Penhey
Removing the RedirectionNavigation class
172
        distribution = self.context.getByName(name)
173
        if distribution is None:
3691.267.4 by Stuart Bishop
Traversal and redirects done
174
            raise NotFoundError(name)
3691.417.1 by Tim Penhey
Removing the RedirectionNavigation class
175
        return self.redirectSubTree(canonical_url(distribution))
3691.267.4 by Stuart Bishop
Traversal and redirects done
176
2519 by Canonical.com Patch Queue Manager
r=BjornT, more actions portlets converted to menus, introduction of LaunchpadView.
177
3691.398.19 by Francis J. Lacoste
Rename most remaining classes (views, database, authorizations, notifications, scripts.)
178
class DistributionFacets(QuestionTargetFacetMixin, StandardLaunchpadFacets):
2344 by Canonical.com Patch Queue Manager
[not r=kiko] specification tracker
179
1970 by Canonical.com Patch Queue Manager
Daf's menus branch. r=SteveA.
180
    usedfor = IDistribution
181
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
182
    enable_only = [
183
        'overview',
184
        'branches',
185
        'bugs',
186
        'answers',
187
        'specifications',
188
        'translations',
189
        ]
2738 by Canonical.com Patch Queue Manager
[trivial] various bugs fixed
190
2423 by Canonical.com Patch Queue Manager
r=bjornt plus some [trivial] extra refactorings. more consistent facet menus across the whole of launchpad. improvements in the API.
191
    def specifications(self):
3842.1.20 by Matthew Paul Thomas
Changes many occurrences of 'specifications' and 'Features' to 'blueprints'; fixes bug 84210 in Blueprint (Naming inconsistencies in sections).
192
        text = 'Blueprints'
2344 by Canonical.com Patch Queue Manager
[not r=kiko] specification tracker
193
        summary = 'Feature specifications for %s' % self.context.displayname
4013.1.4 by kiko
Fix facet target links to take advantage of the defaultviews registered (and fix a defaultview for distributionsourcepackage, which was missing).
194
        return Link('', text, summary)
2344 by Canonical.com Patch Queue Manager
[not r=kiko] specification tracker
195
196
9209.4.5 by Guilherme Salgado
Update all existing breadcrumb adapters to use Breadcrumb rather than BreadcrumbBuilder. Also rename them all
197
class DistributionSetBreadcrumb(Breadcrumb):
6767.6.26 by Maris Fogels
Rework based on reviewer feedback.
198
    """Builds a breadcrumb for an `IDistributionSet`."""
6767.6.8 by Maris Fogels
Migrated the Distribution breadcrumbs to the new system interface.
199
    text = 'Distributions'
200
201
3847.2.11 by Mark Shuttleworth
Improve headings of structural object containers (/products/, /people/) etc
202
class DistributionSetFacets(StandardLaunchpadFacets):
203
204
    usedfor = IDistributionSet
205
206
    enable_only = ['overview', ]
207
208
3842.1.13 by Matthew Paul Thomas
Adds links to other pillar indexes (excluding /projects) from the Actions menu for each pillar index (excluding /projects).
209
class DistributionSetContextMenu(ContextMenu):
210
211
    usedfor = IDistributionSet
3847.2.11 by Mark Shuttleworth
Improve headings of structural object containers (/products/, /people/) etc
212
    links = ['products', 'distributions', 'people', 'meetings']
213
214
    def distributions(self):
215
        return Link('/distros/', 'View distributions')
3842.1.13 by Matthew Paul Thomas
Adds links to other pillar indexes (excluding /projects) from the Actions menu for each pillar index (excluding /projects).
216
217
    def products(self):
4011.2.7 by Bjorn Tillenius
move /products to /projects
218
        return Link('/projects/', 'View projects')
3842.1.13 by Matthew Paul Thomas
Adds links to other pillar indexes (excluding /projects) from the Actions menu for each pillar index (excluding /projects).
219
220
    def people(self):
3847.2.11 by Mark Shuttleworth
Improve headings of structural object containers (/products/, /people/) etc
221
        return Link('/people/', 'View people')
3842.1.13 by Matthew Paul Thomas
Adds links to other pillar indexes (excluding /projects) from the Actions menu for each pillar index (excluding /projects).
222
223
    def meetings(self):
3847.2.11 by Mark Shuttleworth
Improve headings of structural object containers (/products/, /people/) etc
224
        return Link('/sprints/', 'View meetings')
3842.1.13 by Matthew Paul Thomas
Adds links to other pillar indexes (excluding /projects) from the Actions menu for each pillar index (excluding /projects).
225
226
6495.2.3 by Julian Edwards
Add nav menus
227
class DistributionMirrorsNavigationMenu(NavigationMenu):
228
229
    usedfor = IDistributionMirrorMenuMarker
230
    facet = 'overview'
231
    links = ('cdimage_mirrors',
232
             'archive_mirrors',
233
             'disabled_mirrors',
234
             'pending_review_mirrors',
235
             'unofficial_mirrors',
236
             )
237
238
    @property
239
    def distribution(self):
240
        """Helper method to return the distribution object.
241
242
        self.context is the view, so return *its* context.
243
        """
244
        return self.context.context
245
246
    def cdimage_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
247
        text = 'CD mirrors'
9228.1.4 by Brad Crittenden
Changes due to code review.
248
        return Link('+cdmirrors', text, icon='info')
6495.2.3 by Julian Edwards
Add nav menus
249
250
    def archive_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
251
        text = 'Archive mirrors'
9228.1.4 by Brad Crittenden
Changes due to code review.
252
        return Link('+archivemirrors', text, icon='info')
6495.2.3 by Julian Edwards
Add nav menus
253
254
    def newmirror(self):
9152.7.4 by Brad Crittenden
checkpoint
255
        text = 'Register mirror'
9228.1.4 by Brad Crittenden
Changes due to code review.
256
        return Link('+newmirror', text, icon='add')
6495.2.3 by Julian Edwards
Add nav menus
257
258
    def _userCanSeeNonPublicMirrorListings(self):
259
        """Does the user have rights to see non-public mirrors listings?"""
260
        user = getUtility(ILaunchBag).user
261
        return (self.distribution.full_functionality
262
                and user is not None
263
                and user.inTeam(self.distribution.mirror_admin))
264
265
    def disabled_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
266
        text = 'Disabled mirrors'
6495.2.3 by Julian Edwards
Add nav menus
267
        enabled = self._userCanSeeNonPublicMirrorListings()
268
        return Link('+disabledmirrors', text, enabled=enabled, icon='info')
269
270
    def pending_review_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
271
        text = 'Pending-review mirrors'
6495.2.3 by Julian Edwards
Add nav menus
272
        enabled = self._userCanSeeNonPublicMirrorListings()
273
        return Link(
274
            '+pendingreviewmirrors', text, enabled=enabled, icon='info')
275
276
    def unofficial_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
277
        text = 'Unofficial mirrors'
6495.2.3 by Julian Edwards
Add nav menus
278
        enabled = self._userCanSeeNonPublicMirrorListings()
279
        return Link('+unofficialmirrors', text, enabled=enabled, icon='info')
280
281
12393.30.14 by Brad Crittenden
Updated tests for distributions. Handle 'official_malone' where needed. Follow the rules for distributions with bug supervisors.
282
class DistributionLinksMixin(StructuralSubscriptionMenuMixin):
12393.30.1 by Brad Crittenden
Add structural subscription link to all IStructuralSubscriptionTargets
283
    """A mixin to provide common links to menus."""
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
284
285
    @enabled_with_permission('launchpad.Edit')
286
    def edit(self):
287
        text = 'Change details'
288
        return Link('+edit', text, icon='edit')
289
290
291
class DistributionNavigationMenu(NavigationMenu, DistributionLinksMixin):
292
    """A menu of context actions."""
6495.2.3 by Julian Edwards
Add nav menus
293
    usedfor = IDistribution
294
    facet = 'overview'
12393.30.3 by Brad Crittenden
Added new structural subscription to other IStructuralSubscriptionTargets (except IDistributionSourcePackage which is TBD) and included feature flags for all. Tests in test_product.py do not work.
295
7675.1063.7 by Julian Edwards
Add link to 'Configure publisher' from the distro page, and add it to the story test
296
    @enabled_with_permission("launchpad.Admin")
297
    def pubconf(self):
298
        text = "Configure publisher"
299
        return Link("+pubconf", text, icon="edit")
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
300
12393.30.14 by Brad Crittenden
Updated tests for distributions. Handle 'official_malone' where needed. Follow the rules for distributions with bug supervisors.
301
    @cachedproperty
12393.30.3 by Brad Crittenden
Added new structural subscription to other IStructuralSubscriptionTargets (except IDistributionSourcePackage which is TBD) and included feature flags for all. Tests in test_product.py do not work.
302
    def links(self):
13247.1.1 by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed.
303
        return ['edit', 'pubconf', 'subscribe_to_bug_mail', 'edit_bug_mail']
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
304
305
306
class DistributionOverviewMenu(ApplicationMenu, DistributionLinksMixin):
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
307
308
    usedfor = IDistribution
309
    facet = 'overview'
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
310
    links = [
311
        'edit',
312
        'branding',
313
        'driver',
314
        'search',
315
        'members',
316
        'mirror_admin',
317
        'reassign',
318
        'addseries',
319
        'series',
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
320
        'derivatives',
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
321
        'milestones',
322
        'top_contributors',
323
        'builds',
324
        'cdimage_mirrors',
325
        'archive_mirrors',
326
        'pending_review_mirrors',
327
        'disabled_mirrors',
328
        'unofficial_mirrors',
329
        'newmirror',
330
        'announce',
331
        'announcements',
332
        'ppas',
333
        'configure_answers',
11515.6.19 by j.c.sackett
Updated handling of templates for all specification targets. Added tests.
334
        'configure_blueprints',
11551.8.25 by j.c.sackett
Lint fixes.
335
        'configure_translations',
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
336
        ]
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
337
3202.1.1 by Matthew Paul Thomas
re-apply fixes for bug 1001, bug 3192, bug 31839, and bug 32269
338
    @enabled_with_permission('launchpad.Edit')
4005.1.7 by Mark Shuttleworth
Branding works for all pillars
339
    def branding(self):
340
        text = 'Change branding'
341
        return Link('+branding', text, icon='edit')
342
343
    @enabled_with_permission('launchpad.Edit')
3348.1.21 by Mark Shuttleworth
Enable setting and proper use of the "drivers" details.
344
    def driver(self):
3847.2.15 by Mark Shuttleworth
Consistency in menu text and capitalisation
345
        text = 'Appoint driver'
4285.2.1 by Mark Shuttleworth
Massive renaming of distrorelease to distroseries
346
        summary = 'Someone with permission to set goals for all series'
3348.1.21 by Mark Shuttleworth
Enable setting and proper use of the "drivers" details.
347
        return Link('+driver', text, summary, icon='edit')
348
349
    @enabled_with_permission('launchpad.Edit')
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
350
    def reassign(self):
12552.2.9 by Raphaël Badin
Fixed reassign page display. Added tests.
351
        text = 'Change maintainer'
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
352
        return Link('+reassign', text, icon='edit')
353
2908.4.1 by Guilherme Salgado
First round of implementation of MirrorManagement.
354
    def newmirror(self):
3847.2.15 by Mark Shuttleworth
Consistency in menu text and capitalisation
355
        text = 'Register a new mirror'
3545.1.2 by Mark Shuttleworth
Only enable mirrors for full funcitonality distros.
356
        enabled = self.context.full_functionality
357
        return Link('+newmirror', text, enabled=enabled, icon='add')
2908.4.1 by Guilherme Salgado
First round of implementation of MirrorManagement.
358
3691.62.16 by kiko
Put the top contributors link in the menus
359
    def top_contributors(self):
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
360
        text = 'More contributors'
361
        return Link('+topcontributors', text, icon='info')
3691.62.16 by kiko
Put the top contributors link in the menus
362
4285.2.2 by Mark Shuttleworth
Fix cases where db code must still refer to the old DistroRelease table name
363
    def cdimage_mirrors(self):
9152.7.2 by Brad Crittenden
Convert distribution mirror pages to UI 3.0
364
        text = 'CD mirrors'
365
        return Link('+cdmirrors', text, icon='info')
2908.4.1 by Guilherme Salgado
First round of implementation of MirrorManagement.
366
3525.1.1 by Guilherme Salgado
Make the mirror prober probe release mirrors, improve the UI a lot and lots of other fixes.
367
    def archive_mirrors(self):
9152.7.2 by Brad Crittenden
Convert distribution mirror pages to UI 3.0
368
        text = 'Archive mirrors'
369
        return Link('+archivemirrors', text, icon='info')
2908.4.1 by Guilherme Salgado
First round of implementation of MirrorManagement.
370
5206.9.7 by Guilherme Salgado
Some changes suggested by Brad
371
    def _userCanSeeNonPublicMirrorListings(self):
372
        """Does the user have rights to see non-public mirrors listings?"""
373
        user = getUtility(ILaunchBag).user
374
        return (self.context.full_functionality
375
                and user is not None
376
                and user.inTeam(self.context.mirror_admin))
377
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
378
    def disabled_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
379
        text = 'Disabled mirrors'
5206.9.7 by Guilherme Salgado
Some changes suggested by Brad
380
        enabled = self._userCanSeeNonPublicMirrorListings()
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
381
        return Link('+disabledmirrors', text, enabled=enabled, icon='info')
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
382
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
383
    def pending_review_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
384
        text = 'Pending-review mirrors'
5206.9.7 by Guilherme Salgado
Some changes suggested by Brad
385
        enabled = self._userCanSeeNonPublicMirrorListings()
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
386
        return Link(
387
            '+pendingreviewmirrors', text, enabled=enabled, icon='info')
388
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
389
    def unofficial_mirrors(self):
9152.7.4 by Brad Crittenden
checkpoint
390
        text = 'Unofficial mirrors'
5206.9.7 by Guilherme Salgado
Some changes suggested by Brad
391
        enabled = self._userCanSeeNonPublicMirrorListings()
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
392
        return Link('+unofficialmirrors', text, enabled=enabled, icon='info')
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
393
3202.1.1 by Matthew Paul Thomas
re-apply fixes for bug 1001, bug 3192, bug 31839, and bug 32269
394
    @enabled_with_permission('launchpad.Edit')
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
395
    def members(self):
3847.2.15 by Mark Shuttleworth
Consistency in menu text and capitalisation
396
        text = 'Change members team'
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
397
        return Link('+selectmemberteam', text, icon='edit')
398
3500.3.16 by Celso Providelo
Using Distribution.archiveadmin person reference and the archive/queue celebrity, ubuntu/+archiveadmin UI to define it, fixed security adapters and improved pagetests (maybe we need more ...)
399
    @enabled_with_permission('launchpad.Edit')
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
400
    def mirror_admin(self):
3847.2.15 by Mark Shuttleworth
Consistency in menu text and capitalisation
401
        text = 'Change mirror admins'
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
402
        enabled = self.context.full_functionality
403
        return Link('+selectmirroradmins', text, enabled=enabled, icon='edit')
404
2705 by Canonical.com Patch Queue Manager
r=spiv, mark's soyuz loving.
405
    def search(self):
3847.2.15 by Mark Shuttleworth
Consistency in menu text and capitalisation
406
        text = 'Search packages'
2705 by Canonical.com Patch Queue Manager
r=spiv, mark's soyuz loving.
407
        return Link('+search', text, icon='search')
2548 by Canonical.com Patch Queue Manager
r=bjornt, plus some [trivial], lots of menus work, special error page for request timeouts.
408
409
    @enabled_with_permission('launchpad.Admin')
4285.2.1 by Mark Shuttleworth
Massive renaming of distrorelease to distroseries
410
    def addseries(self):
411
        text = 'Add series'
412
        return Link('+addseries', text, icon='add')
2548 by Canonical.com Patch Queue Manager
r=bjornt, plus some [trivial], lots of menus work, special error page for request timeouts.
413
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
414
    def series(self):
415
        text = 'All series'
416
        return Link('+series', text, icon='info')
417
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
418
    def derivatives(self):
419
        text = 'All derivatives'
420
        return Link('+derivatives', text, icon='info')
421
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
422
    def milestones(self):
9116.6.9 by Curtis Hovey
Fixed mad link. Removed unneeded test.
423
        text = 'All milestones'
9116.6.7 by Curtis Hovey
Completed that approved distribution page layout.
424
        return Link('+milestones', text, icon='info')
425
5151.1.1 by Mark Shuttleworth
Initial capability to add news items
426
    @enabled_with_permission('launchpad.Edit')
427
    def announce(self):
428
        text = 'Make announcement'
429
        summary = 'Publish an item of news for this project'
5151.1.63 by Mark Shuttleworth
Make project announcements visible to non-beta-users
430
        return Link('+announce', text, summary, icon='add')
5151.1.1 by Mark Shuttleworth
Initial capability to add news items
431
5151.1.3 by Mark Shuttleworth
List announcements for a project
432
    def announcements(self):
9129.4.4 by Brad Crittenden
Updated announcements link to be consistent with product and project.
433
        text = 'Read all announcements'
434
        enabled = bool(self.context.getAnnouncements())
435
        return Link('+announcements', text, icon='info', enabled=enabled)
5151.1.3 by Mark Shuttleworth
List announcements for a project
436
2772.1.15 by Celso Providelo
Unify +builds pages using the same template, macro usage still grumgy, fixed tests
437
    def builds(self):
3119.1.2 by Matthew Paul Thomas
finish headings; fix pagetests
438
        text = 'Builds'
2772.1.26 by Celso Providelo
Move setupBuildList call back to template, in initialize it would be called in wrong conditions, removing some trailing white spaces.
439
        return Link('+builds', text, icon='info')
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
440
3691.443.66 by Celso Providelo
PPA list page under '+ubuntu' (it's not definitive)
441
    def ppas(self):
442
        text = 'Personal Package Archives'
443
        return Link('+ppas', text, icon='info')
444
11227.3.28 by Curtis Hovey
Added configure_answers link to distributions.
445
    @enabled_with_permission('launchpad.Edit')
446
    def configure_answers(self):
447
        text = 'Configure support tracker'
448
        summary = 'Allow users to ask questions on this project'
449
        return Link('+edit', text, summary, icon='edit')
450
11515.6.19 by j.c.sackett
Updated handling of templates for all specification targets. Added tests.
451
    @enabled_with_permission('launchpad.Edit')
452
    def configure_blueprints(self):
453
        text = 'Configure blueprints'
11551.8.25 by j.c.sackett
Lint fixes.
454
        summary = 'Enable tracking of feature planning.'
11515.6.19 by j.c.sackett
Updated handling of templates for all specification targets. Added tests.
455
        return Link('+edit', text, summary, icon='edit')
3103.1.2 by Bjorn Tillenius
add UI for distribution launchpad usage.
456
12143.2.5 by Danilo Segan
Fix up failing tests.
457
    @enabled_with_permission('launchpad.TranslationsAdmin')
11551.8.4 by j.c.sackett
Added configuration for translations to distribution menu.
458
    def configure_translations(self):
459
        text = 'Configure translations'
11551.8.25 by j.c.sackett
Lint fixes.
460
        summary = 'Allow users to provide translations for this project.'
12143.2.3 by Danilo Segan
Clean up "configure translations" links.
461
        return Link('+configure-translations', text, summary, icon='edit')
11515.6.21 by j.c.sackett
Lint fixes.
462
11551.8.25 by j.c.sackett
Lint fixes.
463
9437.1.3 by Curtis Hovey
Added DerivativeDistributionOverviewMenu because links have different permissions.
464
class DerivativeDistributionOverviewMenu(DistributionOverviewMenu):
465
466
    usedfor = IDerivativeDistribution
467
12758.1.1 by Julian Edwards
Fix +adderies permissions so drivers can create series in derived distros
468
    @enabled_with_permission('launchpad.Moderate')
9437.1.3 by Curtis Hovey
Added DerivativeDistributionOverviewMenu because links have different permissions.
469
    def addseries(self):
470
        text = 'Add series'
471
        return Link('+addseries', text, icon='add')
472
473
10981.4.14 by Brad Crittenden
Add configure_bugtracker to involvement portlet on product bugs page. Refactored bugs menus for DRY
474
class DistributionBugsMenu(PillarBugsMenu):
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
475
476
    usedfor = IDistribution
477
    facet = 'bugs'
12688.1.3 by Brad Crittenden
Fixed more lint
478
12393.30.3 by Brad Crittenden
Added new structural subscription to other IStructuralSubscriptionTargets (except IDistributionSourcePackage which is TBD) and included feature flags for all. Tests in test_product.py do not work.
479
    @property
480
    def links(self):
481
        links = [
482
            'bugsupervisor',
483
            'securitycontact',
484
            'cve',
485
            'filebug',
486
            ]
12688.1.5 by Brad Crittenden
Fixed issues from review. Created add_subscribe_link.
487
        add_subscribe_link(links)
12393.30.3 by Brad Crittenden
Added new structural subscription to other IStructuralSubscriptionTargets (except IDistributionSourcePackage which is TBD) and included feature flags for all. Tests in test_product.py do not work.
488
        return links
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
489
490
9559.1.2 by Henning Eggers
Converted hasspecifications-specs.pt to 3.0 layout. Refactored all specification menus into a Mixin. Fixed specfications vhost breadcrumb. Fixed some labels and page_titles.
491
class DistributionSpecificationsMenu(NavigationMenu,
492
                                     HasSpecificationsMenuMixin):
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
493
    usedfor = IDistribution
494
    facet = 'specifications'
9838.2.19 by Curtis Hovey
Added register a meeting link to hasspecifications pillars and series.
495
    links = ['listall', 'doc', 'assignments', 'new', 'register_sprint']
3203.1.3 by Mark Shuttleworth
Substantial cleanup of spec listings and spec targeting
496
2482 by Canonical.com Patch Queue Manager
r=kiko + some [trivial] various menus landings.
497
7310.5.3 by Michael Nelson
Changes recommended by Graham's review.
498
class DistributionPackageSearchView(PackageSearchViewBase):
7310.5.1 by Michael Nelson
Implementing cprovs suggested cleanup so the searches for Distribution,
499
    """Customised PackageSearchView for Distribution"""
500
8399.3.1 by Michael Nelson
Diff from old branch..
501
    def initialize(self):
502
        """Save the search type if provided."""
503
        super(DistributionPackageSearchView, self).initialize()
504
505
        # If the distribution contains binary packages, then we'll
506
        # default to searches on binary names, but allow the user to
507
        # select.
8399.3.2 by Michael Nelson
Ensured that a binary search is not allowed when the distro does not have published binaries.
508
        if self.context.has_published_binaries:
509
            self.search_type = self.request.get("search_type", 'binary')
510
        else:
511
            self.search_type = 'source'
8399.3.1 by Michael Nelson
Diff from old branch..
512
7310.5.2 by Michael Nelson
Updated with Muharem's suggested changes after reviewing.
513
    def contextSpecificSearch(self):
7310.5.1 by Michael Nelson
Implementing cprovs suggested cleanup so the searches for Distribution,
514
        """See `AbstractPackageSearchView`."""
8399.3.8 by Michael Nelson
Updated so that source packages will be searched instead when indicated or dictated by distribution.has_binary_packages.
515
516
        if self.search_by_binary_name:
11411.2.1 by Michael Nelson
Removed workarounds for bug 217644.
517
            return self.context.searchBinaryPackages(self.text)
8399.3.8 by Michael Nelson
Updated so that source packages will be searched instead when indicated or dictated by distribution.has_binary_packages.
518
        else:
8399.3.28 by Michael Nelson
Updated view and template to use package caches.
519
            non_exact_matches = self.context.searchSourcePackageCaches(
520
                self.text)
521
8399.3.29 by Michael Nelson
Just updating comment wrapping.
522
            # The searchBinaryPackageCaches() method returns tuples, so we
523
            # use the DecoratedResultSet here to just get the
8399.3.28 by Michael Nelson
Updated view and template to use package caches.
524
            # DistributionSourcePackag objects for the template.
525
            def tuple_to_package_cache(cache_name_tuple):
526
                return cache_name_tuple[0]
527
528
            non_exact_matches = DecoratedResultSet(
529
                non_exact_matches, tuple_to_package_cache)
8399.3.5 by Michael Nelson
Added test for substring matches and included fix for storm count method (using decorated result set).
530
531
        return non_exact_matches.config(distinct=True)
8399.3.1 by Michael Nelson
Diff from old branch..
532
533
    @property
534
    def search_by_binary_name(self):
535
        """Return whether the search is on binary names.
536
537
        By default, we search by binary names, as this produces much
538
        better results. But the user may decide to search by sources, or
539
        in the case of other distributions, it will be the only option.
540
        """
541
        return self.search_type == "binary"
542
8399.3.9 by Michael Nelson
Added link to source package search when binary search returns zero results.
543
    @property
544
    def source_search_url(self):
545
        """Return the equivalent search on source packages.
546
547
        By default, we search by binary names, but also provide a link
548
        to the equivalent source package search in some circumstances.
549
        """
7675.284.3 by Celso Providelo
applying review comments, r=abentley.
550
        return "%s/+search?search_type=source&%s" % (
8399.3.9 by Michael Nelson
Added link to source package search when binary search returns zero results.
551
            canonical_url(self.context),
7675.284.3 by Celso Providelo
applying review comments, r=abentley.
552
            self.request.get('QUERY_STRING'),
8399.3.9 by Michael Nelson
Added link to source package search when binary search returns zero results.
553
            )
554
8399.3.1 by Michael Nelson
Diff from old branch..
555
    @cachedproperty
556
    def exact_matches(self):
8399.3.23 by Michael Nelson
ensured matching binaries only displayed if there are some (the caches can be out of date), and gave a default ordering of exact matches.
557
        return self.context.searchBinaryPackages(
558
            self.text, exact_match=True).order_by('name')
8399.3.1 by Michael Nelson
Diff from old branch..
559
560
    @property
561
    def has_exact_matches(self):
562
        return self.exact_matches.count() > 0
563
564
    @property
565
    def has_matches(self):
566
        return self.matches > 0
567
568
    @cachedproperty
569
    def matching_binary_names(self):
570
        """Define the matching binary names for each result in the batch."""
571
        names = {}
8399.3.12 by Michael Nelson
Updated the view and template so that the template always receives DistributionSourcePackages, but the view can still access the cached info.
572
8399.3.28 by Michael Nelson
Updated view and template to use package caches.
573
        for package_cache in self.batchnav.currentBatch():
8399.3.30 by Michael Nelson
more changes from martin, as well as moving the listFirstFiveMatchingNames browser method to protected.
574
            names[package_cache.name] = self._listFirstFiveMatchingNames(
8399.3.18 by Michael Nelson
Ensured a max of 5 matching binary names are displayed for each result.
575
                self.text, package_cache.binpkgnames)
576
8399.3.1 by Michael Nelson
Diff from old branch..
577
        return names
578
8399.3.30 by Michael Nelson
more changes from martin, as well as moving the listFirstFiveMatchingNames browser method to protected.
579
    def _listFirstFiveMatchingNames(self, match_text, space_separated_list):
8399.3.18 by Michael Nelson
Ensured a max of 5 matching binary names are displayed for each result.
580
        """Returns a comma-separated list of the first five matching items"""
581
        name_list = space_separated_list.split(' ')
582
583
        matching_names = [
584
            name for name in name_list if match_text in name]
585
8399.3.22 by Michael Nelson
Ensured that the list of 5 matching binaries is truncated after filtering out the non-matching ones.
586
        if len(matching_names) > 5:
587
            matching_names = matching_names[:5]
8399.3.18 by Michael Nelson
Ensured a max of 5 matching binary names are displayed for each result.
588
            matching_names.append('...')
8399.3.19 by Michael Nelson
Ensured matching distro-series are unique and sorted.
589
8399.3.18 by Michael Nelson
Ensured a max of 5 matching binary names are displayed for each result.
590
        return ", ".join(matching_names)
591
8399.3.1 by Michael Nelson
Diff from old branch..
592
    @cachedproperty
593
    def distroseries_names(self):
594
        """Define the distroseries for each package name in exact matches."""
595
        names = {}
596
        for package_cache in self.exact_matches:
597
            package = package_cache.distributionsourcepackage
8399.3.19 by Michael Nelson
Ensured matching distro-series are unique and sorted.
598
599
            # In the absense of Python3.0's set comprehension, we
600
            # create a list, convert the list to a set and back again:
8399.3.1 by Michael Nelson
Diff from old branch..
601
            distroseries_list = [
602
                pubrec.distroseries.name
8399.3.19 by Michael Nelson
Ensured matching distro-series are unique and sorted.
603
                    for pubrec in package.current_publishing_records
604
                        if pubrec.distroseries.active]
605
            distroseries_list = list(set(distroseries_list))
606
607
            # Yay for alphabetical series names.
608
            distroseries_list.sort()
8399.3.1 by Michael Nelson
Diff from old branch..
609
            names[package.name] = ", ".join(distroseries_list)
610
611
        return names
7310.5.1 by Michael Nelson
Implementing cprovs suggested cleanup so the searches for Distribution,
612
8399.3.6 by Michael Nelson
Ensured that the exact matches only display on the first page of results when doing a distro search.
613
    @property
614
    def display_exact_matches(self):
615
        """Return whether exact match results should be displayed."""
8399.3.16 by Michael Nelson
Added h2 heading for batched results.
616
        if not self.search_by_binary_name:
617
            return False
618
8399.3.6 by Michael Nelson
Ensured that the exact matches only display on the first page of results when doing a distro search.
619
        if self.batchnav.start > 0:
620
            return False
621
622
        return self.has_exact_matches
7310.5.1 by Michael Nelson
Implementing cprovs suggested cleanup so the searches for Distribution,
623
11227.3.28 by Curtis Hovey
Added configure_answers link to distributions.
624
11662.1.5 by j.c.sackett
Removes the UsesLaunchpadMixin that powered the "Uses Launchpad for" sectinos in the template.
625
class DistributionView(HasAnnouncementsView, FeedsMixin):
1943 by Canonical.com Patch Queue Manager
[r=SteveA] Full portlet refactor.
626
    """Default Distribution view class."""
2764.2.1 by Brad Bollenbach
apply my +filebug patch on a fresh new bzr branch
627
12393.30.1 by Brad Crittenden
Add structural subscription link to all IStructuralSubscriptionTargets
628
    def initialize(self):
12393.30.17 by Brad Crittenden
Merge from yellow + use expose_structural_subscription_data_to_js instead of new JSMixin
629
        super(DistributionView, self).initialize()
12393.30.1 by Brad Crittenden
Add structural subscription link to all IStructuralSubscriptionTargets
630
        expose_structural_subscription_data_to_js(
631
            self.context, self.request, self.user)
632
6607.7.1 by Julian Edwards
Clean up the milestones display so that it's a comma separated list.
633
    def linkedMilestonesForSeries(self, series):
634
        """Return a string of linkified milestones in the series."""
6607.7.4 by Julian Edwards
cprov's review suggestions.
635
        # Listify to remove repeated queries.
6607.7.1 by Julian Edwards
Clean up the milestones display so that it's a comma separated list.
636
        milestones = list(series.milestones)
6607.7.4 by Julian Edwards
cprov's review suggestions.
637
        if len(milestones) == 0:
638
            return ""
6607.7.1 by Julian Edwards
Clean up the milestones display so that it's a comma separated list.
639
640
        linked_milestones = []
641
        for milestone in milestones:
642
            linked_milestones.append(
643
                "<a href=%s>%s</a>" % (
644
                    canonical_url(milestone), milestone.name))
645
6607.7.5 by Julian Edwards
allenap comments
646
        return english_list(linked_milestones)
6607.7.1 by Julian Edwards
Clean up the milestones display so that it's a comma separated list.
647
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
648
    @cachedproperty
649
    def latest_derivatives(self):
650
        """The 5 most recent derivatives."""
651
        return self.context.derivatives[:5]
652
4285.3.65 by Celso Providelo
review comments [r=barry].
653
7434.3.3 by Michael Nelson
Initial commit of all front-end-only changes from larger branch. Still
654
class DistributionArchivesView(LaunchpadView):
655
656
    @property
657
    def batchnav(self):
658
        """Return the batch navigator for the archives."""
659
        return BatchNavigator(self.archive_list, self.request)
660
661
    @cachedproperty
662
    def archive_list(self):
663
        """Returns the list of archives for the given distribution.
7627.5.6 by Michael Nelson
Changes for mwhudson
664
7434.3.3 by Michael Nelson
Initial commit of all front-end-only changes from larger branch. Still
665
        The context may be an IDistroSeries or a users archives.
666
        """
667
        results = getUtility(IArchiveSet).getArchivesForDistribution(
11065.2.1 by Jelmer Vernooij
Only include disabled archives that the user has access to get in getArchivesForDistribution(exclude_disabled=False).
668
            self.context, purposes=[ArchivePurpose.COPY], user=self.user,
669
            exclude_disabled=False)
7434.3.3 by Michael Nelson
Initial commit of all front-end-only changes from larger branch. Still
670
        return results.order_by('date_created DESC')
671
9305.1.1 by Celso Providelo
Fixing bug #46789 (Re-introducing the icons lost in the 3.0 redesign of Distribution:+ppas plus some other minor tweaks).
672
4285.6.1 by Celso Providelo
Fix bug #126896 (do not list PPAs with zero packages by default).
673
class DistributionPPASearchView(LaunchpadView):
674
    """Search PPAs belonging to the Distribution in question."""
4285.3.65 by Celso Providelo
review comments [r=barry].
675
9557.1.1 by Michael Nelson
Adds a view.label for the distribution-ppas view.
676
    page_title = "Personal Package Archives"
677
4285.3.65 by Celso Providelo
review comments [r=barry].
678
    def initialize(self):
4285.6.8 by Celso Providelo
applying extra review comments [r=bjornt].
679
        self.name_filter = self.request.get('name_filter')
9693.1.1 by Julian Edwards
Fix an oops when someone hand-hacks URLs searching PPAs.
680
        if isinstance(self.name_filter, list):
681
            # This happens if someone hand-hacks the URL so that it has
9693.1.2 by Julian Edwards
Fix comment to remove the XXX
682
            # more than one name_filter field.  We could do something
683
            # like form.getOne() so that the request would be rejected,
684
            # but we can acutally do better and join the terms supplied
685
            # instead.
9693.1.1 by Julian Edwards
Fix an oops when someone hand-hacks URLs searching PPAs.
686
            self.name_filter = " ".join(self.name_filter)
4285.6.8 by Celso Providelo
applying extra review comments [r=bjornt].
687
        self.show_inactive = self.request.get('show_inactive')
688
5971.5.3 by Celso Providelo
Protoype of new PPA search page.
689
    @property
9557.1.1 by Michael Nelson
Adds a view.label for the distribution-ppas view.
690
    def label(self):
691
        return 'Personal Package Archives for %s' % self.context.title
9305.1.1 by Celso Providelo
Fixing bug #46789 (Re-introducing the icons lost in the 3.0 redesign of Distribution:+ppas plus some other minor tweaks).
692
693
    @property
5971.5.3 by Celso Providelo
Protoype of new PPA search page.
694
    def search_results(self):
695
        """Process search form request."""
696
        if self.name_filter is None:
697
            return None
698
4285.6.8 by Celso Providelo
applying extra review comments [r=bjornt].
699
        # Preserve self.show_inactive state because it's used in the
700
        # template and build a boolean field to be passed for
701
        # searchPPAs.
4285.6.10 by Celso Providelo
more review comments.
702
        show_inactive = (self.show_inactive == 'on')
4285.6.8 by Celso Providelo
applying extra review comments [r=bjornt].
703
4285.6.1 by Celso Providelo
Fix bug #126896 (do not list PPAs with zero packages by default).
704
        ppas = self.context.searchPPAs(
5565.5.2 by Julian Edwards
First security changes.
705
            text=self.name_filter, show_inactive=show_inactive,
706
            user=self.user)
4285.6.8 by Celso Providelo
applying extra review comments [r=bjornt].
707
4285.3.14 by Celso Providelo
Search PPA page.
708
        self.batchnav = BatchNavigator(ppas, self.request)
5971.5.3 by Celso Providelo
Protoype of new PPA search page.
709
        return self.batchnav.currentBatch()
710
711
    @property
712
    def number_of_registered_ppas(self):
713
        """The number of archives with PPA purpose.
714
715
        It doesn't include private PPAs.
716
        """
717
        return self.context.searchPPAs(show_inactive=True).count()
718
719
    @property
720
    def number_of_active_ppas(self):
721
        """The number of PPAs with at least one source publication.
722
723
        It doesn't include private PPAs.
724
        """
725
        return self.context.searchPPAs(show_inactive=False).count()
726
727
    @property
728
    def number_of_ppa_sources(self):
729
        """The number of sources published across all PPAs."""
7320.2.1 by Celso Providelo
Fixing bug #250001 (sane PPA page for other distributions than ubuntu).
730
        return getUtility(IArchiveSet).getNumberOfPPASourcesForDistribution(
731
            self.context)
5971.5.3 by Celso Providelo
Protoype of new PPA search page.
732
733
    @property
734
    def number_of_ppa_binaries(self):
735
        """The number of binaries published across all PPAs."""
7320.2.1 by Celso Providelo
Fixing bug #250001 (sane PPA page for other distributions than ubuntu).
736
        return getUtility(IArchiveSet).getNumberOfPPABinariesForDistribution(
737
            self.context)
3691.443.66 by Celso Providelo
PPA list page under '+ubuntu' (it's not definitive)
738
6149.1.6 by Celso Providelo
applying review comments, r=sinzui.
739
    @property
740
    def latest_ppa_source_publications(self):
6149.1.1 by Celso Providelo
Fixing bug 221305 (presenting a section in /+ppas listing the last 5 source publications, uploaded or copied). Also supress the information sections in that page when a search is requested, it makes the page cleaner for the user to insped the results.
741
        """Return the last 5 sources publication in the context PPAs."""
742
        archive_set = getUtility(IArchiveSet)
743
        return archive_set.getLatestPPASourcePublicationsForDistribution(
744
            distribution=self.context)
745
6149.1.6 by Celso Providelo
applying review comments, r=sinzui.
746
    @property
747
    def most_active_ppas(self):
6149.1.3 by Celso Providelo
Adding 'Most active' page section in /+ppas page.
748
        """Return the last 5 most active PPAs."""
749
        archive_set = getUtility(IArchiveSet)
750
        return archive_set.getMostActivePPAsForDistribution(
751
            distribution=self.context)
752
3103.1.2 by Bjorn Tillenius
add UI for distribution launchpad usage.
753
9184.3.1 by Barry Warsaw
Convert /distros to UI 3.0
754
class DistributionSetActionNavigationMenu(RegistryCollectionActionMenuBase):
755
    """Action menu for `DistributionSetView`."""
756
757
    usedfor = IDistributionSet
12493.3.6 by Raphaël Badin
Fixed style.
758
    links = [
759
        'register_team', 'register_project', 'register_distribution',
12493.3.1 by rvb
Add the 'Register a distribution' link to the distros page.
760
        'create_account']
9184.3.1 by Barry Warsaw
Convert /distros to UI 3.0
761
762
763
class DistributionSetView(LaunchpadView):
764
    """View for /distros top level collection."""
765
766
    implements(IRegistryCollectionNavigationMenu)
767
768
    page_title = 'Distributions registered in Launchpad'
769
770
    @cachedproperty
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
771
    def count(self):
772
        return self.context.count()
773
774
4005.1.7 by Mark Shuttleworth
Branding works for all pillars
775
class DistributionAddView(LaunchpadFormView):
3691.339.8 by Guilherme Salgado
Use the new image-widget for projects/distributions/sprints
776
777
    schema = IDistribution
9116.5.1 by Curtis Hovey
Updated distribution +add to UI 3.0
778
    label = "Register a new distribution"
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
779
    field_names = [
780
        "name",
781
        "displayname",
782
        "title",
783
        "summary",
784
        "description",
785
        "domainname",
786
        "members",
787
        "official_malone",
11983.4.1 by j.c.sackett
Swapped booleans in distribution with enums in browser for Add and Edit views.
788
        "blueprints_usage",
11551.8.32 by j.c.sackett
Returned config options to the official_bool rather than usage enum. A more comprehensive solution in another branch will be needed to address the problem.
789
        "official_rosetta",
11983.4.1 by j.c.sackett
Swapped booleans in distribution with enums in browser for Add and Edit views.
790
        "answers_usage",
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
791
        ]
3691.339.8 by Guilherme Salgado
Use the new image-widget for projects/distributions/sprints
792
9116.5.1 by Curtis Hovey
Updated distribution +add to UI 3.0
793
    @property
794
    def page_title(self):
795
        """The page title."""
796
        return self.label
797
798
    @property
799
    def cancel_url(self):
800
        """See `LaunchpadFormView`."""
801
        return canonical_url(self.context)
802
3691.339.8 by Guilherme Salgado
Use the new image-widget for projects/distributions/sprints
803
    @action("Save", name='save')
804
    def save_action(self, action, data):
2090 by Canonical.com Patch Queue Manager
[r=SteveA] another round of import fascism and other cleanups
805
        distribution = getUtility(IDistributionSet).new(
806
            name=data['name'],
807
            displayname=data['displayname'],
808
            title=data['title'],
809
            summary=data['summary'],
810
            description=data['description'],
811
            domainname=data['domainname'],
812
            members=data['members'],
3691.339.8 by Guilherme Salgado
Use the new image-widget for projects/distributions/sprints
813
            owner=self.user,
12552.2.1 by Raphaël Badin
Added registrant field to distribution.
814
            registrant=self.user,
4005.1.7 by Mark Shuttleworth
Branding works for all pillars
815
            )
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
816
        notify(ObjectCreatedEvent(distribution))
3691.339.8 by Guilherme Salgado
Use the new image-widget for projects/distributions/sprints
817
        self.next_url = canonical_url(distribution)
1062 by Canonical.com Patch Queue Manager
bazaar renaming and initial soyuz refactoring for distribution, distrorelease
818
2821.2.14 by Brad Bollenbach
add a Distribution.bugcontact and UI for setting it
819
9116.5.3 by Curtis Hovey
Added a RegistryEditForm that provides the common features for Edit forms.
820
class DistributionEditView(RegistryEditFormView):
4697.1.16 by Matthew Paul Thomas
Finishes fixing bug 32104 (+edit and +launchpad should be merged), and fixes bug 132147 (Distribution registrant can change Launchpad usage, but test claims they can't).
821
822
    schema = IDistribution
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
823
    field_names = [
824
        'displayname',
825
        'title',
826
        'summary',
827
        'description',
828
        'bug_reporting_guidelines',
829
        'bug_reported_acknowledgement',
830
        'icon',
831
        'logo',
832
        'mugshot',
833
        'official_malone',
834
        'enable_bug_expiration',
11983.4.1 by j.c.sackett
Swapped booleans in distribution with enums in browser for Add and Edit views.
835
        'blueprints_usage',
11551.8.32 by j.c.sackett
Returned config options to the official_bool rather than usage enum. A more comprehensive solution in another branch will be needed to address the problem.
836
        'official_rosetta',
11983.4.1 by j.c.sackett
Swapped booleans in distribution with enums in browser for Add and Edit views.
837
        'answers_usage',
11227.3.36 by Curtis Hovey
Long lists -> veritical lists.
838
        'translation_focus',
839
        ]
6484.3.1 by Julian Edwards
Merge the distro change branding page into the change details one.
840
841
    custom_widget('icon', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE)
842
    custom_widget('logo', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE)
843
    custom_widget('mugshot', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE)
4697.1.16 by Matthew Paul Thomas
Finishes fixing bug 32104 (+edit and +launchpad should be merged), and fixes bug 132147 (Distribution registrant can change Launchpad usage, but test claims they can't).
844
9116.5.2 by Curtis Hovey
Updated distribution +edit to UI 3.0
845
    @property
846
    def label(self):
847
        """See `LaunchpadFormView`."""
848
        return 'Change %s details' % self.context.displayname
849
5283.1.1 by Curtis Hovey
Restored the enable_bug_expiration UI. The can_expire code needs updating.
850
    def validate(self, data):
851
        """Constrain bug expiration to Launchpad Bugs tracker."""
852
        # enable_bug_expiration is disabled by JavaScript when official_malone
853
        # is set False. The contraint is enforced here in case the JavaScript
854
        # fails to load or activate.
855
        official_malone = data.get('official_malone', False)
856
        if not official_malone:
857
            data['enable_bug_expiration'] = False
4697.1.16 by Matthew Paul Thomas
Finishes fixing bug 32104 (+edit and +launchpad should be merged), and fixes bug 132147 (Distribution registrant can change Launchpad usage, but test claims they can't).
858
859
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
860
class DistributionSeriesBaseView(LaunchpadView):
861
    """A base view to list distroseries."""
9418.2.3 by Curtis Hovey
Converted the distro +series page to UI 3.0. Copied product +series formating.
862
    @cachedproperty
863
    def styled_series(self):
864
        """A list of dicts; keys: series, css_class, is_development_focus"""
865
        all_series = []
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
866
        for series in self._displayed_series:
9418.2.3 by Curtis Hovey
Converted the distro +series page to UI 3.0. Copied product +series formating.
867
            all_series.append({
868
                'series': series,
869
                'css_class': self.getCssClass(series),
870
                })
871
        return all_series
872
873
    def getCssClass(self, series):
12079.2.2 by Curtis Hovey
Removed unhighlighted. Renamed dimmed to lowlight. Removed .series class because
874
        """The highlight, lowlight, or normal CSS class."""
10054.26.1 by Adi Roiban
Refactor DistroSeriesStatus to SeriesStatus; Don't prompt for setting up translations for obsolete product series.
875
        if series.status == SeriesStatus.DEVELOPMENT:
12079.2.2 by Curtis Hovey
Removed unhighlighted. Renamed dimmed to lowlight. Removed .series class because
876
            return 'highlight'
10054.26.1 by Adi Roiban
Refactor DistroSeriesStatus to SeriesStatus; Don't prompt for setting up translations for obsolete product series.
877
        elif series.status == SeriesStatus.OBSOLETE:
12079.2.2 by Curtis Hovey
Removed unhighlighted. Renamed dimmed to lowlight. Removed .series class because
878
            return 'lowlight'
9418.2.3 by Curtis Hovey
Converted the distro +series page to UI 3.0. Copied product +series formating.
879
        else:
12079.2.2 by Curtis Hovey
Removed unhighlighted. Renamed dimmed to lowlight. Removed .series class because
880
            # This is normal presentation.
881
            return ''
9418.2.3 by Curtis Hovey
Converted the distro +series page to UI 3.0. Copied product +series formating.
882
883
12768.2.1 by Raphael Badin
Display derivatives (on distribution and distroseries index pages).
884
class DistributionSeriesView(DistributionSeriesBaseView):
885
    """A view to list the distribution series."""
886
    label = 'Timeline'
887
    show_add_series_link = True
888
    show_milestones_link = True
889
890
    @property
891
    def _displayed_series(self):
892
        return self.context.series
893
894
895
class DistributionDerivativesView(DistributionSeriesBaseView):
896
    """A view to list the distribution derivatives."""
897
    label = 'Derivatives'
898
    show_add_series_link = False
899
    show_milestones_link = False
900
901
    @property
902
    def _displayed_series(self):
903
        return self.context.derivatives
904
905
9116.5.4 by Curtis Hovey
Converted the +selectmirroradmins to UI 3.0
906
class DistributionChangeMirrorAdminView(RegistryEditFormView):
907
    """A view to change the mirror administrator."""
908
    schema = IDistribution
909
    field_names = ['mirror_admin']
910
911
    @property
912
    def label(self):
913
        """See `LaunchpadFormView`."""
9116.5.6 by Curtis Hovey
Updated +selectmemberteam to UI 3.0
914
        return "Change the %s mirror administrator" % self.context.displayname
915
916
917
class DistributionChangeMembersView(RegistryEditFormView):
918
    """A view to change the members team."""
919
    schema = IDistribution
920
    field_names = ['members']
921
922
    @property
923
    def label(self):
924
        """See `LaunchpadFormView`."""
925
        return "Change the %s members team" % self.context.displayname
9116.5.4 by Curtis Hovey
Converted the +selectmirroradmins to UI 3.0
926
927
3691.214.24 by Guilherme Salgado
Implement the new +countrymirrors-archive page, together with some fixes to its underlying bits, new/improved tests and a new argument to the prober script, which causes it to not connect to anything other than localhost
928
class DistributionCountryArchiveMirrorsView(LaunchpadView):
4436.2.5 by Curtis Hovey
Fixed long lines.
929
    """A text/plain page that lists the mirrors in the country of the request.
3691.214.24 by Guilherme Salgado
Implement the new +countrymirrors-archive page, together with some fixes to its underlying bits, new/improved tests and a new argument to the prober script, which causes it to not connect to anything other than localhost
930
931
    If there are no mirrors located in the country of the request, we fallback
932
    to the main Ubuntu repositories.
933
    """
6495.2.3 by Julian Edwards
Add nav menus
934
    implements(IDistributionMirrorMenuMarker)
3691.214.24 by Guilherme Salgado
Implement the new +countrymirrors-archive page, together with some fixes to its underlying bits, new/improved tests and a new argument to the prober script, which causes it to not connect to anything other than localhost
935
936
    def render(self):
5464.2.1 by Guilherme Salgado
Add the IP address and some request headers to the headers of the +countrymirrors page.
937
        request = self.request
3691.214.27 by Guilherme Salgado
A bunch of changes requested by Bjorn
938
        if not self.context.full_functionality:
5464.2.1 by Guilherme Salgado
Add the IP address and some request headers to the headers of the +countrymirrors page.
939
            request.response.setStatus(404)
3691.214.27 by Guilherme Salgado
A bunch of changes requested by Bjorn
940
            return u''
5464.2.1 by Guilherme Salgado
Add the IP address and some request headers to the headers of the +countrymirrors page.
941
        ip_address = ipaddress_from_request(request)
942
        country = request_country(request)
3691.214.24 by Guilherme Salgado
Implement the new +countrymirrors-archive page, together with some fixes to its underlying bits, new/improved tests and a new argument to the prober script, which causes it to not connect to anything other than localhost
943
        mirrors = getUtility(IDistributionMirrorSet).getBestMirrorsForCountry(
944
            country, MirrorContent.ARCHIVE)
945
        body = "\n".join(mirror.base_url for mirror in mirrors)
5464.2.1 by Guilherme Salgado
Add the IP address and some request headers to the headers of the +countrymirrors page.
946
        request.response.setHeader('content-type', 'text/plain;charset=utf-8')
5217.5.1 by Guilherme Salgado
Add an extra header to http://launchpad.net/ubuntu/+countrymirrors-archive showing the country given to us by GeoIP.
947
        if country is None:
948
            country_name = 'Unknown'
949
        else:
950
            country_name = country.name
5464.2.1 by Guilherme Salgado
Add the IP address and some request headers to the headers of the +countrymirrors page.
951
        request.response.setHeader('X-Generated-For-Country', country_name)
952
        request.response.setHeader('X-Generated-For-IP', ip_address)
6916.1.1 by Curtis Hovey
Fixed comment formats to fidn missing persons, dates, and some bugs.
953
        # XXX: Guilherme Salgado 2008-01-09 bug=173729: These are here only
954
        # for debugging.
5464.2.1 by Guilherme Salgado
Add the IP address and some request headers to the headers of the +countrymirrors page.
955
        request.response.setHeader(
956
            'X-REQUEST-HTTP_X_FORWARDED_FOR',
957
            request.get('HTTP_X_FORWARDED_FOR'))
958
        request.response.setHeader(
959
            'X-REQUEST-REMOTE_ADDR', request.get('REMOTE_ADDR'))
3691.214.24 by Guilherme Salgado
Implement the new +countrymirrors-archive page, together with some fixes to its underlying bits, new/improved tests and a new argument to the prober script, which causes it to not connect to anything other than localhost
960
        return body.encode('utf-8')
961
962
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
963
class DistributionMirrorsView(LaunchpadView):
964
6495.2.3 by Julian Edwards
Add nav menus
965
    implements(IDistributionMirrorMenuMarker)
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
966
    show_freshness = True
9389.2.1 by Brad Crittenden
Add mirror type to +pendingreviewmirrors and removed 'freshness'.
967
    show_mirror_type = False
9152.7.4 by Brad Crittenden
checkpoint
968
    description = None
3691.214.40 by Guilherme Salgado
Fix a bunch of trivial mirror prober bugs: 46662, 68395 and 107473
969
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
970
    @cachedproperty
971
    def mirror_count(self):
972
        return self.mirrors.count()
973
974
    def _sum_throughput(self, mirrors):
975
        """Given a list of mirrors, calculate the total bandwidth
976
        available.
977
        """
978
        throughput = 0
979
        # this would be a wonderful place to have abused DBItem.sort_key ;-)
980
        for mirror in mirrors:
981
            if mirror.speed == MirrorSpeed.S128K:
982
                throughput += 128
983
            elif mirror.speed == MirrorSpeed.S256K:
984
                throughput += 256
985
            elif mirror.speed == MirrorSpeed.S512K:
986
                throughput += 512
987
            elif mirror.speed == MirrorSpeed.S1M:
988
                throughput += 1000
989
            elif mirror.speed == MirrorSpeed.S2M:
990
                throughput += 2000
991
            elif mirror.speed == MirrorSpeed.S10M:
992
                throughput += 10000
993
            elif mirror.speed == MirrorSpeed.S45M:
994
                throughput += 45000
995
            elif mirror.speed == MirrorSpeed.S100M:
996
                throughput += 100000
997
            elif mirror.speed == MirrorSpeed.S1G:
998
                throughput += 1000000
999
            elif mirror.speed == MirrorSpeed.S2G:
1000
                throughput += 2000000
1001
            elif mirror.speed == MirrorSpeed.S4G:
1002
                throughput += 4000000
1003
            elif mirror.speed == MirrorSpeed.S10G:
1004
                throughput += 10000000
1005
            elif mirror.speed == MirrorSpeed.S20G:
1006
                throughput += 20000000
1007
            else:
1008
                # need to be made aware of new values in
1009
                # interfaces/distributionmirror.py MirrorSpeed
1010
                return 'Indeterminate'
1011
        if throughput < 1000:
1012
            return str(throughput) + ' Kbps'
1013
        elif throughput < 1000000:
13247.1.1 by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed.
1014
            return str(throughput / 1000) + ' Mbps'
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1015
        else:
13247.1.1 by Danilo Segan
Reapply bug 772754 fix with packagecopyjob changes removed.
1016
            return str(throughput / 1000000) + ' Gbps'
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1017
1018
    @cachedproperty
1019
    def total_throughput(self):
1020
        return self._sum_throughput(self.mirrors)
1021
1022
    def getMirrorsGroupedByCountry(self):
3691.51.27 by Guilherme Salgado
Final tweaks suggested by Bjorn and a new test for distribution pages
1023
        """Given a list of mirrors, create and return list of dictionaries
1024
        containing the country names and the list of mirrors on that country.
1025
1026
        This list is ordered by country name.
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1027
        """
12208.2.5 by j.c.sackett
Updated the getOverallFreshness method to use cachedproperties that are prepopulated when archive mirrors are queried for.
1028
        mirrors_by_country = defaultdict(list)
12192.2.7 by j.c.sackett
Updated mirrors_by_country code per review.
1029
        for mirror in self.mirrors:
12208.2.5 by j.c.sackett
Updated the getOverallFreshness method to use cachedproperties that are prepopulated when archive mirrors are queried for.
1030
            mirrors_by_country[mirror.country.name].append(mirror)
1031
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1032
        return [dict(country=country,
1033
                     mirrors=mirrors,
1034
                     number=len(mirrors),
1035
                     throughput=self._sum_throughput(mirrors))
3691.51.27 by Guilherme Salgado
Final tweaks suggested by Bjorn and a new test for distribution pages
1036
                for country, mirrors in sorted(mirrors_by_country.items())]
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1037
1038
1039
class DistributionArchiveMirrorsView(DistributionMirrorsView):
3525.1.1 by Guilherme Salgado
Make the mirror prober probe release mirrors, improve the UI a lot and lots of other fixes.
1040
3691.51.1 by Guilherme Salgado
Some small UI tweaks on mirror-related pages
1041
    heading = 'Official Archive Mirrors'
9152.7.2 by Brad Crittenden
Convert distribution mirror pages to UI 3.0
1042
    description = ('These mirrors provide repositories and archives of all '
1043
                   'software for the distribution.')
3525.1.1 by Guilherme Salgado
Make the mirror prober probe release mirrors, improve the UI a lot and lots of other fixes.
1044
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1045
    @cachedproperty
1046
    def mirrors(self):
12192.2.4 by j.c.sackett
Added country preloading version of the _mirrors properties.
1047
        return self.context.archive_mirrors_by_country
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1048
12192.2.9 by j.c.sackett
Fixed some mismatches between new code and tests.
1049
    @cachedproperty
1050
    def mirror_count(self):
1051
        return len(self.mirrors)
1052
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1053
4285.2.1 by Mark Shuttleworth
Massive renaming of distrorelease to distroseries
1054
class DistributionSeriesMirrorsView(DistributionMirrorsView):
3525.1.1 by Guilherme Salgado
Make the mirror prober probe release mirrors, improve the UI a lot and lots of other fixes.
1055
3691.51.1 by Guilherme Salgado
Some small UI tweaks on mirror-related pages
1056
    heading = 'Official CD Mirrors'
9152.7.2 by Brad Crittenden
Convert distribution mirror pages to UI 3.0
1057
    description = ('These mirrors offer ISO images which you can download '
1058
                   'and burn to CD to make installation disks.')
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
1059
    show_freshness = False
3525.1.1 by Guilherme Salgado
Make the mirror prober probe release mirrors, improve the UI a lot and lots of other fixes.
1060
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1061
    @cachedproperty
1062
    def mirrors(self):
12192.2.4 by j.c.sackett
Added country preloading version of the _mirrors properties.
1063
        return self.context.cdimage_mirrors_by_country
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1064
12192.2.9 by j.c.sackett
Fixed some mismatches between new code and tests.
1065
    @cachedproperty
1066
    def mirror_count(self):
1067
        return len(self.mirrors)
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1068
12208.2.6 by j.c.sackett
Lint fix.
1069
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1070
class DistributionMirrorsRSSBaseView(LaunchpadView):
1071
    """A base class for RSS feeds of distribution mirrors."""
3691.51.42 by Guilherme Salgado
Fix https://launchpad.net/products/launchpad/+bug/64029 (XML/RSS of cdimage mirror status)
1072
3691.51.46 by Guilherme Salgado
Some fixes as per Bjorn's review
1073
    def initialize(self):
3973.1.19 by Steve Alexander
make milestones dynmenu show only fairly recent milestones
1074
        self.now = datetime.datetime.utcnow()
3691.51.46 by Guilherme Salgado
Some fixes as per Bjorn's review
1075
1076
    def render(self):
1077
        self.request.response.setHeader(
1078
            'content-type', 'text/xml;charset=utf-8')
1079
        body = LaunchpadView.render(self)
1080
        return body.encode('utf-8')
3691.51.42 by Guilherme Salgado
Fix https://launchpad.net/products/launchpad/+bug/64029 (XML/RSS of cdimage mirror status)
1081
1082
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1083
class DistributionArchiveMirrorsRSSView(DistributionMirrorsRSSBaseView):
1084
    """The RSS feed for archive mirrors."""
1085
3691.214.3 by Guilherme Salgado
Trivial changes suggested by kiko
1086
    heading = 'Archive Mirrors'
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1087
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1088
    @cachedproperty
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1089
    def mirrors(self):
1090
        return self.context.archive_mirrors
1091
1092
4285.2.1 by Mark Shuttleworth
Massive renaming of distrorelease to distroseries
1093
class DistributionSeriesMirrorsRSSView(DistributionMirrorsRSSBaseView):
1094
    """The RSS feed for series mirrors."""
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1095
3691.214.3 by Guilherme Salgado
Trivial changes suggested by kiko
1096
    heading = 'CD Mirrors'
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1097
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1098
    @cachedproperty
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1099
    def mirrors(self):
4285.2.2 by Mark Shuttleworth
Fix cases where db code must still refer to the old DistroRelease table name
1100
        return self.context.cdimage_mirrors
3691.214.2 by Guilherme Salgado
Add an rss feed for archive mirrors too
1101
1102
3691.51.24 by Guilherme Salgado
Properly fix [WWW] bug 57507 and make sure release mirrors are disabled if they miss any of the files they should contain.
1103
class DistributionMirrorsAdminView(DistributionMirrorsView):
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
1104
1105
    def initialize(self):
1106
        """Raise an Unauthorized exception if the user is not a member of this
1107
        distribution's mirror_admin team.
1108
        """
4664.1.1 by Curtis Hovey
Normalized comments for bug 3732.
1109
        # XXX: Guilherme Salgado 2006-06-16:
1110
        # We don't want these pages to be public but we can't protect
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
1111
        # them with launchpad.Edit because that would mean only people with
1112
        # that permission on a Distribution would be able to see them. That's
1113
        # why we have to do the permission check here.
1114
        if not (self.user and self.user.inTeam(self.context.mirror_admin)):
1115
            raise Unauthorized('Forbidden')
1116
1117
1118
class DistributionUnofficialMirrorsView(DistributionMirrorsAdminView):
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
1119
3691.51.1 by Guilherme Salgado
Some small UI tweaks on mirror-related pages
1120
    heading = 'Unofficial Mirrors'
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
1121
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1122
    @cachedproperty
1123
    def mirrors(self):
1124
        return self.context.unofficial_mirrors
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
1125
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
1126
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
1127
class DistributionPendingReviewMirrorsView(DistributionMirrorsAdminView):
1128
1129
    heading = 'Pending-review mirrors'
9389.2.1 by Brad Crittenden
Add mirror type to +pendingreviewmirrors and removed 'freshness'.
1130
    show_mirror_type = True
1131
    show_freshness = False
5206.9.1 by Guilherme Salgado
Add a status column to DistributionMirror so that we can track pending-review mirrors. Also rename a few other columns and add an extra page which lists all mirrors that are pending review.
1132
1133
    @cachedproperty
1134
    def mirrors(self):
1135
        return self.context.pending_review_mirrors
1136
1137
3525.1.14 by Guilherme Salgado
Add Distribution.mirror_admin and give them permission to see the lists of unofficial/disabled mirrors and mark the ones that should be official
1138
class DistributionDisabledMirrorsView(DistributionMirrorsAdminView):
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
1139
3691.51.1 by Guilherme Salgado
Some small UI tweaks on mirror-related pages
1140
    heading = 'Disabled Mirrors'
3525.1.5 by Guilherme Salgado
Loads of changes to summarize the arch/source releases that a mirror contains and to display the releases/flavours that a release mirror contains.
1141
5084.10.3 by Mark Shuttleworth
Show number of mirrors per country and in total
1142
    @cachedproperty
1143
    def mirrors(self):
1144
        return self.context.disabled_mirrors
7675.1063.1 by Julian Edwards
basic implementation of +pubconf page, sans tests. So sue me for not doing TDD, I don't care.
1145
1146
12552.2.9 by Raphaël Badin
Fixed reassign page display. Added tests.
1147
class DistributionReassignmentView(ObjectReassignmentView):
1148
    """View class for changing distribution maintainer."""
1149
    ownerOrMaintainerName = 'maintainer'
7675.1066.2 by Raphael Badin
Merged db-devel.
1150
1151
7675.1063.2 by Julian Edwards
s/DistributionPublisherConfig/DistributionPublisherConfigView/
1152
class DistributionPublisherConfigView(LaunchpadFormView):
7675.1063.1 by Julian Edwards
basic implementation of +pubconf page, sans tests. So sue me for not doing TDD, I don't care.
1153
    """View class for configuring publisher options for a DistroSeries.
1154
1155
    It redirects to the main distroseries page after a successful edit.
1156
    """
1157
    schema = IPublisherConfig
1158
    field_names = ['root_dir', 'base_url', 'copy_base_url']
1159
1160
    @property
1161
    def label(self):
1162
        """See `LaunchpadFormView`."""
1163
        return 'Publisher configuration for %s' % self.context.title
1164
1165
    @property
1166
    def page_title(self):
1167
        """The page title."""
1168
        return self.label
1169
1170
    @property
1171
    def cancel_url(self):
1172
        """See `LaunchpadFormView`."""
1173
        return canonical_url(self.context)
1174
1175
    @property
1176
    def initial_values(self):
1177
        """If the config already exists, set up the fields with data."""
1178
        config = getUtility(
1179
            IPublisherConfigSet).getByDistribution(self.context)
1180
        values = {}
1181
        if config is not None:
1182
            for name in self.field_names:
1183
                values[name] = getattr(config, name)
7675.1063.8 by Julian Edwards
fix lint
1184
7675.1063.1 by Julian Edwards
basic implementation of +pubconf page, sans tests. So sue me for not doing TDD, I don't care.
1185
        return values
1186
1187
    @action("Save")
1188
    def save_action(self, action, data):
1189
        """Update the context and redirect to its overview page."""
1190
        config = getUtility(IPublisherConfigSet).getByDistribution(
1191
            self.context)
1192
        if config is None:
1193
            config = getUtility(IPublisherConfigSet).new(
1194
                distribution=self.context,
7675.1063.3 by Julian Edwards
bunch o' tests
1195
                root_dir=data['root_dir'],
1196
                base_url=data['base_url'],
1197
                copy_base_url=data['copy_base_url'])
7675.1063.1 by Julian Edwards
basic implementation of +pubconf page, sans tests. So sue me for not doing TDD, I don't care.
1198
        else:
1199
            form.applyChanges(config, self.form_fields, data, self.adapters)
1200
1201
        self.request.response.addInfoNotification(
1202
            'Your changes have been applied.')
1203
        self.next_url = canonical_url(self.context)