from allmydata.uri import from_string_dirnode
from allmydata.interfaces import IDirectoryNode, IFileNode, IFilesystemNode, \
IImmutableFileNode, IMutableFileNode, ExistingChildError, \
- NoSuchChildError, EmptyPathnameComponentError
+ NoSuchChildError, EmptyPathnameComponentError, SDMF_VERSION, MDMF_VERSION
+from allmydata.blacklist import ProhibitedNode
from allmydata.monitor import Monitor, OperationCancelledError
from allmydata import dirnode
from allmydata.web.common import text_plain, WebError, \
IOpHandleTable, NeedOperationHandleError, \
boolean_of_arg, get_arg, get_root, parse_replace_arg, \
should_create_intermediate_directories, \
- getxmlfile, RenderMixin, humanize_failure, convert_children_json
+ getxmlfile, RenderMixin, humanize_failure, convert_children_json, \
+ parse_mutable_type_arg
from allmydata.web.filenode import ReplaceMeMixin, \
FileNodeHandler, PlaceHolderNodeHandler
from allmydata.web.check_results import CheckResults, \
mutable = True
if t == "mkdir-immutable":
mutable = False
+
+ mt = None
+ if mutable:
+ arg = get_arg(req, "mutable-type", None)
+ mt = parse_mutable_type_arg(arg)
+ if mt is "invalid":
+ raise WebError("Unknown type: %s" % arg,
+ http.BAD_REQUEST)
d = self.node.create_subdirectory(name, kids,
- mutable=mutable)
+ mutable=mutable,
+ mutable_version=mt)
d.addCallback(make_handler_for,
self.client, self.node, name)
return d
if not t:
# render the directory as HTML, using the docFactory and Nevow's
# whole templating thing.
- return DirectoryAsHTML(self.node)
+ return DirectoryAsHTML(self.node,
+ self.client.mutable_file_default)
if t == "json":
return DirectoryJSONMetadata(ctx, self.node)
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":
name = name.decode("utf-8")
replace = boolean_of_arg(get_arg(req, "replace", "true"))
kids = {}
- d = self.node.create_subdirectory(name, kids, overwrite=replace)
+ arg = get_arg(req, "mutable-type", None)
+ mt = parse_mutable_type_arg(arg)
+ if mt is not None and mt is not "invalid":
+ d = self.node.create_subdirectory(name, kids, overwrite=replace,
+ mutable_version=mt)
+ elif mt is "invalid":
+ raise WebError("Unknown type: %s" % arg, http.BAD_REQUEST)
+ else:
+ d = self.node.create_subdirectory(name, kids, overwrite=replace)
d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
return d
req.content.seek(0)
kids_json = req.content.read()
kids = convert_children_json(self.client.nodemaker, kids_json)
- d = self.node.create_subdirectory(name, kids, overwrite=False)
+ arg = get_arg(req, "mutable-type", None)
+ mt = parse_mutable_type_arg(arg)
+ if mt is not None and mt is not "invalid":
+ d = self.node.create_subdirectory(name, kids, overwrite=False,
+ mutable_version=mt)
+ elif mt is "invalid":
+ raise WebError("Unknown type: %s" % arg)
+ else:
+ d = self.node.create_subdirectory(name, kids, overwrite=False)
d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
return d
charset = get_arg(req, "_charset", "utf-8")
name = name.decode(charset)
replace = boolean_of_arg(get_arg(req, "replace", "true"))
-
+
# We mustn't pass childcap for the readcap argument because we don't
# know whether it is a read cap. Passing a read cap as the writecap
# argument will work (it ends up calling NodeMaker.create_from_cap,
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):
docFactory = getxmlfile("directory.xhtml")
addSlash = True
- def __init__(self, node):
+ def __init__(self, node, default_mutable_format):
rend.Page.__init__(self)
self.node = node
+ assert default_mutable_format in (MDMF_VERSION, SDMF_VERSION)
+ self.default_mutable_format = default_mutable_format
+
def beforeRender(self, ctx):
# attempt to get the dirnode's children, stashing them (or the
# failure that results) for later use
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")[
T.input(type='submit', value='rename', name="rename"),
]
- ctx.fillSlots("delete", delete)
+ ctx.fillSlots("unlink", unlink)
ctx.fillSlots("rename", rename)
times = []
ctx.fillSlots("size", "-")
info_link = "%s/uri/%s/?t=info" % (root, quoted_uri)
+ elif isinstance(target, ProhibitedNode):
+ ctx.fillSlots("filename", T.strike[name])
+ if IDirectoryNode.providedBy(target.wrapped_node):
+ blacklisted_type = "DIR-BLACKLISTED"
+ else:
+ blacklisted_type = "BLACKLISTED"
+ ctx.fillSlots("type", blacklisted_type)
+ ctx.fillSlots("size", "-")
+ info_link = None
+ ctx.fillSlots("info", ["Access Prohibited:", T.br, target.reason])
+
else:
# unknown
ctx.fillSlots("filename", html.escape(name))
# writecap and the readcap
info_link = "%s?t=info" % urllib.quote(name)
- ctx.fillSlots("info", T.a(href=info_link)["More Info"])
+ if info_link:
+ ctx.fillSlots("info", T.a(href=info_link)["More Info"])
return ctx.tag
+ # XXX: Duplicated from root.py.
def render_forms(self, ctx, data):
forms = []
if self.dirnode_children is None:
return T.div["No upload forms: directory is unreadable"]
+ mdmf_directory_input = T.input(type='radio', name='mutable-type',
+ id='mutable-directory-mdmf',
+ value='mdmf')
+ sdmf_directory_input = T.input(type='radio', name='mutable-type',
+ id='mutable-directory-sdmf',
+ value='sdmf', checked='checked')
mkdir = T.form(action=".", method="post",
enctype="multipart/form-data")[
T.fieldset[
T.legend(class_="freeform-form-label")["Create a new directory in this directory"],
"New directory name: ",
T.input(type="text", name="name"), " ",
+ T.label(for_='mutable-directory-sdmf')["SDMF"],
+ sdmf_directory_input,
+ T.label(for_='mutable-directory-mdmf')["MDMF"],
+ mdmf_directory_input,
T.input(type="submit", value="Create"),
]]
forms.append(T.div(class_="freeform-form")[mkdir])
+ # Build input elements for mutable file type. We do this outside
+ # of the list so we can check the appropriate format, based on
+ # the default configured in the client (which reflects the
+ # default configured in tahoe.cfg)
+ if self.default_mutable_format == MDMF_VERSION:
+ mdmf_input = T.input(type='radio', name='mutable-type',
+ id='mutable-type-mdmf', value='mdmf',
+ checked='checked')
+ else:
+ mdmf_input = T.input(type='radio', name='mutable-type',
+ id='mutable-type-mdmf', value='mdmf')
+
+ if self.default_mutable_format == SDMF_VERSION:
+ sdmf_input = T.input(type='radio', name='mutable-type',
+ id='mutable-type-sdmf', value='sdmf',
+ checked="checked")
+ else:
+ sdmf_input = T.input(type='radio', name='mutable-type',
+ id='mutable-type-sdmf', value='sdmf')
+
upload = T.form(action=".", method="post",
enctype="multipart/form-data")[
T.fieldset[
T.input(type="submit", value="Upload"),
" Mutable?:",
T.input(type="checkbox", name="mutable"),
+ sdmf_input, T.label(for_="mutable-type-sdmf")["SDMF"],
+ mdmf_input,
+ T.label(for_="mutable-type-mdmf")["MDMF (experimental)"],
]]
forms.append(T.div(class_="freeform-form")[upload])
kiddata = ("filenode", {'size': childnode.get_size(),
'mutable': childnode.is_mutable(),
})
+ if childnode.is_mutable() and \
+ childnode.get_version() is not None:
+ mutable_type = childnode.get_version()
+ assert mutable_type in (SDMF_VERSION, MDMF_VERSION)
+
+ if mutable_type == MDMF_VERSION:
+ mutable_type = "mdmf"
+ else:
+ mutable_type = "sdmf"
+ kiddata[1]['mutable-type'] = mutable_type
+
elif IDirectoryNode.providedBy(childnode):
kiddata = ("dirnode", {'mutable': childnode.is_mutable()})
else: