1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Common views for objects that implement `IPillar`."""
__metaclass__ = type
__all__ = [
'InvolvedMenu',
'PillarView',
'PillarBugsMenu',
]
from operator import attrgetter
from zope.interface import (
implements,
Interface,
)
from canonical.launchpad.webapp.menu import (
ApplicationMenu,
enabled_with_permission,
Link,
NavigationMenu,
)
from canonical.launchpad.webapp.publisher import (
LaunchpadView,
nearest,
)
from lp.app.browser.tales import MenuAPI
from lp.app.enums import (
service_uses_launchpad,
ServiceUsage,
)
from lp.app.interfaces.launchpad import IServiceUsage
from lp.bugs.browser.structuralsubscription import (
StructuralSubscriptionMenuMixin,
)
from lp.registry.interfaces.distributionsourcepackage import (
IDistributionSourcePackage,
)
from lp.registry.interfaces.distroseries import IDistroSeries
from lp.registry.interfaces.pillar import IPillar
from lp.registry.interfaces.projectgroup import IProjectGroup
from lp.services.propertycache import cachedproperty
class IInvolved(Interface):
"""A marker interface for getting involved."""
class InvolvedMenu(NavigationMenu):
"""The get involved menu."""
usedfor = IInvolved
links = [
'report_bug', 'ask_question', 'help_translate', 'submit_code',
'register_blueprint']
@property
def pillar(self):
return self.context
def report_bug(self):
return Link(
'+filebug', 'Report a bug', site='bugs', icon='bugs',
enabled=self.pillar.official_malone)
def ask_question(self):
return Link(
'+addquestion', 'Ask a question', site='answers', icon='answers',
enabled=service_uses_launchpad(self.pillar.answers_usage))
def help_translate(self):
return Link(
'', 'Help translate', site='translations', icon='translations',
enabled=service_uses_launchpad(self.pillar.translations_usage))
def submit_code(self):
if self.pillar.codehosting_usage in [
ServiceUsage.LAUNCHPAD,
ServiceUsage.EXTERNAL,
]:
enabled = True
else:
enabled = False
return Link(
'+addbranch', 'Submit code', site='code', icon='code',
enabled=enabled)
def register_blueprint(self):
return Link(
'+addspec',
'Register a blueprint',
site='blueprints',
icon='blueprints',
enabled=service_uses_launchpad(self.pillar.blueprints_usage))
class PillarView(LaunchpadView):
"""A view for any `IPillar`."""
implements(IInvolved)
configuration_links = []
visible_disabled_link_names = []
def __init__(self, context, request):
super(PillarView, self).__init__(context, request)
self.official_malone = False
self.answers_usage = ServiceUsage.UNKNOWN
self.blueprints_usage = ServiceUsage.UNKNOWN
self.translations_usage = ServiceUsage.UNKNOWN
self.codehosting_usage = ServiceUsage.UNKNOWN
pillar = nearest(self.context, IPillar)
self._set_official_launchpad(pillar)
if IDistroSeries.providedBy(self.context):
distribution = self.context.distribution
self.codehosting_usage = distribution.codehosting_usage
self.answers_usage = ServiceUsage.NOT_APPLICABLE
elif IDistributionSourcePackage.providedBy(self.context):
self.blueprints_usage = ServiceUsage.UNKNOWN
self.translations_usage = ServiceUsage.UNKNOWN
elif IProjectGroup.providedBy(pillar):
# XXX: 2010-10-07 EdwinGrubbs bug=656292
# Fix _set_official_launchpad().
# Project groups do not support submit code, override the
# default.
self.codehosting_usage = ServiceUsage.NOT_APPLICABLE
else:
# The context is used by all apps.
pass
def _set_official_launchpad(self, pillar):
"""Does the pillar officially use launchpad."""
# XXX: 2010-10-07 EdwinGrubbs bug=656292
# Fix _set_official_launchpad().
# This if structure is required because it may be called many
# times to build the complete set of official applications.
if service_uses_launchpad(IServiceUsage(pillar).bug_tracking_usage):
self.official_malone = True
if service_uses_launchpad(IServiceUsage(pillar).answers_usage):
self.answers_usage = ServiceUsage.LAUNCHPAD
if service_uses_launchpad(IServiceUsage(pillar).blueprints_usage):
self.blueprints_usage = ServiceUsage.LAUNCHPAD
if service_uses_launchpad(pillar.translations_usage):
self.translations_usage = ServiceUsage.LAUNCHPAD
if service_uses_launchpad(IServiceUsage(pillar).codehosting_usage):
self.codehosting_usage = ServiceUsage.LAUNCHPAD
@property
def has_involvement(self):
"""This `IPillar` uses Launchpad."""
return (self.official_malone
or service_uses_launchpad(self.answers_usage)
or service_uses_launchpad(self.blueprints_usage)
or service_uses_launchpad(self.translations_usage)
or service_uses_launchpad(self.codehosting_usage))
@property
def enabled_links(self):
"""The enabled involvement links."""
menuapi = MenuAPI(self)
return sorted([
link for link in menuapi.navigation.values() if link.enabled],
key=attrgetter('sort_key'))
@cachedproperty
def visible_disabled_links(self):
"""Important disabled links.
These are displayed to notify the user to provide configuration
info to enable the links.
Override the visible_disabled_link_names attribute to change
the results.
"""
involved_menu = MenuAPI(self).navigation
important_links = [
involved_menu[name]
for name in self.visible_disabled_link_names]
return sorted([
link for link in important_links if not link.enabled],
key=attrgetter('sort_key'))
@property
def registration_completeness(self):
"""The percent complete for registration.
Not used by all pillars.
"""
return None
class PillarBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
"""Base class for pillar bugs menus."""
facet = 'bugs'
configurable_bugtracker = False
@enabled_with_permission('launchpad.Edit')
def bugsupervisor(self):
text = 'Change bug supervisor'
return Link('+bugsupervisor', text, icon='edit')
def cve(self):
text = 'CVE reports'
return Link('+cve', text, icon='cve')
def filebug(self):
text = 'Report a bug'
return Link('+filebug', text, icon='bug')
@enabled_with_permission('launchpad.Edit')
def securitycontact(self):
text = 'Change security contact'
return Link('+securitycontact', text, icon='edit')
|