~launchpad-pqm/launchpad/devel

8687.15.18 by Karl Fogel
Add the copyright header block to files under lib/canonical/.
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4789.5.2 by Tim Penhey
New work on badge handling.
3
4
"""Badges are shown to indicate either content state or links.
5
6
Badges are shown in two main places:
7
 * listing views
8
 * main content pages.
9
"""
10
11
__metaclass__ = type
12
__all__ = [
13
    'Badge',
14
    'HasBadgeBase',
15
    'IHasBadges',
16
    'STANDARD_BADGES',
17
    ]
18
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
19
from zope.interface import (
20
    implements,
21
    Interface,
22
    )
23
5474.3.10 by Edwin Grubbs
Working display using HasBadgeBase
24
from canonical.lazr.interfaces import IObjectPrivacy
4789.5.2 by Tim Penhey
New work on badge handling.
25
26
27
class Badge:
4789.5.11 by Tim Penhey
Updates following review.
28
    """A is badge is used to represent a link between two objects.
29
30
    This link is then rendered as small icons on the object listing
31
    views, and as larger images on the object content pages.
32
    """
33
34
    def __init__(self, icon_image=None, heading_image=None,
35
                 alt='', title='', id=''):
36
        self.small_image = icon_image
37
        self.large_image = heading_image
4789.5.2 by Tim Penhey
New work on badge handling.
38
        self.alt = alt
39
        self.title = title
4789.5.10 by Tim Penhey
Added (optional) id attribute to large badges to ease testing pages.
40
        self.id = id
4789.5.2 by Tim Penhey
New work on badge handling.
41
5474.3.10 by Edwin Grubbs
Working display using HasBadgeBase
42
    def copy(self):
43
        return Badge(self.small_image, self.large_image, self.alt,
44
                     self.title, self.id)
45
4789.5.11 by Tim Penhey
Updates following review.
46
    def renderIconImage(self):
4789.5.8 by Tim Penhey
Add missing docstrings to Badge.
47
        """Render the small image as an HTML img tag."""
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
48
        if self.small_image:
49
            return ('<img alt="%s" width="14" height="14" src="%s"'
5474.3.17 by Edwin Grubbs
Fixed lint errors
50
                    ' title="%s"/>'
51
                    % (self.alt, self.small_image, self.title))
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
52
        else:
53
            return ''
4789.5.2 by Tim Penhey
New work on badge handling.
54
4789.5.11 by Tim Penhey
Updates following review.
55
    def renderHeadingImage(self):
4789.5.8 by Tim Penhey
Add missing docstrings to Badge.
56
        """Render the large image as an HTML img tag."""
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
57
        if self.large_image:
4789.5.10 by Tim Penhey
Added (optional) id attribute to large badges to ease testing pages.
58
            if self.id:
59
                id_attribute = 'id="%s"' % self.id
60
            else:
61
                id_attribute = ''
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
62
            return ('<img alt="%s" width="32" height="32" src="%s"'
4789.5.10 by Tim Penhey
Added (optional) id attribute to large badges to ease testing pages.
63
                    ' title="%s" %s/>' % (
64
                    self.alt, self.large_image, self.title, id_attribute))
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
65
        else:
66
            return ''
4789.5.2 by Tim Penhey
New work on badge handling.
67
68
69
STANDARD_BADGES = {
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
70
    'bug': Badge('/@@/bug', '/@@/bug-large',
4789.5.10 by Tim Penhey
Added (optional) id attribute to large badges to ease testing pages.
71
                 'bug', 'Linked to a bug', 'bugbadge'),
4789.5.11 by Tim Penhey
Updates following review.
72
    'blueprint': Badge('/@@/blueprint', None,
5474.3.13 by Edwin Grubbs
Bugs now using HasBadgeBase. Fixed tests.
73
                       '(Linked to a blueprint)', 'Linked to a blueprint'),
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
74
    'branch': Badge('/@@/branch', '/@@/branch-large',
5474.3.17 by Edwin Grubbs
Fixed lint errors
75
                    '(Linked to a branch)', 'Linked to a branch',
76
                    'branchbadge'),
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
77
    'private': Badge('/@@/private', '/@@/private-large',
5474.3.13 by Edwin Grubbs
Bugs now using HasBadgeBase. Fixed tests.
78
                     '(Private)', 'Private', 'privatebadge'),
79
    'security': Badge('/@@/security', '/@@/security-large',
80
                      '(Security vulnerability)', 'Security vulnerability',
81
                      'securitybadge'),
7637.4.6 by Tim Penhey
Make sure that the base class implements the correct visibility method too.
82
    'mergeproposal': Badge('/@@/merge-proposal-icon',
83
                           '/@@/merge-proposal-large',
84
                           '(Has a merge proposal)', 'Has a merge proposal',
85
                           'mpbadge'),
10189.4.1 by Tom Berger
interim commit, so that i can merge in another branch
86
    'patch': Badge(None, None, '(Has a patch)', 'Has a patch', 'haspatch'),
4789.5.2 by Tim Penhey
New work on badge handling.
87
    }
88
89
90
class IHasBadges(Interface):
4789.5.15 by Tim Penhey
More updates following review comments.
91
    """A method to determine visible badges.
92
93
    Badges are used to show connections between different content objects, for
94
    example a BugBranch is a link between a bug and a branch.  To represent
95
    this link a bug has a branch badge, and the branch has a bug badge.
4789.5.2 by Tim Penhey
New work on badge handling.
96
4789.5.11 by Tim Penhey
Updates following review.
97
    Badges should honour the visibility of the linked objects.
98
    """
4789.5.2 by Tim Penhey
New work on badge handling.
99
5474.3.20 by Edwin Grubbs
Ignore pylint error
100
    # A zope interface doesn't have self as a parameter for its methods.
101
    # pylint: disable-msg=E0211
4789.5.3 by Tim Penhey
Moved ObjectReassignmentView to avoid circular imports.
102
    def getVisibleBadges():
5474.3.17 by Edwin Grubbs
Fixed lint errors
103
        """Return a list of `Badge` objects that the logged in user can see.
104
        """
4789.5.2 by Tim Penhey
New work on badge handling.
105
106
107
class HasBadgeBase:
4789.5.11 by Tim Penhey
Updates following review.
108
    """The standard base implementation for badge visibility.
109
4789.5.15 by Tim Penhey
More updates following review comments.
110
    Derived classes need to provide a sequence of badge names that
111
    could be visible available through the attribute `badges`.
112
113
    The visibility of these badges are checked by calling a method like
114
    `isFooBadgeVisible` where Foo is the capitalised name of the badge.
4789.5.11 by Tim Penhey
Updates following review.
115
    """
4789.5.2 by Tim Penhey
New work on badge handling.
116
    implements(IHasBadges)
117
5474.3.10 by Edwin Grubbs
Working display using HasBadgeBase
118
    # All private objects should show the private badge.
5474.3.21 by Edwin Grubbs
Fixed issues raised in the review
119
    badges = ('private',)
5474.3.10 by Edwin Grubbs
Working display using HasBadgeBase
120
121
    # This class is now a default adapter for IHasBadges.
122
    def __init__(self, context):
123
        self.context = context
124
125
    def isPrivateBadgeVisible(self):
126
        # Show a privacy badge.
127
        return IObjectPrivacy(self.context).is_private
4789.5.11 by Tim Penhey
Updates following review.
128
4789.5.3 by Tim Penhey
Moved ObjectReassignmentView to avoid circular imports.
129
    def getVisibleBadges(self):
4789.5.2 by Tim Penhey
New work on badge handling.
130
        """See `IHasBadges`."""
131
        result = []
132
        for badge_name in self.badges:
4789.5.11 by Tim Penhey
Updates following review.
133
            if self._isBadgeVisible(badge_name):
4789.5.5 by Tim Penhey
Badge doctest working appropriately now.
134
                badge = self.getBadge(badge_name)
135
                if badge:
136
                    result.append(badge)
4789.5.2 by Tim Penhey
New work on badge handling.
137
        return result
138
4789.5.11 by Tim Penhey
Updates following review.
139
    def _isBadgeVisible(self, badge_name):
140
        """Is the badge_name badge visible for the logged in user?
141
142
        Delegate the determination to a method based on the name
143
        of the badge.
144
        """
4789.5.3 by Tim Penhey
Moved ObjectReassignmentView to avoid circular imports.
145
        method_name = "is%sBadgeVisible" % badge_name.capitalize()
5474.3.23 by Edwin Grubbs
HasBadgeBase now raises AttributeError instead of NotImplementedError
146
        method = getattr(self, method_name)
147
        return method()
4789.5.11 by Tim Penhey
Updates following review.
148
5474.3.10 by Edwin Grubbs
Working display using HasBadgeBase
149
    def _getBadgeTitle(self, badge_name):
150
        """Does the badge_name badge have a custom title?
151
152
        Delegate the determination to a method based on the name
153
        of the badge.
154
        """
155
        method_name = "get%sBadgeTitle" % badge_name.capitalize()
156
        if hasattr(self, method_name):
157
            return getattr(self, method_name)()
158
        else:
159
            return None
160
4789.5.11 by Tim Penhey
Updates following review.
161
    def getBadge(self, badge_name):
162
        """Return the badge instance for the name specified."""
163
        # Can be overridden to provide non-standard badges.
5474.3.10 by Edwin Grubbs
Working display using HasBadgeBase
164
        badge = STANDARD_BADGES.get(badge_name)
165
        badge_title = self._getBadgeTitle(badge_name)
166
        if badge_title is not None:
167
            badge = badge.copy()
168
            badge.title = badge_title
169
        return badge