Merge github.com:web2py/web2py
This commit is contained in:
@@ -29,7 +29,7 @@ update:
|
|||||||
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
echo 'Version 2.0.6 ('`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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.0.6 (2012-09-02 12:26:12) stable
|
Version 2.0.7 (2012-09-04 15:32:23) stable
|
||||||
|
|||||||
@@ -249,6 +249,10 @@ def site():
|
|||||||
fname = request.vars.file.filename
|
fname = request.vars.file.filename
|
||||||
f = request.vars.file.file
|
f = request.vars.file.file
|
||||||
|
|
||||||
|
else:
|
||||||
|
session.flash = 'No file uploaded and no URL specified'
|
||||||
|
redirect(URL(r=request))
|
||||||
|
|
||||||
if f:
|
if f:
|
||||||
appname = cleanpath(form_update.vars.name)
|
appname = cleanpath(form_update.vars.name)
|
||||||
installed = app_install(appname, f,
|
installed = app_install(appname, f,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
'are not used yet': 'are not used yet',
|
'are not used yet': 'are not used yet',
|
||||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
||||||
'arguments': 'arguments',
|
'arguments': 'arguments',
|
||||||
|
'at char %s': 'at char %s',
|
||||||
|
'at line %s': 'at line %s',
|
||||||
'back': '<<back',
|
'back': '<<back',
|
||||||
'can be a git repo': 'can be a git repo',
|
'can be a git repo': 'can be a git repo',
|
||||||
'Change admin password': 'Change admin password',
|
'Change admin password': 'Change admin password',
|
||||||
@@ -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',
|
||||||
@@ -87,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',
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -92,11 +92,14 @@ _TEST()
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CACHED_REGEXES = {}
|
CACHED_REGEXES = {}
|
||||||
|
CACHED_REGEXES_MAX_SIZE = 1000
|
||||||
|
|
||||||
def re_compile(regex):
|
def re_compile(regex):
|
||||||
try:
|
try:
|
||||||
return CACHED_REGEXES[regex]
|
return CACHED_REGEXES[regex]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
if len(CACHED_REGEXES) >= CACHED_REGEXES_MAX_SIZE:
|
||||||
|
CACHED_REGEXES.clear()
|
||||||
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
||||||
return compiled_regex
|
return compiled_regex
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
@@ -837,17 +838,6 @@ def render(text,
|
|||||||
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,6 +1304,18 @@ 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',
|
||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
+36
-19
@@ -2379,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
|
||||||
@@ -6460,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:
|
||||||
@@ -7198,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
|
|
||||||
be part of one or more Table objects defined on the DAL object.
|
|
||||||
The "fields" list can include one or more DAL Table objects in addition
|
|
||||||
to or instead of including Field objects, or it can be just a single
|
|
||||||
table (not in a 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,
|
The "fields" argument is a list of DAL Field objects that match the
|
||||||
a list of field names can be provided (in tablename.fieldname format)
|
fields returned from the DB. The Field objects should be part of one or
|
||||||
via the "colnames" argument. Note, the fields and colnames must be in
|
more Table objects defined on the DAL object. The "fields" list can
|
||||||
the same order as the fields in the results cursor returned from the DB.
|
include one or more DAL Table objects in addition to or instead of
|
||||||
|
including Field objects, or it can be just a single table (not in a
|
||||||
|
list). In that case, the Field objects will be extracted from the
|
||||||
|
table(s).
|
||||||
|
|
||||||
|
Instead of specifying the "fields" argument, the "colnames" argument
|
||||||
|
can be specified as a list of field names in tablename.fieldname format.
|
||||||
|
Again, these should represent tables and fields defined on the DAL
|
||||||
|
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:
|
||||||
@@ -7233,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 = []
|
||||||
|
|||||||
+16
-33
@@ -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
|
||||||
@@ -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'] = \
|
||||||
|
|||||||
+28
-6
@@ -135,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:
|
||||||
@@ -287,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',
|
||||||
@@ -350,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:
|
||||||
@@ -384,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"
|
||||||
@@ -498,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
|
||||||
@@ -687,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))
|
||||||
|
|||||||
+8
-7
@@ -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:
|
||||||
@@ -1663,8 +1663,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)),
|
||||||
|
|||||||
+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:
|
||||||
|
|||||||
Reference in New Issue
Block a user