mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-20 19:49:06 +00:00
checkpointing new webapi: not all tests pass yet
This commit is contained in:
parent
21e12f383d
commit
6570253d6b
525
src/allmydata/test/test_web.py
Normal file
525
src/allmydata/test/test_web.py
Normal file
@ -0,0 +1,525 @@
|
||||
|
||||
import re, os.path
|
||||
from zope.interface import implements
|
||||
from twisted.application import service
|
||||
from twisted.trial import unittest
|
||||
from twisted.internet import defer
|
||||
from twisted.web import client, error
|
||||
from twisted.python import failure
|
||||
from allmydata import webish, interfaces, dirnode, uri
|
||||
from allmydata.encode import NotEnoughPeersError
|
||||
import itertools
|
||||
|
||||
# create a fake uploader/downloader, and a couple of fake dirnodes, then
|
||||
# create a webserver that works against them
|
||||
|
||||
class MyClient(service.MultiService):
|
||||
nodeid = "fake_nodeid"
|
||||
def get_versions(self):
|
||||
return {'allmydata': "fake",
|
||||
'foolscap': "fake",
|
||||
'twisted': "fake",
|
||||
'zfec': "fake",
|
||||
}
|
||||
introducer_furl = "None"
|
||||
def connected_to_introducer(self):
|
||||
return False
|
||||
def get_all_peerids(self):
|
||||
return []
|
||||
|
||||
class MyDownloader(service.Service):
|
||||
implements(interfaces.IDownloader)
|
||||
name = "downloader"
|
||||
def __init__(self, files):
|
||||
self.files = files
|
||||
|
||||
def download(self, uri, target):
|
||||
print "DOWNLOADING", uri
|
||||
if uri not in self.files:
|
||||
e = NotEnoughPeersError()
|
||||
f = failure.Failure(e)
|
||||
target.fail(f)
|
||||
return defer.fail(f)
|
||||
data = self.files[uri]
|
||||
target.open(len(data))
|
||||
target.write(data)
|
||||
target.close()
|
||||
return defer.maybeDeferred(target.finish)
|
||||
|
||||
uri_counter = itertools.count()
|
||||
|
||||
class MyUploader(service.Service):
|
||||
implements(interfaces.IUploader)
|
||||
name = "uploader"
|
||||
def __init__(self, files):
|
||||
self.files = files
|
||||
|
||||
def upload(self, uploadable):
|
||||
f = uploadable.get_filehandle()
|
||||
data = f.read()
|
||||
uri = str(uri_counter.next())
|
||||
self.files[uri] = data
|
||||
uploadable.close_filehandle(f)
|
||||
return defer.succeed(uri)
|
||||
|
||||
class MyDirectoryNode(dirnode.MutableDirectoryNode):
|
||||
|
||||
def __init__(self, nodes, uri=None):
|
||||
self._nodes = nodes
|
||||
if uri is None:
|
||||
uri = str(uri_counter.next())
|
||||
self._uri = str(uri)
|
||||
self._nodes[self._uri] = self
|
||||
self.children = {}
|
||||
self._mutable = True
|
||||
|
||||
def get_immutable_uri(self):
|
||||
return self.get_uri() + "RO"
|
||||
|
||||
def get(self, name):
|
||||
def _try():
|
||||
uri = self.children[name]
|
||||
if uri not in self._nodes:
|
||||
raise IndexError("this isn't supposed to happen")
|
||||
return self._nodes[uri]
|
||||
return defer.maybeDeferred(_try)
|
||||
|
||||
def set_uri(self, name, child_uri):
|
||||
self.children[name] = child_uri
|
||||
return defer.succeed(None)
|
||||
|
||||
def create_empty_directory(self, name):
|
||||
node = MyDirectoryNode(self._nodes)
|
||||
self.children[name] = node.get_uri()
|
||||
return defer.succeed(node)
|
||||
|
||||
def list(self):
|
||||
kids = dict([(name, self._nodes[uri])
|
||||
for name,uri in self.children.iteritems()])
|
||||
return defer.succeed(kids)
|
||||
|
||||
class MyFileNode(dirnode.FileNode):
|
||||
pass
|
||||
|
||||
|
||||
class MyVirtualDrive(service.Service):
|
||||
name = "vdrive"
|
||||
public_root = None
|
||||
private_root = None
|
||||
def have_public_root(self):
|
||||
return bool(self.public_root)
|
||||
def have_private_root(self):
|
||||
return bool(self.private_root)
|
||||
def get_public_root(self):
|
||||
return defer.succeed(self.public_root)
|
||||
def get_private_root(self):
|
||||
return defer.succeed(self.private_root)
|
||||
|
||||
class Web(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.s = MyClient()
|
||||
self.s.startService()
|
||||
s = webish.WebishServer("0")
|
||||
s.setServiceParent(self.s)
|
||||
port = s.listener._port.getHost().port
|
||||
self.webish_url = "http://localhost:%d" % port
|
||||
|
||||
v = MyVirtualDrive()
|
||||
v.setServiceParent(self.s)
|
||||
|
||||
self.nodes = {} # maps URI to node
|
||||
self.files = {} # maps file URI to contents
|
||||
dl = MyDownloader(self.files)
|
||||
dl.setServiceParent(self.s)
|
||||
ul = MyUploader(self.files)
|
||||
ul.setServiceParent(self.s)
|
||||
|
||||
v.public_root = MyDirectoryNode(self.nodes)
|
||||
v.private_root = MyDirectoryNode(self.nodes)
|
||||
foo = MyDirectoryNode(self.nodes)
|
||||
self._foo_node = foo
|
||||
self._foo_uri = foo.get_uri()
|
||||
self._foo_readonly_uri = foo.get_immutable_uri()
|
||||
v.public_root.children["foo"] = foo.get_uri()
|
||||
|
||||
self.BAR_CONTENTS = "bar.txt contents"
|
||||
|
||||
bar_uri = uri.pack_uri("SI"+"0"*30,
|
||||
"K"+"0"*15,
|
||||
"EH"+"0"*30,
|
||||
25, 100, 123)
|
||||
bar_txt = MyFileNode(bar_uri, self.s)
|
||||
self._bar_txt_uri = bar_txt.get_uri()
|
||||
self.nodes[bar_uri] = bar_txt
|
||||
self.files[bar_txt.get_uri()] = self.BAR_CONTENTS
|
||||
foo.children["bar.txt"] = bar_txt.get_uri()
|
||||
|
||||
foo.children["sub"] = MyDirectoryNode(self.nodes).get_uri()
|
||||
|
||||
blocking_uri = uri.pack_uri("SI"+"1"*30,
|
||||
"K"+"1"*15,
|
||||
"EH"+"1"*30,
|
||||
25, 100, 124)
|
||||
blocking_file = MyFileNode(blocking_uri, self.s)
|
||||
self.nodes[blocking_uri] = blocking_file
|
||||
self.files[blocking_uri] = "blocking contents"
|
||||
foo.children["blockingfile"] = blocking_file.get_uri()
|
||||
|
||||
# public/
|
||||
# public/foo/
|
||||
# public/foo/bar.txt
|
||||
# public/foo/sub/
|
||||
# public/foo/blockingfile
|
||||
self.NEWFILE_CONTENTS = "newfile contents\n"
|
||||
|
||||
def tearDown(self):
|
||||
return self.s.stopService()
|
||||
|
||||
def failUnlessIsBarDotTxt(self, res):
|
||||
self.failUnlessEqual(res, self.BAR_CONTENTS)
|
||||
|
||||
def GET(self, urlpath):
|
||||
url = self.webish_url + urlpath
|
||||
return client.getPage(url, method="GET")
|
||||
|
||||
def PUT(self, urlpath, data):
|
||||
url = self.webish_url + urlpath
|
||||
return client.getPage(url, method="PUT", postdata=data)
|
||||
|
||||
def DELETE(self, urlpath):
|
||||
url = self.webish_url + urlpath
|
||||
return client.getPage(url, method="DELETE")
|
||||
|
||||
def POST(self, urlpath, data):
|
||||
url = self.webish_url + urlpath
|
||||
return client.getPage(url, method="POST", postdata=data)
|
||||
|
||||
def shouldFail(self, res, expected_failure, which, substring=None):
|
||||
print "SHOULDFAIL", res
|
||||
if isinstance(res, failure.Failure):
|
||||
res.trap(expected_failure)
|
||||
if substring:
|
||||
self.failUnless(substring in str(res),
|
||||
"substring '%s' not in '%s'"
|
||||
% (substring, str(res)))
|
||||
else:
|
||||
self.fail("%s was supposed to raise %s, not get '%s'" %
|
||||
(which, expected_failure, res))
|
||||
|
||||
def should404(self, res, which):
|
||||
if isinstance(res, failure.Failure):
|
||||
res.trap(error.Error)
|
||||
self.failUnlessEqual(res.value.status, "404")
|
||||
else:
|
||||
self.fail("%s was supposed to raise %s, not get '%s'" %
|
||||
(which, expected_failure, res))
|
||||
|
||||
def test_create(self): # YES
|
||||
pass
|
||||
|
||||
def test_welcome(self): # YES
|
||||
d = self.GET("")
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL(self): # YES
|
||||
d = self.GET("/vdrive/global/foo/bar.txt")
|
||||
d.addCallback(self.failUnlessIsBarDotTxt)
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_missing(self): # YES
|
||||
d = self.GET("/vdrive/global/foo/missing")
|
||||
def _oops(f):
|
||||
print f
|
||||
print dir(f)
|
||||
print f.value
|
||||
print dir(f.value)
|
||||
print f.value.args
|
||||
print f.value.response
|
||||
print f.value.status
|
||||
return f
|
||||
#d.addBoth(_oops)
|
||||
d.addBoth(self.should404, "test_GET_FILEURL_missing")
|
||||
return d
|
||||
|
||||
def test_PUT_NEWFILEURL(self): # YES
|
||||
d = self.PUT("/vdrive/global/foo/new.txt", self.NEWFILE_CONTENTS)
|
||||
def _check(res):
|
||||
self.failUnless("new.txt" in self._foo_node.children)
|
||||
new_uri = self._foo_node.children["new.txt"]
|
||||
new_contents = self.files[new_uri]
|
||||
self.failUnlessEqual(new_contents, self.NEWFILE_CONTENTS)
|
||||
self.failUnlessEqual(res.strip(), new_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWFILEURL_mkdirs(self): # YES
|
||||
d = self.PUT("/vdrive/global/foo/newdir/new.txt", self.NEWFILE_CONTENTS)
|
||||
def _check(res):
|
||||
self.failIf("new.txt" in self._foo_node.children)
|
||||
self.failUnless("newdir" in self._foo_node.children)
|
||||
newdir_uri = self._foo_node.children["newdir"]
|
||||
newdir_node = self.nodes[newdir_uri]
|
||||
self.failUnless("new.txt" in newdir_node.children)
|
||||
new_uri = newdir_node.children["new.txt"]
|
||||
new_contents = self.files[new_uri]
|
||||
self.failUnlessEqual(new_contents, self.NEWFILE_CONTENTS)
|
||||
self.failUnlessEqual(res.strip(), new_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWFILEURL_blocked(self): # YES
|
||||
d = self.PUT("/vdrive/global/foo/blockingfile/new.txt",
|
||||
self.NEWFILE_CONTENTS)
|
||||
d.addBoth(self.shouldFail, error.Error, "PUT_NEWFILEURL_blocked",
|
||||
"403 Forbidden")
|
||||
return d
|
||||
|
||||
def test_DELETE_FILEURL(self):
|
||||
d = self.DELETE("/vdrive/global/foo/bar.txt")
|
||||
return d
|
||||
|
||||
def test_DELETE_FILEURL_missing(self):
|
||||
d = self.DELETE("/vdrive/global/foo/missing")
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_json(self): # YES
|
||||
# twisted.web.http.parse_qs ignores any query args without an '=', so
|
||||
# I can't do "GET /path?json", I have to do "GET /path/t=json"
|
||||
# instead. This may make it tricky to emulate the S3 interface
|
||||
# completely.
|
||||
d = self.GET("/vdrive/global/foo/bar.txt?t=json")
|
||||
def _got(json):
|
||||
# TODO
|
||||
self.failUnless("JSON" in json, json)
|
||||
d.addCallback(_got)
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_json_missing(self): # YES
|
||||
d = self.GET("/vdrive/global/foo/missing?json")
|
||||
d.addBoth(self.should404, "test_GET_FILEURL_json_missing")
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_localfile(self): # YES
|
||||
localfile = os.path.abspath("web/GET_FILEURL_localfile")
|
||||
os.makedirs("web")
|
||||
d = self.GET("/vdrive/global/foo/bar.txt?localfile=%s" % localfile)
|
||||
def _done(res):
|
||||
self.failUnless(os.path.exists(localfile))
|
||||
data = open(localfile, "rb").read()
|
||||
self.failUnlessEqual(data, self.BAR_CONTENTS)
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_localfile_nonlocal(self): # YES
|
||||
# TODO: somehow pretend that we aren't local, and verify that the
|
||||
# server refuses to write to local files, probably by changing the
|
||||
# server's idea of what counts as "local".
|
||||
old_LOCALHOST = webish.LOCALHOST
|
||||
webish.LOCALHOST = "127.0.0.2"
|
||||
localfile = os.path.abspath("web/GET_FILEURL_localfile_nonlocal")
|
||||
os.makedirs("web")
|
||||
d = self.GET("/vdrive/global/foo/bar.txt?localfile=%s" % localfile)
|
||||
d.addBoth(self.shouldFail, error.Error, "localfile non-local",
|
||||
"403 Forbidden")
|
||||
def _check(res):
|
||||
self.failIf(os.path.exists(localfile))
|
||||
d.addCallback(_check)
|
||||
def _reset(res):
|
||||
print "RESETTING", res
|
||||
webish.LOCALHOST = old_LOCALHOST
|
||||
return res
|
||||
d.addBoth(_reset)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWFILEURL_localfile(self): # YES
|
||||
localfile = os.path.abspath("web/PUT_NEWFILEURL_localfile")
|
||||
os.makedirs("web")
|
||||
f = open(localfile, "wb")
|
||||
f.write(self.NEWFILE_CONTENTS)
|
||||
f.close()
|
||||
d = self.PUT("/vdrive/global/foo/new.txt?localfile=%s" % localfile, "")
|
||||
def _check(res):
|
||||
self.failUnless("new.txt" in self._foo_node.children)
|
||||
new_uri = self._foo_node.children["new.txt"]
|
||||
new_contents = self.files[new_uri]
|
||||
self.failUnlessEqual(new_contents, self.NEWFILE_CONTENTS)
|
||||
self.failUnlessEqual(res.strip(), new_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWFILEURL_localfile_mkdirs(self): # YES
|
||||
localfile = os.path.abspath("web/PUT_NEWFILEURL_localfile_mkdirs")
|
||||
os.makedirs("web")
|
||||
f = open(localfile, "wb")
|
||||
f.write(self.NEWFILE_CONTENTS)
|
||||
f.close()
|
||||
d = self.PUT("/vdrive/global/foo/newdir/new.txt?localfile=%s" %
|
||||
localfile, "")
|
||||
def _check(res):
|
||||
self.failIf("new.txt" in self._foo_node.children)
|
||||
self.failUnless("newdir" in self._foo_node.children)
|
||||
newdir_uri = self._foo_node.children["newdir"]
|
||||
newdir_node = self.nodes[newdir_uri]
|
||||
self.failUnless("new.txt" in newdir_node.children)
|
||||
new_uri = newdir_node.children["new.txt"]
|
||||
new_contents = self.files[new_uri]
|
||||
self.failUnlessEqual(new_contents, self.NEWFILE_CONTENTS)
|
||||
self.failUnlessEqual(res.strip(), new_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_uri(self): # YES
|
||||
d = self.GET("/vdrive/global/foo/bar.txt?t=uri")
|
||||
def _check(res):
|
||||
self.failUnlessEqual(res, self._bar_txt_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_GET_FILEURL_uri_missing(self): # YES
|
||||
d = self.GET("/vdrive/global/foo/missing?t=uri")
|
||||
d.addBoth(self.should404, "test_GET_FILEURL_uri_missing")
|
||||
return d
|
||||
|
||||
def test_GET_DIRURL(self): # YES
|
||||
d = self.GET("/vdrive/global/foo")
|
||||
def _check(res):
|
||||
self.failUnless(re.search(r'<td><a href="bar.txt">bar.txt</a></td>'
|
||||
'\s+<td>FILE</td>'
|
||||
'\s+<td>123</td>'
|
||||
, res))
|
||||
self.failUnless(re.search(r'<td><a href="sub">sub</a></td>'
|
||||
'\s+<td>DIR</td>', res))
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_GET_DIRURL_json(self): # YES
|
||||
d = self.GET("/vdrive/global/foo?t=json")
|
||||
def _got(json):
|
||||
# TODO
|
||||
self.failUnless("JSON" in json, json)
|
||||
d.addCallback(_got)
|
||||
return d
|
||||
|
||||
def test_GET_DIRURL_uri(self): # YES
|
||||
d = self.GET("/vdrive/global/foo?t=uri")
|
||||
def _check(res):
|
||||
self.failUnlessEqual(res, self._foo_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_GET_DIRURL_readonly_uri(self): # YES
|
||||
d = self.GET("/vdrive/global/foo?t=readonly-uri")
|
||||
def _check(res):
|
||||
self.failUnlessEqual(res, self._foo_readonly_uri)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWDIRURL(self): # YES
|
||||
d = self.PUT("/vdrive/global/foo/newdir?t=mkdir", "")
|
||||
def _check(res):
|
||||
self.failUnless("newdir" in self._foo_node.children)
|
||||
newdir_uri = self._foo_node.children["newdir"]
|
||||
newdir_node = self.nodes[newdir_uri]
|
||||
self.failIf(newdir_node.children)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWDIRURL_mkdirs(self): # YES
|
||||
d = self.PUT("/vdrive/global/foo/subdir/newdir?t=mkdir", "")
|
||||
def _check(res):
|
||||
self.failIf("newdir" in self._foo_node.children)
|
||||
self.failUnless("subdir" in self._foo_node.children)
|
||||
subdir_node = self.nodes[self._foo_node.children["subdir"]]
|
||||
self.failUnless("newdir" in subdir_node.children)
|
||||
newdir_node = self.nodes[subdir_node.children["newdir"]]
|
||||
self.failIf(newdir_node.children)
|
||||
d.addCallback(_check)
|
||||
return d
|
||||
|
||||
def test_DELETE_DIRURL(self):
|
||||
d = self.DELETE("/vdrive/global/foo")
|
||||
return d
|
||||
|
||||
def test_DELETE_DIRURL_missing(self):
|
||||
d = self.DELETE("/vdrive/global/missing")
|
||||
return d
|
||||
|
||||
def test_GET_DIRURL_localdir(self):
|
||||
localdir = os.path.abspath("web/GET_DIRURL_localdir")
|
||||
os.makedirs("web")
|
||||
d = self.GET("/vdrive/global/foo?localdir=%s" % localdir)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWDIRURL_localdir(self):
|
||||
localdir = os.path.abspath("web/PUT_NEWDIRURL_localdir")
|
||||
os.makedirs("web")
|
||||
# create some files there
|
||||
d = self.GET("/vdrive/global/foo/newdir?localdir=%s" % localdir)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWDIRURL_localdir_mkdirs(self):
|
||||
localdir = os.path.abspath("web/PUT_NEWDIRURL_localdir_mkdirs")
|
||||
os.makedirs("web")
|
||||
# create some files there
|
||||
d = self.GET("/vdrive/global/foo/subdir/newdir?localdir=%s" % localdir)
|
||||
return d
|
||||
|
||||
def test_POST_upload(self):
|
||||
form = "TODO"
|
||||
d = self.POST("/vdrive/global/foo", form)
|
||||
return d
|
||||
|
||||
def test_POST_mkdir(self):
|
||||
form = "TODO"
|
||||
d = self.POST("/vdrive/global/foo", form)
|
||||
return d
|
||||
|
||||
def test_POST_put_uri(self):
|
||||
form = "TODO"
|
||||
d = self.POST("/vdrive/global/foo", form)
|
||||
return d
|
||||
|
||||
def test_POST_delete(self):
|
||||
form = "TODO, bar.txt"
|
||||
d = self.POST("/vdrive/global/foo", form)
|
||||
return d
|
||||
|
||||
def test_URI_GET(self):
|
||||
d = self.GET("/uri/%s/bar.txt" % foo_uri)
|
||||
return d
|
||||
|
||||
def test_PUT_NEWFILEURL_uri(self):
|
||||
d = self.PUT("/vdrive/global/foo/new.txt?uri", new_uri)
|
||||
return d
|
||||
|
||||
def test_XMLRPC(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
"""
|
||||
# GET / (welcome)
|
||||
# GET FILEURL
|
||||
# PUT NEWFILEURL
|
||||
# DELETE FILEURL
|
||||
# GET FILEURL?t=json
|
||||
# GET FILEURL?localfile=$FILENAME
|
||||
# PUT NEWFILEURL?localfile=$FILENAME
|
||||
# GET FILEURL?t=uri
|
||||
# GET DIRURL
|
||||
# GET DIRURL?t=json
|
||||
# GET DIRURL?t=uri
|
||||
# GET DIRURL?t=readonly-uri
|
||||
# PUT NEWDIRURL?t=mkdir
|
||||
# DELETE DIRURL
|
||||
# GET DIRURL?localdir=$DIRNAME
|
||||
# PUT NEWDIRURL?localdir=$DIRNAME
|
||||
# POST DIRURL?t=upload-form
|
||||
# POST DIRURL?t=mkdir-form
|
||||
# POST DIRURL?t=put-uri-form
|
||||
# POST DIRURL?t=delete-form
|
||||
# GET .../url/$URI
|
||||
# and a few others
|
||||
# PUT NEWFILEURL?t=uri
|
||||
# /xmlrpc
|
||||
"""
|
@ -2,13 +2,14 @@
|
||||
from twisted.application import service, strports
|
||||
from twisted.web import static, resource, server, html, http
|
||||
from twisted.python import util, log
|
||||
from twisted.internet import defer
|
||||
from nevow import inevow, rend, loaders, appserver, url, tags as T
|
||||
from nevow.static import File as nevow_File # TODO: merge with static.File?
|
||||
from allmydata.util import idlib
|
||||
from allmydata.uri import unpack_uri
|
||||
from allmydata.interfaces import IDownloadTarget, IDirectoryNode, IFileNode
|
||||
from allmydata.dirnode import FileNode
|
||||
from allmydata import upload
|
||||
from allmydata import upload, download
|
||||
from zope.interface import implements, Interface
|
||||
import urllib
|
||||
from formless import annotate, webform
|
||||
@ -24,84 +25,6 @@ def get_downloader_service(ctx):
|
||||
def get_uploader_service(ctx):
|
||||
return IClient(ctx).getServiceNamed("uploader")
|
||||
|
||||
class Welcome(rend.Page):
|
||||
addSlash = True
|
||||
docFactory = getxmlfile("welcome.xhtml")
|
||||
|
||||
def data_version(self, ctx, data):
|
||||
v = IClient(ctx).get_versions()
|
||||
return "tahoe: %s, zfec: %s, foolscap: %s, twisted: %s" % \
|
||||
(v['allmydata'], v['zfec'], v['foolscap'], v['twisted'])
|
||||
|
||||
def data_my_nodeid(self, ctx, data):
|
||||
return idlib.b2a(IClient(ctx).nodeid)
|
||||
def data_introducer_furl(self, ctx, data):
|
||||
return IClient(ctx).introducer_furl
|
||||
def data_connected_to_introducer(self, ctx, data):
|
||||
if IClient(ctx).connected_to_introducer():
|
||||
return "yes"
|
||||
return "no"
|
||||
def data_connected_to_vdrive(self, ctx, data):
|
||||
if IClient(ctx).getServiceNamed("vdrive").have_public_root():
|
||||
return "yes"
|
||||
return "no"
|
||||
def data_num_peers(self, ctx, data):
|
||||
#client = inevow.ISite(ctx)._client
|
||||
client = IClient(ctx)
|
||||
return len(list(client.get_all_peerids()))
|
||||
|
||||
def data_peers(self, ctx, data):
|
||||
d = []
|
||||
client = IClient(ctx)
|
||||
for nodeid in sorted(client.get_all_peerids()):
|
||||
row = (idlib.b2a(nodeid),)
|
||||
d.append(row)
|
||||
return d
|
||||
|
||||
def render_row(self, ctx, data):
|
||||
(nodeid_a,) = data
|
||||
ctx.fillSlots("peerid", nodeid_a)
|
||||
return ctx.tag
|
||||
|
||||
def render_global_vdrive(self, ctx, data):
|
||||
if IClient(ctx).getServiceNamed("vdrive").have_public_root():
|
||||
return T.p["To view the global shared filestore, ",
|
||||
T.a(href="../global_vdrive")["Click Here!"],
|
||||
]
|
||||
return T.p["vdrive.furl not specified (or vdrive server not "
|
||||
"responding), no vdrive available."]
|
||||
|
||||
def render_private_vdrive(self, ctx, data):
|
||||
if IClient(ctx).getServiceNamed("vdrive").have_private_root():
|
||||
return T.p["To view your personal private non-shared filestore, ",
|
||||
T.a(href="../private_vdrive")["Click Here!"],
|
||||
]
|
||||
return T.p["personal vdrive not available."]
|
||||
|
||||
# this is a form where users can download files by URI
|
||||
|
||||
def bind_download(self, ctx):
|
||||
uriarg = annotate.Argument("uri",
|
||||
annotate.String("URI of file to download: "))
|
||||
namearg = annotate.Argument("filename",
|
||||
annotate.String("Filename to download as: "))
|
||||
ctxarg = annotate.Argument("ctx", annotate.Context())
|
||||
meth = annotate.Method(arguments=[uriarg, namearg, ctxarg],
|
||||
label="Download File by URI")
|
||||
# buttons always use value=data.label
|
||||
# MethodBindingRenderer uses value=(data.action or data.label)
|
||||
return annotate.MethodBinding("download", meth, action="Download")
|
||||
|
||||
def download(self, uri, filename, ctx):
|
||||
log.msg("webish downloading URI")
|
||||
target = url.here.sibling("download_uri").add("uri", uri)
|
||||
if filename:
|
||||
target = target.add("filename", filename)
|
||||
return target
|
||||
|
||||
def render_forms(self, ctx, data):
|
||||
return webform.renderForms()
|
||||
|
||||
|
||||
class Directory(rend.Page):
|
||||
addSlash = True
|
||||
@ -112,27 +35,15 @@ class Directory(rend.Page):
|
||||
self._dirname = dirname
|
||||
|
||||
def childFactory(self, ctx, name):
|
||||
print "Directory.childFactory", name
|
||||
if name.startswith("freeform"): # ick
|
||||
return None
|
||||
if name == "@manifest": # ick, this time it's my fault
|
||||
return Manifest(self._dirnode, self._dirname)
|
||||
if self._dirname == "/":
|
||||
dirname = "/" + name
|
||||
else:
|
||||
dirname = self._dirname + "/" + name
|
||||
d = self._dirnode.get(name)
|
||||
def _got_child(res):
|
||||
if IFileNode.providedBy(res):
|
||||
dl = get_downloader_service(ctx)
|
||||
return Downloader(dl, name, res)
|
||||
elif IDirectoryNode.providedBy(res):
|
||||
return Directory(res, dirname)
|
||||
else:
|
||||
raise RuntimeError("what is this %s" % res)
|
||||
d.addCallback(_got_child)
|
||||
return d
|
||||
return rend.NotFound
|
||||
|
||||
def render_title(self, ctx, data):
|
||||
print "DIRECTORY.render_title"
|
||||
return ctx.tag["Directory '%s':" % self._dirname]
|
||||
|
||||
def render_header(self, ctx, data):
|
||||
@ -380,15 +291,13 @@ class TypedFile(static.File):
|
||||
self.contentEncodings,
|
||||
self.defaultType)
|
||||
|
||||
class Downloader(resource.Resource):
|
||||
def __init__(self, downloader, name, filenode):
|
||||
self._downloader = downloader
|
||||
class FileDownloader(resource.Resource):
|
||||
def __init__(self, name, filenode):
|
||||
self._name = name
|
||||
IFileNode(filenode)
|
||||
self._filenode = filenode
|
||||
|
||||
def render(self, ctx):
|
||||
req = inevow.IRequest(ctx)
|
||||
def render(self, req):
|
||||
gte = static.getTypeAndEncoding
|
||||
type, encoding = gte(self._name,
|
||||
static.File.contentTypes,
|
||||
@ -400,6 +309,242 @@ class Downloader(resource.Resource):
|
||||
d.addErrback(lambda why: None)
|
||||
return server.NOT_DONE_YET
|
||||
|
||||
class BlockingFileError(Exception):
|
||||
"""We cannot auto-create a parent directory, because there is a file in
|
||||
the way"""
|
||||
|
||||
LOCALHOST = "127.0.0.1"
|
||||
|
||||
class NeedLocalhostError:
|
||||
implements(inevow.IResource)
|
||||
|
||||
def locateChild(self, ctx, segments):
|
||||
return rend.NotFound
|
||||
|
||||
def renderHTTP(self, ctx):
|
||||
req = inevow.IRequest(ctx)
|
||||
req.setResponseCode(http.FORBIDDEN)
|
||||
req.setHeader("content-type", "text/plain")
|
||||
return "localfile= or localdir= requires a local connection"
|
||||
|
||||
|
||||
|
||||
class LocalFileDownloader(resource.Resource):
|
||||
def __init__(self, filenode, local_filename):
|
||||
self._local_filename = local_filename
|
||||
IFileNode(filenode)
|
||||
self._filenode = filenode
|
||||
|
||||
def render(self, req):
|
||||
print "LOCALFILEDOWNLOADER", self._local_filename
|
||||
target = download.FileName(self._local_filename)
|
||||
d = self._filenode.download(target)
|
||||
def _done(res):
|
||||
req.write(self._filenode.get_uri())
|
||||
req.finish()
|
||||
d.addCallback(_done)
|
||||
return server.NOT_DONE_YET
|
||||
|
||||
class FileJSONMetadata(rend.Page):
|
||||
def __init__(self, filenode):
|
||||
self._filenode = filenode
|
||||
|
||||
def renderHTTP(self, ctx):
|
||||
file_uri = self._filenode.get_uri()
|
||||
pieces = unpack_uri(file_uri)
|
||||
data = "filenode\n"
|
||||
data += "JSONny stuff here\n"
|
||||
data += "uri=%s, size=%s" % (file_uri, pieces['size'])
|
||||
return data
|
||||
|
||||
class FileXMLMetadata(FileJSONMetadata):
|
||||
def renderHTTP(self, ctx):
|
||||
file_uri = self._filenode.get_uri()
|
||||
pieces = unpack_uri(file_uri)
|
||||
data = "<xmlish>\n"
|
||||
data += "filenode\n"
|
||||
data += "stuff here\n"
|
||||
data += "uri=%s, size=%s" % (file_uri, pieces['size'])
|
||||
return data
|
||||
|
||||
class FileURI(FileJSONMetadata):
|
||||
def renderHTTP(self, ctx):
|
||||
file_uri = self._filenode.get_uri()
|
||||
return file_uri
|
||||
|
||||
class LocalDirectoryDownloader(resource.Resource):
|
||||
def __init__(self, dirnode):
|
||||
self._dirnode = dirnode
|
||||
|
||||
def renderHTTP(self, ctx):
|
||||
dl = get_downloader_service(ctx)
|
||||
pass # TODO
|
||||
|
||||
class DirectoryJSONMetadata(rend.Page):
|
||||
def __init__(self, dirnode):
|
||||
self._dirnode = dirnode
|
||||
|
||||
def renderHTTP(self, ctx):
|
||||
file_uri = self._dirnode.get_uri()
|
||||
data = "dirnode\n"
|
||||
data += "JSONny stuff here\n"
|
||||
d = self._dirnode.list()
|
||||
def _got(children, data):
|
||||
for name, childnode in children.iteritems():
|
||||
data += "name=%s, child_uri=%s" % (name, childnode.get_uri())
|
||||
return data
|
||||
d.addCallback(_got, data)
|
||||
def _done(data):
|
||||
data += "done\n"
|
||||
return data
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
class DirectoryXMLMetadata(DirectoryJSONMetadata):
|
||||
def renderHTTP(self, ctx):
|
||||
file_uri = self._dirnode.get_uri()
|
||||
pieces = unpack_uri(file_uri)
|
||||
data = "<xmlish>\n"
|
||||
data += "dirnode\n"
|
||||
data += "stuff here\n"
|
||||
d = self._dirnode.list()
|
||||
def _got(children, data):
|
||||
for name, childnode in children:
|
||||
data += "name=%s, child_uri=%s" % (name, childnode.get_uri())
|
||||
return data
|
||||
d.addCallback(_got)
|
||||
def _done(data):
|
||||
data += "</done>\n"
|
||||
return data
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
class DirectoryURI(DirectoryJSONMetadata):
|
||||
def renderHTTP(self, ctx):
|
||||
dir_uri = self._dirnode.get_uri()
|
||||
return dir_uri
|
||||
|
||||
class DirectoryReadonlyURI(DirectoryJSONMetadata):
|
||||
def renderHTTP(self, ctx):
|
||||
dir_uri = self._dirnode.get_immutable_uri()
|
||||
return dir_uri
|
||||
|
||||
class POSTHandler(rend.Page):
|
||||
def __init__(self, node):
|
||||
self._node = node
|
||||
|
||||
# TODO: handler methods
|
||||
|
||||
class DELETEHandler(rend.Page):
|
||||
def __init__(self, node, name):
|
||||
self._node = node
|
||||
self._name = name
|
||||
|
||||
def renderHTTP(self, ctx):
|
||||
d = self._node.delete(self._name)
|
||||
def _done(res):
|
||||
# what should this return??
|
||||
return "%s deleted" % self._name
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
class PUTHandler(rend.Page):
|
||||
def __init__(self, node, path, t, localfile, localdir):
|
||||
self._node = node
|
||||
self._path = path
|
||||
self._t = t
|
||||
self._localfile = localfile
|
||||
self._localdir = localdir
|
||||
|
||||
def renderHTTP(self, ctx):
|
||||
req = inevow.IRequest(ctx)
|
||||
t = self._t
|
||||
localfile = self._localfile
|
||||
localdir = self._localdir
|
||||
self._uploader = get_uploader_service(ctx)
|
||||
|
||||
# we must traverse the path, creating new directories as necessary
|
||||
d = self._get_or_create_directories(self._node, self._path[:-1])
|
||||
name = self._path[-1]
|
||||
if localfile:
|
||||
d.addCallback(self._upload_localfile, localfile, name)
|
||||
elif localdir:
|
||||
d.addCallback(self._upload_localdir, localdir)
|
||||
elif t == "uri":
|
||||
d.addCallback(self._attach_uri, req.content, name)
|
||||
elif t == "mkdir":
|
||||
d.addCallback(self._mkdir, name)
|
||||
else:
|
||||
d.addCallback(self._upload_file, req.content, name)
|
||||
def _check_blocking(f):
|
||||
f.trap(BlockingFileError)
|
||||
req.setResponseCode(http.FORBIDDEN)
|
||||
req.setHeader("content-type", "text/plain")
|
||||
return str(f)
|
||||
d.addErrback(_check_blocking)
|
||||
return d
|
||||
|
||||
def _get_or_create_directories(self, node, path):
|
||||
if not IDirectoryNode.providedBy(node):
|
||||
raise BlockingFileError
|
||||
if not path:
|
||||
return node
|
||||
d = node.get(path[0])
|
||||
def _maybe_create(f):
|
||||
f.trap(KeyError)
|
||||
print "CREATING", path[0]
|
||||
return node.create_empty_directory(path[0])
|
||||
d.addErrback(_maybe_create)
|
||||
d.addCallback(self._get_or_create_directories, path[1:])
|
||||
return d
|
||||
|
||||
def _mkdir(self, node, name):
|
||||
d = node.create_empty_directory(name)
|
||||
def _done(newnode):
|
||||
return newnode.get_uri()
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def _upload_file(self, node, contents, name):
|
||||
uploadable = upload.FileHandle(contents)
|
||||
d = self._uploader.upload(uploadable)
|
||||
def _uploaded(uri):
|
||||
d1 = node.set_uri(name, uri)
|
||||
d1.addCallback(lambda res: uri)
|
||||
return d1
|
||||
d.addCallback(_uploaded)
|
||||
def _done(uri):
|
||||
log.msg("webish upload complete")
|
||||
return uri
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def _upload_localfile(self, node, localfile, name):
|
||||
uploadable = upload.FileName(localfile)
|
||||
d = self._uploader.upload(uploadable)
|
||||
def _uploaded(uri):
|
||||
print "SETTING URI", name, uri
|
||||
d1 = node.set_uri(name, uri)
|
||||
d1.addCallback(lambda res: uri)
|
||||
return d1
|
||||
d.addCallback(_uploaded)
|
||||
def _done(uri):
|
||||
log.msg("webish upload complete")
|
||||
return uri
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def _attach_uri(self, parentnode, contents, name):
|
||||
newuri = contents.read().strip()
|
||||
d = parentnode.set_uri(name, newuri)
|
||||
def _done(res):
|
||||
return newuri
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def _upload_localdir(self, node, localdir):
|
||||
pass # TODO
|
||||
|
||||
class Manifest(rend.Page):
|
||||
docFactory = getxmlfile("manifest.xhtml")
|
||||
def __init__(self, dirnode, dirname):
|
||||
@ -419,10 +564,148 @@ class Manifest(rend.Page):
|
||||
ctx.fillSlots("refresh_capability", refresh_cap)
|
||||
return ctx.tag
|
||||
|
||||
class VDrive(rend.Page):
|
||||
|
||||
def __init__(self, node, name):
|
||||
self.node = node
|
||||
self.name = name
|
||||
|
||||
def get_child_at_path(self, path):
|
||||
if path:
|
||||
return self.node.get_child_at_path(path)
|
||||
return defer.succeed(self.node)
|
||||
|
||||
def locateChild(self, ctx, segments):
|
||||
req = inevow.IRequest(ctx)
|
||||
method = req.method
|
||||
path = segments
|
||||
|
||||
# when we're pointing at a directory (like /vdrive/public/my_pix),
|
||||
# Directory.addSlash causes a redirect to /vdrive/public/my_pix/,
|
||||
# which appears here as ['my_pix', '']. This is supposed to hit the
|
||||
# same Directory as ['my_pix'].
|
||||
if path and path[-1] == '':
|
||||
path = path[:-1]
|
||||
|
||||
print "VDrive.locateChild", method, segments, req.args
|
||||
t = ""
|
||||
if "t" in req.args:
|
||||
t = req.args["t"][0]
|
||||
|
||||
localfile = None
|
||||
if "localfile" in req.args:
|
||||
localfile = req.args["localfile"][0]
|
||||
localdir = None
|
||||
if "localdir" in req.args:
|
||||
localdir = req.args["localdir"][0]
|
||||
if (localfile or localdir) and req.getHost().host != LOCALHOST:
|
||||
return NeedLocalhostError(), ()
|
||||
# TODO: think about clobbering/revealing config files and node secrets
|
||||
|
||||
if method == "GET":
|
||||
# the node must exist, and our operation will be performed on the
|
||||
# node itself.
|
||||
name = path[-1]
|
||||
d = self.get_child_at_path(path)
|
||||
def file_or_dir(node):
|
||||
if IFileNode.providedBy(node):
|
||||
if localfile:
|
||||
# write contents to a local file
|
||||
return LocalFileDownloader(node, localfile), ()
|
||||
elif t == "":
|
||||
# send contents as the result
|
||||
print "FileDownloader"
|
||||
return FileDownloader(name, node), ()
|
||||
elif t == "json":
|
||||
print "Localfilejsonmetadata"
|
||||
return FileJSONMetadata(node), ()
|
||||
elif t == "xml":
|
||||
return FileXMLMetadata(node), ()
|
||||
elif t == "uri":
|
||||
return FileURI(node), ()
|
||||
else:
|
||||
raise RuntimeError("bad t=%s" % t)
|
||||
elif IDirectoryNode.providedBy(node):
|
||||
print "GOT DIR"
|
||||
if localdir:
|
||||
# recursive download to a local directory
|
||||
return LocalDirectoryDownloader(node, localdir), ()
|
||||
elif t == "":
|
||||
# send an HTML representation of the directory
|
||||
print "GOT HTML DIR"
|
||||
return Directory(node, name), ()
|
||||
elif t == "json":
|
||||
return DirectoryJSONMetadata(node), ()
|
||||
elif t == "xml":
|
||||
return DirectoryXMLMetadata(node), ()
|
||||
elif t == "uri":
|
||||
return DirectoryURI(node), ()
|
||||
elif t == "readonly-uri":
|
||||
return DirectoryReadonlyURI(node), ()
|
||||
else:
|
||||
raise RuntimeError("bad t=%s" % t)
|
||||
else:
|
||||
raise RuntimeError("unknown node type")
|
||||
d.addCallback(file_or_dir)
|
||||
elif method == "POST":
|
||||
# the node must exist, and our operation will be performed on the
|
||||
# node itself.
|
||||
d = self.get_child_at_path(path)
|
||||
d.addCallback(lambda node: POSTHandler(node), ())
|
||||
elif method == "DELETE":
|
||||
# the node must exist, and our operation will be performed on its
|
||||
# parent node.
|
||||
assert path # you can't delete the root
|
||||
d = self.get_child_at_path(path[:-1])
|
||||
d.addCallback(lambda node: DELETEHandler(node, path[-1]), )
|
||||
elif method in ("PUT",):
|
||||
# the node may or may not exist, and our operation may involve
|
||||
# all the ancestors of the node.
|
||||
return PUTHandler(self.node, path, t, localfile, localdir), ()
|
||||
else:
|
||||
return rend.NotFound
|
||||
def _trap_KeyError(f):
|
||||
f.trap(KeyError)
|
||||
return rend.FourOhFour(), ()
|
||||
d.addErrback(_trap_KeyError)
|
||||
return d
|
||||
|
||||
|
||||
class Root(rend.Page):
|
||||
|
||||
addSlash = True
|
||||
docFactory = getxmlfile("welcome.xhtml")
|
||||
|
||||
def locateChild(self, ctx, segments):
|
||||
if segments[0] == "download_uri":
|
||||
client = IClient(ctx)
|
||||
vdrive = client.getServiceNamed("vdrive")
|
||||
print "Root.locateChild", segments
|
||||
|
||||
if segments[0] == "vdrive":
|
||||
if len(segments) < 2:
|
||||
return rend.NotFound
|
||||
if segments[1] == "global":
|
||||
d = vdrive.get_public_root()
|
||||
name = "public vdrive"
|
||||
elif segments[1] == "private":
|
||||
d = vdrive.get_private_root()
|
||||
name = "private vdrive"
|
||||
else:
|
||||
return rend.NotFound
|
||||
d.addCallback(lambda dirnode: VDrive(dirnode, name))
|
||||
d.addCallback(lambda vd: vd.locateChild(ctx, segments[2:]))
|
||||
return d
|
||||
elif segments[0] == "uri":
|
||||
if len(segments) < 2:
|
||||
return rend.NotFound
|
||||
uri = segments[1]
|
||||
d = vdrive.get_node(uri)
|
||||
d.addCallback(lambda node: VDrive(node), uri)
|
||||
d.addCallback(lambda vd: vd.locateChild(ctx, segments[2:]))
|
||||
return d
|
||||
elif segments[0] == "xmlrpc":
|
||||
pass # TODO
|
||||
elif segments[0] == "download_uri":
|
||||
req = inevow.IRequest(ctx)
|
||||
dl = get_downloader_service(ctx)
|
||||
filename = "unknown_filename"
|
||||
@ -436,14 +719,14 @@ class Root(rend.Page):
|
||||
uri = req.args["uri"][0]
|
||||
else:
|
||||
return rend.NotFound
|
||||
child = Downloader(dl, filename, FileNode(uri, IClient(ctx)))
|
||||
child = FileDownloader(filename, FileNode(uri, IClient(ctx)))
|
||||
return child, ()
|
||||
return rend.Page.locateChild(self, ctx, segments)
|
||||
|
||||
child_webform_css = webform.defaultCSS
|
||||
child_tahoe_css = nevow_File(util.sibpath(__file__, "web/tahoe.css"))
|
||||
|
||||
child_welcome = Welcome()
|
||||
#child_welcome = Welcome()
|
||||
|
||||
def child_global_vdrive(self, ctx):
|
||||
client = IClient(ctx)
|
||||
@ -465,6 +748,80 @@ class Root(rend.Page):
|
||||
else:
|
||||
return static.Data("sorry, still initializing", "text/plain")
|
||||
|
||||
def data_version(self, ctx, data):
|
||||
v = IClient(ctx).get_versions()
|
||||
return "tahoe: %s, zfec: %s, foolscap: %s, twisted: %s" % \
|
||||
(v['allmydata'], v['zfec'], v['foolscap'], v['twisted'])
|
||||
|
||||
def data_my_nodeid(self, ctx, data):
|
||||
return idlib.b2a(IClient(ctx).nodeid)
|
||||
def data_introducer_furl(self, ctx, data):
|
||||
return IClient(ctx).introducer_furl
|
||||
def data_connected_to_introducer(self, ctx, data):
|
||||
if IClient(ctx).connected_to_introducer():
|
||||
return "yes"
|
||||
return "no"
|
||||
def data_connected_to_vdrive(self, ctx, data):
|
||||
if IClient(ctx).getServiceNamed("vdrive").have_public_root():
|
||||
return "yes"
|
||||
return "no"
|
||||
def data_num_peers(self, ctx, data):
|
||||
#client = inevow.ISite(ctx)._client
|
||||
client = IClient(ctx)
|
||||
return len(list(client.get_all_peerids()))
|
||||
|
||||
def data_peers(self, ctx, data):
|
||||
d = []
|
||||
client = IClient(ctx)
|
||||
for nodeid in sorted(client.get_all_peerids()):
|
||||
row = (idlib.b2a(nodeid),)
|
||||
d.append(row)
|
||||
return d
|
||||
|
||||
def render_row(self, ctx, data):
|
||||
(nodeid_a,) = data
|
||||
ctx.fillSlots("peerid", nodeid_a)
|
||||
return ctx.tag
|
||||
|
||||
def render_global_vdrive(self, ctx, data):
|
||||
if IClient(ctx).getServiceNamed("vdrive").have_public_root():
|
||||
return T.p["To view the global shared filestore, ",
|
||||
T.a(href="../global_vdrive")["Click Here!"],
|
||||
]
|
||||
return T.p["vdrive.furl not specified (or vdrive server not "
|
||||
"responding), no vdrive available."]
|
||||
|
||||
def render_private_vdrive(self, ctx, data):
|
||||
if IClient(ctx).getServiceNamed("vdrive").have_private_root():
|
||||
return T.p["To view your personal private non-shared filestore, ",
|
||||
T.a(href="../private_vdrive")["Click Here!"],
|
||||
]
|
||||
return T.p["personal vdrive not available."]
|
||||
|
||||
# this is a form where users can download files by URI
|
||||
|
||||
def bind_download(self, ctx):
|
||||
uriarg = annotate.Argument("uri",
|
||||
annotate.String("URI of file to download: "))
|
||||
namearg = annotate.Argument("filename",
|
||||
annotate.String("Filename to download as: "))
|
||||
ctxarg = annotate.Argument("ctx", annotate.Context())
|
||||
meth = annotate.Method(arguments=[uriarg, namearg, ctxarg],
|
||||
label="Download File by URI")
|
||||
# buttons always use value=data.label
|
||||
# MethodBindingRenderer uses value=(data.action or data.label)
|
||||
return annotate.MethodBinding("download", meth, action="Download")
|
||||
|
||||
def download(self, uri, filename, ctx):
|
||||
log.msg("webish downloading URI")
|
||||
target = url.here.sibling("download_uri").add("uri", uri)
|
||||
if filename:
|
||||
target = target.add("filename", filename)
|
||||
return target
|
||||
|
||||
def render_forms(self, ctx, data):
|
||||
return webform.renderForms()
|
||||
|
||||
|
||||
class WebishServer(service.MultiService):
|
||||
name = "webish"
|
||||
@ -472,7 +829,7 @@ class WebishServer(service.MultiService):
|
||||
def __init__(self, webport):
|
||||
service.MultiService.__init__(self)
|
||||
self.root = Root()
|
||||
self.root.putChild("", url.here.child("welcome"))#Welcome())
|
||||
#self.root.putChild("", url.here.child("welcome"))#Welcome())
|
||||
|
||||
self.site = site = appserver.NevowSite(self.root)
|
||||
s = strports.service(webport, site)
|
||||
|
Loading…
Reference in New Issue
Block a user