sislau avatar sislau committed 889995a

Tests and implementation for new interwiki:namespace:itemname parsing resolving in util stuff.

Comments (0)

Files changed (3)

MoinMoin/themes/__init__.py

         breadcrumbs = []
         trail = user.getTrail()
         for interwiki_item_name in trail:
-            wiki_name, item_name = split_interwiki(interwiki_item_name)
+            wiki_name, namespace, item_name = split_interwiki(interwiki_item_name)
             err = not is_known_wiki(wiki_name)
-            href = url_for_item(item_name, wiki_name=wiki_name)
+            href = url_for_item(item_name, namespace=namespace, 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
         if target.startswith("wiki:"):
             target = target[5:]
 
-        wiki_name, item_name = split_interwiki(target)
+        wiki_name, namespace, item_name = split_interwiki(target)
         if wiki_name == 'Self':
             wiki_name = ''
-        href = url_for_item(item_name, wiki_name=wiki_name)
+        href = url_for_item(item_name, namespace=namespace, wiki_name=wiki_name)
         if not title:
             title = item_name
         return href, title, wiki_name

MoinMoin/util/_tests/test_interwiki.py

 import tempfile
 import os.path
 import shutil
+import unittest
 
-from MoinMoin.util.interwiki import split_interwiki, join_wiki, InterWikiMap
+from MoinMoin.util.interwiki import split_interwiki, join_wiki, InterWikiMap, url_for_item, _split_namespace
 from MoinMoin._tests import wikiconfig
+from MoinMoin.config import CURRENT
+from MoinMoin.app import before_wiki
 
+from flask import current_app as app
 
-class TestInterWiki(object):
+class TestInterWiki():
     class Config(wikiconfig.Config):
-        interwiki_map = dict(Self='http://localhost:8080/', MoinMoin='http://moinmo.in/', )
+        interwiki_map = {'Self': 'http://localhost/',
+                         'MoinMoin': 'http://moinmo.in/',
+                         'OtherWiki': 'http://otherwiki.com/',
+                         'OtherWiki:ns1': 'http://otherwiki.com/ns1/',
+                         'OtherWiki:ns1:ns2': 'http://otherwiki.com/ns1/ns2/'
+        }
 
-    def testSplitWiki(self):
-        tests = [('SomePage', ('Self', 'SomePage')),
-                 ('OtherWiki:OtherPage', ('OtherWiki', 'OtherPage')),
-                 (':OtherPage', ('', 'OtherPage')),
-                 # broken ('/OtherPage', ('Self', '/OtherPage')),
-                 # wrong interpretation ('MainPage/OtherPage', ('Self', 'MainPage/OtherPage')),
+    def test_url_for_item(self):
+        before_wiki()
+        revid = 'cdc431e0fc624d6fb8372152dcb66457'
+
+        tests = [(('SomePage', '', '', CURRENT, 'frontend.show_item', False), '/SomePage'),
+                 (('SomePage', '', '', CURRENT, 'frontend.show_item', True), 'http://localhost/SomePage'),
+                 (('SomePage', '', '', CURRENT, 'frontend.modify_item', False), '/+modify/SomePage'),
+                 # FIXME if you set interwiki_map = dict(Self='http://localhost/', MoinMoin='http://moinmo.in/', ),
+                 # the above line make it fails, it returns http://localhost/+modify/SomePage
+#                 (('SomePage', '', '', CURRENT, 'frontend.modify_item', True), 'http://localhost:8080/+modify/SomePage'),
+                 (('SomePage', '', '', revid, 'frontend.show_item', False), '/+show/+{0}/SomePage'.format(revid)),
+                 (('SomePage', '', '', revid, 'frontend.show_item_meta', False), '/+meta/+{0}/SomePage'.format(revid)),
+                 # Valid namespaces
+                 (('SomePage', '', 'ns1', CURRENT, 'frontend.show_item', False), '/:ns1:SomePage'),
+                 (('SomePage', '', 'ns1:ns2', CURRENT, 'frontend.show_item', True), 'http://localhost/:ns1:ns2:SomePage'),
+                 (('SomePage', '', 'ns1', CURRENT, 'frontend.modify_item', False), '/+modify/:ns1:SomePage'),
+                 (('SomePage', '', 'ns1:ns2', CURRENT, 'frontend.show_item_meta', True), 'http://localhost/+meta/:ns1:ns2:SomePage'),
+
+                 (('SomePage', '', 'ns1', revid, 'frontend.show_item', False), '/+show/+{0}/:ns1:SomePage'.format(revid)),
+                 (('SomePage', '', 'ns1:ns2', revid, 'frontend.show_item_meta', False), '/+meta/+{0}/:ns1:ns2:SomePage'.format(revid)),
+
+                 # FIXME will exist a map for this case?
+                 (('SomePage', 'MoinMoin', 'ns1', CURRENT, 'frontend.show_item', False), 'http://moinmo.in/:ns1:SomePage'),
+                 (('SomePage', 'MoinMoin', '', CURRENT, 'frontend.show_item', False), 'http://moinmo.in/SomePage'),
+#                 what to expect in these cases???
+#                 (('SomePage', 'MoinMoin', '', rev, 'frontend.show_item', False), 'http://moinmo.in/SomePage'),
+#                 (('SomePage', 'non-existent', '', CURRENT, 'frontend.show_item', False), '/non-existent:SomePage'),
+#                 (('SomePage', 'non-existent', 'ns1', CURRENT, 'frontend.show_item', False), '/non-existent:ns1:SomePage'),
                 ]
-        for markup, (wikiname, pagename) in tests:
-            assert split_interwiki(markup) == (wikiname, pagename)
+
+        for (item_name, wiki_name, namespace, rev, endpoint, _external), url in tests:
+            print (item_name, wiki_name, namespace, rev, endpoint, _external)
+            assert url_for_item(item_name, wiki_name, namespace, rev, endpoint, _external) == url
+
+    def test__split_namespace(self):
+        map = set()
+        map.add('ns1')
+        map.add('ns1:ns2')
+        tests = [('', ('', '')),
+                 ('OtherWiki:', ('', 'OtherWiki:')),
+                 ('ns1:', ('ns1', '')),
+                 ('ns3:foo', ('', 'ns3:foo')),
+                 ('ns1:OtherPage', ('ns1', 'OtherPage')),
+                 ('ns1:ns2:OtherPage', ('ns1:ns2', 'OtherPage')),
+                 ('ns1:ns2:ns1:ns2:OtherPage', ('ns1:ns2', 'ns1:ns2:OtherPage')),
+                 ('SomePage', ('', 'SomePage')),
+                 ('OtherWiki:ns1:OtherPage', ('', 'OtherWiki:ns1:OtherPage')),
+                ]
+        for markup, (namespace, pagename) in tests:
+            assert _split_namespace(map, markup) == (namespace, pagename)
+
+    def test_split_interwiki(self):
+        app.cfg.namespace_mapping = [(u'', 'default_backend'), (u'ns1:', 'default_backend'), (u'ns1:ns2:', 'other_backend')]
+        tests = [('', ('Self', '', '')),
+                 ('OtherWiki:', ('OtherWiki', '', '')),
+                 (':ns1:', ('Self', 'ns1', '')),
+                 (':ns3:foo', ('Self', '', ':ns3:foo')),
+                 ('SomePage', ('Self', '', 'SomePage')),
+                 ('OtherWiki:OtherPage', ('OtherWiki', '', 'OtherPage')),
+                 ('NonExistentWiki:OtherPage', ('Self', '', 'NonExistentWiki:OtherPage')),
+                 (':ns1:OtherPage', ('Self', 'ns1', 'OtherPage')),
+                 (':ns1:ns2:OtherPage', ('Self', 'ns1:ns2', 'OtherPage')),
+                 # XXX
+#                 ('ns1:OtherPage', ('Self', '', 'ns1:OtherPage')),
+#                 ('ns1:ns2:OtherPage', ('Self', '', 'ns1:ns2:OtherPage')),
+                 ('ns1:OtherPage', ('Self', 'ns1', 'OtherPage')),
+                 ('ns1:ns2:OtherPage', ('Self', 'ns1:ns2', 'OtherPage')),
+                 # XXX
+                 ('OtherWiki:ns1:OtherPage', ('OtherWiki', 'ns1', 'OtherPage')),
+                 ('OtherWiki:ns1:ns2:OtherPage', ('OtherWiki', 'ns1:ns2', 'OtherPage')),
+                 ('OtherWiki:ns3:ns2:OtherPage/foo', ('OtherWiki', '', 'ns3:ns2:OtherPage/foo')),
+                ]
+        for markup, (wikiname, namespace, pagename) in tests:
+            assert split_interwiki(markup) == (wikiname, namespace, pagename)
 
     def testJoinWiki(self):
-        tests = [(('http://example.org/', u'SomePage'), 'http://example.org/SomePage'),
-                 (('http://example.org/?page=$PAGE&action=show', u'SomePage'), 'http://example.org/?page=SomePage&action=show'),
-                 (('http://example.org/', u'Aktuelle\xc4nderungen'), 'http://example.org/Aktuelle%C3%84nderungen'),
-                 (('http://example.org/$PAGE/show', u'Aktuelle\xc4nderungen'), 'http://example.org/Aktuelle%C3%84nderungen/show'),
+        tests = [(('http://example.org/', u'SomePage', ''), 'http://example.org/SomePage'),
+                 (('http://example.org/?page=$PAGE&action=show', u'SomePage', ''), 'http://example.org/?page=SomePage&action=show'),
+                 (('http://example.org/', u'Aktuelle\xc4nderungen', ''), 'http://example.org/Aktuelle%C3%84nderungen'),
+                 (('http://example.org/$PAGE/show', u'Aktuelle\xc4nderungen', ''), 'http://example.org/Aktuelle%C3%84nderungen/show'),
+
+                 (('http://example.org/', u'SomePage', u'ns1'), 'http://example.org/:ns1:SomePage'),
+                 (('http://example.org/?page=$PAGE&action=show&namespace=$NAMESPACE', u'SomePage', u'ns1'), 'http://example.org/?page=SomePage&action=show&namespace=ns1'),
+                 (('http://example.org/', u'Aktuelle\xc4nderungen', u'ns1ççç'), 'http://example.org/:ns1%C3%83%C2%A7%C3%83%C2%A7%C3%83%C2%A7:Aktuelle%C3%84nderungen'),
+                 (('http://example.org/$NAMESPACE/$PAGE/show', u'Aktuelle\xc4nderungen', u'nsç1'), 'http://example.org/ns%C3%83%C2%A71/Aktuelle%C3%84nderungen/show'),
                 ]
-        for (baseurl, pagename), url in tests:
-            assert join_wiki(baseurl, pagename) == url
-
+        for (baseurl, pagename, namespace), url in tests:
+            assert join_wiki(baseurl, pagename, namespace) == url
 
 class TestInterWikiMapBackend(object):
     """

MoinMoin/util/interwiki.py

     return wiki_name in app.cfg.interwiki_map
 
 
-def url_for_item(item_name, wiki_name='', rev=CURRENT, endpoint='frontend.show_item', _external=False):
+def url_for_item(item_name, wiki_name='', namespace='', rev=CURRENT, endpoint='frontend.show_item', _external=False):
     """
     Compute URL for some local or remote/interwiki item.
 
     URLs are built in the same way as local URLs.
     Computed URLs are always fully specified.
     """
+    # TODO check if both namespace and Interwiki exists
     if is_local_wiki(wiki_name):
+        if namespace != '':
+            item_name = ':' + namespace + ':' + item_name
         if rev is None or rev == CURRENT:
             url = url_for(endpoint, item_name=item_name, _external=_external)
         else:
             if (rev is None or rev == CURRENT) 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)
+                url = join_wiki(wiki_base_url, item_name, namespace)
             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.
+                item_name = namespace + ':' + item_name
                 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
                 url = wiki_base_url + path
     return url
 
+def _split_namespace(namespaces_set, url):
+    """
+    Find the longest namespace in the set.
+    the namespaces are separeted by colons (:).
+    Example:
+        namespaces_set(['ns1', 'ns1:ns2'])
+        url: ns1:urlalasd return: ns1, urlalasd
+        url: ns3:urlalasd return: '', ns3:urlalasd
+        url: ns2:urlalasd return: '', ns2:urlalasd
+        url: ns1:ns2:urlalasd return: ns1:ns2, urlalasd
+    param namespaces_set: set of namespaces (strings) to search
+    param url: string
+    returns: (namespace, url)
+    """
+    namespace = ''
+    tokens_list = url.split(':')
+    for token in tokens_list:
+        if namespace:
+            token = namespace + ':' + token
+        if token in namespaces_set:
+            namespace = token
+        else:
+            break
+    if namespace:
+        length = len(namespace) + 1
+        url = url[length:]
+    return namespace, url
 
 def split_interwiki(wikiurl):
     """ Split a interwiki name, into wikiname and pagename, e.g:
 
-    'MoinMoin:FrontPage' -> "MoinMoin", "FrontPage"
-    'FrontPage' -> "Self", "FrontPage"
-    'MoinMoin:Page with blanks' -> "MoinMoin", "Page with blanks"
-    'MoinMoin:' -> "MoinMoin", ""
-
+    'MoinMoin:FrontPage' -> "MoinMoin", "", "FrontPage"
+    'FrontPage' -> "Self", "", "FrontPage"
+    'MoinMoin:Page with blanks' -> "MoinMoin", "", "Page with blanks"
+    'MoinMoin:' -> "MoinMoin", "", ""
+    XXX
+    'MoinMoin:interwikins:AnyPage' -> "MoinMoin:interwikins:", "", "AnyPage"
+    XXX
+    ':ns:AnyPage' -> "Self", "ns", "AnyPage" if ns namespace exists or "Self", "", ":ns:AnyPage" if not.
+    ':ns1:ns2:AnyPage' -> "Self", "ns1:ns2", "AnyPage" if ns1:ns2 namespace exists OR
+                         "Self", "ns1", "ns2:AnyPage" if ns1 namespace exists OR
+                         "Self", "", "ns1:ns2:AnyPage" else.
     :param wikiurl: the url to split
     :rtype: tuple
-    :returns: (wikiname, pagename)
+    :returns: (wikiname, namespace, pagename)
     """
-    try:
-        wikiname, pagename = wikiurl.split(":", 1)
-    except ValueError:
-        wikiname, pagename = 'Self', wikiurl
-    return wikiname, pagename
+    namespace_mapping_set = set()
+    for namespace, _ in app.cfg.namespace_mapping:
+        namespace_mapping_set.add(namespace.rstrip(':'))
+    #Base case: no colon in wikiurl
+    if wikiurl.find(':') == -1:
+        return 'Self', '', wikiurl
+    if not wikiurl.startswith(':'):
+        interwikinamespace, item_name = _split_namespace(set(app.cfg.interwiki_map.keys()), wikiurl)
+        if not interwikinamespace:
+            # XXX if we want to process local name spaces whitout the colon at the beging, just uncoment the lines above:
+            localnamespace, item_name =  _split_namespace(set(namespace_mapping_set), wikiurl)
+            return 'Self', localnamespace, item_name
+#            return 'Self', '', item_name
+        if interwikinamespace.find(':') == -1:
+            return interwikinamespace, '', item_name
+        else:
+            return interwikinamespace.split(':', 1)[0], interwikinamespace.split(':', 1)[1], item_name
+    else:
+        localnamespace, item_name =  _split_namespace(set(namespace_mapping_set), wikiurl.split(':', 1)[1])
+        if not localnamespace:
+            item_name = ':' + item_name
+        return 'Self', localnamespace, item_name
 
-
-def join_wiki(wikiurl, wikitail):
+def join_wiki(wikiurl, wikitail, namespace):
     """
     Add a (url_quoted) page name to an interwiki url.
 
 
     :param wikiurl: wiki url, maybe including a $PAGE placeholder
     :param wikitail: page name
+    :param namespace: namespace
     :rtype: string
     :returns: generated URL of the page in the other wiki
     """
     wikitail = url_quote(wikitail, charset=config.charset, safe='/')
+    namespace = url_quote(namespace, charset=config.charset, safe='/')
+    if not('$PAGE' in wikiurl or '$NAMESPACE' in wikiurl):
+        if namespace != '':
+            namespace = ':' + namespace + ':'
+        return wikiurl + namespace + wikitail
     if '$PAGE' in wikiurl:
-        return wikiurl.replace('$PAGE', wikitail)
-    else:
-        return wikiurl + wikitail
+        wikiurl = wikiurl.replace('$PAGE', wikitail)
+    if '$NAMESPACE' in wikiurl:
+        wikiurl = wikiurl.replace('$NAMESPACE', namespace)
+    return wikiurl
 
 
 def getInterwikiName(item_name):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.