[CalendarServer-changes] [663] CalendarServer/trunk/twistedcaldav/extensions.py

source_changes at macosforge.org source_changes at macosforge.org
Mon Dec 4 19:33:56 PST 2006


Revision: 663
          http://trac.macosforge.org/projects/calendarserver/changeset/663
Author:   wsanchez at apple.com
Date:     2006-12-04 19:33:55 -0800 (Mon, 04 Dec 2006)

Log Message:
-----------
Implement a less boneheaded directory renderer.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/extensions.py

Modified: CalendarServer/trunk/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/extensions.py	2006-12-05 03:33:27 UTC (rev 662)
+++ CalendarServer/trunk/twistedcaldav/extensions.py	2006-12-05 03:33:55 UTC (rev 663)
@@ -26,23 +26,147 @@
     "ReadOnlyResourceMixIn",
 ]
 
+import urllib
+import time
+
 from twisted.web2 import responsecode
-from twisted.web2.http import HTTPError
+from twisted.web2.http import HTTPError, Response
+from twisted.web2.http_headers import MimeType
+from twisted.web2.static import MetaDataMixin
 from twisted.web2.dav.http import StatusResponse
+from twisted.web2.dav.static import DAVFile as SuperDAVFile
+from twisted.web2.dav.resource import DAVResource as SuperDAVResource
 
-import twisted.web2.dav.resource
-import twisted.web2.dav.static
-
-class DAVResource (twisted.web2.dav.resource.DAVResource):
+class DAVResource (SuperDAVResource):
     """
     Extended L{twisted.web2.dav.resource.DAVResource} implementation.
     """
 
-class DAVFile (twisted.web2.dav.static.DAVFile):
+class DAVFile (SuperDAVFile):
     """
     Extended L{twisted.web2.dav.static.DAVFile} implementation.
     """
+    def render(self, req):
+        """You know what you doing."""
+        if not self.fp.exists():
+            return responsecode.NOT_FOUND
 
+        if self.fp.isdir():
+            if req.uri[-1] != "/":
+                # Redirect to include trailing '/' in URI
+                return http.RedirectResponse(req.unparseURL(path=req.path+'/'))
+            else:
+                ifp = self.fp.childSearchPreauth(*self.indexNames)
+                if ifp:
+                    # Render from the index file
+                    return self.createSimilarFile(ifp.path).render(req)
+
+                return self.render_directory(req)
+
+        try:
+            f = self.fp.open()
+        except IOError, e:
+            import errno
+            if e[0] == errno.EACCES:
+                return responsecode.FORBIDDEN
+            elif e[0] == errno.ENOENT:
+                return responsecode.NOT_FOUND
+            else:
+                raise
+
+        response = http.Response()
+        response.stream = stream.FileStream(f, 0, self.fp.getsize())
+
+        for (header, value) in (
+            ("content-type", self.contentType()),
+            ("content-encoding", self.contentEncoding()),
+        ):
+            if value is not None:
+                response.headers.setHeader(header, value)
+
+        return response
+
+    def render_directory(self, request):
+        """
+        Render a directory listing.
+        """
+        title = "Directory listing for %s" % urllib.unquote(request.path)
+    
+        s = """<html>
+<head>
+<title>%(title)s</title>
+<style>
+th, .even td, .odd td { padding-right: 0.5em; font-family: monospace}
+.even-dir { background-color: #efe0ef }
+.even { background-color: #eee }
+.odd-dir {background-color: #f0d0ef }
+.odd { background-color: #dedede }
+.icon { text-align: center }
+.listing {
+  margin-left: auto;
+  margin-right: auto;
+  width: 50%%;
+  padding: 0.1em;
+}
+body { border: 0; padding: 0; margin: 0; background-color: #efefef;}
+h1 {padding: 0.1em; background-color: #777; color: white; border-bottom: thin white dashed;}
+</style>
+</head>
+<body>
+<div class="directory-listing">
+<h1>%(title)s</h1>
+<table>
+
+<tr><th>Filename</th> <th>Size</th> <th>Last Modified</th> <th>File Type</th></tr>
+""" % { "title": "Directory listing for %s" % urllib.unquote(request.path) }
+
+        even = False
+        for name in self.listChildren():
+            child = self.getChild(name)
+
+            url = urllib.quote(name, '/')
+            if isinstance(child, SuperDAVFile) and child.isCollection():
+                url += "/"
+                name += "/"
+
+            if isinstance(child, MetaDataMixin):
+                size = child.contentLength()
+                lastModified = child.lastModified()
+                contentType = child.contentType()
+            else:
+                size = None
+                lastModified = None
+                contentType = None
+
+            def orNone(value, default="?", f=None):
+                if value is None:
+                    return default
+                elif f is not None:
+                    return f(value)
+                else:
+                    return value
+
+            # FIXME: gray out resources that are not readable
+            s += """<tr class="%(even)s"><td><a href="%(url)s">%(name)s</a></td> <td align="right">%(size)s</td> <td>%(lastModified)s</td><td>%(type)s</td></tr>\n""" % {
+                "even": even and "even" or "odd",
+                "url": url,
+                "name": name,
+                "size": orNone(size),
+                "lastModified": orNone(lastModified, f=lambda t: time.strftime("%Y-%b-%d %H:%M", time.localtime(t))),
+                "type": orNone(contentType, default="-", f=lambda m: "%s/%s %s" % (m.mediaType, m.mediaSubtype, m.params)),
+            }
+            even = not even
+        s += """
+</table>
+</div>
+</body>
+</html>
+"""
+
+        response = Response(200, {}, s)
+        response.headers.setHeader("content-type", MimeType("text", "html"))
+        return response
+
 class ReadOnlyResourceMixIn (object):
     """
     Read only resource.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061204/9fdaa4c8/attachment.html


More information about the calendarserver-changes mailing list