Changeset 3827

Show
Ignore:
Timestamp:
06/12/08 16:17:57 (5 months ago)
Author:
k0s
Message:

major upgrade for 0.5 version; the whole conditions have been changed largely fixing #3129; also, words are now used "is", "is not", etc instead of ==, !=, etc operators

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • ticketsubmitpolicyplugin/0.11/setup.py

    r3774 r3827  
    11from setuptools import find_packages, setup 
    22 
    3 version='0.4.1
     3version='0.5
    44 
    55setup(name='TicketSubmitPolicy', 
  • ticketsubmitpolicyplugin/0.11/ticketsubmitpolicy/ticketsubmitpolicy.py

    r3819 r3827  
    44 
    55from genshi.builder import tag  
     6from genshi.core import Markup 
    67from genshi.filters import Transformer 
     8from genshi.input import HTML 
    79 
    810from trac.core import * 
     
    2830        """name of the policy""" 
    2931 
    30     def filter_stream(stream, field, comparitor, value, *args): 
    31         """filter the stream and return it""" 
    32  
    3332    def javascript(): 
    3433        """returns javascript functions""" 
    3534 
    36     def onload(field, comparitor, value, *args): 
     35    def onload(policy, condition, *args): 
    3736        """returns code to be executable on page load""" 
    3837 
    39     def onsubmit(field, comparitor, value, *args): 
     38    def onsubmit(policy, condition, *args): 
    4039        """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 
    4144 
    4245class TicketRequires(Component): 
     
    4750        return 'requires' 
    4851 
    49     def filter_stream(self, stream, field, comparitor, value, requiredfield): 
    50         return stream 
    51  
    5252    def javascript(self): 
    5353        return """ 
    54 function requires(contingentfield, comparitor, value, requiredfield) 
    55 
    56 var val=getValue("field-" + contingentfield); 
     54function requires(policy, requiredfield) 
     55
    5756var element=document.getElementById("field-" + requiredfield); 
    5857var field=getValue("field-" + requiredfield); 
    5958 
    60 if (comparitor(val, value)) 
     59if (condition(policy)) 
    6160{ 
    6261 
    6362if (!field) 
    6463{ 
    65 return "Please provide a " + requiredfield + " for this " + contingentfield + " " + value + " ticket"; 
     64return "Please provide a " + requiredfield + " for this ticket"; 
    6665} 
    6766 
     
    7675"""  
    7776 
    78     def onload(self, field, comparitor, value, *args): 
     77    def onload(self, policy, condition, *args): 
    7978        return 
    8079 
    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) 
    8382        return requires 
     83 
     84    def filter_stream(self, stream, policy, condition, requiredfield): 
     85        return stream 
     86 
     87 
    8488 
    8589###  
     
    9296        return 'excludes' 
    9397 
    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
     101var element=document.getElementById("field-" + excludedfield); 
     102 
     103if (condition(policy)) 
     104
     105element.style.display="none"; 
     106
     107else 
     108
     109element.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 
    97130        return stream 
    98131 
    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 else 
    110 { 
    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         return 
    122132 
    123133 
    124134class TicketSubmitPolicyPlugin(Component): 
    125135    """ 
     136    enforce a policy for allowing ticket submission based on fields 
     137     
     138     
    126139    get the selected option from HTML like this: 
    127140 
     
    144157    implements(ITemplateStreamFilter)  
    145158    policies = ExtensionPoint(ITicketSubmitPolicy) 
    146  
    147 #     comparitors =  {'!=': 'is',  
    148 #                     '==': 'isNot', 
    149 #                     'in': 'isIn', 
    150 #                     'not in': 'isNotIn' } 
    151159 
    152160    comparitors = { 'is': 1, 
     
    169177        section = dict([i for i in self.config.options('ticket-submit-policy')]) 
    170178 
     179        def parse_list(string): 
     180            return [ i.strip() for i in string.split(',') if i.strip()]  
    171181 
    172182        policies = {} # XXX this should probably be a real class, not an abused dict 
     
    183193                condition = section[key] 
    184194 
     195                # TODO:  split by '&&' and parse disparate conditions 
     196 
    185197                # look for longest match to prevent substring matching 
    186198                comparitors = sorted(self.comparitors.keys(), key=lambda x: len(x), reverse=True) 
    187199                match = re.match('.* (%s) .*' % '|'.join(comparitors), condition) 
    188200                if match: 
    189                     comparitor = match.groups()[0] 
     201                    comparitor = str(match.groups()[0]) # needs to be a str to be JS compatible via repr 
    190202                    field, value = [i.strip() for i in condition.split(comparitor, 1)] 
     203                    field = str(field) 
    191204                    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 
    195207                    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)) 
    199213 
    200214                else: 
     
    205219            if not policies[name].has_key('actions'): 
    206220                policies[name]['actions'] = [] 
    207             args = [ i.strip() for i in section[key].split(',') if i.strip()] 
     221            args = parse_list(section[key]) 
    208222            policies[name]['actions'].append({'name': action, 'args': args}) 
    209223 
     
    222236            # setup variables 
    223237            javascript = [self.javascript()] 
     238 
    224239            onload = [] 
    225240            onsubmit = [] 
     
    228243            # add JS functions to the head block 
    229244            for policy in self.policies: 
     245 
    230246                policy_javascript = policy.javascript() 
    231247                if policy_javascript: 
     
    234250            policies = self.parse() 
    235251             
    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) 
    242262 
    243263                # find the correct handler for the policy 
     
    249269                 
    250270                    # 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']) 
    252272 
    253273 
    254274                    # 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']) 
    256276                    if policy_onload: 
    257277                        onload.append(policy_onload) 
    258                     policy_onsubmit = handler.onsubmit(field, comparitor, value, *action['args']) 
     278                    policy_onsubmit = handler.onsubmit(name, policy['condition'], *action['args']) 
    259279                    if policy_onsubmit: 
    260280                        onsubmit.append(policy_onsubmit) 
     
    263283            if onload: 
    264284                javascript.append(self.onload(onload)) 
    265                 stream |= Transformer("body").attr('onload', 'onload()') 
     285                stream |= Transformer("body").attr('onload', 'load()') 
    266286            if onsubmit: 
    267287                javascript.append(self.onsubmit(onsubmit)) 
     
    269289 
    270290            # 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) 
    273294 
    274295        return stream 
     
    278299    def onload(self, items): 
    279300        return """ 
    280 function onload() 
     301function load() 
    281302{ 
    282303%s 
     
    298319function onsubmit() 
    299320{ 
     321 
    300322var errors = new Array(); 
    301323%s 
     
    323345    def javascript(self): 
    324346        """head javascript required to enforce ticket submission policy""" 
     347        # XXX this should probably go into a separate file 
     348 
    325349        string = """ 
    326350function getValue(id) 
     
    357381{ 
    358382return !isIn(x,y); 
     383} 
     384 
     385function 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; 
    359400} 
    360401