Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -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,14 +29,14 @@ 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.4 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
echo 'Version 2.0.7 ('`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
|
||||||
rm -f routes.py
|
rm -f routes.py
|
||||||
rm -f applications/*/sessions/*
|
rm -f applications/*/sessions/*
|
||||||
rm -f applications/*/errors/* | echo 'too many files'
|
rm -f applications/*/errors/* | echo 'too many files'
|
||||||
rm -f applications/*/cache/*
|
rm -f applications/*/cache/*
|
||||||
rm -f applications/admin/databases/*
|
rm -f applications/admin/databases/*
|
||||||
rm -f applications/welcome/databases/*
|
rm -f applications/welcome/databases/*
|
||||||
rm -f applications/examples/databases/*
|
rm -f applications/examples/databases/*
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.0.4 (2012-08-31 16:04:08) stable
|
Version 2.0.7 (2012-09-04 17:58:46) stable
|
||||||
|
|||||||
@@ -244,11 +244,15 @@ def site():
|
|||||||
DIV(T('Unable to download app because:'),PRE(str(e)))
|
DIV(T('Unable to download app because:'),PRE(str(e)))
|
||||||
redirect(URL(r=request))
|
redirect(URL(r=request))
|
||||||
fname = form_update.vars.url
|
fname = form_update.vars.url
|
||||||
|
|
||||||
elif form_update.accepted and form_update.vars.file:
|
elif form_update.accepted and form_update.vars.file:
|
||||||
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',
|
||||||
@@ -58,6 +60,7 @@
|
|||||||
'exposes': 'exposes',
|
'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 does not exist': 'file does not exist',
|
||||||
'file saved on %s': 'file saved on %s',
|
'file saved on %s': 'file saved on %s',
|
||||||
'filter': 'filter',
|
'filter': 'filter',
|
||||||
@@ -70,7 +73,9 @@
|
|||||||
'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',
|
'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:',
|
'Last saved on:': 'Last saved on:',
|
||||||
@@ -85,6 +90,7 @@
|
|||||||
'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',
|
||||||
@@ -107,6 +113,7 @@
|
|||||||
'Save via Ajax': 'Save via Ajax',
|
'Save via Ajax': 'Save via Ajax',
|
||||||
'Saved file hash:': 'Saved file hash:',
|
'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',
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ function doClickSave() {
|
|||||||
prepareDataForSave('saved_on', jQuery("input[name='saved_on']").val()),
|
prepareDataForSave('saved_on', jQuery("input[name='saved_on']").val()),
|
||||||
prepareDataForSave('saved_on', jQuery("input[name='saved_on']").val()),
|
prepareDataForSave('saved_on', jQuery("input[name='saved_on']").val()),
|
||||||
prepareDataForSave('from_ajax','true')));
|
prepareDataForSave('from_ajax','true')));
|
||||||
// console.info(area.textarea.value);
|
// console.info(area.textarea.value);
|
||||||
jQuery("input[name='saved_on']").attr('style','background-color:yellow');
|
jQuery("input[name='saved_on']").attr('style','background-color:yellow');
|
||||||
jQuery("input[name='saved_on']").val('saving now...')
|
jQuery("input[name='saved_on']").val('saving now...')
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
@@ -65,13 +65,13 @@ function doClickSave() {
|
|||||||
dataType: "json",
|
dataType: "json",
|
||||||
data: dataForPost[0],
|
data: dataForPost[0],
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
beforeSend: function(xhr) {
|
beforeSend: function(xhr) {
|
||||||
xhr.setRequestHeader('web2py-component-location',document.location);
|
xhr.setRequestHeader('web2py-component-location',document.location);
|
||||||
xhr.setRequestHeader('web2py-component-element','doClickSave');},
|
xhr.setRequestHeader('web2py-component-element','doClickSave');},
|
||||||
success: function(json,text,xhr){
|
success: function(json,text,xhr){
|
||||||
|
|
||||||
// show flash message (if any)
|
// show flash message (if any)
|
||||||
var flash=xhr.getResponseHeader('web2py-component-flash');
|
var flash=xhr.getResponseHeader('web2py-component-flash');
|
||||||
if (flash) jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
if (flash) jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||||
else jQuery('.flash').hide();
|
else jQuery('.flash').hide();
|
||||||
|
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -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',
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
+30
-7
@@ -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,7 +367,11 @@ 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)
|
||||||
if store_current:
|
if store_current:
|
||||||
@@ -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
|
||||||
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
regex = re_compile('|'.join(map(fnmatch.translate, patterns)))
|
||||||
allow_generic = patterns and regex.search(short_action)
|
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
||||||
|
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)
|
||||||
|
|||||||
@@ -544,6 +544,7 @@ 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_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*$')
|
||||||
@@ -620,7 +621,7 @@ def render(text,
|
|||||||
- class_prefix is a prefix for ALL classes in markmin text. E.g. if class_prefix='my_'
|
- class_prefix is a prefix for ALL classes in markmin text. E.g. if class_prefix='my_'
|
||||||
then for ``test``:cls class will be changed to "my_cls" (default value is '')
|
then for ``test``:cls class will be changed to "my_cls" (default value is '')
|
||||||
- id_prefix is prefix for ALL ids in markmin text (default value is 'markmin_'). E.g.:
|
- id_prefix is prefix for ALL ids in markmin text (default value is 'markmin_'). E.g.:
|
||||||
-- [[id]] will be converted to <a name="markmin_id"></a>
|
-- [[id]] will be converted to <div class="anchor" id="markmin_id"></div>
|
||||||
-- [[link #id]] will be converted to <a href="#markmin_id">link</a>
|
-- [[link #id]] will be converted to <a href="#markmin_id">link</a>
|
||||||
-- ``test``:cls[id] will be converted to <code class="cls" id="markmin_id">test</code>
|
-- ``test``:cls[id] will be converted to <code class="cls" id="markmin_id">test</code>
|
||||||
|
|
||||||
@@ -832,22 +833,11 @@ def render(text,
|
|||||||
# this is experimental @{function/args}
|
# this is experimental @{function/args}
|
||||||
# turns into a digitally signed URL
|
# turns into a digitally signed URL
|
||||||
def u1(match,URL=URL):
|
def u1(match,URL=URL):
|
||||||
a,c,f,args = match.group('a','c','f','args')
|
a,c,f,args = match.group('a','c','f','args')
|
||||||
return URL(a=a or None,c=c or None,f = f or None,
|
return URL(a=a or None,c=c or None,f = f or None,
|
||||||
args=args.split('/'), scheme=True, host=True)
|
args=args.split('/'), scheme=True, host=True)
|
||||||
text = regex_URL.sub(u1,text)
|
text = regex_URL.sub(u1,text)
|
||||||
|
|
||||||
if environment:
|
|
||||||
def u2(match, environment=environment):
|
|
||||||
f = environment.get(match.group('a'), match.group(0))
|
|
||||||
if callable(f):
|
|
||||||
try:
|
|
||||||
f = f(match.group('b'))
|
|
||||||
except Exception, e:
|
|
||||||
f = 'ERROR: %s' % e
|
|
||||||
return str(f)
|
|
||||||
text = regex_env.sub(u2, text)
|
|
||||||
|
|
||||||
if latex == 'google':
|
if latex == 'google':
|
||||||
text = regex_dd.sub('``\g<latex>``:latex ', text)
|
text = regex_dd.sub('``\g<latex>``:latex ', text)
|
||||||
|
|
||||||
@@ -1314,12 +1304,24 @@ def render(text,
|
|||||||
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)
|
text = text.translate(ttab_out)
|
||||||
|
|
||||||
|
if environment:
|
||||||
|
def u2(match, environment=environment):
|
||||||
|
f = environment.get(match.group('a'), match.group(0))
|
||||||
|
if callable(f):
|
||||||
|
try:
|
||||||
|
f = f(match.group('b'))
|
||||||
|
except Exception, e:
|
||||||
|
f = 'ERROR: %s' % e
|
||||||
|
return str(f)
|
||||||
|
text = regex_env.sub(u2, text)
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
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):
|
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,
|
class_prefix=class_prefix, id_prefix=id_prefix,
|
||||||
pretty_print=pretty_print)
|
pretty_print=pretty_print)
|
||||||
@@ -1403,3 +1405,4 @@ if __name__ == '__main__':
|
|||||||
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)"
|
||||||
run_doctests()
|
run_doctests()
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
+124
-80
@@ -227,15 +227,21 @@ thread = threading.local()
|
|||||||
# internal representation of tables with field
|
# internal representation of tables with field
|
||||||
# <table>.<field>, tables and fields may only be [a-zA-Z0-9_]
|
# <table>.<field>, tables and fields may only be [a-zA-Z0-9_]
|
||||||
|
|
||||||
regex_type = re.compile('^([\w\_\:]+)')
|
REGEX_TYPE = re.compile('^([\w\_\:]+)')
|
||||||
regex_dbname = re.compile('^(\w+)(\:\w+)*')
|
REGEX_DBNAME = re.compile('^(\w+)(\:\w+)*')
|
||||||
regex_safe = re.compile('^\w+$')
|
REGEX_W = re.compile('^\w+$')
|
||||||
regex_table_field = re.compile('^(\w+)\.(\w+)$')
|
REGEX_TABLE_DOT_FIELD = re.compile('^(\w+)\.(\w+)$')
|
||||||
regex_content = re.compile('(?P<table>[\w\-]+)\.(?P<field>[\w\-]+)\.(?P<uuidkey>[\w\-]+)\.(?P<name>\w+)\.\w+$')
|
REGEX_UPLOAD_PATTERN = re.compile('(?P<table>[\w\-]+)\.(?P<field>[\w\-]+)\.(?P<uuidkey>[\w\-]+)\.(?P<name>\w+)\.\w+$')
|
||||||
regex_cleanup_fn = re.compile('[\'"\s;]+')
|
REGEX_CLEANUP_FN = re.compile('[\'"\s;]+')
|
||||||
string_unpack=re.compile('(?<!\|)\|(?!\|)')
|
REGEX_UNPACK = re.compile('(?<!\|)\|(?!\|)')
|
||||||
regex_python_keywords = re.compile('^(and|del|from|not|while|as|elif|global|or|with|assert|else|if|pass|yield|break|except|import|print|class|exec|in|raise|continue|finally|is|return|def|for|lambda|try)$')
|
REGEX_PYTHON_KEYWORDS = re.compile('^(and|del|from|not|while|as|elif|global|or|with|assert|else|if|pass|yield|break|except|import|print|class|exec|in|raise|continue|finally|is|return|def|for|lambda|try)$')
|
||||||
regex_select_as_parser = re.compile("\s+AS\s+(\S+)")
|
REGEX_SELECT_AS_PARSER = re.compile("\s+AS\s+(\S+)")
|
||||||
|
REGEX_CONST_STRING = re.compile('(\"[^\"]*?\")|(\'[^\']*?\')')
|
||||||
|
REGEX_SEARCH_PATTERN = re.compile('^{[^\.]+\.[^\.]+(\.(lt|gt|le|ge|eq|ne|contains|startswith|year|month|day|hour|minute|second))?(\.not)?}$')
|
||||||
|
REGEX_SQUARE_BRACKETS = re.compile('^.+\[.+\]$')
|
||||||
|
REGEX_STORE_PATTERN = re.compile('\.(?P<e>\w{1,5})$')
|
||||||
|
REGEX_QUOTES = re.compile("'[^']*'")
|
||||||
|
REGEX_ALPHANUMERIC = re.compile('^[a-zA-Z]\w*$')
|
||||||
|
|
||||||
# list of drivers will be built on the fly
|
# list of drivers will be built on the fly
|
||||||
# and lists only what is available
|
# and lists only what is available
|
||||||
@@ -434,7 +440,7 @@ def AND(a,b):
|
|||||||
def IDENTITY(x): return x
|
def IDENTITY(x): return x
|
||||||
|
|
||||||
def varquote_aux(name,quotestr='%s'):
|
def varquote_aux(name,quotestr='%s'):
|
||||||
return name if regex_safe.match(name) else quotestr % name
|
return name if REGEX_W.match(name) else quotestr % name
|
||||||
|
|
||||||
if 'google' in DRIVERS:
|
if 'google' in DRIVERS:
|
||||||
|
|
||||||
@@ -1397,7 +1403,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
if isinstance(item,SQLALL):
|
if isinstance(item,SQLALL):
|
||||||
new_fields += item._table
|
new_fields += item._table
|
||||||
elif isinstance(item,str):
|
elif isinstance(item,str):
|
||||||
if regex_table_field.match(item):
|
if REGEX_TABLE_DOT_FIELD.match(item):
|
||||||
tablename,fieldname = item.split('.')
|
tablename,fieldname = item.split('.')
|
||||||
append(db[tablename][fieldname])
|
append(db[tablename][fieldname])
|
||||||
else:
|
else:
|
||||||
@@ -1419,7 +1425,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
tablenames = tables(query)
|
tablenames = tables(query)
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if isinstance(field, basestring) \
|
if isinstance(field, basestring) \
|
||||||
and regex_table_field.match(field):
|
and REGEX_TABLE_DOT_FIELD.match(field):
|
||||||
tn,fn = field.split('.')
|
tn,fn = field.split('.')
|
||||||
field = self.db[tn][fn]
|
field = self.db[tn][fn]
|
||||||
for tablename in tables(field):
|
for tablename in tables(field):
|
||||||
@@ -1762,7 +1768,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
elif field_type == 'blob' and not blob_decode:
|
elif field_type == 'blob' and not blob_decode:
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
key = regex_type.match(field_type).group(0)
|
key = REGEX_TYPE.match(field_type).group(0)
|
||||||
return self.parsemap[key](value,field_type)
|
return self.parsemap[key](value,field_type)
|
||||||
|
|
||||||
def parse_reference(self, value, field_type):
|
def parse_reference(self, value, field_type):
|
||||||
@@ -1877,7 +1883,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
new_rows = []
|
new_rows = []
|
||||||
tmps = []
|
tmps = []
|
||||||
for colname in colnames:
|
for colname in colnames:
|
||||||
if not regex_table_field.match(colname):
|
if not REGEX_TABLE_DOT_FIELD.match(colname):
|
||||||
tmps.append(None)
|
tmps.append(None)
|
||||||
else:
|
else:
|
||||||
(tablename, fieldname) = colname.split('.')
|
(tablename, fieldname) = colname.split('.')
|
||||||
@@ -1933,7 +1939,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
self.parse_value(value,
|
self.parse_value(value,
|
||||||
fields[j].type,blob_decode)
|
fields[j].type,blob_decode)
|
||||||
new_column_name = \
|
new_column_name = \
|
||||||
regex_select_as_parser.search(colname)
|
REGEX_SELECT_AS_PARSER.search(colname)
|
||||||
if not new_column_name is None:
|
if not new_column_name is None:
|
||||||
column_name = new_column_name.groups(0)
|
column_name = new_column_name.groups(0)
|
||||||
setattr(new_row,column_name[0],value)
|
setattr(new_row,column_name[0],value)
|
||||||
@@ -2283,6 +2289,8 @@ class MySQLAdapter(BaseAdapter):
|
|||||||
def concat_add(self,table):
|
def concat_add(self,table):
|
||||||
return '; ALTER TABLE %s ADD ' % table
|
return '; ALTER TABLE %s ADD ' % table
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^?]+)(\?set_encoding=(?P<charset>\w+))?$')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -2295,7 +2303,7 @@ class MySQLAdapter(BaseAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^?]+)(\?set_encoding=(?P<charset>\w+))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -2371,9 +2379,9 @@ class PostgreSQLAdapter(BaseAdapter):
|
|||||||
if self.driver_name == 'psycopg2':
|
if self.driver_name == 'psycopg2':
|
||||||
return psycopg2_adapt(obj).getquoted()
|
return psycopg2_adapt(obj).getquoted()
|
||||||
elif self.driver_name == 'pg8000':
|
elif self.driver_name == 'pg8000':
|
||||||
return str(obj).replace("%","%%").replace("'","''")
|
return "'%s'" % str(obj).replace("%","%%").replace("'","''")
|
||||||
else:
|
else:
|
||||||
return str(obj).replace("'","''")
|
return "'%s'" % str(obj).replace("'","''")
|
||||||
|
|
||||||
def sequence_name(self,table):
|
def sequence_name(self,table):
|
||||||
return '%s_id_Seq' % table
|
return '%s_id_Seq' % table
|
||||||
@@ -2407,6 +2415,8 @@ class PostgreSQLAdapter(BaseAdapter):
|
|||||||
# % (table._tablename, table._fieldname, table._sequence_name))
|
# % (table._tablename, table._fieldname, table._sequence_name))
|
||||||
self.execute(query)
|
self.execute(query)
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:@]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?sslmode=(?P<sslmode>.+))?$')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}, srid=4326):
|
adapter_args={}, srid=4326):
|
||||||
@@ -2420,7 +2430,7 @@ class PostgreSQLAdapter(BaseAdapter):
|
|||||||
self.srid = srid
|
self.srid = srid
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:@]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?sslmode=(?P<sslmode>.+))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, "Invalid URI string in DAL"
|
raise SyntaxError, "Invalid URI string in DAL"
|
||||||
user = credential_decoder(m.group('user'))
|
user = credential_decoder(m.group('user'))
|
||||||
@@ -2631,6 +2641,8 @@ class NewPostgreSQLAdapter(PostgreSQLAdapter):
|
|||||||
class JDBCPostgreSQLAdapter(PostgreSQLAdapter):
|
class JDBCPostgreSQLAdapter(PostgreSQLAdapter):
|
||||||
drivers = ('zxJDBC',)
|
drivers = ('zxJDBC',)
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>.+)$')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -2643,7 +2655,7 @@ class JDBCPostgreSQLAdapter(PostgreSQLAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>.+)$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, "Invalid URI string in DAL"
|
raise SyntaxError, "Invalid URI string in DAL"
|
||||||
user = credential_decoder(m.group('user'))
|
user = credential_decoder(m.group('user'))
|
||||||
@@ -2778,6 +2790,7 @@ class OracleAdapter(BaseAdapter):
|
|||||||
def after_connection(self):
|
def after_connection(self):
|
||||||
self.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';")
|
self.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';")
|
||||||
self.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';")
|
self.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';")
|
||||||
|
|
||||||
oracle_fix = re.compile("[^']*('[^']*'[^']*)*\:(?P<clob>CLOB\('([^']+|'')*'\))")
|
oracle_fix = re.compile("[^']*('[^']*'[^']*)*\:(?P<clob>CLOB\('([^']+|'')*'\))")
|
||||||
|
|
||||||
def execute(self, command, args=None):
|
def execute(self, command, args=None):
|
||||||
@@ -2905,6 +2918,10 @@ class MSSQLAdapter(BaseAdapter):
|
|||||||
return '0'
|
return '0'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
REGEX_DSN = re.compile('^(?P<dsn>.+)$')
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?(?P<urlargs>.*))?$')
|
||||||
|
REGEX_ARGPATTERN = re.compile('(?P<argkey>[^=]+)=(?P<argvalue>[^&]*)')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}, fake_connect=False, srid=4326):
|
adapter_args={}, fake_connect=False, srid=4326):
|
||||||
@@ -2921,7 +2938,7 @@ class MSSQLAdapter(BaseAdapter):
|
|||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
if '@' not in ruri:
|
if '@' not in ruri:
|
||||||
try:
|
try:
|
||||||
m = re.compile('^(?P<dsn>.+)$').match(ruri)
|
m = self.REGEX_DSN.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
'Parsing uri string(%s) has no result' % self.uri
|
'Parsing uri string(%s) has no result' % self.uri
|
||||||
@@ -2934,7 +2951,7 @@ class MSSQLAdapter(BaseAdapter):
|
|||||||
# was cnxn = 'DSN=%s' % dsn
|
# was cnxn = 'DSN=%s' % dsn
|
||||||
cnxn = dsn
|
cnxn = dsn
|
||||||
else:
|
else:
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?(?P<urlargs>.*))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -2955,9 +2972,8 @@ class MSSQLAdapter(BaseAdapter):
|
|||||||
# (in the form of arg1=value1&arg2=value2&...)
|
# (in the form of arg1=value1&arg2=value2&...)
|
||||||
# Default values (drivers like FreeTDS insist on uppercase parameter keys)
|
# Default values (drivers like FreeTDS insist on uppercase parameter keys)
|
||||||
argsdict = { 'DRIVER':'{SQL Server}' }
|
argsdict = { 'DRIVER':'{SQL Server}' }
|
||||||
urlargs = m.group('urlargs') or ''
|
urlargs = m.group('urlargs') or ''
|
||||||
argpattern = re.compile('(?P<argkey>[^=]+)=(?P<argvalue>[^&]*)')
|
for argmatch in self.REGEX_ARGPATTERN.finditer(urlargs):
|
||||||
for argmatch in argpattern.finditer(urlargs):
|
|
||||||
argsdict[str(argmatch.group('argkey')).upper()] = argmatch.group('argvalue')
|
argsdict[str(argmatch.group('argkey')).upper()] = argmatch.group('argvalue')
|
||||||
urlargs = ';'.join(['%s=%s' % (ak, av) for (ak, av) in argsdict.iteritems()])
|
urlargs = ';'.join(['%s=%s' % (ak, av) for (ak, av) in argsdict.iteritems()])
|
||||||
cnxn = 'SERVER=%s;PORT=%s;DATABASE=%s;UID=%s;PWD=%s;%s' \
|
cnxn = 'SERVER=%s;PORT=%s;DATABASE=%s;UID=%s;PWD=%s;%s' \
|
||||||
@@ -3117,7 +3133,7 @@ class SybaseAdapter(MSSQLAdapter):
|
|||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
if '@' not in ruri:
|
if '@' not in ruri:
|
||||||
try:
|
try:
|
||||||
m = re.compile('^(?P<dsn>.+)$').match(ruri)
|
m = self.REGEX_DSN.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
'Parsing uri string(%s) has no result' % self.uri
|
'Parsing uri string(%s) has no result' % self.uri
|
||||||
@@ -3128,7 +3144,7 @@ class SybaseAdapter(MSSQLAdapter):
|
|||||||
logger.error('NdGpatch error')
|
logger.error('NdGpatch error')
|
||||||
raise e
|
raise e
|
||||||
else:
|
else:
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?(?P<urlargs>.*))?$').match(ruri)
|
m = self.REGEX_URI.match(uri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -3220,6 +3236,8 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
return ['DELETE FROM %s;' % table._tablename,
|
return ['DELETE FROM %s;' % table._tablename,
|
||||||
'SET GENERATOR %s TO 0;' % table._sequence_name]
|
'SET GENERATOR %s TO 0;' % table._sequence_name]
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>.+?)(\?set_encoding=(?P<charset>\w+))?$')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -3232,7 +3250,7 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>.+?)(\?set_encoding=(?P<charset>\w+))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, "Invalid URI string in DAL: %s" % self.uri
|
raise SyntaxError, "Invalid URI string in DAL: %s" % self.uri
|
||||||
user = credential_decoder(m.group('user'))
|
user = credential_decoder(m.group('user'))
|
||||||
@@ -3277,6 +3295,8 @@ class FireBirdAdapter(BaseAdapter):
|
|||||||
class FireBirdEmbeddedAdapter(FireBirdAdapter):
|
class FireBirdEmbeddedAdapter(FireBirdAdapter):
|
||||||
drivers = ('kinterbasdb','firebirdsql','fdb','pyodbc')
|
drivers = ('kinterbasdb','firebirdsql','fdb','pyodbc')
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<path>[^\?]+)(\?set_encoding=(?P<charset>\w+))?$')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -3289,7 +3309,7 @@ class FireBirdEmbeddedAdapter(FireBirdAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<path>[^\?]+)(\?set_encoding=(?P<charset>\w+))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -3383,6 +3403,8 @@ class InformixAdapter(BaseAdapter):
|
|||||||
return "to_date('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % obj
|
return "to_date('%s','%%Y-%%m-%%d %%H:%%M:%%S')" % obj
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>.+)$')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -3395,7 +3417,7 @@ class InformixAdapter(BaseAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>.+)$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -3584,7 +3606,7 @@ INGRES_SEQNAME='ii***lineitemsequence' # NOTE invalid database object name
|
|||||||
# to be a delimited identifier)
|
# to be a delimited identifier)
|
||||||
|
|
||||||
class IngresAdapter(BaseAdapter):
|
class IngresAdapter(BaseAdapter):
|
||||||
drivers = ('ingredbi',)
|
drivers = ('ingresdbi',)
|
||||||
|
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'CHAR(1)',
|
'boolean': 'CHAR(1)',
|
||||||
@@ -3762,6 +3784,9 @@ class SAPDBAdapter(BaseAdapter):
|
|||||||
% (table._tablename, table._id.name, table._sequence_name))
|
% (table._tablename, table._id.name, table._sequence_name))
|
||||||
self.execute(query)
|
self.execute(query)
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:@]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?sslmode=(?P<sslmode>.+))?$')
|
||||||
|
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -3774,7 +3799,7 @@ class SAPDBAdapter(BaseAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:@]+)(\:(?P<port>[0-9]+))?/(?P<db>[^\?]+)(\?sslmode=(?P<sslmode>.+))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, "Invalid URI string in DAL"
|
raise SyntaxError, "Invalid URI string in DAL"
|
||||||
user = credential_decoder(m.group('user'))
|
user = credential_decoder(m.group('user'))
|
||||||
@@ -3803,6 +3828,8 @@ class SAPDBAdapter(BaseAdapter):
|
|||||||
class CubridAdapter(MySQLAdapter):
|
class CubridAdapter(MySQLAdapter):
|
||||||
drivers = ('cubriddb',)
|
drivers = ('cubriddb',)
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^?]+)(\?set_encoding=(?P<charset>\w+))?$')
|
||||||
|
|
||||||
def __init__(self, db, uri, pool_size=0, folder=None, db_codec='UTF-8',
|
def __init__(self, db, uri, pool_size=0, folder=None, db_codec='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -3815,7 +3842,7 @@ class CubridAdapter(MySQLAdapter):
|
|||||||
self.db_codec = db_codec
|
self.db_codec = db_codec
|
||||||
self.find_or_make_work_folder()
|
self.find_or_make_work_folder()
|
||||||
ruri = uri.split('://',1)[1]
|
ruri = uri.split('://',1)[1]
|
||||||
m = re.compile('^(?P<user>[^:@]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:/]+)(\:(?P<port>[0-9]+))?/(?P<db>[^?]+)(\?set_encoding=(?P<charset>\w+))?$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, \
|
raise SyntaxError, \
|
||||||
"Invalid URI string in DAL: %s" % self.uri
|
"Invalid URI string in DAL: %s" % self.uri
|
||||||
@@ -3934,6 +3961,8 @@ class UseDatabaseStoredFile:
|
|||||||
class GoogleSQLAdapter(UseDatabaseStoredFile,MySQLAdapter):
|
class GoogleSQLAdapter(UseDatabaseStoredFile,MySQLAdapter):
|
||||||
uploads_in_blob = True
|
uploads_in_blob = True
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<instance>.*)/(?P<db>.*)$')
|
||||||
|
|
||||||
def __init__(self, db, uri='google:sql://realm:domain/database',
|
def __init__(self, db, uri='google:sql://realm:domain/database',
|
||||||
pool_size=0, folder=None, db_codec='UTF-8',
|
pool_size=0, folder=None, db_codec='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
@@ -3947,7 +3976,7 @@ class GoogleSQLAdapter(UseDatabaseStoredFile,MySQLAdapter):
|
|||||||
self.folder = folder or pjoin('$HOME',thread.folder.split(
|
self.folder = folder or pjoin('$HOME',thread.folder.split(
|
||||||
os.sep+'applications'+os.sep,1)[1])
|
os.sep+'applications'+os.sep,1)[1])
|
||||||
ruri = uri.split("://")[1]
|
ruri = uri.split("://")[1]
|
||||||
m = re.compile('^(?P<instance>.*)/(?P<db>.*)$').match(ruri)
|
m = self.REGEX_URI.match(ruri)
|
||||||
if not m:
|
if not m:
|
||||||
raise SyntaxError, "Invalid URI string in SQLDB: %s" % self.uri
|
raise SyntaxError, "Invalid URI string in SQLDB: %s" % self.uri
|
||||||
instance = credential_decoder(m.group('instance'))
|
instance = credential_decoder(m.group('instance'))
|
||||||
@@ -4143,6 +4172,8 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
def file_open(self, filename, mode='rb', lock=True): pass
|
def file_open(self, filename, mode='rb', lock=True): pass
|
||||||
def file_close(self, fileobj): pass
|
def file_close(self, fileobj): pass
|
||||||
|
|
||||||
|
REGEX_NAMESPACE = re.compile('.*://(?P<namespace>.+)')
|
||||||
|
|
||||||
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
def __init__(self,db,uri,pool_size=0,folder=None,db_codec ='UTF-8',
|
||||||
credential_decoder=IDENTITY, driver_args={},
|
credential_decoder=IDENTITY, driver_args={},
|
||||||
adapter_args={}):
|
adapter_args={}):
|
||||||
@@ -4174,7 +4205,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
db['_lastsql'] = ''
|
db['_lastsql'] = ''
|
||||||
self.db_codec = 'UTF-8'
|
self.db_codec = 'UTF-8'
|
||||||
self.pool_size = 0
|
self.pool_size = 0
|
||||||
match = re.compile('.*://(?P<namespace>.+)').match(uri)
|
match = self.REGEX_NAMESPACE.match(uri)
|
||||||
if match:
|
if match:
|
||||||
namespace_manager.set_namespace(match.group('namespace'))
|
namespace_manager.set_namespace(match.group('namespace'))
|
||||||
|
|
||||||
@@ -4734,11 +4765,8 @@ def cleanup(text):
|
|||||||
"""
|
"""
|
||||||
validates that the given text is clean: only contains [0-9a-zA-Z_]
|
validates that the given text is clean: only contains [0-9a-zA-Z_]
|
||||||
"""
|
"""
|
||||||
|
if not REGEX_ALPHANUMERIC.match(text):
|
||||||
if re.compile('[^0-9a-zA-Z_]').findall(text):
|
raise SyntaxError, 'invalid table or field name: %s' % text
|
||||||
raise SyntaxError, \
|
|
||||||
'only [0-9a-zA-Z_] allowed in table and field names, received %s' \
|
|
||||||
% text
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
class MongoDBAdapter(NoSQLAdapter):
|
class MongoDBAdapter(NoSQLAdapter):
|
||||||
@@ -5474,6 +5502,8 @@ class IMAPAdapter(NoSQLAdapter):
|
|||||||
|
|
||||||
dbengine = 'imap'
|
dbengine = 'imap'
|
||||||
|
|
||||||
|
REGEX_URI = re.compile('^(?P<user>[^:]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:@]+)(\:(?P<port>[0-9]+))?$')
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
db,
|
db,
|
||||||
uri,
|
uri,
|
||||||
@@ -5521,7 +5551,7 @@ class IMAPAdapter(NoSQLAdapter):
|
|||||||
|
|
||||||
db['_lastsql'] = ''
|
db['_lastsql'] = ''
|
||||||
|
|
||||||
m = re.compile('^(?P<user>[^:]+)(\:(?P<password>[^@]*))?@(?P<host>[^\:@]+)(\:(?P<port>[0-9]+))?$').match(uri)
|
m = self.REGEX_URI.match(uri)
|
||||||
user = m.group('user')
|
user = m.group('user')
|
||||||
password = m.group('password')
|
password = m.group('password')
|
||||||
host = m.group('host')
|
host = m.group('host')
|
||||||
@@ -6364,7 +6394,8 @@ def bar_decode_integer(value):
|
|||||||
return [int(x) for x in value.split('|') if x.strip()]
|
return [int(x) for x in value.split('|') if x.strip()]
|
||||||
|
|
||||||
def bar_decode_string(value):
|
def bar_decode_string(value):
|
||||||
return [x.replace('||', '|') for x in string_unpack.split(value[1:-1]) if x.strip()]
|
return [x.replace('||', '|') for x in
|
||||||
|
REGEX_UNPACK.split(value[1:-1]) if x.strip()]
|
||||||
|
|
||||||
|
|
||||||
class Row(object):
|
class Row(object):
|
||||||
@@ -6379,7 +6410,7 @@ class Row(object):
|
|||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key=str(key)
|
key=str(key)
|
||||||
m = regex_table_field.match(key)
|
m = REGEX_TABLE_DOT_FIELD.match(key)
|
||||||
if key in self.get('_extra',{}):
|
if key in self.get('_extra',{}):
|
||||||
return self._extra[key]
|
return self._extra[key]
|
||||||
elif m:
|
elif m:
|
||||||
@@ -6429,7 +6460,7 @@ class Row(object):
|
|||||||
return '<Row %s>' % self.__dict__
|
return '<Row %s>' % self.__dict__
|
||||||
|
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
return dict.__getitem__(self,'id')
|
return object.__getattribute__(self,'id')
|
||||||
|
|
||||||
def __eq__(self,other):
|
def __eq__(self,other):
|
||||||
try:
|
try:
|
||||||
@@ -6506,11 +6537,10 @@ def smart_query(fields,text):
|
|||||||
n = str(field).lower()
|
n = str(field).lower()
|
||||||
if not n in field_map:
|
if not n in field_map:
|
||||||
field_map[n] = field
|
field_map[n] = field
|
||||||
re_constants = re.compile('(\"[^\"]*?\")|(\'[^\']*?\')')
|
|
||||||
constants = {}
|
constants = {}
|
||||||
i = 0
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
m = re_constants.search(text)
|
m = REGEX_CONST_STRING.search(text)
|
||||||
if not m: break
|
if not m: break
|
||||||
text = text[:m.start()]+('#%i' % i)+text[m.end():]
|
text = text[:m.start()]+('#%i' % i)+text[m.end():]
|
||||||
constants[str(i)] = m.group()[1:-1]
|
constants[str(i)] = m.group()[1:-1]
|
||||||
@@ -6720,7 +6750,7 @@ class DAL(object):
|
|||||||
try:
|
try:
|
||||||
if is_jdbc and not uri.startswith('jdbc:'):
|
if is_jdbc and not uri.startswith('jdbc:'):
|
||||||
uri = 'jdbc:'+uri
|
uri = 'jdbc:'+uri
|
||||||
self._dbname = regex_dbname.match(uri).group()
|
self._dbname = REGEX_DBNAME.match(uri).group()
|
||||||
if not self._dbname in ADAPTERS:
|
if not self._dbname in ADAPTERS:
|
||||||
raise SyntaxError, "Error in URI '%s' or database not supported" % self._dbname
|
raise SyntaxError, "Error in URI '%s' or database not supported" % self._dbname
|
||||||
# notice that driver args or {} else driver_args
|
# notice that driver args or {} else driver_args
|
||||||
@@ -6833,8 +6863,8 @@ def index():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
db = self
|
db = self
|
||||||
re1 = re.compile('^{[^\.]+\.[^\.]+(\.(lt|gt|le|ge|eq|ne|contains|startswith|year|month|day|hour|minute|second))?(\.not)?}$')
|
re1 = REGEX_SEARCH_PATTERN
|
||||||
re2 = re.compile('^.+\[.+\]$')
|
re2 = REGEX_SQUARE_BRACKETS
|
||||||
|
|
||||||
def auto_table(table,base='',depth=0):
|
def auto_table(table,base='',depth=0):
|
||||||
patterns = []
|
patterns = []
|
||||||
@@ -7037,7 +7067,7 @@ def index():
|
|||||||
if not isinstance(tablename,str):
|
if not isinstance(tablename,str):
|
||||||
raise SyntaxError, "missing table name"
|
raise SyntaxError, "missing table name"
|
||||||
elif tablename.startswith('_') or hasattr(self,tablename) or \
|
elif tablename.startswith('_') or hasattr(self,tablename) or \
|
||||||
regex_python_keywords.match(tablename):
|
REGEX_PYTHON_KEYWORDS.match(tablename):
|
||||||
raise SyntaxError, 'invalid table name: %s' % tablename
|
raise SyntaxError, 'invalid table name: %s' % tablename
|
||||||
elif tablename in self.tables:
|
elif tablename in self.tables:
|
||||||
raise SyntaxError, 'table already defined: %s' % tablename
|
raise SyntaxError, 'table already defined: %s' % tablename
|
||||||
@@ -7168,21 +7198,34 @@ def index():
|
|||||||
|
|
||||||
[{field1: value1, field2: value2}, {field1: value1b, field2: value2b}]
|
[{field1: value1, field2: value2}, {field1: value1b, field2: value2b}]
|
||||||
|
|
||||||
Added 2012-08-24 "fields" optional argument. If not None, the
|
Added 2012-08-24 "fields" and "colnames" optional arguments. If either
|
||||||
results cursor returned by the DB driver will be converted to a
|
is provided, the results cursor returned by the DB driver will be
|
||||||
DAL Rows object using the db._adapter.parse() method. This requires
|
converted to a DAL Rows object using the db._adapter.parse() method.
|
||||||
specifying the "fields" argument as a list of DAL Field objects
|
|
||||||
that match the fields returned from the DB. The Field objects should
|
The "fields" argument is a list of DAL Field objects that match the
|
||||||
be part of one or more Table objects defined on the DAL object.
|
fields returned from the DB. The Field objects should be part of one or
|
||||||
The "fields" list can include one or more DAL Table objects in addition
|
more Table objects defined on the DAL object. The "fields" list can
|
||||||
to or instead of including Field objects, or it can be just a single
|
include one or more DAL Table objects in addition to or instead of
|
||||||
table (not in a list). In that case, the Field objects will be
|
including Field objects, or it can be just a single table (not in a
|
||||||
extracted from the table(s).
|
list). In that case, the Field objects will be extracted from the
|
||||||
|
table(s).
|
||||||
|
|
||||||
The field names will be extracted from the Field objects, or optionally,
|
Instead of specifying the "fields" argument, the "colnames" argument
|
||||||
a list of field names can be provided (in tablename.fieldname format)
|
can be specified as a list of field names in tablename.fieldname format.
|
||||||
via the "colnames" argument. Note, the fields and colnames must be in
|
Again, these should represent tables and fields defined on the DAL
|
||||||
the same order as the fields in the results cursor returned from the DB.
|
object.
|
||||||
|
|
||||||
|
It is also possible to specify both "fields" and the associated
|
||||||
|
"colnames". In that case, "fields" can also include DAL Expression
|
||||||
|
objects in addition to Field objects. For Field objects in "fields",
|
||||||
|
the associated "colnames" must still be in tablename.fieldname format.
|
||||||
|
For Expression objects in "fields", the associated "colnames" can
|
||||||
|
be any arbitrary labels.
|
||||||
|
|
||||||
|
Note, the DAL Table objects referred to by "fields" or "colnames" can
|
||||||
|
be dummy tables and do not have to represent any real tables in the
|
||||||
|
database. Also, note that the "fields" and "colnames" must be in the
|
||||||
|
same order as the fields in the results cursor returned from the DB.
|
||||||
"""
|
"""
|
||||||
adapter = self._adapter
|
adapter = self._adapter
|
||||||
if placeholders:
|
if placeholders:
|
||||||
@@ -7203,8 +7246,12 @@ def index():
|
|||||||
# convert the list for each row into a dictionary so it's
|
# convert the list for each row into a dictionary so it's
|
||||||
# easier to work with. row['field_name'] rather than row[0]
|
# easier to work with. row['field_name'] rather than row[0]
|
||||||
return [dict(zip(fields,row)) for row in data]
|
return [dict(zip(fields,row)) for row in data]
|
||||||
data = adapter.cursor.fetchall()
|
try:
|
||||||
if fields:
|
data = adapter.cursor.fetchall()
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
if fields or colnames:
|
||||||
|
fields = [] if fields is None else fields
|
||||||
if not isinstance(fields, list):
|
if not isinstance(fields, list):
|
||||||
fields = [fields]
|
fields = [fields]
|
||||||
extracted_fields = []
|
extracted_fields = []
|
||||||
@@ -8348,7 +8395,7 @@ class Field(Expression):
|
|||||||
self.second = None
|
self.second = None
|
||||||
self.name = fieldname = cleanup(fieldname)
|
self.name = fieldname = cleanup(fieldname)
|
||||||
if not isinstance(fieldname,str) or hasattr(Table,fieldname) or \
|
if not isinstance(fieldname,str) or hasattr(Table,fieldname) or \
|
||||||
fieldname[0] == '_' or regex_python_keywords.match(fieldname):
|
fieldname[0] == '_' or REGEX_PYTHON_KEYWORDS.match(fieldname):
|
||||||
raise SyntaxError, 'Field: invalid field name: %s' % fieldname
|
raise SyntaxError, 'Field: invalid field name: %s' % fieldname
|
||||||
self.type = type if not isinstance(type, Table) else 'reference %s' % type
|
self.type = type if not isinstance(type, Table) else 'reference %s' % type
|
||||||
self.length = length if not length is None else DEFAULTLENGTH.get(self.type,512)
|
self.length = length if not length is None else DEFAULTLENGTH.get(self.type,512)
|
||||||
@@ -8402,8 +8449,8 @@ class Field(Expression):
|
|||||||
elif not filename:
|
elif not filename:
|
||||||
filename = file.name
|
filename = file.name
|
||||||
filename = os.path.basename(filename.replace('/', os.sep)\
|
filename = os.path.basename(filename.replace('/', os.sep)\
|
||||||
.replace('\\', os.sep))
|
.replace('\\', os.sep))
|
||||||
m = re.compile('\.(?P<e>\w{1,5})$').search(filename)
|
m = REGEX_STORE_PATTERN.search(filename)
|
||||||
extension = m and m.group('e') or 'txt'
|
extension = m and m.group('e') or 'txt'
|
||||||
uuid_key = web2py_uuid().replace('-', '')[-16:]
|
uuid_key = web2py_uuid().replace('-', '')[-16:]
|
||||||
encoded_filename = base64.b16encode(filename).lower()
|
encoded_filename = base64.b16encode(filename).lower()
|
||||||
@@ -8456,7 +8503,7 @@ class Field(Expression):
|
|||||||
raise http.HTTP(404)
|
raise http.HTTP(404)
|
||||||
if self.authorize and not self.authorize(row):
|
if self.authorize and not self.authorize(row):
|
||||||
raise http.HTTP(403)
|
raise http.HTTP(403)
|
||||||
m = regex_content.match(name)
|
m = REGEX_UPLOAD_PATTERN.match(name)
|
||||||
if not m or not self.isattachment:
|
if not m or not self.isattachment:
|
||||||
raise TypeError, 'Can\'t retrieve %s' % name
|
raise TypeError, 'Can\'t retrieve %s' % name
|
||||||
file_properties = self.retrieve_file_properties(name,path)
|
file_properties = self.retrieve_file_properties(name,path)
|
||||||
@@ -8481,11 +8528,11 @@ class Field(Expression):
|
|||||||
if self.custom_retrieve_file_properties:
|
if self.custom_retrieve_file_properties:
|
||||||
return self.custom_retrieve_file_properties(name, path)
|
return self.custom_retrieve_file_properties(name, path)
|
||||||
try:
|
try:
|
||||||
m = regex_content.match(name)
|
m = REGEX_UPLOAD_PATTERN.match(name)
|
||||||
if not m or not self.isattachment:
|
if not m or not self.isattachment:
|
||||||
raise TypeError, 'Can\'t retrieve %s file properties' % name
|
raise TypeError, 'Can\'t retrieve %s file properties' % name
|
||||||
filename = base64.b16decode(m.group('name'), True)
|
filename = base64.b16decode(m.group('name'), True)
|
||||||
filename = regex_cleanup_fn.sub('_', filename)
|
filename = REGEX_CLEANUP_FN.sub('_', filename)
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError):
|
||||||
filename = name
|
filename = name
|
||||||
if isinstance(self_uploadfield, str): # ## if file is in DB
|
if isinstance(self_uploadfield, str): # ## if file is in DB
|
||||||
@@ -8595,7 +8642,6 @@ class Query(object):
|
|||||||
return Query(self.db,self.db._adapter.NOT,self)
|
return Query(self.db,self.db._adapter.NOT,self)
|
||||||
|
|
||||||
|
|
||||||
regex_quotes = re.compile("'[^']*'")
|
|
||||||
|
|
||||||
|
|
||||||
def xorify(orderby):
|
def xorify(orderby):
|
||||||
@@ -9104,7 +9150,7 @@ class Rows(object):
|
|||||||
for record in self:
|
for record in self:
|
||||||
row = []
|
row = []
|
||||||
for col in colnames:
|
for col in 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('.')
|
||||||
@@ -9123,8 +9169,7 @@ class Rows(object):
|
|||||||
def xml(self,strict=False,row_name='row',rows_name='rows'):
|
def xml(self,strict=False,row_name='row',rows_name='rows'):
|
||||||
"""
|
"""
|
||||||
serializes the table using sqlhtml.SQLTABLE (if present)
|
serializes the table using sqlhtml.SQLTABLE (if present)
|
||||||
"""
|
"""
|
||||||
alphanumeric = re.compile('[a-zA-Z]\w*')
|
|
||||||
if strict:
|
if strict:
|
||||||
ncols = len(self.colnames)
|
ncols = len(self.colnames)
|
||||||
def f(row,field,indent=' '):
|
def f(row,field,indent=' '):
|
||||||
@@ -9138,9 +9183,8 @@ class Rows(object):
|
|||||||
indent,
|
indent,
|
||||||
field)
|
field)
|
||||||
elif not callable(row):
|
elif not callable(row):
|
||||||
if alphanumeric.match(field):
|
if REGEX_ALPHANUMERIC.match(field):
|
||||||
return '%s<%s>%s</%s>' % \
|
return '%s<%s>%s</%s>' % (indent,field,row,field)
|
||||||
(indent,field,row,field)
|
|
||||||
else:
|
else:
|
||||||
return '%s<extra name="%s">%s</extra>' % \
|
return '%s<extra name="%s">%s</extra>' % \
|
||||||
(indent,field,row)
|
(indent,field,row)
|
||||||
@@ -9164,7 +9208,7 @@ class Rows(object):
|
|||||||
def inner_loop(record, col):
|
def inner_loop(record, col):
|
||||||
(t, f) = col.split('.')
|
(t, f) = col.split('.')
|
||||||
res = None
|
res = None
|
||||||
if not regex_table_field.match(col):
|
if not REGEX_TABLE_DOT_FIELD.match(col):
|
||||||
key = col
|
key = col
|
||||||
res = record._extra[col]
|
res = record._extra[col]
|
||||||
else:
|
else:
|
||||||
|
|||||||
+5
-4
@@ -800,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')
|
||||||
@@ -830,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):
|
||||||
|
|||||||
+17
-34
@@ -91,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']
|
||||||
@@ -148,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)
|
||||||
@@ -274,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):
|
||||||
@@ -290,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/'
|
||||||
@@ -382,26 +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') and eget('REQUEST_URI'):
|
|
||||||
# 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'] = ''
|
|
||||||
elif not eget('REQUEST_URI'):
|
|
||||||
if eget('QUERY_STRING'):
|
|
||||||
environ['REQUEST_URI'] = eget('PATH_INFO') + '?' + eget('QUERY_STRING')
|
|
||||||
else:
|
|
||||||
environ['REQUEST_URI'] = eget('PATH_INFO')
|
|
||||||
if not eget('HTTP_HOST'):
|
|
||||||
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:
|
||||||
@@ -438,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
|
||||||
@@ -460,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
|
||||||
@@ -492,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
|
||||||
|
|
||||||
@@ -502,7 +484,8 @@ def wsgibase(environ, responder):
|
|||||||
# try load session or create new session file
|
# try load session or create new session file
|
||||||
# ##################################################
|
# ##################################################
|
||||||
|
|
||||||
session.connect(request, response)
|
if not env.web2py_disable_session:
|
||||||
|
session.connect(request, response)
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
# set no-cache headers
|
# set no-cache headers
|
||||||
@@ -558,7 +541,7 @@ def wsgibase(environ, responder):
|
|||||||
# if session not in db try store session on filesystem
|
# if session not in db try store session on filesystem
|
||||||
# this must be done after trying to commit database!
|
# this must be done after trying to commit database!
|
||||||
# ##################################################
|
# ##################################################
|
||||||
|
|
||||||
session._try_store_on_disk(request, response)
|
session._try_store_on_disk(request, response)
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
@@ -566,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'] = \
|
||||||
|
|||||||
+37
-11
@@ -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')
|
||||||
|
|||||||
+12
-8
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -454,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),
|
||||||
@@ -870,4 +875,3 @@ def main():
|
|||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|||||||
+42
-32
@@ -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'
|
||||||
@@ -1376,8 +1376,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 +1498,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,30 +1509,39 @@ 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()")
|
||||||
|
|
||||||
criterion.extend([operators,value_input,new_button,and_button,or_button])
|
criteria.append(DIV(
|
||||||
criteria.append(DIV(criterion, _id='w2p_field_%s' % name,
|
operators,value_input,new_button,
|
||||||
_class='w2p_query_row hidden'))
|
and_button,or_button,close_button,
|
||||||
|
_id='w2p_field_%s' % name,
|
||||||
|
_class='w2p_query_row hidden',
|
||||||
|
_style='display:inline'))
|
||||||
|
|
||||||
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('.','-');
|
||||||
var option = jQuery('#w2p_field_'+b+' select').val();
|
var option = jQuery('#w2p_field_'+b+' select').val();
|
||||||
var value = jQuery('#w2p_value_'+b).val().replace('"','\\\\"');
|
var value = jQuery('#w2p_value_'+b).val().replace('"','\\\\"');
|
||||||
@@ -1541,10 +1549,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
|
||||||
@@ -1663,8 +1672,9 @@ class SQLFORM(FORM):
|
|||||||
session.flash = T('not authorized')
|
session.flash = T('not authorized')
|
||||||
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)),
|
||||||
@@ -1854,12 +1864,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,
|
||||||
@@ -1868,13 +1872,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','')
|
||||||
@@ -1888,6 +1892,12 @@ 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:
|
||||||
@@ -2568,7 +2578,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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
+14
-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,
|
||||||
@@ -1060,7 +1061,6 @@ class Auth(object):
|
|||||||
request = current.request
|
request = current.request
|
||||||
session = current.session
|
session = current.session
|
||||||
auth = session.auth
|
auth = session.auth
|
||||||
self.use_username = None # None means postpone detection
|
|
||||||
self.user_groups = auth and auth.user_groups or {}
|
self.user_groups = auth and auth.user_groups or {}
|
||||||
if auth and auth.last_visit and auth.last_visit + \
|
if auth and auth.last_visit and auth.last_visit + \
|
||||||
datetime.timedelta(days=0, seconds=auth.expiration) > request.now:
|
datetime.timedelta(days=0, seconds=auth.expiration) > request.now:
|
||||||
@@ -1251,21 +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 is None:
|
if self.settings.use_username and not 'retrieve_username' \
|
||||||
# should always be false if auth.define_tables() is called
|
in self.settings.actions_disabled:
|
||||||
self.use_username = 'username' in self.table_user().fields
|
|
||||||
if self.use_username and \
|
|
||||||
not 'retrieve_username' 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
|
||||||
@@ -1357,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
|
||||||
@@ -1375,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:
|
||||||
|
|||||||
+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))
|
||||||
|
|||||||
@@ -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