1 #!/usr/bin/env python 2 3 "Resources for use with WebStack." 4 5 import WebStack.Generic 6 import XSLForms.Fields 7 import XSLForms.Prepare 8 import XSLForms.Output 9 import XSLOutput 10 import os 11 12 class XSLFormsResource: 13 14 """ 15 A generic XSLForms resource for use with WebStack. 16 17 When overriding this class, define the following attributes appropriately: 18 19 * template_resources - a dictionary mapping output identifiers to 20 (template_filename, output_filename) tuples, 21 indicating the template and stylesheet filenames 22 to be employed 23 24 * in_page_resources - a dictionary mapping fragment identifiers to 25 (output_filename, node_identifier) tuples, 26 indicating the stylesheet filename to be 27 employed, along with the node identifier used in 28 the original template and output documents to 29 mark a region of those documents as the fragment 30 to be updated upon "in-page" requests 31 32 * resource_dir - the absolute path of the directory in which 33 stylesheet resources are to reside 34 35 All filenames shall be simple leafnames for files residing in the resource's 36 special resource directory 'resource_dir'. 37 38 The following attributes may also be specified: 39 40 * path_encoding - the assumed encoding of characters in request 41 paths 42 43 * encoding - the assumed encoding of characters in request 44 bodies 45 """ 46 47 path_encoding = "iso-8859-1" 48 encoding = "utf-8" 49 template_resources = {} 50 in_page_resources = {} 51 resource_dir = None 52 53 def get_fields_from_body(self, trans, encoding): 54 55 """ 56 From the given transaction 'trans' and using the stated text 'encoding' 57 get the field values from the request body and return a dictionary 58 mapping field names to lists of such values. 59 """ 60 61 text = trans.get_request_stream().read().decode(encoding) 62 parameters = {} 63 for text_line in text.split("\r\n"): 64 text_parts = text_line.split("=") 65 text_name, text_value = text_parts[0], "=".join(text_parts[1:]) 66 if not parameters.has_key(text_name): 67 parameters[text_name] = [] 68 # NOTE: Workaround from posted text. 69 if text_value[-1] == "\x00": 70 text_value = text_value[:-1] 71 parameters[text_name].append(text_value) 72 return parameters 73 74 def prepare_output(self, output_identifier): 75 76 """ 77 Prepare the output stylesheets using the given 'output_identifier' to 78 indicate which templates and stylesheets are to be employed in the 79 production of output from the resource. 80 81 The 'output_identifier' is used as a key to the 'template_resources' 82 dictionary attribute. 83 """ 84 85 template_filename, output_filename = self.template_resources[output_identifier] 86 output_path = os.path.join(self.resource_dir, output_filename) 87 template_path = os.path.join(self.resource_dir, template_filename) 88 XSLForms.Prepare.ensure_stylesheet(template_path, output_path) 89 return output_path 90 91 def prepare_fragment(self, output_identifier, fragment_identifier): 92 93 """ 94 Prepare the output stylesheets for the given 'output_identifier' and 95 'fragment_identifier', indicating which templates and stylesheets are to 96 be employed in the production of output from the resource. 97 98 The 'output_identifier' is used as a key to the 'template_resources' 99 dictionary attribute; the 'fragment_identifier' is used as a key to the 100 'in_page_resources' dictionary attribute. 101 """ 102 103 output_path = self.prepare_output(output_identifier) 104 fragment_filename, node_identifier = self.in_page_resources[fragment_identifier] 105 fragment_path = os.path.join(self.resource_dir, fragment_filename) 106 XSLForms.Prepare.ensure_stylesheet_fragment(output_path, fragment_path, node_identifier) 107 return fragment_path 108 109 def send_output(self, trans, stylesheet_filenames, document, stylesheet_parameters=None): 110 111 """ 112 Send the output from the resource to the user employing the transaction 113 'trans', stylesheets having the given 'stylesheet_filenames', the 114 'document' upon which the output will be based, and the optional 115 parameters as defined in the 'stylesheet_parameters' dictionary. 116 """ 117 118 proc = XSLOutput.Processor(stylesheet_filenames, parameters=stylesheet_parameters) 119 proc.send_output(trans.get_response_stream(), trans.get_response_stream_encoding(), 120 document) 121 122 def get_in_page_resource(self, trans): 123 124 """ 125 Return the in-page resource being referred to in the given transaction 126 'trans'. 127 """ 128 129 return trans.get_path_info().split("/")[-1] 130 131 def respond(self, trans): 132 133 """ 134 Respond to the request described by the given transaction 'trans'. 135 """ 136 137 # Only obtain field information according to the stated method. 138 139 method = trans.get_request_method() 140 in_page_resource = self.get_in_page_resource(trans) 141 142 # Handle typical request methods, processing request information. 143 144 if method == "GET": 145 146 # Get the fields from the request path (URL). 147 148 form = XSLForms.Fields.Form(encoding=self.path_encoding, values_are_lists=1) 149 parameters = trans.get_fields_from_path() 150 form.set_parameters(parameters) 151 152 elif method == "POST": 153 154 # Get the fields from the request body. 155 156 form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1) 157 158 # Handle requests for in-page updates. 159 160 if in_page_resource in self.in_page_resources.keys(): 161 parameters = self.get_fields_from_body(trans, self.encoding) 162 else: 163 parameters = trans.get_fields_from_body(self.encoding) 164 165 # Get the XML representation of the request. 166 167 form.set_parameters(parameters) 168 169 else: 170 171 # Initialise empty containers. 172 173 parameters = {} 174 documents = {} 175 176 # Call an overridden method with the processed request information. 177 178 self.respond_to_form(trans, form) 179 180 def respond_to_form(self, trans, form): 181 182 """ 183 Respond to the request described by the given transaction 'trans', using 184 the given 'form' object to conveniently retrieve field (request 185 parameter) information and structured form information (as DOM-style XML 186 documents). 187 """ 188 189 trans.set_response_code(500) 190 raise WebStack.Generic.EndOfResponse 191 192 # vim: tabstop=4 expandtab shiftwidth=4