changeset 313:8fa4a76d71ff

cleanup interwiki code, new easier/more powerful functions removed crappy resolve_interwiki added is_known_wiki(wiki_name) - check if <wiki_name> is in the interwiki_map added is_local_wiki(wiki_name) - check if <wiki_name> is THIS wiki new powerful url_for_item(...) function, that is somehow similar to url_for, but also includes computing interwiki URLs. It either can compute standard interwiki URLs (for default item views of any remote wiki) or special interwiki URLs (for specific revs/endpoints for remote moin wikis, like in a farm). link converter refactored so it uses url_for_item()
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Fri, 05 Aug 2011 13:18:23 +0200
parents 23a6a6b85d4c
children f39b2747ac16
files MoinMoin/converter/link.py MoinMoin/converter/moinwiki19_in.py MoinMoin/converter/moinwiki_in.py MoinMoin/themes/__init__.py MoinMoin/user.py MoinMoin/util/_tests/test_interwiki.py MoinMoin/util/interwiki.py
diffstat 7 files changed, 111 insertions(+), 101 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/converter/link.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/converter/link.py	Fri Aug 05 13:18:23 2011 +0200
@@ -13,7 +13,7 @@
 
 from flask import g as flaskg
 
-from MoinMoin.util.interwiki import resolve_interwiki, join_wiki
+from MoinMoin.util.interwiki import is_known_wiki, url_for_item
 from MoinMoin.util.iri import Iri, IriPath
 from MoinMoin.util.mime import Type, type_moin_document
 from MoinMoin.util.tree import html, moin_page, xlink, xinclude
@@ -110,6 +110,8 @@
         """
         get 'do' and 'rev' values from query string and remove them from querystring
 
+        at the end, we translate the 'do' value to a werkzeug endpoint.
+
         Note: we can't use url_decode/url_encode from e.g. werkzeug because
               url_encode quotes the qs values (and Iri code will quote them again)
         """
@@ -138,62 +140,42 @@
             query = None
         if revno is not None:
             revno = int(revno)
-        return do, revno, query
+        do_to_endpoint = dict(
+            show='frontend.show_item',
+            modify='frontend.modify_item',
+            # ...
+        )
+        endpoint = do_to_endpoint[do or 'show']
+        return endpoint, revno, query
 
     def handle_wiki_links(self, elem, input):
-        do, revno, query = self._get_do_rev(input.query)
-        link = Iri(query=query, fragment=input.fragment)
-
+        wiki_name = 'Self'
         if input.authority and input.authority.host:
-            # interwiki link
-            wikitag, wikiurl, wikitail, err = resolve_interwiki(unicode(input.authority.host), unicode(input.path[1:]))
-            if not err:
+            wn = unicode(input.authority.host)
+            if is_known_wiki(wn):
+                # interwiki link
                 elem.set(html.class_, 'moin-interwiki')
-                if do is not None:
-                    # this will only work for wikis with compatible URL design
-                    # for other wikis, don't use do=... in your interwiki links
-                    wikitail = '/+' + do + wikitail
-                base = Iri(join_wiki(wikiurl, wikitail))
-            else:
-                # TODO (for now, we just link to Self:item_name in case of
-                # errors, see code below)
-                pass
-        else:
-            err = False
-
-        if not input.authority or err:
-            # local wiki link
-            path = input.path[1:]
-            if revno is not None:
-                path = IriPath('%d/' % revno) + path
-            if do is not None:
-                path = IriPath('+%s/' % do) + path
-            link.path = path
-            base = self.url_root
-
-        elem.set(self._tag_xlink_href, base + link)
+                wiki_name = wn
+        item_name = unicode(input.path[1:])
+        endpoint, revno, query = self._get_do_rev(input.query)
+        url = url_for_item(item_name, wiki_name=wiki_name, rev=revno, endpoint=endpoint)
+        link = Iri(url, query=query, fragment=input.fragment)
+        elem.set(self._tag_xlink_href, link)
 
     def handle_wikilocal_links(self, elem, input, page):
-        do, revno, query = self._get_do_rev(input.query)
-        link = Iri(query=query, fragment=input.fragment)
-
         if input.path:
+            # this can be a relative path, make it absolute:
             path = input.path
             path = self.absolute_path(path, page.path)
-
-            if not flaskg.storage.has_item(unicode(path)):
+            item_name = unicode(path)
+            if not flaskg.storage.has_item(item_name):
                 elem.set(html.class_, 'moin-nonexistent')
         else:
-            path = page.path[1:]
-
-        if revno is not None:
-            path = IriPath('%d/' % revno) + path
-        if do is not None:
-            path = IriPath('+%s/') + path
-        link.path = path
-        output = self.url_root + link
-
-        elem.set(self._tag_xlink_href, output)
+            item_name = unicode(page.path[1:])
+        endpoint, revno, query = self._get_do_rev(input.query)
+        url = url_for_item(item_name, rev=revno, endpoint=endpoint)
+        link = Iri(url, query=query, fragment=input.fragment)
+        elem.set(self._tag_xlink_href, link)
 
 
 class ConverterItemRefs(ConverterBase):
--- a/MoinMoin/converter/moinwiki19_in.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/converter/moinwiki19_in.py	Fri Aug 05 13:18:23 2011 +0200
@@ -17,7 +17,7 @@
 logging = log.getLogger(__name__)
 
 from MoinMoin import config, wikiutil
-from MoinMoin.util.interwiki import resolve_interwiki
+from MoinMoin.util.interwiki import is_known_wiki
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.tree import html, moin_page, xlink
 
@@ -103,8 +103,7 @@
             text = freelink_email
 
         else:
-            wikitag_bad = resolve_interwiki(freelink_interwiki_ref, freelink_interwiki_page)[3]
-            if wikitag_bad:
+            if not is_known_wiki(freelink_interwiki_ref):
                 stack.top_append(freelink)
                 return
 
--- a/MoinMoin/converter/moinwiki_in.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/converter/moinwiki_in.py	Fri Aug 05 13:18:23 2011 +0200
@@ -21,7 +21,7 @@
 from MoinMoin import config
 from MoinMoin.util.iri import Iri
 from MoinMoin.util.tree import html, moin_page, xlink, xinclude
-from MoinMoin.util.interwiki import resolve_interwiki
+from MoinMoin.util.interwiki import is_known_wiki
 from MoinMoin.i18n import _
 
 from ._args import Arguments
@@ -786,8 +786,7 @@
             link_interwiki_site=None, link_interwiki_item=None):
         """Handle all kinds of links."""
         if link_interwiki_site:
-            err = resolve_interwiki(link_interwiki_site, link_interwiki_item)[3]
-            if not err:
+            if is_known_wiki(link_interwiki_site):
                 link = Iri(scheme='wiki',
                         authority=link_interwiki_site,
                         path='/' + link_interwiki_item)
--- a/MoinMoin/themes/__init__.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/themes/__init__.py	Fri Aug 05 13:18:23 2011 +0200
@@ -21,7 +21,7 @@
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin import wikiutil, user
 from MoinMoin.config import USERID, ADDRESS, HOSTNAME
-from MoinMoin.util.interwiki import split_interwiki, resolve_interwiki, join_wiki, getInterwikiHome
+from MoinMoin.util.interwiki import split_interwiki, getInterwikiHome, is_local_wiki, is_known_wiki, url_for_item
 from MoinMoin.util.crypto import cache_key
 from MoinMoin.util.forms import make_generator
 
@@ -103,9 +103,9 @@
         trail = user.getTrail()
         for interwiki_item_name in trail:
             wiki_name, item_name = split_interwiki(interwiki_item_name)
-            wiki_name, wiki_base_url, item_name, err = resolve_interwiki(wiki_name, item_name)
-            href = join_wiki(wiki_base_url, item_name)
-            if wiki_name in [self.cfg.interwikiname, 'Self', ]:
+            err = not is_known_wiki(wiki_name)
+            href = url_for_item(item_name, wiki_name=wiki_name)
+            if is_local_wiki(wiki_name):
                 exists = self.storage.has_item(item_name)
                 wiki_name = ''  # means "this wiki" for the theme code
             else:
@@ -129,13 +129,12 @@
         wikiname, itemname = getInterwikiHome(name)
         title = "%s @ %s" % (aliasname, wikiname)
         # link to (interwiki) user homepage
-        if wikiname == "Self":
+        if is_local_wiki(wikiname):
             exists = self.storage.has_item(itemname)
         else:
             # We cannot check if wiki pages exists in remote wikis
             exists = True
-        wiki_name, wiki_base_url, item_name, err = resolve_interwiki(wikiname, itemname)
-        wiki_href = join_wiki(wiki_base_url, item_name)
+        wiki_href = url_for_item(itemname, wiki_name=wikiname)
         return wiki_href, aliasname, title, exists
 
     def split_navilink(self, text):
@@ -183,9 +182,8 @@
 
         # try handling interwiki links
         wiki_name, item_name = split_interwiki(target)
-        wiki_name, wiki_base_url, item_name, err = resolve_interwiki(wiki_name, item_name)
-        href = join_wiki(wiki_base_url, item_name)
-        if wiki_name not in [self.cfg.interwikiname, 'Self', ]:
+        href = url_for_item(item_name, wiki_name=wiki_name)
+        if not is_local_wiki(wiki_name):
             if not title:
                 title = item_name
             return href, title, wiki_name
@@ -219,7 +217,7 @@
 
         # Add sister pages (see http://usemod.com/cgi-bin/mb.pl?SisterSitesImplementationGuide )
         for sistername, sisterurl in self.cfg.sistersites:
-            if sistername == self.cfg.interwikiname:  # it is THIS wiki
+            if is_local_wiki(sistername):
                 items.append(('sisterwiki current', sisterurl, sistername))
             else:
                 cid = cache_key(usage="SisterSites", sistername=sistername)
@@ -318,14 +316,11 @@
             css = 'editor mail'
         else:
             homewiki = app.cfg.user_homewiki
-            if homewiki in ('Self', app.cfg.interwikiname):
-                homewiki = u'Self'
+            if is_local_wiki(homewiki):
                 css = 'editor homepage local'
-                uri = url_for('frontend.show_item', item_name=name, _external=external)
             else:
                 css = 'editor homepage interwiki'
-                wt, wu, tail, err = resolve_interwiki(homewiki, name)
-                uri = join_wiki(wu, tail)
+            uri = url_for_item(name, wiki_name=homewiki, _external=external)
 
     result = dict(name=name, text=text, css=css, title=title)
     if uri:
--- a/MoinMoin/user.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/user.py	Fri Aug 05 13:18:23 2011 +0200
@@ -30,7 +30,7 @@
 
 from MoinMoin import config, wikiutil
 from MoinMoin.i18n import _, L_, N_
-from MoinMoin.util.interwiki import getInterwikiHome
+from MoinMoin.util.interwiki import getInterwikiHome, is_local_wiki
 from MoinMoin.util.crypto import crypt_password, upgrade_password, valid_password, \
                                  generate_token, valid_token
 
@@ -731,7 +731,7 @@
             it doesn't matter whether it already exists or not.
         """
         wikiname, pagename = getInterwikiHome(self.name)
-        if wikiname == 'Self':
+        if is_local_wiki(wikiname):
             markup = '[[%s]]' % pagename
         else:
             markup = '[[%s:%s]]' % (wikiname, pagename)
--- a/MoinMoin/util/_tests/test_interwiki.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/util/_tests/test_interwiki.py	Fri Aug 05 13:18:23 2011 +0200
@@ -14,7 +14,7 @@
 import os.path
 import shutil
 
-from MoinMoin.util.interwiki import resolve_interwiki, split_interwiki, join_wiki, InterWikiMap
+from MoinMoin.util.interwiki import split_interwiki, join_wiki, InterWikiMap
 from MoinMoin._tests import wikiconfig
 
 
@@ -41,12 +41,6 @@
         for (baseurl, pagename), url in tests:
             assert join_wiki(baseurl, pagename) == url
 
-    def testResolveInterWiki(self):
-        result = resolve_interwiki('MoinMoin', 'SomePage')
-        assert result == ('MoinMoin', u'http://moinmo.in/', 'SomePage', False)
-        result = resolve_interwiki('Self', 'SomePage')
-        assert result == ('Self', u'http://localhost:8080/', 'SomePage', False)
-
 
 class TestInterWikiMapBackend(object):
     """
--- a/MoinMoin/util/interwiki.py	Fri Aug 05 12:04:00 2011 +0200
+++ b/MoinMoin/util/interwiki.py	Fri Aug 05 13:18:23 2011 +0200
@@ -11,12 +11,76 @@
 from werkzeug import url_quote
 
 from flask import current_app as app
+from flask import url_for
 
 import os.path
 
 from MoinMoin import config
 
 
+def is_local_wiki(wiki_name):
+    """
+    check if <wiki_name> is THIS wiki
+    """
+    return wiki_name in ['', 'Self', app.cfg.interwikiname, ]
+
+
+def is_known_wiki(wiki_name):
+    """
+    check if <wiki_name> is a known wiki name
+
+    Note: interwiki_map should have entries for the special wikinames
+    denoting THIS wiki, so we do not need to check these names separately.
+    """
+    return wiki_name in app.cfg.interwiki_map
+
+
+def url_for_item(item_name, wiki_name='', rev=-1, endpoint='frontend.show_item', _external=False):
+    """
+    Compute URL for some local or remote/interwiki item.
+
+    For local items:
+    give <rev> to get the url of some specific revision.
+    give the <endpoint> to get the url of some specific view,
+    give _external=True to compute fully specified URLs.
+
+    For remote/interwiki items:
+    If you just give <item_name> and <wiki_name>, a generic interwiki URL
+    will be built.
+    If you also give <rev> and/or <endpoint>, it is assumed that remote wiki
+    URLs are built in the same way as local URLs.
+    Computed URLs are always fully specified.
+    """
+    if is_local_wiki(wiki_name):
+        if rev is None or rev == -1:
+            url = url_for(endpoint, item_name=item_name, _external=_external)
+        else:
+            url = url_for(endpoint, item_name=item_name, rev=rev, _external=_external)
+    else:
+        try:
+            wiki_base_url = app.cfg.interwiki_map[wiki_name]
+        except KeyError, err:
+            logging.warning("no interwiki_map entry for %r" % wiki_name)
+            url = '' # can we find something useful?
+        else:
+            if (rev is None or rev == -1) and endpoint == 'frontend.show_item':
+                # we just want to show latest revision (no special revision given) -
+                # this is the generic interwiki url support, should work for any remote wiki
+                url = join_wiki(wiki_base_url, item_name)
+            else:
+                # rev and/or endpoint was given, assume same URL building as for local wiki.
+                # we need this for moin wiki farms, e.g. to link from search results to
+                # some specific item/revision in another farm wiki.
+                local_url = url_for(endpoint, item_name=item_name, rev=rev, _external=False)
+                # we know that everything left of the + belongs to script url, but we
+                # just want e.g. +show/42/FooBar to append it to the other wiki's
+                # base URL.
+                i = local_url.index('/+')
+                path = local_url[i+1:]
+                url = wiki_base_url + path
+    return url
+
+
 def split_interwiki(wikiurl):
     """ Split a interwiki name, into wikiname and pagename, e.g:
 
@@ -36,29 +100,6 @@
     return wikiname, pagename
 
 
-def resolve_interwiki(wikiname, pagename):
-    """ Resolve an interwiki reference (wikiname:pagename).
-
-    Note: it is required that the interwiki_map contains entries for our
-    own wikiname and also for 'Self' (same url):
-
-    interwiki_map = {
-        'Self': 'http://ourserver/ourpath/',
-        'OurInterWikiName': 'http://ourserver/ourpath/',
-        # other entries ...
-    }
-
-    :param wikiname: interwiki wiki name
-    :param pagename: interwiki page name
-    :rtype: tuple
-    :returns: (wikitag, wikiurl, wikitail, err)
-    """
-    try:
-        return (wikiname, app.cfg.interwiki_map[wikiname], pagename, False)
-    except KeyError:
-        return (wikiname, app.cfg.interwiki_map['Self'], "InterWiki", True)
-
-
 def join_wiki(wikiurl, wikitail):
     """
     Add a (url_quoted) page name to an interwiki url.
@@ -93,7 +134,7 @@
     :returns: (wikiname, itemname)
     """
     homewiki = app.cfg.user_homewiki
-    if homewiki == app.cfg.interwikiname:
+    if is_local_wiki(homewiki):
         homewiki = u'Self'
     return homewiki, username