mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-30 01:38:55 +00:00
wapi: add POST /uri/$DIRECTORY?t=set_children
Unfinished bits: doc in webapi.txt, test handling of badly formed JSON, return reasonable HTTP response, examination of the effect of this patch on code coverage -- but I'm committing it anyway because MikeB can use it and I'm being called to dinner...
This commit is contained in:
parent
5cdc678d24
commit
99f006c584
@ -250,7 +250,7 @@ class NewDirectoryNode:
|
|||||||
assert isinstance(name, unicode)
|
assert isinstance(name, unicode)
|
||||||
return self.set_node(name, self._create_node(child_uri), metadata)
|
return self.set_node(name, self._create_node(child_uri), metadata)
|
||||||
|
|
||||||
def set_uris(self, entries):
|
def set_children(self, entries):
|
||||||
node_entries = []
|
node_entries = []
|
||||||
for e in entries:
|
for e in entries:
|
||||||
if len(e) == 2:
|
if len(e) == 2:
|
||||||
|
@ -669,7 +669,7 @@ class IDirectoryNode(IMutableFilesystemNode):
|
|||||||
If this directory node is read-only, the Deferred will errback with a
|
If this directory node is read-only, the Deferred will errback with a
|
||||||
NotMutableError."""
|
NotMutableError."""
|
||||||
|
|
||||||
def set_uris(entries):
|
def set_children(entries):
|
||||||
"""Add multiple (name, child_uri) pairs (or (name, child_uri,
|
"""Add multiple (name, child_uri) pairs (or (name, child_uri,
|
||||||
metadata) triples) to a directory node. Returns a Deferred that fires
|
metadata) triples) to a directory node. Returns a Deferred that fires
|
||||||
(with None) when the operation finishes. This is equivalent to
|
(with None) when the operation finishes. This is equivalent to
|
||||||
|
@ -110,7 +110,7 @@ def make_verifier_uri():
|
|||||||
return uri.SSKVerifierURI(storage_index=os.urandom(16),
|
return uri.SSKVerifierURI(storage_index=os.urandom(16),
|
||||||
fingerprint=os.urandom(32))
|
fingerprint=os.urandom(32))
|
||||||
|
|
||||||
class NonGridDirectoryNode(dirnode.NewDirectoryNode):
|
class FakeDirectoryNode(dirnode.NewDirectoryNode):
|
||||||
"""This offers IDirectoryNode, but uses a FakeMutableFileNode for the
|
"""This offers IDirectoryNode, but uses a FakeMutableFileNode for the
|
||||||
backing store, so it doesn't go to the grid. The child data is still
|
backing store, so it doesn't go to the grid. The child data is still
|
||||||
encrypted and serialized, so this isn't useful for tests that want to
|
encrypted and serialized, so this isn't useful for tests that want to
|
||||||
|
@ -7,15 +7,13 @@ from allmydata.interfaces import IURI, IClient, IMutableFileNode, \
|
|||||||
INewDirectoryURI, IReadonlyNewDirectoryURI, IFileNode
|
INewDirectoryURI, IReadonlyNewDirectoryURI, IFileNode
|
||||||
from allmydata.util import hashutil, testutil
|
from allmydata.util import hashutil, testutil
|
||||||
from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \
|
from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \
|
||||||
NonGridDirectoryNode, create_chk_filenode
|
FakeDirectoryNode, create_chk_filenode
|
||||||
from twisted.internet import defer, reactor
|
from twisted.internet import defer, reactor
|
||||||
|
|
||||||
# to test dirnode.py, we want to construct a tree of real DirectoryNodes that
|
# to test dirnode.py, we want to construct a tree of real DirectoryNodes that
|
||||||
# contain pointers to fake files. We start with a fake MutableFileNode that
|
# contain pointers to fake files. We start with a fake MutableFileNode that
|
||||||
# stores all of its data in a static table.
|
# stores all of its data in a static table.
|
||||||
|
|
||||||
FakeDirectoryNode = NonGridDirectoryNode
|
|
||||||
|
|
||||||
class Marker:
|
class Marker:
|
||||||
implements(IFileNode, IMutableFileNode) # sure, why not
|
implements(IFileNode, IMutableFileNode) # sure, why not
|
||||||
def __init__(self, nodeuri):
|
def __init__(self, nodeuri):
|
||||||
@ -281,8 +279,8 @@ class Dirnode(unittest.TestCase, testutil.ShouldFailMixin):
|
|||||||
d.addCallback(lambda res: n.delete(u"d3"))
|
d.addCallback(lambda res: n.delete(u"d3"))
|
||||||
d.addCallback(lambda res: n.delete(u"d4"))
|
d.addCallback(lambda res: n.delete(u"d4"))
|
||||||
|
|
||||||
# metadata through set_uris()
|
# metadata through set_children()
|
||||||
d.addCallback(lambda res: n.set_uris([ (u"e1", fake_file_uri),
|
d.addCallback(lambda res: n.set_children([ (u"e1", fake_file_uri),
|
||||||
(u"e2", fake_file_uri, {}),
|
(u"e2", fake_file_uri, {}),
|
||||||
(u"e3", fake_file_uri,
|
(u"e3", fake_file_uri,
|
||||||
{"key": "value"}),
|
{"key": "value"}),
|
||||||
|
@ -7,7 +7,7 @@ from twisted.web import client, error, http
|
|||||||
from twisted.python import failure, log
|
from twisted.python import failure, log
|
||||||
from allmydata import interfaces, provisioning, uri, webish, upload, download
|
from allmydata import interfaces, provisioning, uri, webish, upload, download
|
||||||
from allmydata.util import fileutil
|
from allmydata.util import fileutil
|
||||||
from allmydata.test.common import NonGridDirectoryNode, FakeCHKFileNode, FakeMutableFileNode, create_chk_filenode
|
from allmydata.test.common import FakeDirectoryNode, FakeCHKFileNode, FakeMutableFileNode, create_chk_filenode
|
||||||
from allmydata.interfaces import IURI, INewDirectoryURI, IReadonlyNewDirectoryURI, IFileURI, IMutableFileURI, IMutableFileNode
|
from allmydata.interfaces import IURI, INewDirectoryURI, IReadonlyNewDirectoryURI, IFileURI, IMutableFileURI, IMutableFileNode
|
||||||
|
|
||||||
# create a fake uploader/downloader, and a couple of fake dirnodes, then
|
# create a fake uploader/downloader, and a couple of fake dirnodes, then
|
||||||
@ -35,18 +35,18 @@ class FakeClient(service.MultiService):
|
|||||||
def connected_to_introducer(self):
|
def connected_to_introducer(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_node_from_uri(self, uri):
|
def create_node_from_uri(self, auri):
|
||||||
u = IURI(uri)
|
u = uri.from_string(auri)
|
||||||
if (INewDirectoryURI.providedBy(u)
|
if (INewDirectoryURI.providedBy(u)
|
||||||
or IReadonlyNewDirectoryURI.providedBy(u)):
|
or IReadonlyNewDirectoryURI.providedBy(u)):
|
||||||
return NonGridDirectoryNode(self).init_from_uri(u)
|
return FakeDirectoryNode(self).init_from_uri(u)
|
||||||
if IFileURI.providedBy(u):
|
if IFileURI.providedBy(u):
|
||||||
return FakeCHKFileNode(u, self)
|
return FakeCHKFileNode(u, self)
|
||||||
assert IMutableFileURI.providedBy(u), u
|
assert IMutableFileURI.providedBy(u), u
|
||||||
return FakeMutableFileNode(self).init_from_uri(u)
|
return FakeMutableFileNode(self).init_from_uri(u)
|
||||||
|
|
||||||
def create_empty_dirnode(self):
|
def create_empty_dirnode(self):
|
||||||
n = NonGridDirectoryNode(self)
|
n = FakeDirectoryNode(self)
|
||||||
d = n.create()
|
d = n.create()
|
||||||
d.addCallback(lambda res: n)
|
d.addCallback(lambda res: n)
|
||||||
return d
|
return d
|
||||||
@ -1299,6 +1299,46 @@ class Web(WebMixin, unittest.TestCase):
|
|||||||
d.addCallback(self.failUnlessNodeKeysAre, [])
|
d.addCallback(self.failUnlessNodeKeysAre, [])
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def test_POST_set_children(self):
|
||||||
|
contents9, n9, newuri9 = self.makefile(9)
|
||||||
|
contents10, n10, newuri10 = self.makefile(10)
|
||||||
|
contents11, n11, newuri11 = self.makefile(11)
|
||||||
|
|
||||||
|
reqbody = """{
|
||||||
|
"atomic_added_1": [ "filenode", { "rw_uri": "%s",
|
||||||
|
"size": 0,
|
||||||
|
"metadata": {
|
||||||
|
"ctime": 1002777696.7564139,
|
||||||
|
"mtime": 1002777696.7564139
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"atomic_added_2": [ "filenode", { "rw_uri": "%s",
|
||||||
|
"size": 1,
|
||||||
|
"metadata": {
|
||||||
|
"ctime": 1002777696.7564139,
|
||||||
|
"mtime": 1002777696.7564139
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"atomic_added_3": [ "filenode", { "rw_uri": "%s",
|
||||||
|
"size": 2,
|
||||||
|
"metadata": {
|
||||||
|
"ctime": 1002777696.7564139,
|
||||||
|
"mtime": 1002777696.7564139
|
||||||
|
}
|
||||||
|
} ]
|
||||||
|
}""" % (newuri9, newuri10, newuri11)
|
||||||
|
|
||||||
|
url = self.webish_url + self.public_url + "/foo" + "?t=set_children"
|
||||||
|
|
||||||
|
d = client.getPage(url, method="POST", postdata=reqbody)
|
||||||
|
def _then(res):
|
||||||
|
self.failUnlessURIMatchesChild(newuri9, self._foo_node, u"atomic_added_1")
|
||||||
|
self.failUnlessURIMatchesChild(newuri10, self._foo_node, u"atomic_added_2")
|
||||||
|
self.failUnlessURIMatchesChild(newuri11, self._foo_node, u"atomic_added_3")
|
||||||
|
|
||||||
|
d.addCallback(_then)
|
||||||
|
return d
|
||||||
|
|
||||||
def test_POST_put_uri(self):
|
def test_POST_put_uri(self):
|
||||||
contents, n, newuri = self.makefile(8)
|
contents, n, newuri = self.makefile(8)
|
||||||
d = self.POST(self.public_url + "/foo", t="uri", name="new.txt", uri=newuri)
|
d = self.POST(self.public_url + "/foo", t="uri", name="new.txt", uri=newuri)
|
||||||
|
@ -899,6 +899,16 @@ class POSTHandler(rend.Page):
|
|||||||
d.addCallback(_got_child_check)
|
d.addCallback(_got_child_check)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def _POST_set_children(self, children):
|
||||||
|
cs = []
|
||||||
|
for name, (file_or_dir, mddict) in children.iteritems():
|
||||||
|
cap = str(mddict.get('rw_uri') or mddict.get('ro_uri'))
|
||||||
|
cs.append((name, cap, mddict.get('metadata')))
|
||||||
|
|
||||||
|
d = self._node.set_children(cs)
|
||||||
|
d.addCallback(lambda res: "Okay so I did it.")
|
||||||
|
return d
|
||||||
|
|
||||||
def renderHTTP(self, ctx):
|
def renderHTTP(self, ctx):
|
||||||
req = inevow.IRequest(ctx)
|
req = inevow.IRequest(ctx)
|
||||||
|
|
||||||
@ -973,16 +983,16 @@ class POSTHandler(rend.Page):
|
|||||||
d = self._POST_overwrite(contents)
|
d = self._POST_overwrite(contents)
|
||||||
elif t == "check":
|
elif t == "check":
|
||||||
d = self._POST_check(name)
|
d = self._POST_check(name)
|
||||||
# elif t == "set_children":
|
elif t == "set_children":
|
||||||
# d = self._POST_set_(name)
|
req.content.seek(0)
|
||||||
# if not name:
|
body = req.content.read()
|
||||||
# raise RuntimeError("set-uri requires a name")
|
try:
|
||||||
# newuri = get_arg(req, "uri")
|
children = simplejson.loads(body)
|
||||||
# assert newuri is not None
|
except ValueError, le:
|
||||||
# d = self._check_replacement(name)
|
le.args = tuple(le.args + (body,))
|
||||||
# d.addCallback(lambda res: self._node.set_uri(name, newuri))
|
# TODO test handling of bad JSON
|
||||||
# d.addCallback(lambda res: newuri)
|
raise
|
||||||
|
d = self._POST_set_children(children)
|
||||||
else:
|
else:
|
||||||
print "BAD t=%s" % t
|
print "BAD t=%s" % t
|
||||||
return "BAD t=%s" % t
|
return "BAD t=%s" % t
|
||||||
@ -1346,9 +1356,8 @@ class UnlinkedPUTSSKUploader(rend.Page):
|
|||||||
req = inevow.IRequest(ctx)
|
req = inevow.IRequest(ctx)
|
||||||
assert req.method == "PUT"
|
assert req.method == "PUT"
|
||||||
# SDMF: files are small, and we can only upload data
|
# SDMF: files are small, and we can only upload data
|
||||||
contents = req.content
|
req.content.seek(0)
|
||||||
contents.seek(0)
|
data = req.content.read()
|
||||||
data = contents.read()
|
|
||||||
d = IClient(ctx).create_mutable_file(data)
|
d = IClient(ctx).create_mutable_file(data)
|
||||||
d.addCallback(lambda n: n.get_uri())
|
d.addCallback(lambda n: n.get_uri())
|
||||||
return d
|
return d
|
||||||
|
Loading…
Reference in New Issue
Block a user