summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorianb <devnull@localhost>2005-07-03 19:59:13 +0000
committerianb <devnull@localhost>2005-07-03 19:59:13 +0000
commit94bee1ee2c1e56ceb6a94e889a62dff2b8159e36 (patch)
treef12a173621e3f41544595dc0beae92b4d44feee6 /examples
parent70f1fa9f5e88aa9083802b7f575bcf9862da06dc (diff)
downloadpaste-94bee1ee2c1e56ceb6a94e889a62dff2b8159e36.tar.gz
Refactored heavily; now each file type (of which there are currently just two) is its own class of servlet, and dispatching is done to the appropriate class.
Diffstat (limited to 'examples')
-rw-r--r--examples/filebrowser/js-lib/common.js2
-rw-r--r--examples/filebrowser/pathobj.py175
-rw-r--r--examples/filebrowser/server.conf12
-rw-r--r--examples/filebrowser/sitepage.py38
-rw-r--r--examples/filebrowser/templates/directory.pt2
-rw-r--r--examples/filebrowser/templates/edit_text.pt15
-rw-r--r--examples/filebrowser/templates/view_file.pt5
-rw-r--r--examples/filebrowser/web/__init__.py18
-rw-r--r--examples/filebrowser/web/download.py20
-rw-r--r--examples/filebrowser/web/index.py40
10 files changed, 225 insertions, 102 deletions
diff --git a/examples/filebrowser/js-lib/common.js b/examples/filebrowser/js-lib/common.js
index a7e52c7..31a9162 100644
--- a/examples/filebrowser/js-lib/common.js
+++ b/examples/filebrowser/js-lib/common.js
@@ -13,7 +13,7 @@ function lazyToggle(container, url, options) {
if (Element.hidden(container)) {
Element.show(container);
if (! $(container).lazy_loaded) {
- new Ajax.Updater(container, url, {method: 'get'});
+ new Ajax.Updater(container, url, options);
$(container).lazy_loaded = true;
}
if (options.link) {
diff --git a/examples/filebrowser/pathobj.py b/examples/filebrowser/pathobj.py
new file mode 100644
index 0000000..015b882
--- /dev/null
+++ b/examples/filebrowser/pathobj.py
@@ -0,0 +1,175 @@
+import re
+import os
+import mimetypes
+from paste.wareweb import dispatch, public
+from paste.httpexceptions import *
+import sitepage
+
+view_servlet_module = None
+
+class BadFilePath(Exception):
+ pass
+
+class PathContext(object):
+
+ path_classes = {}
+
+ def __init__(self, root):
+ self.root = root
+
+ def path(self, path):
+ filename = self.root + '/' + path.lstrip('/')
+ if os.path.isdir(filename):
+ ptype = 'dir'
+ else:
+ ptype = os.path.splitext(filename)[1]
+ path_class = self.path_classes.get(
+ ptype, self.path_classes['*'])
+ return path_class(path, filename, self)
+
+ @classmethod
+ def register_class(cls, path_class):
+ assert not isinstance(path_class.extensions, (str, unicode))
+ for ptype in path_class.extensions:
+ assert ptype not in cls.path_classes, (
+ "When adding class %r, conflict with class %r for "
+ "extension %r" % (path_class, cls.path_classes[ptype],
+ ptype))
+ cls.path_classes[ptype] = path_class
+
+class Path(sitepage.SitePage):
+
+ extensions = ['*']
+
+ dispatch = dispatch.ActionDispatch(
+ action_name='action',
+ default_action='view_raw')
+
+ isdir = False
+
+ def __init__(self, path, filename, context):
+ super(Path, self).__init__()
+ self.path = path
+ self.filename = filename
+ self.pathcontext = context
+ self.root = context.root
+ self.mimetype, self.encoding = mimetypes.guess_type(self.filename)
+ if not self.mimetype:
+ self.mimetype = 'application/octet-stream'
+ self.basename = os.path.basename(filename)
+ self.exists = os.path.exists(filename)
+
+ def __str__(self):
+ return self.path
+
+ def __repr__(self):
+ return '<%s %s>' % (self.__class__.__name__, self.path)
+
+ def setup(self):
+ self.title = 'File: %s' % self.basename
+ self.options.parent = {
+ 'url': self.pathurl.up(),
+ 'name': self.pathurl.up().name() or 'root',
+ }
+ self.setup_file()
+
+ def setup_file(self):
+ mime = self.mimetype
+ if mime and mime.startswith('text/'):
+ self.options.content = self.read()
+ else:
+ self.options.content = None
+ self.options.is_image = mime and mime.startswith('image/')
+ self.options.use_iframe = mime == 'text/html'
+
+ def action_view(self):
+ self.view = 'view_file.pt'
+ self.options.allow_edit = self.mimetype.startswith('text/')
+
+ def join(self, name):
+ parts = name.split('/')
+ for part in parts:
+ if part.startswith('.'):
+ raise BadFilePath(
+ "The path part %r starts with '.', which is illegal"
+ % part)
+ if ':' in name:
+ raise BadFilePath(
+ "The path %r contains ':', which is illegal" % name)
+ if '\\' in name:
+ raise BadFilePath(
+ "The path %r contains '\\', which is illegal" % name)
+ name = name.lstrip('/')
+ name = re.sub(r'//+', '/', name)
+ new_path = self.path + '/' + name
+ return self.pathcontext.path(new_path)
+
+ bad_regexes = [
+ re.compile(r'<script.*?</script>', re.I+re.S),
+ re.compile(r'style="[^"]*position:.*?"', re.I+re.S),
+ ]
+
+ def action_view_raw(self):
+ self.view = None
+ if not self.exists:
+ raise HTTPNotFound
+ self.set_header('Content-type', self.mimetype)
+ content = self.read()
+ if (self.mimetype.startswith('text/html')
+ and servlet.fields.get('html') == 'clean'):
+ for bad_regex in bad_regexes:
+ content = self.bad_regex.sub('', content)
+ self.write(content)
+
+ def action_edit(self):
+ self.view = 'edit_text.pt'
+ self.options.content = self.read()
+ self.options.action = str(self.pathurl)
+
+ def action_save(self):
+ content = self.fields.content
+ f = open(self.filename, 'wb')
+ f.write(content)
+ f.close()
+ self.message.write('%i bytes saved' % len(content))
+ self.redirect(str(self.pathurl(action='view')))
+
+ def read(self):
+ f = open(self.filename, 'rb')
+ content = f.read()
+ f.close()
+ return content
+
+PathContext.register_class(Path)
+
+class Dir(Path):
+
+ extensions = ['dir']
+
+ isdir = True
+
+ def setup_file(self):
+ files = []
+ for filename in sorted(os.listdir(self.filename)):
+ try:
+ path_servlet = self.join(filename)
+ except BadFilePath:
+ continue
+ files.append({
+ 'path': path_servlet,
+ 'name': filename,
+ 'url': self.pathurl(filename, action='view'),
+ 'copyid': self.pathid('copy_', str(path_servlet)),
+ })
+ if path_servlet.isdir:
+ files[-1]['name'] += '/'
+ self.options.files = files
+
+ def action_view_raw(self):
+ self.action_view()
+
+ def action_view(self):
+ self.view = 'directory.pt'
+
+PathContext.register_class(Dir)
+
diff --git a/examples/filebrowser/server.conf b/examples/filebrowser/server.conf
index 7a0dd1b..da36acb 100644
--- a/examples/filebrowser/server.conf
+++ b/examples/filebrowser/server.conf
@@ -5,13 +5,8 @@ import os
app_template = 'wareweb_zpt'
app_name = 'filebrowser'
framework = 'wareweb'
-root_path = '/home/ianb/svn.w4py.org/Paste/trunk/examples/filebrowser'
+root_path = os.path.dirname(__file__)
publish_dir = os.path.join(root_path, 'web')
-sys_path.extend([
- os.path.dirname(root_path),
- '/home/ianb/co/py-lib',
- '/home/ianb/co/ZPTKit',
- ])
## Server options:
@@ -23,6 +18,9 @@ server = 'wsgiutils'
reload = True
# If true, tracebacks will be shown in the browser:
debug = True
+show_exceptions_in_error_log = False
browse_path = os.path.join(root_path, 'test-data')
-#browse_path = '/home/ianb/media/music/artist'
+
+if os.path.exists(os.path.join(root_path, 'local.conf')):
+ include('local.conf')
diff --git a/examples/filebrowser/sitepage.py b/examples/filebrowser/sitepage.py
index 10ac1a5..62b31ad 100644
--- a/examples/filebrowser/sitepage.py
+++ b/examples/filebrowser/sitepage.py
@@ -4,8 +4,8 @@ import os
import urllib
from paste.wareweb import *
from paste import wsgilib
+from paste import CONFIG
from ZPTKit.zptwareweb import ZPTComponent
-from py.path import local
import handlers
class SitePage(Servlet):
@@ -16,32 +16,23 @@ class SitePage(Servlet):
def awake(self):
super(SitePage, self).awake(call_setup=False)
- self.root = local(self.config['browse_path'])
- if 'browser.filepath' in self.environ:
- self.pathinfo = self.environ['browser.filepath']
- self.path = self.root.join(self.pathinfo)
- else:
- self.pathinfo = ''
- self.path = None
+ self.pathcontext = self.environ['filebrowser.pathcontext']
self.pathurl = URL(self.environ,
script_name=self.app_url,
- path_info=self.pathinfo)
+ path_info=self.path_info)
+ # While this is the URL that points to the non-file-specific
+ # application (for things like copy and past)
self.globalurl = URL(self.environ,
script_name=self.app_url + '/_app',
path_info='')
self.icons = Icon(self.app_url + '/_icons')
self.app_static_url = self.app_url + '/_static'
+ # Prototype adds this special _ variable for Ajax requests:
self.fragment = '_' in self.fields
self.copybin = self.session.setdefault('copybin', {})
self.update_copybin_display()
self.setup()
- def rootedpath(self, path):
- path = str(path)
- assert path.startswith(str(self.root)), (
- "Bad path: %r (doesn't start with %r)" % (path, self.root))
- return path[len(str(self.root)):]
-
def handler(self, path=None):
path = path or self.file
handler = handlers.get_handler(path)
@@ -49,10 +40,10 @@ class SitePage(Servlet):
def update_copybin_display(self):
files = self.options.copyfiles = []
for filename, cutcopy in self.copybin.items():
- path = local(self.root).join(filename)
+ path = self.pathcontext.path(filename)
files.append(
{'filename': filename,
- 'url': self.app_url + filename,
+ 'url': self.app_url + filename + "?action=view",
'path': path,
'name': path.basename,
'cut': cutcopy=='cut',
@@ -62,14 +53,12 @@ class SitePage(Servlet):
files.sort(key=lambda x: x['filename'])
def pathid(self, prefix, path):
- if isinstance(path, local):
- path = self.rootedpath(path)
- return prefix + path.replace('/', '__')
+ return prefix + str(path).replace('/', '__')
def copybutton(self, path, copytype='copy'):
assert copytype in ('copy', 'cut')
copyurl = self.globalurl('copybin', **{
- copytype: self.rootedpath(path)})
+ copytype: path})
remote = copyurl.remote(
id='copybin',
onComplete='function (req) {new Effect.Highlight(%r)}'
@@ -79,7 +68,7 @@ class SitePage(Servlet):
return remote.link(img)
def pastebutton(self, path):
- copyurl = self.globalurl('copybin', paste=self.rootedpath(path),
+ copyurl = self.globalurl('copybin', paste=path,
back=wsgilib.construct_url(self.environ))
return '<a href="%s">%s</a>' % (
copyurl, self.icons('editpaste', alt="paste",
@@ -155,6 +144,9 @@ class URL(object):
def name(self):
return self.path_info.split('/')[-1]
+ def js_set_location(self):
+ return 'location.href = %r' % str(self)
+
_idgen_count = itertools.count()
def idgen():
return 'node%s' % hex(_idgen_count.next() % 0xffffff)[2:]
@@ -190,7 +182,7 @@ class JSRemote(object):
class JSToggle(JSRemote):
def javascript(self):
- return "lazyToggle(%r, %r, {link: this, parameters: %r}); return false" % (
+ return "lazyToggle(%r, %r, %s); return false" % (
self.id, self.url.url_without_qs,
self.option_js(parameters=repr(urllib.urlencode(self.url.vars.items())),
link='this'))
diff --git a/examples/filebrowser/templates/directory.pt b/examples/filebrowser/templates/directory.pt
index 6215086..5f0df9a 100644
--- a/examples/filebrowser/templates/directory.pt
+++ b/examples/filebrowser/templates/directory.pt
@@ -18,7 +18,7 @@
'odd', 'even')"
tal:define="toggle f/url/toggle">
<div class="controls">
- <span tal:condition="python: f['path'].check(dir=1)"
+ <span tal:condition="python: f['path'].isdir"
tal:replace="structure python: servlet.pastebutton(f['path'])"/>
<span tal:replace="structure python: servlet.copybutton(f['path'], 'cut')"/>
<span tal:replace="structure python: servlet.copybutton(f['path'],
diff --git a/examples/filebrowser/templates/edit_text.pt b/examples/filebrowser/templates/edit_text.pt
new file mode 100644
index 0000000..e2d7ba7
--- /dev/null
+++ b/examples/filebrowser/templates/edit_text.pt
@@ -0,0 +1,15 @@
+<html metal:use-macro="here/standard_template.pt/macros/page">
+<metal:body fill-slot="body">
+
+<form tal:attributes="action options/action" method="POST">
+<input type="hidden" name="action" value="save">
+Edit:<br>
+<textarea name="content" rows=10 cols=60 style="width: 100%"
+ tal:content="options/content"></textarea>
+<br>
+<input type="submit" value="Save">
+<button tal:attributes="onclick servlet/pathurl/js_set_location">Cancel</button>
+</form>
+
+</metal:body>
+</html> \ No newline at end of file
diff --git a/examples/filebrowser/templates/view_file.pt b/examples/filebrowser/templates/view_file.pt
index f0904df..d6ad93a 100644
--- a/examples/filebrowser/templates/view_file.pt
+++ b/examples/filebrowser/templates/view_file.pt
@@ -8,8 +8,11 @@ Parent: <a tal:attributes="href options/parent/url"
tal:content="options/parent/name">name</a><br>
</tal:if>
</tal:if>
-Mimetype: <span tal:replace="options/mimetype"/><br>
+Mimetype: <span tal:replace="servlet/mimetype"/><br>
<a tal:attributes="href servlet/pathurl/action=download">download</a>
+<tal:if condition="options/allow_edit"> |
+ <a tal:attributes="href servlet/pathurl/action=edit">edit</a></tal:if>
+
</p>
<pre tal:condition="python: options['content'] and not options['use_iframe']"
diff --git a/examples/filebrowser/web/__init__.py b/examples/filebrowser/web/__init__.py
index 0ffdb8b..4be1d00 100644
--- a/examples/filebrowser/web/__init__.py
+++ b/examples/filebrowser/web/__init__.py
@@ -1,9 +1,11 @@
import os
import urllib
from py.path import local
+from paste import CONFIG
from paste import wsgilib
from paste import httpexceptions
from paste import urlparser
+from filebrowser import pathobj
def urlparser_hook(environ):
if not environ.has_key('filebrowser.base_url'):
@@ -20,20 +22,18 @@ special_dirs['app'] = urlparser.URLParser(
os.path.dirname(__file__), 'filebrowser.web')
def application(environ, start_response):
- if environ.get('browser.resolved'):
+ context = environ['filebrowser.pathcontext'] = pathobj.PathContext(
+ root=environ['paste.config']['browse_path'])
+ if environ.get('filebrowser.resolved'):
return special_dirs['app'](environ, start_response)
- conf = environ['paste.config']
path_info = environ.get('PATH_INFO', '')
for special_dir, parser in special_dirs.items():
if path_info.startswith('/_%s/' % special_dir):
- environ['browser.resolved'] = True
+ environ['filebrowser.resolved'] = True
wsgilib.path_info_pop(environ)
return parser(environ, start_response)
- environ['browser.filepath'] = urllib.unquote(environ['PATH_INFO'])
- vars = dict(wsgilib.parse_querystring(environ))
- action = (vars.get('action') or ['index'])[0]
- servlet_fn = os.path.join(os.path.dirname(__file__), action + '.py')
- servlet_app = urlparser.make_py(environ, servlet_fn)
- return servlet_app(environ, start_response)
+ path = urllib.unquote(environ['PATH_INFO'])
+ path_servlet = context.path(path)
+ return path_servlet(environ, start_response)
diff --git a/examples/filebrowser/web/download.py b/examples/filebrowser/web/download.py
deleted file mode 100644
index a18ebf6..0000000
--- a/examples/filebrowser/web/download.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import mimetypes
-import re
-from filebrowser.sitepage import SitePage
-
-bad_regexes = [
- re.compile(r'<script.*?</script>', re.I+re.S),
- re.compile(r'style="[^"]*position:.*?"', re.I+re.S),
- ]
-
-class download(SitePage):
-
- def setup(self):
- mime, _ = mimetypes.guess_type(str(self.path))
- self.set_header('Content-type', mime)
- self.view = None
- content = self.path.read()
- if self.fields.get('html') == 'clean':
- for bad_regex in bad_regexes:
- content = bad_regex.sub('', content)
- self.write(content)
diff --git a/examples/filebrowser/web/index.py b/examples/filebrowser/web/index.py
deleted file mode 100644
index 2a80712..0000000
--- a/examples/filebrowser/web/index.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import mimetypes
-from filebrowser.sitepage import SitePage
-
-class index(SitePage):
-
- def setup(self):
- self.title = 'File: %s' % self.path.basename
- self.options.parent = {
- 'url': self.pathurl.up(),
- 'name': self.pathurl.up().name() or 'root',
- }
- if self.path.check(dir=1):
- self.setup_dir()
- else:
- self.setup_file()
-
- def setup_dir(self):
- files = []
- for f in self.path.listdir(sort=True):
- files.append({
- 'path': f,
- 'name': f.basename,
- 'url': self.pathurl[f.basename],
- 'copyid': self.pathid('copy_', f),
- })
- if f.check(dir=1):
- files[-1]['name'] += '/'
- self.options.files = files
- self.view = 'directory.pt'
-
- def setup_file(self):
- self.options.mimetype, _ = mimetypes.guess_type(str(self.path))
- mime = self.options.mimetype
- self.view = 'view_file.pt'
- if mime and mime.startswith('text/'):
- self.options.content = self.path.read()
- else:
- self.options.content = None
- self.options.is_image = mime and mime.startswith('image/')
- self.options.use_iframe = mime == 'text/html'