Changeset 16384
- Timestamp:
- Mar 25, 2017, 12:31:47 AM (3 years ago)
- Location:
- tracformsplugin/trunk
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
tracformsplugin/trunk/setup.py
r15445 r16384 1 #!/usr/bin/env python 1 2 # -*- coding: utf-8 -*- 2 3 … … 6 7 7 8 try: 8 from trac.util.dist import get_l10n_cmdclass 9 from trac.util.dist import get_l10n_cmdclass 10 9 11 cmdclass = get_l10n_cmdclass() 10 12 if cmdclass: 11 13 extra['cmdclass'] = cmdclass 12 14 extractors = [ 13 ('**.py', 15 ('**.py', 'python', None), 14 16 ('**/templates/**.html', 'genshi', None), 15 17 ] … … 21 23 pass 22 24 23 24 25 VERSION = '0.5' 25 26 26 27 setup( 27 name ='TracForms',28 description ='Universal form provider for tickets and wiki',29 version =VERSION,28 name='TracForms', 29 description='Universal form provider for tickets and wiki', 30 version=VERSION, 30 31 author='Rich Harkins', 31 32 author_email='rich@worldsinfinite.com', 32 maintainer ='Steffen Hoffmann',33 maintainer_email ='hoff.st@web.de',34 url = 'http://trac-hacks.org/wiki/TracFormsPlugin',35 license ='GPL',36 packages =['tracforms'],37 package_data ={33 maintainer='Steffen Hoffmann', 34 maintainer_email='hoff.st@web.de', 35 url='https://trac-hacks.org/wiki/TracFormsPlugin', 36 license='GPL', 37 packages=['tracforms'], 38 package_data={ 38 39 'tracforms': [ 39 40 'htdocs/*', 'locale/*/LC_MESSAGES/*.mo', 'locale/.placeholder', … … 41 42 ] 42 43 }, 43 zip_safe =True,44 install_requires = ['Trac >= 0.11'],45 extras_require = {'Babel': 'Babel>= 0.9.5', 'Trac': 'Trac >= 0.12'},46 entry_points ={44 zip_safe=True, 45 install_requires=['Trac'], 46 extras_require={'Babel': 'Babel>= 0.9.5'}, 47 entry_points={ 47 48 'trac.plugins': [ 48 49 'tracforms.api = tracforms.api', -
tracformsplugin/trunk/tracforms/__init__.py
r9924 r16384 1 import pkg_resources 2 pkg_resources.require('Trac >= 1.0') -
tracformsplugin/trunk/tracforms/api.py
r11137 r16384 1 1 # -*- coding: utf-8 -*- 2 2 3 from genshi.builder import Markup, tag 3 from urllib import unquote_plus 4 4 5 from pkg_resources import resource_filename 5 from urllib import unquote_plus6 6 7 7 from trac.core import Component, ExtensionPoint, Interface, implements 8 8 from trac.perm import IPermissionRequestor 9 from trac.resource import IResourceManager, Resource , ResourceNotFound, \9 from trac.resource import IResourceManager, ResourceNotFound, \ 10 10 get_resource_name, get_resource_shortname, \ 11 11 get_resource_url 12 13 # Import i18n methods. Fallback modules maintain compatibility to Trac 0.11 14 # by keeping Babel optional here. 15 try: 16 from trac.util.translation import domain_functions 17 add_domain, _, tag_ = \ 18 domain_functions('tracforms', ('add_domain', '_', 'tag_')) 19 dgettext = None 20 except ImportError: 21 from genshi.builder import tag as tag_ 22 from trac.util.translation import gettext 23 _ = gettext 24 def add_domain(a,b,c=None): 25 pass 26 def dgettext(domain, string, **kwargs): 27 return safefmt(string, kwargs) 28 def safefmt(string, kwargs): 29 if kwargs: 30 try: 31 return string % kwargs 32 except KeyError: 33 pass 34 return string 35 12 from trac.util.html import Markup, tag 13 from trac.util.translation import domain_functions 36 14 from trac.web import IRequestHandler 37 from trac.web.api import HTTPBadRequest, HTTPUnauthorized 38 39 # Import AccountManagerPlugin methods, if plugin is installed. 15 from trac.web.api import HTTPBadRequest 16 40 17 try: 41 18 from acct_mgr.api import IPasswordStore 42 can_check_user = True43 19 except ImportError: 44 20 can_check_user = False 45 21 else: 22 can_check_user = True 46 23 from compat import json 24 25 add_domain, _, tag_ = \ 26 domain_functions('tracforms', ('add_domain', '_', 'tag_')) 27 dgettext = None 47 28 48 29 … … 64 45 def form_deleted(form): 65 46 """Called when a form is deleted.""" 66 # DEVEL: not implemented yet47 # DEVEL: not implemented yet 67 48 68 49 … … 84 65 85 66 def save_tracform(self, src, state, updater, 86 87 67 base_version=None, keep_history=False, 68 track_fields=False, cursor=None): 88 69 pass 89 70 … … 95 76 96 77 def reset_tracform(self, src, field=None, author=None, step=0, 97 78 cursor=None): 98 79 pass 99 80 … … 106 87 def builder(fn): 107 88 return tracob_first(fn, default) 89 108 90 return builder 109 91 else: … … 116 98 else: 117 99 return default 100 118 101 wrapper.__name__ = fn.__name__ 119 102 wrapper.__doc__ = fn.__doc__ … … 203 186 tag.a(parent_name, href=parent_url) or parent_name 204 187 # DEVEL: resource description not implemented yet 205 # if format == 'summary':188 # if format == 'summary': 206 189 # return Form(self.env, resource).description 207 190 if resource.id: … … 211 194 # TRANSLATOR: Most verbose title, i.e. for form history page 212 195 return tag(Markup(_("Form %(form_id)s (in %(parent)s)", 213 form_id=resource.id, parent=parent)))196 form_id=resource.id, parent=parent))) 214 197 else: 215 198 # TRANSLATOR: Title printed i.e. in form select page … … 220 203 def get_resource_url(self, resource, href, **kwargs): 221 204 # use parent's url instead 222 return get_resource_url(self.env, resource.parent, href) 205 return get_resource_url(self.env, resource.parent, href) 223 206 224 207 def resource_exists(self, resource): 225 208 try: 226 209 if get_tracform_meta(resource.id)[1] is not None: 227 return True210 return True 228 211 except ResourceNotFound: 229 212 return False … … 258 241 backpath = args.pop('__backpath__', None) 259 242 context = json.loads(unquote_plus( 260 243 args.pop('__context__', '[null, null, null]'))) 261 244 if None in context: 262 245 # TRANSLATOR: HTTP error message … … 279 262 result = json.dumps(args, separators=(',', ':')) 280 263 self.save_tracform(context, result, who, basever, 281 282 264 keep_history=keep_history, 265 track_fields=track_fields) 283 266 buffer = 'OK' 284 267 if backpath is not None: … … 302 285 req.end_headers() 303 286 req.write(buffer) 304 -
tracformsplugin/trunk/tracforms/compat.py
r10484 r16384 1 1 # -*- coding: utf-8 -*- 2 2 3 # 2011 Steffen Hoffmann 4 5 """Various classes and functions to provide backwards-compatibility with 6 previous versions of Python from 2.4 onward. 7 """ 8 9 # json was introduced in 2.6, use simplejson for older versions 10 # parse_qs was copied to urlparse and deprecated in cgi in 2.6 11 import sys 12 if sys.version_info[0] == 2 and sys.version_info[1] > 5: 3 try: 13 4 import json 14 from urlparse import parse_qs 15 else: 5 except ImportError: 16 6 import simplejson as json 17 from cgi import parse_qs18 19 # A Trac issue rather than a Python one:20 # Provide `resource_exists`, that has been backported to Trac 0.11.8 only.21 try:22 from trac.resource import resource_exists23 except ImportError:24 from trac.resource import ResourceSystem25 def resource_exists(env, resource):26 """Checks for resource existence without actually instantiating a27 model.28 29 :return: `True` if the resource exists, `False` if it doesn't30 and `None` in case no conclusion could be made (i.e. when31 `IResourceManager.resource_exists` is not implemented).32 """33 manager = ResourceSystem(env).get_resource_manager(resource.realm)34 if manager and hasattr(manager, 'resource_exists'):35 return manager.resource_exists(resource)36 elif resource.id is None:37 return False38 -
tracformsplugin/trunk/tracforms/environment.py
r10044 r16384 42 42 43 43 def __init__(self, base=None, prefixes=()): 44 super(FormEnvironment, self).__init__() 44 45 if base is not None: 45 46 self.update(base) … … 47 48 self.prefixes = prefixes + ('',) 48 49 49 def __getitem__(self, key, NOT_FOUND=KeyError):50 obj = self.get(key, NOT_FOUND)51 if obj is NOT_FOUND:50 def __getitem__(self, key, default=KeyError): 51 obj = self.get(key, default) 52 if obj is default: 52 53 raise KeyError(key) 53 54 else: … … 56 57 def get(self, search, default=None, singleton=True, all=False): 57 58 values = tuple(dict.__getitem__(self, key) 58 59 for key in sorted(self.keyset(search, all))) 59 60 if singleton: 60 61 if not values: … … 93 94 94 95 _sorted = None 96 95 97 @property 96 98 def sorted_keys(self): … … 108 110 for key in keys: 109 111 self[key] = tuple(value) 110 -
tracformsplugin/trunk/tracforms/errors.py
r10079 r16384 33 33 34 34 message = _("ERROR: No TracForms command '%r'") 35 -
tracformsplugin/trunk/tracforms/formdb.py
r11137 r16384 1 1 # -*- coding: utf-8 -*- 2 2 3 #import copy4 3 import re 5 4 import time 6 import u nittest5 import urlparse 7 6 8 7 from trac.config import BoolOption, ListOption, Option 9 from trac.core import Component,implements8 from trac.core import implements 10 9 from trac.db import Column, DatabaseManager, Index, Table 11 from trac.resource import Resource 10 from trac.resource import Resource, resource_exists 12 11 from trac.search.api import search_to_sql 13 12 from trac.web.chrome import Chrome 14 13 15 14 from api import IFormDBObserver, _ 16 from compat import json , parse_qs, resource_exists15 from compat import json 17 16 from tracdb import DBComponent 18 17 from util import is_number, parse_history, resource_from_page, xml_unescape … … 91 90 cursor = db.cursor() 92 91 sql = """ 93 SELECT id, 94 realm, 95 resource_id, 96 subcontext, 97 author, 98 time, 99 keep_history, 100 track_fields 101 FROM forms 102 """ 92 SELECT id, realm, resource_id, subcontext, author, time, 93 keep_history, track_fields 94 FROM forms 95 """ 103 96 if not is_number(src): 104 97 sql += """ … … 119 112 else: 120 113 form_id = src 121 src = tuple([src], )114 src = tuple([src], ) 122 115 cursor.execute(sql, src) 123 116 return cursor.fetchone() or \ … … 142 135 WHERE id=%s 143 136 """ 144 src = tuple([src], )137 src = tuple([src], ) 145 138 cursor.execute(sql, src) 146 139 row = cursor.fetchone() … … 152 145 return True 153 146 else: 154 if not path_or_realmin self.parent_blacklisted.keys():147 if path_or_realm not in self.parent_blacklisted.keys(): 155 148 return True 156 149 else: … … 162 155 163 156 def save_tracform(self, src, state, author, 164 165 157 base_version=None, keep_history=False, 158 track_fields=False, db=None): 166 159 (form_id, realm, resource_id, subcontext, last_updater, 167 168 160 last_updated_on, form_keep_history, 161 form_track_fields) = self.get_tracform_meta(src, db=db) 169 162 170 163 if form_keep_history is not None: … … 178 171 179 172 if ((base_version is None and last_updated_on is None) or 180 (base_version == last_updated_on)):173 (base_version == last_updated_on)): 181 174 if state != old_state and self.save_tracform_allowed(realm, 182 175 resource_id): … … 191 184 VALUES (%s, %s, %s, %s, %s, %s) 192 185 """, (realm, resource_id, subcontext, 193 state, author, updated_on))194 form_id = db.get_last_id(cursor, 'forms') 186 state, author, updated_on)) 187 form_id = db.get_last_id(cursor, 'forms') 195 188 else: 196 189 cursor.execute(""" … … 207 200 VALUES (%s, %s, %s, %s) 208 201 """, (form_id, last_updated_on, 209 last_updater, old_state))202 last_updater, old_state)) 210 203 if track_fields: 211 204 # Break down old version and new version. … … 245 238 author = last_updater 246 239 return ((form_id, realm, resource_id, subcontext, state, 247 author, updated_on),240 author, updated_on), 248 241 (form_id, realm, resource_id, subcontext, old_state, 249 last_updater, last_updated_on))242 last_updater, last_updated_on)) 250 243 else: 251 244 raise ValueError(_("Conflict")) … … 324 317 now = int(time.time()) 325 318 author, updated_on, old_state = self.get_tracform_history( 326 319 form_id, db=db)[0] or \ 327 320 (author, now, '{}') 328 321 if updated_on == now: … … 415 408 # A reference is enough, as long as we ensure strictly read-only 416 409 # access and short lifetime of the reference. Change later, if needed. 417 # users = copy.deepcopy(self.known_users)410 # users = copy.deepcopy(self.known_users) 418 411 users = self.known_users 419 412 return users … … 454 447 return users 455 448 456 ##########################################################################457 449 # TracForms schemas 458 450 # Hint: See older versions of this file for the original SQL statements. 459 451 # Most of them have been rewritten to imrove compatibility with Trac. 460 452 461 # def dbschema_2008_06_14_0000(self, cursor):453 # def dbschema_2008_06_14_0000(self, cursor): 462 454 # """This was a simple test for the schema base class.""" 463 455 … … 477 469 Column('old_states')] 478 470 ] 479 db_connector , _ = DatabaseManager(env)._get_connector()471 db_connector = DatabaseManager(env).get_connector()[0] 480 472 for table in tables: 481 473 for stmt in db_connector.to_sql(table): … … 558 550 Index(['tracform_id', 'field'], unique=True) 559 551 ] 560 db_connector , _ = DatabaseManager(env)._get_connector()552 db_connector = DatabaseManager(env).get_connector()[0] 561 553 for stmt in db_connector.to_sql(table): 562 554 cursor.execute(stmt) … … 566 558 567 559 Migrate to slicker named major tables and associated indexes too. 568 """ 560 """ 569 561 table = Table('forms', key='id')[ 570 562 Column('id', auto_increment=True), … … 579 571 Index(['time']) 580 572 ] 581 db_connector , _ = DatabaseManager(env)._get_connector()573 db_connector = DatabaseManager(env).get_connector()[0] 582 574 for stmt in db_connector.to_sql(table): 583 575 cursor.execute(stmt) … … 607 599 values = form.values() 608 600 sql = "INSERT INTO forms (" + ", ".join(fields) + \ 609 ") VALUES (" + ", ".join(["%s" for I in xrange(len(fields))]) \ 610 + ")" 601 ") VALUES (" + ", ".join( 602 ["%s" for I in xrange(len(fields))]) \ 603 + ")" 611 604 cursor.execute(sql, values) 612 605 … … 649 642 for row in history: 650 643 sql = "UPDATE forms_history SET old_state=%s " + \ 651 "WHERE id=%s AND time=%s"644 "WHERE id=%s AND time=%s" 652 645 cursor.execute(sql, (row['old_state'], row['id'], row['time'])) 653 646 … … 698 691 699 692 def db14(self, env, cursor): 700 """Split context into proper Trac resource descriptors.""" 693 """Split context into proper Trac resource descriptors.""" 701 694 cursor.execute(""" 702 695 CREATE TABLE forms_old … … 721 714 Index(['time']) 722 715 ] 723 db_connector , _ = DatabaseManager(env)._get_connector()716 db_connector = DatabaseManager(env).get_connector()[0] 724 717 for stmt in db_connector.to_sql(table): 725 718 cursor.execute(stmt) … … 742 735 values = form.values() 743 736 sql = "INSERT INTO forms (" + ", ".join(fields) + \ 744 ") VALUES (" + ", ".join(["%s" for I in xrange(len(fields))]) \ 745 + ")" 737 ") VALUES (" + ", ".join( 738 ["%s" for I in xrange(len(fields))]) \ 739 + ")" 746 740 cursor.execute(sql, values) 747 741 … … 764 758 return Chrome(env).format_author(req, author) 765 759 760 766 761 def _url_to_json(state_url): 767 762 """Convert urlencoded state serial to JSON state serial.""" 768 state = parse_qs(state_url)763 state = urlparse.parse_qs(state_url) 769 764 for name, value in state.iteritems(): 770 765 if isinstance(value, (list, tuple)): … … 774 769 state[name] = xml_unescape(value) 775 770 return json.dumps(state, separators=(',', ':')) 771 776 772 777 773 def _context_to_resource(env, context): … … 806 802 realm = '' 807 803 return realm, resource_id, subcontext 808 809 810 if __name__ == '__main__':811 from trac.test import EnvironmentStub812 env = EnvironmentStub()813 db = FormDBComponent(env)814 db.upgrade_environment(None)815 updated_on_1 = db.save_tracform('/', 'hello world', 'me')[0][4]816 assert db.get_tracform_state('/') == 'hello world'817 updated_on_2 = \818 db.save_tracform('/', 'ack oop', 'you', updated_on_1)[0][4]819 assert db.get_tracform_state('/') == 'ack oop'820 assert tuple(db.get_tracform_history('/')) == (821 ('me', updated_on_1, 'hello world'),822 )823 -
tracformsplugin/trunk/tracforms/htdocs/tracforms.css
r10123 r16384 8 8 margin-right: auto; 9 9 } 10 10 11 #content.tracforms #form { 11 12 background: #eef; … … 23 24 width: 100%; 24 25 } 26 25 27 #form table.properties td { 26 28 width: 40%; 27 29 } 30 28 31 #form table.properties th { 29 32 width: 20%; 30 33 } 34 31 35 #form table.properties td, #form table.properties th { 32 36 font-size: 80%; … … 35 39 vertical-align: top; 36 40 } 41 37 42 #form table.properties .author, #form table.properties .date { 38 43 color: #990; 39 44 } 40 45 41 #changelog { border: 1px outset #996; padding: 1em } 46 #changelog { 47 border: 1px outset #996; 48 padding: 1em 49 } 50 42 51 #changelog h3, #ticketchange h3 { 43 52 border-bottom: 1px solid #d7d7d7; … … 46 55 font-weight: normal; 47 56 } 48 #changelog .changes { list-style: square; margin-left: 2em; padding: 0 }49 57 58 #changelog .changes { 59 list-style: square; 60 margin-left: 2em; 61 padding: 0 62 } 63 -
tracformsplugin/trunk/tracforms/macros.py
r11283 r16384 6 6 import time 7 7 import traceback 8 9 8 from math import modf 10 9 10 from api import FormDBUser, PasswordStoreUser, _ 11 from compat import json 12 from errors import FormError, FormTooManyValuesError 13 from formdb import format_author 11 14 from trac.util.datefmt import format_datetime 12 15 from trac.util.text import to_unicode 16 from trac.wiki.formatter import Formatter 13 17 from trac.wiki.macros import WikiMacroBase 14 from trac.wiki.formatter import Formatter15 16 from api import FormDBUser, PasswordStoreUser, _17 from compat import json18 from environment import FormEnvironment19 from errors import FormError, FormTooManyValuesError20 from formdb import format_author21 18 from util import resource_from_page, xml_escape 22 19 … … 24 21 argstrRE = re.compile('%(.*?)%') 25 22 tfRE = re.compile('\[' 26 'tf(?:\.([a-zA-Z_]+?))?'27 '(?::([^\[\]]*?))?'28 '\]')23 'tf(?:\.([a-zA-Z_]+?))?' 24 '(?::([^\[\]]*?))?' 25 '\]') 29 26 chartrans = { 30 u'"' 31 u'\t' 32 u'\n' 33 u'\r' 34 27 u'"': u'"', 28 u'\t': u'	', 29 u'\n': u'
', 30 u'\r': u'
', 31 } 35 32 kwtrans = { 36 'class' 37 'id' 38 'mode' 39 'title' 40 33 'class': '_class', 34 'id': '_id', 35 'mode': '_mode', 36 'title': '_title', 37 } 41 38 42 39 … … 44 41 """Docs for TracForms macro...""" 45 42 46 def expand_macro(self, formatter, name, args):47 processor = FormProcessor(self, formatter, name, args)43 def expand_macro(self, formatter, name, content, args=None): 44 processor = FormProcessor(self, formatter, name, content) 48 45 return processor.execute() 49 46 … … 72 69 self.args = args 73 70 self.name = name 71 self.env = None 72 self.context = None 73 self.subform = None 74 self.updated = None 75 self.form_realm = None 76 self.form_resource_id = None 77 self.form_subcontext = None 78 self.form_updater = None 79 self.form_updated_on = None 80 self.form_keep_history = None 81 self.form_track_fields = None 82 self.form_id = None 74 83 75 84 def execute(self): 76 85 formatter = self.formatter 77 86 args = self.args 78 name = self.name79 87 80 88 # Look in the formatter req object for evidence we are executing. … … 113 121 except FormError, e: 114 122 errors.append(str(e)) 115 except Exception , e:123 except Exception: 116 124 errors.append(traceback.format_exc()) 117 125 else: … … 123 131 # Determine our destination context and load the current state. 124 132 self.context = tuple([realm, resource_id, 125 self.subcontext is not None and \133 self.subcontext is not None and 126 134 self.subcontext or '']) 127 135 state = self.macro.get_tracform_state(self.context) … … 136 144 self.sorted_env = None 137 145 (self.form_id, self.form_realm, self.form_resource_id, 138 139 146 self.form_subcontext, self.form_updater, self.form_updated_on, 147 self.form_keep_history, self.form_track_fields) = \ 140 148 self.macro.get_tracform_meta(self.context) 141 149 self.form_id = self.form_id is not None and int(self.form_id) or None … … 170 178 dest = self.formatter.req.href('/form/update') 171 179 yield ('<FORM class="printableform" ' + 172 173 (form_cssid is not None174 175 176 (form_name is not None177 178 179 (form_class is not None180 181 182 180 'method="POST" action=%r' % str(dest) + 181 (form_cssid is not None 182 and ' id="%s"' % form_cssid 183 or '') + 184 (form_name is not None 185 and ' name="%s"' % form_name 186 or '') + 187 (form_class is not None 188 and ' class="%s"' % form_class 189 or '') + 190 '>') 183 191 yield text 184 192 if self.allow_submit: … … 205 213 self.context, separators=(',', ':')) 206 214 yield '<INPUT type="hidden" ' + \ 207 'name="__context__" value=%r>' % context215 'name="__context__" value=%r>' % context 208 216 backpath = self.formatter.req.href(self.formatter.req.path_info) 209 217 yield '<INPUT type="hidden" ' \ 210 218 'name="__backpath__" value=%s>' % str(backpath) 211 219 form_token = self.formatter.req.form_token 212 220 yield '<INPUT type="hidden" ' \ 213 221 'name="__FORM_TOKEN" value=%r>' % str(form_token) 214 222 yield '</FORM>' 215 223 else: … … 226 234 arg = (str(float(arg))) 227 235 yield arg 228 except ValueError , e:236 except ValueError: 229 237 name, value = (arg[1:].split('=', 1) + [True])[:2] 230 238 kw[str(kwtrans.get(name, name))] = value … … 291 299 return tuple(value) 292 300 else: 293 return (value,)301 return value, 294 302 else: 295 303 if isinstance(value, (list, tuple)): … … 360 368 361 369 def cmd_submit_name(self, name): 362 self.submit_name 370 self.submit_name = name 363 371 364 372 def cmd_setenv(self, name, value): … … 370 378 self.sorted_env = None 371 379 372 def cmd_operation( _self, _name, _op, *_args, **_kw):380 def cmd_operation(self, _name, _op, *_args, **_kw): 373 381 if _op in ('is', 'as'): 374 382 _op, _args = _args[0], _args[1:] 375 op = getattr( _self, 'op_' + _op, None)383 op = getattr(self, 'op_' + _op, None) 376 384 if op is None: 377 385 raise FormTooManyValuesError(str(_name)) 386 378 387 def partial(*_newargs, **_newkw): 379 388 if _kw or _newkw: … … 383 392 kw = {} 384 393 return op(*(_newargs + _args), **kw) 385 _self.env['op:' + _name] = partial 394 395 self.env['op:' + _name] = partial 386 396 387 397 def wiki(self, text): 388 398 out = StringIO.StringIO() 389 Formatter(self.formatter.env, self.formatter.context).format(text, out) 399 Formatter(self.formatter.env, self.formatter.context).format(text, 400 out) 390 401 return out.getvalue() 391 402 … … 414 425 except FormError, e: 415 426 return '<PRE>' + str(e) + '</PRE>' 416 except Exception , e:427 except Exception: 417 428 return '<PRE>' + traceback.format_exc() + '</PRE>' 418 429 … … 450 461 (readonly is True and ' readonly="readonly"' or '') + 451 462 (content is not None and (' value="%s"' 452 463 % xml_escape(content)) or '') + 453 464 '>') 454 465 … … 483 494 _title = kw.pop('_title', None) 484 495 current = self.get_field(field) 485 result = [] 486 result.append("<SELECT name='%s'" % field + 487 (_id is not None and ' id="%s"' % _id or '') + 488 (_class is not None and ' class="%s"' % _class or '') + 489 (_title is not None and ' title="%s"' % _title or '') + 490 '>') 496 result = ["<SELECT name='%s'" % field + 497 (_id is not None and ' id="%s"' % _id or '') + 498 (_class is not None and ' class="%s"' % _class or '') + 499 (_title is not None and ' title="%s"' % _title or '') + 500 '>'] 491 501 for value in values: 492 502 value, label = (value.split('//', 1) + [value])[:2] 493 503 result += ("<OPTION value='%s'" % value.strip() + 494 (current == value and ' selected' or '') +495 '>' + label.strip() + '</OPTION>')504 (current == value and ' selected' or '') + 505 '>' + label.strip() + '</OPTION>') 496 506 result.append("</SELECT>") 497 507 return ''.join(result) … … 505 515 if _mode == 'ro' or (_mode == 'once' and current is not None): 506 516 readonly = True 507 return ((_mode != 'rd' and "<TEXTAREA name='%s'" % field or \517 return ((_mode != 'rd' and "<TEXTAREA name='%s'" % field or 508 518 "<TEXTAREA ") + 509 519 (cols is not None and ' cols="%s"' % cols or '') + … … 522 532 # TRANSLATOR: Default updater name 523 533 who = self.macro.get_tracform_fieldinfo( 524 525 534 self.form_id is not None and self.form_id or self.context, 535 field)[0] or _("unknown") 526 536 return format_author(self.formatter.env, self.formatter.req, who) 527 537 528 538 def op_when(self, field, format='%m/%d/%Y %H:%M:%S'): 529 539 when = self.macro.get_tracform_fieldinfo( 530 self.form_id is not None and self.form_id or \540 self.form_id is not None and self.form_id or 531 541 self.context, field)[1] 532 542 return (when is not None and format_datetime( 533 543 when, format=str(format)) or _("unknown")) 534 544 535 545 def op_id(self): … … 556 566 values 557 567 """ 558 # #msum() from http://code.activestate.com/recipes/393090/ (r5)568 # msum() from http://code.activestate.com/recipes/393090/ (r5) 559 569 # Depends on IEEE-754 arithmetic guarantees. 560 partials = [] 570 partials = [] # sorted, non-overlapping partial sums 561 571 for x in values: 562 572 x = float(x) … … 629 639 return ''.join(result) 630 640 641 631 642 def _xml_escape(text): 632 643 """Escape literal '&' first to prevent evaluation of valid HTML escape … … 638 649 text = text.replace(k, chartrans[k]) 639 650 return text 640 -
tracformsplugin/trunk/tracforms/model.py
r10211 r16384 32 32 self.resource = form_resource_or_parent_realm 33 33 parent = self.resource.parent 34 if self.siblings == []:34 if not self.siblings: 35 35 self._get_siblings(parent.realm, parent.id) 36 36 else: … … 40 40 else: 41 41 self.id = None 42 if self.id is not None and (parent_realm is None or \ 43 parent_id is None or subcontext is None): 42 if self.id is not None and \ 43 (parent_realm is None or parent_id is None or 44 subcontext is None): 44 45 # get complete context, required as resource parent 45 46 ctxt = self.forms.get_tracform_meta(self.id)[1:4] … … 48 49 self.subcontext = ctxt[2] 49 50 elif isinstance(parent_realm, basestring) and \ 50 parent_id is not None and self.id is None:51 parent_id is not None and self.id is None: 51 52 # find form(s), if parent descriptors are available 52 53 if subcontext is not None: … … 55 56 self._get_siblings(parent_realm, parent_id) 56 57 if isinstance(parent_realm, basestring) and \ 57 parent_id is not None:58 parent_id is not None: 58 59 self.resource = Resource(parent_realm, parent_id 59 ).child('form', self.id, version)60 ).child('form', self.id, version) 60 61 else: 61 62 raise ResourceNotFound( … … 64 65 """, realm=parent_realm, parent_id=parent_id), 65 66 subcontext and _("with subcontext %(subcontext)s", 66 subcontext=subcontext) or '')67 subcontext=subcontext) or '') 67 68 68 69 def _get_siblings(self, parent_realm, parent_id): … … 78 79 def has_data(self): 79 80 """Return whether there is any form content stored.""" 80 return (self.forms.get_tracform_fields(self.id) is not None or \81 self.forms.get_tracform_history(self.id) is not None or \81 return (self.forms.get_tracform_fields(self.id) is not None or 82 self.forms.get_tracform_history(self.id) is not None or 82 83 self.forms.get_tracform_state(self.id) not in [None, '{}']) 83 -
tracformsplugin/trunk/tracforms/templates/form.html
r11561 r16384 4 4 <html xmlns="http://www.w3.org/1999/xhtml" 5 5 xmlns:py="http://genshi.edgewall.org/" 6 xmlns:xi="http://www.w3.org/2001/XInclude" 6 xmlns:xi="http://www.w3.org/2001/XInclude" 7 7 xmlns:i18n="http://genshi.edgewall.org/i18n" 8 8 i18n:domain="tracforms"> -
tracformsplugin/trunk/tracforms/templates/switch.html
r10487 r16384 4 4 <html xmlns="http://www.w3.org/1999/xhtml" 5 5 xmlns:py="http://genshi.edgewall.org/" 6 xmlns:xi="http://www.w3.org/2001/XInclude" 6 xmlns:xi="http://www.w3.org/2001/XInclude" 7 7 xmlns:i18n="http://genshi.edgewall.org/i18n" 8 8 i18n:domain="tracforms"> -
tracformsplugin/trunk/tracforms/tracdb.py
r10211 r16384 90 90 if installed is None: 91 91 self.log.info( 92 93 db_connector , _ = DatabaseManager(self.env)._get_connector()92 'Installing TracForm plugin schema %s' % db_version) 93 db_connector = DatabaseManager(self.env).get_connector()[0] 94 94 db = self._get_db(db) 95 95 cursor = db.cursor() … … 117 117 118 118 def get_installed_version(self, db): 119 version = self.get_system_value(db, self.plugin_name + '_version' , -1)119 version = self.get_system_value(db, self.plugin_name + '_version') 120 120 if version is None: 121 121 # check for old naming schema 122 oldversion = self.get_system_value( 123 db, 'TracFormDBComponent:version', -1)122 oldversion = self.get_system_value(db, 123 'TracFormDBComponent:version') 124 124 version = _db_oldversion_dict.get(oldversion) 125 125 if version is None: … … 144 144 # Trac db 'system' table management methods for TracForms entry 145 145 146 def get_system_value(self, db, key , default=None):146 def get_system_value(self, db, key): 147 147 db = self._get_db(db) 148 148 cursor = db.cursor() … … 156 156 cursor = db.cursor() 157 157 cursor.execute( 158 158 "UPDATE system SET value=%s WHERE name=%s", (value, key)) 159 159 cursor.execute("SELECT value FROM system WHERE name=%s", (key,)) 160 160 if not cursor.fetchone(): … … 173 173 'dbschema_2008_06_15_0004': 4, 'dbschema_2008_06_15_0010': 10, 174 174 'dbschema_2008_06_15_0011': 11, 'dbschema_2008_06_15_0012': 12, 175 } 176 175 } -
tracformsplugin/trunk/tracforms/util.py
r11561 r16384 5 5 import htmlentitydefs 6 6 import re 7 import unittest7 import codecs 8 8 9 from codecs import getencoder 10 from genshi.builder import Markup, tag 9 from trac.resource import ResourceSystem 10 from trac.util.html import Markup, tag 11 from trac.util.text import to_unicode 11 12 12 from trac.resource import ResourceSystem13 from trac.util.text import to_unicode13 from api import _ 14 from compat import json 14 15 15 from api import _ 16 from compat import json 17 18 __all__ = ['parse_history', 'resource_from_page', 19 'xml_escape', 'xml_unescape'] 16 __all__ = ['parse_history', 'resource_from_page', 'xml_escape', 17 'xml_unescape'] 20 18 21 19 … … 26 24 a dict of field change lists for stepwise form reset. 27 25 """ 28 field history = {}26 field_history = {} 29 27 history = [] 30 if not fieldwise ==False:31 def _add_change(field history, field, author, time, old, new):32 if field not in field history.keys():33 field history[field] = [{'author': author, 'time': time,28 if fieldwise is not False: 29 def _add_change(field_history, field, author, time, old, new): 30 if field not in field_history.keys(): 31 field_history[field] = [{'author': author, 'time': time, 34 32 'old': old, 'new': new}] 35 33 else: 36 field history[field].append({'author': author, 'time': time,34 field_history[field].append({'author': author, 'time': time, 37 35 'old': old, 'new': new}) 38 return field history36 return field_history 39 37 40 38 new_fields = None 39 last_author = last_change = None 41 40 for changeset in changes: 42 41 # break down old and new version … … 57 56 new_value = new_fields.get(field) 58 57 if new_value != old_value: 59 if fieldwise ==False:58 if fieldwise is False: 60 59 change = _render_change(old_value, new_value) 61 60 if change is not None: 62 61 updated_fields[field] = change 63 62 else: 64 field history = _add_change(fieldhistory, field,65 last_author, last_change,66 old_value, new_value)63 field_history = _add_change(field_history, field, 64 last_author, last_change, 65 old_value, new_value) 67 66 for field in new_fields: 68 67 if old_fields.get(field) is None: 69 if fieldwise ==False:68 if fieldwise is False: 70 69 change = _render_change(None, new_fields[field]) 71 70 if change is not None: 72 71 updated_fields[field] = change 73 72 else: 74 field history = _add_change(fieldhistory, field,75 last_author, last_change,76 None, new_fields[field])73 field_history = _add_change(field_history, field, 74 last_author, last_change, 75 None, new_fields[field]) 77 76 new_fields = old_fields 78 77 history.append({'author': last_author, … … 81 80 last_author = changeset['author'] 82 81 last_change = changeset['time'] 83 return fieldwise == False and history or fieldhistory 82 return fieldwise is False and history or field_history 83 84 84 85 85 def _render_change(old, new): … … 103 103 return rendered 104 104 105 105 106 # adapted from code published by Daniel Goldberg on 09-Dec-2008 at 106 107 # http://stackoverflow.com/questions/354038 … … 112 113 return False 113 114 115 114 116 # code from an article published by Uche Ogbuji on 15-Jun-2005 at 115 117 # http://www.xml.com/pub/a/2005/06/15/py-xml.html 116 118 def xml_escape(text): 117 enc = getencoder('us-ascii')119 enc = codecs.getencoder('us-ascii') 118 120 return enc(to_unicode(text), 'xmlcharrefreplace')[0] 121 119 122 120 123 # adapted from code published by John J. Lee on 06-Jun-2007 at … … 123 126 unichresc_RE = re.compile(r'&#?[A-Za-z0-9]+?;') 124 127 128 125 129 def xml_unescape(text): 126 130 return unichresc_RE.sub(_replace_entities, text) 131 127 132 128 133 def _unescape_charref(ref): … … 134 139 base = 16 135 140 return unichr(int(name, base)) 141 136 142 137 143 def _replace_entities(match): … … 145 151 repl = ent 146 152 return repl 153 147 154 148 155 def resource_from_page(env, page): … … 158 165 else: 159 166 return page, None 160 161 162 class UnescapeTests(unittest.TestCase):163 164 def test_unescape_charref(self):165 self.assertEqual(unescape_charref(u"&"), u"&")166 self.assertEqual(unescape_charref(u"—"), u"\N{EM DASH}")167 self.assertEqual(unescape_charref(u"—"), u"\N{EM DASH}")168 169 def test_unescape(self):170 self.assertEqual(unescape(u"& < — — —"),171 u"& < %s %s %s" % tuple(u"\N{EM DASH}"*3)172 )173 self.assertEqual(unescape(u"&a&"), u"&a&")174 self.assertEqual(unescape(u"a&"), u"a&")175 self.assertEqual(unescape(u"&nonexistent;"), u"&nonexistent;")176 177 # unittest.main()178 -
tracformsplugin/trunk/tracforms/web_ui.py
r15447 r16384 2 2 3 3 import re 4 5 from genshi.builder import Markup, tag6 4 from pkg_resources import resource_filename 7 5 … … 11 9 from trac.search.api import ISearchSource, shorten_result 12 10 from trac.util.datefmt import to_datetime 11 from trac.util.html import Markup, tag 13 12 from trac.web.api import IRequestFilter, IRequestHandler 14 13 from trac.web.chrome import ITemplateProvider, add_ctxtnav, add_stylesheet … … 20 19 from util import parse_history, resource_from_page 21 20 22 tf pageRE= re.compile('/form(/\d+|$)')21 tf_page_re = re.compile('/form(/\d+|$)') 23 22 24 23 … … 44 43 realm, resource_id = resource_from_page(env, page) 45 44 # break (recursive) search for form in forms realm 46 if tf pageRE.match(page) ==None and resource_id is not None:45 if tf_page_re.match(page) is None and resource_id is not None: 47 46 if page == '/wiki' or page == '/wiki/': 48 47 page = '/wiki/WikiStart' … … 51 50 if len(form.siblings) == 0: 52 51 # no form record found for this parent resource 53 return (template, data, content_type)52 return template, data, content_type 54 53 elif form.resource.id is not None: 55 54 # single form record found … … 68 67 resource_id=parent.id) 69 68 add_ctxtnav(req, _("Back to forms list"), href=href) 70 return (template, data, content_type)69 return template, data, content_type 71 70 72 71 # ITemplateProvider methods … … 108 107 109 108 if req.args.get('action') == 'select': 110 realm =req.args.get('realm')111 resource_id =req.args.get('resource_id')109 realm = req.args.get('realm') 110 resource_id = req.args.get('resource_id') 112 111 if realm is not None and resource_id is not None: 113 112 form = Form(env, realm, resource_id) … … 139 138 # show reset button in case of existing data and proper permission 140 139 data['allow_reset'] = req.perm(form.resource) \ 141 .has_permission('FORM_RESET') and form.has_data 140 .has_permission( 141 'FORM_RESET') and form.has_data 142 142 add_stylesheet(req, 'tracforms/tracforms.css') 143 143 return 'form.html', data, None 144 144 145 145 def _do_switch(self, env, req, form): 146 data = {'_dgettext': dgettext} 147 data['page_title'] = get_resource_description(env, form.resource, 148 href=req.href) 149 data['title'] = get_resource_shortname(env, form.resource) 150 data['siblings'] = [] 146 data = { 147 '_dgettext': dgettext, 148 'page_title': get_resource_description(env, form.resource, 149 href=req.href), 150 'title': get_resource_shortname(env, form.resource), 151 'siblings': [] 152 } 151 153 for sibling in form.siblings: 152 154 form_id = tag.strong(tag.a( 153 154 155 _("Form %(form_id)s", form_id=sibling[0]), 156 href=req.href.form(sibling[0]))) 155 157 if sibling[1] == '': 156 158 data['siblings'].append(form_id) … … 158 160 # TRANSLATOR: Form list entry for form select page 159 161 data['siblings'].append(tag(Markup(_( 160 161 form_id=form_id, subcontext =sibling[1]))))162 "%(form_id)s (subcontext = '%(subcontext)s')", 163 form_id=form_id, subcontext=sibling[1])))) 162 164 add_stylesheet(req, 'tracforms/tracforms.css') 163 165 return 'switch.html', data, None … … 165 167 def _do_reset(self, env, req, form): 166 168 author = req.authname 169 step = None 167 170 if 'rewind' in req.args: 168 171 step = -1 … … 207 210 208 211 def get_search_results(self, req, terms, filters): 209 if not 'form'in filters:212 if 'form' not in filters: 210 213 return 211 214 env = self.env 212 215 results = self.search_tracforms(env, terms) 213 216 214 for id , realm, parent, subctxt, state, author, updated_on in results:217 for id_, realm, parent, subctxt, state, author, updated_on in results: 215 218 # DEVEL: support for handling form revisions not implemented yet 216 # form = Form(env, realm, parent, subctxt, id, version)217 form = Form(env, realm, parent, subctxt, id )219 # form = Form(env, realm, parent, subctxt, id, version) 220 form = Form(env, realm, parent, subctxt, id_) 218 221 if 'FORM_VIEW' in req.perm(form.resource): 219 222 form = form.resource … … 232 235 fields.append(''.join([name, delimiter, value])) 233 236 return '; '.join(fields) 234
Note: See TracChangeset
for help on using the changeset viewer.