tahoe-lafs/src/allmydata/web/info.py
Sajith Sasidharan 950d111793 Use POST target paths without pre-existing query arguments
`action="."` on `/uri/URI:DIR2:$DIRCAP` will render as `/uri/`, which
is not the result we want.
2020-06-17 21:16:38 -04:00

335 lines
11 KiB
Python

import os, urllib
from twisted.python.filepath import FilePath
from twisted.web.template import tags as T, Element, renderElement, XMLFile, renderer
from allmydata.util import base32
from allmydata.interfaces import IDirectoryNode, IFileNode, MDMF_VERSION
from allmydata.web.common import MultiFormatResource
from allmydata.mutable.common import UnrecoverableFileError # TODO: move
class MoreInfo(MultiFormatResource):
"""
A ``Resource`` for describing more information about a node.
:param node Node: The node to describe.
"""
def __init__(self, node):
super(MoreInfo, self).__init__()
self.node = node
def render_HTML(self, req):
"""
Render an HTML template describing this node.
"""
return renderElement(req, MoreInfoElement(self.node))
render_INFO = render_HTML
class MoreInfoElement(Element):
"""
An ``Element`` HTML template which can be flattened to describe this node.
:param Node node: The node to describe.
"""
loader = XMLFile(FilePath(__file__).sibling("info.xhtml"))
def __init__(self, node):
super(MoreInfoElement, self).__init__()
self.original = node
def abbrev(self, storage_index_or_none):
if storage_index_or_none:
return base32.b2a(storage_index_or_none)[:6]
return "LIT file"
def get_type(self):
node = self.original
if IDirectoryNode.providedBy(node):
if not node.is_mutable():
return "immutable directory"
return "directory"
if IFileNode.providedBy(node):
si = node.get_storage_index()
if si:
if node.is_mutable():
ret = "mutable file"
if node.get_version() == MDMF_VERSION:
ret += " (mdmf)"
else:
ret += " (sdmf)"
return ret
return "immutable file"
return "immutable LIT file"
return "unknown"
@renderer
def title(self, req, tag):
node = self.original
si = node.get_storage_index()
t = "More Info for %s" % self.get_type()
if si:
t += " (SI=%s)" % self.abbrev(si)
return tag(t)
@renderer
def header(self, req, tag):
return self.title(req, tag)
@renderer
def type(self, req, tag):
return tag(self.get_type())
@renderer
def si(self, req, tag):
si = self.original.get_storage_index()
if not si:
return "None"
return tag(base32.b2a(si))
@renderer
def size(self, req, tag):
node = self.original
d = node.get_current_size()
def _no_size(size):
if size is None:
return "?"
return size
d.addCallback(_no_size)
def _handle_unrecoverable(f):
f.trap(UnrecoverableFileError)
return "?"
d.addErrback(_handle_unrecoverable)
d.addCallback(lambda size: tag(str(size)))
return d
@renderer
def directory_writecap(self, req, tag):
node = self.original
if not IDirectoryNode.providedBy(node):
return ""
if node.is_readonly():
return ""
return tag(node.get_uri())
@renderer
def directory_readcap(self, req, tag):
node = self.original
if not IDirectoryNode.providedBy(node):
return ""
return tag(node.get_readonly_uri())
@renderer
def directory_verifycap(self, req, tag):
node = self.original
if not IDirectoryNode.providedBy(node):
return ""
verifier = node.get_verify_cap()
if verifier:
return tag(node.get_verify_cap().to_string())
return ""
@renderer
def file_writecap(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
node = node._node
write_uri = node.get_write_uri()
if not write_uri:
return ""
return tag(write_uri)
@renderer
def file_readcap(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
node = node._node
read_uri = node.get_readonly_uri()
if not read_uri:
return ""
return tag(read_uri)
@renderer
def file_verifycap(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
node = node._node
verifier = node.get_verify_cap()
if verifier:
return tag(node.get_verify_cap().to_string())
return ""
def get_root(self, req):
# the addSlash=True gives us one extra (empty) segment
depth = len(req.prepath) + len(req.postpath) - 1
link = "/".join([".."] * depth)
return link
@renderer
def raw_link(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
node = node._node
elif IFileNode.providedBy(node):
pass
else:
return ""
root = self.get_root(req)
quoted_uri = urllib.quote(node.get_uri())
text_plain_url = "%s/file/%s/@@named=/raw.txt" % (root, quoted_uri)
return T.li("Raw data as ", T.a("text/plain", href=text_plain_url))
@renderer
def is_checkable(self, req, tag):
node = self.original
si = node.get_storage_index()
if si:
return tag
# don't show checker button for LIT files
return ""
@renderer
def check_form(self, req, tag):
node = self.original
quoted_uri = urllib.quote(node.get_uri())
target = self.get_root(req) + "/uri/" + quoted_uri
if IDirectoryNode.providedBy(node):
target += "/"
check = T.form(action=target, method="post",
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="check"),
T.input(type="hidden", name="return_to", value="."),
T.legend("Check on this object", class_="freeform-form-label"),
T.div(
"Verify every bit? (EXPENSIVE):",
T.input(type="checkbox", name="verify"),
),
T.div("Repair any problems?: ",
T.input(type="checkbox", name="repair")),
T.div("Add/renew lease on all shares?: ",
T.input(type="checkbox", name="add-lease")),
T.div("Emit results in JSON format?: ",
T.input(type="checkbox", name="output", value="JSON")),
T.input(type="submit", value="Check"),
))
return tag(check)
@renderer
def is_mutable_file(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
return ""
if (IFileNode.providedBy(node)
and node.is_mutable() and not node.is_readonly()):
return tag
return ""
@renderer
def overwrite_form(self, req, tag):
node = self.original
root = self.get_root(req)
action = "%s/uri/%s" % (root, urllib.quote(node.get_uri()))
done_url = "%s/uri/%s?t=info" % (root, urllib.quote(node.get_uri()))
overwrite = T.form(action=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=done_url),
T.legend("Overwrite", class_="freeform-form-label"),
"Upload new contents: ",
T.input(type="file", name="file"),
" ",
T.input(type="submit", value="Replace Contents")
))
return tag(overwrite)
@renderer
def is_directory(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
return tag
return ""
@renderer
def deep_check_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
deep_check = T.form(action=req.path, method="post",
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-deep-check"),
T.input(type="hidden", name="return_to", value="."),
T.legend("Run a deep-check operation (EXPENSIVE)", class_="freeform-form-label"),
T.div(
"Verify every bit? (EVEN MORE EXPENSIVE):",
T.input(type="checkbox", name="verify"),
),
T.div("Repair any problems?: ",
T.input(type="checkbox", name="repair")),
T.div("Add/renew lease on all shares?: ",
T.input(type="checkbox", name="add-lease")),
T.div("Emit results in JSON format?: ",
T.input(type="checkbox", name="output", value="JSON")),
T.input(type="hidden", name="ophandle", value=ophandle),
T.input(type="submit", value="Deep-Check"),
))
return tag(deep_check)
@renderer
def deep_size_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
deep_size = T.form(action=req.path, method="post",
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-deep-size"),
T.legend("Run a deep-size operation (EXPENSIVE)", class_="freeform-form-label"),
T.input(type="hidden", name="ophandle", value=ophandle),
T.input(type="submit", value="Deep-Size"),
))
return tag(deep_size)
@renderer
def deep_stats_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
deep_stats = T.form(action=req.path, method="post",
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-deep-stats"),
T.legend("Run a deep-stats operation (EXPENSIVE)", class_="freeform-form-label"),
T.input(type="hidden", name="ophandle", value=ophandle),
T.input(type="submit", value="Deep-Stats"),
))
return tag(deep_stats)
@renderer
def manifest_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
manifest = T.form(action=req.path, method="post",
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-manifest"),
T.legend("Run a manifest operation (EXPENSIVE)", class_="freeform-form-label"),
T.div("Output Format: ",
T.select(name="output")
( T.option("HTML", value="html", selected="true"),
T.option("text", value="text"),
T.option("JSON", value="json"),
),
),
T.input(type="hidden", name="ophandle", value=ophandle),
T.input(type="submit", value="Manifest"),
))
return tag(manifest)
# TODO: edge metadata