from twisted.internet import defer
from twisted.internet.interfaces import IPushProducer
from twisted.python.failure import Failure
-from twisted.web import http, html
+from twisted.web import http
from nevow import url, rend, inevow, tags as T
from nevow.inevow import IRequest
boolean_of_arg, get_arg, get_root, parse_replace_arg, \
should_create_intermediate_directories, \
getxmlfile, RenderMixin, humanize_failure, convert_children_json, \
- parse_mutable_type_arg
+ get_format, get_mutable_type
from allmydata.web.filenode import ReplaceMeMixin, \
FileNodeHandler, PlaceHolderNodeHandler
-from allmydata.web.check_results import CheckResults, \
- CheckAndRepairResults, DeepCheckResults, DeepCheckAndRepairResults, \
- LiteralCheckResults
+from allmydata.web.check_results import CheckResultsRenderer, \
+ CheckAndRepairResultsRenderer, DeepCheckResultsRenderer, \
+ DeepCheckAndRepairResultsRenderer, LiteralCheckResultsRenderer
from allmydata.web.info import MoreInfo
from allmydata.web.operations import ReloadMixin
from allmydata.web.check_results import json_check_results, \
kids_json = req.content.read()
kids = convert_children_json(self.client.nodemaker,
kids_json)
+ file_format = get_format(req, None)
mutable = True
+ mt = get_mutable_type(file_format)
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_version=mt)
req = IRequest(ctx)
# This is where all of the directory-related ?t=* code goes.
t = get_arg(req, "t", "").strip()
+
+ # t=info contains variable ophandles, t=rename-form contains the name
+ # of the child being renamed. Neither is allowed an ETag.
+ FIXED_OUTPUT_TYPES = ["", "json", "uri", "readonly-uri"]
+ if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES:
+ si = self.node.get_storage_index()
+ if si and req.setETag('DIR:%s-%s' % (base32.b2a(si), t or "")):
+ return ""
+
if not t:
# render the directory as HTML, using the docFactory and Nevow's
# whole templating thing.
d = self._POST_mkdir_with_children(req)
elif t == "mkdir-immutable":
d = self._POST_mkdir_immutable(req)
- elif t == "mkdir-p":
- # TODO: docs, tests
- d = self._POST_mkdir_p(req)
elif t == "upload":
d = self._POST_upload(ctx) # this one needs the context
elif t == "uri":
d = self._POST_unlink(req)
elif t == "rename":
d = self._POST_rename(req)
+ elif t == "move":
+ d = self._POST_move(req)
elif t == "check":
d = self._POST_check(req)
elif t == "start-deep-check":
name = name.decode("utf-8")
replace = boolean_of_arg(get_arg(req, "replace", "true"))
kids = {}
- 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,
+ mt = get_mutable_type(get_format(req, None))
+ 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)
- 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)
+ mt = get_mutable_type(get_format(req, None))
+ d = self.node.create_subdirectory(name, kids, overwrite=False,
+ mutable_version=mt)
d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
return d
d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
return d
- def _POST_mkdir_p(self, req):
- path = get_arg(req, "path")
- if not path:
- raise WebError("mkdir-p requires a path")
- path_ = tuple([seg.decode("utf-8") for seg in path.split('/') if seg ])
- # TODO: replace
- d = self._get_or_create_directories(self.node, path_)
- d.addCallback(lambda node: node.get_uri())
- return d
-
- def _get_or_create_directories(self, node, path):
- if not IDirectoryNode.providedBy(node):
- # unfortunately it is too late to provide the name of the
- # blocking directory in the error message.
- raise BlockingFileError("cannot create directory because there "
- "is a file in the way")
- if not path:
- return defer.succeed(node)
- d = node.get(path[0])
- def _maybe_create(f):
- f.trap(NoSuchChildError)
- return node.create_subdirectory(path[0])
- d.addErrback(_maybe_create)
- d.addCallback(self._get_or_create_directories, path[1:])
- return d
-
def _POST_upload(self, ctx):
req = IRequest(ctx)
charset = get_arg(req, "_charset", "utf-8")
d.addCallback(lambda res: "thing renamed")
return d
+ def _POST_move(self, req):
+ charset = get_arg(req, "_charset", "utf-8")
+ from_name = get_arg(req, "from_name")
+ if from_name is not None:
+ from_name = from_name.strip()
+ from_name = from_name.decode(charset)
+ assert isinstance(from_name, unicode)
+ to_name = get_arg(req, "to_name")
+ if to_name is not None:
+ to_name = to_name.strip()
+ to_name = to_name.decode(charset)
+ assert isinstance(to_name, unicode)
+ if not to_name:
+ to_name = from_name
+ to_dir = get_arg(req, "to_dir")
+ if to_dir is not None:
+ to_dir = to_dir.strip()
+ to_dir = to_dir.decode(charset)
+ assert isinstance(to_dir, unicode)
+ if not from_name or not to_dir:
+ raise WebError("move requires from_name and to_dir")
+ replace = boolean_of_arg(get_arg(req, "replace", "true"))
+
+ # Disallow slashes in both from_name and to_name, that would only
+ # cause confusion. t=move is only for moving things from the
+ # *current* directory into a second directory named by to_dir=
+ if "/" in from_name:
+ raise WebError("from_name= may not contain a slash",
+ http.BAD_REQUEST)
+ if "/" in to_name:
+ raise WebError("to_name= may not contain a slash",
+ http.BAD_REQUEST)
+
+ target_type = get_arg(req, "target_type", "name")
+ if target_type == "name":
+ d = self.node.get_child_at_path(to_dir)
+ elif target_type == "uri":
+ d = defer.succeed(self.client.create_node_from_uri(str(to_dir)))
+ else:
+ raise WebError("invalid target_type parameter", http.BAD_REQUEST)
+
+ def is_target_node_usable(target_node):
+ if not IDirectoryNode.providedBy(target_node):
+ raise WebError("to_dir is not a directory", http.BAD_REQUEST)
+ return target_node
+ d.addCallback(is_target_node_usable)
+ d.addCallback(lambda new_parent:
+ self.node.move_child_to(from_name, new_parent,
+ to_name, replace))
+ d.addCallback(lambda res: "thing moved")
+ return d
+
def _maybe_literal(self, res, Results_Class):
if res:
return Results_Class(self.client, res)
- return LiteralCheckResults(self.client)
+ return LiteralCheckResultsRenderer(self.client)
def _POST_check(self, req):
# check this directory
add_lease = boolean_of_arg(get_arg(req, "add-lease", "false"))
if repair:
d = self.node.check_and_repair(Monitor(), verify, add_lease)
- d.addCallback(self._maybe_literal, CheckAndRepairResults)
+ d.addCallback(self._maybe_literal, CheckAndRepairResultsRenderer)
else:
d = self.node.check(Monitor(), verify, add_lease)
- d.addCallback(self._maybe_literal, CheckResults)
+ d.addCallback(self._maybe_literal, CheckResultsRenderer)
return d
def _start_operation(self, monitor, renderer, ctx):
add_lease = boolean_of_arg(get_arg(ctx, "add-lease", "false"))
if repair:
monitor = self.node.start_deep_check_and_repair(verify, add_lease)
- renderer = DeepCheckAndRepairResults(self.client, monitor)
+ renderer = DeepCheckAndRepairResultsRenderer(self.client, monitor)
else:
monitor = self.node.start_deep_check(verify, add_lease)
- renderer = DeepCheckResults(self.client, monitor)
+ renderer = DeepCheckResultsRenderer(self.client, monitor)
return self._start_operation(monitor, renderer, ctx)
def _POST_stream_deep_check(self, ctx):
u = from_string_dirnode(dirnode.get_uri())
return u.abbrev_si()
+SPACE = u"\u00A0"*2
+
class DirectoryAsHTML(rend.Page):
# The remainder of this class is to render the directory into
# human+browser -oriented HTML.
T.input(type='hidden', name='t', value='rename-form'),
T.input(type='hidden', name='name', value=name),
T.input(type='hidden', name='when_done', value="."),
- T.input(type='submit', value='rename', name="rename"),
+ T.input(type='submit', value='rename/move', name="rename"),
]
ctx.fillSlots("unlink", unlink)
# page that doesn't know about the directory at all
dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl)
- ctx.fillSlots("filename",
- T.a(href=dlurl)[html.escape(name)])
+ ctx.fillSlots("filename", T.a(href=dlurl)[name])
ctx.fillSlots("type", "SSK")
ctx.fillSlots("size", "?")
elif IImmutableFileNode.providedBy(target):
dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl)
- ctx.fillSlots("filename",
- T.a(href=dlurl)[html.escape(name)])
+ ctx.fillSlots("filename", T.a(href=dlurl)[name])
ctx.fillSlots("type", "FILE")
ctx.fillSlots("size", target.get_size())
elif IDirectoryNode.providedBy(target):
# directory
uri_link = "%s/uri/%s/" % (root, urllib.quote(target_uri))
- ctx.fillSlots("filename",
- T.a(href=uri_link)[html.escape(name)])
+ ctx.fillSlots("filename", T.a(href=uri_link)[name])
if not target.is_mutable():
dirtype = "DIR-IMM"
elif target.is_readonly():
else:
# unknown
- ctx.fillSlots("filename", html.escape(name))
+ ctx.fillSlots("filename", name)
if target.get_write_uri() is not None:
unknowntype = "?"
elif not self.node.is_mutable() or target.is_alleged_immutable():
return ctx.tag
- # XXX: Duplicated from root.py.
+ # XXX: similar to render_upload_form and render_mkdir_form in 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")[
+ mkdir_sdmf = T.input(type='radio', name='format',
+ value='sdmf', id='mkdir-sdmf',
+ checked='checked')
+ mkdir_mdmf = T.input(type='radio', name='format',
+ value='mdmf', id='mkdir-mdmf')
+
+ mkdir_form = T.form(action=".", method="post",
+ enctype="multipart/form-data")[
T.fieldset[
T.input(type="hidden", name="t", value="mkdir"),
T.input(type="hidden", name="when_done", value="."),
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"),
+ "New directory name:"+SPACE,
+ T.input(type="text", name="name"), SPACE,
+ T.input(type="submit", value="Create"), SPACE*2,
+ mkdir_sdmf, T.label(for_='mutable-directory-sdmf')[" SDMF"], SPACE,
+ mkdir_mdmf, T.label(for_='mutable-directory-mdmf')[" MDMF (experimental)"],
]]
- 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")[
+ forms.append(T.div(class_="freeform-form")[mkdir_form])
+
+ upload_chk = T.input(type='radio', name='format',
+ value='chk', id='upload-chk',
+ checked='checked')
+ upload_sdmf = T.input(type='radio', name='format',
+ value='sdmf', id='upload-sdmf')
+ upload_mdmf = T.input(type='radio', name='format',
+ value='mdmf', id='upload-mdmf')
+
+ upload_form = T.form(action=".", method="post",
+ enctype="multipart/form-data")[
T.fieldset[
T.input(type="hidden", name="t", value="upload"),
T.input(type="hidden", name="when_done", value="."),
T.legend(class_="freeform-form-label")["Upload a file to this directory"],
- "Choose a file to upload: ",
- T.input(type="file", name="file", class_="freeform-input-file"),
- " ",
- 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)"],
+ "Choose a file to upload:"+SPACE,
+ T.input(type="file", name="file", class_="freeform-input-file"), SPACE,
+ T.input(type="submit", value="Upload"), SPACE*2,
+ upload_chk, T.label(for_="upload-chk") [" Immutable"], SPACE,
+ upload_sdmf, T.label(for_="upload-sdmf")[" SDMF"], SPACE,
+ upload_mdmf, T.label(for_="upload-mdmf")[" MDMF (experimental)"],
]]
- forms.append(T.div(class_="freeform-form")[upload])
+ forms.append(T.div(class_="freeform-form")[upload_form])
- mount = T.form(action=".", method="post",
- enctype="multipart/form-data")[
+ attach_form = T.form(action=".", method="post",
+ enctype="multipart/form-data")[
T.fieldset[
T.input(type="hidden", name="t", value="uri"),
T.input(type="hidden", name="when_done", value="."),
T.legend(class_="freeform-form-label")["Add a link to a file or directory which is already in Tahoe-LAFS."],
- "New child name: ",
- T.input(type="text", name="name"), " ",
- "URI of new child: ",
- T.input(type="text", name="uri"), " ",
+ "New child name:"+SPACE,
+ T.input(type="text", name="name"), SPACE*2,
+ "URI of new child:"+SPACE,
+ T.input(type="text", name="uri"), SPACE,
T.input(type="submit", value="Attach"),
]]
- forms.append(T.div(class_="freeform-form")[mount])
+ forms.append(T.div(class_="freeform-form")[attach_form])
return forms
def render_results(self, ctx, data):
kiddata = ("filenode", {'size': childnode.get_size(),
'mutable': childnode.is_mutable(),
})
- if childnode.is_mutable() and \
- childnode.get_version() is not None:
+ if childnode.is_mutable():
mutable_type = childnode.get_version()
assert mutable_type in (SDMF_VERSION, MDMF_VERSION)
-
if mutable_type == MDMF_VERSION:
- mutable_type = "mdmf"
+ file_format = "MDMF"
else:
- mutable_type = "sdmf"
- kiddata[1]['mutable-type'] = mutable_type
+ file_format = "SDMF"
+ else:
+ file_format = "CHK"
+ kiddata[1]['format'] = file_format
elif IDirectoryNode.providedBy(childnode):
kiddata = ("dirnode", {'mutable': childnode.is_mutable()})
ctx.tag.attributes['value'] = name
return ctx.tag
-
class ManifestResults(rend.Page, ReloadMixin):
docFactory = getxmlfile("manifest.xhtml")