~launchpad-pqm/launchpad/devel

8687.15.17 by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/.
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
2068 by Canonical.com Patch Queue Manager
[r=SteveA/trivial] import fascism, kill translationeffort, kill sshkey browser code, add __all__s to interfaces, other cleanings-up
3
4
"""View support classes for the bazaar application."""
5
1862 by Canonical.com Patch Queue Manager
bunch more [trivial] cleanup of stuff from canonical/thing putting stuff in better places.
6
__metaclass__ = type
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
7
3754.3.12 by Tim Penhey
moving pages around
8
__all__ = [
9
    'BazaarApplicationView',
10
    'BazaarProductView',
11
    ]
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
12
3754.3.15 by Tim Penhey
Reworked following extensive review, added batching, reorganised the query code
13
from datetime import datetime
3412.1.15 by David Allouche
factor out and document Branch.sort_key
14
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
15
import bzrlib
1677 by Canonical.com Patch Queue Manager
fixes for baz import pages
16
from zope.component import getUtility
3754.3.12 by Tim Penhey
moving pages around
17
4619.1.10 by Tim Penhey
Updates following review
18
from canonical.config import config
14600.2.2 by Curtis Hovey
Moved webapp to lp.services.
19
from lp.services.webapp import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
20
    canonical_url,
21
    LaunchpadView,
22
    )
14600.2.2 by Curtis Hovey
Moved webapp to lp.services.
23
from lp.services.webapp.authorization import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
24
    precache_permission_for_objects,
25
    )
10454.7.4 by James Westby
Use search instead of getActiveImports on the main page.
26
from lp.code.enums import CodeImportReviewStatus
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
27
from lp.code.interfaces.branch import (
28
    IBranchCloud,
29
    IBranchSet,
30
    )
8138.1.2 by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing.
31
from lp.code.interfaces.branchcollection import IAllBranches
32
from lp.code.interfaces.codeimport import ICodeImportSet
8537.4.2 by Tim Penhey
Add a test to confirm the precaching of the permissions.
33
from lp.registry.interfaces.product import IProductSet
11382.6.34 by Gavin Panella
Reformat imports in all files touched so far.
34
from lp.services.propertycache import cachedproperty
1102 by Canonical.com Patch Queue Manager
Lucille had some XXXs which should have been NOTEs
35
1862 by Canonical.com Patch Queue Manager
bunch more [trivial] cleanup of stuff from canonical/thing putting stuff in better places.
36
4190.5.8 by Tim Penhey
Making sure that the branch listings are appropriately filtered on the different pages. Some of these changes required some tinkering.
37
class BazaarApplicationView(LaunchpadView):
1677 by Canonical.com Patch Queue Manager
fixes for baz import pages
38
14433.2.38 by Curtis Hovey
Moved page_title into view.
39
    page_title = 'Launchpad Branches'
40
5763.4.2 by Tim Penhey
Initial work.
41
    @property
3754.2.2 by Tim Penhey
Added extract_text for pagetests
42
    def branch_count(self):
8028.1.2 by Jonathan Lange
Remove IBranchSet.count, change IAllBranches.count invocations to count
43
        """Return the number of public branches."""
44
        return getUtility(IAllBranches).visibleByUser(None).count()
3311.1.5 by Mark Shuttleworth
Tighten up branch listings
45
5763.4.2 by Tim Penhey
Initial work.
46
    @property
3754.2.4 by Tim Penhey
Getting the products that have branches
47
    def product_count(self):
48
        return getUtility(IProductSet).getProductsWithBranches().count()
49
5763.4.2 by Tim Penhey
Initial work.
50
    @property
1677 by Canonical.com Patch Queue Manager
fixes for baz import pages
51
    def import_count(self):
10454.7.4 by James Westby
Use search instead of getActiveImports on the main page.
52
        return getUtility(ICodeImportSet).search(
53
            review_status=CodeImportReviewStatus.REVIEWED).count()
1677 by Canonical.com Patch Queue Manager
fixes for baz import pages
54
5223.5.3 by jml at canonical
Several small refinements.
55
    @property
5223.5.2 by jml at canonical
Show the Bazaar version in the code homepage.
56
    def bzr_version(self):
57
        return bzrlib.__version__
58
8537.4.1 by Tim Penhey
Precache the launchpad.View on the branches shown.
59
    def _precacheViewPermissions(self, branches):
60
        """Precache the launchpad.View permissions on the branches."""
61
        # XXX: TimPenhey 2009-06-08 bug=324546
62
        # Until there is an API to do this nicely, shove the launchpad.view
63
        # permission into the request cache directly.
8537.4.4 by Tim Penhey
Remove the special precaching code in the branch browser classes.
64
        precache_permission_for_objects(
65
            self.request, 'launchpad.View', branches)
8537.4.1 by Tim Penhey
Precache the launchpad.View on the branches shown.
66
        return branches
67
5223.5.2 by jml at canonical
Show the Bazaar version in the code homepage.
68
    @cachedproperty
3768.1.6 by Tim Penhey
using cached properties of listified objects instead of query objects
69
    def recently_changed_branches(self):
3754.2.3 by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page
70
        """Return the five most recently changed branches."""
8537.4.1 by Tim Penhey
Precache the launchpad.View on the branches shown.
71
        return self._precacheViewPermissions(
72
            list(getUtility(IBranchSet).getRecentlyChangedBranches(
73
                    5, visible_by_user=self.user)))
3754.2.3 by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page
74
3768.1.6 by Tim Penhey
using cached properties of listified objects instead of query objects
75
    @cachedproperty
76
    def recently_imported_branches(self):
3754.2.3 by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page
77
        """Return the five most recently imported branches."""
8537.4.1 by Tim Penhey
Precache the launchpad.View on the branches shown.
78
        return self._precacheViewPermissions(
79
            list(getUtility(IBranchSet).getRecentlyImportedBranches(
80
                    5, visible_by_user=self.user)))
3754.2.3 by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page
81
3768.1.6 by Tim Penhey
using cached properties of listified objects instead of query objects
82
    @cachedproperty
83
    def recently_registered_branches(self):
3754.2.3 by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page
84
        """Return the five most recently registered branches."""
8537.4.1 by Tim Penhey
Precache the launchpad.View on the branches shown.
85
        return self._precacheViewPermissions(
86
            list(getUtility(IBranchSet).getRecentlyRegisteredBranches(
87
                    5, visible_by_user=self.user)))
4619.1.1 by Tim Penhey
Project cloud preview, and more... for code front page listings.
88
89
    @cachedproperty
90
    def short_product_tag_cloud(self):
91
        """Show a preview of the product tag cloud."""
13303.11.10 by Aaron Bentley
Fix pages broken by assuming LaunchpadView.
92
        return BazaarProductView(None, None).products(
4619.1.10 by Tim Penhey
Updates following review
93
            num_products=config.launchpad.code_homepage_product_cloud_size)
3754.2.3 by Tim Penhey
added IBranchSet methods to populate code.launchpad.net page
94
2622 by Canonical.com Patch Queue Manager
[trivial] remove all uses of browser:suburl and nuke the suburl directive code.
95
3851.4.1 by Tim Penhey
changes to products with code page
96
class ProductInfo:
4190.5.8 by Tim Penhey
Making sure that the branch listings are appropriately filtered on the different pages. Some of these changes required some tinkering.
97
11435.5.3 by Tim Penhey
Make the view work better.
98
    def __init__(self, name, commits, author_count, size, elapsed):
99
        self.name = name
100
        self.url = '/' + name
101
        self.commits = commits
102
        self.author_count = author_count
103
        self.size = size
3851.4.1 by Tim Penhey
changes to products with code page
104
        self.elapsed_since_commit = elapsed
105
7703.6.5 by Jonathan Lange
Move a lot of text around.
106
    @property
11435.5.3 by Tim Penhey
Make the view work better.
107
    def tag_class(self):
108
        return "cloud-size-%s" % self.size
7703.6.5 by Jonathan Lange
Move a lot of text around.
109
110
    @property
111
    def time_darkness(self):
112
        if self.elapsed_since_commit is None:
113
            return "light"
114
        if self.elapsed_since_commit.days < 7:
115
            return "dark"
11435.5.3 by Tim Penhey
Make the view work better.
116
        if self.elapsed_since_commit.days < 14:
7703.6.5 by Jonathan Lange
Move a lot of text around.
117
            return "medium"
118
        return "light"
119
120
    @property
121
    def html_class(self):
11435.5.3 by Tim Penhey
Make the view work better.
122
        return "%s cloud-%s" % (self.tag_class, self.time_darkness)
7703.6.5 by Jonathan Lange
Move a lot of text around.
123
124
    @property
125
    def html_title(self):
11435.5.3 by Tim Penhey
Make the view work better.
126
        if self.commits == 1:
127
            size = "1 commit"
128
        else:
129
            size = "%d commits" % self.commits
130
        if self.author_count == 1:
131
            who = "1 person"
132
        else:
133
            who = "%s people" % self.author_count
134
        if self.elapsed_since_commit.days == 0:
7703.6.5 by Jonathan Lange
Move a lot of text around.
135
            commit = "last commit less than a day old"
136
        elif self.elapsed_since_commit.days == 1:
137
            commit = "last commit one day old"
138
        else:
139
            commit = (
140
                "last commit %d days old" % self.elapsed_since_commit.days)
11435.5.3 by Tim Penhey
Make the view work better.
141
        return "%s by %s, %s" % (size, who, commit)
7703.6.5 by Jonathan Lange
Move a lot of text around.
142
143
9129.5.3 by Tim Penhey
Make the main page use the new view.
144
class BazaarProjectsRedirect(LaunchpadView):
145
    """Redirect the user to /projects on the code rootsite."""
146
147
    def initialize(self):
148
        # Redirect to the caller to the new location.
149
        product_set = getUtility(IProductSet)
150
        redirect_url = canonical_url(product_set, rootsite="code")
151
        # Moved permanently.
152
        self.request.response.redirect(redirect_url, status=301)
153
154
13303.11.10 by Aaron Bentley
Fix pages broken by assuming LaunchpadView.
155
class BazaarProductView(LaunchpadView):
7703.6.5 by Jonathan Lange
Move a lot of text around.
156
    """Browser class for products gettable with Bazaar."""
157
14433.2.34 by Curtis Hovey
Moved page_title into view.
158
    page_title = 'Projects with active branches'
159
7779.2.3 by Jonathan Lange
Increase the granularity of the branch tag cloud font size
160
    def _make_distribution_map(self, values, percentile_map):
161
        """Given some values and a map of percentiles to other values, return
162
        a function that will take a value in the same domain as 'values' and
163
        map it to a value in the 'percentile_map' dict.
164
7779.2.5 by Jonathan Lange
Lay off the crack, Haskell boy!
165
        There *must* be a percentile_map entry for 1.0.
7779.2.3 by Jonathan Lange
Increase the granularity of the branch tag cloud font size
166
        """
7779.2.5 by Jonathan Lange
Lay off the crack, Haskell boy!
167
        def constrained_minimum(xs, a):
168
            """Return the smallest value of 'xs' strictly bigger than 'a'."""
169
            return min(x for x in xs if x > a)
170
171
        cutoffs = percentile_map.keys()
172
        num_values = float(len(values))
173
        value_to_cutoffs = {}
174
        for index, value in enumerate(values):
175
            cutoff = constrained_minimum(cutoffs, (index / num_values))
176
            value_to_cutoffs[value] = percentile_map[cutoff]
177
        if num_values > 0 and 1 in percentile_map:
178
            value_to_cutoffs[values[-1]] = percentile_map[1]
179
        return value_to_cutoffs
7779.2.2 by Jonathan Lange
Extract a more general concept out of the way we select branch size.
180
7703.6.5 by Jonathan Lange
Move a lot of text around.
181
    def products(self, num_products=None):
8225.2.2 by Tim Penhey
Add a comment to say that the results are still sorted.
182
        # The product_info ends up sorted on product name, as the product name
183
        # is the first item of the tuple returned, and is guaranteed to be
184
        # unique by the sql query.
7703.6.3 by Jonathan Lange
Change the way we fetch the tag data so that:
185
        product_info = sorted(
11435.5.9 by Tim Penhey
Remove the unnecessary listification.
186
            getUtility(IBranchCloud).getProductsWithInfo(num_products))
11435.5.3 by Tim Penhey
Make the view work better.
187
        if len(product_info) == 0:
188
            return
7703.6.3 by Jonathan Lange
Change the way we fetch the tag data so that:
189
        now = datetime.today()
190
        counts = sorted(zip(*product_info)[1])
7779.2.3 by Jonathan Lange
Increase the granularity of the branch tag cloud font size
191
        size_mapping = {
192
            0.2: 'smallest',
193
            0.4: 'small',
194
            0.6: 'medium',
195
            0.8: 'large',
196
            1.0: 'largest',
197
            }
11435.5.3 by Tim Penhey
Make the view work better.
198
        num_commits_to_size = self._make_distribution_map(
7779.2.3 by Jonathan Lange
Increase the granularity of the branch tag cloud font size
199
            counts, size_mapping)
200
11435.5.3 by Tim Penhey
Make the view work better.
201
        for name, commits, author_count, last_revision_date in product_info:
202
            size = num_commits_to_size[commits]
7703.6.3 by Jonathan Lange
Change the way we fetch the tag data so that:
203
            elapsed = now - last_revision_date
11435.5.3 by Tim Penhey
Make the view work better.
204
            yield ProductInfo(name, commits, author_count, size, elapsed)