paulb@22 | 1 | #!/usr/bin/env python |
paulb@22 | 2 | |
paulb@22 | 3 | "A calendar application." |
paulb@22 | 4 | |
paulb@22 | 5 | import WebStack.Generic |
paulb@380 | 6 | import time |
paulb@22 | 7 | |
paulb@22 | 8 | class DirectoryResource: |
paulb@22 | 9 | |
paulb@22 | 10 | """ |
paulb@22 | 11 | A resource which handles incoming calendars and viewing requests. |
paulb@22 | 12 | An arbitrary set of rules can be applied to determine what is to be done |
paulb@22 | 13 | with a request, and in this case, the application appears as a directory of |
paulb@22 | 14 | calendars, yet also accepts incoming calendars. |
paulb@22 | 15 | """ |
paulb@22 | 16 | |
paulb@22 | 17 | def respond(self, trans): |
paulb@22 | 18 | |
paulb@22 | 19 | """ |
paulb@22 | 20 | Examine the incoming request, either saving a calendar or displaying |
paulb@22 | 21 | one. |
paulb@22 | 22 | """ |
paulb@22 | 23 | |
paulb@380 | 24 | # Remember uploaded calendars using a session. |
paulb@22 | 25 | |
paulb@380 | 26 | session = trans.get_session(create=1) |
paulb@22 | 27 | |
paulb@22 | 28 | # Determine the action to be taken. |
paulb@22 | 29 | |
paulb@22 | 30 | method = trans.get_request_method() |
paulb@22 | 31 | |
paulb@22 | 32 | # NOTE: Some frameworks do not pass in the content type. |
paulb@22 | 33 | |
paulb@22 | 34 | content_type = trans.get_content_type() |
paulb@22 | 35 | |
paulb@380 | 36 | # Handle uploads. |
paulb@380 | 37 | |
paulb@22 | 38 | if method == "PUT": |
paulb@380 | 39 | |
paulb@380 | 40 | # Get the last path component as the name of the calendar. |
paulb@380 | 41 | # NOTE: This could be improved to permit hierarchical naming. |
paulb@380 | 42 | |
paulb@380 | 43 | calendar_name = trans.get_path_without_query().split("/")[-1] |
paulb@22 | 44 | input = trans.get_request_stream() |
paulb@380 | 45 | data = input.read() |
paulb@380 | 46 | |
paulb@380 | 47 | # Store the calendar in the session. |
paulb@22 | 48 | |
paulb@380 | 49 | session["calendar name"] = calendar_name |
paulb@380 | 50 | session["media type"] = content_type.media_type |
paulb@380 | 51 | session["calendar data"] = data |
paulb@380 | 52 | session["calendar size"] = len(data) |
paulb@380 | 53 | session["calendar time"] = time.strftime("%Y-%m-%dT%T") |
paulb@22 | 54 | |
paulb@380 | 55 | # Handle directory browsing. |
paulb@380 | 56 | |
paulb@380 | 57 | elif method == "PROPFIND": |
paulb@380 | 58 | trans.set_response_code(207) |
paulb@22 | 59 | trans.set_content_type(WebStack.Generic.ContentType("text/html")) |
paulb@22 | 60 | out = trans.get_response_stream() |
paulb@380 | 61 | out.write("""<?xml version="1.0"?> |
paulb@380 | 62 | <D:multistatus xmlns:D="DAV:"> |
paulb@380 | 63 | """) |
paulb@380 | 64 | |
paulb@380 | 65 | if trans.get_path_info() == "/": |
paulb@380 | 66 | out.write(""" |
paulb@380 | 67 | <D:response> |
paulb@380 | 68 | <D:href>%s</D:href> |
paulb@380 | 69 | <D:propstat> |
paulb@380 | 70 | <D:prop> |
paulb@380 | 71 | <D:creationdate>%s</D:creationdate> |
paulb@380 | 72 | <D:displayname>%s</D:displayname> |
paulb@380 | 73 | <D:resourcetype> |
paulb@380 | 74 | <D:collection/> |
paulb@380 | 75 | </D:resourcetype> |
paulb@380 | 76 | </D:prop> |
paulb@380 | 77 | <D:status>HTTP/1.1 200 OK</D:status> |
paulb@380 | 78 | </D:propstat> |
paulb@380 | 79 | </D:response> |
paulb@380 | 80 | """ % (trans.get_path_without_query(), time.strftime("%Y-%m-%dT%T"), trans.get_path_without_query())) |
paulb@380 | 81 | |
paulb@380 | 82 | if session.has_key("calendar name"): |
paulb@380 | 83 | out.write(""" |
paulb@380 | 84 | <D:response> |
paulb@380 | 85 | <D:href>%s%s</D:href> |
paulb@380 | 86 | <D:propstat> |
paulb@380 | 87 | <D:prop> |
paulb@380 | 88 | <D:creationdate>%s</D:creationdate> |
paulb@380 | 89 | <D:displayname>%s</D:displayname> |
paulb@380 | 90 | <D:resourcetype/> |
paulb@380 | 91 | <D:getcontenttype>%s</D:getcontenttype> |
paulb@380 | 92 | </D:prop> |
paulb@380 | 93 | <D:status>HTTP/1.1 200 OK</D:status> |
paulb@380 | 94 | </D:propstat> |
paulb@380 | 95 | </D:response> |
paulb@380 | 96 | """ % (trans.get_path_without_query(), session.get("calendar name"), session.get("calendar time") or time.strftime("%Y-%m-%dT%T"), |
paulb@380 | 97 | session.get("calendar name"), session.get("media type") or "")) |
paulb@380 | 98 | |
paulb@380 | 99 | out.write(""" |
paulb@380 | 100 | </D:multistatus> |
paulb@380 | 101 | """) |
paulb@380 | 102 | |
paulb@380 | 103 | # Handle downloads. |
paulb@380 | 104 | |
paulb@380 | 105 | elif method == "GET": |
paulb@380 | 106 | trans.set_content_type(WebStack.Generic.ContentType("text/html")) |
paulb@380 | 107 | out = trans.get_response_stream() |
paulb@380 | 108 | out.write(""" |
paulb@380 | 109 | <html> |
paulb@380 | 110 | <head> |
paulb@380 | 111 | <title>Last Uploaded Calendar</title> |
paulb@380 | 112 | </head> |
paulb@380 | 113 | <body> |
paulb@380 | 114 | <h1>Calendar %s</h1> |
paulb@380 | 115 | <p>Media type: %s</p> |
paulb@380 | 116 | <p>Calendar size: %s</p> |
paulb@380 | 117 | <pre>%s</pre> |
paulb@380 | 118 | </body> |
paulb@380 | 119 | </html> |
paulb@380 | 120 | """ % (session.get("calendar name"), session.get("media type"), session.get("calendar size"), |
paulb@380 | 121 | session.get("calendar data", "").replace("&", "&").replace("<", "<").replace(">", ">"))) |
paulb@380 | 122 | |
paulb@380 | 123 | # Disallow other methods. |
paulb@380 | 124 | |
paulb@380 | 125 | else: |
paulb@380 | 126 | trans.set_response_code(405) |
paulb@22 | 127 | |
paulb@22 | 128 | # vim: tabstop=4 expandtab shiftwidth=4 |