mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-25 23:51:07 +00:00
950d111793
`action="."` on `/uri/URI:DIR2:$DIRCAP` will render as `/uri/`, which is not the result we want.
335 lines
11 KiB
Python
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
|