128
from lp.services.feeds.browser import (
130
from canonical.launchpad.browser.feeds import (
129
131
BugTargetLatestBugsFeedLink,
132
from lp.bugs.interfaces.bugtracker import IHasExternalBugTracker
134
from canonical.launchpad.interfaces.launchpad import IHasExternalBugTracker
133
135
from canonical.launchpad.mailnotification import get_unified_diff
134
136
from canonical.launchpad.searchbuilder import (
558
559
# Security proxy this object on the way out.
559
560
return getUtility(IBugTaskSet).get(bugtask.id)
561
# If we've come this far, there's no task for the requested context.
562
# If we are attempting to navigate past the non-existent bugtask,
563
# we raise NotFound error. eg +delete or +edit etc.
564
# Otherwise we are simply navigating to a non-existent task and so we
565
# redirect to one that exists.
566
travseral_stack = self.request.getTraversalStack()
567
if len(travseral_stack) > 0:
562
# If we've come this far, there's no task for the requested
563
# context. Redirect to one that exists.
569
564
return self.redirectSubTree(canonical_url(bug.default_bugtask))
2255
2242
'reporter': self.bug.owner.displayname,
2256
2243
'status': self.status.title,
2257
2244
'status_class': 'status' + self.status.name,
2258
'tags': [{'url': base_tag_url + tag, 'tag': tag}
2259
for tag in self.bug.tags],
2245
'tags': ' '.join(self.bug.tags),
2260
2246
'title': self.bug.title,
2263
# This is a total hack, but pystache will run both truth/false values
2264
# for an empty list for some reason, and it "works" if it's just a
2265
# flag like this. We need this value for the mustache template to be
2266
# able to tell that there are no tags without looking at the list.
2267
flattened['has_tags'] = True if len(flattened['tags']) else False
2271
2250
class BugListingBatchNavigator(TableBatchNavigator):
2272
2251
"""A specialised batch navigator to load smartly extra bug information."""
2499
2478
return Link('+nominations', 'Review nominations', icon='bug')
2502
# All sort orders supported by BugTaskSet.search() and a title for
2505
('importance', 'Importance', 'desc'),
2506
('status', 'Status', 'asc'),
2507
('id', 'Bug number', 'desc'),
2508
('title', 'Bug title', 'asc'),
2509
('targetname', 'Package/Project/Series name', 'asc'),
2510
('milestone_name', 'Milestone', 'asc'),
2511
('date_last_updated', 'Date bug last updated', 'desc'),
2512
('assignee', 'Assignee', 'asc'),
2513
('reporter', 'Reporter', 'asc'),
2514
('datecreated', 'Bug age', 'desc'),
2515
('tag', 'Bug Tags', 'asc'),
2516
('heat', 'Bug heat', 'desc'),
2517
('date_closed', 'Date bug closed', 'desc'),
2518
('dateassigned', 'Date when the bug task was assigned', 'desc'),
2519
('number_of_duplicates', 'Number of duplicates', 'desc'),
2520
('latest_patch_uploaded', 'Date latest patch uploaded', 'desc'),
2521
('message_count', 'Number of comments', 'desc'),
2522
('milestone', 'Milestone ID', 'desc'),
2523
('specification', 'Linked blueprint', 'asc'),
2524
('task', 'Bug task ID', 'desc'),
2525
('users_affected_count', 'Number of affected users', 'desc'),
2529
2481
class BugTaskSearchListingView(LaunchpadFormView, FeedsMixin, BugsInfoMixin):
2530
2482
"""View that renders a list of bugs for a given set of search criteria."""
3021
2970
the search criteria taken from the request. Params in
3022
2971
`extra_params` take precedence over request params.
3024
if self._batch_navigator is None:
3025
unbatchedTasks = self.searchUnbatched(
3026
searchtext, context, extra_params)
3027
self._batch_navigator = self._getBatchNavigator(unbatchedTasks)
3028
return self._batch_navigator
2973
unbatchedTasks = self.searchUnbatched(
2974
searchtext, context, extra_params)
2975
return self._getBatchNavigator(unbatchedTasks)
3030
2977
def searchUnbatched(self, searchtext=None, context=None,
3031
2978
extra_params=None, prejoins=[]):