Hatta File Tree Branch

changeset 632:607a934cc6bb

Add support for docs/path/pages (docs tree)
author Randy Selzler <RS-merc@Data-Warp.com>
date Mon Dec 21 11:08:18 2009 -0600 (2009-12-21)
parents d973b363d32e
children 9c8347beb368
files hatta.py
line diff
     1.1 --- a/hatta.py	Thu Dec 03 01:31:43 2009 +0100
     1.2 +++ b/hatta.py	Mon Dec 21 11:08:18 2009 -0600
     1.3 @@ -292,6 +292,8 @@
     1.4          """
     1.5  
     1.6          self.charset = charset or 'utf-8'
     1.7 +        # RegEx matching path components that contain ".."
     1.8 +        self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
     1.9          self.path = path
    1.10          if not os.path.exists(self.path):
    1.11              os.makedirs(self.path)
    1.12 @@ -330,11 +332,17 @@
    1.13          return path
    1.14  
    1.15      def _file_path(self, title):
    1.16 -        return os.path.join(self.path, werkzeug.url_quote(title, safe=''))
    1.17 +        if self.dot_dot_re.search(title):
    1.18 +            raise werkzeug.exceptions.Forbidden(
    1.19 +                    u'_file_path: Link contains ".." components: %s' % title)
    1.20 +        return os.path.join(self.path, werkzeug.url_quote(title, safe='/'))
    1.21  
    1.22      def _title_to_file(self, title):
    1.23 +        if self.dot_dot_re.search(title):
    1.24 +            raise werkzeug.exceptions.Forbidden(
    1.25 +                    u'_title_to_file: Link contains "..": %s' % title)
    1.26          return os.path.join(self.repo_prefix,
    1.27 -                            werkzeug.url_quote(title, safe=''))
    1.28 +                    werkzeug.url_quote(title, safe='/'))
    1.29  
    1.30      def _file_to_title(self, filename):
    1.31          assert filename.startswith(self.repo_prefix)
    1.32 @@ -383,12 +391,28 @@
    1.33      @locked_repo
    1.34      def save_file(self, title, file_name, author=u'', comment=u'', parent=None):
    1.35          """Save an existing file as specified page."""
    1.36 +        import errno
    1.37  
    1.38          user = author.encode('utf-8') or _(u'anon').encode('utf-8')
    1.39          text = comment.encode('utf-8') or _(u'comment').encode('utf-8')
    1.40          repo_file = self._title_to_file(title)
    1.41          file_path = self._file_path(title)
    1.42 -        mercurial.util.rename(file_name, file_path)
    1.43 +        path_dir = os.path.dirname(file_path)
    1.44 +
    1.45 +        if os.path.isdir(file_path):
    1.46 +            raise werkzeug.exceptions.Forbidden(
    1.47 +                    u'save_file: Page name is a directory: %s' % file_path)
    1.48 +
    1.49 +        try:
    1.50 +            if not os.path.isdir(path_dir):
    1.51 +                os.makedirs(path_dir)
    1.52 +            mercurial.util.rename(file_name, file_path)
    1.53 +        except OSError, err:
    1.54 +            # Path component is an existing page?
    1.55 +            msg = u'save_file: [Errno %s] %s: in path %s' % (err.errno,
    1.56 +                    os.strerror(err.errno), file_path)
    1.57 +            raise werkzeug.exceptions.Forbidden(msg)
    1.58 +
    1.59          changectx = self._changectx()
    1.60          try:
    1.61              filectx_tip = changectx[repo_file]
    1.62 @@ -604,12 +628,15 @@
    1.63                      yield title, rev, date, author, comment
    1.64  
    1.65      def all_pages(self):
    1.66 -        """Iterate over the titles of all pages in the wiki."""
    1.67 -
    1.68 -        for filename in os.listdir(self.path):
    1.69 -            if (os.path.isfile(os.path.join(self.path, filename))
    1.70 -                and not filename.startswith('.')):
    1.71 -                yield werkzeug.url_unquote(filename)
    1.72 +        """Iterate over the titles of all pages in the wiki tree."""
    1.73 +
    1.74 +        for dirpath, dirnames, filenames in os.walk(self.path):
    1.75 +            dirnames[:] = [d for d in dirnames if not d.startswith('.')]
    1.76 +            relpath = dirpath[len(self.path)+1:]
    1.77 +            for name in filenames:
    1.78 +                if (os.path.isfile(os.path.join(dirpath, name))
    1.79 +                    and not name.startswith('.')):
    1.80 +                    yield werkzeug.url_unquote(os.path.join(relpath, name))
    1.81  
    1.82      def changed_since(self, rev):
    1.83          """Return all pages that changed since specified repository revision."""
    1.84 @@ -2106,10 +2133,26 @@
    1.85          yield u'</table>'
    1.86  
    1.87  class WikiTitleConverter(werkzeug.routing.PathConverter):
    1.88 -    """Behaves like the path converter, except that it escapes slashes."""
    1.89 +    """Behaves like the path converter, except ".." components are rejected."""
    1.90 +
    1.91 +# RLS, FIXME NOTE: to_url appears to control "Title" rendering at top of pages...
    1.92 +
    1.93 +    def __init__FIXME_RLS(self, junk):
    1.94 +        # If __init__FIXME_RLS is changed to __init__ then the class
    1.95 +        # is initialized, but backlinks fail... Don't know why ! 2009-11-27 RLS
    1.96 +        """
    1.97 +        Initialize for to_url and url_quote.
    1.98 +        """
    1.99 +        # RegEx matching path components that contain ".."
   1.100 +        self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
   1.101  
   1.102      def to_url(self, value):
   1.103 -        return werkzeug.url_quote(value, self.map.charset, safe="")
   1.104 +        # Kludge because __init__ breaks backlinks.
   1.105 +        self.dot_dot_re = re.compile('(^|/)\.\.(?=(/|$))')
   1.106 +        if self.dot_dot_re.search(value):
   1.107 +            raise werkzeug.exceptions.Forbidden(
   1.108 +                    u'to_url: Name contains ".." path component: %s' % value)
   1.109 +        return werkzeug.url_quote(value, self.map.charset, safe='/')
   1.110  
   1.111  class WikiAllConverter(werkzeug.routing.BaseConverter):
   1.112      """Matches everything."""
   1.113 @@ -2123,6 +2166,7 @@
   1.114      application and most of the logic.
   1.115      """
   1.116      storage_class = WikiStorage
   1.117 +    titleConverter_class = WikiTitleConverter
   1.118      index_class = WikiSearch
   1.119      mime_map = {
   1.120          'text': WikiPageText,