Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07fc786177 | ||
|
|
b7f046cd21 | ||
|
|
30eb7f2146 | ||
|
|
790635c863 | ||
|
|
fe67f78028 | ||
|
|
7e0fe7dc8d | ||
|
|
607941c54d | ||
|
|
6c55cb33cb | ||
|
|
fc30a3f649 | ||
|
|
d566e4f444 | ||
|
|
2174677f6f | ||
|
|
fb544a832c | ||
|
|
d9121967e7 | ||
|
|
f2247bc5b6 | ||
|
|
ee0cffc944 | ||
|
|
a45e08c43b | ||
|
|
9c931025cc | ||
|
|
07a97d62b8 | ||
|
|
65fec492f0 | ||
|
|
da7d3c6dbd | ||
|
|
73c66c142d | ||
|
|
29c513e5a3 | ||
|
|
72bb9d3513 | ||
|
|
90c0e0ff7e | ||
|
|
7b24ce3f41 | ||
|
|
d61748466e | ||
|
|
c17c28e42b | ||
|
|
524a65d0a9 | ||
|
|
51d8932252 | ||
|
|
7b655465bb | ||
|
|
71c44e62b8 | ||
|
|
2295b93f32 | ||
|
|
04d0b82268 | ||
|
|
dffb2eada2 | ||
|
|
c109fa727c | ||
|
|
91c9c6fb28 | ||
|
|
e4f8896b7f | ||
|
|
a558af3b09 | ||
|
|
918d3bd6df | ||
|
|
e4b6fba5ca | ||
|
|
41caa71ab0 | ||
|
|
f8786e5b6d | ||
|
|
78b5f4f8aa | ||
|
|
a0e4154f26 | ||
|
|
3f7749cf20 | ||
|
|
dba7247b44 | ||
|
|
43ac53f6a1 | ||
|
|
e82982d25d | ||
|
|
665a5cdee2 | ||
|
|
b81e4b60e5 | ||
|
|
a017996aba | ||
|
|
92ad68aad7 | ||
|
|
77618dd18b | ||
|
|
f0d075bbd6 | ||
|
|
156c2c294e | ||
|
|
c6037b0355 | ||
|
|
5edde2638e | ||
|
|
ba70a77932 | ||
|
|
1554a831ac | ||
|
|
efbabbafa3 | ||
|
|
017fd0dd14 | ||
|
|
79e7d974ad | ||
|
|
1cf2f84d24 | ||
|
|
c844759c63 | ||
|
|
b3be11953d | ||
|
|
4ee59cfaaf | ||
|
|
21cf4f9024 | ||
|
|
53889ece3d | ||
|
|
910f4c0f13 | ||
|
|
10555af3e6 | ||
|
|
ec92b8fff1 | ||
|
|
25f349a3a9 | ||
|
|
9f763c677c | ||
|
|
1444c5b476 | ||
|
|
3c0ed7b8b9 | ||
|
|
528cf0ed0f | ||
|
|
a8580673b6 | ||
|
|
04fe5199f1 |
@@ -23,6 +23,7 @@
|
|||||||
- Support for Google App Engine projections, thanks Christian
|
- Support for Google App Engine projections, thanks Christian
|
||||||
- Field(... 'upload', default=path) now accepts a path to a local file as default value, if user does not upload a file. Relative path looks inside current application folder, thanks Marin
|
- Field(... 'upload', default=path) now accepts a path to a local file as default value, if user does not upload a file. Relative path looks inside current application folder, thanks Marin
|
||||||
- executesql(...,fields=,columns=) allows parsing of results in Rows, thanks Anthony
|
- executesql(...,fields=,columns=) allows parsing of results in Rows, thanks Anthony
|
||||||
|
- Rows.find(lambda row: bool(), limitby=(0,1))
|
||||||
|
|
||||||
### Auth improvements
|
### Auth improvements
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ update:
|
|||||||
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
echo 'Version 2.0.2 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
echo 'Version 2.0.8 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
@@ -127,5 +127,5 @@ push:
|
|||||||
tag:
|
tag:
|
||||||
git tag -l '$(S)'
|
git tag -l '$(S)'
|
||||||
hg tag -l '$(S)'
|
hg tag -l '$(S)'
|
||||||
make commit
|
make commit S='$(S)'
|
||||||
make push
|
make push
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.0.2 (2012-08-29 22:00:56) stable
|
Version 2.0.8 (2012-09-06 21:32:40) stable
|
||||||
|
|||||||
@@ -137,11 +137,11 @@ def check_version():
|
|||||||
elif new_version != True:
|
elif new_version != True:
|
||||||
return A(T('web2py is up to date'), _href=WEB2PY_URL)
|
return A(T('web2py is up to date'), _href=WEB2PY_URL)
|
||||||
elif platform.system().lower() in ('windows','win32','win64') and os.path.exists("web2py.exe"):
|
elif platform.system().lower() in ('windows','win32','win64') and os.path.exists("web2py.exe"):
|
||||||
return SPAN('You should upgrade to version %s' % version_number)
|
return SPAN('You should upgrade to version %s.%s.%s' % version_number[:3])
|
||||||
else:
|
else:
|
||||||
return sp_button(URL('upgrade_web2py'), T('upgrade now')) \
|
return sp_button(URL('upgrade_web2py'), T('upgrade now')) \
|
||||||
+ XML(' <strong class="upgrade_version">%s</strong>' % version_number)
|
+ XML(' <strong class="upgrade_version">%s.%s.%s</strong>' \
|
||||||
|
% version_number[:3])
|
||||||
|
|
||||||
def logout():
|
def logout():
|
||||||
""" Logout handler """
|
""" Logout handler """
|
||||||
@@ -249,6 +249,10 @@ def site():
|
|||||||
fname = request.vars.file.filename
|
fname = request.vars.file.filename
|
||||||
f = request.vars.file.file
|
f = request.vars.file.file
|
||||||
|
|
||||||
|
else:
|
||||||
|
session.flash = 'No file uploaded and no URL specified'
|
||||||
|
redirect(URL(r=request))
|
||||||
|
|
||||||
if f:
|
if f:
|
||||||
appname = cleanpath(form_update.vars.name)
|
appname = cleanpath(form_update.vars.name)
|
||||||
installed = app_install(appname, f,
|
installed = app_install(appname, f,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
'are not used yet': 'are not used yet',
|
'are not used yet': 'are not used yet',
|
||||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
||||||
'arguments': 'arguments',
|
'arguments': 'arguments',
|
||||||
|
'at char %s': 'at char %s',
|
||||||
|
'at line %s': 'at line %s',
|
||||||
'back': '<<back',
|
'back': '<<back',
|
||||||
'can be a git repo': 'can be a git repo',
|
'can be a git repo': 'can be a git repo',
|
||||||
'Change admin password': 'Change admin password',
|
'Change admin password': 'Change admin password',
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
'created by': 'created by',
|
'created by': 'created by',
|
||||||
'crontab': 'crontab',
|
'crontab': 'crontab',
|
||||||
'currently running': 'currently running',
|
'currently running': 'currently running',
|
||||||
|
'currently saved or': 'currently saved or',
|
||||||
'database administration': 'database administration',
|
'database administration': 'database administration',
|
||||||
'Debug': 'Debug',
|
'Debug': 'Debug',
|
||||||
'defines tables': 'defines tables',
|
'defines tables': 'defines tables',
|
||||||
@@ -43,16 +46,23 @@
|
|||||||
'Detailed traceback description': 'Detailed traceback description',
|
'Detailed traceback description': 'Detailed traceback description',
|
||||||
'direction: ltr': 'direction: ltr',
|
'direction: ltr': 'direction: ltr',
|
||||||
'Disable': 'Disable',
|
'Disable': 'Disable',
|
||||||
|
'docs': 'docs',
|
||||||
'download layouts': 'download layouts',
|
'download layouts': 'download layouts',
|
||||||
'download plugins': 'download plugins',
|
'download plugins': 'download plugins',
|
||||||
'Edit': 'Edit',
|
'Edit': 'Edit',
|
||||||
'Edit application': 'Edit application',
|
'Edit application': 'Edit application',
|
||||||
|
'edit views:': 'edit views:',
|
||||||
|
'Editing file "%s"': 'Editing file "%s"',
|
||||||
'Error snapshot': 'Error snapshot',
|
'Error snapshot': 'Error snapshot',
|
||||||
'Error ticket': 'Error ticket',
|
'Error ticket': 'Error ticket',
|
||||||
'Errors': 'Errors',
|
'Errors': 'Errors',
|
||||||
'Exception instance attributes': 'Exception instance attributes',
|
'Exception instance attributes': 'Exception instance attributes',
|
||||||
'exposes': 'exposes',
|
'exposes': 'exposes',
|
||||||
|
'exposes:': 'exposes:',
|
||||||
'extends': 'extends',
|
'extends': 'extends',
|
||||||
|
'failed to compile file because:': 'failed to compile file because:',
|
||||||
|
'file does not exist': 'file does not exist',
|
||||||
|
'file saved on %s': 'file saved on %s',
|
||||||
'filter': 'filter',
|
'filter': 'filter',
|
||||||
'Frames': 'Frames',
|
'Frames': 'Frames',
|
||||||
'Get from URL:': 'Get from URL:',
|
'Get from URL:': 'Get from URL:',
|
||||||
@@ -63,8 +73,12 @@
|
|||||||
'inspect attributes': 'inspect attributes',
|
'inspect attributes': 'inspect attributes',
|
||||||
'Install': 'Install',
|
'Install': 'Install',
|
||||||
'Installed applications': 'Installed applications',
|
'Installed applications': 'Installed applications',
|
||||||
|
'invalid password.': 'invalid password.',
|
||||||
|
'Key bindings': 'Key bindings',
|
||||||
|
'Language files (static strings) updated': 'Language files (static strings) updated',
|
||||||
'languages': 'languages',
|
'languages': 'languages',
|
||||||
'Languages': 'Languages',
|
'Languages': 'Languages',
|
||||||
|
'Last saved on:': 'Last saved on:',
|
||||||
'loading...': 'loading...',
|
'loading...': 'loading...',
|
||||||
'locals': 'locals',
|
'locals': 'locals',
|
||||||
'Login': 'Login',
|
'Login': 'Login',
|
||||||
@@ -72,10 +86,11 @@
|
|||||||
'Logout': 'Logout',
|
'Logout': 'Logout',
|
||||||
'Models': 'Models',
|
'Models': 'Models',
|
||||||
'models': 'models',
|
'models': 'models',
|
||||||
'modules': 'modules',
|
|
||||||
'Modules': 'Modules',
|
'Modules': 'Modules',
|
||||||
|
'modules': 'modules',
|
||||||
'New application wizard': 'New application wizard',
|
'New application wizard': 'New application wizard',
|
||||||
'New simple application': 'New simple application',
|
'New simple application': 'New simple application',
|
||||||
|
'online designer': 'online designer',
|
||||||
'Overwrite installed app': 'Overwrite installed app',
|
'Overwrite installed app': 'Overwrite installed app',
|
||||||
'Pack all': 'Pack all',
|
'Pack all': 'Pack all',
|
||||||
'Peeking at file': 'Peeking at file',
|
'Peeking at file': 'Peeking at file',
|
||||||
@@ -88,11 +103,17 @@
|
|||||||
'Reload routes': 'Reload routes',
|
'Reload routes': 'Reload routes',
|
||||||
'request': 'request',
|
'request': 'request',
|
||||||
'response': 'response',
|
'response': 'response',
|
||||||
|
'restore': 'restore',
|
||||||
|
'revert': 'revert',
|
||||||
'rules are not defined': 'rules are not defined',
|
'rules are not defined': 'rules are not defined',
|
||||||
'rules:': 'rules:',
|
'rules:': 'rules:',
|
||||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
|
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
|
||||||
'Running on %s': 'Running on %s',
|
'Running on %s': 'Running on %s',
|
||||||
|
'Save': 'Save',
|
||||||
|
'Save via Ajax': 'Save via Ajax',
|
||||||
|
'Saved file hash:': 'Saved file hash:',
|
||||||
'session': 'session',
|
'session': 'session',
|
||||||
|
'session expired': 'session expired',
|
||||||
'shell': 'shell',
|
'shell': 'shell',
|
||||||
'Site': 'Site',
|
'Site': 'Site',
|
||||||
'Start wizard': 'Start wizard',
|
'Start wizard': 'Start wizard',
|
||||||
@@ -109,7 +130,9 @@
|
|||||||
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
|
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
|
||||||
'Ticket ID': 'Ticket ID',
|
'Ticket ID': 'Ticket ID',
|
||||||
'Ticket Missing': 'Ticket Missing',
|
'Ticket Missing': 'Ticket Missing',
|
||||||
|
'to previous version.': 'to previous version.',
|
||||||
'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]',
|
'To create a plugin, name a file/folder plugin_[name]': 'To create a plugin, name a file/folder plugin_[name]',
|
||||||
|
'toggle breakpoint': 'toggle breakpoint',
|
||||||
'Traceback': 'Traceback',
|
'Traceback': 'Traceback',
|
||||||
'Translation strings for the application': 'Translation strings for the application',
|
'Translation strings for the application': 'Translation strings for the application',
|
||||||
'Uninstall': 'Uninstall',
|
'Uninstall': 'Uninstall',
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
<h2>web2py™ {{=T('Web Framework')}}</h2>
|
<h2>web2py™ {{=T('Web Framework')}}</h2>
|
||||||
<h3>{{=T('Login to the Administrative Interface')}}</h3>
|
<h3>{{=T('Login to the Administrative Interface')}}</h3>
|
||||||
<div>
|
|
||||||
|
{{if request.is_https or request.is_local:}}
|
||||||
|
<div class="form">
|
||||||
<form action="{{=URL(r=request)}}" method="post">
|
<form action="{{=URL(r=request)}}" method="post">
|
||||||
<div><input type="hidden" name="send" value="{{=send}}"/></div>
|
<div><input type="hidden" name="send" value="{{=send}}"/></div>
|
||||||
<table>
|
<table>
|
||||||
@@ -11,4 +13,6 @@
|
|||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
{{else:}}
|
||||||
|
<p class="help">{{=T('ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.')}}</p>
|
||||||
|
{{pass}}
|
||||||
|
|||||||
@@ -223,16 +223,12 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[0]))}}
|
{{=editpluralsfile('languages',pfile,dict(nplurals=p[0]))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('languages',pfile,dict(id=id))}},
|
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<b>{{=T("are not used yet")}}</b>,
|
<b>{{=T("are not used yet")}}</b>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{=T("rules:")}}
|
|
||||||
<span class="file{{=' error' if p[3]!='ok' else ''}}">
|
|
||||||
{{=peekfile('gluon/contrib/rules', p[2], dict(app=app, id=id), p[3] if p[3]!='ok' else None)}}
|
|
||||||
</span>
|
|
||||||
{{pass}}
|
{{pass}}
|
||||||
)
|
)
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,13 +4,119 @@
|
|||||||
'!langname!': 'English (US)',
|
'!langname!': 'English (US)',
|
||||||
'%s %%(shop)': '%s %%(shop)',
|
'%s %%(shop)': '%s %%(shop)',
|
||||||
'%s %%(shop[0])': '%s %%(shop[0])',
|
'%s %%(shop[0])': '%s %%(shop[0])',
|
||||||
|
'%s %%{quark[0]}': '%s %%{quark[0]}',
|
||||||
'%s %%{shop[0]}': '%s %%{shop[0]}',
|
'%s %%{shop[0]}': '%s %%{shop[0]}',
|
||||||
'%s %%{shop}': '%s %%{shop}',
|
'%s %%{shop}': '%s %%{shop}',
|
||||||
|
'%Y-%m-%d': '%Y-%m-%d',
|
||||||
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
|
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
|
||||||
'@markmin\x01**Hello World**': '**Hello World**',
|
'@markmin\x01**Hello World**': '**Hello World**',
|
||||||
|
'About': 'About',
|
||||||
|
'Access Control': 'Access Control',
|
||||||
|
'Administrative Interface': 'Administrative Interface',
|
||||||
|
'Ajax Recipes': 'Ajax Recipes',
|
||||||
|
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
||||||
|
'Buy this book': 'Buy this book',
|
||||||
|
'Cannot be empty': 'Cannot be empty',
|
||||||
|
'Check to delete': 'Check to delete',
|
||||||
|
'Client IP': 'Client IP',
|
||||||
|
'Community': 'Community',
|
||||||
|
'Components and Plugins': 'Components and Plugins',
|
||||||
|
'Controller': 'Controller',
|
||||||
|
'Copyright': 'Copyright',
|
||||||
|
'Created By': 'Created By',
|
||||||
|
'Created On': 'Created On',
|
||||||
|
'customize me!': 'customize me!',
|
||||||
|
'Database': 'Database',
|
||||||
|
'DB Model': 'DB Model',
|
||||||
|
'Demo': 'Demo',
|
||||||
|
'Deployment Recipes': 'Deployment Recipes',
|
||||||
|
'Description': 'Description',
|
||||||
|
'Documentation': 'Documentation',
|
||||||
|
"Don't know what to do?": "Don't know what to do?",
|
||||||
|
'Download': 'Download',
|
||||||
|
'E-mail': 'E-mail',
|
||||||
|
'Email and SMS': 'Email and SMS',
|
||||||
'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g',
|
'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g',
|
||||||
'enter date and time as %(format)s': 'enter date and time as %(format)s',
|
'enter date and time as %(format)s': 'enter date and time as %(format)s',
|
||||||
|
'Errors': 'Errors',
|
||||||
|
'FAQ': 'FAQ',
|
||||||
|
'First name': 'First name',
|
||||||
|
'Forms and Validators': 'Forms and Validators',
|
||||||
|
'Free Applications': 'Free Applications',
|
||||||
|
'Group %(group_id)s created': 'Group %(group_id)s created',
|
||||||
|
'Group ID': 'Group ID',
|
||||||
|
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
|
||||||
|
'Groups': 'Groups',
|
||||||
'Hello World': 'Hello World',
|
'Hello World': 'Hello World',
|
||||||
'Hello World ## comment': 'Hello World ',
|
'Hello World ## comment': 'Hello World ',
|
||||||
'Hello World## comment': 'Hello World',
|
'Hello World## comment': 'Hello World',
|
||||||
|
'Home': 'Home',
|
||||||
|
'How did you get here?': 'How did you get here?',
|
||||||
|
'Introduction': 'Introduction',
|
||||||
|
'Invalid email': 'Invalid email',
|
||||||
|
'Is Active': 'Is Active',
|
||||||
|
'Last name': 'Last name',
|
||||||
|
'Layout': 'Layout',
|
||||||
|
'Layout Plugins': 'Layout Plugins',
|
||||||
|
'Layouts': 'Layouts',
|
||||||
|
'Live Chat': 'Live Chat',
|
||||||
|
'Logged in': 'Logged in',
|
||||||
|
'Logged out': 'Logged out',
|
||||||
|
'Login': 'Login',
|
||||||
|
'Logout': 'Logout',
|
||||||
|
'Lost Password': 'Lost Password',
|
||||||
|
'Lost password?': 'Lost password?',
|
||||||
|
'Menu Model': 'Menu Model',
|
||||||
|
'Modified By': 'Modified By',
|
||||||
|
'Modified On': 'Modified On',
|
||||||
|
'My Sites': 'My Sites',
|
||||||
|
'Name': 'Name',
|
||||||
|
'Object or table name': 'Object or table name',
|
||||||
|
'Online examples': 'Online examples',
|
||||||
|
'Origin': 'Origin',
|
||||||
|
'Other Plugins': 'Other Plugins',
|
||||||
|
'Other Recipes': 'Other Recipes',
|
||||||
|
'Overview': 'Overview',
|
||||||
|
'Password': 'Password',
|
||||||
|
"Password fields don't match": "Password fields don't match",
|
||||||
|
'please input your password again': 'please input your password again',
|
||||||
|
'Plugins': 'Plugins',
|
||||||
|
'Powered by': 'Powered by',
|
||||||
|
'Preface': 'Preface',
|
||||||
|
'Profile': 'Profile',
|
||||||
|
'Python': 'Python',
|
||||||
|
'Quick Examples': 'Quick Examples',
|
||||||
|
'Recipes': 'Recipes',
|
||||||
|
'Record ID': 'Record ID',
|
||||||
|
'Register': 'Register',
|
||||||
|
'Registration identifier': 'Registration identifier',
|
||||||
|
'Registration key': 'Registration key',
|
||||||
|
'Registration successful': 'Registration successful',
|
||||||
|
'Remember me (for 30 days)': 'Remember me (for 30 days)',
|
||||||
|
'Reset Password key': 'Reset Password key',
|
||||||
|
'Role': 'Role',
|
||||||
|
'Semantic': 'Semantic',
|
||||||
|
'Services': 'Services',
|
||||||
|
'Stylesheet': 'Stylesheet',
|
||||||
|
'Support': 'Support',
|
||||||
|
'The Core': 'The Core',
|
||||||
|
'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s',
|
||||||
|
'The Views': 'The Views',
|
||||||
|
'This App': 'This App',
|
||||||
|
'Timestamp': 'Timestamp',
|
||||||
|
'Twitter': 'Twitter',
|
||||||
|
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
||||||
|
'User %(id)s Logged-out': 'User %(id)s Logged-out',
|
||||||
|
'User %(id)s Registered': 'User %(id)s Registered',
|
||||||
|
'User ID': 'User ID',
|
||||||
|
'value already in database or empty': 'value already in database or empty',
|
||||||
|
'Verify Password': 'Verify Password',
|
||||||
|
'Videos': 'Videos',
|
||||||
|
'View': 'View',
|
||||||
|
'Welcome': 'Welcome',
|
||||||
|
'Welcome to web2py!': 'Welcome to web2py!',
|
||||||
|
'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s',
|
||||||
|
'You are successfully running web2py': 'You are successfully running web2py',
|
||||||
|
'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs',
|
||||||
|
'You visited the url %s': 'You visited the url %s',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
'edit profile': 'modifica profilo',
|
'edit profile': 'modifica profilo',
|
||||||
'Edit This App': 'Modifica questa applicazione',
|
'Edit This App': 'Modifica questa applicazione',
|
||||||
'Email and SMS': 'Email and SMS',
|
'Email and SMS': 'Email and SMS',
|
||||||
|
'Email non valida': 'Email non valida',
|
||||||
'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g',
|
'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g',
|
||||||
'Errors': 'Errors',
|
'Errors': 'Errors',
|
||||||
'export as csv file': 'esporta come file CSV',
|
'export as csv file': 'esporta come file CSV',
|
||||||
@@ -95,6 +96,7 @@
|
|||||||
'Layouts': 'Layouts',
|
'Layouts': 'Layouts',
|
||||||
'Live Chat': 'Live Chat',
|
'Live Chat': 'Live Chat',
|
||||||
'Logged in': 'Logged in',
|
'Logged in': 'Logged in',
|
||||||
|
'Logged out': 'Logged out',
|
||||||
'login': 'accesso',
|
'login': 'accesso',
|
||||||
'Login': 'Login',
|
'Login': 'Login',
|
||||||
'logout': 'uscita',
|
'logout': 'uscita',
|
||||||
@@ -113,6 +115,7 @@
|
|||||||
'new record inserted': 'nuovo record inserito',
|
'new record inserted': 'nuovo record inserito',
|
||||||
'next 100 rows': 'prossime 100 righe',
|
'next 100 rows': 'prossime 100 righe',
|
||||||
'No databases in this application': 'Nessun database presente in questa applicazione',
|
'No databases in this application': 'Nessun database presente in questa applicazione',
|
||||||
|
'Non può essere vuoto': 'Non può essere vuoto',
|
||||||
'not authorized': 'non autorizzato',
|
'not authorized': 'non autorizzato',
|
||||||
'Object or table name': 'Object or table name',
|
'Object or table name': 'Object or table name',
|
||||||
'Online examples': 'Vedere gli esempi',
|
'Online examples': 'Vedere gli esempi',
|
||||||
@@ -166,12 +169,14 @@
|
|||||||
'This App': 'This App',
|
'This App': 'This App',
|
||||||
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
||||||
'Timestamp': 'Ora (timestamp)',
|
'Timestamp': 'Ora (timestamp)',
|
||||||
|
'too short': 'too short',
|
||||||
'Twitter': 'Twitter',
|
'Twitter': 'Twitter',
|
||||||
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
||||||
'Update': 'Update',
|
'Update': 'Update',
|
||||||
'Update:': 'Aggiorna:',
|
'Update:': 'Aggiorna:',
|
||||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).',
|
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).',
|
||||||
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
||||||
|
'User %(id)s Logged-out': 'User %(id)s Logged-out',
|
||||||
'User %(id)s Registered': 'User %(id)s Registered',
|
'User %(id)s Registered': 'User %(id)s Registered',
|
||||||
'User ID': 'ID Utente',
|
'User ID': 'ID Utente',
|
||||||
'Verify Password': 'Verify Password',
|
'Verify Password': 'Verify Password',
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
'is': ['are'],
|
'is': ['are'],
|
||||||
'man': ['men'],
|
'man': ['men'],
|
||||||
'person': ['people'],
|
'person': ['people'],
|
||||||
|
'quark': ['quarks'],
|
||||||
'shop': ['shops'],
|
'shop': ['shops'],
|
||||||
'this': ['these'],
|
'this': ['these'],
|
||||||
'was': ['were'],
|
'was': ['were'],
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ td,th {text-align:left; padding:2px 5px 2px 5px}
|
|||||||
th {vertical-align:middle; border-right:1px solid white}
|
th {vertical-align:middle; border-right:1px solid white}
|
||||||
td {vertical-align:top}
|
td {vertical-align:top}
|
||||||
form table tr td label {text-align:left}
|
form table tr td label {text-align:left}
|
||||||
p,table,ol,ul {padding:0; margin: 0.5em 0}
|
p,table,ol,ul {padding:0; margin: 0.75em 0}
|
||||||
p {text-align:justify}
|
p {text-align:justify}
|
||||||
ol, ul {list-style-position:inside}
|
ol, ul {list-style-position:outside; margin-left:2em}
|
||||||
li {margin-bottom:0.5em}
|
li {margin-bottom:0.5em}
|
||||||
span,input,select,textarea,button,label,a {display:inline}
|
span,input,select,textarea,button,label,a {display:inline}
|
||||||
img {border:0}
|
img {border:0}
|
||||||
@@ -39,13 +39,6 @@ input[type=text],input[type=password],select{width:300px; margin-right:5px}
|
|||||||
|
|
||||||
/* Sticky footer begin */
|
/* Sticky footer begin */
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
min-height:100%;
|
|
||||||
height:auto !important;
|
|
||||||
height:100%;
|
|
||||||
margin:0 auto -8em; /* set last value to footer height plus footer vertical padding */
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
padding:20px 0 50px 0;
|
padding:20px 0 50px 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@
|
|||||||
</section><!--/main-->
|
</section><!--/main-->
|
||||||
|
|
||||||
<!-- Footer ================================================== -->
|
<!-- Footer ================================================== -->
|
||||||
<footer class="footer">
|
<footer class="footer" id="footer">
|
||||||
{{block footer}} <!-- this is default footer -->
|
{{block footer}} <!-- this is default footer -->
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
<div class="copyright pull-left">{{=T('Copyright')}} © {{=request.now.year}}</div>
|
<div class="copyright pull-left">{{=T('Copyright')}} © {{=request.now.year}}</div>
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ __all__ = ['Cache', 'lazy_cache']
|
|||||||
|
|
||||||
DEFAULT_TIME_EXPIRE = 300
|
DEFAULT_TIME_EXPIRE = 300
|
||||||
|
|
||||||
|
|
||||||
class CacheAbstract(object):
|
class CacheAbstract(object):
|
||||||
"""
|
"""
|
||||||
Abstract class for cache implementations.
|
Abstract class for cache implementations.
|
||||||
|
|||||||
+28
-5
@@ -91,6 +91,18 @@ def _TEST():
|
|||||||
_TEST()
|
_TEST()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CACHED_REGEXES = {}
|
||||||
|
CACHED_REGEXES_MAX_SIZE = 1000
|
||||||
|
|
||||||
|
def re_compile(regex):
|
||||||
|
try:
|
||||||
|
return CACHED_REGEXES[regex]
|
||||||
|
except KeyError:
|
||||||
|
if len(CACHED_REGEXES) >= CACHED_REGEXES_MAX_SIZE:
|
||||||
|
CACHED_REGEXES.clear()
|
||||||
|
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
||||||
|
return compiled_regex
|
||||||
|
|
||||||
class mybuiltin(object):
|
class mybuiltin(object):
|
||||||
"""
|
"""
|
||||||
NOTE could simple use a dict and populate it,
|
NOTE could simple use a dict and populate it,
|
||||||
@@ -355,6 +367,10 @@ def build_environment(request, response, session, store_current=True):
|
|||||||
environment.update((k,getattr(v, k)) for k in v.__all__)
|
environment.update((k,getattr(v, k)) for k in v.__all__)
|
||||||
if not request.env:
|
if not request.env:
|
||||||
request.env = Storage()
|
request.env = Storage()
|
||||||
|
# Enable standard conditional models (i.e., /*.py, /[controller]/*.py, and
|
||||||
|
# /[controller]/[function]/*.py)
|
||||||
|
response.models_to_run = [r'^\w+\.py$', r'^%s/\w+\.py$' % request.controller,
|
||||||
|
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
|
||||||
|
|
||||||
t = environment['T'] = translator(request)
|
t = environment['T'] = translator(request)
|
||||||
c = environment['cache'] = Cache(request)
|
c = environment['cache'] = Cache(request)
|
||||||
@@ -485,9 +501,13 @@ def run_models_in(environment):
|
|||||||
path = pjoin(folder, 'models')
|
path = pjoin(folder, 'models')
|
||||||
models = listdir(path, '^\w+\.py$',0,sort=False)
|
models = listdir(path, '^\w+\.py$',0,sort=False)
|
||||||
compiled=False
|
compiled=False
|
||||||
paths = (path, pjoin(path,c), pjoin(path,c,f))
|
n = len(path) + 1
|
||||||
for model in models:
|
for model in models:
|
||||||
if not os.path.split(model)[0] in paths and c!='appadmin':
|
regex = environment['response'].models_to_run
|
||||||
|
if isinstance(regex, list):
|
||||||
|
regex = re_compile('|'.join(regex))
|
||||||
|
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py')
|
||||||
|
if not regex.search(file) and c!= 'appadmin':
|
||||||
continue
|
continue
|
||||||
elif compiled:
|
elif compiled:
|
||||||
code = read_pyc(model)
|
code = read_pyc(model)
|
||||||
@@ -581,10 +601,13 @@ def run_view_in(environment):
|
|||||||
folder = request.folder
|
folder = request.folder
|
||||||
path = pjoin(folder, 'compiled')
|
path = pjoin(folder, 'compiled')
|
||||||
badv = 'invalid view (%s)' % view
|
badv = 'invalid view (%s)' % view
|
||||||
patterns = response.generic_patterns or []
|
if response.generic_patterns:
|
||||||
regex = re.compile('|'.join(map(fnmatch.translate, patterns)))
|
patterns = response.generic_patterns
|
||||||
|
regex = re_compile('|'.join(map(fnmatch.translate, patterns)))
|
||||||
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
||||||
allow_generic = patterns and regex.search(short_action)
|
allow_generic = regex.search(short_action)
|
||||||
|
else:
|
||||||
|
allow_generic = False
|
||||||
if not isinstance(view, str):
|
if not isinstance(view, str):
|
||||||
ccode = parse_template(view, pjoin(folder, 'views'),
|
ccode = parse_template(view, pjoin(folder, 'views'),
|
||||||
context=environment)
|
context=environment)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# created by Massimo Di Pierro
|
# created by Massimo Di Pierro
|
||||||
# recreated by Vladyslav Kozlovskyy
|
# recreated by Vladyslav Kozlovskyy
|
||||||
@@ -44,8 +44,8 @@ from markmin2pdf import markmin2pdf # requires pdflatex
|
|||||||
print markmin2pdf(m)
|
print markmin2pdf(m)
|
||||||
``
|
``
|
||||||
====================
|
====================
|
||||||
# This is a test block with new features:
|
# This is a test block
|
||||||
|
with new features:
|
||||||
This is a blockquote with
|
This is a blockquote with
|
||||||
a list with tables in it:
|
a list with tables in it:
|
||||||
-----------
|
-----------
|
||||||
@@ -71,7 +71,9 @@ a list with tables in it:
|
|||||||
-----------:blockquoteclass[blockquoteid]
|
-----------:blockquoteclass[blockquoteid]
|
||||||
|
|
||||||
This this a new paragraph
|
This this a new paragraph
|
||||||
with a table. Table has header, footer, sections, odd and even rows:
|
with a followed table.
|
||||||
|
Table has header, footer, sections,
|
||||||
|
odd and even rows:
|
||||||
-------------------------------
|
-------------------------------
|
||||||
**Title 1**|**Title 2**|**Title 3**
|
**Title 1**|**Title 2**|**Title 3**
|
||||||
==============================
|
==============================
|
||||||
@@ -98,6 +100,8 @@ Now lists can be multilevel:
|
|||||||
You can continue item text on
|
You can continue item text on
|
||||||
next strings
|
next strings
|
||||||
|
|
||||||
|
. paragraph in an item
|
||||||
|
|
||||||
++. Ordered item 1 of sublevel 2 with
|
++. Ordered item 1 of sublevel 2 with
|
||||||
a paragraph (paragraph can start
|
a paragraph (paragraph can start
|
||||||
with point after plus or minus
|
with point after plus or minus
|
||||||
@@ -143,7 +147,7 @@ line 1
|
|||||||
line 2
|
line 2
|
||||||
line 3
|
line 3
|
||||||
``
|
``
|
||||||
++++. Yet another item with code block:
|
++++. Yet another item with code block (we need to indent \`\` to add code block as part of item):
|
||||||
``
|
``
|
||||||
line 1
|
line 1
|
||||||
line 2
|
line 2
|
||||||
@@ -201,7 +205,7 @@ We wanted a markup language with the following requirements:
|
|||||||
- support table, ul, ol, code
|
- support table, ul, ol, code
|
||||||
- support html5 video and audio elements (html serialization only)
|
- support html5 video and audio elements (html serialization only)
|
||||||
- can align images and resize them
|
- can align images and resize them
|
||||||
- can specify class for tables and code elements
|
- can specify class for tables, blockquotes and code elements
|
||||||
- can add anchors
|
- can add anchors
|
||||||
- does not use _ for markup (since it creates odd behavior)
|
- does not use _ for markup (since it creates odd behavior)
|
||||||
- automatically links urls
|
- automatically links urls
|
||||||
@@ -420,6 +424,23 @@ generates
|
|||||||
|
|
||||||
(the ``!`!`...`!`!:custom`` block is rendered by the ``custom=lambda`` function passed to ``render``).
|
(the ``!`!`...`!`!:custom`` block is rendered by the ``custom=lambda`` function passed to ``render``).
|
||||||
|
|
||||||
|
### Line breaks
|
||||||
|
|
||||||
|
``[[NEWLINE]]`` tag is used to break lines:
|
||||||
|
``
|
||||||
|
#### Multiline [[NEWLINE]]
|
||||||
|
title
|
||||||
|
paragraph [[NEWLINE]]
|
||||||
|
with breaks[[NEWLINE]]in it
|
||||||
|
``
|
||||||
|
generates:
|
||||||
|
|
||||||
|
#### Multiline [[NEWLINE]]
|
||||||
|
title
|
||||||
|
paragraph [[NEWLINE]]
|
||||||
|
with breaks[[NEWLINE]]in it
|
||||||
|
|
||||||
|
|
||||||
### Html5 support
|
### Html5 support
|
||||||
|
|
||||||
Markmin also supports the <video> and <audio> html5 tags using the notation:
|
Markmin also supports the <video> and <audio> html5 tags using the notation:
|
||||||
@@ -430,7 +451,7 @@ Markmin also supports the <video> and <audio> html5 tags using the notation:
|
|||||||
[[message [title] link video]]
|
[[message [title] link video]]
|
||||||
[[message [title] link audio]]
|
[[message [title] link audio]]
|
||||||
``
|
``
|
||||||
where ``message`` will be shown in brousers without HTML5 video/audio tags support.
|
where ``message`` will be shown in browsers without HTML5 video/audio tags support.
|
||||||
|
|
||||||
### Latex and other extensions
|
### Latex and other extensions
|
||||||
|
|
||||||
@@ -512,18 +533,18 @@ DISABLED_META = '\x08'
|
|||||||
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
||||||
regex_URL=re.compile(r'@/(?P<a>\w*)/(?P<c>\w*)/(?P<f>\w*(\.\w+)?)(/(?P<args>[\w\.\-/]+))?')
|
regex_URL=re.compile(r'@/(?P<a>\w*)/(?P<c>\w*)/(?P<f>\w*(\.\w+)?)(/(?P<args>[\w\.\-/]+))?')
|
||||||
regex_env=re.compile(r'@\{(?P<a>[\w\-\.]+?)(\:(?P<b>.*?))?\}')
|
regex_env=re.compile(r'@\{(?P<a>[\w\-\.]+?)(\:(?P<b>.*?))?\}')
|
||||||
regex_expand_meta = re.compile('('+META+'|'+DISABLED_META+')')
|
regex_expand_meta = re.compile('('+META+'|'+DISABLED_META+'|````)')
|
||||||
regex_dd=re.compile(r'\$\$(?P<latex>.*?)\$\$')
|
regex_dd=re.compile(r'\$\$(?P<latex>.*?)\$\$')
|
||||||
regex_code = re.compile('('+META+'|'+DISABLED_META+r')|(``(?P<t>.+?)``(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[^\]]*)\])?)?)',re.S)
|
regex_code = re.compile('('+META+'|'+DISABLED_META+r'|````)|(``(?P<t>.+?)``(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[^\]]*)\])?)?)',re.S)
|
||||||
regex_strong=re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*')
|
regex_strong=re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*')
|
||||||
regex_del=re.compile(r'~~(?P<t>[^\s*]+( +[^\s*]+)*)~~')
|
regex_del=re.compile(r'~~(?P<t>[^\s*]+( +[^\s*]+)*)~~')
|
||||||
regex_em=re.compile(r"''(?P<t>[^\s']+(?: +[^\s']+)*)''")
|
regex_em=re.compile(r"''(?P<t>[^\s']+(?: +[^\s']+)*)''")
|
||||||
regex_num=re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
|
regex_num=re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
|
||||||
regex_list=re.compile('^(?:(#{1,6}|\.+ |\++ |\++\. |\-+ |\-+\. )\s*)?(.*)$')
|
regex_list=re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s+)?(.*)$')
|
||||||
regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
|
regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
|
||||||
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
|
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
|
||||||
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
||||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[^\s\'\"\]\}\)]+)',re.M)
|
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
|
||||||
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]')
|
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]')
|
||||||
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$')
|
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$')
|
||||||
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$')
|
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$')
|
||||||
@@ -579,7 +600,8 @@ def render(text,
|
|||||||
autolinks='default',
|
autolinks='default',
|
||||||
protolinks='default',
|
protolinks='default',
|
||||||
class_prefix='',
|
class_prefix='',
|
||||||
id_prefix='markmin_'):
|
id_prefix='markmin_',
|
||||||
|
pretty_print=False):
|
||||||
"""
|
"""
|
||||||
Arguments:
|
Arguments:
|
||||||
- text is the text to be processed
|
- text is the text to be processed
|
||||||
@@ -791,9 +813,18 @@ def render(text,
|
|||||||
>>> render('[[id1 [span **messag** in ''markmin''] ]] ... [[**link** to id [link\\\'s title] #mark1]]')
|
>>> render('[[id1 [span **messag** in ''markmin''] ]] ... [[**link** to id [link\\\'s title] #mark1]]')
|
||||||
'<p><div class="anchor" id="markmin_id1">span <strong>messag</strong> in markmin</div> ... <a href="#markmin_mark1" title="link\\\'s title"><strong>link</strong> to id</a></p>'
|
'<p><div class="anchor" id="markmin_id1">span <strong>messag</strong> in markmin</div> ... <a href="#markmin_mark1" title="link\\\'s title"><strong>link</strong> to id</a></p>'
|
||||||
|
|
||||||
|
>>> render('# Multiline[[NEWLINE]]\\n title\\nParagraph[[NEWLINE]]\\nwith breaks[[NEWLINE]]\\nin it')
|
||||||
|
'<h1>Multiline<br /> title</h1><p>Paragraph<br /> with breaks<br /> in it</p>'
|
||||||
|
|
||||||
|
>>> render("anchor with name 'NEWLINE': [[NEWLINE [ ] ]]")
|
||||||
|
'<p>anchor with name \\'NEWLINE\\': <div class="anchor" id="markmin_NEWLINE"></div></p>'
|
||||||
|
|
||||||
|
>>> render("anchor with name 'NEWLINE': [[NEWLINE [newline] ]]")
|
||||||
|
'<p>anchor with name \\'NEWLINE\\': <div class="anchor" id="markmin_NEWLINE">newline</div></p>'
|
||||||
"""
|
"""
|
||||||
if autolinks=="default": autolinks = autolinks_simple
|
if autolinks=="default": autolinks = autolinks_simple
|
||||||
if protolinks=="default": protolinks = protolinks_simple
|
if protolinks=="default": protolinks = protolinks_simple
|
||||||
|
pp='\n' if pretty_print else ''
|
||||||
text = str(text or '')
|
text = str(text or '')
|
||||||
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
|
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
|
||||||
|
|
||||||
@@ -816,9 +847,12 @@ def render(text,
|
|||||||
segments = []
|
segments = []
|
||||||
def mark_code(m):
|
def mark_code(m):
|
||||||
g = m.group(0)
|
g = m.group(0)
|
||||||
if m.group() in ( META, DISABLED_META ):
|
if g in (META, DISABLED_META ):
|
||||||
segments.append((None, None, None, g))
|
segments.append((None, None, None, g))
|
||||||
return m.group()
|
return m.group()
|
||||||
|
elif g == '````':
|
||||||
|
segments.append((None, None, None, ''))
|
||||||
|
return m.group()
|
||||||
else:
|
else:
|
||||||
c = m.group('c') or ''
|
c = m.group('c') or ''
|
||||||
p = m.group('p') or ''
|
p = m.group('p') or ''
|
||||||
@@ -849,13 +883,13 @@ def render(text,
|
|||||||
#############################################################
|
#############################################################
|
||||||
# normalize spaces
|
# normalize spaces
|
||||||
#############################################################
|
#############################################################
|
||||||
strings=[t.strip() for t in text.split('\n')]
|
strings=text.split('\n')
|
||||||
|
|
||||||
def parse_title(t, s): #out, lev, etags, tag, s):
|
def parse_title(t, s): #out, lev, etags, tag, s):
|
||||||
hlevel=str(len(t))
|
hlevel=str(len(t))
|
||||||
out.extend(etags[::-1])
|
out.extend(etags[::-1])
|
||||||
out.append("<h%s>%s"%(hlevel,s))
|
out.append("<h%s>%s"%(hlevel,s))
|
||||||
etags[:]=["</h%s>"%hlevel]
|
etags[:]=["</h%s>%s"%(hlevel,pp)]
|
||||||
lev=0
|
lev=0
|
||||||
ltags[:]=[]
|
ltags[:]=[]
|
||||||
tlev[:]=[]
|
tlev[:]=[]
|
||||||
@@ -880,8 +914,8 @@ def render(text,
|
|||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
for i in xrange(lent-lev):
|
for i in xrange(lent-lev):
|
||||||
out.append('<'+tag+'>')
|
out.append('<'+tag+'>'+pp)
|
||||||
etags.append('</'+tag+'>')
|
etags.append('</'+tag+'>'+pp)
|
||||||
lev+=1
|
lev+=1
|
||||||
ltags.append(lev)
|
ltags.append(lev)
|
||||||
tlev.append(tag)
|
tlev.append(tag)
|
||||||
@@ -892,8 +926,8 @@ def render(text,
|
|||||||
ltags.pop()
|
ltags.pop()
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
tlev[-1]=tag
|
tlev[-1]=tag
|
||||||
out.append('<'+tag+'>')
|
out.append('<'+tag+'>'+pp)
|
||||||
etags.append('</'+tag+'>')
|
etags.append('</'+tag+'>'+pp)
|
||||||
ltags.append(lev)
|
ltags.append(lev)
|
||||||
else:
|
else:
|
||||||
if ltags.count(lev)>1:
|
if ltags.count(lev)>1:
|
||||||
@@ -901,7 +935,7 @@ def render(text,
|
|||||||
ltags.pop()
|
ltags.pop()
|
||||||
mtag='l'
|
mtag='l'
|
||||||
out.append('<li>')
|
out.append('<li>')
|
||||||
etags.append('</li>')
|
etags.append('</li>'+pp)
|
||||||
ltags.append(lev)
|
ltags.append(lev)
|
||||||
if s[:1] == '-':
|
if s[:1] == '-':
|
||||||
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
||||||
@@ -954,7 +988,7 @@ def render(text,
|
|||||||
return (s, mtag, lineno)
|
return (s, mtag, lineno)
|
||||||
|
|
||||||
lineno+=1
|
lineno+=1
|
||||||
s = strings[lineno]
|
s = strings[lineno].strip()
|
||||||
if s:
|
if s:
|
||||||
if '|' in s:
|
if '|' in s:
|
||||||
# table
|
# table
|
||||||
@@ -967,7 +1001,7 @@ def render(text,
|
|||||||
|
|
||||||
# parse table:
|
# parse table:
|
||||||
while lineno < strings_len:
|
while lineno < strings_len:
|
||||||
s = strings[lineno]
|
s = strings[lineno].strip()
|
||||||
if s[:1] == '=':
|
if s[:1] == '=':
|
||||||
if s.count('=')==len(s) and len(s)>3: # header or footer
|
if s.count('=')==len(s) and len(s)>3: # header or footer
|
||||||
if not thead: # if thead list is empty:
|
if not thead: # if thead list is empty:
|
||||||
@@ -994,7 +1028,7 @@ def render(text,
|
|||||||
if regex_num.match(f)
|
if regex_num.match(f)
|
||||||
else '',
|
else '',
|
||||||
f.strip()
|
f.strip()
|
||||||
) for f in s.split('|')])+'</tr>')
|
) for f in s.split('|')])+'</tr>'+pp)
|
||||||
rownum+=1
|
rownum+=1
|
||||||
lineno+=1
|
lineno+=1
|
||||||
|
|
||||||
@@ -1002,15 +1036,15 @@ def render(text,
|
|||||||
t_id = ' id="%s%s"'%(id_prefix, t_id) if t_id else ''
|
t_id = ' id="%s%s"'%(id_prefix, t_id) if t_id else ''
|
||||||
s = ''
|
s = ''
|
||||||
if thead:
|
if thead:
|
||||||
s += '<thead>'+''.join([l for l in thead])+'</thead>'
|
s += '<thead>'+pp+''.join([l for l in thead])+'</thead>'+pp
|
||||||
if not tbody: # tbody strings are in tout list
|
if not tbody: # tbody strings are in tout list
|
||||||
tbody = tout
|
tbody = tout
|
||||||
tout = []
|
tout = []
|
||||||
if tbody: # if tbody list is not empty:
|
if tbody: # if tbody list is not empty:
|
||||||
s += '<tbody>'+''.join([l for l in tbody])+'</tbody>'
|
s += '<tbody>'+pp+''.join([l for l in tbody])+'</tbody>'+pp
|
||||||
if tout: # tfoot is not empty:
|
if tout: # tfoot is not empty:
|
||||||
s += '<tfoot>'+''.join([l for l in tout])+'</tfoot>'
|
s += '<tfoot>'+pp+''.join([l for l in tout])+'</tfoot>'+pp
|
||||||
s = '<table%s%s>%s</table>' % (t_cls, t_id, s)
|
s = '<table%s%s>%s%s</table>%s' % (t_cls, t_id, pp, s, pp)
|
||||||
mtag='t'
|
mtag='t'
|
||||||
else:
|
else:
|
||||||
# parse blockquote:
|
# parse blockquote:
|
||||||
@@ -1021,7 +1055,7 @@ def render(text,
|
|||||||
|
|
||||||
# search blockquote closing line:
|
# search blockquote closing line:
|
||||||
while lineno < strings_len:
|
while lineno < strings_len:
|
||||||
s = strings[lineno]
|
s = strings[lineno].strip()
|
||||||
if not t_mode:
|
if not t_mode:
|
||||||
m = regex_tq.match(s)
|
m = regex_tq.match(s)
|
||||||
if m:
|
if m:
|
||||||
@@ -1031,7 +1065,7 @@ def render(text,
|
|||||||
break
|
break
|
||||||
|
|
||||||
if regex_bq_headline.match(s):
|
if regex_bq_headline.match(s):
|
||||||
if lineno+1 < strings_len and strings[lineno+1]:
|
if lineno+1 < strings_len and strings[lineno+1].strip():
|
||||||
t_mode = True
|
t_mode = True
|
||||||
lineno+=1
|
lineno+=1
|
||||||
continue
|
continue
|
||||||
@@ -1044,7 +1078,7 @@ def render(text,
|
|||||||
|
|
||||||
t_cls = ' class="%s%s"'%(class_prefix,t_cls) if t_cls and t_cls != 'id' else ''
|
t_cls = ' class="%s%s"'%(class_prefix,t_cls) if t_cls and t_cls != 'id' else ''
|
||||||
t_id = ' id="%s%s"'%(id_prefix,t_id) if t_id else ''
|
t_id = ' id="%s%s"'%(id_prefix,t_id) if t_id else ''
|
||||||
s = '<blockquote%s%s>%s</blockquote>' \
|
s = '<blockquote%s%s>%s</blockquote>%s' \
|
||||||
% (t_cls,
|
% (t_cls,
|
||||||
t_id,
|
t_id,
|
||||||
render('\n'.join(strings[bq_begin:lineno]),
|
render('\n'.join(strings[bq_begin:lineno]),
|
||||||
@@ -1057,7 +1091,9 @@ def render(text,
|
|||||||
autolinks,
|
autolinks,
|
||||||
protolinks,
|
protolinks,
|
||||||
class_prefix,
|
class_prefix,
|
||||||
id_prefix)
|
id_prefix,
|
||||||
|
pretty_print),
|
||||||
|
pp
|
||||||
)
|
)
|
||||||
mtag='q'
|
mtag='q'
|
||||||
else:
|
else:
|
||||||
@@ -1068,51 +1104,56 @@ def render(text,
|
|||||||
|
|
||||||
if sep == 'p':
|
if sep == 'p':
|
||||||
pbeg = "<p>"
|
pbeg = "<p>"
|
||||||
pend = "</p>"
|
pend = "</p>"+pp
|
||||||
br = ''
|
br = ''
|
||||||
else:
|
else:
|
||||||
pbeg = pend = ''
|
pbeg = pend = ''
|
||||||
br = "<br />" if sep=='br' else ''
|
br = "<br />"+pp if sep=='br' else ''
|
||||||
|
|
||||||
lev = 0 # рівень вкладеності списків
|
lev = 0 # nesting level of lists
|
||||||
c0 = '' # перший символ поточного рядка
|
c0 = '' # first character of current line
|
||||||
out = [] # результуючий список рядків
|
out = [] # list of processed lines
|
||||||
etags = [] # завершуючі таги
|
etags = [] # trailing tags
|
||||||
ltags = [] # номер рівня відповідний завершуючому тагу
|
ltags = [] # level# correspondent to trailing tag
|
||||||
tlev = [] # таг рівня ('ul' або 'ol')
|
tlev = [] # list of tags for each level ('ul' or 'ol')
|
||||||
mtag = '' # marked tag (~last tag) ('l','.','h','p','t'). Used for set <br/>
|
mtag = '' # marked tag (~last tag) ('l','.','h','p','t'). Used to set <br/>
|
||||||
# and for avoid <p></p> around tables and blockquotes
|
# and to avoid <p></p> around tables and blockquotes
|
||||||
lineno = 0
|
lineno = 0
|
||||||
strings_len = len(strings)
|
strings_len = len(strings)
|
||||||
while lineno < strings_len:
|
while lineno < strings_len:
|
||||||
s = strings[lineno]
|
s0 = strings[lineno][:1]
|
||||||
|
s = strings[lineno].strip()
|
||||||
""" # + - . ---------------------
|
""" # + - . ---------------------
|
||||||
## ++ -- .. ------- field | field | field <-title
|
## ++ -- .. ------- field | field | field <-title
|
||||||
### +++ --- ... quote =====================
|
### +++ --- ... quote =====================
|
||||||
#### ++++ ---- .... ------- field | field | field <-body
|
#### ++++ ---- .... ------- field | field | field <-body
|
||||||
##### +++++ ----- ..... ---------------------:class[id]
|
##### +++++ ----- ..... ---------------------:class[id]
|
||||||
"""
|
"""
|
||||||
pc0=c0 # перший символ попереднього рядка
|
pc0=c0 # first character of previous line
|
||||||
c0=s[:1]
|
c0=s[:1]
|
||||||
if c0: # for non empty strings
|
if c0: # for non empty strings
|
||||||
if c0 in "#+-.": # first character is one of: # + - .
|
if c0 in "#+-.": # first character is one of: # + - .
|
||||||
match = regex_list.search(s)
|
(t1,t2,p,ss) = regex_list.findall(s)[0]
|
||||||
(t,p,s) = match.group(1), None, match.group(2)
|
# t1 - tag ("###")
|
||||||
t = (t or '').strip()
|
# t2 - tag ("+++", "---", "...")
|
||||||
if t.endswith('.'): t, p = t[:-1], '.'
|
|
||||||
# t - tag ("###", "+++", "---", "...")
|
|
||||||
# p - paragraph point ('.')->for "++." or "--."
|
# p - paragraph point ('.')->for "++." or "--."
|
||||||
# s - other part of string
|
# ss - other part of string
|
||||||
if t:
|
if t1 or t2:
|
||||||
# headers and lists:
|
# headers and lists:
|
||||||
if c0 == '#': # headers
|
if c0 == '#': # headers
|
||||||
(lev, mtag) = parse_title(t, s)
|
(lev, mtag) = parse_title(t1, ss)
|
||||||
|
lineno+=1
|
||||||
|
continue
|
||||||
elif c0 == '+': # ordered list
|
elif c0 == '+': # ordered list
|
||||||
(lev, mtag, lineno)= parse_list(t, p, s, 'ol', lev, mtag, lineno)
|
(lev, mtag, lineno)= parse_list(t2, p, ss, 'ol', lev, mtag, lineno)
|
||||||
|
lineno+=1
|
||||||
|
continue
|
||||||
elif c0 == '-': # unordered list
|
elif c0 == '-': # unordered list
|
||||||
(lev, mtag, lineno) = parse_list(t, p, s, 'ul', lev, mtag, lineno)
|
(lev, mtag, lineno) = parse_list(t2, p, ss, 'ul', lev, mtag, lineno)
|
||||||
else: # c0 == '.' # paragraph in lists
|
lineno+=1
|
||||||
(lev, mtag, lineno) = parse_point(t, s, lev, mtag, lineno)
|
continue
|
||||||
|
elif lev>0: # and c0 == '.' # paragraph in lists
|
||||||
|
(lev, mtag, lineno) = parse_point(t2, ss, lev, mtag, lineno)
|
||||||
lineno+=1
|
lineno+=1
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
@@ -1123,7 +1164,7 @@ def render(text,
|
|||||||
# new paragraph
|
# new paragraph
|
||||||
pc0=''
|
pc0=''
|
||||||
|
|
||||||
if pc0 == '':
|
if pc0 == '' or (mtag != 'p' and s0 not in (' ','\t')):
|
||||||
# paragraph
|
# paragraph
|
||||||
out.extend(etags[::-1])
|
out.extend(etags[::-1])
|
||||||
etags=[]
|
etags=[]
|
||||||
@@ -1171,12 +1212,12 @@ def render(text,
|
|||||||
style = p_begin = p_end = ''
|
style = p_begin = p_end = ''
|
||||||
if p == 'center':
|
if p == 'center':
|
||||||
p_begin = '<p style="text-align:center">'
|
p_begin = '<p style="text-align:center">'
|
||||||
p_end = '</p>'
|
p_end = '</p>'+pp
|
||||||
elif p in ('left','right'):
|
elif p in ('left','right'):
|
||||||
style = ' style="float:%s"' % p
|
style = ' style="float:%s"' % p
|
||||||
if p in ('video','audio'):
|
if p in ('video','audio'):
|
||||||
t = render(t, {}, {}, 'br', URL, environment, latex,
|
t = render(t, {}, {}, 'br', URL, environment, latex,
|
||||||
autolinks, protolinks, class_prefix, id_prefix)
|
autolinks, protolinks, class_prefix, id_prefix, pretty_print)
|
||||||
return '<%(p)s controls="controls"%(title)s%(width)s><source src="%(k)s" />%(t)s</%(p)s>' \
|
return '<%(p)s controls="controls"%(title)s%(width)s><source src="%(k)s" />%(t)s</%(p)s>' \
|
||||||
% dict(p=p, title=title, width=width, k=k, t=t)
|
% dict(p=p, title=title, width=width, k=k, t=t)
|
||||||
alt = ' alt="%s"'%escape(t).replace(META, DISABLED_META) if t else ''
|
alt = ' alt="%s"'%escape(t).replace(META, DISABLED_META) if t else ''
|
||||||
@@ -1197,13 +1238,16 @@ def render(text,
|
|||||||
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
|
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
|
||||||
target = ' target="_blank"' if p == 'popup' else ''
|
target = ' target="_blank"' if p == 'popup' else ''
|
||||||
t = render(t, {}, {}, 'br', URL, environment, latex, autolinks,
|
t = render(t, {}, {}, 'br', URL, environment, latex, autolinks,
|
||||||
protolinks, class_prefix, id_prefix) if t else k
|
protolinks, class_prefix, id_prefix, pretty_print) if t else k
|
||||||
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
|
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
|
||||||
% dict(k=k, title=title, target=target, t=t)
|
% dict(k=k, title=title, target=target, t=t)
|
||||||
|
if t == 'NEWLINE' and not a:
|
||||||
|
return '<br />'+pp
|
||||||
return '<div class="anchor" id="%s">%s</div>' % (escape(id_prefix+t),
|
return '<div class="anchor" id="%s">%s</div>' % (escape(id_prefix+t),
|
||||||
render(a, {},{},'br', URL,
|
render(a, {},{},'br', URL,
|
||||||
environment, latex, autolinks,
|
environment, latex, autolinks,
|
||||||
protolinks, class_prefix, id_prefix))
|
protolinks, class_prefix,
|
||||||
|
id_prefix, pretty_print))
|
||||||
|
|
||||||
parts = text.split(LINK)
|
parts = text.split(LINK)
|
||||||
text = parts[0]
|
text = parts[0]
|
||||||
@@ -1230,9 +1274,9 @@ def render(text,
|
|||||||
if code[:1]=='\n': code=code[1:]
|
if code[:1]=='\n': code=code[1:]
|
||||||
if code[-1:]=='\n': code=code[:-1]
|
if code[-1:]=='\n': code=code[:-1]
|
||||||
if p:
|
if p:
|
||||||
return extra[b](code,p)
|
return str(extra[b](code,p))
|
||||||
else:
|
else:
|
||||||
return extra[b](code)
|
return str(extra[b](code))
|
||||||
elif b=='cite':
|
elif b=='cite':
|
||||||
return '['+','.join('<a href="#%s" class="%s">%s</a>' \
|
return '['+','.join('<a href="#%s" class="%s">%s</a>' \
|
||||||
% (d,b,d) \
|
% (d,b,d) \
|
||||||
@@ -1241,23 +1285,23 @@ def render(text,
|
|||||||
return LATEX % code.replace('"','\"').replace('\n',' ')
|
return LATEX % code.replace('"','\"').replace('\n',' ')
|
||||||
elif b in html_colors:
|
elif b in html_colors:
|
||||||
return '<span style="color: %s">%s</span>' \
|
return '<span style="color: %s">%s</span>' \
|
||||||
% (b, render(code,{},{},'br',URL,environment,latex,autolinks, protolinks))
|
% (b, render(code, {}, {}, 'br', URL, environment, latex,
|
||||||
|
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
|
||||||
elif b in ('c', 'color') and p:
|
elif b in ('c', 'color') and p:
|
||||||
c=p.split(':')
|
c=p.split(':')
|
||||||
fg='color: %s;' % c[0] if c[0] else ''
|
fg='color: %s;' % c[0] if c[0] else ''
|
||||||
bg='background-color: %s;' % c[1] if len(c)>1 and c[1] else ''
|
bg='background-color: %s;' % c[1] if len(c)>1 and c[1] else ''
|
||||||
return '<span style="%s%s">%s</span>' \
|
return '<span style="%s%s">%s</span>' \
|
||||||
% (fg, bg, render(code,{},{},'br', URL, environment, latex, autolinks, protolinks))
|
% (fg, bg, render(code, {}, {}, 'br', URL, environment, latex,
|
||||||
|
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
|
||||||
cls = ' class="%s%s"'%(class_prefix,b) if b and b != 'id' else ''
|
cls = ' class="%s%s"'%(class_prefix,b) if b and b != 'id' else ''
|
||||||
id = ' id="%s%s"'%(id_prefix,escape(p)) if p else ''
|
id = ' id="%s%s"'%(id_prefix,escape(p)) if p else ''
|
||||||
beg=(code[:1]=='\n')
|
beg=(code[:1]=='\n')
|
||||||
end=[None,-1][code[-1:]=='\n']
|
end=[None,-1][code[-1:]=='\n']
|
||||||
if beg and end:
|
if beg and end:
|
||||||
return '<pre><code%s%s>%s</code></pre>' % (cls, id, escape(code[1:-1]))
|
return '<pre><code%s%s>%s</code></pre>%s' % (cls, id, escape(code[1:-1]), pp)
|
||||||
return '<code%s%s>%s</code>' % (cls, id, escape(code[beg:end]))
|
return '<code%s%s>%s</code>' % (cls, id, escape(code[beg:end]))
|
||||||
|
|
||||||
text = regex_expand_meta.sub(expand_meta, text)
|
text = regex_expand_meta.sub(expand_meta, text)
|
||||||
text = text.translate(ttab_out)
|
|
||||||
|
|
||||||
if environment:
|
if environment:
|
||||||
def u2(match, environment=environment):
|
def u2(match, environment=environment):
|
||||||
@@ -1270,12 +1314,20 @@ def render(text,
|
|||||||
return str(f)
|
return str(f)
|
||||||
text = regex_env.sub(u2, text)
|
text = regex_env.sub(u2, text)
|
||||||
|
|
||||||
return text
|
return text.translate(ttab_out)
|
||||||
|
|
||||||
|
|
||||||
def markmin2html(text, extra={}, allowed={}, sep='p',
|
def markmin2html(text, extra={}, allowed={}, sep='p',
|
||||||
autolinks='default',protolinks='default'):
|
autolinks='default', protolinks='default',
|
||||||
|
class_prefix='', id_prefix='markmin_', pretty_print=False):
|
||||||
return render(text, extra, allowed, sep,
|
return render(text, extra, allowed, sep,
|
||||||
autolinks=autolinks, protolinks=protolinks)
|
autolinks=autolinks, protolinks=protolinks,
|
||||||
|
class_prefix=class_prefix, id_prefix=id_prefix,
|
||||||
|
pretty_print=pretty_print)
|
||||||
|
|
||||||
|
def run_doctests():
|
||||||
|
import doctest
|
||||||
|
doctest.testmod()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
@@ -1312,7 +1364,9 @@ if __name__ == '__main__':
|
|||||||
pre { background-color: #E0E0E0; padding: 5px; }
|
pre { background-color: #E0E0E0; padding: 5px; }
|
||||||
</style>""")[1:]
|
</style>""")[1:]
|
||||||
|
|
||||||
print html % dict(title="Markmin markup language", style=style, body=markmin2html(__doc__))
|
print html % dict(title="Markmin markup language",
|
||||||
|
style=style,
|
||||||
|
body=markmin2html(__doc__, pretty_print=True))
|
||||||
elif sys.argv[1:2] == ['-t']:
|
elif sys.argv[1:2] == ['-t']:
|
||||||
from timeit import Timer
|
from timeit import Timer
|
||||||
loops=1000
|
loops=1000
|
||||||
@@ -1338,7 +1392,8 @@ if __name__ == '__main__':
|
|||||||
else:
|
else:
|
||||||
markmin_style = ""
|
markmin_style = ""
|
||||||
|
|
||||||
print html % dict(title=sys.argv[1], style=markmin_style, body=markmin2html(markmin_text))
|
print html % dict(title=sys.argv[1], style=markmin_style,
|
||||||
|
body=markmin2html(markmin_text, pretty_print=True))
|
||||||
finally:
|
finally:
|
||||||
fargv.close()
|
fargv.close()
|
||||||
|
|
||||||
@@ -1348,4 +1403,5 @@ if __name__ == '__main__':
|
|||||||
print " -t - timeit __doc__ (for testing purpuse only)"
|
print " -t - timeit __doc__ (for testing purpuse only)"
|
||||||
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
|
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
|
||||||
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
|
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
|
||||||
doctest.testmod()
|
run_doctests()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -39,6 +39,7 @@ class WebClient(object):
|
|||||||
session_regex = SESSION_REGEX):
|
session_regex = SESSION_REGEX):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.postbacks = postbacks
|
self.postbacks = postbacks
|
||||||
|
self.forms = {}
|
||||||
self.history = []
|
self.history = []
|
||||||
self.cookies = {}
|
self.cookies = {}
|
||||||
self.default_headers = default_headers
|
self.default_headers = default_headers
|
||||||
|
|||||||
@@ -66,12 +66,14 @@ class _BaseImporter(object):
|
|||||||
help the management of this aspect.
|
help the management of this aspect.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._STANDARD_PYTHON_IMPORTER = _STANDARD_PYTHON_IMPORTER
|
||||||
def __call__(self, name, globals=None, locals=None,
|
def __call__(self, name, globals=None, locals=None,
|
||||||
fromlist=None, level=-1):
|
fromlist=None, level=-1):
|
||||||
"""
|
"""
|
||||||
The import method itself.
|
The import method itself.
|
||||||
"""
|
"""
|
||||||
return _STANDARD_PYTHON_IMPORTER(name,
|
return self._STANDARD_PYTHON_IMPORTER(name,
|
||||||
globals,
|
globals,
|
||||||
locals,
|
locals,
|
||||||
fromlist,
|
fromlist,
|
||||||
@@ -226,7 +228,8 @@ class _Web2pyImporter(_BaseImporter):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
global DEBUG
|
global DEBUG
|
||||||
super(_Web2pyImporter, self).__init__()
|
self.super_class = super(_Web2pyImporter, self)
|
||||||
|
self.super_class.__init__()
|
||||||
self.web2py_path = web2py_path
|
self.web2py_path = web2py_path
|
||||||
self.__web2py_path_os_path_sep = self.web2py_path+os.path.sep
|
self.__web2py_path_os_path_sep = self.web2py_path+os.path.sep
|
||||||
self.__web2py_path_os_path_sep_len = len(self.__web2py_path_os_path_sep)
|
self.__web2py_path_os_path_sep_len = len(self.__web2py_path_os_path_sep)
|
||||||
@@ -284,16 +287,16 @@ class _Web2pyImporter(_BaseImporter):
|
|||||||
globals, locals, fromlist, level)
|
globals, locals, fromlist, level)
|
||||||
else:
|
else:
|
||||||
# import like "from x import a, b, ..."
|
# import like "from x import a, b, ..."
|
||||||
return super(_Web2pyImporter, self) \
|
return self.super_class \
|
||||||
.__call__(modules_prefix+"."+name,
|
.__call__(modules_prefix+"."+name,
|
||||||
globals, locals, fromlist, level)
|
globals, locals, fromlist, level)
|
||||||
except ImportError, e:
|
except ImportError, e:
|
||||||
try:
|
try:
|
||||||
return super(_Web2pyImporter, self).__call__(name, globals, locals,
|
return self.super_class.__call__(name, globals, locals,
|
||||||
fromlist, level)
|
fromlist, level)
|
||||||
except ImportError, e1:
|
except ImportError, e1:
|
||||||
raise e
|
raise e
|
||||||
return super(_Web2pyImporter, self).__call__(name, globals, locals,
|
return self.super_class.__call__(name, globals, locals,
|
||||||
fromlist, level)
|
fromlist, level)
|
||||||
|
|
||||||
def __import__dot(self, prefix, name, globals, locals, fromlist,
|
def __import__dot(self, prefix, name, globals, locals, fromlist,
|
||||||
|
|||||||
+341
-281
File diff suppressed because it is too large
Load Diff
+28
-42
@@ -12,13 +12,14 @@ Plural subsystem is created by Vladyslav Kozlovskyy (Ukraine)
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import pkgutil
|
||||||
from utf8 import Utf8
|
from utf8 import Utf8
|
||||||
from cgi import escape
|
from cgi import escape
|
||||||
import portalocker
|
import portalocker
|
||||||
import logging
|
import logging
|
||||||
import marshal
|
import marshal
|
||||||
import copy_reg
|
import copy_reg
|
||||||
from fileutils import abspath, listdir
|
from fileutils import listdir
|
||||||
import settings
|
import settings
|
||||||
from cfs import getcfs
|
from cfs import getcfs
|
||||||
from thread import allocate_lock
|
from thread import allocate_lock
|
||||||
@@ -31,6 +32,8 @@ __all__ = ['translator', 'findT', 'update_all_languages']
|
|||||||
ospath = os.path
|
ospath = os.path
|
||||||
ostat = os.stat
|
ostat = os.stat
|
||||||
osep = os.sep
|
osep = os.sep
|
||||||
|
pjoin = os.path.join
|
||||||
|
pdirname = os.path.dirname
|
||||||
isdir = os.path.isdir
|
isdir = os.path.isdir
|
||||||
is_gae = settings.global_settings.web2py_runtime_gae
|
is_gae = settings.global_settings.web2py_runtime_gae
|
||||||
|
|
||||||
@@ -80,7 +83,6 @@ regex_backslash = re.compile(r"\\([\\{}%])")
|
|||||||
regex_plural = re.compile('%({.+?})')
|
regex_plural = re.compile('%({.+?})')
|
||||||
regex_plural_dict = re.compile('^{(?P<w>[^()[\]][^()[\]]*?)\((?P<n>[^()\[\]]+)\)}$') # %%{word(varname or number)}
|
regex_plural_dict = re.compile('^{(?P<w>[^()[\]][^()[\]]*?)\((?P<n>[^()\[\]]+)\)}$') # %%{word(varname or number)}
|
||||||
regex_plural_tuple = re.compile('^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$') # %%{word[index]} or %%{word}
|
regex_plural_tuple = re.compile('^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$') # %%{word[index]} or %%{word}
|
||||||
regex_plural_rules = re.compile('^plural_rules-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$')
|
|
||||||
|
|
||||||
# UTF8 helper functions
|
# UTF8 helper functions
|
||||||
def upper_fun(s):
|
def upper_fun(s):
|
||||||
@@ -213,47 +215,30 @@ def read_possible_languages(appdir):
|
|||||||
langs['en'] = ('en', 'English', 0)
|
langs['en'] = ('en', 'English', 0)
|
||||||
return langs
|
return langs
|
||||||
|
|
||||||
def read_global_plural_rules(filename):
|
|
||||||
"""
|
|
||||||
retrieve plural rules from rules/*plural_rules-lang*.py file.
|
|
||||||
|
|
||||||
args:
|
|
||||||
filename (str): plural_rules filename
|
|
||||||
|
|
||||||
returns:
|
|
||||||
(nplurals, get_plural_id, construct_plural_form, status)
|
|
||||||
e.g.: (3, <function>, <function>, ok)
|
|
||||||
"""
|
|
||||||
env = {}
|
|
||||||
data = portalocker.read_locked(filename)
|
|
||||||
try:
|
|
||||||
exec(data) in env
|
|
||||||
status='ok'
|
|
||||||
except Exception, e:
|
|
||||||
status='Syntax error in %s (%s)' % (filename, e)
|
|
||||||
logging.error(status)
|
|
||||||
nplurals = env.get('nplurals', DEFAULT_NPLURALS)
|
|
||||||
get_plural_id = env.get('get_plural_id', DEFAULT_GET_PLURAL_ID)
|
|
||||||
construct_plural_form = env.get('construct_plural_form',
|
|
||||||
DEFAULT_CONSTRUCTOR_PLURAL_FORM)
|
|
||||||
return (nplurals, get_plural_id, construct_plural_form, status)
|
|
||||||
|
|
||||||
|
|
||||||
def read_possible_plurals():
|
def read_possible_plurals():
|
||||||
"""
|
"""
|
||||||
create list of all possible plural rules files
|
create list of all possible plural rules files
|
||||||
result is cached to increase speed
|
result is cached to increase speed
|
||||||
"""
|
"""
|
||||||
pdir = abspath('gluon','contrib','rules')
|
try:
|
||||||
|
import gluon.contrib.plural_rules as package
|
||||||
plurals = {}
|
plurals = {}
|
||||||
# scan rules directory for plural_rules-*.py files:
|
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
|
||||||
for pname in os.listdir(pdir):
|
if len(modname)==2:
|
||||||
if not isdir(pname) and regex_plural_rules.match(pname):
|
module = __import__(package.__name__+'.'+modname)
|
||||||
lang = pname[13:-3]
|
lang = modname
|
||||||
fname = ospath.join(pdir, pname)
|
pname = modname+'.py'
|
||||||
n, f1, f2, status = read_global_plural_rules(fname)
|
nplurals = getattr(module,'nplurals', DEFAULT_NPLURALS)
|
||||||
if status == 'ok':
|
get_plural_id = getattr(
|
||||||
plurals[lang] = (lang, n, f1, f2, pname)
|
module,'get_plural_id',
|
||||||
|
DEFAULT_GET_PLURAL_ID)
|
||||||
|
construct_plural_form = getattr(
|
||||||
|
module,'construct_plural_form',
|
||||||
|
DEFAULT_CONSTRUCTOR_PLURAL_FORM)
|
||||||
|
plurals[lang] = (lang, nplurals, get_plural_id,
|
||||||
|
construct_plural_form, pname)
|
||||||
|
except ImportError:
|
||||||
|
logging.warn('Unable to import plural rules')
|
||||||
plurals['default'] = ('default',
|
plurals['default'] = ('default',
|
||||||
DEFAULT_NPLURALS,
|
DEFAULT_NPLURALS,
|
||||||
DEFAULT_GET_PLURAL_ID,
|
DEFAULT_GET_PLURAL_ID,
|
||||||
@@ -505,7 +490,7 @@ class translator(object):
|
|||||||
if int(n)==1:
|
if int(n)==1:
|
||||||
return word
|
return word
|
||||||
elif word:
|
elif word:
|
||||||
id = min(int(n)-1,1) # self.get_plural_id(abs(int(n)))
|
id = self.get_plural_id(abs(int(n)))
|
||||||
# id = 0 first plural form
|
# id = 0 first plural form
|
||||||
# id = 1 second plural form
|
# id = 1 second plural form
|
||||||
# etc.
|
# etc.
|
||||||
@@ -815,8 +800,8 @@ def findT(path, language='en'):
|
|||||||
"""
|
"""
|
||||||
must be run by the admin app
|
must be run by the admin app
|
||||||
"""
|
"""
|
||||||
filename = ospath.join(path, 'languages', language + '.py')
|
lang_file = ospath.join(path, 'languages', language + '.py')
|
||||||
sentences = read_dict(filename)
|
sentences = read_dict(lang_file)
|
||||||
mp = ospath.join(path, 'models')
|
mp = ospath.join(path, 'models')
|
||||||
cp = ospath.join(path, 'controllers')
|
cp = ospath.join(path, 'controllers')
|
||||||
vp = ospath.join(path, 'views')
|
vp = ospath.join(path, 'views')
|
||||||
@@ -845,8 +830,9 @@ def findT(path, language='en'):
|
|||||||
'en' if language in ('default', 'en') else language)
|
'en' if language in ('default', 'en') else language)
|
||||||
if not '!langname!' in sentences:
|
if not '!langname!' in sentences:
|
||||||
sentences['!langname!'] = (
|
sentences['!langname!'] = (
|
||||||
'English' if language in ('default', 'en') else sentences['!langcode!'])
|
'English' if language in ('default', 'en')
|
||||||
write_dict(filename, sentences)
|
else sentences['!langcode!'])
|
||||||
|
write_dict(lang_file, sentences)
|
||||||
|
|
||||||
### important to allow safe session.flash=T(....)
|
### important to allow safe session.flash=T(....)
|
||||||
def lazyT_unpickle(data):
|
def lazyT_unpickle(data):
|
||||||
|
|||||||
+16
-29
@@ -30,7 +30,7 @@ import string
|
|||||||
import urllib2
|
import urllib2
|
||||||
from thread import allocate_lock
|
from thread import allocate_lock
|
||||||
|
|
||||||
from fileutils import abspath, write_file, parse_version
|
from fileutils import abspath, write_file, parse_version, copystream
|
||||||
from settings import global_settings
|
from settings import global_settings
|
||||||
from admin import add_path_first, create_missing_folders, create_missing_app_folders
|
from admin import add_path_first, create_missing_folders, create_missing_app_folders
|
||||||
from globals import current
|
from globals import current
|
||||||
@@ -84,7 +84,6 @@ from http import HTTP, redirect
|
|||||||
from globals import Request, Response, Session
|
from globals import Request, Response, Session
|
||||||
from compileapp import build_environment, run_models_in, \
|
from compileapp import build_environment, run_models_in, \
|
||||||
run_controller_in, run_view_in
|
run_controller_in, run_view_in
|
||||||
from fileutils import copystream, parse_version
|
|
||||||
from contenttype import contenttype
|
from contenttype import contenttype
|
||||||
from dal import BaseAdapter
|
from dal import BaseAdapter
|
||||||
from settings import global_settings
|
from settings import global_settings
|
||||||
@@ -92,7 +91,8 @@ from validators import CRYPT
|
|||||||
from cache import Cache
|
from cache import Cache
|
||||||
from html import URL, xmlescape
|
from html import URL, xmlescape
|
||||||
from utils import is_valid_ip_address
|
from utils import is_valid_ip_address
|
||||||
from rewrite import load, url_in, thread as rwthread, try_rewrite_on_error
|
from rewrite import load, url_in, thread as rwthread, \
|
||||||
|
try_rewrite_on_error, fixup_missing_path_info
|
||||||
import newcron
|
import newcron
|
||||||
|
|
||||||
__all__ = ['wsgibase', 'save_password', 'appfactory', 'HttpServer']
|
__all__ = ['wsgibase', 'save_password', 'appfactory', 'HttpServer']
|
||||||
@@ -149,10 +149,11 @@ def copystream_progress(request, chunk_size= 10**5):
|
|||||||
and stores progress upload status in cache.ram
|
and stores progress upload status in cache.ram
|
||||||
X-Progress-ID:length and X-Progress-ID:uploaded
|
X-Progress-ID:length and X-Progress-ID:uploaded
|
||||||
"""
|
"""
|
||||||
if not request.env.content_length:
|
env = request.env
|
||||||
|
if not env.content_length:
|
||||||
return cStringIO.StringIO()
|
return cStringIO.StringIO()
|
||||||
source = request.env.wsgi_input
|
source = env.wsgi_input
|
||||||
size = int(request.env.content_length)
|
size = int(env.content_length)
|
||||||
dest = tempfile.TemporaryFile()
|
dest = tempfile.TemporaryFile()
|
||||||
if not 'X-Progress-ID' in request.vars:
|
if not 'X-Progress-ID' in request.vars:
|
||||||
copystream(source, dest, size, chunk_size)
|
copystream(source, dest, size, chunk_size)
|
||||||
@@ -275,7 +276,8 @@ def environ_aux(environ,request):
|
|||||||
def parse_get_post_vars(request, environ):
|
def parse_get_post_vars(request, environ):
|
||||||
|
|
||||||
# always parse variables in URL for GET, POST, PUT, DELETE, etc. in get_vars
|
# always parse variables in URL for GET, POST, PUT, DELETE, etc. in get_vars
|
||||||
dget = cgi.parse_qsl(request.env.query_string or '', keep_blank_values=1)
|
env = request.env
|
||||||
|
dget = cgi.parse_qsl(env.query_string or '', keep_blank_values=1)
|
||||||
for (key, value) in dget:
|
for (key, value) in dget:
|
||||||
if key in request.get_vars:
|
if key in request.get_vars:
|
||||||
if isinstance(request.get_vars[key], list):
|
if isinstance(request.get_vars[key], list):
|
||||||
@@ -291,7 +293,7 @@ def parse_get_post_vars(request, environ):
|
|||||||
request.body = body = copystream_progress(request)
|
request.body = body = copystream_progress(request)
|
||||||
except IOError:
|
except IOError:
|
||||||
raise HTTP(400,"Bad Request - HTTP body is incomplete")
|
raise HTTP(400,"Bad Request - HTTP body is incomplete")
|
||||||
if (body and request.env.request_method in ('POST', 'PUT', 'BOTH')):
|
if (body and env.request_method in ('POST', 'PUT', 'BOTH')):
|
||||||
dpost = cgi.FieldStorage(fp=body,environ=environ,keep_blank_values=1)
|
dpost = cgi.FieldStorage(fp=body,environ=environ,keep_blank_values=1)
|
||||||
# The same detection used by FieldStorage to detect multipart POSTs
|
# The same detection used by FieldStorage to detect multipart POSTs
|
||||||
is_multipart = dpost.type[:10] == 'multipart/'
|
is_multipart = dpost.type[:10] == 'multipart/'
|
||||||
@@ -383,21 +385,7 @@ def wsgibase(environ, responder):
|
|||||||
# serve file if static
|
# serve file if static
|
||||||
# ##################################################
|
# ##################################################
|
||||||
|
|
||||||
eget = environ.get
|
fixup_missing_path_info(environ)
|
||||||
if not eget('PATH_INFO',None) and eget('REQUEST_URI',None):
|
|
||||||
# for fcgi, get path_info and
|
|
||||||
# query_string from request_uri
|
|
||||||
items = environ['REQUEST_URI'].split('?')
|
|
||||||
environ['PATH_INFO'] = items[0]
|
|
||||||
if len(items) > 1:
|
|
||||||
environ['QUERY_STRING'] = items[1]
|
|
||||||
else:
|
|
||||||
environ['QUERY_STRING'] = ''
|
|
||||||
if not eget('HTTP_HOST',None):
|
|
||||||
environ['HTTP_HOST'] = \
|
|
||||||
eget('SERVER_NAME')+':'+eget('SERVER_PORT')
|
|
||||||
|
|
||||||
|
|
||||||
(static_file, environ) = url_in(request, environ)
|
(static_file, environ) = url_in(request, environ)
|
||||||
|
|
||||||
if static_file:
|
if static_file:
|
||||||
@@ -434,6 +422,7 @@ def wsgibase(environ, responder):
|
|||||||
is_https = env.wsgi_url_scheme \
|
is_https = env.wsgi_url_scheme \
|
||||||
in ['https', 'HTTPS'] or env.https=='on')
|
in ['https', 'HTTPS'] or env.https=='on')
|
||||||
request.uuid = request.compute_uuid() # requires client
|
request.uuid = request.compute_uuid() # requires client
|
||||||
|
request.url = environ['PATH_INFO']
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
# access the requested application
|
# access the requested application
|
||||||
@@ -456,9 +445,6 @@ def wsgibase(environ, responder):
|
|||||||
elif not request.is_local and \
|
elif not request.is_local and \
|
||||||
exists(pjoin(request.folder,'DISABLED')):
|
exists(pjoin(request.folder,'DISABLED')):
|
||||||
raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>")
|
raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>")
|
||||||
request.url = URL(r=request,
|
|
||||||
args=request.args,
|
|
||||||
extension=request.raw_extension)
|
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
# build missing folders
|
# build missing folders
|
||||||
@@ -488,9 +474,9 @@ def wsgibase(environ, responder):
|
|||||||
# load cookies
|
# load cookies
|
||||||
# ##################################################
|
# ##################################################
|
||||||
|
|
||||||
if request.env.http_cookie:
|
if env.http_cookie:
|
||||||
try:
|
try:
|
||||||
request.cookies.load(request.env.http_cookie)
|
request.cookies.load(env.http_cookie)
|
||||||
except Cookie.CookieError, e:
|
except Cookie.CookieError, e:
|
||||||
pass # invalid cookies
|
pass # invalid cookies
|
||||||
|
|
||||||
@@ -498,6 +484,7 @@ def wsgibase(environ, responder):
|
|||||||
# try load session or create new session file
|
# try load session or create new session file
|
||||||
# ##################################################
|
# ##################################################
|
||||||
|
|
||||||
|
if not env.web2py_disable_session:
|
||||||
session.connect(request, response)
|
session.connect(request, response)
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
@@ -562,7 +549,7 @@ def wsgibase(environ, responder):
|
|||||||
# ##################################################
|
# ##################################################
|
||||||
|
|
||||||
if request.cid:
|
if request.cid:
|
||||||
rheaders = response.headers
|
rheaders = http_response.headers
|
||||||
if response.flash and \
|
if response.flash and \
|
||||||
not 'web2py-component-flash' in rheaders:
|
not 'web2py-component-flash' in rheaders:
|
||||||
rheaders['web2py-component-flash'] = \
|
rheaders['web2py-component-flash'] = \
|
||||||
|
|||||||
+40
-18
@@ -38,6 +38,7 @@ thread = threading.local() # thread-local storage for routing params
|
|||||||
regex_at = re.compile(r'(?<!\\)\$[a-zA-Z]\w*')
|
regex_at = re.compile(r'(?<!\\)\$[a-zA-Z]\w*')
|
||||||
regex_anything = re.compile(r'(?<!\\)\$anything')
|
regex_anything = re.compile(r'(?<!\\)\$anything')
|
||||||
regex_redirect = re.compile(r'(\d+)->(.*)')
|
regex_redirect = re.compile(r'(\d+)->(.*)')
|
||||||
|
regex_full_url = re.compile(r'^(?P<scheme>http|https|HTTP|HTTPS)\://(?P<host>[^/]*)(?P<uri>.*)')
|
||||||
|
|
||||||
def _router_default():
|
def _router_default():
|
||||||
"return new copy of default base router"
|
"return new copy of default base router"
|
||||||
@@ -134,6 +135,27 @@ ROUTER_BASE_KEYS = set(
|
|||||||
# filter_err: helper for doctest & unittest
|
# filter_err: helper for doctest & unittest
|
||||||
# regex_filter_out: doctest
|
# regex_filter_out: doctest
|
||||||
|
|
||||||
|
def fixup_missing_path_info(environ):
|
||||||
|
eget = environ.get
|
||||||
|
path_info = eget('PATH_INFO')
|
||||||
|
request_uri = eget('REQUEST_URI')
|
||||||
|
if not path_info and request_uri:
|
||||||
|
# for fcgi, get path_info and
|
||||||
|
# query_string from request_uri
|
||||||
|
items = request_uri.split('?')
|
||||||
|
path_info = environ['PATH_INFO'] = items[0]
|
||||||
|
environ['QUERY_STRING'] = items[1] if len(items) > 1 else ''
|
||||||
|
elif not request_uri:
|
||||||
|
query_string = eget('QUERY_STRING')
|
||||||
|
if query_string:
|
||||||
|
environ['REQUEST_URI'] = '%s?%s' % (path_info,query_string)
|
||||||
|
else:
|
||||||
|
environ['REQUEST_URI'] = path_info
|
||||||
|
if not eget('HTTP_HOST'):
|
||||||
|
environ['HTTP_HOST'] = \
|
||||||
|
'%s:%s' % (eget('SERVER_NAME'),eget('SERVER_PORT'))
|
||||||
|
|
||||||
|
|
||||||
def url_in(request, environ):
|
def url_in(request, environ):
|
||||||
"parse and rewrite incoming URL"
|
"parse and rewrite incoming URL"
|
||||||
if routers:
|
if routers:
|
||||||
@@ -286,8 +308,8 @@ def load(routes='routes.py', app=None, data=None, rdict=None):
|
|||||||
|
|
||||||
for sym in ('routes_app', 'routes_in', 'routes_out'):
|
for sym in ('routes_app', 'routes_in', 'routes_out'):
|
||||||
if sym in symbols:
|
if sym in symbols:
|
||||||
for (k, v) in symbols[sym]:
|
for items in symbols[sym]:
|
||||||
p[sym].append(compile_regex(k, v))
|
p[sym].append(compile_regex(*items))
|
||||||
for sym in ('routes_onerror', 'routes_apps_raw',
|
for sym in ('routes_onerror', 'routes_apps_raw',
|
||||||
'error_handler','error_message', 'error_message_ticket',
|
'error_handler','error_message', 'error_message_ticket',
|
||||||
'default_application','default_controller', 'default_function',
|
'default_application','default_controller', 'default_function',
|
||||||
@@ -349,7 +371,7 @@ def load(routes='routes.py', app=None, data=None, rdict=None):
|
|||||||
log_rewrite('URL rewrite is on. configuration in %s' % path)
|
log_rewrite('URL rewrite is on. configuration in %s' % path)
|
||||||
|
|
||||||
|
|
||||||
def compile_regex(k, v):
|
def compile_regex(k, v, env=None):
|
||||||
"""
|
"""
|
||||||
Preprocess and compile the regular expressions in routes_app/in/out
|
Preprocess and compile the regular expressions in routes_app/in/out
|
||||||
The resulting regex will match a pattern of the form:
|
The resulting regex will match a pattern of the form:
|
||||||
@@ -383,7 +405,7 @@ def compile_regex(k, v):
|
|||||||
# same for replacement pattern, but with \g
|
# same for replacement pattern, but with \g
|
||||||
for item in regex_at.findall(v):
|
for item in regex_at.findall(v):
|
||||||
v = v.replace(item, r'\g<%s>' % item[1:])
|
v = v.replace(item, r'\g<%s>' % item[1:])
|
||||||
return (re.compile(k, re.DOTALL), v)
|
return (re.compile(k, re.DOTALL), v, env or {})
|
||||||
|
|
||||||
def load_routers(all_apps):
|
def load_routers(all_apps):
|
||||||
"load-time post-processing of routers"
|
"load-time post-processing of routers"
|
||||||
@@ -497,8 +519,9 @@ def regex_uri(e, regexes, tag, default=None):
|
|||||||
(e.get('REMOTE_ADDR','localhost'),
|
(e.get('REMOTE_ADDR','localhost'),
|
||||||
e.get('wsgi.url_scheme', 'http').lower(), host,
|
e.get('wsgi.url_scheme', 'http').lower(), host,
|
||||||
e.get('REQUEST_METHOD', 'get').lower(), path)
|
e.get('REQUEST_METHOD', 'get').lower(), path)
|
||||||
for (regex, value) in regexes:
|
for (regex, value, custom_env) in regexes:
|
||||||
if regex.match(key):
|
if regex.match(key):
|
||||||
|
e.update(custom_env)
|
||||||
rewritten = regex.sub(value, key)
|
rewritten = regex.sub(value, key)
|
||||||
log_rewrite('%s: [%s] [%s] -> %s' % (tag, key, value, rewritten))
|
log_rewrite('%s: [%s] [%s] -> %s' % (tag, key, value, rewritten))
|
||||||
return rewritten
|
return rewritten
|
||||||
@@ -686,7 +709,7 @@ def regex_filter_out(url, e=None):
|
|||||||
e.get('request_method', 'get').lower(), items[0])
|
e.get('request_method', 'get').lower(), items[0])
|
||||||
else:
|
else:
|
||||||
items[0] = ':http://localhost:get %s' % items[0]
|
items[0] = ':http://localhost:get %s' % items[0]
|
||||||
for (regex, value) in thread.routes.routes_out:
|
for (regex, value, tmp) in thread.routes.routes_out:
|
||||||
if regex.match(items[0]):
|
if regex.match(items[0]):
|
||||||
rewritten = '?'.join([regex.sub(value, items[0])] + items[1:])
|
rewritten = '?'.join([regex.sub(value, items[0])] + items[1:])
|
||||||
log_rewrite('routes_out: [%s] -> %s' % (url, rewritten))
|
log_rewrite('routes_out: [%s] -> %s' % (url, rewritten))
|
||||||
@@ -695,11 +718,14 @@ def regex_filter_out(url, e=None):
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
def filter_url(url, method='get', remote='0.0.0.0', out=False, app=False, lang=None,
|
def filter_url(url, method='get', remote='0.0.0.0',
|
||||||
domain=(None,None), env=False, scheme=None, host=None, port=None):
|
out=False, app=False, lang=None,
|
||||||
"doctest/unittest interface to regex_filter_in() and regex_filter_out()"
|
domain=(None,None), env=False, scheme=None,
|
||||||
regex_url = re.compile(r'^(?P<scheme>http|https|HTTP|HTTPS)\://(?P<host>[^/]*)(?P<uri>.*)')
|
host=None, port=None):
|
||||||
match = regex_url.match(url)
|
"""
|
||||||
|
doctest/unittest interface to regex_filter_in() and regex_filter_out()
|
||||||
|
"""
|
||||||
|
match = regex_full_url.match(url)
|
||||||
urlscheme = match.group('scheme').lower()
|
urlscheme = match.group('scheme').lower()
|
||||||
urlhost = match.group('host').lower()
|
urlhost = match.group('host').lower()
|
||||||
uri = match.group('uri')
|
uri = match.group('uri')
|
||||||
@@ -994,6 +1020,7 @@ class MapUrlIn(object):
|
|||||||
static_file = pjoin(self.request.env.applications_parent,
|
static_file = pjoin(self.request.env.applications_parent,
|
||||||
'applications', self.application,
|
'applications', self.application,
|
||||||
'static', file)
|
'static', file)
|
||||||
|
self.extension = None
|
||||||
log_rewrite("route: static=%s" % static_file)
|
log_rewrite("route: static=%s" % static_file)
|
||||||
return static_file
|
return static_file
|
||||||
|
|
||||||
@@ -1053,7 +1080,7 @@ class MapUrlIn(object):
|
|||||||
if self.map_hyphen:
|
if self.map_hyphen:
|
||||||
uri = uri.replace('_', '-')
|
uri = uri.replace('_', '-')
|
||||||
app = app.replace('_', '-')
|
app = app.replace('_', '-')
|
||||||
if self.extension != 'html':
|
if self.extension and self.extension != 'html':
|
||||||
uri += '.' + self.extension
|
uri += '.' + self.extension
|
||||||
if self.language:
|
if self.language:
|
||||||
uri = '/%s%s' % (self.language, uri)
|
uri = '/%s%s' % (self.language, uri)
|
||||||
@@ -1271,19 +1298,14 @@ def map_url_in(request, env, app=False):
|
|||||||
# handle mapping of lang/static to static/lang in externally-rewritten URLs
|
# handle mapping of lang/static to static/lang in externally-rewritten URLs
|
||||||
# in case we have to handle them ourselves
|
# in case we have to handle them ourselves
|
||||||
if map.languages and map.map_static is False and map.arg0 == 'static' and map.args(1) in map.languages:
|
if map.languages and map.map_static is False and map.arg0 == 'static' and map.args(1) in map.languages:
|
||||||
if 'es' in map.languages:
|
|
||||||
print 'handle static/lang %s' % map.args(1)
|
|
||||||
map.map_controller()
|
map.map_controller()
|
||||||
map.map_language()
|
map.map_language()
|
||||||
else:
|
else:
|
||||||
if 'es' in map.languages:
|
|
||||||
print 'NO handle static/lang %s' % map.args(1)
|
|
||||||
map.map_language()
|
map.map_language()
|
||||||
map.map_controller()
|
map.map_controller()
|
||||||
static_file = map.map_static()
|
static_file = map.map_static()
|
||||||
if 'es' in map.languages:
|
|
||||||
print 'static_file=%s' % static_file
|
|
||||||
if static_file:
|
if static_file:
|
||||||
|
map.update_request()
|
||||||
return (static_file, map.env)
|
return (static_file, map.env)
|
||||||
map.map_function()
|
map.map_function()
|
||||||
map.validate_args()
|
map.validate_args()
|
||||||
|
|||||||
+14
-9
@@ -88,7 +88,7 @@ except:
|
|||||||
from simplejson import loads, dumps
|
from simplejson import loads, dumps
|
||||||
|
|
||||||
|
|
||||||
from gluon import DAL, Field, IS_NOT_EMPTY, IS_IN_SET, IS_NOT_IN_DB
|
from gluon import DAL, Field, IS_NOT_EMPTY, IS_IN_SET, IS_NOT_IN_DB, IS_INT_IN_RANGE
|
||||||
from gluon.utils import web2py_uuid
|
from gluon.utils import web2py_uuid
|
||||||
|
|
||||||
|
|
||||||
@@ -262,7 +262,8 @@ class MetaScheduler(threading.Thread):
|
|||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
while p.is_alive() and (time.time()-start < task.timeout):
|
while p.is_alive() and (
|
||||||
|
not task.timeout or time.time()-start < task.timeout):
|
||||||
if tout:
|
if tout:
|
||||||
try:
|
try:
|
||||||
logging.debug(' partial output saved')
|
logging.debug(' partial output saved')
|
||||||
@@ -453,15 +454,20 @@ class Scheduler(MetaScheduler):
|
|||||||
Field('args','text',default='[]',requires=TYPE(list)),
|
Field('args','text',default='[]',requires=TYPE(list)),
|
||||||
Field('vars','text',default='{}',requires=TYPE(dict)),
|
Field('vars','text',default='{}',requires=TYPE(dict)),
|
||||||
Field('enabled','boolean',default=True),
|
Field('enabled','boolean',default=True),
|
||||||
Field('start_time','datetime',default=now),
|
Field('start_time','datetime',default=now, requires=IS_NOT_EMPTY()),
|
||||||
Field('next_run_time','datetime',default=now),
|
Field('next_run_time','datetime',default=now),
|
||||||
Field('stop_time','datetime'),
|
Field('stop_time','datetime'),
|
||||||
Field('repeats','integer',default=1,comment="0=unlimited"),
|
Field('repeats','integer',default=1,comment="0=unlimited",
|
||||||
Field('retry_failed', 'integer', default=0, comment="-1=unlimited"),
|
requires=IS_INT_IN_RANGE(0, None)),
|
||||||
Field('period','integer',default=60,comment='seconds'),
|
Field('retry_failed', 'integer', default=0, comment="-1=unlimited",
|
||||||
Field('timeout','integer',default=60,comment='seconds'),
|
requires=IS_INT_IN_RANGE(-1, None)),
|
||||||
|
Field('period','integer',default=60,comment='seconds',
|
||||||
|
requires=IS_INT_IN_RANGE(0, None)),
|
||||||
|
Field('timeout','integer',default=60,comment='seconds',
|
||||||
|
requires=IS_INT_IN_RANGE(0, None)),
|
||||||
Field('sync_output', 'integer', default=0,
|
Field('sync_output', 'integer', default=0,
|
||||||
comment="update output every n sec: 0=never"),
|
comment="update output every n sec: 0=never",
|
||||||
|
requires=IS_INT_IN_RANGE(0, None)),
|
||||||
Field('times_run','integer',default=0,writable=False),
|
Field('times_run','integer',default=0,writable=False),
|
||||||
Field('times_failed','integer',default=0,writable=False),
|
Field('times_failed','integer',default=0,writable=False),
|
||||||
Field('last_run_time','datetime',writable=False,readable=False),
|
Field('last_run_time','datetime',writable=False,readable=False),
|
||||||
@@ -869,4 +875,3 @@ def main():
|
|||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
# this file exists for backward compatibility
|
# this file exists for backward compatibility
|
||||||
|
|
||||||
__all__ = ['DAL','Field','drivers']
|
__all__ = ['DAL','Field','DRIVERS']
|
||||||
|
|
||||||
from dal import DAL, Field, Table, Query, Set, Expression, Row, Rows, drivers, BaseAdapter, SQLField, SQLTable, SQLXorable, SQLQuery, SQLSet, SQLRows, SQLStorage, SQLDB, GQLDB, SQLALL, SQLCustomType
|
from dal import DAL, Field, Table, Query, Set, Expression, Row, Rows, DRIVERS, BaseAdapter, SQLField, SQLTable, SQLXorable, SQLQuery, SQLSet, SQLRows, SQLStorage, SQLDB, GQLDB, SQLALL, SQLCustomType
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+63
-44
@@ -24,7 +24,7 @@ from html import FORM, INPUT, LABEL, OPTION, SELECT, BUTTON
|
|||||||
from html import TABLE, THEAD, TBODY, TR, TD, TH, STYLE
|
from html import TABLE, THEAD, TBODY, TR, TD, TH, STYLE
|
||||||
from html import URL, truncate_string, FIELDSET
|
from html import URL, truncate_string, FIELDSET
|
||||||
from dal import DAL, Field, Table, Row, CALLABLETYPES, smart_query, \
|
from dal import DAL, Field, Table, Row, CALLABLETYPES, smart_query, \
|
||||||
bar_encode, regex_table_field, Reference
|
bar_encode, Reference, REGEX_TABLE_DOT_FIELD
|
||||||
from storage import Storage
|
from storage import Storage
|
||||||
from utils import md5_hash
|
from utils import md5_hash
|
||||||
from validators import IS_EMPTY_OR, IS_NOT_EMPTY, IS_LIST_OF, IS_DATE, \
|
from validators import IS_EMPTY_OR, IS_NOT_EMPTY, IS_LIST_OF, IS_DATE, \
|
||||||
@@ -702,17 +702,17 @@ def formstyle_bootstrap(form, fields):
|
|||||||
_submit = False
|
_submit = False
|
||||||
|
|
||||||
if isinstance(controls, INPUT):
|
if isinstance(controls, INPUT):
|
||||||
controls['_class'] = 'input-xlarge'
|
controls.add_class('input-xlarge')
|
||||||
if controls['_type'] == 'submit':
|
if controls['_type'] == 'submit':
|
||||||
# flag submit button
|
# flag submit button
|
||||||
_submit = True
|
_submit = True
|
||||||
controls['_class'] = 'btn btn-primary'
|
controls['_class'] = 'btn btn-primary'
|
||||||
|
|
||||||
if isinstance(controls, SELECT):
|
if isinstance(controls, SELECT):
|
||||||
controls['_class'] = 'input-xlarge'
|
controls.add_class('input-xlarge')
|
||||||
|
|
||||||
if isinstance(controls, TEXTAREA):
|
if isinstance(controls, TEXTAREA):
|
||||||
controls['_class'] = 'input-xlarge'
|
controls.add_class('input-xlarge')
|
||||||
|
|
||||||
if isinstance(label, LABEL):
|
if isinstance(label, LABEL):
|
||||||
label['_class'] = 'control-label'
|
label['_class'] = 'control-label'
|
||||||
@@ -874,8 +874,9 @@ class SQLFORM(FORM):
|
|||||||
# if no fields are provided, build it from the provided table
|
# if no fields are provided, build it from the provided table
|
||||||
# will only use writable or readable fields, unless forced to ignore
|
# will only use writable or readable fields, unless forced to ignore
|
||||||
if fields is None:
|
if fields is None:
|
||||||
fields = [f.name for f in table if (
|
fields = [f.name for f in table if
|
||||||
ignore_rw or f.writable or f.readable) and not f.compute]
|
(ignore_rw or f.writable or f.readable) and
|
||||||
|
(readonly or not f.compute)]
|
||||||
self.fields = fields
|
self.fields = fields
|
||||||
|
|
||||||
# make sure we have an id
|
# make sure we have an id
|
||||||
@@ -1376,8 +1377,8 @@ class SQLFORM(FORM):
|
|||||||
# this should never happen but seems to happen to some
|
# this should never happen but seems to happen to some
|
||||||
del fields['delete_this_record']
|
del fields['delete_this_record']
|
||||||
for field in self.table:
|
for field in self.table:
|
||||||
if not field.name in fields and field.writable==False \
|
if not field.name in fields and field.writable is False \
|
||||||
and field.update is None:
|
and field.update is None and field.compute is None:
|
||||||
if record_id and self.record:
|
if record_id and self.record:
|
||||||
fields[field.name] = self.record[field.name]
|
fields[field.name] = self.record[field.name]
|
||||||
elif not self.table[field.name].default is None:
|
elif not self.table[field.name].default is None:
|
||||||
@@ -1498,11 +1499,10 @@ class SQLFORM(FORM):
|
|||||||
selectfields = []
|
selectfields = []
|
||||||
for field in fields:
|
for field in fields:
|
||||||
name = str(field).replace('.','-')
|
name = str(field).replace('.','-')
|
||||||
criterion = []
|
|
||||||
options = search_options.get(field.type,None)
|
options = search_options.get(field.type,None)
|
||||||
if options:
|
if options:
|
||||||
label = isinstance(field.label,str) and T(field.label) or field.label
|
label = isinstance(field.label,str) and T(field.label) or field.label
|
||||||
selectfields.append((str(field),label))
|
selectfields.append(OPTION(label, _value=str(field)))
|
||||||
operators = SELECT(*[T(option) for option in options])
|
operators = SELECT(*[T(option) for option in options])
|
||||||
if field.type=='boolean':
|
if field.type=='boolean':
|
||||||
value_input = SELECT(
|
value_input = SELECT(
|
||||||
@@ -1510,28 +1510,37 @@ class SQLFORM(FORM):
|
|||||||
OPTION(T("False"),_value="F"),
|
OPTION(T("False"),_value="F"),
|
||||||
_id="w2p_value_"+name)
|
_id="w2p_value_"+name)
|
||||||
else:
|
else:
|
||||||
value_input = INPUT(_type='text',_id="w2p_value_"+name,
|
value_input = INPUT(_type='text',
|
||||||
|
_id="w2p_value_"+name,
|
||||||
_class=field.type)
|
_class=field.type)
|
||||||
new_button = INPUT(
|
new_button = INPUT(
|
||||||
_type="button", _value=T('New'),_class="btn",
|
_type="button", _value=T('New'),_class="btn",
|
||||||
_onclick="w2p_build_query('new','"+str(field)+"')")
|
_onclick="w2p_build_query('new','%s')" % field)
|
||||||
and_button = INPUT(
|
and_button = INPUT(
|
||||||
_type="button", _value=T('And'),_class="btn",
|
_type="button", _value=T('And'),_class="btn",
|
||||||
_onclick="w2p_build_query('and','"+str(field)+"')")
|
_onclick="w2p_build_query('and','%s')" % field)
|
||||||
or_button = INPUT(
|
or_button = INPUT(
|
||||||
_type="button", _value=T('Or'),_class="btn",
|
_type="button", _value=T('Or'),_class="btn",
|
||||||
_onclick="w2p_build_query('or','"+str(field)+"')")
|
_onclick="w2p_build_query('or','%s')" % field)
|
||||||
|
close_button = INPUT(
|
||||||
|
_type="button", _value=T('Close'),_class="btn",
|
||||||
|
_onclick="jQuery('#w2p_query_panel').slideUp()")
|
||||||
|
|
||||||
|
criteria.append(DIV(
|
||||||
|
operators,value_input,new_button,
|
||||||
|
and_button,or_button,close_button,
|
||||||
|
_id='w2p_field_%s' % name,
|
||||||
|
_class='w2p_query_row hidden',
|
||||||
|
_style='display:inline'))
|
||||||
|
|
||||||
criterion.extend([operators,value_input,new_button,and_button,or_button])
|
|
||||||
criteria.append(DIV(criterion, _id='w2p_field_%s' % name,
|
|
||||||
_class='w2p_query_row hidden'))
|
|
||||||
criteria.insert(0,SELECT(
|
criteria.insert(0,SELECT(
|
||||||
_id="w2p_query_fields",
|
_id="w2p_query_fields",
|
||||||
_onchange="jQuery('.w2p_query_row').hide();jQuery('#w2p_field_'+jQuery('#w2p_query_fields').val().replace('.','-')).show();",
|
_onchange="jQuery('.w2p_query_row').hide();jQuery('#w2p_field_'+jQuery('#w2p_query_fields').val().replace('.','-')).show();",
|
||||||
*[OPTION(label, _value=fname) for fname,label in selectfields]))
|
_style='float:left',
|
||||||
|
*selectfields))
|
||||||
|
|
||||||
fadd = SCRIPT("""
|
fadd = SCRIPT("""
|
||||||
jQuery('#w2p_query_panel input,#w2p_query_panel select').css(
|
jQuery('#w2p_query_panel input,#w2p_query_panel select').css('width','auto');
|
||||||
'width','auto').css('float','left');
|
|
||||||
jQuery(function(){web2py_ajax_fields('#w2p_query_panel');});
|
jQuery(function(){web2py_ajax_fields('#w2p_query_panel');});
|
||||||
function w2p_build_query(aggregator,a) {
|
function w2p_build_query(aggregator,a) {
|
||||||
var b=a.replace('.','-');
|
var b=a.replace('.','-');
|
||||||
@@ -1541,10 +1550,11 @@ class SQLFORM(FORM):
|
|||||||
var k=jQuery('#web2py_keywords');
|
var k=jQuery('#web2py_keywords');
|
||||||
var v=k.val();
|
var v=k.val();
|
||||||
if(aggregator=='new') k.val(s); else k.val((v?(v+' '+ aggregator +' '):'')+s);
|
if(aggregator=='new') k.val(s); else k.val((v?(v+' '+ aggregator +' '):'')+s);
|
||||||
jQuery('#w2p_query_panel').slideUp();
|
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
return CAT(DIV(_id="w2p_query_panel",_class='hidden',*criteria),fadd)
|
return CAT(
|
||||||
|
DIV(_id="w2p_query_panel",_class='hidden',*criteria),fadd)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -1656,7 +1666,7 @@ class SQLFORM(FORM):
|
|||||||
if user_signature:
|
if user_signature:
|
||||||
if (args != request.args and user_signature and \
|
if (args != request.args and user_signature and \
|
||||||
not URL.verify(request,user_signature=user_signature)) or \
|
not URL.verify(request,user_signature=user_signature)) or \
|
||||||
(not session.auth.user and \
|
(not (session.auth and session.auth.user) and \
|
||||||
('edit' in request.args or \
|
('edit' in request.args or \
|
||||||
'create' in request.args or \
|
'create' in request.args or \
|
||||||
'delete' in request.args)):
|
'delete' in request.args)):
|
||||||
@@ -1664,7 +1674,8 @@ class SQLFORM(FORM):
|
|||||||
redirect(referrer)
|
redirect(referrer)
|
||||||
|
|
||||||
def gridbutton(buttonclass='buttonadd', buttontext='Add',
|
def gridbutton(buttonclass='buttonadd', buttontext='Add',
|
||||||
buttonurl=url(args=[]),callback=None,delete=None,trap=True):
|
buttonurl=url(args=[]), callback=None,
|
||||||
|
delete=None, trap=True):
|
||||||
if showbuttontext:
|
if showbuttontext:
|
||||||
if callback:
|
if callback:
|
||||||
return A(SPAN(_class=ui.get(buttonclass)),
|
return A(SPAN(_class=ui.get(buttonclass)),
|
||||||
@@ -1826,14 +1837,15 @@ class SQLFORM(FORM):
|
|||||||
try:
|
try:
|
||||||
dbset = dbset(SQLFORM.build_query(
|
dbset = dbset(SQLFORM.build_query(
|
||||||
fields,request.vars.get('keywords','')))
|
fields,request.vars.get('keywords','')))
|
||||||
rows = dbset.select()
|
rows = dbset.select(cacheable=True)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
response.flash = T('Internal Error')
|
response.flash = T('Internal Error')
|
||||||
rows = []
|
rows = []
|
||||||
else:
|
else:
|
||||||
rows = dbset.select()
|
rows = dbset.select(cacheable=True)
|
||||||
else:
|
else:
|
||||||
rows = dbset.select(left=left,orderby=orderby,*columns)
|
rows = dbset.select(left=left,orderby=orderby,
|
||||||
|
cacheable=True*columns)
|
||||||
|
|
||||||
if export_type in exportManager:
|
if export_type in exportManager:
|
||||||
value = exportManager[export_type]
|
value = exportManager[export_type]
|
||||||
@@ -1853,12 +1865,6 @@ class SQLFORM(FORM):
|
|||||||
|
|
||||||
session['_web2py_grid_referrer_'+formname] = url2(vars=request.vars)
|
session['_web2py_grid_referrer_'+formname] = url2(vars=request.vars)
|
||||||
console = DIV(_class='web2py_console %(header)s %(cornertop)s' % ui)
|
console = DIV(_class='web2py_console %(header)s %(cornertop)s' % ui)
|
||||||
if create:
|
|
||||||
console.append(gridbutton(
|
|
||||||
buttonclass='buttonadd',
|
|
||||||
buttontext='Add',
|
|
||||||
buttonurl=url(args=['new',tablename])))
|
|
||||||
|
|
||||||
error = None
|
error = None
|
||||||
if searchable:
|
if searchable:
|
||||||
sfields = reduce(lambda a,b:a+b,
|
sfields = reduce(lambda a,b:a+b,
|
||||||
@@ -1867,13 +1873,13 @@ class SQLFORM(FORM):
|
|||||||
search_widget = search_widget[tablename]
|
search_widget = search_widget[tablename]
|
||||||
if search_widget=='default':
|
if search_widget=='default':
|
||||||
search_menu = SQLFORM.search_menu(sfields)
|
search_menu = SQLFORM.search_menu(sfields)
|
||||||
search_widget = lambda sfield, url: FORM(
|
search_widget = lambda sfield, url: DIV(FORM(
|
||||||
INPUT(_name='keywords',_value=request.vars.keywords,
|
INPUT(_name='keywords',_value=request.vars.keywords,
|
||||||
_id='web2py_keywords',_onfocus="jQuery('#w2p_query_fields').change();jQuery('#w2p_query_panel').slideDown();"),
|
_id='web2py_keywords',_onfocus="jQuery('#w2p_query_fields').change();jQuery('#w2p_query_panel').slideDown();"),
|
||||||
INPUT(_type='submit',_value=T('Search'),_class="btn"),
|
INPUT(_type='submit',_value=T('Search'),_class="btn"),
|
||||||
INPUT(_type='submit',_value=T('Clear'),_class="btn",
|
INPUT(_type='submit',_value=T('Clear'),_class="btn",
|
||||||
_onclick="jQuery('#web2py_keywords').val('');"),
|
_onclick="jQuery('#web2py_keywords').val('');"),
|
||||||
search_menu,_method="GET",_action=url)
|
_method="GET",_action=url),search_menu)
|
||||||
form = search_widget and search_widget(sfields,url()) or ''
|
form = search_widget and search_widget(sfields,url()) or ''
|
||||||
console.append(form)
|
console.append(form)
|
||||||
keywords = request.vars.get('keywords','')
|
keywords = request.vars.get('keywords','')
|
||||||
@@ -1887,12 +1893,19 @@ class SQLFORM(FORM):
|
|||||||
error = T('Invalid query')
|
error = T('Invalid query')
|
||||||
else:
|
else:
|
||||||
subquery = None
|
subquery = None
|
||||||
|
if create:
|
||||||
|
console.append(gridbutton(
|
||||||
|
buttonclass='buttonadd',
|
||||||
|
buttontext='Add',
|
||||||
|
buttonurl=url(args=['new',tablename])))
|
||||||
|
|
||||||
if subquery:
|
if subquery:
|
||||||
dbset = dbset(subquery)
|
dbset = dbset(subquery)
|
||||||
try:
|
try:
|
||||||
if left or groupby:
|
if left or groupby:
|
||||||
c = 'count(*)'
|
c = 'count(*)'
|
||||||
nrows = dbset.select(c,left=left,groupby=groupby).first()[c]
|
nrows = dbset.select(c,left=left,cacheable=True,
|
||||||
|
groupby=groupby).first()[c]
|
||||||
else:
|
else:
|
||||||
nrows = dbset.count()
|
nrows = dbset.count()
|
||||||
except:
|
except:
|
||||||
@@ -1976,7 +1989,9 @@ class SQLFORM(FORM):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
table_fields = [f for f in fields if f._tablename in tablenames]
|
table_fields = [f for f in fields if f._tablename in tablenames]
|
||||||
rows = dbset.select(left=left,orderby=orderby,groupby=groupby,limitby=limitby,*table_fields)
|
rows = dbset.select(left=left,orderby=orderby,
|
||||||
|
groupby=groupby,limitby=limitby,
|
||||||
|
cacheable=True,*table_fields)
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
rows = None
|
rows = None
|
||||||
error = T("Query Not Supported")
|
error = T("Query Not Supported")
|
||||||
@@ -2186,12 +2201,14 @@ class SQLFORM(FORM):
|
|||||||
LI(A(T(db[referee]._plural),
|
LI(A(T(db[referee]._plural),
|
||||||
_class=trap_class(),
|
_class=trap_class(),
|
||||||
_href=url()),
|
_href=url()),
|
||||||
SPAN(divider,_class='divider'),_class='w2p_grid_breadcrumb_elem'))
|
SPAN(divider,_class='divider'),
|
||||||
|
_class='w2p_grid_breadcrumb_elem'))
|
||||||
if kwargs.get('details',True):
|
if kwargs.get('details',True):
|
||||||
breadcrumbs.append(
|
breadcrumbs.append(
|
||||||
LI(A(name,_class=trap_class(),
|
LI(A(name,_class=trap_class(),
|
||||||
_href=url(args=['view',referee,id])),
|
_href=url(args=['view',referee,id])),
|
||||||
SPAN(divider,_class='divider'),_class='w2p_grid_breadcrumb_elem'))
|
SPAN(divider,_class='divider'),
|
||||||
|
_class='w2p_grid_breadcrumb_elem'))
|
||||||
nargs+=2
|
nargs+=2
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@@ -2217,16 +2234,18 @@ class SQLFORM(FORM):
|
|||||||
del kwargs[key]
|
del kwargs[key]
|
||||||
check = {}
|
check = {}
|
||||||
id_field_name = table._id.name
|
id_field_name = table._id.name
|
||||||
for field in table._referenced_by:
|
for rfield in table._referenced_by:
|
||||||
if field.readable:
|
if rfield.readable:
|
||||||
check[field.tablename] = check.get(field.tablename,[])+[field.name]
|
check[rfield.tablename] = \
|
||||||
|
check.get(rfield.tablename,[])+[rfield.name]
|
||||||
for tablename in sorted(check):
|
for tablename in sorted(check):
|
||||||
linked_fieldnames = check[tablename]
|
linked_fieldnames = check[tablename]
|
||||||
tb = db[tablename]
|
tb = db[tablename]
|
||||||
multiple_links = len(linked_fieldnames)>1
|
multiple_links = len(linked_fieldnames)>1
|
||||||
for fieldname in linked_fieldnames:
|
for fieldname in linked_fieldnames:
|
||||||
if linked_tables is None or tablename in linked_tables:
|
if linked_tables is None or tablename in linked_tables:
|
||||||
t = T(tb._plural) if not multiple_links else T(tb._plural+'('+fieldname+')')
|
t = T(tb._plural) if not multiple_links else \
|
||||||
|
T(tb._plural+'('+fieldname+')')
|
||||||
args0 = tablename+'.'+fieldname
|
args0 = tablename+'.'+fieldname
|
||||||
links.append(
|
links.append(
|
||||||
lambda row,t=t,nargs=nargs,args0=args0:\
|
lambda row,t=t,nargs=nargs,args0=args0:\
|
||||||
@@ -2560,7 +2579,7 @@ class ExportClass(object):
|
|||||||
for record in self.rows:
|
for record in self.rows:
|
||||||
row = []
|
row = []
|
||||||
for col in self.rows.colnames:
|
for col in self.rows.colnames:
|
||||||
if not regex_table_field.match(col):
|
if not REGEX_TABLE_DOT_FIELD.match(col):
|
||||||
row.append(record._extra[col])
|
row.append(record._extra[col])
|
||||||
else:
|
else:
|
||||||
(t, f) = col.split('.')
|
(t, f) = col.split('.')
|
||||||
|
|||||||
+1
-1
@@ -136,7 +136,7 @@ class StorageList(Storage):
|
|||||||
like Storage but missing elements default to [] instead of None
|
like Storage but missing elements default to [] instead of None
|
||||||
"""
|
"""
|
||||||
def __getitem__(self,key):
|
def __getitem__(self,key):
|
||||||
return self.__gteattr__(key)
|
return self.__getattr__(key)
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
if key in self:
|
if key in self:
|
||||||
return getattr(self,key)
|
return getattr(self,key)
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ from test_storage import *
|
|||||||
from test_template import *
|
from test_template import *
|
||||||
from test_utils import *
|
from test_utils import *
|
||||||
from test_contribs import *
|
from test_contribs import *
|
||||||
|
from test_markmin import *
|
||||||
# from test_web import *
|
# from test_web import *
|
||||||
|
|||||||
@@ -411,12 +411,14 @@ class TestMinMaxSum(unittest.TestCase):
|
|||||||
self.assertEqual(db.t.insert(a=3), 3)
|
self.assertEqual(db.t.insert(a=3), 3)
|
||||||
s = db.t.a.min()
|
s = db.t.a.min()
|
||||||
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 1)
|
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 1)
|
||||||
|
self.assertEqual(db(db.t.id > 0).select(s).first()[s], 1)
|
||||||
|
self.assertEqual(db().select(s).first()[s], 1)
|
||||||
s = db.t.a.max()
|
s = db.t.a.max()
|
||||||
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 3)
|
self.assertEqual(db().select(s).first()[s], 3)
|
||||||
s = db.t.a.sum()
|
s = db.t.a.sum()
|
||||||
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 6)
|
self.assertEqual(db().select(s).first()[s], 6)
|
||||||
s = db.t.a.count()
|
s = db.t.a.count()
|
||||||
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 3)
|
self.assertEqual(db().select(s).first()[s], 3)
|
||||||
db.t.drop()
|
db.t.drop()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ try:
|
|||||||
'1 shop')
|
'1 shop')
|
||||||
self.assertEqual(str(T('%s %%{shop[0]}', 2)),
|
self.assertEqual(str(T('%s %%{shop[0]}', 2)),
|
||||||
'2 shops')
|
'2 shops')
|
||||||
|
self.assertEqual(str(T('%s %%{quark[0]}', 1)),
|
||||||
|
'1 quark')
|
||||||
|
self.assertEqual(str(T('%s %%{quark[0]}', 2)),
|
||||||
|
'2 quarks')
|
||||||
self.assertEqual(str(T.M('**Hello World**')),
|
self.assertEqual(str(T.M('**Hello World**')),
|
||||||
'<strong>Hello World</strong>')
|
'<strong>Hello World</strong>')
|
||||||
T.force('it')
|
T.force('it')
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Unit tests for running web2py
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
if os.path.isdir('gluon'):
|
||||||
|
sys.path.append(os.path.realpath('gluon'))
|
||||||
|
else:
|
||||||
|
sys.path.append(os.path.realpath('../'))
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from gluon.contrib.markmin.markmin2html import run_doctests
|
||||||
|
|
||||||
|
class TestMarkmin(unittest.TestCase):
|
||||||
|
def testMarkmin(self):
|
||||||
|
run_doctests()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
@@ -41,6 +41,11 @@ class TestWeb(unittest.TestCase):
|
|||||||
client.get('index')
|
client.get('index')
|
||||||
self.assertTrue('Welcome Homer' in client.text)
|
self.assertTrue('Welcome Homer' in client.text)
|
||||||
|
|
||||||
|
client = WebClient('http://127.0.0.1:8000/admin/default/')
|
||||||
|
client.post('index',data=dict(password='hello'))
|
||||||
|
client.get('site')
|
||||||
|
client.get('design/welcome')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|||||||
+18
-11
@@ -839,6 +839,7 @@ class Auth(object):
|
|||||||
table_event = None,
|
table_event = None,
|
||||||
table_cas = None,
|
table_cas = None,
|
||||||
showid = False,
|
showid = False,
|
||||||
|
use_username = False,
|
||||||
login_email_validate = True,
|
login_email_validate = True,
|
||||||
login_userfield = None,
|
login_userfield = None,
|
||||||
logout_onlogout = None,
|
logout_onlogout = None,
|
||||||
@@ -1250,18 +1251,21 @@ class Auth(object):
|
|||||||
else:
|
else:
|
||||||
login = A(T('Login'), _href=href('login'))
|
login = A(T('Login'), _href=href('login'))
|
||||||
register = A(T('Register'), _href=href('register'))
|
register = A(T('Register'), _href=href('register'))
|
||||||
retrieve_username = A(T('Forgot username?'), _href=href('retrieve_username'))
|
retrieve_username = A(
|
||||||
lost_password = A(T('Lost password?'), _href=href('request_reset_password'))
|
T('Forgot username?'), _href=href('retrieve_username'))
|
||||||
|
lost_password = A(
|
||||||
|
T('Lost password?'), _href=href('request_reset_password'))
|
||||||
bar = SPAN(s1, login, s3, _class='auth_navbar')
|
bar = SPAN(s1, login, s3, _class='auth_navbar')
|
||||||
|
|
||||||
if not 'register' in self.settings.actions_disabled:
|
if not 'register' in self.settings.actions_disabled:
|
||||||
bar.insert(-1, s2)
|
bar.insert(-1, s2)
|
||||||
bar.insert(-1, register)
|
bar.insert(-1, register)
|
||||||
if self.use_username and \
|
if self.settings.use_username and not 'retrieve_username' \
|
||||||
not 'retrieve_username' in self.settings.actions_disabled:
|
in self.settings.actions_disabled:
|
||||||
bar.insert(-1, s2)
|
bar.insert(-1, s2)
|
||||||
bar.insert(-1, retrieve_username)
|
bar.insert(-1, retrieve_username)
|
||||||
if not 'request_reset_password' in self.settings.actions_disabled:
|
if not 'request_reset_password' \
|
||||||
|
in self.settings.actions_disabled:
|
||||||
bar.insert(-1, s2)
|
bar.insert(-1, s2)
|
||||||
bar.insert(-1, lost_password)
|
bar.insert(-1, lost_password)
|
||||||
return bar
|
return bar
|
||||||
@@ -1353,7 +1357,7 @@ class Auth(object):
|
|||||||
writable=False,readable=False,
|
writable=False,readable=False,
|
||||||
label=T('Modified By')))
|
label=T('Modified By')))
|
||||||
|
|
||||||
def define_tables(self, username=False, signature=None,
|
def define_tables(self, username=None, signature=None,
|
||||||
migrate=True, fake_migrate=False):
|
migrate=True, fake_migrate=False):
|
||||||
"""
|
"""
|
||||||
to be called unless tables are defined manually
|
to be called unless tables are defined manually
|
||||||
@@ -1371,7 +1375,10 @@ class Auth(object):
|
|||||||
|
|
||||||
db = self.db
|
db = self.db
|
||||||
settings = self.settings
|
settings = self.settings
|
||||||
self.use_username = username
|
if username is None:
|
||||||
|
username = settings.use_username
|
||||||
|
else:
|
||||||
|
settings.use_username = username
|
||||||
if not self.signature:
|
if not self.signature:
|
||||||
self.define_signature()
|
self.define_signature()
|
||||||
if signature==True:
|
if signature==True:
|
||||||
@@ -1612,12 +1619,12 @@ class Auth(object):
|
|||||||
checks = []
|
checks = []
|
||||||
# make a guess about who this user is
|
# make a guess about who this user is
|
||||||
for fieldname in ['registration_id','username','email']:
|
for fieldname in ['registration_id','username','email']:
|
||||||
if fieldname in table_user.fields() and keys.get(fieldname,None):
|
if fieldname in table_user.fields() and \
|
||||||
|
keys.get(fieldname,None):
|
||||||
checks.append(fieldname)
|
checks.append(fieldname)
|
||||||
value = keys[fieldname]
|
value = keys[fieldname]
|
||||||
user = user or table_user._db(
|
user = table_user(**{fieldname:value})
|
||||||
(table_user.registration_id==value)|
|
if user: break
|
||||||
(table_user[fieldname]==value)).select().first()
|
|
||||||
if not checks:
|
if not checks:
|
||||||
return None
|
return None
|
||||||
if not 'registration_id' in keys:
|
if not 'registration_id' in keys:
|
||||||
|
|||||||
+23
-20
@@ -1376,6 +1376,7 @@ class IS_GENERIC_URL(Validator):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
error_message='enter a valid URL',
|
error_message='enter a valid URL',
|
||||||
@@ -1402,6 +1403,9 @@ class IS_GENERIC_URL(Validator):
|
|||||||
"prepend_scheme='%s' is not in allowed_schemes=%s" \
|
"prepend_scheme='%s' is not in allowed_schemes=%s" \
|
||||||
% (self.prepend_scheme, self.allowed_schemes)
|
% (self.prepend_scheme, self.allowed_schemes)
|
||||||
|
|
||||||
|
GENERIC_URL = re.compile(r"%[^0-9A-Fa-f]{2}|%[^0-9A-Fa-f][0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]|%$|%[0-9A-Fa-f]$|%[^0-9A-Fa-f]$")
|
||||||
|
GENERIC_URL_VALID = re.compile(r"[A-Za-z0-9;/?:@&=+$,\-_\.!~*'\(\)%#]+$")
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
"""
|
"""
|
||||||
:param value: a string, the URL to validate
|
:param value: a string, the URL to validate
|
||||||
@@ -1411,12 +1415,9 @@ class IS_GENERIC_URL(Validator):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# if the URL does not misuse the '%' character
|
# if the URL does not misuse the '%' character
|
||||||
if not re.compile(
|
if not self.GENERIC_URL.search(value):
|
||||||
r"%[^0-9A-Fa-f]{2}|%[^0-9A-Fa-f][0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]|%$|%[0-9A-Fa-f]$|%[^0-9A-Fa-f]$"
|
|
||||||
).search(value):
|
|
||||||
# if the URL is only composed of valid characters
|
# if the URL is only composed of valid characters
|
||||||
if re.compile(
|
if self.GENERIC_URL_VALID.match(value):
|
||||||
r"[A-Za-z0-9;/?:@&=+$,\-_\.!~*'\(\)%#]+$").match(value):
|
|
||||||
# Then split up the URL into its components and check on
|
# Then split up the URL into its components and check on
|
||||||
# the scheme
|
# the scheme
|
||||||
scheme = url_split_regex.match(value).group(2)
|
scheme = url_split_regex.match(value).group(2)
|
||||||
@@ -1432,11 +1433,10 @@ class IS_GENERIC_URL(Validator):
|
|||||||
# ports, check to see if adding a valid scheme fixes
|
# ports, check to see if adding a valid scheme fixes
|
||||||
# the problem (but only do this if it doesn't have
|
# the problem (but only do this if it doesn't have
|
||||||
# one already!)
|
# one already!)
|
||||||
if not re.compile('://').search(value) and None\
|
if value.find('://')<0 and None in self.allowed_schemes:
|
||||||
in self.allowed_schemes:
|
|
||||||
schemeToUse = self.prepend_scheme or 'http'
|
schemeToUse = self.prepend_scheme or 'http'
|
||||||
prependTest = self.__call__(schemeToUse
|
prependTest = self.__call__(
|
||||||
+ '://' + value)
|
schemeToUse + '://' + value)
|
||||||
# if the prepend test succeeded
|
# if the prepend test succeeded
|
||||||
if prependTest[1] is None:
|
if prependTest[1] is None:
|
||||||
# if prepending in the output is enabled
|
# if prepending in the output is enabled
|
||||||
@@ -1791,6 +1791,9 @@ class IS_HTTP_URL(Validator):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
GENERIC_VALID_IP = re.compile("([\w.!~*'|;:&=+$,-]+@)?\d+\.\d+\.\d+\.\d+(:\d*)*$")
|
||||||
|
GENERIC_VALID_DOMAIN = re.compile("([\w.!~*'|;:&=+$,-]+@)?(([A-Za-z0-9]+[A-Za-z0-9\-]*[A-Za-z0-9]+\.)*([A-Za-z0-9]+\.)*)*([A-Za-z]+[A-Za-z0-9\-]*[A-Za-z0-9]+)\.?(:\d*)*$")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
error_message='enter a valid URL',
|
error_message='enter a valid URL',
|
||||||
@@ -1843,16 +1846,12 @@ class IS_HTTP_URL(Validator):
|
|||||||
# if there is an authority component
|
# if there is an authority component
|
||||||
if authority:
|
if authority:
|
||||||
# if authority is a valid IP address
|
# if authority is a valid IP address
|
||||||
if re.compile(
|
if self.GENERIC_VALID_IP.match(authority):
|
||||||
"([\w.!~*'|;:&=+$,-]+@)?\d+\.\d+\.\d+\.\d+(:\d*)*$").match(authority):
|
|
||||||
# Then this HTTP URL is valid
|
# Then this HTTP URL is valid
|
||||||
return (value, None)
|
return (value, None)
|
||||||
else:
|
else:
|
||||||
# else if authority is a valid domain name
|
# else if authority is a valid domain name
|
||||||
domainMatch = \
|
domainMatch = self.GENERIC_VALID_DOMAIN.match(authority)
|
||||||
re.compile(
|
|
||||||
"([\w.!~*'|;:&=+$,-]+@)?(([A-Za-z0-9]+[A-Za-z0-9\-]*[A-Za-z0-9]+\.)*([A-Za-z0-9]+\.)*)*([A-Za-z]+[A-Za-z0-9\-]*[A-Za-z0-9]+)\.?(:\d*)*$"
|
|
||||||
).match(authority)
|
|
||||||
if domainMatch:
|
if domainMatch:
|
||||||
# if the top-level domain really exists
|
# if the top-level domain really exists
|
||||||
if domainMatch.group(5).lower()\
|
if domainMatch.group(5).lower()\
|
||||||
@@ -1865,13 +1864,13 @@ class IS_HTTP_URL(Validator):
|
|||||||
path = componentsMatch.group(5)
|
path = componentsMatch.group(5)
|
||||||
# relative case: if this is a valid path (if it starts with
|
# relative case: if this is a valid path (if it starts with
|
||||||
# a slash)
|
# a slash)
|
||||||
if re.compile('/').match(path):
|
if path.startswith('/'):
|
||||||
# Then this HTTP URL is valid
|
# Then this HTTP URL is valid
|
||||||
return (value, None)
|
return (value, None)
|
||||||
else:
|
else:
|
||||||
# abbreviated case: if we haven't already, prepend a
|
# abbreviated case: if we haven't already, prepend a
|
||||||
# scheme and see if it fixes the problem
|
# scheme and see if it fixes the problem
|
||||||
if not re.compile('://').search(value):
|
if value.find('://')<0:
|
||||||
schemeToUse = self.prepend_scheme or 'http'
|
schemeToUse = self.prepend_scheme or 'http'
|
||||||
prependTest = self.__call__(schemeToUse
|
prependTest = self.__call__(schemeToUse
|
||||||
+ '://' + value)
|
+ '://' + value)
|
||||||
@@ -2521,9 +2520,11 @@ class CLEANUP(Validator):
|
|||||||
|
|
||||||
removes special characters on validation
|
removes special characters on validation
|
||||||
"""
|
"""
|
||||||
|
REGEX_CLEANUP = re.compile('[^\x09\x0a\x0d\x20-\x7e]')
|
||||||
|
|
||||||
def __init__(self, regex='[^\x09\x0a\x0d\x20-\x7e]'):
|
def __init__(self, regex=None):
|
||||||
self.regex = re.compile(regex)
|
self.regex = self.REGEX_CLEANUP if regex is None \
|
||||||
|
else re.compile(regex)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
v = self.regex.sub('',str(value).strip())
|
v = self.regex.sub('',str(value).strip())
|
||||||
@@ -2790,11 +2791,13 @@ class IS_STRONG(object):
|
|||||||
|
|
||||||
class IS_IN_SUBSET(IS_IN_SET):
|
class IS_IN_SUBSET(IS_IN_SET):
|
||||||
|
|
||||||
|
REGEX_W = re.compile('\w+')
|
||||||
|
|
||||||
def __init__(self, *a, **b):
|
def __init__(self, *a, **b):
|
||||||
IS_IN_SET.__init__(self, *a, **b)
|
IS_IN_SET.__init__(self, *a, **b)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
values = re.compile("\w+").findall(str(value))
|
values = self.REGEX_W.findall(str(value))
|
||||||
failures = [x for x in values if IS_IN_SET.__call__(self, x)[1]]
|
failures = [x for x in values if IS_IN_SET.__call__(self, x)[1]]
|
||||||
if failures:
|
if failures:
|
||||||
return (value, translate(self.error_message))
|
return (value, translate(self.error_message))
|
||||||
|
|||||||
+2
-2
@@ -1004,9 +1004,9 @@ def start(cron=True):
|
|||||||
print ProgramAuthor
|
print ProgramAuthor
|
||||||
print ProgramVersion
|
print ProgramVersion
|
||||||
|
|
||||||
from dal import drivers
|
from dal import DRIVERS
|
||||||
if not options.nobanner:
|
if not options.nobanner:
|
||||||
print 'Database drivers available: %s' % ', '.join(drivers)
|
print 'Database drivers available: %s' % ', '.join(DRIVERS)
|
||||||
|
|
||||||
|
|
||||||
# ## if -L load options from options.config file
|
# ## if -L load options from options.config file
|
||||||
|
|||||||
+15
-10
@@ -27,12 +27,14 @@
|
|||||||
# set by the setLevel call, the [logger_myapp] section, and the [handler_...]
|
# set by the setLevel call, the [logger_myapp] section, and the [handler_...]
|
||||||
# section. For example, you will not see DEBUG messages unless all three are
|
# section. For example, you will not see DEBUG messages unless all three are
|
||||||
# set to DEBUG.
|
# set to DEBUG.
|
||||||
|
#
|
||||||
|
# Available levels: DEBUG INFO WARNING ERROR CRITICAL
|
||||||
|
|
||||||
[loggers]
|
[loggers]
|
||||||
keys=root,rocket,markdown,web2py,rewrite,cron,app,welcome
|
keys=root,rocket,markdown,web2py,rewrite,cron,app,welcome
|
||||||
|
|
||||||
[handlers]
|
[handlers]
|
||||||
keys=consoleHandler,messageBoxHandler
|
keys=consoleHandler,messageBoxHandler,rotatingFileHandler
|
||||||
#keys=consoleHandler,rotatingFileHandler
|
#keys=consoleHandler,rotatingFileHandler
|
||||||
#keys=osxSysLogHandler
|
#keys=osxSysLogHandler
|
||||||
|
|
||||||
@@ -41,50 +43,53 @@ keys=simpleFormatter
|
|||||||
|
|
||||||
[logger_root]
|
[logger_root]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler,rotatingFileHandler
|
||||||
|
|
||||||
[logger_web2py]
|
[logger_web2py]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler,rotatingFileHandler
|
||||||
qualname=web2py
|
qualname=web2py
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
|
# URL rewrite logging (routes.py)
|
||||||
|
# See also the logging parameter in routes.py
|
||||||
|
#
|
||||||
[logger_rewrite]
|
[logger_rewrite]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
qualname=web2py.rewrite
|
qualname=web2py.rewrite
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler,rotatingFileHandler
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
[logger_cron]
|
[logger_cron]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
qualname=web2py.cron
|
qualname=web2py.cron
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler,rotatingFileHandler
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
# generic app handler
|
# generic app handler
|
||||||
[logger_app]
|
[logger_app]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
qualname=web2py.app
|
qualname=web2py.app
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler,rotatingFileHandler
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
# welcome app handler
|
# welcome app handler
|
||||||
[logger_welcome]
|
[logger_welcome]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
qualname=web2py.app.welcome
|
qualname=web2py.app.welcome,rotatingFileHandler
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
# loggers for legacy getLogger calls: Rocket and markdown
|
# loggers for legacy getLogger calls: Rocket and markdown
|
||||||
[logger_rocket]
|
[logger_rocket]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
handlers=consoleHandler,messageBoxHandler
|
handlers=consoleHandler,messageBoxHandler,rotatingFileHandler
|
||||||
qualname=Rocket
|
qualname=Rocket
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
[logger_markdown]
|
[logger_markdown]
|
||||||
level=WARNING
|
level=WARNING
|
||||||
handlers=consoleHandler
|
handlers=consoleHandler,rotatingFileHandler
|
||||||
qualname=markdown
|
qualname=markdown
|
||||||
propagate=0
|
propagate=0
|
||||||
|
|
||||||
@@ -106,7 +111,7 @@ args=()
|
|||||||
#
|
#
|
||||||
[handler_rotatingFileHandler]
|
[handler_rotatingFileHandler]
|
||||||
class=handlers.RotatingFileHandler
|
class=handlers.RotatingFileHandler
|
||||||
level=INFO
|
level=DEBUG
|
||||||
formatter=simpleFormatter
|
formatter=simpleFormatter
|
||||||
args=("logs/web2py.log", "a", 1000000, 5)
|
args=("logs/web2py.log", "a", 1000000, 5)
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ administrator_email = 'you@localhost'
|
|||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
for file in os.listdir(path):
|
for file in os.listdir(path):
|
||||||
filename = os.path.join(path, file)
|
|
||||||
|
|
||||||
if not ALLOW_DUPLICATES:
|
if not ALLOW_DUPLICATES:
|
||||||
fileobj = open(filename, 'r')
|
fileobj = open(file, 'r')
|
||||||
try:
|
try:
|
||||||
file_data = fileobj.read()
|
file_data = fileobj.read()
|
||||||
finally:
|
finally:
|
||||||
@@ -42,10 +40,10 @@ while 1:
|
|||||||
hashes[key] = 1
|
hashes[key] = 1
|
||||||
|
|
||||||
error = RestrictedError()
|
error = RestrictedError()
|
||||||
error.load(request, request.application, filename)
|
error.load(request, request.application, file)
|
||||||
|
|
||||||
mail.send(to=administrator_email, subject='new web2py ticket', message=error.traceback)
|
mail.send(to=administrator_email, subject='new web2py ticket', message=error.traceback)
|
||||||
|
|
||||||
os.unlink(filename)
|
os.unlink(os.path.join(path, file))
|
||||||
time.sleep(SLEEP_MINUTES * 60)
|
time.sleep(SLEEP_MINUTES * 60)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user