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, stylesheet_parameters, document): 110 111 """ 112 Send the output from the resource to the user employing the transaction 113 'trans', stylesheets having the given 'stylesheet_filenames', parameters 114 as defined in the 'stylesheet_parameters' dictionary, and the 'document' 115 upon which the output will be based. 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 respond(self, trans): 123 124 """ 125 Respond to the request described by the given transaction 'trans'. 126 """ 127 128 # Only obtain field information according to the stated method. 129 130 method = trans.get_request_method() 131 path_info = trans.get_path_info() 132 133 # Handle typical request methods, processing request information. 134 135 if method == "GET": 136 137 # Get the fields from the request path (URL). 138 139 form = XSLForms.Fields.Form(encoding=self.path_encoding, values_are_lists=1) 140 parameters = trans.get_fields_from_path() 141 form.set_parameters(parameters) 142 143 elif method == "POST": 144 145 # Get the fields from the request body. 146 147 form = XSLForms.Fields.Form(encoding=self.encoding, values_are_lists=1) 148 149 # Handle requests for in-page updates. 150 151 if path_info in self.in_page_resources.keys(): 152 parameters = self.get_fields_from_body(trans, self.encoding) 153 else: 154 parameters = trans.get_fields_from_body(self.encoding) 155 156 # Get the XML representation of the request. 157 158 form.set_parameters(parameters) 159 160 else: 161 162 # Initialise empty containers. 163 164 parameters = {} 165 documents = {} 166 167 # Call an overridden method with the processed request information. 168 169 self.respond_to_form(trans, form) 170 171 def respond_to_form(self, trans, form): 172 173 """ 174 Respond to the request described by the given transaction 'trans', using 175 the given 'form' object to conveniently retrieve field (request 176 parameter) information and structured form information (as DOM-style XML 177 documents). 178 """ 179 180 trans.set_response_code(500) 181 raise WebStack.Generic.EndOfResponse 182 183 # vim: tabstop=4 expandtab shiftwidth=4