Merge github.com:web2py/web2py
This commit is contained in:
@@ -29,14 +29,14 @@ update:
|
||||
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
||||
echo "remember that pymysql was tweaked"
|
||||
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
|
||||
make clean
|
||||
### clean up baisc apps
|
||||
rm -f routes.py
|
||||
rm -f applications/*/sessions/*
|
||||
rm -f applications/*/sessions/*
|
||||
rm -f applications/*/errors/* | echo 'too many files'
|
||||
rm -f applications/*/cache/*
|
||||
rm -f applications/*/cache/*
|
||||
rm -f applications/admin/databases/*
|
||||
rm -f applications/welcome/databases/*
|
||||
rm -f applications/examples/databases/*
|
||||
|
||||
@@ -1 +1 @@
|
||||
Version 2.0.6 (2012-09-02 12:26:12) stable
|
||||
Version 2.0.7 (2012-09-04 15:32:23) stable
|
||||
|
||||
@@ -244,11 +244,15 @@ def site():
|
||||
DIV(T('Unable to download app because:'),PRE(str(e)))
|
||||
redirect(URL(r=request))
|
||||
fname = form_update.vars.url
|
||||
|
||||
|
||||
elif form_update.accepted and form_update.vars.file:
|
||||
fname = request.vars.file.filename
|
||||
f = request.vars.file.file
|
||||
|
||||
else:
|
||||
session.flash = 'No file uploaded and no URL specified'
|
||||
redirect(URL(r=request))
|
||||
|
||||
if f:
|
||||
appname = cleanpath(form_update.vars.name)
|
||||
installed = app_install(appname, f,
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
'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?',
|
||||
'arguments': 'arguments',
|
||||
'at char %s': 'at char %s',
|
||||
'at line %s': 'at line %s',
|
||||
'back': '<<back',
|
||||
'can be a git repo': 'can be a git repo',
|
||||
'Change admin password': 'Change admin password',
|
||||
@@ -58,6 +60,7 @@
|
||||
'exposes': 'exposes',
|
||||
'exposes:': 'exposes:',
|
||||
'extends': 'extends',
|
||||
'failed to compile file because:': 'failed to compile file because:',
|
||||
'file does not exist': 'file does not exist',
|
||||
'file saved on %s': 'file saved on %s',
|
||||
'filter': 'filter',
|
||||
@@ -87,6 +90,7 @@
|
||||
'modules': 'modules',
|
||||
'New application wizard': 'New application wizard',
|
||||
'New simple application': 'New simple application',
|
||||
'online designer': 'online designer',
|
||||
'Overwrite installed app': 'Overwrite installed app',
|
||||
'Pack all': 'Pack all',
|
||||
'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('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']").val('saving now...')
|
||||
jQuery.ajax({
|
||||
@@ -65,13 +65,13 @@ function doClickSave() {
|
||||
dataType: "json",
|
||||
data: dataForPost[0],
|
||||
timeout: 5000,
|
||||
beforeSend: function(xhr) {
|
||||
beforeSend: function(xhr) {
|
||||
xhr.setRequestHeader('web2py-component-location',document.location);
|
||||
xhr.setRequestHeader('web2py-component-element','doClickSave');},
|
||||
success: function(json,text,xhr){
|
||||
success: function(json,text,xhr){
|
||||
|
||||
// show flash message (if any)
|
||||
var flash=xhr.getResponseHeader('web2py-component-flash');
|
||||
// show flash message (if any)
|
||||
var flash=xhr.getResponseHeader('web2py-component-flash');
|
||||
if (flash) jQuery('.flash').html(decodeURIComponent(flash)).slideDown();
|
||||
else jQuery('.flash').hide();
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
<h2>web2py™ {{=T('Web Framework')}}</h2>
|
||||
<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">
|
||||
<div><input type="hidden" name="send" value="{{=send}}"/></div>
|
||||
<table>
|
||||
@@ -11,4 +13,6 @@
|
||||
</table>
|
||||
</form>
|
||||
</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 This App': 'Modifica questa applicazione',
|
||||
'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',
|
||||
'Errors': 'Errors',
|
||||
'export as csv file': 'esporta come file CSV',
|
||||
@@ -95,6 +96,7 @@
|
||||
'Layouts': 'Layouts',
|
||||
'Live Chat': 'Live Chat',
|
||||
'Logged in': 'Logged in',
|
||||
'Logged out': 'Logged out',
|
||||
'login': 'accesso',
|
||||
'Login': 'Login',
|
||||
'logout': 'uscita',
|
||||
@@ -113,6 +115,7 @@
|
||||
'new record inserted': 'nuovo record inserito',
|
||||
'next 100 rows': 'prossime 100 righe',
|
||||
'No databases in this application': 'Nessun database presente in questa applicazione',
|
||||
'Non può essere vuoto': 'Non può essere vuoto',
|
||||
'not authorized': 'non autorizzato',
|
||||
'Object or table name': 'Object or table name',
|
||||
'Online examples': 'Vedere gli esempi',
|
||||
@@ -166,12 +169,14 @@
|
||||
'This App': 'This App',
|
||||
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
||||
'Timestamp': 'Ora (timestamp)',
|
||||
'too short': 'too short',
|
||||
'Twitter': 'Twitter',
|
||||
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
||||
'Update': 'Update',
|
||||
'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).',
|
||||
'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': 'ID Utente',
|
||||
'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}
|
||||
td {vertical-align:top}
|
||||
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}
|
||||
ol, ul {list-style-position:inside}
|
||||
ol, ul {list-style-position:outside; margin-left:2em}
|
||||
li {margin-bottom:0.5em}
|
||||
span,input,select,textarea,button,label,a {display:inline}
|
||||
img {border:0}
|
||||
@@ -39,13 +39,6 @@ input[type=text],input[type=password],select{width:300px; margin-right:5px}
|
||||
|
||||
/* 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 {
|
||||
padding:20px 0 50px 0;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
</section><!--/main-->
|
||||
|
||||
<!-- Footer ================================================== -->
|
||||
<footer class="footer">
|
||||
<footer class="footer" id="footer">
|
||||
{{block footer}} <!-- this is default footer -->
|
||||
<div class="footer-content">
|
||||
<div class="copyright pull-left">{{=T('Copyright')}} © {{=request.now.year}}</div>
|
||||
|
||||
@@ -92,11 +92,14 @@ _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
|
||||
|
||||
|
||||
@@ -544,6 +544,7 @@ regex_list=re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s+)?(.*)$')
|
||||
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_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[^\s\'\"\]\}\)]+)',re.M)
|
||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
|
||||
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]')
|
||||
regex_link_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_'
|
||||
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]] 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>
|
||||
-- ``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}
|
||||
# turns into a digitally signed 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,
|
||||
args=args.split('/'), scheme=True, host=True)
|
||||
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':
|
||||
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]))
|
||||
text = regex_expand_meta.sub(expand_meta, text)
|
||||
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
|
||||
|
||||
def markmin2html(text, extra={}, allowed={}, sep='p',
|
||||
def markmin2html(text, extra={}, allowed={}, sep='p',
|
||||
autolinks='default', protolinks='default',
|
||||
class_prefix='', id_prefix='markmin_', pretty_print=False):
|
||||
return render(text, extra, allowed, sep,
|
||||
class_prefix='', id_prefix='markmin_', pretty_print=False):
|
||||
return render(text, extra, allowed, sep,
|
||||
autolinks=autolinks, protolinks=protolinks,
|
||||
class_prefix=class_prefix, id_prefix=id_prefix,
|
||||
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 [@path_to/css] - process file.markmin + link path_to/css (optional)"
|
||||
run_doctests()
|
||||
|
||||
|
||||
+36
-19
@@ -2379,9 +2379,9 @@ class PostgreSQLAdapter(BaseAdapter):
|
||||
if self.driver_name == 'psycopg2':
|
||||
return psycopg2_adapt(obj).getquoted()
|
||||
elif self.driver_name == 'pg8000':
|
||||
return str(obj).replace("%","%%").replace("'","''")
|
||||
return "'%s'" % str(obj).replace("%","%%").replace("'","''")
|
||||
else:
|
||||
return str(obj).replace("'","''")
|
||||
return "'%s'" % str(obj).replace("'","''")
|
||||
|
||||
def sequence_name(self,table):
|
||||
return '%s_id_Seq' % table
|
||||
@@ -6460,7 +6460,7 @@ class Row(object):
|
||||
return '<Row %s>' % self.__dict__
|
||||
|
||||
def __int__(self):
|
||||
return dict.__getitem__(self,'id')
|
||||
return object.__getattribute__(self,'id')
|
||||
|
||||
def __eq__(self,other):
|
||||
try:
|
||||
@@ -7198,21 +7198,34 @@ def index():
|
||||
|
||||
[{field1: value1, field2: value2}, {field1: value1b, field2: value2b}]
|
||||
|
||||
Added 2012-08-24 "fields" optional argument. If not None, the
|
||||
results cursor returned by the DB driver will be converted to a
|
||||
DAL Rows object using the db._adapter.parse() method. This requires
|
||||
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).
|
||||
Added 2012-08-24 "fields" and "colnames" optional arguments. If either
|
||||
is provided, the results cursor returned by the DB driver will be
|
||||
converted to a DAL Rows object using the db._adapter.parse() method.
|
||||
|
||||
The "fields" argument is 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,
|
||||
a list of field names can be provided (in tablename.fieldname format)
|
||||
via the "colnames" argument. Note, the fields and colnames must be in
|
||||
the same order as the fields in the results cursor returned from the DB.
|
||||
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
|
||||
if placeholders:
|
||||
@@ -7233,8 +7246,12 @@ def index():
|
||||
# convert the list for each row into a dictionary so it's
|
||||
# easier to work with. row['field_name'] rather than row[0]
|
||||
return [dict(zip(fields,row)) for row in data]
|
||||
data = adapter.cursor.fetchall()
|
||||
if fields:
|
||||
try:
|
||||
data = adapter.cursor.fetchall()
|
||||
except:
|
||||
return None
|
||||
if fields or colnames:
|
||||
fields = [] if fields is None else fields
|
||||
if not isinstance(fields, list):
|
||||
fields = [fields]
|
||||
extracted_fields = []
|
||||
|
||||
+17
-34
@@ -91,7 +91,8 @@ from validators import CRYPT
|
||||
from cache import Cache
|
||||
from html import URL, xmlescape
|
||||
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
|
||||
|
||||
__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
|
||||
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()
|
||||
source = request.env.wsgi_input
|
||||
size = int(request.env.content_length)
|
||||
source = env.wsgi_input
|
||||
size = int(env.content_length)
|
||||
dest = tempfile.TemporaryFile()
|
||||
if not 'X-Progress-ID' in request.vars:
|
||||
copystream(source, dest, size, chunk_size)
|
||||
@@ -274,7 +276,8 @@ def environ_aux(environ,request):
|
||||
def parse_get_post_vars(request, environ):
|
||||
|
||||
# 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:
|
||||
if key in request.get_vars:
|
||||
if isinstance(request.get_vars[key], list):
|
||||
@@ -290,7 +293,7 @@ def parse_get_post_vars(request, environ):
|
||||
request.body = body = copystream_progress(request)
|
||||
except IOError:
|
||||
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)
|
||||
# The same detection used by FieldStorage to detect multipart POSTs
|
||||
is_multipart = dpost.type[:10] == 'multipart/'
|
||||
@@ -382,26 +385,7 @@ def wsgibase(environ, responder):
|
||||
# serve file if static
|
||||
# ##################################################
|
||||
|
||||
eget = environ.get
|
||||
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')
|
||||
|
||||
|
||||
fixup_missing_path_info(environ)
|
||||
(static_file, environ) = url_in(request, environ)
|
||||
|
||||
if static_file:
|
||||
@@ -438,6 +422,7 @@ def wsgibase(environ, responder):
|
||||
is_https = env.wsgi_url_scheme \
|
||||
in ['https', 'HTTPS'] or env.https=='on')
|
||||
request.uuid = request.compute_uuid() # requires client
|
||||
request.url = environ['PATH_INFO']
|
||||
|
||||
# ##################################################
|
||||
# access the requested application
|
||||
@@ -460,9 +445,6 @@ def wsgibase(environ, responder):
|
||||
elif not request.is_local and \
|
||||
exists(pjoin(request.folder,'DISABLED')):
|
||||
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
|
||||
@@ -492,9 +474,9 @@ def wsgibase(environ, responder):
|
||||
# load cookies
|
||||
# ##################################################
|
||||
|
||||
if request.env.http_cookie:
|
||||
if env.http_cookie:
|
||||
try:
|
||||
request.cookies.load(request.env.http_cookie)
|
||||
request.cookies.load(env.http_cookie)
|
||||
except Cookie.CookieError, e:
|
||||
pass # invalid cookies
|
||||
|
||||
@@ -502,7 +484,8 @@ def wsgibase(environ, responder):
|
||||
# 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
|
||||
@@ -558,7 +541,7 @@ def wsgibase(environ, responder):
|
||||
# if session not in db try store session on filesystem
|
||||
# this must be done after trying to commit database!
|
||||
# ##################################################
|
||||
|
||||
|
||||
session._try_store_on_disk(request, response)
|
||||
|
||||
# ##################################################
|
||||
@@ -566,7 +549,7 @@ def wsgibase(environ, responder):
|
||||
# ##################################################
|
||||
|
||||
if request.cid:
|
||||
rheaders = response.headers
|
||||
rheaders = http_response.headers
|
||||
if response.flash and \
|
||||
not 'web2py-component-flash' in rheaders:
|
||||
rheaders['web2py-component-flash'] = \
|
||||
|
||||
+28
-6
@@ -135,6 +135,27 @@ ROUTER_BASE_KEYS = set(
|
||||
# filter_err: helper for doctest & unittest
|
||||
# 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):
|
||||
"parse and rewrite incoming URL"
|
||||
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'):
|
||||
if sym in symbols:
|
||||
for (k, v) in symbols[sym]:
|
||||
p[sym].append(compile_regex(k, v))
|
||||
for items in symbols[sym]:
|
||||
p[sym].append(compile_regex(*items))
|
||||
for sym in ('routes_onerror', 'routes_apps_raw',
|
||||
'error_handler','error_message', 'error_message_ticket',
|
||||
'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)
|
||||
|
||||
|
||||
def compile_regex(k, v):
|
||||
def compile_regex(k, v, env=None):
|
||||
"""
|
||||
Preprocess and compile the regular expressions in routes_app/in/out
|
||||
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
|
||||
for item in regex_at.findall(v):
|
||||
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):
|
||||
"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('wsgi.url_scheme', 'http').lower(), host,
|
||||
e.get('REQUEST_METHOD', 'get').lower(), path)
|
||||
for (regex, value) in regexes:
|
||||
for (regex, value, custom_env) in regexes:
|
||||
if regex.match(key):
|
||||
e.update(custom_env)
|
||||
rewritten = regex.sub(value, key)
|
||||
log_rewrite('%s: [%s] [%s] -> %s' % (tag, key, value, rewritten))
|
||||
return rewritten
|
||||
@@ -687,7 +709,7 @@ def regex_filter_out(url, e=None):
|
||||
e.get('request_method', 'get').lower(), items[0])
|
||||
else:
|
||||
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]):
|
||||
rewritten = '?'.join([regex.sub(value, items[0])] + items[1:])
|
||||
log_rewrite('routes_out: [%s] -> %s' % (url, rewritten))
|
||||
|
||||
+8
-7
@@ -702,17 +702,17 @@ def formstyle_bootstrap(form, fields):
|
||||
_submit = False
|
||||
|
||||
if isinstance(controls, INPUT):
|
||||
controls['_class'] = 'input-xlarge'
|
||||
controls.add_class('input-xlarge')
|
||||
if controls['_type'] == 'submit':
|
||||
# flag submit button
|
||||
_submit = True
|
||||
controls['_class'] = 'btn btn-primary'
|
||||
|
||||
if isinstance(controls, SELECT):
|
||||
controls['_class'] = 'input-xlarge'
|
||||
controls.add_class('input-xlarge')
|
||||
|
||||
if isinstance(controls, TEXTAREA):
|
||||
controls['_class'] = 'input-xlarge'
|
||||
controls.add_class('input-xlarge')
|
||||
|
||||
if isinstance(label, LABEL):
|
||||
label['_class'] = 'control-label'
|
||||
@@ -1376,8 +1376,8 @@ class SQLFORM(FORM):
|
||||
# this should never happen but seems to happen to some
|
||||
del fields['delete_this_record']
|
||||
for field in self.table:
|
||||
if not field.name in fields and field.writable==False \
|
||||
and field.update is None:
|
||||
if not field.name in fields and field.writable is False \
|
||||
and field.update is None and field.compute is None:
|
||||
if record_id and self.record:
|
||||
fields[field.name] = self.record[field.name]
|
||||
elif not self.table[field.name].default is None:
|
||||
@@ -1663,8 +1663,9 @@ class SQLFORM(FORM):
|
||||
session.flash = T('not authorized')
|
||||
redirect(referrer)
|
||||
|
||||
def gridbutton(buttonclass='buttonadd',buttontext='Add',
|
||||
buttonurl=url(args=[]),callback=None,delete=None,trap=True):
|
||||
def gridbutton(buttonclass='buttonadd', buttontext='Add',
|
||||
buttonurl=url(args=[]), callback=None,
|
||||
delete=None, trap=True):
|
||||
if showbuttontext:
|
||||
if callback:
|
||||
return A(SPAN(_class=ui.get(buttonclass)),
|
||||
|
||||
+14
-11
@@ -839,6 +839,7 @@ class Auth(object):
|
||||
table_event = None,
|
||||
table_cas = None,
|
||||
showid = False,
|
||||
use_username = False,
|
||||
login_email_validate = True,
|
||||
login_userfield = None,
|
||||
logout_onlogout = None,
|
||||
@@ -1060,7 +1061,6 @@ class Auth(object):
|
||||
request = current.request
|
||||
session = current.session
|
||||
auth = session.auth
|
||||
self.use_username = None # None means postpone detection
|
||||
self.user_groups = auth and auth.user_groups or {}
|
||||
if auth and auth.last_visit and auth.last_visit + \
|
||||
datetime.timedelta(days=0, seconds=auth.expiration) > request.now:
|
||||
@@ -1251,21 +1251,21 @@ class Auth(object):
|
||||
else:
|
||||
login = A(T('Login'), _href=href('login'))
|
||||
register = A(T('Register'), _href=href('register'))
|
||||
retrieve_username = A(T('Forgot username?'), _href=href('retrieve_username'))
|
||||
lost_password = A(T('Lost password?'), _href=href('request_reset_password'))
|
||||
retrieve_username = A(
|
||||
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')
|
||||
|
||||
if not 'register' in self.settings.actions_disabled:
|
||||
bar.insert(-1, s2)
|
||||
bar.insert(-1, register)
|
||||
if self.use_username is None:
|
||||
# should always be false if auth.define_tables() is called
|
||||
self.use_username = 'username' in self.table_user().fields
|
||||
if self.use_username and \
|
||||
not 'retrieve_username' in self.settings.actions_disabled:
|
||||
if self.settings.use_username and not 'retrieve_username' \
|
||||
in self.settings.actions_disabled:
|
||||
bar.insert(-1, s2)
|
||||
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, lost_password)
|
||||
return bar
|
||||
@@ -1357,7 +1357,7 @@ class Auth(object):
|
||||
writable=False,readable=False,
|
||||
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):
|
||||
"""
|
||||
to be called unless tables are defined manually
|
||||
@@ -1375,7 +1375,10 @@ class Auth(object):
|
||||
|
||||
db = self.db
|
||||
settings = self.settings
|
||||
self.use_username = username
|
||||
if username is None:
|
||||
username = settings.use_username
|
||||
else:
|
||||
settings.use_username = username
|
||||
if not self.signature:
|
||||
self.define_signature()
|
||||
if signature==True:
|
||||
|
||||
Reference in New Issue
Block a user