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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
|
# Copyright 2010 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=E0211,E0213
"""Interfaces related to bugs."""
__metaclass__ = type
__all__ = [
'BugDistroSeriesTargetDetails',
'IBugTarget',
'IHasBugs',
'IHasBugHeat',
'IHasOfficialBugTags',
'IOfficialBugTag',
'IOfficialBugTagTarget',
'IOfficialBugTagTargetPublic',
'IOfficialBugTagTargetRestricted',
'ISeriesBugTarget',
]
from lazr.enum import DBEnumeratedType
from lazr.restful.declarations import (
call_with,
export_as_webservice_entry,
export_read_operation,
export_write_operation,
exported,
LAZR_WEBSERVICE_EXPORTED,
operation_for_version,
operation_parameters,
operation_removed_in_version,
operation_returns_collection_of,
REQUEST_USER,
)
from lazr.restful.fields import Reference
from lazr.restful.interface import copy_field
from zope.interface import (
Attribute,
Interface,
)
from zope.schema import (
Bool,
Choice,
Datetime,
List,
Object,
Text,
TextLine,
)
from canonical.launchpad import _
from lp.bugs.interfaces.bugtask import (
BugBlueprintSearch,
BugBranchSearch,
BugTagsSearchCombinator,
IBugTask,
IBugTaskSearch,
)
from lp.services.fields import Tag
search_tasks_params_common = {
"order_by": List(
title=_('List of fields by which the results are ordered.'),
value_type=Text(),
required=False),
"search_text": copy_field(IBugTaskSearch['searchtext']),
"status": copy_field(IBugTaskSearch['status']),
"importance": copy_field(IBugTaskSearch['importance']),
"assignee": Reference(schema=Interface),
"bug_reporter": Reference(schema=Interface),
"bug_supervisor": Reference(schema=Interface),
"bug_commenter": Reference(schema=Interface),
"bug_subscriber": Reference(schema=Interface),
"structural_subscriber": Reference(schema=Interface),
"owner": Reference(schema=Interface),
"affected_user": Reference(schema=Interface),
"has_patch": copy_field(IBugTaskSearch['has_patch']),
"has_cve": copy_field(IBugTaskSearch['has_cve']),
"tags": copy_field(IBugTaskSearch['tag']),
"tags_combinator": copy_field(IBugTaskSearch['tags_combinator']),
"omit_duplicates": copy_field(IBugTaskSearch['omit_dupes']),
"status_upstream": copy_field(IBugTaskSearch['status_upstream']),
"milestone_assignment": copy_field(
IBugTaskSearch['milestone_assignment']),
"milestone": copy_field(IBugTaskSearch['milestone']),
"component": copy_field(IBugTaskSearch['component']),
"nominated_for": Reference(schema=Interface),
"has_no_package": copy_field(IBugTaskSearch['has_no_package']),
"hardware_bus": Choice(
title=_(u"The bus of a hardware device related to a bug"),
# The vocabulary should be HWBus; this is fixed in
# _schema_circular_imports to avoid circular imports.
vocabulary=DBEnumeratedType, required=False),
"hardware_vendor_id": TextLine(
title=_(
u"The vendor ID of a hardware device related to a bug."),
description=_(
u"Allowed values of the vendor ID depend on the bus of the "
"device.\n\n"
"Vendor IDs of PCI, PCCard and USB devices are hexadecimal "
"string representations of 16 bit integers in the format "
"'0x01ab': The prefix '0x', followed by exactly 4 digits; "
"where a digit is one of the characters 0..9, a..f. The "
"characters A..F are not allowed.\n\n"
"SCSI vendor IDs are strings with exactly 8 characters. "
"Shorter names are right-padded with space (0x20) characters."
"\n\n"
"IDs for other buses may be arbitrary strings."),
required=False),
"hardware_product_id": TextLine(
title=_(
u"The product ID of a hardware device related to a bug."),
description=_(
u"Allowed values of the product ID depend on the bus of the "
"device.\n\n"
"Product IDs of PCI, PCCard and USB devices are hexadecimal "
"string representations of 16 bit integers in the format "
"'0x01ab': The prefix '0x', followed by exactly 4 digits; "
"where a digit is one of the characters 0..9, a..f. The "
"characters A..F are not allowed.\n\n"
"SCSI product IDs are strings with exactly 16 characters. "
"Shorter names are right-padded with space (0x20) characters."
"\n\n"
"IDs for other buses may be arbitrary strings."),
required=False),
"hardware_driver_name": TextLine(
title=_(
u"The driver controlling a hardware device related to a "
"bug."),
required=False),
"hardware_driver_package_name": TextLine(
title=_(
u"The package of the driver which controls a hardware "
"device related to a bug."),
required=False),
"hardware_owner_is_bug_reporter": Bool(
title=_(
u"Search for bugs reported by people who own the given "
"device or who use the given hardware driver."),
required=False),
"hardware_owner_is_affected_by_bug": Bool(
title=_(
u"Search for bugs where people affected by a bug own the "
"given device or use the given hardware driver."),
required=False),
"hardware_owner_is_subscribed_to_bug": Bool(
title=_(
u"Search for bugs where a bug subscriber owns the "
"given device or uses the given hardware driver."),
required=False),
"hardware_is_linked_to_bug": Bool(
title=_(
u"Search for bugs which are linked to hardware reports "
"which contain the given device or whcih contain a device"
"controlled by the given driver."),
required=False),
"linked_branches": Choice(
title=_(
u"Search for bugs that are linked to branches or for bugs "
"that are not linked to branches."),
vocabulary=BugBranchSearch, required=False),
"modified_since": Datetime(
title=_(
u"Search for bugs that have been modified since the given "
"date."),
required=False),
"created_since": Datetime(
title=_(
u"Search for bugs that have been created since the given "
"date."),
required=False),
}
search_tasks_params_for_api_default = dict(
search_tasks_params_common,
omit_targeted=copy_field(
IBugTaskSearch['omit_targeted']))
search_tasks_params_for_api_devel = dict(
search_tasks_params_common,
omit_targeted=copy_field(
IBugTaskSearch['omit_targeted'], default=False),
linked_blueprints=Choice(
title=_(
u"Search for bugs that are linked to blueprints or for "
u"bugs that are not linked to blueprints."),
vocabulary=BugBlueprintSearch, required=False))
class IHasBugs(Interface):
"""An entity which has a collection of bug tasks."""
export_as_webservice_entry()
# XXX Tom Berger 2008-09-26, Bug #274735
# The following are attributes, rather than fields, and must remain
# so, to make sure that they are not being copied into snapshots.
# Eventually, we'd like to remove these attributes from the content
# class altogether.
open_bugtasks = Attribute("A list of open bugTasks for this target.")
closed_bugtasks = Attribute("A list of closed bugTasks for this target.")
inprogress_bugtasks = Attribute(
"A list of in-progress bugTasks for this target.")
high_bugtasks = Attribute(
"A list of high importance BugTasks for this target.")
critical_bugtasks = Attribute(
"A list of critical BugTasks for this target.")
new_bugtasks = Attribute("A list of New BugTasks for this target.")
unassigned_bugtasks = Attribute(
"A list of unassigned BugTasks for this target.")
all_bugtasks = Attribute(
"A list of all BugTasks ever reported for this target.")
has_bugtasks = Attribute(
"True if a BugTask has ever been reported for this target.")
# searchTasks devel API declaration.
@call_with(search_params=None, user=REQUEST_USER)
@operation_parameters(**search_tasks_params_for_api_devel)
@operation_returns_collection_of(IBugTask)
@export_read_operation()
# Pop the *default* version (decorators are run last to first).
@operation_removed_in_version('devel')
# searchTasks default API declaration.
@call_with(search_params=None, user=REQUEST_USER)
@operation_parameters(**search_tasks_params_for_api_default)
@operation_returns_collection_of(IBugTask)
@export_read_operation()
@operation_for_version('beta')
def searchTasks(search_params, user=None,
order_by=None, search_text=None,
status=None, importance=None,
assignee=None, bug_reporter=None, bug_supervisor=None,
bug_commenter=None, bug_subscriber=None, owner=None,
affected_user=None, has_patch=None, has_cve=None,
distribution=None, tags=None,
tags_combinator=BugTagsSearchCombinator.ALL,
omit_duplicates=True, omit_targeted=None,
status_upstream=None, milestone_assignment=None,
milestone=None, component=None, nominated_for=None,
sourcepackagename=None, has_no_package=None,
hardware_bus=None, hardware_vendor_id=None,
hardware_product_id=None, hardware_driver_name=None,
hardware_driver_package_name=None,
hardware_owner_is_bug_reporter=None,
hardware_owner_is_affected_by_bug=False,
hardware_owner_is_subscribed_to_bug=False,
hardware_is_linked_to_bug=False, linked_branches=None,
linked_blueprints=None, structural_subscriber=None,
modified_since=None, created_since=None, prejoins=[]):
"""Search the IBugTasks reported on this entity.
:search_params: a BugTaskSearchParams object
Return an iterable of matching results.
Note: milestone is currently ignored for all IBugTargets
except IProduct.
In order to search bugs that are related to a given hardware
device, you must specify the bus, the vendor ID, the product
ID of the device and set at least one of
hardware_owner_is_bug_reporter,
hardware_owner_is_affected_by_bug,
hardware_owner_is_subscribed_to_bug,
hardware_is_linked_to_bug to True.
"""
def getBugTaskWeightFunction():
"""Return a function that is used to weight the bug tasks.
The function should take a bug task as a parameter and return
an OrderedBugTask.
The ordered bug tasks are used to choose the most relevant bug task
for any particular context.
"""
class IBugTarget(IHasBugs):
"""An entity on which a bug can be reported.
Examples include an IDistribution, an IDistroSeries and an
IProduct.
"""
export_as_webservice_entry()
# XXX Brad Bollenbach 2006-08-02 bug=54974: This attribute name smells.
bugtargetdisplayname = Attribute("A display name for this bug target")
bugtargetname = Attribute("The target as shown in mail notifications.")
bug_reporting_guidelines = exported(
Text(
title=(
u"Helpful guidelines for reporting a bug"),
description=(
u"These guidelines will be shown to "
"everyone reporting a bug and should be "
"text or a bulleted list with your particular "
"requirements, if any."),
required=False,
max_length=50000))
bug_reported_acknowledgement = exported(
Text(
title=(
u"After reporting a bug, I can expect the following."),
description=(
u"This message of acknowledgement will be displayed "
"to anyone after reporting a bug."),
required=False,
max_length=50000))
enable_bugfiling_duplicate_search = Bool(
title=u"Search for possible duplicate bugs when a new bug is filed",
description=(
u"If enabled, Launchpad searches the project for bugs which "
u"could match the summary given by the bug reporter. However, "
u"this can lead users to mistake an existing bug as the one "
u"they want to report. This can happen for example for hardware "
u"related bugs where the one symptom can be caused by "
u"completely different hardware and drivers."),
required=False)
def createBug(bug_params):
"""Create a new bug on this target.
bug_params is an instance of
canonical.launchpad.interfaces.CreateBugParams.
"""
# We assign the schema for an `IBugTask` attribute here
# in order to avoid circular dependencies.
IBugTask['target'].schema = IBugTarget
IBugTask['transitionToTarget'].getTaggedValue(
LAZR_WEBSERVICE_EXPORTED)['params']['target'].schema = IBugTarget
class IHasBugHeat(Interface):
"""An entity which has bug heat."""
max_bug_heat = Attribute(
"The current highest bug heat value for this entity.")
def setMaxBugHeat(heat):
"""Set the max_bug_heat for this context."""
def recalculateBugHeatCache():
"""Recalculate and set the various bug heat values for this context.
Several different objects cache max_bug_heat.
When DistributionSourcePackage is the target, the total_bug_heat
and bug_count are also cached.
"""
class BugDistroSeriesTargetDetails:
"""The details of a bug targeted to a specific IDistroSeries.
The following attributes are provided:
:series: The IDistroSeries.
:istargeted: Is there a fix targeted to this series?
:sourcepackage: The sourcepackage to which the fix would be targeted.
:assignee: An IPerson, or None if no assignee.
:status: A BugTaskStatus dbschema item, or None, if series is not
targeted.
"""
def __init__(self, series, istargeted=False, sourcepackage=None,
assignee=None, status=None):
self.series = series
self.istargeted = istargeted
self.sourcepackage = sourcepackage
self.assignee = assignee
self.status = status
class IHasOfficialBugTags(Interface):
"""An entity that exposes a set of official bug tags."""
official_bug_tags = exported(List(
title=_("Official Bug Tags"),
description=_("The list of bug tags defined as official."),
value_type=Tag(),
readonly=True))
def getUsedBugTags():
"""Return the tags used by the context as a sorted list of strings."""
def getUsedBugTagsWithOpenCounts(user, tag_limit=0, include_tags=None):
"""Return name and bug count of tags having open bugs.
:param user: The user who wants the report.
:param tag_limit: The number of tags to return (excludes those found by
matching include_tags). If 0 then all tags are returned. If
non-zero then the most frequently used tags are returned.
:param include_tags: A list of string tags to return irrespective of
usage. Tags in this list that have no open bugs are returned with a
count of 0. May be None if there are tags to require inclusion of.
:return: A dict from tag -> count.
"""
def _getOfficialTagClause():
"""Get the storm clause for finding this targets tags."""
class IOfficialBugTagTargetPublic(IHasOfficialBugTags):
"""Public attributes for `IOfficialBugTagTarget`."""
official_bug_tags = copy_field(
IHasOfficialBugTags['official_bug_tags'], readonly=False)
class IOfficialBugTagTargetRestricted(Interface):
"""Restricted methods for `IOfficialBugTagTarget`."""
@operation_parameters(
tag=Tag(title=u'The official bug tag', required=True))
@export_write_operation()
@operation_for_version('beta')
def addOfficialBugTag(tag):
"""Add tag to the official bug tags of this target."""
@operation_parameters(
tag=Tag(title=u'The official bug tag', required=True))
@export_write_operation()
@operation_for_version('beta')
def removeOfficialBugTag(tag):
"""Remove tag from the official bug tags of this target."""
class IOfficialBugTagTarget(IOfficialBugTagTargetPublic,
IOfficialBugTagTargetRestricted):
"""An entity for which official bug tags can be defined."""
# XXX intellectronica 2009-03-16 bug=342413
# We can start using straight inheritance once it becomes possible
# to export objects implementing multiple interfaces in the
# webservice API.
class IOfficialBugTag(Interface):
"""Official bug tags for a product, a project or a distribution."""
tag = Tag(
title=u'The official bug tag', required=True)
target = Object(
title=u'The target of this bug tag.',
schema=IOfficialBugTagTarget,
description=
u'The distribution or product having this official bug tag.')
class ISeriesBugTarget(Interface):
"""An `IBugTarget` which is a series."""
bugtarget_parent = Attribute(
"Non-series parent of this series bug target.")
|