changeset 402:ab4ac448d5d8

merged
author Michael Mayorov <marchael@kb.csu.ru>
date Sat, 06 Aug 2011 14:35:57 +0000
parents 215d7a8f5b3e (current diff) c61d7e7c6c6b (diff)
children 79d80bcd1d32
files MoinMoin/_tests/wikiconfig.py MoinMoin/apps/frontend/views.py MoinMoin/items/__init__.py wikiconfig.py
diffstat 15 files changed, 171 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/wikiconfig.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/_tests/wikiconfig.py	Sat Aug 06 14:35:57 2011 +0000
@@ -23,5 +23,5 @@
     _test_items_xml = join(_here, 'testitems.xml')
     content_acl = None
     item_root = 'FrontPage'
-    interwiki_map = dict(MoinMoin='http://moinmo.in/')
+    interwiki_map = dict(Self='http://localhost:8080/', MoinMoin='http://moinmo.in/')
 
--- a/MoinMoin/apps/feed/views.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/apps/feed/views.py	Sat Aug 06 14:35:57 2011 +0000
@@ -11,7 +11,7 @@
 
 from datetime import datetime
 
-from flask import request, url_for, Response
+from flask import request, Response
 from flask import current_app as app
 from flask import g as flaskg
 
@@ -27,6 +27,8 @@
 from MoinMoin.themes import get_editor_info
 from MoinMoin.items import Item
 from MoinMoin.util.crypto import cache_key
+from MoinMoin.util.interwiki import url_for_item
+
 
 @feed.route('/atom/<itemname:item_name>')
 @feed.route('/atom', defaults=dict(item_name=''))
@@ -66,7 +68,7 @@
                      summary=rev.get(COMMENT, ''), summary_type='text',
                      content=content, content_type=content_type,
                      author=get_editor_info(rev, external=True),
-                     url=url_for('frontend.show_item', item_name=name, rev=this_revno, _external=True),
+                     url=url_for_item(name, rev=this_revno, _external=True),
                      updated=datetime.utcfromtimestamp(rev.timestamp),
                     )
         content = feed.to_string()
--- a/MoinMoin/apps/frontend/views.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/apps/frontend/views.py	Sat Aug 06 14:35:57 2011 +0000
@@ -41,6 +41,7 @@
 from MoinMoin import config, user, wikiutil
 from MoinMoin.config import CONTENTTYPE, ITEMLINKS, ITEMTRANSCLUSIONS
 from MoinMoin.util import crypto
+from MoinMoin.util.interwiki import url_for_item
 from MoinMoin.security.textcha import TextCha, TextChaizedForm, TextChaValid
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError, AccessDeniedError
 from MoinMoin.signalling import item_displayed, item_modified
@@ -59,8 +60,7 @@
 @frontend.route('/')
 def show_root():
     item_name = app.cfg.item_root
-    location = url_for('.show_item', item_name=item_name)
-    return redirect(location)
+    return redirect(url_for_item(item_name))
 
 @frontend.route('/robots.txt')
 def robots():
@@ -196,7 +196,7 @@
 
 @frontend.route('/+show/<itemname:item_name>')
 def redirect_show_item(item_name):
-    return redirect(url_for('.show_item', item_name=item_name))
+    return redirect(url_for_item(item_name))
 
 
 @frontend.route('/+dom/<int:rev>/<itemname:item_name>')
@@ -370,7 +370,7 @@
         TextCha(form).amend_form()
         if form.validate():
             item.revert()
-            return redirect(url_for('.show_item', item_name=item_name))
+            return redirect(url_for_item(item_name))
     return render_template(item.revert_template,
                            item=item, item_name=item_name,
                            rev_no=rev,
@@ -395,7 +395,7 @@
             target = form['target'].value
             comment = form['comment'].value
             item.copy(target, comment)
-            return redirect(url_for('.show_item', item_name=target))
+            return redirect(url_for_item(target))
     return render_template(item.copy_template,
                            item=item, item_name=item_name,
                            form=form,
@@ -419,7 +419,7 @@
             target = form['target'].value
             comment = form['comment'].value
             item.rename(target, comment)
-            return redirect(url_for('.show_item', item_name=target))
+            return redirect(url_for_item(target))
     return render_template(item.rename_template,
                            item=item, item_name=item_name,
                            form=form,
@@ -441,7 +441,7 @@
         if form.validate():
             comment = form['comment'].value
             item.delete(comment)
-            return redirect(url_for('.show_item', item_name=item_name))
+            return redirect(url_for_item(item_name))
     return render_template(item.delete_template,
                            item=item, item_name=item_name,
                            form=form,
@@ -471,7 +471,7 @@
         if form.validate():
             comment = form['comment'].value
             item.destroy(comment=comment, destroy_item=destroy_item)
-            return redirect(url_for('.show_item', item_name=item_name))
+            return redirect(url_for_item(item_name))
     return render_template(item.destroy_template,
                            item=item, item_name=item_name,
                            rev_no=rev,
@@ -498,8 +498,8 @@
             abort(403)
         files = []
         for full_name, rel_name, mimetype in item.flat_index():
-            url = url_for('.show_item', item_name=full_name)
-            url_download = url_for('.download_item', item_name=full_name)
+            url = url_for_item(full_name)
+            url_download = url_for_item(full_name, endpoint='frontend.download_item')
             files.append(dict(name=rel_name, url=url, url_download=url_download, size=0))
         return jsonify(files=files)
     if request.method == 'POST':
@@ -513,8 +513,8 @@
                                item_name=item_name)
             return jsonify(name=subitem_name,
                            size=size,
-                           url=url_for('.show_item', item_name=item_name, rev=revno),
-                           url_download=url_for('.download_item', item_name=item_name, rev=revno),
+                           url=url_for_item(item_name, rev=revno),
+                           url_download=url_for_item(item_name, rev=revno, endpoint='frontend.download_item'),
                           )
         except AccessDeniedError:
             abort(403)
@@ -707,7 +707,7 @@
             msg = _('Your quicklink to this page could not be removed.'), "error"
     if msg:
         flash(*msg)
-    return redirect(url_for('.show_item', item_name=item_name))
+    return redirect(url_for_item(item_name))
 
 
 @frontend.route('/+subscribe/<itemname:item_name>')
@@ -731,7 +731,7 @@
             msg = _('You could not get subscribed to this item.'), "error"
     if msg:
         flash(*msg)
-    return redirect(url_for('.show_item', item_name=item_name))
+    return redirect(url_for_item(item_name))
 
 
 class ValidRegistration(Validator):
--- a/MoinMoin/converter/__init__.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/converter/__init__.py	Sat Aug 06 14:35:57 2011 +0000
@@ -88,6 +88,11 @@
 def convert_to_indexable(rev):
     """
     convert a revision to an indexable document
+
+    :param rev: item revision - please make sure that the content file is
+                ready to read all indexable content from it. if you have just
+                written that content or already read from it, you need to call
+                rev.seek(0) before calling convert_to_indexable(rev).
     """
     try:
         # TODO use different converter mode?
--- a/MoinMoin/converter/_tests/test_link.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/converter/_tests/test_link.py	Sat Aug 06 14:35:57 2011 +0000
@@ -17,20 +17,20 @@
 
 class TestConverterExternOutput(object):
     def setup_class(self):
-        url_root = Iri('./')
-        self.conv = ConverterExternOutput(url_root=url_root)
+        self.conv = ConverterExternOutput()
 
     def test_wiki(self):
         assert 'MoinMoin' in app.cfg.interwiki_map
         pairs = [
+            # note: result URLs assume test wiki running at /
             ('wiki:///Test',
-                './Test'),
+                '/Test'),
             ('wiki:///Test?mode=raw',
-                './Test?mode=raw'),
+                '/Test?mode=raw'),
             ('wiki:///Test#anchor',
-                './Test#anchor'),
+                '/Test#anchor'),
             ('wiki:///Test?mode=raw#anchor',
-                './Test?mode=raw#anchor'),
+                '/Test?mode=raw#anchor'),
             ('wiki://MoinMoin/Test',
                 'http://moinmo.in/Test'),
         ]
@@ -39,27 +39,28 @@
 
     def test_wikilocal(self):
         pairs = [
+            # note: result URLs assume test wiki running at /
             ('wiki.local:',
                 'wiki:///Root',
-                './Root'),
+                '/Root'),
             ('wiki.local:Test',
                 'wiki:///Root',
-                './Test'),
+                '/Test'),
             ('wiki.local:Test',
                 'wiki:///Root/Sub',
-                './Test'),
+                '/Test'),
             ('wiki.local:/Test',
                 'wiki:///Root',
-                './Root/Test'),
+                '/Root/Test'),
             ('wiki.local:/Test',
                 'wiki:///Root/Sub',
-                './Root/Sub/Test'),
+                '/Root/Sub/Test'),
             ('wiki.local:../Test',
                 'wiki:///Root',
-                './Test'),
+                '/Test'),
             ('wiki.local:../Test',
                 'wiki:///Root/Sub',
-                './Root/Test'),
+                '/Root/Test'),
         ]
         for i in pairs:
             yield (self._do_wikilocal, ) + i
@@ -81,8 +82,7 @@
 
 class TestConverterRefs(object):
     def setup_class(self):
-        root = url_root=Iri('./')
-        self.converter = ConverterItemRefs(url_root=root)
+        self.converter = ConverterItemRefs()
 
     def testItems(self):
         tree_xml = u"""
--- a/MoinMoin/converter/link.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/converter/link.py	Sat Aug 06 14:35:57 2011 +0000
@@ -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
@@ -36,9 +36,6 @@
     def handle_wikilocal_transclusions(self, elem, link, page_name):
         pass
 
-    def __init__(self, url_root=None):
-        self.url_root = url_root
-
     def __call__(self, *args, **kw):
         """
         Calls the self.traverse_tree method
@@ -102,14 +99,16 @@
 
 class ConverterExternOutput(ConverterBase):
     @classmethod
-    def _factory(cls, input, output, links=None, url_root=None, **kw):
+    def _factory(cls, input, output, links=None, **kw):
         if links == 'extern':
-            return cls(url_root=url_root)
+            return cls()
 
     def _get_do_rev(self, query):
         """
         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 +137,45 @@
             query = None
         if revno is not None:
             revno = int(revno)
-        return do, revno, query
+        do_to_endpoint = dict(
+            show='frontend.show_item',
+            get='frontend.get_item',
+            download='frontend.download_item',
+            modify='frontend.modify_item',
+            # TODO: if we just always used same function name as do=name, we did not need this dict
+            # ...
+        )
+        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):
@@ -201,9 +183,9 @@
     determine all links and transclusions to other wiki items in this document
     """
     @classmethod
-    def _factory(cls, input, output, items=None, url_root=None, **kw):
+    def _factory(cls, input, output, items=None, **kw):
         if items == 'refs':
-            return cls(url_root=url_root)
+            return cls()
 
     def __init__(self, **kw):
         super(ConverterItemRefs, self).__init__(**kw)
--- a/MoinMoin/converter/moinwiki19_in.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/converter/moinwiki19_in.py	Sat Aug 06 14:35:57 2011 +0000
@@ -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	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/converter/moinwiki_in.py	Sat Aug 06 14:35:57 2011 +0000
@@ -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/items/__init__.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/items/__init__.py	Sat Aug 06 14:35:57 2011 +0000
@@ -61,6 +61,7 @@
 from MoinMoin.themes import render_template
 from MoinMoin import wikiutil, config, user
 from MoinMoin.util.send_file import send_file
+from MoinMoin.util.interwiki import url_for_item
 from MoinMoin.storage.error import NoSuchItemError, NoSuchRevisionError, AccessDeniedError, \
                                    StorageError
 from MoinMoin.config import UUID, NAME, NAME_OLD, MTIME, REVERTED_TO, ACL, \
@@ -264,8 +265,7 @@
         from MoinMoin.converter import default_registry as reg
         include_conv = reg.get(type_moin_document, type_moin_document, includes='expandall')
         macro_conv = reg.get(type_moin_document, type_moin_document, macros='expandall')
-        link_conv = reg.get(type_moin_document, type_moin_document, links='extern',
-                url_root=Iri(request.url_root))
+        link_conv = reg.get(type_moin_document, type_moin_document, links='extern')
         flaskg.clock.start('conv_include')
         doc = include_conv(doc)
         flaskg.clock.stop('conv_include')
@@ -710,7 +710,7 @@
                 except AccessDeniedError:
                     abort(403)
                 else:
-                    return redirect(url_for('frontend.show_item', item_name=self.name))
+                    return redirect(url_for_item(self.name))
         return render_template(self.template,
                                item_name=self.name,
                                rows_meta=str(ROWS_META), cols=str(COLS),
@@ -1171,7 +1171,7 @@
                 except AccessDeniedError:
                     abort(403)
                 else:
-                    return redirect(url_for('frontend.show_item', item_name=self.name))
+                    return redirect(url_for_item(self.name))
         return render_template(self.template,
                                item_name=self.name,
                                rows_data=str(ROWS_DATA), rows_meta=str(ROWS_META), cols=str(COLS),
@@ -1204,8 +1204,7 @@
         from MoinMoin.converter import default_registry as reg
 
         input_conv = reg.get(Type(self.contenttype), type_moin_document)
-        item_conv = reg.get(type_moin_document, type_moin_document,
-                items='refs', url_root=Iri(request.url_root))
+        item_conv = reg.get(type_moin_document, type_moin_document, items='refs')
 
         i = Iri(scheme='wiki', authority='', path='/' + self.name)
 
--- a/MoinMoin/themes/__init__.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/themes/__init__.py	Sat Aug 06 14:35:57 2011 +0000
@@ -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):
@@ -181,22 +180,13 @@
         if target.startswith("wiki:"):
             target = target[5:]
 
-        # 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', ]:
-            if not title:
-                title = item_name
-            return href, title, wiki_name
-
-        # Handle regular pagename like "FrontPage"
-        item_name = wikiutil.normalize_pagename(item_name, self.cfg)
-
+        if wiki_name == 'Self':
+            wiki_name = ''
+        href = url_for_item(item_name, wiki_name=wiki_name)
         if not title:
             title = item_name
-        href = url_for('frontend.show_item', item_name=item_name)
-        return href, title, wiki_local
+        return href, title, wiki_name
 
     def navibar(self, item_name):
         """
@@ -219,7 +209,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 +308,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:
@@ -392,6 +379,7 @@
                             'clock': flaskg.clock,
                             'cfg': app.cfg,
                             'item_name': 'handlers need to give it',
+                            'url_for_item': url_for_item,
                             'get_editor_info': lambda rev: get_editor_info(rev),
                             'gen': make_generator(),
                             })
--- a/MoinMoin/themes/_tests/test_navi_bar.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/themes/_tests/test_navi_bar.py	Sat Aug 06 14:35:57 2011 +0000
@@ -15,7 +15,7 @@
 
 class TestNaviBar(object):
     class Config(wikiconfig.Config):
-        interwiki_map = dict(MoinMoin='http://moinmo.in/', )
+        interwiki_map = dict(Self='http://localhost:8080/', MoinMoin='http://moinmo.in/', )
 
     def setup_method(self, method):
         self.theme = ThemeSupport(app.cfg)
--- a/MoinMoin/user.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/user.py	Sat Aug 06 14:35:57 2011 +0000
@@ -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	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/util/_tests/test_interwiki.py	Sat Aug 06 14:35:57 2011 +0000
@@ -14,13 +14,13 @@
 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
 
 
 class TestInterWiki(object):
     class Config(wikiconfig.Config):
-        interwiki_map = dict(MoinMoin='http://moinmo.in/', )
+        interwiki_map = dict(Self='http://localhost:8080/', MoinMoin='http://moinmo.in/', )
 
     def testSplitWiki(self):
         tests = [('SomePage', ('Self', 'SomePage')),
@@ -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'/', 'SomePage', False)
-
 
 class TestInterWikiMapBackend(object):
     """
--- a/MoinMoin/util/interwiki.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/MoinMoin/util/interwiki.py	Sat Aug 06 14:35:57 2011 +0000
@@ -11,14 +11,76 @@
 from werkzeug import url_quote
 
 from flask import current_app as app
-from flask import request
-from flask import g as flaskg
+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:
 
@@ -38,24 +100,6 @@
     return wikiname, pagename
 
 
-def resolve_interwiki(wikiname, pagename):
-    """ Resolve an interwiki reference (wikiname:pagename).
-
-    :param wikiname: interwiki wiki name
-    :param pagename: interwiki page name
-    :rtype: tuple
-    :returns: (wikitag, wikiurl, wikitail, err)
-    """
-    this_wiki_url = request.script_root + '/'
-    if wikiname in ('Self', app.cfg.interwikiname):
-        return (wikiname, this_wiki_url, pagename, False)
-    else:
-        try:
-            return (wikiname, app.cfg.interwiki_map[wikiname], pagename, False)
-        except KeyError:
-            return (wikiname, this_wiki_url, "InterWiki", True)
-
-
 def join_wiki(wikiurl, wikitail):
     """
     Add a (url_quoted) page name to an interwiki url.
@@ -90,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
 
--- a/wikiconfig.py	Sat Aug 06 07:36:08 2011 +0000
+++ b/wikiconfig.py	Sat Aug 06 14:35:57 2011 +0000
@@ -48,6 +48,10 @@
 
     # Load the interwiki map from intermap.txt:
     interwiki_map = InterWikiMap.from_file(os.path.join(wikiconfig_dir, 'contrib', 'interwiki', 'intermap.txt')).iwmap
+    # we must add entries for 'Self' and our interwikiname:
+    #interwikiname = 'MyInterWikiName'
+    #interwiki_map[interwikiname] = 'http://localhost:8080/'
+    interwiki_map['Self'] = 'http://localhost:8080/'
 
     sitename = u'My MoinMoin'