tahoe-lafs/src/allmydata/web/info.py

335 lines
11 KiB
Python
Raw Normal View History

import os, urllib
2019-08-14 11:53:53 +00:00
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
2019-08-14 11:53:53 +00:00
from allmydata.web.common import MultiFormatResource
from allmydata.mutable.common import UnrecoverableFileError # TODO: move
2019-08-14 11:53:53 +00:00
class MoreInfo(MultiFormatResource):
2019-08-16 17:45:45 +00:00
"""
A ``Resource`` for describing more information about a node.
:param node Node: The node to describe.
"""
2019-08-14 11:53:53 +00:00
def __init__(self, node):
super(MoreInfo, self).__init__()
self.node = node
def render_HTML(self, req):
2019-08-16 17:45:45 +00:00
"""
Render an HTML template describing this node.
"""
2019-08-14 11:53:53 +00:00
return renderElement(req, MoreInfoElement(self.node))
render_INFO = render_HTML
class MoreInfoElement(Element):
2019-08-16 17:45:45 +00:00
"""
An ``Element`` HTML template which can be flattened to describe this node.
:param Node node: The node to describe.
"""
2019-08-14 11:53:53 +00:00
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"
2019-08-14 11:53:53 +00:00
@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)
2019-08-14 11:53:53 +00:00
return tag(t)
2019-08-14 11:53:53 +00:00
@renderer
def header(self, req, tag):
return self.title(req, tag)
2019-08-14 11:53:53 +00:00
@renderer
def type(self, req, tag):
return tag(self.get_type())
2019-08-14 11:53:53 +00:00
@renderer
def si(self, req, tag):
si = self.original.get_storage_index()
if not si:
return "None"
2019-08-14 11:53:53 +00:00
return tag(base32.b2a(si))
2019-08-14 11:53:53 +00:00
@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)
2019-08-14 11:53:53 +00:00
d.addCallback(lambda size: tag(str(size)))
return d
2019-08-14 11:53:53 +00:00
@renderer
def directory_writecap(self, req, tag):
node = self.original
if not IDirectoryNode.providedBy(node):
return ""
if node.is_readonly():
return ""
2019-08-14 11:53:53 +00:00
return tag(node.get_uri())
2019-08-14 11:53:53 +00:00
@renderer
def directory_readcap(self, req, tag):
node = self.original
if not IDirectoryNode.providedBy(node):
return ""
2019-08-14 11:53:53 +00:00
return tag(node.get_readonly_uri())
2019-08-14 11:53:53 +00:00
@renderer
def directory_verifycap(self, req, tag):
node = self.original
if not IDirectoryNode.providedBy(node):
return ""
verifier = node.get_verify_cap()
if verifier:
2019-08-14 11:53:53 +00:00
return tag(node.get_verify_cap().to_string())
return ""
2019-08-14 11:53:53 +00:00
@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 ""
2019-08-14 11:53:53 +00:00
return tag(write_uri)
2019-08-14 11:53:53 +00:00
@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 ""
2019-08-14 11:53:53 +00:00
return tag(read_uri)
2019-08-14 11:53:53 +00:00
@renderer
def file_verifycap(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
node = node._node
verifier = node.get_verify_cap()
if verifier:
2019-08-14 11:53:53 +00:00
return tag(node.get_verify_cap().to_string())
return ""
2019-08-14 11:53:53 +00:00
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
2019-08-14 11:53:53 +00:00
@renderer
def raw_link(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
node = node._node
elif IFileNode.providedBy(node):
pass
else:
return ""
2019-08-14 11:53:53 +00:00
root = self.get_root(req)
quoted_uri = urllib.quote(node.get_uri())
text_plain_url = "%s/file/%s/@@named=/raw.txt" % (root, quoted_uri)
2019-08-14 11:53:53 +00:00
return T.li("Raw data as ", T.a("text/plain", href=text_plain_url))
2019-08-14 11:53:53 +00:00
@renderer
def is_checkable(self, req, tag):
node = self.original
si = node.get_storage_index()
if si:
2019-08-14 11:53:53 +00:00
return tag
# don't show checker button for LIT files
return ""
2019-08-14 11:53:53 +00:00
@renderer
def check_form(self, req, tag):
node = self.original
quoted_uri = urllib.quote(node.get_uri())
2019-08-14 11:53:53 +00:00
target = self.get_root(req) + "/uri/" + quoted_uri
if IDirectoryNode.providedBy(node):
target += "/"
check = T.form(action=target, method="post",
2019-08-14 11:53:53 +00:00
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="check"),
T.input(type="hidden", name="return_to", value="."),
2019-08-14 11:53:53 +00:00
T.legend("Check on this object", class_="freeform-form-label"),
T.div(
"Verify every bit? (EXPENSIVE):",
T.input(type="checkbox", name="verify"),
2019-08-14 11:53:53 +00:00
),
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"),
2019-08-14 11:53:53 +00:00
))
return tag(check)
2019-08-14 11:53:53 +00:00
@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()):
2019-08-14 11:53:53 +00:00
return tag
return ""
2019-08-14 11:53:53 +00:00
@renderer
def overwrite_form(self, req, tag):
node = self.original
2019-08-14 11:53:53 +00:00
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",
2019-08-14 11:53:53 +00:00
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="upload"),
T.input(type='hidden', name='when_done', value=done_url),
2019-08-14 11:53:53 +00:00
T.legend("Overwrite", class_="freeform-form-label"),
"Upload new contents: ",
T.input(type="file", name="file"),
" ",
T.input(type="submit", value="Replace Contents")
2019-08-14 11:53:53 +00:00
))
return tag(overwrite)
2019-08-14 11:53:53 +00:00
@renderer
def is_directory(self, req, tag):
node = self.original
if IDirectoryNode.providedBy(node):
2019-08-14 11:53:53 +00:00
return tag
return ""
2019-08-14 11:53:53 +00:00
@renderer
def deep_check_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
deep_check = T.form(action=req.path, method="post",
2019-08-14 11:53:53 +00:00
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-deep-check"),
T.input(type="hidden", name="return_to", value="."),
2019-08-14 11:53:53 +00:00
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"),
2019-08-14 11:53:53 +00:00
),
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"),
2019-08-14 11:53:53 +00:00
))
return tag(deep_check)
2019-08-14 11:53:53 +00:00
@renderer
def deep_size_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
deep_size = T.form(action=req.path, method="post",
2019-08-14 11:53:53 +00:00
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-deep-size"),
2019-08-14 11:53:53 +00:00
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"),
2019-08-14 11:53:53 +00:00
))
return tag(deep_size)
2019-08-14 11:53:53 +00:00
@renderer
def deep_stats_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
deep_stats = T.form(action=req.path, method="post",
2019-08-14 11:53:53 +00:00
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-deep-stats"),
2019-08-14 11:53:53 +00:00
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"),
2019-08-14 11:53:53 +00:00
))
return tag(deep_stats)
2019-08-14 11:53:53 +00:00
@renderer
def manifest_form(self, req, tag):
ophandle = base32.b2a(os.urandom(16))
manifest = T.form(action=req.path, method="post",
2019-08-14 11:53:53 +00:00
enctype="multipart/form-data")(
T.fieldset(
T.input(type="hidden", name="t", value="start-manifest"),
2019-08-14 11:53:53 +00:00
T.legend("Run a manifest operation (EXPENSIVE)", class_="freeform-form-label"),
T.div("Output Format: ",
T.select(name="output")
2019-08-14 11:53:53 +00:00
( 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"),
2019-08-14 11:53:53 +00:00
))
return tag(manifest)
# TODO: edge metadata