Changeset 3827
- Timestamp:
- 06/12/08 16:17:57 (5 months ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
ticketsubmitpolicyplugin/0.11/setup.py
r3774 r3827 1 1 from setuptools import find_packages, setup 2 2 3 version='0. 4.1'3 version='0.5' 4 4 5 5 setup(name='TicketSubmitPolicy', ticketsubmitpolicyplugin/0.11/ticketsubmitpolicy/ticketsubmitpolicy.py
r3819 r3827 4 4 5 5 from genshi.builder import tag 6 from genshi.core import Markup 6 7 from genshi.filters import Transformer 8 from genshi.input import HTML 7 9 8 10 from trac.core import * … … 28 30 """name of the policy""" 29 31 30 def filter_stream(stream, field, comparitor, value, *args):31 """filter the stream and return it"""32 33 32 def javascript(): 34 33 """returns javascript functions""" 35 34 36 def onload( field, comparitor, value, *args):35 def onload(policy, condition, *args): 37 36 """returns code to be executable on page load""" 38 37 39 def onsubmit( field, comparitor, value, *args):38 def onsubmit(policy, condition, *args): 40 39 """returns code to be executed on form submission""" 40 41 def filter_stream(stream, policy, condition, *args): 42 """filter the stream and return it""" 43 41 44 42 45 class TicketRequires(Component): … … 47 50 return 'requires' 48 51 49 def filter_stream(self, stream, field, comparitor, value, requiredfield):50 return stream51 52 52 def javascript(self): 53 53 return """ 54 function requires(contingentfield, comparitor, value, requiredfield) 55 { 56 var val=getValue("field-" + contingentfield); 54 function requires(policy, requiredfield) 55 { 57 56 var element=document.getElementById("field-" + requiredfield); 58 57 var field=getValue("field-" + requiredfield); 59 58 60 if (co mparitor(val, value))59 if (condition(policy)) 61 60 { 62 61 63 62 if (!field) 64 63 { 65 return "Please provide a " + requiredfield + " for this " + contingentfield + " " + value + "ticket";64 return "Please provide a " + requiredfield + " for this ticket"; 66 65 } 67 66 … … 76 75 """ 77 76 78 def onload(self, field, comparitor, value, *args):77 def onload(self, policy, condition, *args): 79 78 return 80 79 81 def onsubmit(self, field, comparitor, value, requiredfield):82 requires = "requires( '%s', %s, %s, '%s');" % (field, comparitor, value, requiredfield)80 def onsubmit(self, policy, condition, requiredfield): 81 requires = "requires(%s, '%s');" % (policy, requiredfield) 83 82 return requires 83 84 def filter_stream(self, stream, policy, condition, requiredfield): 85 return stream 86 87 84 88 85 89 ### … … 92 96 return 'excludes' 93 97 94 def filter_stream(self, stream, field, comparitor, value, excludedfield): 95 exclude = "exclude('%s', %s, %s, '%s')" % ( field, comparitor, value, excludedfield ) 96 stream |= Transformer("//select[@id='field-%s']" % field).attr('onchange', exclude) 98 def javascript(self): 99 return """function exclude(policy, excludedfield) 100 { 101 var element=document.getElementById("field-" + excludedfield); 102 103 if (condition(policy)) 104 { 105 element.style.display="none"; 106 } 107 else 108 { 109 element.style.display=""; 110 } 111 112 } 113 """ 114 115 def onload(self, policy, condition, excludedfield): 116 return "exclude(%s, '%s');" % (policy, excludedfield ) 117 118 def onsubmit(self, policy, condition, excludedfield): 119 return 120 121 def filter_stream(self, stream, policy, condition, excludedfield): 122 exclude = "exclude(%s, '%s')" % ( policy, excludedfield ) 123 124 # XXX this is unsafe, in the case onchange is already specified on this field; 125 # see http://trac-hacks.org/ticket/3128 126 for c in condition: 127 field = c['field'] 128 stream |= Transformer("//select[@id='field-%s']" % field).attr('onchange', exclude) 129 97 130 return stream 98 131 99 def javascript(self):100 return """function exclude(contingentfield, comparitor, value, excludedfield)101 {102 var val=getValue("field-" + contingentfield);103 var element=document.getElementById("field-" + excludedfield);104 105 if (comparitor(val, value))106 {107 element.style.display="none";108 }109 else110 {111 element.style.display="";112 }113 114 }115 """116 117 def onload(self, field, comparitor, value, excludedfield):118 return "exclude('%s', %s, %s, '%s');" % ( field, comparitor, value, excludedfield )119 120 def onsubmit(self, field, comparitor, value, excludedfield):121 return122 132 123 133 124 134 class TicketSubmitPolicyPlugin(Component): 125 135 """ 136 enforce a policy for allowing ticket submission based on fields 137 138 126 139 get the selected option from HTML like this: 127 140 … … 144 157 implements(ITemplateStreamFilter) 145 158 policies = ExtensionPoint(ITicketSubmitPolicy) 146 147 # comparitors = {'!=': 'is',148 # '==': 'isNot',149 # 'in': 'isIn',150 # 'not in': 'isNotIn' }151 159 152 160 comparitors = { 'is': 1, … … 169 177 section = dict([i for i in self.config.options('ticket-submit-policy')]) 170 178 179 def parse_list(string): 180 return [ i.strip() for i in string.split(',') if i.strip()] 171 181 172 182 policies = {} # XXX this should probably be a real class, not an abused dict … … 183 193 condition = section[key] 184 194 195 # TODO: split by '&&' and parse disparate conditions 196 185 197 # look for longest match to prevent substring matching 186 198 comparitors = sorted(self.comparitors.keys(), key=lambda x: len(x), reverse=True) 187 199 match = re.match('.* (%s) .*' % '|'.join(comparitors), condition) 188 200 if match: 189 comparitor = match.groups()[0]201 comparitor = str(match.groups()[0]) # needs to be a str to be JS compatible via repr 190 202 field, value = [i.strip() for i in condition.split(comparitor, 1)] 203 field = str(field) 191 204 if self.comparitors[comparitor] == 'Array': 192 value = ', '.join(["'%s'" % i.strip() 193 for i in value.split(',')]) 194 value = '[%s]' % value 205 value = parse_list(value) 206 195 207 else: 196 value = "'%s'" % value 197 comparitor = camelCase(comparitor) 198 policies[name]['condition'] = dict(field=field,value=value,comparitor=comparitor) 208 value = str(value) 209 210 if 'condition' not in policies[name]: 211 policies[name]['condition'] = [] 212 policies[name]['condition'].append(dict(field=field,value=value,comparitor=comparitor)) 199 213 200 214 else: … … 205 219 if not policies[name].has_key('actions'): 206 220 policies[name]['actions'] = [] 207 args = [ i.strip() for i in section[key].split(',') if i.strip()]221 args = parse_list(section[key]) 208 222 policies[name]['actions'].append({'name': action, 'args': args}) 209 223 … … 222 236 # setup variables 223 237 javascript = [self.javascript()] 238 224 239 onload = [] 225 240 onsubmit = [] … … 228 243 # add JS functions to the head block 229 244 for policy in self.policies: 245 230 246 policy_javascript = policy.javascript() 231 247 if policy_javascript: … … 234 250 policies = self.parse() 235 251 236 for key, policy in policies.items(): 237 238 # condition 239 field = policy['condition']['field'] 240 comparitor = policy['condition']['comparitor'] 241 value = policy['condition']['value'] 252 for name, policy in policies.items(): 253 254 # insert the condition into the JS 255 conditions = policy['condition'] 256 conditions = ["{field: '%s', comparitor: %s, value: '%s'}" % (condition['field'], 257 camelCase(condition['comparitor']), 258 condition['value']) 259 for condition in conditions] 260 condition = '%s = [ %s ];' % (name, ', '.join(conditions)) 261 javascript.append(condition) 242 262 243 263 # find the correct handler for the policy … … 249 269 250 270 # filter the stream 251 stream = handler.filter_stream(stream, field, comparitor, value, *action['args'])271 stream = handler.filter_stream(stream, name, policy['condition'], *action['args']) 252 272 253 273 254 274 # add other necessary JS to the page 255 policy_onload = handler.onload( field, comparitor, value, *action['args'])275 policy_onload = handler.onload(name, policy['condition'], *action['args']) 256 276 if policy_onload: 257 277 onload.append(policy_onload) 258 policy_onsubmit = handler.onsubmit( field, comparitor, value, *action['args'])278 policy_onsubmit = handler.onsubmit(name, policy['condition'], *action['args']) 259 279 if policy_onsubmit: 260 280 onsubmit.append(policy_onsubmit) … … 263 283 if onload: 264 284 javascript.append(self.onload(onload)) 265 stream |= Transformer("body").attr('onload', ' onload()')285 stream |= Transformer("body").attr('onload', 'load()') 266 286 if onsubmit: 267 287 javascript.append(self.onsubmit(onsubmit)) … … 269 289 270 290 # insert head javascript 271 javascript = tag.script('\n'.join(javascript), **{ "type": "text/javascript"}) 272 stream |= Transformer("head").append(javascript) 291 if javascript: 292 javascript = tag.script('\n'.join(javascript), **{ "type": "text/javascript"}) 293 stream |= Transformer("head").append(javascript) 273 294 274 295 return stream … … 278 299 def onload(self, items): 279 300 return """ 280 function onload()301 function load() 281 302 { 282 303 %s … … 298 319 function onsubmit() 299 320 { 321 300 322 var errors = new Array(); 301 323 %s … … 323 345 def javascript(self): 324 346 """head javascript required to enforce ticket submission policy""" 347 # XXX this should probably go into a separate file 348 325 349 string = """ 326 350 function getValue(id) … … 357 381 { 358 382 return !isIn(x,y); 383 } 384 385 function condition(policy) 386 { 387 length = policy.length; 388 for ( var i=0; i != length; i++ ) 389 { 390 field = getValue('field-' + policy[i].field); 391 comparitor = policy[i].comparitor; 392 value = policy[i].value; 393 394 if ( !comparitor(field, value) ) 395 { 396 return false; 397 } 398 } 399 return true; 359 400 } 360 401
