For this round, I used straight html.

I've moved the form generation to the server-side.
I've added names to match the keys that are being edited.

The design allows any part of the key structure to be edited with urls like
http://localhost:8080/vserver/default
or
http://localhost:8080/vserver/default/directory/$
and the links in the document headers allow more specific edit requests.

I've added a Commit Changes button at the bottom, hitting it does a post to the same location, and the resulting keys are displayed above the usual request content.

Some look and feel of the Cherokee Project site has been co-opted.
Index: admin.html
===================================================================
--- admin.html	(revision 932)
+++ admin.html	(working copy)
@@ -1,15 +1,46 @@
 <html>
 <head>
+<title>%(title)s</title>
+<link href="http://cherokee-project.com/themes/cherokee/cherokee.css"; rel="stylesheet" type="text/css" media="all" />
+<!--
 <link rel="stylesheet" type="text/css" href="js/resources/css/ext-all.css" />
 <script text="text/javascript" src="js/adapter/ext/ext-base.js"></script>
 <script text="text/javascript" src="js/ext-all.js"></script>
 <script type="text/javascript" src="admin.js"></script>
-<style>
-  .section { padding: 0 0 0 1em; }
-</style>
+-->
 </head>
-<body>
+<body id="cherokee_body">
+	<div id="container">
+    <table id="container-table" >
+      <tr>
+        <td id="container-logo" onclick="window.location='/';">&nbsp;&nbsp;&nbsp;</td>
+          <td id="container-nav">
+            <ul id="nav">
+              <li><a href="/">Configuration Home</a></li>
+              <li><a href="http://cherokee-project.com/";>Project</a></li>
+              <li><a href="http://cherokee-project.com/doc";>Documentation</a></li>
+              <li><a href="http://cherokee-project.com/branding";>Logos</a></li>
+            </ul>
+          </td>
+        </tr>
+      </table>
+			 <br />
+                                
+		<div id="main">
+						
+      %(post_info_display)s
 
+      %(content)s
+
+			<div class="clearfix"></div>
+			<div id="footer">
+				Obviously <a href="http://www.cherokee-project.com/"; class="a-pie">powered by Cherokee</a>
+                    <a href="http://www.cherokee-project.com/about/"; class="a-pie"><b> !</b></a><br/>
+
+				&copy; 2005 Alvaro Lopez Ortega
+			</div>
+  </div>  <!-- #main -->
+</div>  <!-- #container -->
 <div id="vserver-list" style="width: 180px;"></div>
 <div id="vserver-options"></div>
 </body>
Index: server.py
===================================================================
--- server.py	(revision 932)
+++ server.py	(working copy)
@@ -2,37 +2,78 @@
 
 from pyscgi.pyscgi import ServerFactory, SCGIHandler
 from cherokeeconf import Config
+from urllib import unquote
 
 DEFAULT_PORT = 4000
 CONFIG_FILE = "admin_test.conf"
 ADMIN_TEMPLATE = "admin.html"
+CONTENT_TYPES = {'js': 'text/javascript', 'css': 'text/css', 'png': 'image/png'}
  
 def strip_slashes (uri):
 	if uri[0] == '/':
 		uri = uri[1:]
-	if uri[-1] == '/':
+	if uri and uri[-1] == '/':
 		uri = uri[:-1]
 	return uri
 
 class MyHandler(SCGIHandler):
     def __init__ (self, request, client_address, server):
-        SCGIHandler.__init__ (self, request, client_address, server)
+        SCGIHandler.__init__ (self, request, client_address, server)      
 
+    def _content_type(self, request_uri):
+        ext = request_uri.split('.')[-1]
+        try:
+            return CONTENT_TYPES[ext]
+        except:
+            return "text/html"
+            
+
     def handle_request (self):
-        self.wfile.write('Content-Type: text/html\r\n\r\n')
+        """Main Request Method"""
+
         self.config = Config(CONFIG_FILE)
-
         request_uri = self.env['REQUEST_URI']
+        self.wfile.write('Content-Type: %s\r\n\r\n' % (self._content_type(request_uri)))
 
-
-        if request_uri.startswith("/config"):
-            self._config_request(request_uri)
+        # just send through images and scripts
+        ext = request_uri.split('.')[-1]
+        if ext in ('js', 'css', 'png'):
+            content = open(request_uri[1:])
+            self.wfile.write(content.read())
+            content.close()
             return
+       
+        self._process_post()
+        self._config_request(request_uri)
 
-	# By deafault, it's an admin interface request
-	self._admin_request(request_uri)
 
+    def _process_post(self):
+        """If values are sent via a post, process them
 
+        Currently, they are simply displayed above the main content
+        """
+
+        self.handle_post()
+
+        if self.post:
+            post_info = {}
+            keys = []
+            for keyvalue in self.post.split("&"):
+                keyvalue = keyvalue.split("=")
+                key, value = unquote(keyvalue[0]), unquote(keyvalue[1]) 
+                keys.append(key)
+                post_info[key] = value
+
+            keys.sort()
+            view_results = []
+            last_key = keys and keys[0]
+            for key in keys:
+                  view_results.append("%s = %s" % (key, post_info[key])) 
+
+            self.post_info = post_info
+            self.post_info_display = "\n".join(view_results)
+
+
     def _config_request(self, request_uri):
         """Configuration request handler."""
 
@@ -40,23 +81,27 @@
             request_path, request_options = request_uri.split("?")
         else:
             request_path = request_uri
-            request_options = "" 
+            request_options = ""       
         
-        
         request_path = strip_slashes(request_path)
         request_options = self._parse_options(request_options)
         
         request_uri_elements = request_path.split("/")
-        config_path = request_uri_elements[1:] # Override the /config/ element
+        if request_uri_elements and request_uri_elements[0] == "config":
+            config_path = request_uri_elements[1:] # Override the /config/ element
+        else:
+            config_path = request_uri_elements
         
         config_node = self.config.root
         
+        paths = []      
         for path_element in config_path:
             path_element = path_element.replace("$", "/")
             			
             if not path_element:
                 continue
             
+            paths.append(path_element)
             config_node = config_node[path_element]
 
         #Special EXT JS request for the treeview
@@ -71,11 +116,18 @@
             return
            
         if config_node:
-            self._node_as_json(config_node)
+            if len(paths) == 0 or (len(paths) == 1 and paths[0] == 'vserver'):
+                # for server listings... just display a list of server, vserver, etc... or vserver's servers
+                self._node_as_html(config_node, paths, self._node_as_html_server_list)            
+            else:
+                # this is a server configuration context... display editable content
+                self._node_as_html(config_node, paths, self._node_as_html_content)
     
     def _admin_request(self, request_uri):
         """Javascript or CSS content request handler."""
-        if request_uri.endswith(".js") or request_uri.endswith(".css"):
+
+        ext = request_uri.split('.')[-1]
+        if ext in ('js', 'css', 'png'):
             content = open(request_uri[1:])
             self.wfile.write(content.read())
             content.close()
@@ -121,6 +173,139 @@
         
         self.wfile.write("]")
 
+    def _node_as_html(self, config_node, paths, content_function):
+        """HTML Presentation of a Config Node"""
+
+        page_info = {}
+        page_info["title"] = "Cherokee Config :: " + " :: ".join(paths)
+        page_info["content"] = content_function(config_node, paths)
+        page_info["post_info_display"] = ""
+        if self.post:
+            page_info["post_info_display"] = "<pre>\n%s\n</pre>" % self.post_info_display
+
+        ui = open(ADMIN_TEMPLATE)
+        admin_template = ui.read()
+        page = admin_template % page_info
+        self.wfile.write(page)
+        ui.close()
+
+    def _paths_request(self, paths):
+        return "/" + "/".join([path.replace("/", "$") for path in paths])
+
+    def _node_as_html_server_list(self, config_node, paths):
+        """HTML list of available servers to configure"""
+
+        content = []
+        parent_path = "/".join(paths) or "Cherokee Configation Site"
+        content.append("<h1>%s</h1>" % parent_path) 
+        content.append("<ul>")
+        servers = []
+        for server in config_node:
+            servers.append(server)
+        servers.sort()
+        new_paths = paths[:]
+        new_paths.append("")
+        for server in servers:
+            new_paths[-1] = server
+            content.append("<li><a href=\"%s\">%s</a></li>" % (self._paths_request(new_paths), server))
+        content.append("</ul>")
+        return "\n".join(content)
+
+    def _node_as_html_content(self, config_node, paths):
+        """HTML page of editable entries"""
+
+        content = []
+        content.append("<form method=\"post\" action=\"\">")
+
+        # list out the path to the this server location
+        parent_path = "/".join(paths)
+        if parent_path:
+            content.append("<h1>")
+            for depth, path in enumerate(paths):
+                if depth < len(paths) - 1:
+                    content.append("<a href=\"%s\">%s</a>" % (self._paths_request(paths[:depth+1]), path))
+                    content.append(" &gt; ")
+                else:
+                    content.append(path)
+            content.append("</h1>")
+
+        edit_html = self._node_as_html_edit(config_node, paths)
+        content.append(edit_html)
+
+        content.append("<p>")
+        content.append("<input type=\"submit\" value=\"Commit Changes\" />")
+        content.append("</p>")
+
+        content.append("</form>")
+
+        return "\n".join(content)
+
+    def _node_as_html_edit(self, config_node, paths):
+        """top, recursable call, turning config_nodes into form fields"""
+        
+        key_prefix = "!" + "!".join(paths)
+        content = []
+        content.append("<div class=\"section\">")
+
+        simple_keys = []
+        complex_keys = []
+        for key in config_node:
+            has_kids = False
+            for entry in config_node[key]:
+                has_kids = True
+                break
+            if has_kids:
+                complex_keys.append(key)
+            else:
+                simple_keys.append(key)
+
+        simple_keys.sort()
+        for key in simple_keys:
+            content.append(self._to_form_field(key_prefix, key, config_node[key].value))
+  
+        complex_keys.sort()
+        for key in complex_keys:
+            content.append(self._to_section(key_prefix, key, config_node[key]))          
+
+        content.append("</div>")
+
+        return "\n".join(content)
+
+
+    def _to_form_field(self, key_prefix, key, value):
+        """given key and value, return a div with a label and an imput box"""
+
+        content = []
+        content.append("<div class=\"entry\">")
+        input_box = "<input name=\"%s\" size=\"%s\" value=\"%s\" />" % (key_prefix + "!" + key, len(value), value)
+        content.append("<label>%s %s</label>" % (key, input_box))
+        content.append("</div>")
+        return "\n".join(content)
+
+
+    def _to_section(self, key_prefix, key, config_node):
+        """give a key, config_node, return a header followed (ala _node_as_html_edit) by key/value inputs, then more complex sections
+        """
+
+        content = []
+        paths = key_prefix[1:].split("!")
+        depth = max(1, len(paths) - 2)
+        h_number = min(depth, 6)    
+        input_box = ""
+        if config_node.value:
+            input_box = " <input name=\"%s\" size=\"%s\" value=\"%s\" />" % (key_prefix + "!" + key, len(config_node.value), config_node.value)
+        my_path = paths[:]
+        my_path.append(key)       
+        link_to_key = "<a href=\"%s\">%s</a>" % (self._paths_request(my_path), key)
+        content.append("<h%s>%s%s</h%s>" % (h_number, link_to_key, input_box, h_number))
+
+        paths.append(key)
+        section_content = self._node_as_html_edit(config_node, paths)
+        content.append(section_content)
+
+        return "\n".join(content)
+
+
     def _node_as_json(self, config_node):
         """Recursive JSON formatted response
  
_______________________________________________
Cherokee mailing list
[email protected]
http://cherokee-project.com/cgi-bin/mailman/listinfo/cherokee

Reply via email to