WUI: change the label of the button to unlink a file from 'del' to 'unlink'. Also change some internal names to 'unlink', and allow 't=unlink' as a synonym for 't=delete' in the web-API interface. Incidentally, improve a test to check for the rename button as well as the unlink button. fixes #1104

This commit is contained in:
david-sarah 2011-07-12 17:12:18 -07:00
parent 23b3a2f45a
commit 07ecac1d83
4 changed files with 54 additions and 38 deletions

View File

@ -88,7 +88,7 @@ URL) will return information about the object, such as metadata. GET
operations are required to have no side-effects.
PUT is used to upload new objects into the filesystem, or to replace an
existing object. DELETE it used to delete objects from the filesystem. Both
existing object. DELETE is used to delete objects from the filesystem. Both
PUT and DELETE are required to be idempotent: performing the same operation
multiple times must have the same side-effects as only performing it once.
@ -1159,6 +1159,11 @@ Deleting A Child
into the subtree will see that the child subdirectories are not modified by
this operation. Only the link from the given directory to its child is severed.
In Tahoe-LAFS v1.9.0 and later, t=unlink can be used as a synonym for t=delete.
If interoperability with older web-API servers is required, t=delete should
be used.
Renaming A Child
----------------

View File

@ -1093,21 +1093,25 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
r'\s+<td align="right">%d</td>' % len(self.BAR_CONTENTS),
])
self.failUnless(re.search(get_bar, res), res)
for line in res.split("\n"):
# find the line that contains the delete button for bar.txt
if ("form action" in line and
'value="delete"' in line and
'value="bar.txt"' in line):
# the form target should use a relative URL
foo_url = urllib.quote("%s/uri/%s/" % (ROOT, self._foo_uri))
self.failUnless(('action="%s"' % foo_url) in line, line)
# and the when_done= should too
#done_url = urllib.quote(???)
#self.failUnless(('name="when_done" value="%s"' % done_url)
# in line, line)
break
else:
self.fail("unable to find delete-bar.txt line", res)
for label in ['unlink', 'rename']:
for line in res.split("\n"):
# find the line that contains the relevant button for bar.txt
if ("form action" in line and
('value="%s"' % (label,)) in line and
'value="bar.txt"' in line):
# the form target should use a relative URL
foo_url = urllib.quote("%s/uri/%s/" % (ROOT, self._foo_uri))
self.failUnlessIn('action="%s"' % foo_url, line)
# and the when_done= should too
#done_url = urllib.quote(???)
#self.failUnlessIn('name="when_done" value="%s"' % done_url, line)
# 'unlink' needs to use POST because it directly has a side effect
if label == 'unlink':
self.failUnlessIn('method="post"', line)
break
else:
self.fail("unable to find '%s bar.txt' line" % (label,), res)
# the DIR reference just points to a URI
sub_url = ("%s/uri/%s/" % (ROOT, urllib.quote(self._sub_uri)))
@ -2638,14 +2642,21 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
d.addCallback(self.failUnlessIsBarDotTxt)
return d
def test_POST_delete(self):
d = self.POST(self.public_url + "/foo", t="delete", name="bar.txt")
def test_POST_delete(self, command_name='delete'):
d = self._foo_node.list()
def _check_before(children):
self.failUnless(u"bar.txt" in children)
d.addCallback(_check_before)
d.addCallback(lambda res: self.POST(self.public_url + "/foo", t=command_name, name="bar.txt"))
d.addCallback(lambda res: self._foo_node.list())
def _check(children):
def _check_after(children):
self.failIf(u"bar.txt" in children)
d.addCallback(_check)
d.addCallback(_check_after)
return d
def test_POST_unlink(self):
return self.test_POST_delete(command_name='unlink')
def test_POST_rename_file(self):
d = self.POST(self.public_url + "/foo", t="rename",
from_name="bar.txt", to_name='wibble.txt')

View File

@ -202,8 +202,8 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin):
d = self._POST_upload(ctx) # this one needs the context
elif t == "uri":
d = self._POST_uri(req)
elif t == "delete":
d = self._POST_delete(req)
elif t == "delete" or t == "unlink":
d = self._POST_unlink(req)
elif t == "rename":
d = self._POST_rename(req)
elif t == "check":
@ -361,22 +361,22 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin):
d.addCallback(lambda res: childcap)
return d
def _POST_delete(self, req):
def _POST_unlink(self, req):
name = get_arg(req, "name")
if name is None:
# apparently an <input type="hidden" name="name" value="">
# won't show up in the resulting encoded form.. the 'name'
# field is completely missing. So to allow deletion of an
# empty file, we have to pretend that None means ''. The only
# downside of this is a slightly confusing error message if
# someone does a POST without a name= field. For our own HTML
# this isn't a big deal, because we create the 'delete' POST
# buttons ourselves.
# field is completely missing. So to allow unlinking of a
# child with a name that is the empty string, we have to
# pretend that None means ''. The only downside of this is
# a slightly confusing error message if someone does a POST
# without a name= field. For our own HTML this isn't a big
# deal, because we create the 'unlink' POST buttons ourselves.
name = ''
charset = get_arg(req, "_charset", "utf-8")
name = name.decode(charset)
d = self.node.delete(name)
d.addCallback(lambda res: "thing deleted")
d.addCallback(lambda res: "thing unlinked")
return d
def _POST_rename(self, req):
@ -644,17 +644,17 @@ class DirectoryAsHTML(rend.Page):
root = get_root(ctx)
here = "%s/uri/%s/" % (root, urllib.quote(self.node.get_uri()))
if self.node.is_unknown() or self.node.is_readonly():
delete = "-"
unlink = "-"
rename = "-"
else:
# this creates a button which will cause our child__delete method
# to be invoked, which deletes the file and then redirects the
# this creates a button which will cause our _POST_unlink method
# to be invoked, which unlinks the file and then redirects the
# browser back to this directory
delete = T.form(action=here, method="post")[
T.input(type='hidden', name='t', value='delete'),
unlink = T.form(action=here, method="post")[
T.input(type='hidden', name='t', value='unlink'),
T.input(type='hidden', name='name', value=name),
T.input(type='hidden', name='when_done', value="."),
T.input(type='submit', value='del', name="del"),
T.input(type='submit', value='unlink', name="unlink"),
]
rename = T.form(action=here, method="get")[
@ -664,7 +664,7 @@ class DirectoryAsHTML(rend.Page):
T.input(type='submit', value='rename', name="rename"),
]
ctx.fillSlots("delete", delete)
ctx.fillSlots("unlink", unlink)
ctx.fillSlots("rename", rename)
times = []

View File

@ -31,7 +31,7 @@
<td><n:slot name="filename"/></td>
<td align="right"><n:slot name="size"/></td>
<td><n:slot name="times"/></td>
<td><n:slot name="delete"/></td>
<td><n:slot name="unlink"/></td>
<td><n:slot name="rename"/></td>
<td><n:slot name="info"/></td>
</tr>