1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Browser views for DistroSeriesDifferences."""
__metaclass__ = type
__all__ = [
'CommentXHTMLRepresentation',
'DistroSeriesDifferenceView',
]
from lazr.restful.interfaces import IWebServiceClientRequest
from z3c.ptcompat import ViewPageTemplateFile
from zope.app.form.browser.itemswidgets import RadioWidget
from zope.component import (
adapts,
getUtility,
)
from zope.interface import (
implements,
Interface,
)
from zope.schema import Choice
from zope.schema.vocabulary import (
SimpleTerm,
SimpleVocabulary,
)
from lp.app.browser.launchpadform import LaunchpadFormView
from lp.registry.enum import (
DistroSeriesDifferenceStatus,
DistroSeriesDifferenceType,
)
from lp.registry.interfaces.distroseriesdifference import (
IDistroSeriesDifference,
)
from lp.registry.interfaces.distroseriesdifferencecomment import (
IDistroSeriesDifferenceComment,
IDistroSeriesDifferenceCommentSource,
)
from lp.registry.model.distroseriesdifferencecomment import (
DistroSeriesDifferenceComment,
)
from lp.services.comments.interfaces.conversation import (
IComment,
IConversation,
)
from lp.services.propertycache import cachedproperty
from lp.services.webapp import (
LaunchpadView,
Navigation,
stepthrough,
)
from lp.services.webapp.authorization import check_permission
from lp.app.browser.launchpadform import custom_widget
class DistroSeriesDifferenceNavigation(Navigation):
usedfor = IDistroSeriesDifference
@stepthrough('comments')
def traverse_comment(self, id_str):
try:
id = int(id_str)
except ValueError:
return None
return getUtility(
IDistroSeriesDifferenceCommentSource).getForDifference(
self.context, id)
@property
def parent_packagesets_names(self):
"""Return the formatted list of packagesets for the related
sourcepackagename in the parent.
"""
return self._formatPackageSets(self.context.parent_packagesets)
@property
def packagesets_names(self):
"""Return the formatted list of packagesets for the related
sourcepackagename in the derived series.
"""
return self._formatPackageSets(self.context.packagesets)
def _formatPackageSets(self, packagesets):
"""Format a list of packagesets to display in the UI."""
if packagesets is not None:
return ', '.join([packageset.name for packageset in packagesets])
else:
return None
class IDistroSeriesDifferenceForm(Interface):
"""An interface used in the browser only for displaying form elements."""
blacklist_options = Choice(vocabulary=SimpleVocabulary((
SimpleTerm('NONE', 'NONE', 'No'),
SimpleTerm(
DistroSeriesDifferenceStatus.BLACKLISTED_ALWAYS,
DistroSeriesDifferenceStatus.BLACKLISTED_ALWAYS.name,
'All versions'),
SimpleTerm(
DistroSeriesDifferenceStatus.BLACKLISTED_CURRENT,
DistroSeriesDifferenceStatus.BLACKLISTED_CURRENT.name,
'These versions'),
)))
class DistroSeriesDifferenceView(LaunchpadFormView):
implements(IConversation)
schema = IDistroSeriesDifferenceForm
custom_widget('blacklist_options', RadioWidget)
@property
def initial_values(self):
"""Ensure the correct radio button is checked for blacklisting."""
blacklisted_statuses = (
DistroSeriesDifferenceStatus.BLACKLISTED_CURRENT,
DistroSeriesDifferenceStatus.BLACKLISTED_ALWAYS,
)
if self.context.status in blacklisted_statuses:
return dict(blacklist_options=self.context.status)
return dict(blacklist_options='NONE')
@property
def binary_summaries(self):
"""Return the summary of the related binary packages."""
source_pub = None
if self.context.source_pub is not None:
source_pub = self.context.source_pub
elif self.context.parent_source_pub is not None:
source_pub = self.context.parent_source_pub
if source_pub is not None:
summary = source_pub.meta_sourcepackage.summary
if summary:
return summary.split('\n')
return None
@property
def comments(self):
"""See `IConversation`."""
comments = self.context.getComments().order_by(
DistroSeriesDifferenceComment.id)
return [
DistroSeriesDifferenceDisplayComment(comment) for
comment in comments]
@cachedproperty
def can_request_diffs(self):
"""Does the user have permission to request diff calculation?"""
return check_permission('launchpad.Edit', self.context)
@cachedproperty
def show_add_comment(self):
"""Only show the 'Add comment' if an editor requests via JS."""
return self.request.is_ajax and self.can_request_diffs
@cachedproperty
def enable_blacklist_options(self):
"""Should we enable the blacklisting (ignore) radio widget options.
Only enable the options if an editor requests via JS and the user
is an archive admin.
"""
return self.request.is_ajax and check_permission(
'launchpad.Admin', self.context)
@cachedproperty
def blacklist_options_css_class(self):
"""The css class for the blacklist option slot.
'blacklist-options' if enabled.
'blacklist-options-disabled' if not enabled.
"""
if self.enable_blacklist_options:
return 'blacklist-options'
else:
return 'blacklist-options-disabled'
@property
def display_diffs(self):
"""Only show diffs if there's a base version."""
return self.context.base_version is not None
@property
def display_child_diff(self):
"""Only show the child diff if we need to."""
return self.context.source_version != self.context.base_version
@property
def display_parent_diff(self):
"""Only show the parent diff if we need to."""
return self.context.parent_source_version != self.context.base_version
@property
def can_have_packages_diffs(self):
"""Return whether this dsd could have packages diffs."""
diff_versions = DistroSeriesDifferenceType.DIFFERENT_VERSIONS
return self.context.difference_type == diff_versions
@property
def show_package_diffs_request_link(self):
"""Return whether package diffs can be requested.
At least one of the package diffs for this dsd must be missing
and the user must have lp.Edit.
This method is used in the template to show the package diff
request link.
"""
derived_diff_computable = (
not self.context.package_diff and self.display_child_diff)
parent_diff_computable = (
not self.context.parent_package_diff and self.display_parent_diff)
return (self.display_diffs and
self.can_request_diffs and
(derived_diff_computable or
parent_diff_computable))
@property
def display_package_diffs_info(self):
"""Whether or not to show package differences info.
Show if:
There are no diffs yet available AND the base version is set AND
either the parent or the derived version differs from the base
version AND the user can request diff calculation,
Or:
There are diffs.
"""
return (
self.context.package_diff is not None or
self.context.parent_package_diff is not None or
self.show_package_diffs_request_link)
class DistroSeriesDifferenceDisplayComment:
"""Used simply to provide `IComment` for rendering."""
implements(IComment)
has_body = True
has_footer = False
display_attachments = False
extra_css_class = ''
def __init__(self, comment):
"""Setup the attributes required by `IComment`."""
self.comment_author = comment.comment_author
self.comment_date = comment.comment_date
self.body_text = comment.body_text
class CommentXHTMLRepresentation(LaunchpadView):
"""Render individual comments when requested via the API."""
adapts(IDistroSeriesDifferenceComment, IWebServiceClientRequest)
implements(Interface)
template = ViewPageTemplateFile(
'../templates/distroseriesdifferencecomment-fragment.pt')
@property
def comment(self):
return DistroSeriesDifferenceDisplayComment(self.context)
|