~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/bugs/browser/bugtask.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-12-15 10:35:32 UTC
  • mfrom: (14517.1.3 new-bzr)
  • Revision ID: launchpad@pqm.canonical.com-20111215103532-q2m4uyk0r8ugiayx
[r=sinzui, poolie][bug=509016] Always load foreign plugins,
 but restrict probers to avoid accidentally opening foreign branches.
 (re-land)

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
from operator import attrgetter
56
56
import os.path
57
57
import re
 
58
import transaction
58
59
import urllib
59
60
import urlparse
60
61
 
78
79
from pytz import utc
79
80
from simplejson import dumps
80
81
from simplejson.encoder import JSONEncoderForHTML
81
 
import transaction
82
82
from z3c.pt.pagetemplate import ViewPageTemplateFile
83
83
from zope import (
84
84
    component,
107
107
    providedBy,
108
108
    )
109
109
from zope.schema import Choice
110
 
from zope.schema.interfaces import IContextSourceBinder
 
110
from zope.schema.interfaces import (
 
111
    IContextSourceBinder,
 
112
    )
111
113
from zope.schema.vocabulary import (
112
114
    getVocabularyRegistry,
113
115
    SimpleVocabulary,
125
127
    _,
126
128
    helpers,
127
129
    )
128
 
from lp.services.feeds.browser import (
 
130
from canonical.launchpad.browser.feeds import (
129
131
    BugTargetLatestBugsFeedLink,
130
132
    FeedsMixin,
131
133
    )
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 (
135
137
    all,
284
286
    )
285
287
from lp.services.utils import obfuscate_structure
286
288
 
287
 
 
288
289
vocabulary_registry = getVocabularyRegistry()
289
290
 
290
291
DISPLAY_BUG_STATUS_FOR_PATCHES = {
558
559
                # Security proxy this object on the way out.
559
560
                return getUtility(IBugTaskSet).get(bugtask.id)
560
561
 
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:
568
 
            raise NotFoundError
 
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))
570
565
 
571
566
 
1789
1784
    def next_url(self):
1790
1785
        """Return the next URL to call when this call completes."""
1791
1786
        if not self.request.is_ajax:
1792
 
            return self._next_url or self._return_url
 
1787
            return super(BugTaskDeletionView, self).next_url
1793
1788
        return None
1794
1789
 
1795
1790
    @action('Delete', name='delete_bugtask')
1800
1795
        success_message = ("This bug no longer affects %s."
1801
1796
                    % bugtask.bugtargetdisplayname)
1802
1797
        error_message = None
1803
 
        # We set the next_url here before the bugtask is deleted since later
1804
 
        # the bugtask will not be available if required to construct the url.
1805
 
        self._next_url = self._return_url
1806
1798
 
1807
1799
        try:
1808
1800
            bugtask.delete()
2234
2226
        assignee = None
2235
2227
        if self.assignee is not None:
2236
2228
            assignee = self.assignee.displayname
2237
 
 
2238
 
        base_tag_url = "%s/?field.tag=" % canonical_url(
2239
 
            self.bugtask.target,
2240
 
            view_name="+bugs")
2241
 
 
2242
 
        flattened = {
 
2229
        return {
2243
2230
            'age': age,
2244
2231
            'assignee': assignee,
2245
2232
            'bug_url': canonical_url(self.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,
2261
2247
            }
2262
2248
 
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
2268
 
        return flattened
2269
 
 
2270
2249
 
2271
2250
class BugListingBatchNavigator(TableBatchNavigator):
2272
2251
    """A specialised batch navigator to load smartly extra bug information."""
2379
2358
 
2380
2359
    @property
2381
2360
    def model(self):
2382
 
        items = [bugtask.model for bugtask in self.getBugListingItems()]
2383
 
        for item in items:
2384
 
            item.update(self.field_visibility)
2385
 
        return {'items': items}
 
2361
        bugtasks = [bugtask.model for bugtask in self.getBugListingItems()]
 
2362
        for bugtask in bugtasks:
 
2363
            bugtask.update(self.field_visibility)
 
2364
        return {'bugtasks': bugtasks}
2386
2365
 
2387
2366
 
2388
2367
class NominatedBugReviewAction(EnumeratedType):
2499
2478
        return Link('+nominations', 'Review nominations', icon='bug')
2500
2479
 
2501
2480
 
2502
 
# All sort orders supported by BugTaskSet.search() and a title for
2503
 
# them.
2504
 
SORT_KEYS = [
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'),
2526
 
    ]
2527
 
 
2528
 
 
2529
2481
class BugTaskSearchListingView(LaunchpadFormView, FeedsMixin, BugsInfoMixin):
2530
2482
    """View that renders a list of bugs for a given set of search criteria."""
2531
2483
 
2555
2507
    custom_widget('structural_subscriber', PersonPickerWidget)
2556
2508
    custom_widget('subscriber', PersonPickerWidget)
2557
2509
 
2558
 
    _batch_navigator = None
2559
 
 
2560
2510
    @cachedproperty
2561
2511
    def bug_tracking_usage(self):
2562
2512
        """Whether the context tracks bugs in Launchpad.
2722
2672
            last_batch = batch_navigator.batch.lastBatch()
2723
2673
            cache.objects['last_start'] = last_batch.startNumber() - 1
2724
2674
            cache.objects.update(_getBatchInfo(batch_navigator.batch))
2725
 
            cache.objects['sort_keys'] = SORT_KEYS
2726
2675
 
2727
2676
    @property
2728
2677
    def show_config_portlet(self):
2794
2743
                orderby_col = orderby_col[1:]
2795
2744
 
2796
2745
            try:
2797
 
                bugset.orderby_expression[orderby_col]
 
2746
                bugset.getOrderByColumnDBName(orderby_col)
2798
2747
            except KeyError:
2799
2748
                raise UnexpectedFormData(
2800
2749
                    "Unknown sort column '%s'" % orderby_col)
3021
2970
            the search criteria taken from the request. Params in
3022
2971
            `extra_params` take precedence over request params.
3023
2972
        """
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)
3029
2976
 
3030
2977
    def searchUnbatched(self, searchtext=None, context=None,
3031
2978
                        extra_params=None, prejoins=[]):