Edgewall Software

Ticket #8166: 8166-post-redirect-messages-r8179.patch

File 8166-post-redirect-messages-r8179.patch, 21.9 KB (added by rblank, 3 years ago)

Patch against 0.11-stable adding post-redirect messages

  • trac/admin/web_ui.py

    diff --git a/trac/admin/web_ui.py b/trac/admin/web_ui.py
    a b  
    3333from trac.util.text import to_unicode 
    3434from trac.util.translation import _ 
    3535from trac.web import HTTPNotFound, IRequestHandler 
    36 from trac.web.chrome import add_script, add_stylesheet, add_warning, Chrome, \ 
    37                             INavigationContributor, ITemplateProvider 
     36from trac.web.chrome import add_notice, add_script, add_stylesheet, \ 
     37                            add_warning, Chrome, INavigationContributor, \ 
     38                            ITemplateProvider 
    3839 
    3940try: 
    4041    from webadmin import IAdminPageProvider 
     
    190191            for option in ('name', 'url', 'descr'): 
    191192                self.config.set('project', option, req.args.get(option)) 
    192193            self.config.save() 
     194            add_notice(req, _("Your changes have been saved.")) 
    193195            req.redirect(req.href.admin(cat, page)) 
    194196 
    195197        data = { 
     
    274276 
    275277            if changed: 
    276278                self.config.save() 
     279            add_notice(req, _("Your changes have been saved.")) 
    277280            req.redirect(req.href.admin(cat, page)) 
    278281 
    279282        data = { 
     
    321324                req.perm.require(action) 
    322325                if (subject, action) not in all_permissions: 
    323326                    perm.grant_permission(subject, action) 
     327                    add_notice(req, _("The user %(user)s has been granted " 
     328                                      "the permission %(perm)s.", user=subject, 
     329                                      perm=action)) 
    324330                    req.redirect(req.href.admin(cat, page)) 
    325331                else: 
    326332                    add_warning(req, 
     
    338344                            % (subject, group, action)) 
    339345                    else: 
    340346                        req.perm.require(action) 
    341                 if (subject,group) not in all_permissions: 
     347                if (subject, group) not in all_permissions: 
    342348                    perm.grant_permission(subject, group) 
     349                    add_notice(req, _("The user '%(user)s' has been added to " 
     350                                      "the group '%(group)s'.", user=subject, 
     351                                      group=group)) 
    343352                    req.redirect(req.href.admin(cat, page)) 
    344353                else: 
    345354                    add_warning(req,  
     
    355364                    subject, action = key.split(':', 1) 
    356365                    if (subject, action) in perm.get_all_permissions(): 
    357366                        perm.revoke_permission(subject, action) 
     367                add_notice(req, _("The selected permissions have been " 
     368                                  "revoked.")) 
    358369                req.redirect(req.href.admin(cat, page)) 
    359370 
    360371        return 'admin_perms.html', { 
  • trac/prefs/web_ui.py

    diff --git a/trac/prefs/web_ui.py b/trac/prefs/web_ui.py
    a b  
    2525from trac.util.datefmt import all_timezones, get_timezone, localtz 
    2626from trac.util.translation import _ 
    2727from trac.web import HTTPNotFound, IRequestHandler 
    28 from trac.web.chrome import add_stylesheet, INavigationContributor, \ 
    29                             ITemplateProvider 
     28from trac.web.chrome import add_notice, add_stylesheet, \ 
     29                            INavigationContributor, ITemplateProvider 
    3030 
    3131 
    3232class PreferencesModule(Component): 
     
    125125            elif field in req.session and (field in req.args or 
    126126                                           field + '_cb' in req.args): 
    127127                del req.session[field] 
     128        add_notice(req, _("Your preferences have been saved.")) 
    128129 
    129130    def _do_load(self, req): 
    130131        if req.authname == 'anonymous': 
  • trac/ticket/admin.py

    diff --git a/trac/ticket/admin.py b/trac/ticket/admin.py
    a b  
    2121from trac.util.datefmt import utc, parse_date, get_date_format_hint, \ 
    2222                              get_datetime_format_hint 
    2323from trac.util.translation import _ 
    24 from trac.web.chrome import add_link, add_script 
     24from trac.web.chrome import add_link, add_notice, add_script 
    2525 
    2626 
    2727class TicketAdminPanel(Component): 
     
    6262                    comp.owner = req.args.get('owner') 
    6363                    comp.description = req.args.get('description') 
    6464                    comp.update() 
     65                    add_notice(req, _("Your changes have been saved.")) 
    6566                    req.redirect(req.href.admin(cat, page)) 
    6667                elif req.args.get('cancel'): 
    6768                    req.redirect(req.href.admin(cat, page)) 
     
    8283                        if req.args.get('owner'): 
    8384                            comp.owner = req.args.get('owner') 
    8485                        comp.insert() 
     86                        add_notice(req, _("The component '%(name)s' has been " 
     87                                          "added.", name=name)) 
    8588                        req.redirect(req.href.admin(cat, page)) 
    8689                    else: 
    8790                        raise TracError(_('Component %s already exists.') % name) 
     
    98101                        comp = model.Component(self.env, name, db=db) 
    99102                        comp.delete(db=db) 
    100103                    db.commit() 
     104                    add_notice(req, _("The selected components have been " 
     105                                      "removed.")) 
    101106                    req.redirect(req.href.admin(cat, page)) 
    102107 
    103108                # Set default component 
     
    107112                        self.log.info('Setting default component to %s', name) 
    108113                        self.config.set('ticket', 'default_component', name) 
    109114                        self.config.save() 
     115                        add_notice(req, _("Your changes have been saved.")) 
    110116                        req.redirect(req.href.admin(cat, page)) 
    111117 
    112118            default = self.config.get('ticket', 'default_component') 
     
    166172                                            _('Invalid Completion Date')) 
    167173                    mil.description = req.args.get('description', '') 
    168174                    mil.update() 
     175                    add_notice(req, _("Your changes have been saved.")) 
    169176                    req.redirect(req.href.admin(cat, page)) 
    170177                elif req.args.get('cancel'): 
    171178                    req.redirect(req.href.admin(cat, page)) 
     
    188195                            mil.due = parse_date(req.args.get('duedate'), 
    189196                                                 req.tz) 
    190197                        mil.insert() 
     198                        add_notice(req, _("The milestone '%(name)s' has been " 
     199                                          "added.", name=name)) 
    191200                        req.redirect(req.href.admin(cat, page)) 
    192201                    else: 
    193202                        raise TracError(_('Milestone %s already exists.') % name) 
     
    205214                        mil = model.Milestone(self.env, name, db=db) 
    206215                        mil.delete(db=db, author=req.authname) 
    207216                    db.commit() 
     217                    add_notice(req, _("The selected milestones have been " 
     218                                      "removed.")) 
    208219                    req.redirect(req.href.admin(cat, page)) 
    209220 
    210221                # Set default milestone 
     
    214225                        self.log.info('Setting default milestone to %s', name) 
    215226                        self.config.set('ticket', 'default_milestone', name) 
    216227                        self.config.save() 
     228                        add_notice(req, _("Your changes have been saved.")) 
    217229                        req.redirect(req.href.admin(cat, page)) 
    218230 
    219231            # Get ticket count 
     
    258270                        ver.time = None # unset 
    259271                    ver.description = req.args.get('description') 
    260272                    ver.update() 
     273                    add_notice(req, _("Your changes have been saved.")) 
    261274                    req.redirect(req.href.admin(cat, page)) 
    262275                elif req.args.get('cancel'): 
    263276                    req.redirect(req.href.admin(cat, page)) 
     
    279292                            ver.time = parse_date(req.args.get('time'), 
    280293                                                  req.tz) 
    281294                        ver.insert() 
     295                        add_notice(req, _("The version '%(name)s' has been " 
     296                                          "added.", name=name)) 
    282297                        req.redirect(req.href.admin(cat, page)) 
    283298                    else: 
    284299                        raise TracError(_('Version %s already exists.') % name) 
     
    295310                        ver = model.Version(self.env, name, db=db) 
    296311                        ver.delete(db=db) 
    297312                    db.commit() 
     313                    add_notice(req, _("The selected versions have been " 
     314                                      "removed.")) 
    298315                    req.redirect(req.href.admin(cat, page)) 
    299316 
    300317                # Set default version 
     
    304321                        self.log.info('Setting default version to %s', name) 
    305322                        self.config.set('ticket', 'default_version', name) 
    306323                        self.config.save() 
     324                        add_notice(req, _("Your changes have been saved.")) 
    307325                        req.redirect(req.href.admin(cat, page)) 
    308326 
    309327            data = { 
     
    339357                if req.args.get('save'): 
    340358                    enum.name = req.args.get('name') 
    341359                    enum.update() 
     360                    add_notice(req, _("Your changes have been saved.")) 
    342361                    req.redirect(req.href.admin(cat, page)) 
    343362                elif req.args.get('cancel'): 
    344363                    req.redirect(req.href.admin(cat, page)) 
     
    357376                        enum = self._enum_cls(self.env) 
    358377                        enum.name = name 
    359378                        enum.insert() 
     379                        add_notice(req, _("The %(field)s '%(name)s' has been " 
     380                                          "added.", 
     381                                          field=self._label[0].lower(), 
     382                                          name=name)) 
    360383                        req.redirect(req.href.admin(cat, page)) 
    361384                    else: 
    362385                        raise TracError(_('%s %s already exists') % (self._type.title(), name)) 
     
    373396                        enum = self._enum_cls(self.env, name, db=db) 
    374397                        enum.delete(db=db) 
    375398                    db.commit() 
     399                    add_notice(req, _("The selected %(fields)s have been " 
     400                                      "removed.", 
     401                                      fields=self._label[1].lower())) 
    376402                    req.redirect(req.href.admin(cat, page)) 
    377403 
    378404                # Appy changes 
     
    403429                            enum.update(db=db) 
    404430                    db.commit() 
    405431 
     432                    add_notice(req, _("Your changes have been saved.")) 
    406433                    req.redirect(req.href.admin(cat, page)) 
    407434 
    408435            data.update(dict(enums=list(self._enum_cls.select(self.env)), 
  • trac/ticket/report.py

    diff --git a/trac/ticket/report.py b/trac/ticket/report.py
    a b  
    3434from trac.util.text import to_unicode, unicode_urlencode 
    3535from trac.util.translation import _ 
    3636from trac.web.api import IRequestHandler, RequestDone 
    37 from trac.web.chrome import add_ctxtnav, add_link, add_stylesheet, \ 
    38                             INavigationContributor, Chrome 
     37from trac.web.chrome import add_ctxtnav, add_link, add_notice, \ 
     38                            add_stylesheet, INavigationContributor, Chrome 
    3939from trac.wiki import IWikiSyntaxProvider, WikiParser 
    4040 
    4141 
     
    152152        cursor = db.cursor() 
    153153        cursor.execute("DELETE FROM report WHERE id=%s", (id,)) 
    154154        db.commit() 
     155        add_notice(req, _("The report has been deleted.")) 
    155156        req.redirect(req.href.report()) 
    156157 
    157158    def _do_save(self, req, db, id): 
     
    166167            cursor.execute("UPDATE report SET title=%s,query=%s,description=%s " 
    167168                           "WHERE id=%s", (title, query, description, id)) 
    168169            db.commit() 
     170            add_notice(req, _("Your changes have been saved.")) 
    169171        req.redirect(req.href.report(id)) 
    170172 
    171173    def _render_confirm_delete(self, req, db, id): 
  • trac/ticket/roadmap.py

    diff --git a/trac/ticket/roadmap.py b/trac/ticket/roadmap.py
    a b  
    3939from trac.ticket.query import Query 
    4040from trac.timeline.api import ITimelineEventProvider 
    4141from trac.web import IRequestHandler 
    42 from trac.web.chrome import add_link, add_stylesheet, add_warning, \ 
    43                             INavigationContributor 
     42from trac.web.chrome import add_link, add_notice, add_stylesheet, \ 
     43                            add_warning, INavigationContributor 
    4444from trac.wiki.api import IWikiSyntaxProvider 
    4545from trac.wiki.formatter import format_to 
    4646 
     47 
    4748class ITicketGroupStatsProvider(Interface): 
    4849    def get_ticket_group_stats(ticket_ids): 
    4950        """ Gather statistics on a group of tickets. 
     
    585586            retarget_to = req.args.get('target') or None 
    586587        milestone.delete(retarget_to, req.authname) 
    587588        db.commit() 
     589        add_notice(req, _("The milestone has been deleted.")) 
    588590        req.redirect(req.href.roadmap()) 
    589591 
    590592    def _do_save(self, req, db, milestone): 
     
    655657            milestone.insert() 
    656658        db.commit() 
    657659 
     660        add_notice(req, _("Your changes have been saved.")) 
    658661        req.redirect(req.href.milestone(milestone.name)) 
    659662 
    660663    def _render_confirm(self, req, db, milestone): 
  • trac/web/api.py

    diff --git a/trac/web/api.py b/trac/web/api.py
    a b  
    180180            'incookie': Request._parse_cookies, 
    181181            '_inheaders': Request._parse_headers 
    182182        } 
     183        self.redirect_handlers = [] 
    183184 
    184185        self.base_url = self.environ.get('trac.base_url') 
    185186        if not self.base_url: 
     
    223224    server_port = property(fget=lambda self: int(self.environ['SERVER_PORT']), 
    224225                           doc='Port number the server is bound to') 
    225226 
     227    def add_redirect_handler(self, handler): 
     228        """Add a callable to be called prior to executing a redirect. 
     229         
     230        The callable is passed the arguments to the `redirect()` call. 
     231        """ 
     232        self.redirect_handlers.append(handler) 
     233 
    226234    def get_header(self, name): 
    227235        """Return the value of the specified HTTP header, or `None` if there's 
    228236        no such header in the request. 
     
    290298        `url` may be relative or absolute, relative URLs will be translated 
    291299        appropriately. 
    292300        """ 
     301        for handler in self.redirect_handlers: 
     302            handler(self, url, permanent) 
     303         
    293304        if self.session: 
    294305            self.session.save() # has to be done before the redirect is sent 
    295306 
  • trac/web/chrome.py

    diff --git a/trac/web/chrome.py b/trac/web/chrome.py
    a b  
    1515# Author: Christopher Lenz <cmlenz@gmx.de> 
    1616 
    1717import datetime 
     18import itertools 
    1819import os.path 
    1920import pkg_resources 
    2021import pprint 
     
    436437 
    437438        chrome = {'links': {}, 'scripts': [], 'ctxtnav': [], 'warnings': [], 
    438439                  'notices': []} 
     440        def on_redirect(req, url, permanent): 
     441            """Save warnings and notices in case of redirect, so that they can 
     442            be displayed after the redirect.""" 
     443            for type_ in ['warnings', 'notices']: 
     444                for (i, message) in enumerate(req.chrome[type_]): 
     445                    req.session['chrome.%s.%d' % (type_, i)] = message 
     446        req.add_redirect_handler(on_redirect) 
    439447 
    440448        # This is ugly... we can't pass the real Request object to the 
    441449        # add_xxx methods, because it doesn't yet have the chrome attribute 
     
    707715        method = {'text/html': 'xhtml', 
    708716                  'text/plain': 'text'}.get(content_type, 'xml') 
    709717 
     718        if method == "xhtml": 
     719            # Retrieve post-redirect messages saved in session 
     720            for type_ in ['warnings', 'notices']: 
     721                try: 
     722                    for i in itertools.count(): 
     723                        req.chrome[type_].append( 
     724                            req.session.pop('chrome.%s.%d' % (type_, i))) 
     725                except KeyError: 
     726                    pass 
     727 
    710728        template = self.load_template(filename, method=method) 
    711729        data = self.populate_data(req, data) 
    712730 
  • trac/web/tests/chrome.py

    diff --git a/trac/web/tests/chrome.py b/trac/web/tests/chrome.py
    a b  
    5656 
    5757    def test_htdocs_location(self): 
    5858        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    59                    href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='') 
     59                   href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', 
     60                   add_redirect_handler=lambda handler: None) 
    6061        info = Chrome(self.env).prepare_request(req) 
    6162        self.assertEqual('/trac.cgi/chrome/common/', info['htdocs_location']) 
    6263 
    6364    def test_logo(self): 
    6465        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    65                    href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='') 
     66                   href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', 
     67                   add_redirect_handler=lambda handler: None) 
    6668 
    6769        # Verify that no logo data is put in the HDF if no logo is configured 
    6870        self.env.config.set('header_logo', 'src', '') 
     
    99101 
    100102    def test_default_links(self): 
    101103        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    102                    href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='') 
     104                   href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', 
     105                   add_redirect_handler=lambda handler: None) 
    103106        links = Chrome(self.env).prepare_request(req)['links'] 
    104107        self.assertEqual('/trac.cgi/wiki', links['start'][0]['href']) 
    105108        self.assertEqual('/trac.cgi/search', links['search'][0]['href']) 
     
    109112 
    110113    def test_icon_links(self): 
    111114        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    112                    href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='') 
     115                   href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='', 
     116                   add_redirect_handler=lambda handler: None) 
    113117        chrome = Chrome(self.env) 
    114118 
    115119        # No icon set in config, so no icon links 
     
    148152            def get_navigation_items(self, req): 
    149153                yield 'metanav', 'test', 'Test' 
    150154        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    151                    href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi') 
     155                   href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi', 
     156                   add_redirect_handler=lambda handler: None) 
    152157        nav = Chrome(self.env).prepare_request(req)['nav'] 
    153158        self.assertEqual({'name': 'test', 'label': 'Test', 'active': False}, 
    154159                         nav['metanav'][0]) 
     
    161166            def get_navigation_items(self, req): 
    162167                yield 'metanav', 'test', 'Test' 
    163168        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    164                    href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi') 
     169                   href=Href('/trac.cgi'), path_info='/', base_path='/trac.cgi', 
     170                   add_redirect_handler=lambda handler: None) 
    165171        handler = TestNavigationContributor(self.env) 
    166172        nav = Chrome(self.env).prepare_request(req, handler)['nav'] 
    167173        self.assertEqual({'name': 'test', 'label': 'Test', 'active': True}, 
     
    181187            def get_navigation_items(self, req): 
    182188                yield 'metanav', 'test2', 'Test 2' 
    183189        req = Mock(chrome={}, abs_href=Href('http://example.org/trac.cgi'), 
    184                    href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/') 
     190                   href=Href('/trac.cgi'), base_path='/trac.cgi', path_info='/', 
     191                   add_redirect_handler=lambda handler: None) 
    185192        chrome = Chrome(self.env) 
    186193 
    187194        # Test with both items set in the order option 
  • trac/wiki/web_ui.py

    diff --git a/trac/wiki/web_ui.py b/trac/wiki/web_ui.py
    a b  
    3636from trac.util.text import shorten_line 
    3737from trac.util.translation import _ 
    3838from trac.versioncontrol.diff import get_diff_options, diff_blocks 
    39 from trac.web.chrome import add_link, add_script, add_stylesheet, \ 
    40                             add_ctxtnav, add_warning, prevnext_nav, \ 
     39from trac.web.chrome import add_ctxtnav, add_link, add_notice, add_script, \ 
     40                            add_stylesheet, add_warning, prevnext_nav, \ 
    4141                            INavigationContributor, ITemplateProvider 
    4242from trac.web import IRequestHandler 
    4343from trac.wiki.api import IWikiPageManipulator, WikiSystem 
     
    254254        db.commit() 
    255255 
    256256        if not page.exists: 
     257            add_notice(req, _("The page '%(name)s' has been deleted.", 
     258                              name=page.name)) 
    257259            req.redirect(req.href.wiki()) 
    258260        else: 
     261            if version and old_version and version > old_version: 
     262                add_notice(req, _("The versions %(from_)d to %(to)d of the " 
     263                                  "page '%(name)s' have been deleted.", 
     264                                  from_=old_version + 1, to=version)) 
     265            else: 
     266                add_notice(req, _("The version %(version)d of the page " 
     267                                  "'%(name)s' has been deleted.", 
     268                                  version=version, name=page.name)) 
    259269            req.redirect(req.href.wiki(page.name)) 
    260270 
    261271    def _do_save(self, req, page): 
     
    276286            page.save(get_reporter_id(req, 'author'), 
    277287                            req.args.get('comment'), 
    278288                            req.remote_addr) 
     289            add_notice(req, _("Your changes have been saved.")) 
    279290            req.redirect(get_resource_url(self.env, page.resource, req.href, 
    280291                                          version=None)) 
    281292        except TracError: