Attachment 'Form-0.10alpha.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     Form.py - MoinMoin macro to display database based forms
   4     
   5     @copyright: 2008 Wolfgang Fischer
   6     @license: GNU GPL, see COPYING for details.
   7 
   8     Information on prerequisites, installation and usage can be found at
   9         http://moinmo.in/MacroMarket/Form
  10         
  11     2008-07-29 Version 0.9alpha because of moin-1.7.1 changes - RudolfReuter
  12       Attention: Python >= 2.5 needed for SQLite access
  13       debug help for tracing, insert the following line
  14           import pdb; pdb.set_trace() #debug
  15       changes in moin-1.7.1:
  16       1. MoinMoin/wikidicts.py - Function get_dict was dropped
  17       2. MoinMoin/wikiutil.py - Function renderText, 4th parameter dropped
  18       Added ".type" check in first Form element. 2008-07-31
  19     2008-12-28 Version 0.10alpha because of moin-1.8.1 changes RudolfReuter
  20       added dict check xxx/FormsDict for Linux version at #Get form dict
  21 """
  22 Dependencies = ['external']  # Can't be cached as it depends on external data
  23 
  24 def execute(macro, args):
  25     args = [ arg.strip() for arg in args.split(',') ]
  26     request = macro.request
  27     if not hasattr(request, 'form_macro_form'):
  28         request.form_macro_form = Form(request)
  29     return request.form_macro_form.render(args)
  30 
  31 
  32 class Form:
  33     import datetime
  34     from MoinMoin import wikiutil
  35 
  36     # fake _ function to get gettext recognize those texts:
  37     _ = lambda x: x
  38     ui_text = {
  39         # TODO: Button labels should be defined here
  40         }
  41     del _
  42 
  43     datetime_types = [ datetime.datetime, datetime.date, datetime.time ]
  44 
  45 
  46     def __init__(self, request):
  47         self.request = request
  48         self.formatter = request.formatter
  49         self.post_args = request.form
  50         self.date_format = request.user.date_fmt or request.cfg.date_fmt
  51         self.datetime_format = request.user.datetime_fmt or request.cfg.datetime_fmt
  52         today = self.datetime.date.today()
  53         self.variables = {
  54             'PAGE': request.page.page_name,
  55             'NOW' : self.datetime.datetime.now(),
  56             'TODAY' : today,
  57             'TODAY_DATETIME' : self.datetime.datetime.fromordinal(today.toordinal()),
  58             'ME': request.user.name,
  59         }
  60         self.forms = {}
  61         self.dict_name_stack = []
  62         self.last_form_key = ''
  63 
  64         # Extract information on post action
  65         self.action = u''
  66         self.action_form = u''
  67         self.action_index = 0
  68         for k in self.post_args.keys():
  69             if k.startswith('_Action_') and len(k) > 18:
  70                 self.action = k[8:11]
  71                 self.action_index = int(k[12:16])
  72                 self.action_form = k[17:]
  73 
  74 
  75 
  76     # =============================
  77     # Render form elements
  78     # =============================
  79     
  80     def render(self, args):
  81         if not args:
  82             return self.error_message('Missing arguments')
  83         element = args[0].lower()
  84         if element == 'start':
  85             return self.render_start()
  86         elif element == 'end':
  87             return self.render_end()
  88         request = self.request
  89         post_args = self.post_args
  90 
  91         if len(args) > 1:  # key specified
  92             key = self.key = args[1]
  93         else:
  94             key = u''
  95         self.dict_name, self.form_name, self.field_name = self.parse_element_key(key, element)
  96         dict_name = self.dict_name
  97         form_name = self.form_name
  98         self.form_key = form_key = u'%s.%s' % (dict_name, form_name)
  99         self.last_form_key = self.form_key
 100         if form_key not in self.forms:  # First element of this form
 101             form = self.form = self.forms[form_key] = {}
 102             form['form_name'] = form_name
 103             form['dict_name'] = dict_name
 104             # Get form dict
 105             if not request.dicts.has_dict(dict_name): # fix for Linux, RudolfReuter 2008-12-28
 106                 request.dicts.adddict(request, dict_name)
 107             form_dict_obj = request.dicts.dict(dict_name)
 108             #if not hasattr(form_dict_obj, 'get_dict'): # 'get_dict' was dropped in moin-1.7.1
 109             #    form['dict'] = { }
 110             #    return self.error_message('The form dictionary "%s" does not exist or is not valid' % dict_name)
 111             if not form_dict_obj.has_key('.type'):
 112                 form['dict'] = { }
 113                 return self.error_message('The form dictionary "%s" does not exist or is not valid' % dict_name)
 114             #form['dict'] = form_dict_obj.get_dict()
 115             form['dict'] = form_dict_obj
 116             form['addonly'] = self.get_stripped_from_form_dict('addonly') == u'1'
 117             # Connect to data source
 118             error = self.connect()
 119             if error:
 120                 return self.error_message(error)
 121 
 122             # Fetch data
 123             error = self.fetch_data()
 124             if error:
 125                 return self.error_message(error)
 126 
 127             if form_key == self.action_form:
 128                 # Do form action
 129                 self.do_action()
 130                 # Fetch updated data
 131                 self.fetch_data()
 132             # Close connection
 133             self.connection.close()
 134             
 135             records = form['records']
 136             form['add_mode'] = (post_args.has_key('_Action_New_0000_%s' % form_key) or not records) and self.get_stripped_from_form_dict('insert')
 137             # Set index of current record
 138             self.set_record_index()
 139             # Add record values to variables dict
 140             # if form_key not in post_args.get('form', []):
 141             index = form['index']
 142             if 0 < index <= len(records):
 143                 record = records[index-1]
 144             else:
 145                 record = value = None
 146             for (field, field_data) in form['fields'].iteritems():
 147                 field_type = field_data[1]
 148                 if record:
 149                     value = record[field_data[0]]
 150                     if field_type not in self.datetime_types and field_type:
 151                         value = field_type(value)
 152                 self.variables['%s.%s' % (form_key, field)] = value
 153            
 154         self.form = self.forms[form_key]
 155         
 156         if element == 'form':
 157             return self.render_form()
 158         elif element == 'buttons':
 159             return self.render_buttons()
 160         elif element == 'navigation':
 161             return self.render_navigation()
 162         elif element == 'filter':
 163             return self.render_filter()
 164         elif element == 'next':
 165             return self.render_next()
 166         else:
 167             return self.render_field(element, args)
 168 
 169         
 170     def render_form(self):
 171         # TODO: handle recursion
 172         # TODO: handle form body doesn't exist
 173         form = self.form
 174         request = self.request
 175         form_text = [ self.get_stripped_from_form_dict('header').replace('\\n', '\n') % self.variables ]
 176         form_body = self.get_stripped_from_form_dict('body').replace('\\n', '\n') % self.variables
 177         if self.get_stripped_from_form_dict('all'):
 178             records = form['records']
 179             count = [len(records), len(records) + 1][self.get_stripped_from_form_dict('insert') != u'']
 180             for i in range(count):
 181                 form_text.append(form_body)
 182         else:
 183             form_text.append(form_body)
 184         form_text.append(self.get_stripped_from_form_dict('footer').replace('\\n', '\n') % self.variables)
 185         # Load the parser
 186         Parser = self.wikiutil.searchAndImportPlugin(request.cfg, "parser", 'wiki')
 187         self.dict_name_stack.append(self.dict_name)
 188         # change in moin-1.7.1 MoinMoin/wikiutil.py line 2476, 4th parameter dropped
 189         #result = self.wikiutil.renderText(request, Parser, u''.join(form_text), line_anchors=False)
 190         result = self.wikiutil.renderText(request, Parser, u''.join(form_text))
 191         self.dict_name_stack.pop()
 192         return result
 193         
 194         
 195     def render_start(self):
 196         return self.formatter.rawHTML('<span><form action="" method="POST" enctype="multipart/form-data">')
 197 
 198         
 199     def render_end(self):
 200         return self.formatter.rawHTML('</form></span>')
 201   
 202     
 203     def render_next(self):
 204         form = self.form
 205         form['index'] += 1
 206         form['add_mode'] = form['index'] > len(form['records'])
 207         return u''
 208 
 209 
 210     def render_field(self, element, args):
 211         form = self.form
 212         field_name = self.field_name
 213         field_key = '%s.%s' % (self.form_key, field_name)
 214         value = self.wikiutil.escape(self.get_field_value(self.form_key, field_name, field_key) or '', 1)
 215         
 216         if element == 'value':
 217             return self.formatter.rawHTML(u'%s<input type="hidden" name="%s" value="%s">' % (value, field_key, value))
 218 
 219         elif element == 'textarea':
 220             if len(args) > 2:
 221                 cols = args[2]
 222             else:
 223                 cols = u''
 224             if len(args) > 3:
 225                 rows = args[3]
 226             else:
 227                 rows = u''
 228             return self.formatter.rawHTML(u'<textarea name="%s" cols="%s" rows="%s">%s</textarea>' % (field_key, cols, rows, value))
 229 
 230         elif element == 'hidden':
 231             return self.formatter.rawHTML(u'<input type="hidden" name="%s" value="%s">' % (field_key, value))
 232 
 233         else:
 234             if len(args) > 2:
 235                 size = args[2]
 236             else:
 237                 size = u''
 238             return self.formatter.rawHTML(u'<input type="text" name="%s" size="%s" value="%s">' % (field_key, size, value))
 239 
 240 
 241     def get_field_value(self, form_key, field_name, field_key, for_action = 0):
 242         if field_name.startswith('@'):
 243             value = self.post_args.get(field_key, [None])[0]
 244         elif not for_action:
 245             form = self.forms[form_key]
 246             index = form['index']
 247             records = form['records']
 248             if index > len(records):
 249                 value = None
 250             else:
 251                 value = records[index-1][form['fields'][field_name][0]]
 252         else:
 253             if form_key == self.action_form:
 254                 index = self.action_index
 255             else:
 256                 index = 0 
 257             value = self.post_args.get(field_key, [u''])[index]
 258             form = self.forms[form_key]
 259             field_type = form['fields'][field_name][1]
 260             if field_type:
 261                 value = field_type(value)
 262         if value == '':
 263             value = None
 264         return value
 265 
 266 
 267     def render_navigation(self):
 268         form = self.form
 269         form_key = self.form_key
 270         return self.formatter.rawHTML("""
 271                     <input type="submit" name="First_%s" value="|<">
 272                     <input type="submit" name="Previous_%s" value="<">
 273                     <input type="text" name="GoTo_%s" size="3" value="%s">
 274                     <input type="submit" name="Next_%s" value=">">
 275                     <input type="submit" name="Last_%s" value=">|"> of %s
 276                     """ % (form_key, form_key, form_key, str(form['index']), form_key, form_key, len(form['records'])))
 277 
 278 
 279     def render_filter(self):
 280         formatter = self.formatter
 281         return formatter.rawHTML('<input type="submit" name="_Action_App_0000" value="Filter"><input type="reset">')
 282 
 283 
 284     def render_buttons(self):
 285         formatter = self.formatter
 286         if self.get_stripped_from_form_dict('all'):
 287             action_index = self.form['index'] - 1
 288         else:
 289             action_index = 0
 290         action_key = ('0000%i_' % action_index)[-5:]
 291         action_key += self.form_key
 292         result = []
 293 #        if self.form['unbound']:
 294 #            result.append(formatter.rawHTML('<input type="submit" name="_Action_App_%s" value="Filter"><input type="reset">' % (action_key)))
 295         if self.form['add_mode']:
 296             result.append(formatter.rawHTML('<input type="submit" name="_Action_Add_%s" value="Add"><input type="submit" name="_Action_Can_%s" value="Cancel">' % (action_key, action_key)))
 297         else:
 298             if self.get_stripped_from_form_dict('update'):
 299                 result.append(formatter.rawHTML('<input type="submit" name="_Action_Sav_%s" value="Save">' % action_key))
 300             if self.get_stripped_from_form_dict('delete'):
 301                 result.append(formatter.rawHTML('<input type="submit" name="_Action_Del_%s" value="Delete">' % action_key))
 302             if self.get_stripped_from_form_dict('insert') and not self.get_stripped_from_form_dict('all'):
 303                 result.append(formatter.rawHTML('<input type="submit" name="_Action_New_%s" value="New">' % action_key))
 304         return u''.join(result)
 305 
 306 
 307 
 308     # =============================
 309     # DataBase communication
 310     # =============================
 311 
 312     def fetch_data(self):
 313         select_query = self.get_stripped_from_form_dict('select')
 314         if select_query:
 315             parameters = self.get_query_parameters('select')
 316         else:
 317             return 'The form "%s" does not contain a select query' % self.form_key
 318         cursor = self.connection.cursor()
 319         cursor.execute(select_query, parameters)
 320         description = cursor.description
 321         form = self.form
 322         form['fields'] = dict([(description[i][0], [i, description[i][1]]) for i in range(len(description))])
 323         form['records'] = [cursor.fetchall(), []][form['addonly']]
 324         cursor.close()
 325         return None
 326 
 327 
 328     def set_record_index(self):
 329         form = self.form
 330         form_key = self.form_key
 331         post_args = self.post_args
 332         records = form['records']
 333         # Calculate index of current record (first record is 1)
 334         if form['add_mode']:
 335             index = len(records) + 1
 336         elif 'GoTo_%s' % form_key in post_args:
 337             index = int(post_args['GoTo_%s' % form_key][0])
 338             if 'First_%s' % form_key in post_args:
 339                 index = 1
 340             elif 'Previous_%s' % form_key in post_args:
 341                 index -= 1
 342             elif 'Next_%s' % form_key in post_args:
 343                 index +=1
 344             elif 'Last_%s' % form_key in post_args:
 345                 index = len(records)
 346             if index < 1:
 347                 index = 1
 348             elif index > len(records):
 349                 index = len(records)
 350         else:
 351             goto_fields = self.get_stripped_from_form_dict('goto_fields')
 352             if goto_fields:
 353                 fields = form['fields']
 354                 goto_fields = [ field.strip() for field in goto_fields.split(',') ]
 355                 variables = self.variables
 356                 def get_value(value, type, variables):
 357                     value = value.strip().strip('"\'')
 358                     if value in variables:
 359                         return variables[value]
 360                     else:
 361                         value = value % variables
 362                     if type == self.datetime.datetime:
 363                         return self.datetime.datetime.strptime(value, self.datetime_format)
 364                     elif type == self.datetime.date:
 365                         return self.datetime.datetime.strptime(value, self.date_format)
 366                     return type(value)
 367                 goto_values_list = self.get_stripped_from_form_dict('goto_values').split(',')
 368                 goto_values = [ (get_value(goto_values_list[i], fields[goto_fields[i]][1], variables), fields[goto_fields[i]][0]) for i in range(len(goto_values_list)) ]
 369                 index = 0
 370                 for record_index in range(len(records)):
 371                     equal = True
 372                     for value in goto_values:
 373                         equal = value[0] == records[record_index][value[1]]
 374                         if not equal:
 375                             break
 376                     if equal:
 377                         index = record_index + 1
 378                         break
 379                 if not index:  # No matching record found
 380                     index = 1  # Set to first record (default)
 381             else:
 382                 index = 1  # Set to first record (default)
 383         form['index'] = index
 384 
 385 
 386     def do_action(self):
 387         cursor = self.connection.cursor()
 388         action = self.action
 389         action_query_map = {'Add' : 'insert', 'Sav' : 'update', 'Del' : 'delete'}
 390         if action in action_query_map:
 391             query_type =action_query_map[action] 
 392             query = self.get_stripped_from_form_dict(query_type) 
 393             if query:
 394                 parameters = self.get_query_parameters(query_type, for_action = 1)
 395                 count = cursor.execute(query, parameters)
 396         self.connection.commit()
 397         cursor.close()
 398 
 399         
 400     def connect(self):
 401         dict_name, self.connection_name = self.parse_connection_key(self.get_stripped_from_form_dict('connection'))
 402         connection_dict_obj = self.request.dicts.dict(dict_name)
 403         #if hasattr(connection_dict_obj, 'get_dict'): # 'get_dict' was dropped in moin-1.7.1
 404         self.connection_dict = connection_dict = connection_dict_obj
 405         #else:
 406             #return 'The connection dictionary "%s" does not exist or is not valid' % dict_name
 407 
 408         connection_name_prefix = '%s.' % self.connection_name
 409         connection_type = self.get_stripped_from_connection_dict('type').lower()
 410 
 411         if connection_type == 'sqlite':
 412             import sqlite3
 413             connection_string = self.get_stripped_from_connection_dict('file')
 414             if connection_string.startswith('attachment:'):
 415                 from MoinMoin.action import AttachFile
 416                 pagename, filename = AttachFile.absoluteName(connection_string[11:], dict_name)
 417                 connection_string = AttachFile.getFilename(self.request, pagename, filename)
 418             self.connection = sqlite3.connect(connection_string)
 419 
 420         elif connection_type == 'odbc':
 421             import pyodbc
 422             connection_string = self.get_stripped_from_connection_dict('connection_string')
 423             self.connection = pyodbc.connect(connection_string)
 424 
 425         elif connection_type == 'mysql':
 426             import MySQLdb
 427             port = connection_dict.get('port', '3306').strip('`')
 428             self.connection = MySQLdb.connect(host = self.get_stripped_from_connection_dict('server'), port = port, user = self.get_stripped_from_connection_dict('uid'), passwd = self.get_stripped_from_connection_dict('pwd'),db = self.get_stripped_from_connection_dict('database'))
 429 
 430         elif connection_type == 'oracle':
 431             import cx_Oracle
 432             if 'port' in parameters:
 433                 port = parameters['%sport' % connection_name_prefix]
 434             else:
 435                 port = 1521
 436             self.connection = cx_Oracle.connect(self.get_stripped_from_connection_dict('uid'), self.get_stripped_from_connection_dict('pwd'), cx_Oracle.makedsn(self.get_stripped_from_connection_dict('server'), port, self.get_stripped_from_connection_dict('database')))
 437 
 438         else:
 439             return 'Connection type "%s" specified in "%s" is unknown' % (connection_type, dict_name)
 440 
 441         return None
 442 
 443 
 444 
 445     # =============================
 446     # Handling Form Dictionaries
 447     # =============================
 448 
 449     def parse_element_key(self, key, element):
 450         key_parts = key.split('.')
 451         if element in ['form', 'buttons', 'navigation', 'filter', 'next']:
 452             key_parts.extend([u'', u'', u''])
 453         else:
 454             if len(key_parts) == 2:
 455                 key_parts.insert(0, u'')
 456             elif len(key_parts) < 2:
 457                 pass  # TODO: raise error - field not specified correctly
 458         dict_name, form_name, field_name = key_parts[:3]
 459         if not (form_name or dict_name):
 460             if self.last_form_key:
 461                 form_key = self.last_form_key
 462                 form = self.forms[form_key]
 463                 dict_name, form_name = form['dict_name'], form['form_name']
 464             else:
 465                 pass  # TODO: raise error - unspecified form
 466         elif not dict_name:
 467             if self.dict_name_stack:
 468                 dict_name = self.dict_name_stack[-1]
 469             else:
 470                 dict_name = self.request.page.page_name
 471         return dict_name, form_name, field_name
 472 
 473         
 474     def parse_connection_key(self, key):
 475         key_parts = key.split('.')
 476         key_parts.extend([u'', u''])
 477         dict_name, connection_name = key_parts[:2]
 478         if not dict_name:
 479             dict_name = self.dict_name
 480         return dict_name, connection_name
 481 
 482 
 483     def get_query_parameters(self, key, for_action = 0):
 484         # In this order:
 485         # 1. variables values
 486         # 2. form values (if not current)
 487         # 3. post values
 488         form_key = self.form_key
 489         variables = self.variables 
 490         result = []
 491         parameters = self.get_stripped_from_form_dict('%s_parameters' % key)
 492         if parameters:
 493             for par in parameters.split(','):
 494                 par = par.strip()
 495                 if variables.has_key(par):
 496                     value = variables[par]
 497                 else:
 498                     key_parts = par.strip().split('.')
 499                     if len(key_parts) == 2:
 500                         key_parts.insert(0, u'')
 501                     elif len(key_parts) < 2:
 502                         pass  # TODO: raise error - parameter not specified correctly
 503                     dict_name, form_name, field_name = key_parts[:3]
 504                     if not (form_name or dict_name):
 505                         dict_name, form_name = self.dict_name, self.form_name
 506                     elif not dict_name:
 507                         dict_name = self.dict_name
 508                     parameter_form_key = u'%s.%s' % (dict_name, form_name)
 509                     parameter_key = u'%s.%s' % (parameter_form_key, field_name)
 510                     if self.forms.has_key(parameter_form_key):
 511                         value = self.get_field_value(parameter_form_key, field_name, parameter_key, for_action = for_action)
 512                 result.append(value)
 513         return result
 514 
 515             
 516         
 517     def get_stripped_from_form_dict(self, key):
 518         return self.form['dict'].get('%s.%s' % (self.form_name, key), u'').strip('`')
 519 
 520         
 521     def get_stripped_from_connection_dict(self, key):
 522         return self.connection_dict.get('%s.%s' % (self.connection_name, key), u'').strip('`')
 523 
 524         
 525 
 526     # =============================
 527     # Error Message
 528     # =============================
 529     
 530     def error_message(self, message):
 531         formatter = self.formatter
 532         result = [ '', formatter.preformatted(True) ]
 533         message = self.wikiutil.escape(message, 1)
 534         result.append(formatter.rawHTML("Form macro error: %s" % message))
 535         result.append(formatter.preformatted(False))
 536         return u'\n'.join(result)
 537        

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2008-12-28 10:43:23, 22.1 KB) [[attachment:Form-0.10alpha.py]]
  • [get | view] (2010-01-29 18:51:04, 22.7 KB) [[attachment:Form-0.11alpha.py]]
  • [get | view] (2014-06-11 22:22:41, 22.8 KB) [[attachment:Form-0.12alpha.py]]
  • [get | view] (2008-02-04 07:06:07, 20.9 KB) [[attachment:Form-0.8alpha.py]]
  • [get | view] (2008-07-31 14:21:14, 21.8 KB) [[attachment:Form-0.9alpha.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.