Radomir…
Below is a patch file from this newbie. Randy at data-warp dot com
Update: 2009-11-27 by Randy I've cleaned up my hack for page trees under docs. Back links seem to be working too (with the latest development version of Hatta).
Question: how should I submit them? Should I push them to the Hatta Mercurial repository. Do I need push permission? I don't want to break anything… Should I email them? Put them into a Wiki page (like I did below)?
--- hatta-2009-10-06.py 2009-10-10 13:17:04.000000000 -0500
+++ hatta-2009-10-06-new.py 2009-10-10 13:17:35.000000000 -0500
@@ -14,12 +14,79 @@
from the wiki or with a text editor -- in either case the changes committed to
the repository will appear in the recent changes and in page's history.
+# 2009-10-09 RLS (Randy Selzler): FIXME_RLS
+# Based upon Hatta development version dated 2009-10-06.
+# Hacked to support links to pages in docs/ trees.
+# Strategy: preserve "/" in page links for docs/ trees,
+# or url_quote them for flat Wikis.
+#
+# Radomir: use or reject my hacks as you see fit.
+# Thanks for the encouragement !!!
+#
+# See FIXME_RLS for unresolved issues, including:
+# * --file-tree option should be frozen when Wiki (repository?) is created.
+# Accessing the same Wiki with and without would cause problems.
+# * Why offer both flat and tree Wiki styles (when is flat better)?
+# I advocate discarding flat support.
+# * title_safe is hardwired within WikiTitleConverter.
+# FIXME_RLS I don't know how to fix this !!!
+# * mercurial support fails when saving pages via symbolic links.
+# The file is changed, but commit complains about link traversal.
+# Perhaps Hatta could implicitly make them read-only?
+# * Much more testing is needed !!!
+# * DELETE/RELOCATE THESE COMMENTS ONCE THE ISSUES ARE RESOLVED.
+#
+# Discussion: if --file-tree is specified on the command line, then docs
+# supports a directory tree for Wiki pages, i.e. docs/ need not be flat.
+# Examples:
+# |=Link |=Path/Filename |
+# |[[foofoo]] |.../hatta/docs/foofoo |
+# |[[foo.hat]] |.../hatta/docs/foo.hat |
+# |[[foo/bar.hat]] |.../hatta/docs/foo/bar.hat |
+# |[[foo/gee.hat|Foo Gee]] |.../hatta/docs/foo/gee.hat |
+# |[[foo/../bad.hat]] |REJECTED, see below |
+#
+# Link paths that contain "../" are rejected (not followed).
+# This prevents Wiki users from escaping the docs directory,
+# simply by creating a ../ link, i.e. [[../../../peek-a-boo.hat]].
+# Wiki admin can create symbolic links to directories outside docs/
+# to provide controlled access.
+#
+# Security via os.path.abspath() comparisons was considered and rejected.
+# Symbolic links that led outside docs/ (to their natural location) would not
+# begin with the same path as those within docs/. Natural locations could be
+# supported with a list of alternative docs/ that were allowed, but this
+# creates an ugly coordination problem between the list and actual links.
+#
+# Symbolic links to Wiki pages in their natural location have several uses:
+# * Cross links between source code and documentation trees.
+# * Wiki access to open source pages versus open source + proprietary pages.
+# * Wiki access for project foo and bar version combinations, i.e.
+# production release links to foo-v1.0 and bar-v1.1
+# beta test release links to foo-v1.3 and bar-v1.1
+# * Repository isolation for open source and proprietary components.
+# * Wiki views for project combinations...
+# Example symbolic links -> :
+# hatta1/docs/
+# a -> /data/a/
+# b -> /data/b/
+# c -> /data/c/
+# hatta2/docs/
+# b -> /data/b/
+# c -> /data/c/
+# hatta3/docs/
+# a -> /data/a/
+# c -> /data/c/
+# Where 3 distinct repositories/trees service /data/a, b, c
+#
+
Usage: hatta.py [options]
Options:
-h, --help show this help message and exit
-d DIR, --pages-dir=DIR
Store pages in DIR
+ -f, --file-tree Whether the wiki should be hierarchical
-t DIR, --cache-dir=DIR
Store cache in DIR
-i INT, --interface=INT
@@ -174,6 +241,8 @@
add('-d', '--pages-dir', dest='pages_path',
help='Store pages in DIR', metavar='DIR')
+ add('-f', '--file-tree', dest='file_tree', default=False,
+ help='Whether the wiki should be hierarchical', action="store_true")
add('-t', '--cache-dir', dest='cache_path',
help='Store cache in DIR', metavar='DIR')
add('-i', '--interface', dest='interface',
@@ -309,7 +378,7 @@
change history, using Mercurial repository as the storage method.
"""
- def __init__(self, path, charset=None):
+ def __init__(self, path, file_tree, charset=None):
"""
Takes the path to the directory where the pages are to be kept.
If the directory doen't exist, it will be created. If it's inside
@@ -318,6 +387,13 @@
"""
self.charset = charset or 'utf-8'
+ self.file_tree = file_tree
+ if self.file_tree:
+ self.title_safe = '/'
+ else:
+ self.title_safe = ''
+ # RegEx matching ".." path components ("..", "../" or "../").
+ self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
self.path = path
if not os.path.exists(self.path):
os.makedirs(self.path)
@@ -356,11 +432,17 @@
return path
def _file_path(self, title):
- return os.path.join(self.path, werkzeug.url_quote(title, safe=''))
+ if self.file_tree and self.dot_dot_re.search(title):
+ raise werkzeug.exceptions.Forbidden(
+ u'_file_path: Link contains "../": %s' % title)
+ return os.path.join(self.path, werkzeug.url_quote(title, safe=self.title_safe))
def _title_to_file(self, title):
+ if self.file_tree and self.dot_dot_re.search(title):
+ raise werkzeug.exceptions.Forbidden(
+ u'_title_to_file: Link contains "../": %s' % title)
return os.path.join(self.repo_prefix,
- werkzeug.url_quote(title, safe=''))
+ werkzeug.url_quote(title, safe=self.title_safe))
def _file_to_title(self, filename):
assert filename.startswith(self.repo_prefix)
@@ -409,12 +491,28 @@
@locked_repo
def save_file(self, title, file_name, author=u'', comment=u'', parent=None):
"""Save an existing file as specified page."""
+ import errno
user = author.encode('utf-8') or _(u'anon').encode('utf-8')
text = comment.encode('utf-8') or _(u'comment').encode('utf-8')
repo_file = self._title_to_file(title)
file_path = self._file_path(title)
- mercurial.util.rename(file_name, file_path)
+ path_dir = os.path.dirname(file_path)
+
+ if os.path.isdir(file_path):
+ raise werkzeug.exceptions.Forbidden(
+ u'save_file: Page is a directory: %s' % file_path)
+
+ try:
+ if not os.path.isdir(path_dir):
+ os.makedirs(path_dir)
+ mercurial.util.rename(file_name, file_path)
+ except OSError, err:
+ # Path component is an existing page?
+ msg = u'save_file: [Errno %s] %s: in path %s' % (err.errno,
+ os.strerror(err.errno), file_path)
+ raise werkzeug.exceptions.Forbidden(msg)
+
changectx = self._changectx()
try:
filectx_tip = changectx[repo_file]
@@ -2091,10 +2189,41 @@
yield u'</table>'
class WikiTitleConverter(werkzeug.routing.PathConverter):
- """Behaves like the path converter, except that it escapes slashes."""
+ """Behaves like the path converter, except optional slash escapes."""
+
+
+# to_url appears to control "Title" rendering at top of pages...
+
+ # FIXME_RLS should be within __init__
+# self.file_tree = True
+# if self.file_tree:
+# self.title_safe = '/'
+# else:
+# self.title_safe = ''
+# self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
+#
+# # 2009-10-09 RLS, __init__ raises a runtime error ?
+# # Newbie issue... how to get file_tree passed in???
+ def __init__FIXME_RLS(self, file_tree):
+ """
+ Initialize title_safe for url_quote.
+ """
+ self.file_tree = file_tree
+ if self.file_tree:
+ self.title_safe = '/'
+ else:
+ self.title_safe = ''
+ self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
def to_url(self, value):
- return werkzeug.url_quote(value, self.map.charset, safe="")
+ # FIXME_RLS hardwired and duplicated effort
+ self.file_tree = True
+ self.title_safe = '/'
+ self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
+ if self.file_tree and self.dot_dot_re.search(value):
+ raise werkzeug.exceptions.Forbidden(
+ u'to_url: Name contains "../": %s' % value)
+ return werkzeug.url_quote(value, self.map.charset, safe=self.title_safe)
class WikiAllConverter(werkzeug.routing.BaseConverter):
"""Matches everything."""
@@ -2108,6 +2237,7 @@
application and most of the logic.
"""
storage_class = WikiStorage
+ titleConverter_class = WikiTitleConverter
index_class = WikiSearch
mime_map = {
'text': WikiPageText,
@@ -2149,6 +2279,7 @@
else:
_ = gettext.translation('hatta', fallback=True).ugettext
self.path = os.path.abspath(config.get('pages_path', 'docs'))
+ self.file_tree = self.config.get_bool('file_tree', False)
self.cache = os.path.abspath(config.get('cache_path', 'cache'))
self.page_charset = config.get('page_charset', 'utf-8')
self.menu_page = self.config.get('menu_page', u'Menu')
@@ -2161,7 +2292,16 @@
self.script_page = self.config.get('script_page', None)
self.icon_page = self.config.get('icon_page', None)
- self.storage = self.storage_class(self.path, self.page_charset)
+ if self.file_tree:
+ self.title_safe = '/'
+ else:
+ self.title_safe = ''
+
+ self.storage = self.storage_class(self.path, self.title_safe, self.page_charset)
+
+ # FIXME_RLS how to pass in file_tree into title converter ???
+ # self.titleConverter = self.titleConverter_class(self.file_tree)
+
if not os.path.isdir(self.cache):
os.makedirs(self.cache)
reindex = True
![[Home]](/+download/logo.png)