From 046bda2b477c69e6534d928423372c516454ed31 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Tue, 23 Oct 2007 17:23:57 -0700
Subject: [PATCH] webish: add checker results and a 'Check' button to the web
 interface

---
 src/allmydata/dirnode.py          |  8 +++++++
 src/allmydata/interfaces.py       |  6 ++++++
 src/allmydata/web/directory.xhtml |  4 ++++
 src/allmydata/webish.py           | 36 +++++++++++++++++++++++++++++++
 4 files changed, 54 insertions(+)

diff --git a/src/allmydata/dirnode.py b/src/allmydata/dirnode.py
index 67b2f194..26305def 100644
--- a/src/allmydata/dirnode.py
+++ b/src/allmydata/dirnode.py
@@ -381,6 +381,10 @@ class ImmutableDirectoryNode:
     def get_verifier(self):
         return IDirnodeURI(self._uri).get_verifier()
 
+    def check(self):
+        verifier = self.get_verifier()
+        return self._client.getServiceNamed("checker").check(verifier)
+
     def get_child_at_path(self, path):
         if not path:
             return defer.succeed(self)
@@ -450,6 +454,10 @@ class FileNode:
     def get_verifier(self):
         return IFileURI(self.uri).get_verifier()
 
+    def check(self):
+        verifier = self.get_verifier()
+        return self._client.getServiceNamed("checker").check(verifier)
+
     def download(self, target):
         downloader = self._client.getServiceNamed("downloader")
         return downloader.download(self.uri, target)
diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index ae4398dc..38285b3d 100644
--- a/src/allmydata/interfaces.py
+++ b/src/allmydata/interfaces.py
@@ -366,6 +366,9 @@ class IFileNode(Interface):
         it holds a share for the file or directory.
         """
 
+    def check():
+        """Perform a file check. See IChecker.check for details."""
+
 class IDirectoryNode(Interface):
     def is_mutable():
         """Return True if this directory is mutable, False if it is read-only.
@@ -404,6 +407,9 @@ class IDirectoryNode(Interface):
         it holds a share for the file or directory.
         """
 
+    def check():
+        """Perform a file check. See IChecker.check for details."""
+
     def list():
         """I return a Deferred that fires with a dictionary mapping child
         name to an IFileNode or IDirectoryNode."""
diff --git a/src/allmydata/web/directory.xhtml b/src/allmydata/web/directory.xhtml
index 9b5b4ad4..478f5bc8 100644
--- a/src/allmydata/web/directory.xhtml
+++ b/src/allmydata/web/directory.xhtml
@@ -30,6 +30,8 @@
     <td>other representations</td>
     <td></td>
     <td></td>
+    <td></td>
+    <td>Checker Results</td>
   </tr>
   <tr n:pattern="item" n:render="row">
     <td><n:slot name="filename"/></td>
@@ -38,6 +40,8 @@
     <td><n:slot name="data"/></td>
     <td><n:slot name="delete"/></td>
     <td><n:slot name="rename"/></td>
+    <td><n:slot name="check"/></td>
+    <td><n:slot name="checker_results"/></td>
   </tr>
 
   <tr n:pattern="empty"><td>directory is empty!</td></tr>
diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py
index 3a07ab2a..88bbc9ab 100644
--- a/src/allmydata/webish.py
+++ b/src/allmydata/webish.py
@@ -166,8 +166,16 @@ class Directory(rend.Page):
         else:
             delete = "-"
             rename = "-"
+
         ctx.fillSlots("delete", delete)
         ctx.fillSlots("rename", rename)
+        check = T.form(action=url.here, method="post")[
+            T.input(type='hidden', name='t', value='check'),
+            T.input(type='hidden', name='name', value=name),
+            T.input(type='hidden', name='when_done', value=url.here),
+            T.input(type='submit', value='check', name="check"),
+            ]
+        ctx.fillSlots("check", check)
 
         # build the base of the uri_link link url
         uri_link = "/uri/" + urllib.quote(target.get_uri().replace("/", "!"))
@@ -219,6 +227,24 @@ class Directory(rend.Page):
 
         ctx.fillSlots("data", childdata)
 
+        checker = IClient(ctx).getServiceNamed("checker")
+        checker_results = checker.checker_results_for(target.get_verifier())
+        recent_results = reversed(checker_results[-5:])
+        if IFileNode.providedBy(target):
+            results = ("[" +
+                       ", ".join(["%d/%d" % (found, needed)
+                                  for (when, (needed, total, found, sharemap))
+                                  in recent_results]) +
+                       "]")
+        elif IDirectoryNode.providedBy(target):
+            results = ("[" +
+                       "".join([{True:"+",False:"-"}[res]
+                                for (when, res) in recent_results]) +
+                       "]")
+        else:
+            results = "%d results" % len(checker_results)
+        ctx.fillSlots("checker_results", results)
+
         return ctx.tag
 
     def render_forms(self, ctx, data):
@@ -692,6 +718,16 @@ class POSTHandler(rend.Page):
             def _done(newnode):
                 return newnode.get_uri()
             d.addCallback(_done)
+        elif t == "check":
+            d = self._node.get(name)
+            def _got_child(child_node):
+                d2 = child_node.check()
+                def _done(res):
+                    log.msg("checked %s, results %s" % (child_node, res))
+                    return res
+                d2.addCallback(_done)
+                return d2
+            d.addCallback(_got_child)
         else:
             print "BAD t=%s" % t
             return "BAD t=%s" % t
-- 
2.45.2