webish: improve download, now you can just append the vdrive path to the base URL to get at the contents of the file. Also added a download-by-URI box

This commit is contained in:
Brian Warner 2006-12-07 14:48:37 -07:00
parent 13d6566c13
commit 4b11831da7
4 changed files with 129 additions and 72 deletions

View File

@ -103,13 +103,13 @@ class SystemTest(unittest.TestCase):
v0 = self.clients[0].getServiceNamed("vdrive")
d1 = v0.make_directory("/", "subdir1")
d1.addCallback(lambda subdir1:
v0.put_file_by_data(subdir1, "data", DATA))
v0.put_file_by_data(subdir1, "mydata567", DATA))
return d1
d.addCallback(_do_publish)
def _publish_done(res):
log.msg("publish finished")
v1 = self.clients[1].getServiceNamed("vdrive")
d1 = v1.get_file_to_data("/subdir1/data")
d1 = v1.get_file_to_data("/subdir1/mydata567")
return d1
d.addCallback(_publish_done)
def _get_done(data):
@ -133,12 +133,11 @@ class SystemTest(unittest.TestCase):
d.addCallback(lambda res: getPage(base + "vdrive/subdir1"))
def _got_subdir1(page):
# there ought to be an href for our file
self.failUnless(">data</a>" in page)
self.failUnless(">mydata567</a>" in page)
d.addCallback(_got_subdir1)
if False: # not implemented yet
d.addCallback(lambda res: getPage(base + "vdrive/subdir/data"))
def _got_data(page):
self.failUnlessEqual(page, self.data)
d.addCallback(_got_data)
d.addCallback(lambda res: getPage(base + "vdrive/subdir1/mydata567"))
def _got_data(page):
self.failUnlessEqual(page, self.data)
d.addCallback(_got_data)
return d

View File

@ -1,8 +1,9 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
<head>
<title n:render="title"></title>
<link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/>
<!-- <link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/> -->
<link href="/webform_css" rel="stylesheet" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

View File

@ -1,15 +1,16 @@
<html xmlns:n="http://nevow.com/ns/nevow/0.1">
<head>
<title>Welcome To AllMyData (tahoe2)</title>
<link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/>
<!-- <link href="http://www.allmydata.com/common/css/styles.css"
rel="stylesheet" type="text/css"/> -->
<link href="/webform_css" rel="stylesheet" type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1>Welcome To AllMyData! (tahoe2)</h1>
<p>To view the global shared filestore, <a href="vdrive">Click Here!</a></p>
<p>To view the global shared filestore, <a href="../vdrive">Click Here!</a></p>
<h2>Mesh Status</h2>
@ -32,6 +33,7 @@
</table>
</div>
<div n:render="forms"/>
</body>
</html>

View File

@ -1,6 +1,6 @@
from twisted.application import service, strports
from twisted.web import static, resource, server
from twisted.web import static, resource, server, html
from twisted.python import util, log
from nevow import inevow, rend, loaders, appserver, url, tags as T
from allmydata.util import idlib
@ -16,38 +16,12 @@ def getxmlfile(name):
class IClient(Interface):
pass
class WebishServer(service.MultiService):
name = "webish"
def __init__(self, webport):
service.MultiService.__init__(self)
self.root = root = static.Data("root", "text/plain")
w = Welcome()
root.putChild("", w)
root.putChild("vdrive",
static.Data("sorry, still initializing", "text/plain"))
self.site = site = appserver.NevowSite(root)
s = strports.service(webport, site)
s.setServiceParent(self)
self.listener = s # stash it so the tests can query for the portnum
def startService(self):
service.MultiService.startService(self)
# to make various services available to render_* methods, we stash a
# reference to the client on the NevowSite. This will be available by
# adapting the 'context' argument to a special marker interface named
# IClient.
self.site.remember(self.parent, IClient)
# I thought you could do the same with an existing interface, but
# apparently 'ISite' does not exist
#self.site._client = self.parent
def set_root_dirnode(self, dirnode):
self.root.putChild("vdrive", Directory(dirnode, "/"))
# I tried doing it this way and for some reason it didn't seem to work
#print "REMEMBERING", self.site, dl, IDownloader
#self.site.remember(dl, IDownloader)
def get_downloader_service(ctx):
return IClient(ctx).getServiceNamed("downloader")
def get_uploader_service(ctx):
return IClient(ctx).getServiceNamed("uploader")
def get_vdrive_service(ctx):
return IClient(ctx).getServiceNamed("vdrive")
class Welcome(rend.Page):
addSlash = True
@ -76,6 +50,31 @@ class Welcome(rend.Page):
ctx.fillSlots("connected", connected)
return ctx.tag
# 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
docFactory = getxmlfile("directory.xhtml")
@ -84,24 +83,20 @@ class Directory(rend.Page):
self._dirnode = dirnode
self._dirname = dirname
def get_service(self, ctx, name):
return IClient(ctx).getServiceNamed(name)
def childFactory(self, ctx, name):
if name.startswith("freeform"): # ick
return None
if name == "_download":
args = inevow.IRequest(ctx).args
filename = args["filename"][0]
verifierid = args["verifierid"][0]
return Downloader(self.get_service(ctx, "downloader"),
self._dirname, filename, idlib.a2b(verifierid))
if self._dirname == "/":
dirname = "/" + name
else:
dirname = self._dirname + "/" + name
d = self._dirnode.callRemote("get", name)
d.addCallback(lambda newnode: Directory(newnode, dirname))
def _got_child(res):
if isinstance(res, str):
dl = get_downloader_service(ctx)
return Downloader(dl, name, res)
return Directory(res, dirname)
d.addCallback(_got_child)
return d
def render_title(self, ctx, data):
@ -118,13 +113,15 @@ class Directory(rend.Page):
name, target = data
if isinstance(target, str):
# file
args = {'verifierid': idlib.b2a(target),
'filename': name,
}
dlurl = "_download?%s" % urllib.urlencode(args)
ctx.fillSlots("filename", T.a(href=dlurl)[name])
dlurl = urllib.quote(name)
ctx.fillSlots("filename",
T.a(href=dlurl)[html.escape(name)])
ctx.fillSlots("type", "FILE")
ctx.fillSlots("fileid", idlib.b2a(target))
uri = idlib.b2a(target)
dl_uri_url = url.root.child("download_uri").child(uri)
# add a filename= query argument to give it a Content-Type
dl_uri_url = dl_uri_url.add("filename", name)
ctx.fillSlots("fileid", T.a(href=dl_uri_url)[html.escape(uri)])
# this creates a button which will cause our child__delete method
# to be invoked, which deletes the file and then redirects the
@ -138,13 +135,14 @@ class Directory(rend.Page):
ctx.fillSlots("delete", delete)
else:
# directory
ctx.fillSlots("filename", T.a(href=name)[name])
subdir_url = urllib.quote(name)
ctx.fillSlots("filename",
T.a(href=subdir_url)[html.escape(name)])
ctx.fillSlots("type", "DIR")
ctx.fillSlots("fileid", "-")
ctx.fillSlots("delete", "-")
return ctx.tag
child_webform_css = webform.defaultCSS
def render_forms(self, ctx, data):
return webform.renderForms()
@ -167,14 +165,15 @@ class Directory(rend.Page):
contentsarg = annotate.Argument("contents", up)
ctxarg = annotate.Argument("ctx", annotate.Context())
meth = annotate.Method(arguments=[contentsarg, ctxarg])
return annotate.MethodBinding("upload", meth, action="Upload File")
meth = annotate.Method(arguments=[contentsarg, ctxarg],
label="Upload File to this directory")
return annotate.MethodBinding("upload", meth, action="Upload")
def upload(self, contents, ctx):
# contents is a cgi.FieldStorage instance
log.msg("starting webish upload")
uploader = self.get_service(ctx, "uploader")
uploader = get_uploader_service(ctx)
d = uploader.upload(upload.Data(contents.value))
name = contents.filename
d.addCallback(lambda vid:
@ -191,8 +190,8 @@ class Directory(rend.Page):
"""Make new directory 1"""
namearg = annotate.Argument("name",
annotate.String("New directory name: "))
meth = annotate.Method(arguments=[namearg])
return annotate.MethodBinding("mkdir", meth, action="Make Directory")
meth = annotate.Method(arguments=[namearg], label="Make New Subdirectory")
return annotate.MethodBinding("mkdir", meth, action="Create Directory")
def mkdir(self, name):
"""mkdir2"""
@ -207,7 +206,7 @@ class Directory(rend.Page):
def child__delete(self, ctx):
# perform the delete, then redirect back to the directory page
args = inevow.IRequest(ctx).args
vdrive = self.get_service(ctx, "vdrive")
vdrive = get_vdrive_service(ctx)
d = vdrive.remove(self._dirnode, args["name"][0])
def _deleted(res):
return url.here.up()
@ -244,9 +243,8 @@ class TypedFile(static.File):
self.defaultType)
class Downloader(resource.Resource):
def __init__(self, downloader, dirname, name, verifierid):
def __init__(self, downloader, name, verifierid):
self._downloader = downloader
self._dirname = dirname
self._name = name
self._verifierid = verifierid
@ -268,3 +266,60 @@ class Downloader(resource.Resource):
return server.NOT_DONE_YET
class Root(rend.Page):
def locateChild(self, ctx, segments):
if segments[0] == "download_uri":
req = inevow.IRequest(ctx)
dl = get_downloader_service(ctx)
filename = "unknown_filename"
if "filename" in req.args:
filename = req.args["filename"][0]
if len(segments) > 1:
# http://host/download_uri/URIGOESHERE
uri_a = segments[1]
elif "uri" in req.args:
# http://host/download_uri?uri=URIGOESHERE
uri_a = req.args["uri"][0]
else:
return rend.NotFound
child = Downloader(dl, filename, idlib.a2b(uri_a))
return child, ()
return rend.Page.locateChild(self, ctx, segments)
child_webform_css = webform.defaultCSS
child_welcome = Welcome()
class WebishServer(service.MultiService):
name = "webish"
def __init__(self, webport):
service.MultiService.__init__(self)
self.root = Root()
placeholder = static.Data("sorry, still initializing", "text/plain")
self.root.putChild("vdrive", placeholder)
self.root.putChild("", url.here.child("welcome"))#Welcome())
self.site = site = appserver.NevowSite(self.root)
s = strports.service(webport, site)
s.setServiceParent(self)
self.listener = s # stash it so the tests can query for the portnum
def startService(self):
service.MultiService.startService(self)
# to make various services available to render_* methods, we stash a
# reference to the client on the NevowSite. This will be available by
# adapting the 'context' argument to a special marker interface named
# IClient.
self.site.remember(self.parent, IClient)
# I thought you could do the same with an existing interface, but
# apparently 'ISite' does not exist
#self.site._client = self.parent
def set_root_dirnode(self, dirnode):
self.root.putChild("vdrive", Directory(dirnode, "/"))
# I tried doing it this way and for some reason it didn't seem to work
#print "REMEMBERING", self.site, dl, IDownloader
#self.site.remember(dl, IDownloader)