changeset 1346:baafe28d8037

Merge with main.
author Alexander Schremmer <alex AT alexanderweb DOT de>
date Sun, 20 Aug 2006 15:58:49 +0200
parents 70e69aad1028 (current diff) f4558797325a (diff)
children 36dec228a83f 4d2dd952a513
files
diffstat 20 files changed, 185 insertions(+), 156 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/Page.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/Page.py	Sun Aug 20 15:58:49 2006 +0200
@@ -845,7 +845,7 @@
         self._raw_body = body
         self._raw_body_modified = modified
 
-    def url(self, request, querystr=None, escape=1):
+    def url(self, request, querystr=None, escape=1, anchor=None, relative=True):
         """ Return complete URL for this page, including scriptname
 
         @param request: the request object
@@ -853,13 +853,18 @@
             (str or dict, see wikiutil.makeQueryString)
         @param escape: escape url for html, to be backward compatible
             with old code (bool)
+        @param anchor: if specified, make a link to this anchor
         @rtype: str
         @return: complete url of this page, including scriptname
         """
-        url = '%s/%s' % (request.getScriptname(),
-                     wikiutil.quoteWikinameURL(self.page_name))
+        # Create url, excluding scriptname
+        url = wikiutil.quoteWikinameURL(self.page_name)
+        if querystr:
+            if isinstance(querystr, dict):
+                action = querystr.get('action', None)
+            else:
+                action = None # XXX we don't support getting the action out of a str
 
-        if querystr:
             querystr = wikiutil.makeQueryString(querystr)
 
             # TODO: remove in 2.0
@@ -872,10 +877,27 @@
                               " http://moinmoin.wikiwikiweb.de/ApiChanges")
                 querystr = wikiutil.escape(querystr)
 
+            # make action URLs denyable by robots.txt:
+            if action is not None and request.cfg.url_prefix_action is not None:
+                url = "%s/%s/%s" % (request.cfg.url_prefix_action, action, url)
             url = '%s?%s' % (url, querystr)
 
+        # Add anchor
+        if anchor:
+            url = "%s#%s" % (url, wikiutil.url_quote_plus(anchor))
+
+        if not relative:
+            url = '%s/%s' % (request.getScriptname(), url)
         return url
 
+    def link_to_raw(self, request, text, querystr=None, anchor=None, **kw):
+        """ core functionality of link_to, without the magic """
+        url = self.url(request, querystr, escape=0, anchor=anchor)
+        # escaping is done by link_tag -> formatter.url -> ._open()
+        link = wikiutil.link_tag(request, url, text,
+                                 formatter=getattr(self, 'formatter', None), **kw)
+        return link
+
     def link_to(self, request, text=None, querystr=None, anchor=None, **kw):
         """ Return HTML markup that links to this page.
 
@@ -893,27 +915,14 @@
         """
         if not text:
             text = self.split_title(request)
-
-        # Create url, excluding scriptname
-        url = wikiutil.quoteWikinameURL(self.page_name)
-        if querystr:
-            if not isinstance(querystr, type({})):
-                # makeQueryString does not escape strings any more
-                querystr = wikiutil.escape(querystr)
-                
-            querystr = wikiutil.makeQueryString(querystr)
-            url = "%s?%s" % (url, querystr)
-
-        # Add anchor
-        if anchor:
-            url = "%s#%s" % (url, wikiutil.url_quote_plus(anchor))
+        text = wikiutil.escape(text)
 
         # Add css class for non existing page
         if not self.exists():
             kw['css_class'] = 'nonexistent'
 
-        link = wikiutil.link_tag(request, url, wikiutil.escape(text),
-                                 formatter=getattr(self, 'formatter', None), **kw)
+        link = self.link_to_raw(request, text, querystr, anchor, **kw)
+
         # Create a link to attachments if any exist
         if kw.get('attachment_indicator', 0):
             from MoinMoin.action import AttachFile
@@ -1200,11 +1209,12 @@
 
             # send the page header
             if self.default_formatter:
-                full_text_query = 'linkto:"%s"' % self.page_name
-                link = '%s/%s?action=fullsearch&amp;value=%s&amp;context=180' % (
-                    request.getScriptname(),
-                    wikiutil.quoteWikinameURL(self.page_name),
-                    wikiutil.url_quote_plus(full_text_query))
+                querydict = {
+                    'action': 'fullsearch',
+                    'value': 'linkto:"%s"' % self.page_name,
+                    'context' : '180',
+                }
+                link = self.url(request, querydict)
 
                 title = self.split_title(request)
                 if self.rev:
--- a/MoinMoin/action/Despam.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/Despam.py	Sun Aug 20 15:58:49 2006 +0200
@@ -45,7 +45,12 @@
                        Column('pages', label=_("Pages"), align='right'),
                        Column('link', label='', align='left')]
     for nr, editor in editors:
-        dataset.addRow((editor, unicode(nr), pg.link_to(request, text=_("Select Author"), querystr="action=Despam&editor=%s" % wikiutil.url_quote_plus(editor))))
+        dataset.addRow((editor, unicode(nr),
+            pg.link_to(request, text=_("Select Author"),
+                querystr={
+                    'action': 'Despam',
+                    'editor': editor, # was: url_quote_plus()
+                })))
 
     table = DataBrowserWidget(request)
     table.setData(dataset)
--- a/MoinMoin/action/LocalSiteMap.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/LocalSiteMap.py	Sun Aug 20 15:58:49 2006 +0200
@@ -64,12 +64,14 @@
     def visit(self, request, name, depth):
         """ Visit a page, i.e. create a link.
         """
-        if not name: return
-        self.append('&nbsp;' * (5*depth))
-        self.append('&nbsp;' + wikiutil.link_tag(request, '%s?action=%s' %
-            (wikiutil.quoteWikinameURL(name), __name__.split('.')[-1]), name))
+        if not name:
+            return
+        pg = Page(request, name)
+        action = __name__.split('.')[-1]
+        self.append('&nbsp;' * (5*depth+1))
+        self.append(pg.link_to(request, name, querystr={'action': action}))
         self.append("&nbsp;<small>[")
-        self.append(Page(request, name).link_to(request, 'view'))
+        self.append(pg.link_to(request, 'view'))
         self.append("</small>]<br>")
 
     def append(self, text):
--- a/MoinMoin/action/RenderAsDocbook.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/RenderAsDocbook.py	Sun Aug 20 15:58:49 2006 +0200
@@ -8,7 +8,6 @@
 from MoinMoin.Page import Page
 
 def execute(pagename, request):
-    url = Page(request, pagename).url(request, {'action': 'show',
-                                                'mimetype': 'text/docbook'}, 0)
+    url = Page(request, pagename).url(request, {'action': 'show', 'mimetype': 'text/docbook'}, escape=0)
     request.http_redirect(url)
 
--- a/MoinMoin/action/SubscribeUser.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/SubscribeUser.py	Sun Aug 20 15:58:49 2006 +0200
@@ -74,7 +74,7 @@
             else:
                 result.append(formatter.smiley('{X}'))
                 result.append(formatter.text(" "))
-            result.append(formatter.url(1, Page(request, userobj.name).url(request)))
+            result.append(formatter.url(1, Page(request, userobj.name).url(request, escape=0)))
             result.append(formatter.text(userobj.name))
             result.append(formatter.url(0))
             result.append(formatter.linebreak(preformatted=0))
--- a/MoinMoin/action/__init__.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/__init__.py	Sun Aug 20 15:58:49 2006 +0200
@@ -277,7 +277,7 @@
 def do_goto(pagename, request):
     """ redirect to another page """
     target = request.form.get('target', [''])[0]
-    request.http_redirect(Page(request, target).url(request))
+    request.http_redirect(Page(request, target).url(request, escape=0))
 
 def do_userform(pagename, request):
     """ save data posted from UserPreferences """
--- a/MoinMoin/action/diff.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/diff.py	Sun Aug 20 15:58:49 2006 +0200
@@ -143,9 +143,11 @@
             if ignorews:
                 request.write(_('(ignoring whitespace)') + '<br>')
             else:
-                qstr = 'action=diff&ignorews=1'
-                if rev1: qstr = '%s&rev1=%s' % (qstr, rev1)
-                if rev2: qstr = '%s&rev2=%s' % (qstr, rev2)
+                qstr = {'action': 'diff', 'ignorews': '1', }
+                if rev1:
+                    qstr['rev1'] = str(rev1)
+                if rev2:
+                    qstr['rev2'] = str(rev2)
                 request.write(Page(request, pagename).link_to(request,
                     text=_('Ignore changes in the amount of whitespace'),
                     querystr=qstr, rel='nofollow') + '<p>')
--- a/MoinMoin/action/fullsearch.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/fullsearch.py	Sun Aug 20 15:58:49 2006 +0200
@@ -77,8 +77,7 @@
         if not page.attachment: # we did not find an attachment
             page = Page(request, page.page_name)
             # TODO: remove escape=0 in 2.0
-            url = page.url(request, querystr={'highlight': query.highlight_re()},
-                           escape=0)
+            url = page.url(request, querystr={'highlight': query.highlight_re()}, escape=0)
             request.http_redirect(url)
             return
 
--- a/MoinMoin/action/newpage.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/action/newpage.py	Sun Aug 20 15:58:49 2006 +0200
@@ -89,7 +89,7 @@
             if parent:
                 pagename = "%s/%s" % (parent, pagename)
 
-            url = Page(self.request, pagename).url(self.request, query, 0)
+            url = Page(self.request, pagename).url(self.request, query, escape=0)
             self.request.http_redirect(url)
 
         return ''
--- a/MoinMoin/config/multiconfig.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/config/multiconfig.py	Sun Aug 20 15:58:49 2006 +0200
@@ -420,8 +420,7 @@
     url_prefix_static = '/moin_static160'
 
     # we need to prefix actions to be able to exclude them by robots.txt:
-    # TODO:
-    # url_prefix_action = '/action'
+    url_prefix_action = 'action' # no leading or trailing '/'
 
     logo_string = None
     interwikiname = None
@@ -583,6 +582,10 @@
         if self.url_prefix is not None: # remove this code when url_prefix setting is removed
             self.url_prefix_static = self.url_prefix
 
+        action_prefix = self.url_prefix_action
+        if action_prefix is not None and action_prefix.endswith('/'): # make sure there is no trailing '/'
+            self.url_prefix_action = action_prefix[:-1]
+
     def load_meta_dict(self):
         """ The meta_dict contains meta data about the wiki instance. """
         if getattr(self, "_meta_dict", None) is None:
--- a/MoinMoin/macro/Action.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/macro/Action.py	Sun Aug 20 15:58:49 2006 +0200
@@ -66,11 +66,8 @@
         text = wikiutil.escape(text, 1)
 
         # Create link
-        formatter = self.macro.formatter
-        page = wikiutil.quoteWikinameURL(formatter.page.page_name)
-        url = '%s?action=%s' % (page, action)
-        link = wikiutil.link_tag(self.request, url, text=text,
-                                 formatter=formatter)
+        page = self.macro.formatter.page
+        link = page.link_to(self.request, text, querystr='action=%s' % action)
         return link
 
 
--- a/MoinMoin/macro/EditTemplates.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/macro/EditTemplates.py	Sun Aug 20 15:58:49 2006 +0200
@@ -15,23 +15,16 @@
     # Get list of template pages readable by current user
     filter = re.compile(self.request.cfg.page_template_regex, re.UNICODE).search
     templates = self.request.rootpage.getPageList(filter=filter)
-
+    result = []
     if templates:
         templates.sort()
-
+        page = self.formatter.page
         # send list of template pages
-        result = self.formatter.bullet_list(1)
-        for page in templates:
-            result = result +\
-                     self.formatter.listitem(1) +\
-                     wikiutil.link_tag(self.request, "%s?action=edit&amp;template=%s" % (
-                        wikiutil.quoteWikinameURL(self.formatter.page.page_name),
-                        wikiutil.quoteWikinameURL(page)), page
-                     ) + \
-                     self.formatter.listitem(0)
+        result.append(self.formatter.bullet_list(1))
+        for template in templates:
+            result.append(self.formatter.listitem(1))
+            result.append(page.link_to(self.request, template, querystr={'action': 'edit', 'template': template}))
+            result.append(self.formatter.listitem(0))
+        result.append(self.formatter.bullet_list(0))
+    return ''.join(result)
 
-        result = result + self.formatter.bullet_list(0)
-        return result
-
-    return ''
-
--- a/MoinMoin/macro/MonthCalendar.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/macro/MonthCalendar.py	Sun Aug 20 15:58:49 2006 +0200
@@ -312,10 +312,10 @@
     qpagenames = '*'.join(map(wikiutil.quoteWikinameURL, parmpagename))
     qtemplate = wikiutil.quoteWikinameURL(parmtemplate)
     querystr = "calparms=%%s,%d,%d,%d,%%d,%%s" % (parmyear, parmmonth, parmoffset)
-    prevlink = p.url(request, querystr % (qpagenames, parmoffset2 - 1, qtemplate), 0)
-    nextlink = p.url(request, querystr % (qpagenames, parmoffset2 + 1, qtemplate), 0)
-    prevylink = p.url(request, querystr % (qpagenames, parmoffset2 - 12, qtemplate), 0)
-    nextylink = p.url(request, querystr % (qpagenames, parmoffset2 + 12, qtemplate), 0)
+    prevlink = p.url(request, querystr % (qpagenames, parmoffset2 - 1, qtemplate), escape=0)
+    nextlink = p.url(request, querystr % (qpagenames, parmoffset2 + 1, qtemplate), escape=0)
+    prevylink = p.url(request, querystr % (qpagenames, parmoffset2 - 12, qtemplate), escape=0)
+    nextylink = p.url(request, querystr % (qpagenames, parmoffset2 + 12, qtemplate), escape=0)
     prevmonth = formatter.url(1, prevlink, 'cal-link') + '&lt;' + formatter.url(0)
     nextmonth = formatter.url(1, nextlink, 'cal-link') + '&gt;' + formatter.url(0)
     prevyear = formatter.url(1, prevylink, 'cal-link') + '&lt;&lt;' + formatter.url(0)
@@ -428,7 +428,7 @@
                             r, g, b = (r, g+colorstep, b)
                 r, g, b = cliprgb(r, g, b)
                 style = 'background-color:#%02x%02x%02x' % (r, g, b)
-                fmtlink = formatter.url(1, daypage.url(request, query), csslink, **onmouse) + str(day) + formatter.url(0)
+                fmtlink = formatter.url(1, daypage.url(request, query, escape=0), csslink, **onmouse) + str(day) + formatter.url(0)
                 if day == currentday and month == currentmonth and year == currentyear:
                     cssday = "cal-today"
                     fmtlink = "<b>%s</b>" % fmtlink # for browser with CSS probs
--- a/MoinMoin/macro/Navigation.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/macro/Navigation.py	Sun Aug 20 15:58:49 2006 +0200
@@ -64,7 +64,7 @@
     """
 
     # querystring for slideshow links
-    PROJECTION = 'action=print&media=projection'
+    PROJECTION = {'action': 'print', 'media': 'projection', }
 
     def __init__(self, macro, args):
         """ Prepare common values used during processing.
@@ -76,7 +76,7 @@
         self.pagename = self.macro.formatter.page.page_name
         self.print_mode = self.macro.request.action == 'print'
         self.media = self.macro.request.form.get('media', [None])[0]
-        self.querystr = self.print_mode and self.PROJECTION or ''
+        self.querystr = self.print_mode and self.PROJECTION or {}
 
 
     def dispatch(self):
@@ -113,6 +113,7 @@
         """ Navigate from a subpage to its siblings.
         """
         _ = self._
+        request = self.macro.request
         # get parent page name
         parent = root or _getParent(self.pagename)
         if not parent:
@@ -127,7 +128,7 @@
 
         # iterate over children, adding links to all of them
         result = []
-        children = _getPages(self.macro.request, '^%s/' % parent)
+        children = _getPages(request, '^%s/' % parent)
         for child in children:
             # display short page name, leaving out the parent path
             # (and make sure the name doesn't get wrapped)
@@ -142,7 +143,7 @@
                 result.append(self.macro.formatter.text(shortname))
             else:
                 # link to sibling / child
-                result.append(Page(self.macro.request, child).link_to(self.macro.request, text=shortname, querystr=self.querystr))
+                result.append(Page(request, child).link_to(request, text=shortname, querystr=self.querystr))
             result.append(' &nbsp; ')
 
         return ''.join(result)
@@ -157,12 +158,13 @@
         _ = self._
         curpage = focus or self.pagename
         result = []
-
+        request = self.macro.request
+        pg = Page(request, curpage)
         if self.print_mode:
             # projection mode
             label = _('Wiki')
-            toggle = ''
-            result.append(Page(self.macro.request, curpage).link_to(self.macro.request, text=_('Edit'), querystr='action=edit'))
+            toggle = {}
+            result.append(pg.link_to(request, text=_('Edit'), querystr={'action': 'edit'}))
             result.append(' &nbsp; ')
         else:
             # wiki mode
@@ -170,15 +172,15 @@
             toggle = self.PROJECTION
 
         # add mode toggle link
-        result.append(Page(self.macro.request, curpage).link_to(self.macro.request, text=label, querystr=toggle))
+        result.append(pg.link_to(request, text=label, querystr=toggle))
 
         # leave out the following on slide pages
         if focus is None:
-            children = _getPages(self.macro.request, '^%s/' % self.pagename)
+            children = _getPages(request, '^%s/' % self.pagename)
             if children:
                 # add link to first child if one exists
                 result.append(' &nbsp; ')
-                result.append(Page(self.macro.request, children[0]).link_to(self.macro.request, text=_('Start'), querystr=self.querystr))
+                result.append(Page(request, children[0]).link_to(request, text=_('Start'), querystr=self.querystr))
 
         return ''.join(result)
 
@@ -187,6 +189,7 @@
         """ Navigate within a slide show.
         """
         _ = self._
+        request = self.macro.request
         parent = root or _getParent(self.pagename)
         if not parent:
             return (self.macro.formatter.sysmsg(1) +
@@ -197,7 +200,7 @@
         result = []
         labels = ['^', '|<', '<<', '>>', '>|']
         filter_regex = '^%s/' % re.escape(parent)
-        pos, size, links = _getLinks(self.macro.request, self.pagename, filter_regex)
+        pos, size, links = _getLinks(request, self.pagename, filter_regex)
         pos += 1
         links = zip(labels, (parent,) + links)
 
@@ -206,7 +209,7 @@
             result.append(' ')
             if name:
                 # active link
-                result.append(Page(self.macro.request, name).link_to(self.macro.request, text=label, querystr=self.querystr))
+                result.append(Page(request, name).link_to(request, text=label, querystr=self.querystr))
             else:
                 # ghosted link
                 result.append(self.macro.formatter.text(label))
--- a/MoinMoin/macro/RecentChanges.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/macro/RecentChanges.py	Sun Aug 20 15:58:49 2006 +0200
@@ -54,36 +54,29 @@
     is_new = lines[-1].action == 'SAVENEW'
     # check whether this page is newer than the user's bookmark
     hilite = line.ed_time_usecs > (bookmark_usecs or line.ed_time_usecs)
-    page = Page(request, line.pagename)
+    page = Page(request, pagename)
 
     html_link = ''
     if not page.exists():
         # indicate page was deleted
-        html_link = request.theme.make_icon('deleted')
+        html_link = request.theme.make_icon('deleted') # TODO: we could link to the last existing rev here
     elif page.isConflict():
         img = macro.formatter.smiley("/!\\")
         #img = request.theme.make_icon('help')
-        html_link = wikiutil.link_tag(request,
-                                      wikiutil.quoteWikinameURL(pagename) + "?action=edit",
-                                      img, formatter=macro.formatter, rel="nofollow")
+        html_link = page.link_to_raw(request, img, querystr={'action': 'edit'}, rel='nofollow')
     elif is_new:
         # show "NEW" icon if page was created after the user's bookmark
         if hilite:
             img = request.theme.make_icon('new')
-            html_link = wikiutil.link_tag(request, wikiutil.quoteWikinameURL(pagename),
-                                          img, formatter=macro.formatter, rel="nofollow")
+            html_link = page.link_to_raw(request, img, rel='nofollow')
     elif hilite:
         # show "UPDATED" icon if page was edited after the user's bookmark
         img = request.theme.make_icon('updated')
-        html_link = wikiutil.link_tag(request,
-                                      wikiutil.quoteWikinameURL(pagename) + "?action=diff&date=%d" % bookmark_usecs,
-                                      img, formatter=macro.formatter, rel="nofollow")
+        html_link = page.link_to_raw(request, img, querystr={'action': 'diff', 'date': '%d' % bookmark_usecs}, rel='nofollow')
     else:
         # show "DIFF" icon else
         img = request.theme.make_icon('diffrc')
-        html_link = wikiutil.link_tag(request,
-                                      wikiutil.quoteWikinameURL(line.pagename) + "?action=diff",
-                                      img, formatter=macro.formatter, rel="nofollow")
+        html_link = page.link_to_raw(request, img, querystr={'action': 'diff'}, rel='nofollow')
 
     # print name of page, with a link to it
     force_split = len(page.page_name) > _MAX_PAGENAME_LENGTH
@@ -131,10 +124,7 @@
     d['comments'] = comments
 
     img = request.theme.make_icon('info')
-    info_html = wikiutil.link_tag(request,
-                                  wikiutil.quoteWikinameURL(line.pagename) + "?action=info",
-                                  img, formatter=macro.formatter, rel="nofollow")
-    d['info_html'] = info_html
+    d['info_html'] = page.link_to_raw(request, img, querystr={'action': 'info'}, rel='nofollow')
 
     return request.theme.recentchanges_entry(d)
 
@@ -256,17 +246,11 @@
             currentBookmark = wikiutil.version2timestamp(bookmark_usecs)
             currentBookmark = user.getFormattedDateTime(currentBookmark)
             currentBookmark = _('(currently set to %s)') % currentBookmark
-
-            url = wikiutil.quoteWikinameURL(pagename) + "?action=bookmark&time=del"
-            deleteBookmark = wikiutil.link_tag(request, url, _("Delete Bookmark"),
-                                               formatter=macro.formatter, rel="nofollow")
+            deleteBookmark = page.link_to(request, _("Delete bookmark"), querystr={'action': 'bookmark', 'time': 'del'}, rel='nofollow')
             d['rc_curr_bookmark'] = currentBookmark + ' ' + deleteBookmark
 
         version = wikiutil.timestamp2version(tnow)
-        url = wikiutil.quoteWikinameURL(pagename) + \
-            "?action=bookmark&time=%d" % version
-        d['rc_update_bookmark'] = wikiutil.link_tag(request, url, _("Set bookmark"),
-                                                    formatter=macro.formatter, rel="nofollow")
+        d['rc_update_bookmark'] = page.link_to(request, _("Set bookmark"), querystr={'action': 'bookmark', 'time': '%d' % version}, rel='nofollow')
 
     # set max size in days
     max_days = min(int(request.form.get('max_days', [0])[0]), _DAYS_SELECTION[-1])
@@ -302,26 +286,22 @@
         if ((this_day != day or (not hilite and not max_days))) and len(pages) > 0:
             # new day or bookmark reached: print out stuff 
             this_day = day
-            for page in pages:
-                ignore_pages[page] = None
+            for p in pages:
+                ignore_pages[p] = None
             pages = pages.values()
             pages.sort(cmp_lines)
             pages.reverse()
 
             if request.user.valid:
-                d['bookmark_link_html'] = wikiutil.link_tag(
-                    request,
-                    wikiutil.quoteWikinameURL(
-                        macro.formatter.page.page_name) + "?action=bookmark&time=%d" % (pages[0][0].ed_time_usecs,),
-                        _("set bookmark"),
-                        formatter=macro.formatter, rel="nofollow")
+                bmtime = pages[0][0].ed_time_usecs
+                d['bookmark_link_html'] = page.link_to(request, _("Set bookmark"), querystr={'action': 'bookmark', 'time': '%d' % bmtime}, rel='nofollow')
             else:
                 d['bookmark_link_html'] = None
             d['date'] = request.user.getFormattedDate(wikiutil.version2timestamp(pages[0][0].ed_time_usecs))
             request.write(request.theme.recentchanges_daybreak(d))
 
-            for page in pages:
-                request.write(format_page_edits(macro, page, bookmark_usecs))
+            for p in pages:
+                request.write(format_page_edits(macro, p, bookmark_usecs))
             pages = {}
             day_count += 1
             if max_days and (day_count >= max_days):
@@ -348,26 +328,22 @@
             # end of loop reached: print out stuff 
             # XXX duplicated code from above
             # but above does not trigger if we have the first day in wiki history
-            for page in pages:
-                ignore_pages[page] = None
+            for p in pages:
+                ignore_pages[p] = None
             pages = pages.values()
             pages.sort(cmp_lines)
             pages.reverse()
 
             if request.user.valid:
-                d['bookmark_link_html'] = wikiutil.link_tag(
-                    request,
-                    wikiutil.quoteWikinameURL(
-                        macro.formatter.page.page_name) + "?action=bookmark&time=%d" % (pages[0][0].ed_time_usecs,),
-                        _("Set bookmark"),
-                        formatter=macro.formatter, rel="nofollow")
+                bmtime = pages[0][0].ed_time_usecs
+                d['bookmark_link_html'] = page.link_to(request, _("Set bookmark"), querystr={'action': 'bookmark', 'time': '%d' % bmtime}, rel='nofollow')
             else:
                 d['bookmark_link_html'] = None
             d['date'] = request.user.getFormattedDate(wikiutil.version2timestamp(pages[0][0].ed_time_usecs))
             request.write(request.theme.recentchanges_daybreak(d))
 
-            for page in pages:
-                request.write(format_page_edits(macro, page, bookmark_usecs))
+            for p in pages:
+                request.write(format_page_edits(macro, p, bookmark_usecs))
 
 
     d['rc_msg'] = msg
--- a/MoinMoin/request/__init__.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/request/__init__.py	Sun Aug 20 15:58:49 2006 +0200
@@ -1060,6 +1060,18 @@
 
             # The last component in path_info is the page name, if any
             path = self.getPathinfo()
+
+            # we can have all action URLs like this: /action/ActionName/PageName?action=ActionName&...
+            # this is just for robots.txt being able to forbid them for crawlers
+            prefix = self.cfg.url_prefix_action
+            if prefix is not None:
+                prefix = '/%s/' % prefix # e.g. '/action/'
+                if path.startswith(prefix):
+                    # remove prefix and action name
+                    path = path[len(prefix):]
+                    action, path = path.split('/', 1)
+                    path = '/' + path
+
             if path.startswith('/'):
                 pagename = self.normalizePagename(path)
             else:
@@ -1094,10 +1106,10 @@
                         wikitag, wikiurl, wikitail, error = wikiutil.resolve_wiki(self, pagetrail[-1])
                         url = wikiurl + wikiutil.quoteWikinameURL(wikitail)
                     else:
-                        url = Page(self, pagetrail[-1]).url(self)
+                        url = Page(self, pagetrail[-1]).url(self, escape=0)
                 else:
                     # Or to localized FrontPage
-                    url = wikiutil.getFrontPage(self).url(self)
+                    url = wikiutil.getFrontPage(self).url(self, escape=0)
                 self.http_redirect(url)
                 return self.finish()
 
--- a/MoinMoin/theme/__init__.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/theme/__init__.py	Sun Aug 20 15:58:49 2006 +0200
@@ -524,9 +524,7 @@
 
         if isinstance(msg, (str, unicode)):
             # Render simple strings with a close link
-            close = d['page'].link_to(self.request,
-                                      text=_('Clear message'),
-                                      querystr={'action': 'show'})
+            close = d['page'].link_to(self.request, text=_('Clear message'))
             html = u'<p>%s</p>\n<div class="buttons">%s</div>\n' % (msg, close)
         else:
             # msg is a widget
@@ -1160,10 +1158,10 @@
         _ = self.request.getText
         return """\
 <script type="text/javascript">
-var gui_editor_link_href = "%(url)s?action=edit&editor=gui";
+var gui_editor_link_href = "%(url)s";
 var gui_editor_link_text = "%(text)s";
 </script>        
-""" % {'url': page.url(self.request),
+""" % {'url': page.url(self.request, querystr={'action': 'edit', 'editor': 'gui', }, escape=0),
        'text': _('Edit (GUI)', formatted=False),
       }
 
--- a/MoinMoin/wikiutil.py	Sun Aug 20 15:58:33 2006 +0200
+++ b/MoinMoin/wikiutil.py	Sun Aug 20 15:58:49 2006 +0200
@@ -191,7 +191,7 @@
     """
     if qstr is None:
         qstr = {}
-    if isinstance(qstr, type({})):
+    if isinstance(qstr, dict):
         qstr.update(kw)
         items = ['%s=%s' % (url_quote_plus(key, want_unicode=want_unicode), url_quote_plus(value, want_unicode=want_unicode)) for key, value in qstr.items()]
         qstr = '&'.join(items)
@@ -1458,6 +1458,8 @@
     @rtype: string
     @return: formatted link tag
     """
+    if formatter is None:
+        formatter = request.html_formatter
     if kw.has_key('css_class'):
         css_class = kw['css_class']
         del kw['css_class'] # one time is enough
@@ -1469,26 +1471,29 @@
         text = params # default
     if formatter:
         url = "%s/%s" % (request.getScriptname(), params)
+        # formatter.url will escape the url part
         if on is not None:
-            return formatter.url(on, url, css_class, **kw)
-        return (formatter.url(1, url, css_class, **kw) +
+            tag = formatter.url(on, url, css_class, **kw)
+        else:
+            tag = (formatter.url(1, url, css_class, **kw) +
                 formatter.rawHTML(text) +
                 formatter.url(0))
-    if on is not None and not on:
-        return '</a>'
-
-    attrs = ''
-    if css_class:
-        attrs += ' class="%s"' % css_class
-    if id:
-        attrs += ' id="%s"' % id
-    if name:
-        attrs += ' name="%s"' % name
-    result = '<a%s href="%s/%s">' % (attrs, request.getScriptname(), params)
-    if on:
-        return result
-    else:
-        return "%s%s</a>" % (result, text)
+    else: # this shouldn't be used any more:
+        if on is not None and not on:
+            tag = '</a>'
+        else:
+            attrs = ''
+            if css_class:
+                attrs += ' class="%s"' % css_class
+            if id:
+                attrs += ' id="%s"' % id
+            if name:
+                attrs += ' name="%s"' % name
+            tag = '<a%s href="%s/%s">' % (attrs, request.getScriptname(), params) # XXX wikiutil.escape(params) !?
+            if not on:
+                tag = "%s%s</a>" % (tag, text)
+        request.log("Warning: wikiutil.link_tag called without formatter and without request.html_formatter. tag=%r" % (tag, ))
+    return tag
 
 def containsConflictMarker(text):
     """ Returns true if there is a conflict marker in the text. """
--- a/docs/CHANGES	Sun Aug 20 15:58:33 2006 +0200
+++ b/docs/CHANGES	Sun Aug 20 15:58:49 2006 +0200
@@ -225,11 +225,33 @@
       1. The setting is now called url_prefix_static (to make it more clear
          that we mean the static stuff, not the wiki script url).
       2. The strongly recommended (and default) value of it is '/moin_static160'
-         for moin version 1.6.0 (and will be ...161 for moin 1.6.1). We use a
-         very long cache lifetime for static stuff now, so it is required to
-         change the URL of static stuff when the static stuff changes (e.g. on
-         a version upgrade of moin) to avoid problems with stale cache content.
+         for moin version 1.6.0 (and will be ...161 for moin 1.6.1). It is
+         possible and recommended to use a very long cache lifetime for static
+         stuff now (Expires: access plus 1 year), because we require to change
+         the URL of static stuff when the static stuff changes (e.g. on a
+         version upgrade of moin) to avoid problems with stale cache content.
          Your moin will be faster with lower load and traffic because of this.
+         For standalone server, we use 1 year expiry for static stuff now.
+         For Apache, Lighttpd and other "external" servers, you have to care
+         for configuring them to use a long expiry and change url_prefix_static
+         related configuration on upgrade.
+    * url_prefix_action ['action'] was introduced for lowering load and traffic
+      caused by searchengine crawlers. Up to now, crawlers where causing a high
+      load in internet moin wikis because they tried to get about everything,
+      including all actions linked from the user interface.
+      Known crawlers only get 403 for most actions, but nevertheless they first
+      tried. There was no means keeping them away from actions due to the rather
+      braindead robots.txt standard. You can only disallow pathes there, but
+      moin's actions were querystring based, not path based (this would need
+      regex support in robots.txt, but there is no such thing).
+      This changed now. Moin will now generate action URLs you can handle in
+      robots.txt, like /action/info/PageName?action=info. So if you don't want
+      bots triggering actions, just disallow /action/ there. Keep in mind that
+      attachments are handled by /action/AttachFile, so if you want attached
+      files and pictures indexed by search engine, don't disallow
+      /action/AttachFile/ in your robots.txt.
+    * We don't use ...?action=show any more for the "Clear message" links shown
+      in the message boxes, but directly link to the page.
 
 Version 1.5-current:
    * moin.fcg improved - if you use FastCGI, you must use the new file:
--- a/wiki/htdocs/robots.txt	Sun Aug 20 15:58:33 2006 +0200
+++ b/wiki/htdocs/robots.txt	Sun Aug 20 15:58:49 2006 +0200
@@ -2,5 +2,8 @@
 
 User-agent: *
 Crawl-delay: 20
-Disallow:
+# This has to match script url + cfg.url_prefix_action - it
+# saves lots of search engine load and traffic by disallowing crawlers
+# to request action related URLs:
+Disallow: /action/