8
8
'UsesBugsDistributionVocabulary',
9
'BugNominatableDistroSeriesVocabulary',
10
'BugNominatableProductSeriesVocabulary',
11
'BugNominatableSeriesVocabulary',
12
'BugTrackerVocabulary',
15
'DistributionUsingMaloneVocabulary',
16
'project_products_using_malone_vocabulary_factory',
17
'UsesBugsDistributionVocabulary',
18
'WebBugTrackerVocabulary',
11
from sqlobject import OR
22
from operator import attrgetter
24
from sqlobject import (
29
from storm.expr import (
34
from zope.component import getUtility
35
from zope.interface import implements
36
from zope.schema.interfaces import (
40
from zope.schema.vocabulary import (
45
from canonical.launchpad.helpers import (
49
from canonical.launchpad.interfaces.lpstorm import IStore
50
from canonical.launchpad.webapp.vocabulary import (
53
NamedSQLObjectVocabulary,
54
SQLObjectVocabularyBase,
56
from canonical.launchpad.webapp.interfaces import ILaunchBag
57
from lp.app.browser.stringformatter import FormattersAPI
58
from lp.app.enums import ServiceUsage
59
from lp.bugs.interfaces.bugtask import IBugTask
60
from lp.bugs.interfaces.bugtracker import BugTrackerType
61
from lp.bugs.model.bug import Bug
62
from lp.bugs.model.bugtracker import BugTracker
63
from lp.bugs.model.bugwatch import BugWatch
13
64
from lp.registry.interfaces.distribution import IDistribution
65
from lp.registry.interfaces.projectgroup import IProjectGroup
66
from lp.registry.interfaces.series import SeriesStatus
67
from lp.registry.model.distribution import Distribution
68
from lp.registry.model.distroseries import DistroSeries
69
from lp.registry.model.productseries import ProductSeries
14
70
from lp.registry.vocabularies import DistributionVocabulary
37
93
self._table.q.official_malone == True,
38
94
self._table.id == distro_id)
97
class BugVocabulary(SQLObjectVocabularyBase):
103
class BugTrackerVocabulary(SQLObjectVocabularyBase):
104
"""All web and email based external bug trackers."""
105
displayname = 'Select a bug tracker'
106
step_title = 'Search'
107
implements(IHugeVocabulary)
111
_order_by = [BugTracker.title]
113
def toTerm(self, obj):
114
"""See `IVocabulary`."""
115
return SimpleTerm(obj, obj.name, obj.title)
117
def getTermByToken(self, token):
118
"""See `IVocabularyTokenized`."""
119
result = IStore(self._table).find(
122
BugTracker.name == token).one()
124
raise LookupError(token)
125
return self.toTerm(result)
127
def search(self, query, vocab_filter=None):
128
"""Search for web bug trackers."""
129
query = ensure_unicode(query).lower()
130
results = IStore(self._table).find(
133
BugTracker.active == True,
135
CONTAINSSTRING(BugTracker.name, query),
136
CONTAINSSTRING(BugTracker.title, query),
137
CONTAINSSTRING(BugTracker.summary, query),
138
CONTAINSSTRING(BugTracker.baseurl, query))))
139
results = results.order_by(self._order_by)
142
def searchForTerms(self, query=None, vocab_filter=None):
143
"""See `IHugeVocabulary`."""
144
results = self.search(query, vocab_filter)
145
return CountableIterator(results.count(), results, self.toTerm)
148
class WebBugTrackerVocabulary(BugTrackerVocabulary):
149
"""All web-based bug tracker types."""
150
_filter = BugTracker.bugtrackertype != BugTrackerType.EMAILADDRESS
153
def project_products_using_malone_vocabulary_factory(context):
154
"""Return a vocabulary containing a project's products using Malone."""
155
project = IProjectGroup(context)
156
return SimpleVocabulary([
157
SimpleTerm(product, product.name, title=product.displayname)
158
for product in project.products
159
if product.bug_tracking_usage == ServiceUsage.LAUNCHPAD])
162
class BugWatchVocabulary(SQLObjectVocabularyBase):
166
assert IBugTask.providedBy(self.context), (
167
"BugWatchVocabulary expects its context to be an IBugTask.")
168
bug = self.context.bug
170
for watch in bug.watches:
171
yield self.toTerm(watch)
173
def toTerm(self, watch):
176
return cgi.escape(string, quote=True)
178
if watch.url.startswith('mailto:'):
179
user = getUtility(ILaunchBag).user
181
title = FormattersAPI(
182
watch.bugtracker.title).obfuscate_email()
184
watch, watch.id, escape(title))
187
title = escape(watch.bugtracker.title)
189
title = title.replace(
190
url, '<a href="%s">%s</a>' % (
191
escape(url), escape(url)))
193
title = '%s <<a href="%s">%s</a>>' % (
194
title, escape(url), escape(url[7:]))
195
return SimpleTerm(watch, watch.id, title)
198
watch, watch.id, '%s <a href="%s">#%s</a>' % (
199
escape(watch.bugtracker.title),
201
escape(watch.remotebug)))
204
class DistributionUsingMaloneVocabulary:
205
"""All the distributions that uses Malone officially."""
207
implements(IVocabulary, IVocabularyTokenized)
209
_orderBy = 'displayname'
211
def __init__(self, context=None):
212
self.context = context
215
"""Return an iterator which provides the terms from the vocabulary."""
216
distributions_using_malone = Distribution.selectBy(
217
official_malone=True, orderBy=self._orderBy)
218
for distribution in distributions_using_malone:
219
yield self.getTerm(distribution)
222
return Distribution.selectBy(official_malone=True).count()
224
def __contains__(self, obj):
225
return (IDistribution.providedBy(obj)
226
and obj.bug_tracking_usage == ServiceUsage.LAUNCHPAD)
228
def getTerm(self, obj):
230
raise LookupError(obj)
231
return SimpleTerm(obj, obj.name, obj.displayname)
233
def getTermByToken(self, token):
234
found_dist = Distribution.selectOneBy(
235
name=token, official_malone=True)
236
if found_dist is None:
237
raise LookupError(token)
238
return self.getTerm(found_dist)
241
def BugNominatableSeriesVocabulary(context=None):
242
"""Return a nominatable series vocabulary."""
243
if getUtility(ILaunchBag).distribution:
244
return BugNominatableDistroSeriesVocabulary(
245
context, getUtility(ILaunchBag).distribution)
247
assert getUtility(ILaunchBag).product
248
return BugNominatableProductSeriesVocabulary(
249
context, getUtility(ILaunchBag).product)
252
class BugNominatableSeriesVocabularyBase(NamedSQLObjectVocabulary):
253
"""Base vocabulary class for series for which a bug can be nominated."""
256
bug = self.context.bug
258
all_series = self._getNominatableObjects()
260
for series in sorted(all_series, key=attrgetter("displayname")):
261
if bug.canBeNominatedFor(series):
262
yield self.toTerm(series)
264
def toTerm(self, obj):
265
return SimpleTerm(obj, obj.name, obj.name.capitalize())
267
def getTermByToken(self, token):
268
obj = self._queryNominatableObjectByName(token)
270
raise LookupError(token)
272
return self.toTerm(obj)
274
def _getNominatableObjects(self):
275
"""Return the series objects that the bug can be nominated for."""
276
raise NotImplementedError
278
def _queryNominatableObjectByName(self, name):
279
"""Return the series object with the given name."""
280
raise NotImplementedError
283
class BugNominatableProductSeriesVocabulary(
284
BugNominatableSeriesVocabularyBase):
285
"""The product series for which a bug can be nominated."""
287
_table = ProductSeries
289
def __init__(self, context, product):
290
BugNominatableSeriesVocabularyBase.__init__(self, context)
291
self.product = product
293
def _getNominatableObjects(self):
294
"""See BugNominatableSeriesVocabularyBase."""
295
return shortlist(self.product.series)
297
def _queryNominatableObjectByName(self, name):
298
"""See BugNominatableSeriesVocabularyBase."""
299
return self.product.getSeries(name)
302
class BugNominatableDistroSeriesVocabulary(
303
BugNominatableSeriesVocabularyBase):
304
"""The distribution series for which a bug can be nominated."""
306
_table = DistroSeries
308
def __init__(self, context, distribution):
309
BugNominatableSeriesVocabularyBase.__init__(self, context)
310
self.distribution = distribution
312
def _getNominatableObjects(self):
313
"""Return all non-obsolete distribution series"""
315
series for series in shortlist(self.distribution.series)
316
if series.status != SeriesStatus.OBSOLETE]
318
def _queryNominatableObjectByName(self, name):
319
"""See BugNominatableSeriesVocabularyBase."""
320
return self.distribution.getSeries(name)