1 #!/usr/bin/env python 2 3 "A WebStack application for a system configurator." 4 5 import WebStack.Generic 6 import XSLForms.Fields 7 import XSLForms.Output 8 import XSLOutput 9 import libxml2dom 10 import os 11 12 # NOTE: Move these functions into a common utility library. 13 14 def add_elements(positions, element_name, element_parent_name=None): 15 if not positions: 16 return 17 for position in positions: 18 if element_parent_name: 19 parent_elements = position.xpath(element_parent_name) 20 if not parent_elements: 21 parent_element = position.ownerDocument.createElementNS(None, element_parent_name) 22 position.appendChild(parent_element) 23 else: 24 parent_element = parent_elements[0] 25 else: 26 parent_element = position 27 parent_element.appendChild(position.ownerDocument.createElementNS(None, element_name)) 28 29 def remove_elements(positions): 30 if not positions: 31 return 32 for position in positions: 33 position.parentNode.removeChild(position) 34 35 class ConfiguratorResource: 36 37 "A resource providing a system configurator." 38 39 resource_dir = os.path.join(os.path.split(__file__)[0], "Resources") 40 encoding = "utf-8" 41 42 def respond(self, trans): 43 44 # Produce stylesheet. 45 46 if trans.get_path_info().split("/")[-1] == "styles.css": 47 trans.set_content_type(WebStack.Generic.ContentType("text/css", self.encoding)) 48 out = trans.get_response_stream() 49 f = open(os.path.join(self.resource_dir, "styles.css"), "rb") 50 out.write(f.read()) 51 f.close() 52 raise WebStack.Generic.EndOfResponse 53 54 global XSLForms # NOTE: Strangely required to avoid UnboundLocalError! 55 method = trans.get_request_method() 56 57 # Only obtain field information according to the stated method. 58 59 if method == "GET": 60 fields = XSLForms.Fields.Fields(encoding="iso-8859-1", values_are_lists=1) 61 parameters = trans.get_fields_from_path() 62 documents = fields.make_documents(parameters.items()) 63 elif method == "POST": 64 fields = XSLForms.Fields.Fields(encoding=self.encoding, values_are_lists=1) 65 parameters = trans.get_fields_from_body(self.encoding) 66 documents = fields.make_documents(parameters.items()) 67 elif method == "PROPFIND": 68 dav_xsl = os.path.join(self.resource_dir, "config_dav.xsl") 69 database_xml = os.path.join(self.resource_dir, "config_database.xml") 70 database = libxml2dom.parse(database_xml) 71 72 # Process the path. 73 74 parts = trans.get_path_info().split("/") 75 if not parts[-1]: 76 del parts[-1] 77 78 start = parts[-1] 79 path = "/".join(parts) 80 proc = XSLOutput.Processor([dav_xsl], parameters={ 81 "path" : path, 82 "start" : start 83 }) 84 85 trans.set_response_code(207) 86 proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), 87 database) 88 raise WebStack.Generic.EndOfResponse 89 else: 90 trans.set_response_code(405) 91 raise WebStack.Generic.EndOfResponse 92 93 # Ensure the presence of a document. 94 95 if documents.has_key("configuration"): 96 configuration = documents["configuration"] 97 else: 98 configuration = fields.new_instance("configuration") 99 100 # Add and remove elements according to the selectors found. 101 102 selectors = fields.get_selectors(parameters.items(), documents) 103 add_elements(selectors.get("add-memory-unit"), "memory-unit") 104 remove_elements(selectors.get("remove-memory-unit")) 105 add_elements(selectors.get("add-storage-unit"), "storage-unit") 106 remove_elements(selectors.get("remove-storage-unit")) 107 add_elements(selectors.get("add-hard-disk"), "hard-disk") 108 remove_elements(selectors.get("remove-hard-disk")) 109 110 # Send a response according to certain parameters. 111 # When exported, an XML version of the data is returned. 112 113 if parameters.has_key("export"): 114 trans.set_content_type(WebStack.Generic.ContentType("text/xml", self.encoding)) 115 libxml2dom.toStream(configuration, trans.get_response_stream(), trans.get_response_stream_encoding()) 116 117 # When not exported, the data is transformed to produce a normal Web 118 # page. 119 120 else: 121 122 # Transform, adding enumerations/ranges. 123 124 database_xsl = os.path.join(self.resource_dir, "config_database.xsl") 125 database_xml = os.path.join(self.resource_dir, "config_database.xml") 126 proc = XSLOutput.Processor([database_xsl], references={"database" : database_xml}) 127 configuration = proc.get_result(configuration) 128 129 # Start the response. 130 131 trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding)) 132 133 # Ensure that an output stylesheet exists. 134 135 trans_xsl = os.path.join(self.resource_dir, "config_output.xsl") 136 template_xml = os.path.join(self.resource_dir, "config_template.xhtml") 137 138 if not os.path.exists(trans_xsl) or \ 139 os.path.getmtime(trans_xsl) < os.path.getmtime(template_xml): 140 141 import XSLForms.Prepare 142 template_xml = os.path.join(self.resource_dir, "config_template.xhtml") 143 XSLForms.Prepare.make_stylesheet(template_xml, trans_xsl) 144 145 # Complete the response. 146 147 proc = XSLOutput.Processor([trans_xsl]) 148 proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), 149 configuration) 150 151 # vim: tabstop=4 expandtab shiftwidth=4