Compare commits

...
37 Commits
Author SHA1 Message Date
mdipierro 63224e8ce6 2.7.3 2013-10-11 18:10:57 -05:00
mdipierro ff7f9568db fixed validation of nagtive integers, thanks Stefan 2013-10-11 18:06:57 -05:00
mdipierro 3635dd8faf fixed problem with Virtual Fields and grid 2013-10-11 17:59:30 -05:00
mdipierro d5fda056ff simplified logic for number validators 2013-10-11 17:07:17 -05:00
mdipierro d8e8d1d597 fixed problem with IS_INT_IN_RANGE for large numbers 2013-10-11 16:59:05 -05:00
mdipierro 59290534bc fixed issue 1708:gae memcache_contrib does not set the time_expire, thanks Nicholas 2013-10-09 11:58:15 -05:00
mdipierro 8fb0b71be6 fixed compilerapp sorting issue, better 2013-10-09 11:31:33 -05:00
mdipierro ddc0fc9949 fixed compilerapp sorting issue, possibly 2013-10-09 11:15:07 -05:00
mdipierro 5428fdbd04 reverted error commit 2013-10-09 09:07:00 -05:00
Massimo 98f2bfbfb6 Merge branch 'master' of github.com:web2py/web2py 2013-10-08 11:39:30 -05:00
Massimo d780d26cc9 merge heads 2013-10-08 11:38:28 -05:00
mdipierro a5711bd933 Merge pull request #244 from timrichardson/issue/1692
fix for Issue 1692 virtual fields in SQLFORM.grid
2013-10-08 09:35:51 -07:00
mdipierro b96cde2f77 Merge pull request #243 from cccaballero/master
more spanish translations
2013-10-08 09:34:16 -07:00
Tim Richardson a3f3ed1298 fix for Issue 1692 virtual fields in forms 2013-10-08 13:31:36 +11:00
mdipierro 5f34193ac7 fixed demo mode 2013-10-07 09:17:51 -05:00
cccaballero 6fe6852a0c more spanish translations
more spanish translations
2013-10-07 09:49:48 -04:00
mdipierro 961d143f7d 2.7.2 2013-10-07 08:40:39 -05:00
mdipierro 0e98544a79 Merge pull request #242 from rhr/master
fix for using the shell with IPython >= 1.0
2013-10-06 19:37:56 -07:00
mdipierro 86d8b8dece Merge pull request #241 from spametki/master
IMAP fixed patch for google code issue 1707
2013-10-06 19:37:11 -07:00
Rick Ree 46e2a663e9 fix for using the shell with IPython >= 1.0 2013-10-06 17:18:04 -05:00
spametki e7fbd0095f IMAP google code issue 1707: fixed patch 2013-10-06 14:39:23 -03:00
mdipierro add6fa526e fixed regex status in http.py 2013-10-06 11:52:23 -05:00
mdipierro 47e77e9a9c Merge pull request #239 from abastardi/patch-1
Fixed problem with Rows.render
2013-10-06 08:15:09 -07:00
mdipierro 81036ac997 Merge pull request #237 from alfonsodg/master
Added gitignore restrictions and changes for admin.py
2013-10-06 08:13:58 -07:00
mdipierro 77df883566 Merge pull request #236 from niphlod/enhancement/anyserver_options
fixed gevent workers
2013-10-06 08:11:03 -07:00
mdipierro bfc7e3b4e9 Merge pull request #238 from houdinihound/patch-1
Support for HTTP Status Code: 429 - Too Many Requests
2013-10-06 08:09:52 -07:00
spametki e05fe15470 IMAP .insert support for custom date (Google Code issue 1707) 2013-10-06 12:09:44 -03:00
mdipierro 2a062a2ff5 fixed setup scripts for apache to use processes, not threads, thanks Thomas 2013-10-06 10:08:40 -05:00
abastardi 44e7b70dbc Fixed problem with Rows.render 2013-10-06 09:04:47 -04:00
Jose C 88abefb896 Support for HTTP Status Code: 429 - Too Many Requests
Currently raising HTTP 429 results in HTTP 500 being sent.  This patch resolves that issue.
2013-10-05 15:42:48 +01:00
mdipierro 06ca5e6857 grid refcator patch for ajax, thanks Niphlod 2013-10-05 08:52:45 -05:00
Alfonso de la Guarda Reyes c1f8d34892 Minor fixes for pep and styles widget.py 2013-10-05 08:08:37 -05:00
Alfonso de la Guarda Reyes 5679661914 Minor fixes for pep and style 2013-10-05 08:03:50 -05:00
Alfonso de la Guarda Reyes cd957cf52b Fixes for some pep and code syntax 2013-10-05 07:59:04 -05:00
Alfonso de la Guarda Reyes fff798c1cc Added restriction for .idea inside gitignore 2013-10-05 07:51:12 -05:00
niphlod b464d3185e fixed gevent workers 2013-10-05 13:43:03 +02:00
mdipierro cfb68ff90f fixed ldap_auth.py 2013-10-04 21:31:39 -05:00
24 changed files with 269 additions and 270 deletions
+1
View File
@@ -55,3 +55,4 @@ applications/admin/cron/cron.master
HOWTO-web2py-devel HOWTO-web2py-devel
*.sublime-project *.sublime-project
*.sublime-workspace *.sublime-workspace
.idea/*
+1 -1
View File
@@ -1,4 +1,4 @@
## 2.7.1 ## 2.7.1 - 2.7.2
- jQuery 1.10.2 - jQuery 1.10.2
- codemirror 3.18, thanks Paolo - codemirror 3.18, thanks Paolo
+1 -1
View File
@@ -30,7 +30,7 @@ update:
echo "remember that pymysql was tweaked" echo "remember that pymysql was tweaked"
src: src:
### Use semantic versioning ### Use semantic versioning
echo 'Version 2.7.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION echo 'Version 2.7.3-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > 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
View File
@@ -1 +1 @@
Version 2.7.1-stable+timestamp.2013.10.04.15.14.09 Version 2.7.3-stable+timestamp.2013.10.11.18.10.01
+34 -26
View File
@@ -33,7 +33,7 @@ class Servers:
@staticmethod @staticmethod
def wsgiref(app, address, **options): # pragma: no cover def wsgiref(app, address, **options): # pragma: no cover
from wsgiref.simple_server import make_server, WSGIRequestHandler from wsgiref.simple_server import make_server, WSGIRequestHandler
options = {}
class QuietHandler(WSGIRequestHandler): class QuietHandler(WSGIRequestHandler):
def log_request(*args, **kw): def log_request(*args, **kw):
pass pass
@@ -71,6 +71,7 @@ class Servers:
@staticmethod @staticmethod
def paste(app, address, **options): def paste(app, address, **options):
options = {}
from paste import httpserver from paste import httpserver
from paste.translogger import TransLogger from paste.translogger import TransLogger
httpserver.serve(app, host=address[0], port=address[1], **options) httpserver.serve(app, host=address[0], port=address[1], **options)
@@ -90,10 +91,12 @@ class Servers:
@staticmethod @staticmethod
def gevent(app, address, **options): def gevent(app, address, **options):
options = options['options']
workers = options.workers
from gevent import pywsgi from gevent import pywsgi
from gevent.pool import Pool from gevent.pool import Pool
pywsgi.WSGIServer(address, app, spawn='workers' in options and Pool( pywsgi.WSGIServer(address, app, spawn=workers and Pool(
int(options.workers)) or 'default').serve_forever() int(options.workers)) or 'default', log=None).serve_forever()
@staticmethod @staticmethod
def bjoern(app, address, **options): def bjoern(app, address, **options):
@@ -130,6 +133,7 @@ class Servers:
@staticmethod @staticmethod
def gunicorn(app, address, **options): def gunicorn(app, address, **options):
options = {}
from gunicorn.app.base import Application from gunicorn.app.base import Application
config = {'bind': "%s:%d" % address} config = {'bind': "%s:%d" % address}
config.update(options) config.update(options)
@@ -176,27 +180,6 @@ class Servers:
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address) s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
s.start() s.start()
def run(servername, ip, port, softcron=True, logging=False, profiler=None):
if servername == 'gevent':
from gevent import monkey
monkey.patch_all()
elif servername == 'eventlet':
import eventlet
eventlet.monkey_patch()
import gluon.main
if logging:
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
logfilename='httpserver.log',
profiler_dir=profiler)
else:
application = gluon.main.wsgibase
if softcron:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
getattr(Servers, servername)(application, (ip, int(port)))
def mongrel2_handler(application, conn, debug=False): def mongrel2_handler(application, conn, debug=False):
""" """
@@ -303,6 +286,30 @@ def mongrel2_handler(application, conn, debug=False):
req, data, code=code, status=status, headers=headers) req, data, code=code, status=status, headers=headers)
def run(servername, ip, port, softcron=True, logging=False, profiler=None,
options=None):
if servername == 'gevent':
from gevent import monkey
monkey.patch_all()
elif servername == 'eventlet':
import eventlet
eventlet.monkey_patch()
import gluon.main
if logging:
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
logfilename='httpserver.log',
profiler_dir=profiler)
else:
application = gluon.main.wsgibase
if softcron:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
getattr(Servers, servername)(application, (ip, int(port)), options=options)
def main(): def main():
usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P" usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P"
try: try:
@@ -339,14 +346,15 @@ def main():
help='port number') help='port number')
parser.add_option('-w', parser.add_option('-w',
'--workers', '--workers',
default='', default=None,
dest='workers', dest='workers',
help='number of workers number') help='number of workers number')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
print 'starting %s on %s:%s...' % ( print 'starting %s on %s:%s...' % (
options.server, options.ip, options.port) options.server, options.ip, options.port)
run(options.server, options.ip, options.port, run(options.server, options.ip, options.port,
logging=options.logging, profiler=options.profiler_dir) logging=options.logging, profiler=options.profiler_dir,
options=options)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
+67 -64
View File
@@ -7,33 +7,35 @@
'%s %%{row} updated': '%s filas actualizadas', '%s %%{row} updated': '%s filas actualizadas',
'%Y-%m-%d': '%Y-%m-%d', '%Y-%m-%d': '%Y-%m-%d',
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
'(requires internet access, experimental)': '(requires internet access, experimental)', '(requires internet access, experimental)': '(requiere acceso a internet, experimental)',
'(something like "it-it")': '(algo como "it-it")', '(something like "it-it")': '(algo como "it-it")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)', '@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files', '@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
'A new version of web2py is available': 'Hay una nueva versión de web2py disponible', 'A new version of web2py is available': 'Hay una nueva versión de web2py disponible',
'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s', 'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s',
'About': 'acerca de', 'About': 'acerca de',
'About application': 'Acerca de la aplicación', 'About application': 'Acerca de la aplicación',
'additional code for your application': 'código adicional para su aplicación', 'additional code for your application': 'código adicional para su aplicación',
'Additional code for your application': 'Additional code for your application', 'Additional code for your application': 'Código adicional para su aplicación',
'admin disabled because no admin password': ' por falta de contraseña', 'admin disabled because no admin password': 'admin deshabilitado por falta de contraseña',
'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE', 'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE',
'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña', 'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña',
'Admin is disabled because insecure channel': 'Admin deshabilitado, el canal no es seguro', 'Admin is disabled because insecure channel': 'Admin deshabilitado, el canal no es seguro',
'Admin is disabled because unsecure channel': 'Admin deshabilitado, el canal no es seguro', 'Admin is disabled because unsecure channel': 'Admin deshabilitado, el canal no es seguro',
'Admin language': 'Admin language', 'Admin language': 'Lenguaje de administración',
'administrative interface': 'administrative interface', 'administrative interface': 'interfaz administrativa',
'Administrator Password:': 'Contraseña del Administrador:', 'Administrator Password:': 'Contraseña del Administrador:',
'An error occured, please %s the page': 'An error occured, please %s the page', 'An error occured, please %s the page': 'Ha ocurrido un error, por favor %s la página',
'and rename it (required):': 'y renombrela (requerido):', 'and rename it (required):': 'y renombrela (requerido):',
'and rename it:': ' y renombrelo:', 'and rename it:': ' y renombrelo:',
'appadmin': 'appadmin', 'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro', 'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro',
'application "%s" uninstalled': 'aplicación "%s" desinstalada', 'application "%s" uninstalled': 'aplicación "%s" desinstalada',
'application %(appname)s installed with md5sum: %(digest)s': 'application %(appname)s installed with md5sum: %(digest)s',
'application compiled': 'aplicación compilada', 'application compiled': 'aplicación compilada',
'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada', 'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada',
'Application name:': 'Application name:', 'Application name:': 'Nombre de la aplicación:',
'are not used': 'are not used', 'are not used': 'are not used',
'are not used yet': 'are not used yet', 'are not used yet': 'are not used yet',
'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?', 'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?',
@@ -43,13 +45,13 @@
'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?', 'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?',
'Are you sure you want to upgrade web2py now?': '¿Está seguro que desea actualizar web2py ahora?', 'Are you sure you want to upgrade web2py now?': '¿Está seguro que desea actualizar web2py ahora?',
'arguments': 'argumentos', 'arguments': 'argumentos',
'at char %s': 'at char %s', 'at char %s': 'en el caracter %s',
'at line %s': 'at line %s', 'at line %s': 'en la línea %s',
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.', 'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.', 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.',
'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que se ejecuta!', 'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que se ejecuta!',
'Autocomplete': 'Autocomplete', 'Autocomplete': 'Autocomplete',
'Autocomplete Python Code': 'Autocomplete Python Code', 'Autocomplete Python Code': 'Autocompletar código Python',
'Available databases and tables': 'Bases de datos y tablas disponibles', 'Available databases and tables': 'Bases de datos y tablas disponibles',
'back': 'atrás', 'back': 'atrás',
'breakpoint': 'breakpoint', 'breakpoint': 'breakpoint',
@@ -57,17 +59,17 @@
'browse': 'buscar', 'browse': 'buscar',
'cache': 'cache', 'cache': 'cache',
'cache, errors and sessions cleaned': 'cache, errores y sesiones eliminados', 'cache, errors and sessions cleaned': 'cache, errores y sesiones eliminados',
'can be a git repo': 'can be a git repo', 'can be a git repo': 'puede ser un repositorio git',
'Cannot be empty': 'No puede estar vacío', 'Cannot be empty': 'No puede estar vacío',
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se puede compilar: hay errores en su aplicación. Depure, corrija errores y vuelva a intentarlo.', 'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se puede compilar: hay errores en su aplicación. Depure, corrija errores y vuelva a intentarlo.',
'Cannot compile: there are errors in your app:': 'No se puede compilar: hay errores en su aplicación:', 'Cannot compile: there are errors in your app:': 'No se puede compilar: hay errores en su aplicación:',
'cannot create file': 'no es posible crear archivo', 'cannot create file': 'no es posible crear archivo',
'cannot upload file "%(filename)s"': 'no es posible subir archivo "%(filename)s"', 'cannot upload file "%(filename)s"': 'no es posible subir archivo "%(filename)s"',
'Change admin password': 'cambie contraseña admin', 'Change admin password': 'cambie contraseña admin',
'change editor settings': 'change editor settings', 'change editor settings': 'cambiar la configuración del editor',
'Change Password': 'Cambie Contraseña', 'Change Password': 'Cambie Contraseña',
'check all': 'marcar todos', 'check all': 'marcar todos',
'Check for upgrades': 'Check for upgrades', 'Check for upgrades': 'buscar actualizaciones',
'Check to delete': 'Marque para eliminar', 'Check to delete': 'Marque para eliminar',
'Checking for upgrades...': 'Buscando actulizaciones...', 'Checking for upgrades...': 'Buscando actulizaciones...',
'Clean': 'limpiar', 'Clean': 'limpiar',
@@ -75,23 +77,24 @@
'click here for the administrative interface': 'haga clic aquí para usar la interfaz administrativa', 'click here for the administrative interface': 'haga clic aquí para usar la interfaz administrativa',
'Click row to expand traceback': 'Click row to expand traceback', 'Click row to expand traceback': 'Click row to expand traceback',
'click to check for upgrades': 'haga clic para buscar actualizaciones', 'click to check for upgrades': 'haga clic para buscar actualizaciones',
'click to open': 'click to open', 'click to open': 'click para abrir',
'Client IP': 'IP del Cliente', 'Client IP': 'IP del Cliente',
'code': 'código', 'code': 'código',
'Code listing': 'Code listing', 'Code listing': 'Listado de código',
'collapse/expand all': 'collapse/expand all', 'collapse/expand all': 'contraer/expandir todo',
'commit (mercurial)': 'commit (mercurial)', 'commit (mercurial)': 'confirmar (mercurial)',
'Compile': 'compilar', 'Compile': 'compilar',
'compiled application removed': 'aplicación compilada removida', 'compiled application removed': 'aplicación compilada removida',
'continue': 'continue', 'continue': 'continuar',
'Controllers': 'Controladores', 'Controllers': 'Controladores',
'controllers': 'controladores', 'controllers': 'controladores',
'Count': 'Count', 'Count': 'Count',
'Create': 'crear', 'Create': 'Crear',
'create file with filename:': 'cree archivo con nombre:', 'create file with filename:': 'cree archivo con nombre:',
'Create new application using the Wizard': 'Create new application using the Wizard', 'Create new application using the Wizard': 'Crear nueva aplicación utilizando el asistente',
'create new application:': 'nombre de la nueva aplicación:', 'create new application:': 'nombre de la nueva aplicación:',
'Create new simple application': 'Cree una nueva aplicación', 'Create new simple application': 'Cree una nueva aplicación',
'Create/Upload': 'Create/Upload',
'created by': 'creado por', 'created by': 'creado por',
'crontab': 'crontab', 'crontab': 'crontab',
'Current request': 'Solicitud en curso', 'Current request': 'Solicitud en curso',
@@ -112,25 +115,25 @@
'delete': 'eliminar', 'delete': 'eliminar',
'delete all checked': 'eliminar marcados', 'delete all checked': 'eliminar marcados',
'delete plugin': 'eliminar plugin', 'delete plugin': 'eliminar plugin',
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)', 'Delete this file (you will be asked to confirm deletion)': 'Elimine este fichero (se le pedirá confirmación)',
'Delete:': 'Elimine:', 'Delete:': 'Elimine:',
'Deploy': 'Deploy', 'Deploy': 'Deploy',
'Deploy on Google App Engine': 'Instale en Google App Engine', 'Deploy on Google App Engine': 'Instale en Google App Engine',
'Deploy to OpenShift': 'Deploy to OpenShift', 'Deploy to OpenShift': 'Instale en OpenShift',
'Description': 'Descripción', 'Description': 'Descripción',
'design': 'modificar', 'design': 'modificar',
'DESIGN': 'DISEÑO', 'DESIGN': 'DISEÑO',
'Design for': 'Diseño para', 'Design for': 'Diseño para',
'Detailed traceback description': 'Detailed traceback description', 'Detailed traceback description': 'Detailed traceback description',
'details': 'details', 'details': 'detalles',
'direction: ltr': 'direction: ltr', 'direction: ltr': 'direction: ltr',
'Disable': 'Disable', 'Disable': 'Deshabilitar',
'docs': 'docs', 'docs': 'docs',
'done!': 'listo!', 'done!': 'listo!',
'Download': 'Download', 'Download': 'Descargar',
'download files via http:': 'download files via http:', 'download files via http:': 'descargar archivos via http:',
'download layouts': 'download layouts', 'download layouts': 'descargar layouts',
'download plugins': 'download plugins', 'download plugins': 'descargar plugins',
'E-mail': 'Correo electrónico', 'E-mail': 'Correo electrónico',
'EDIT': 'EDITAR', 'EDIT': 'EDITAR',
'Edit': 'editar', 'Edit': 'editar',
@@ -157,7 +160,7 @@
'Expand Abbreviation': 'Expand Abbreviation', 'Expand Abbreviation': 'Expand Abbreviation',
'export as csv file': 'exportar como archivo CSV', 'export as csv file': 'exportar como archivo CSV',
'exposes': 'expone', 'exposes': 'expone',
'exposes:': 'exposes:', 'exposes:': 'expone:',
'extends': 'extiende', 'extends': 'extiende',
'failed to compile file because:': 'failed to compile file because:', 'failed to compile file because:': 'failed to compile file because:',
'failed to reload module': 'recarga del módulo ha fallado', 'failed to reload module': 'recarga del módulo ha fallado',
@@ -173,8 +176,8 @@
'file saved on %(time)s': 'archivo guardado %(time)s', 'file saved on %(time)s': 'archivo guardado %(time)s',
'file saved on %s': 'archivo guardado %s', 'file saved on %s': 'archivo guardado %s',
'filter': 'filter', 'filter': 'filter',
'Find Next': 'Find Next', 'Find Next': 'Buscar próximo',
'Find Previous': 'Find Previous', 'Find Previous': 'Bucar anterior',
'First name': 'Nombre', 'First name': 'Nombre',
'Frames': 'Frames', 'Frames': 'Frames',
'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].', 'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].',
@@ -221,8 +224,8 @@
'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa', 'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa',
'Logout': 'fin de sesión', 'Logout': 'fin de sesión',
'Lost Password': 'Contraseña perdida', 'Lost Password': 'Contraseña perdida',
'manage': 'manage', 'manage': 'gestionar',
'Manage': 'Manage', 'Manage': 'Gestionar',
'merge': 'combinar', 'merge': 'combinar',
'Models': 'Modelos', 'Models': 'Modelos',
'models': 'modelos', 'models': 'modelos',
@@ -230,11 +233,11 @@
'modules': 'módulos', 'modules': 'módulos',
'Name': 'Nombre', 'Name': 'Nombre',
'new application "%s" created': 'nueva aplicación "%s" creada', 'new application "%s" created': 'nueva aplicación "%s" creada',
'New application wizard': 'New application wizard', 'New application wizard': 'Asistente para nueva aplicación',
'new plugin installed': 'nuevo plugin instalado', 'new plugin installed': 'nuevo plugin instalado',
'New Record': 'Registro nuevo', 'New Record': 'Registro nuevo',
'new record inserted': 'nuevo registro insertado', 'new record inserted': 'nuevo registro insertado',
'New simple application': 'New simple application', 'New simple application': 'Nueva aplicación',
'next': 'next', 'next': 'next',
'next 100 rows': '100 filas siguientes', 'next 100 rows': '100 filas siguientes',
'NO': 'NO', 'NO': 'NO',
@@ -245,16 +248,16 @@
'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder', 'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder',
'online designer': 'online designer', 'online designer': 'online designer',
'or alternatively': 'or alternatively', 'or alternatively': 'or alternatively',
'Or Get from URL:': 'Or Get from URL:', 'Or Get from URL:': 'O obtener desde una URL:',
'or import from csv file': 'o importar desde archivo CSV', 'or import from csv file': 'o importar desde archivo CSV',
'or provide app url:': 'o provea URL de la aplicación:', 'or provide app url:': 'o provea URL de la aplicación:',
'or provide application url:': 'o provea URL de la aplicación:', 'or provide application url:': 'o provea URL de la aplicación:',
'Origin': 'Origen', 'Origin': 'Origen',
'Original/Translation': 'Original/Traducción', 'Original/Translation': 'Original/Traducción',
'Overwrite installed app': 'sobreescriba aplicación instalada', 'Overwrite installed app': 'sobreescriba la aplicación instalada',
'Pack all': 'empaquetar todo', 'Pack all': 'empaquetar todo',
'Pack compiled': 'empaquete compiladas', 'Pack compiled': 'empaquete compiladas',
'Pack custom': 'Pack custom', 'Pack custom': 'empaquetar personalizado',
'pack plugin': 'empaquetar plugin', 'pack plugin': 'empaquetar plugin',
'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, no puede cambiar la contraseña aquí', 'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, no puede cambiar la contraseña aquí',
'Password': 'Contraseña', 'Password': 'Contraseña',
@@ -268,8 +271,8 @@
'Plural-Forms:': 'Plural-Forms:', 'Plural-Forms:': 'Plural-Forms:',
'Powered by': 'Este sitio usa', 'Powered by': 'Este sitio usa',
'previous 100 rows': '100 filas anteriores', 'previous 100 rows': '100 filas anteriores',
'Private files': 'Private files', 'Private files': 'Archivos privados',
'private files': 'private files', 'private files': 'archivos privados',
'Query:': 'Consulta:', 'Query:': 'Consulta:',
'Rapid Search': 'Rapid Search', 'Rapid Search': 'Rapid Search',
'record': 'registro', 'record': 'registro',
@@ -282,9 +285,9 @@
'reload': 'reload', 'reload': 'reload',
'Reload routes': 'Reload routes', 'Reload routes': 'Reload routes',
'Remove compiled': 'eliminar compiladas', 'Remove compiled': 'eliminar compiladas',
'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s', 'Removed Breakpoint on %s at line %s': 'Eliminado punto de ruptura en %s en la línea %s',
'Replace': 'Replace', 'Replace': 'Reemplazar',
'Replace All': 'Replace All', 'Replace All': 'Reemplazar todos',
'request': 'request', 'request': 'request',
'Resolve Conflict file': 'archivo Resolución de Conflicto', 'Resolve Conflict file': 'archivo Resolución de Conflicto',
'response': 'response', 'response': 'response',
@@ -300,19 +303,19 @@
'Running on %s': 'Running on %s', 'Running on %s': 'Running on %s',
'Save': 'Save', 'Save': 'Save',
'save': 'guardar', 'save': 'guardar',
'Save file:': 'Save file:', 'Save file:': 'Guardar:',
'Save file: %s': 'Save file: %s', 'Save file: %s': 'Guardar: %s',
'Save via Ajax': 'Save via Ajax', 'Save via Ajax': 'Guardar via Ajax',
'Saved file hash:': 'Hash del archivo guardado:', 'Saved file hash:': 'Hash del archivo guardado:',
'selected': 'seleccionado(s)', 'selected': 'seleccionado(s)',
'session': 'session', 'session': 'session',
'session expired': 'sesión expirada', 'session expired': 'sesión expirada',
'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s', 'Set Breakpoint on %s at line %s: %s': 'Establecer punto de ruptura en %s en la línea %s: %s',
'shell': 'shell', 'shell': 'shell',
'Site': 'sitio', 'Site': 'sitio',
'some files could not be removed': 'algunos archivos no pudieron ser removidos', 'some files could not be removed': 'algunos archivos no pudieron ser removidos',
'Start searching': 'Start searching', 'Start searching': 'Iniciar búsqueda',
'Start wizard': 'Start wizard', 'Start wizard': 'Iniciar asistente',
'state': 'estado', 'state': 'estado',
'Static': 'Static', 'Static': 'Static',
'static': 'estáticos', 'static': 'estáticos',
@@ -321,7 +324,7 @@
'stop': 'stop', 'stop': 'stop',
'submit': 'enviar', 'submit': 'enviar',
'Submit': 'Submit', 'Submit': 'Submit',
'successful': 'successful', 'successful': 'exitoso',
'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?', 'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?',
'table': 'tabla', 'table': 'tabla',
'Table name': 'Nombre de la tabla', 'Table name': 'Nombre de la tabla',
@@ -329,21 +332,21 @@
'Testing application': 'Probando aplicación', 'Testing application': 'Probando aplicación',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.', 'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.',
'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador', 'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller', 'The application logic, each URL path is mapped in one exposed function in the controller': 'La lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
'the data representation, define database tables and sets': 'la representación de datos, define tablas y conjuntos de base de datos', 'the data representation, define database tables and sets': 'la representación de datos, define tablas y conjuntos de base de datos',
'The data representation, define database tables and sets': 'The data representation, define database tables and sets', 'The data representation, define database tables and sets': 'La representación de datos, define tablas y conjuntos de base de datos',
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates', 'The presentations layer, views are also known as templates': 'La capa de presentación, las vistas también son llamadas plantillas',
'the presentations layer, views are also known as templates': 'la capa de presentación, las vistas también son llamadas plantillas', 'the presentations layer, views are also known as templates': 'la capa de presentación, las vistas también son llamadas plantillas',
'There are no controllers': 'No hay controladores', 'There are no controllers': 'No hay controladores',
'There are no models': 'No hay modelos', 'There are no models': 'No hay modelos',
'There are no modules': 'No hay módulos', 'There are no modules': 'No hay módulos',
'There are no plugins': 'There are no plugins', 'There are no plugins': 'No hay plugins',
'There are no private files': 'There are no private files', 'There are no private files': 'No hay archivos privados',
'There are no static files': 'No hay archivos estáticos', 'There are no static files': 'No hay archivos estáticos',
'There are no translators, only default language is supported': 'No hay traductores, sólo el lenguaje por defecto es soportado', 'There are no translators, only default language is supported': 'No hay traductores, sólo el lenguaje por defecto es soportado',
'There are no views': 'No hay vistas', 'There are no views': 'No hay vistas',
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app', 'These files are not served, they are only available from within your app': 'Estos archivos no son servidos, ellos solo estan disponibles para su aplicación',
'These files are served without processing, your images go here': 'These files are served without processing, your images go here', 'These files are served without processing, your images go here': 'Estos archivos son servidos sin procesar, sus imágenes van aquí',
'these files are served without processing, your images go here': 'estos archivos son servidos sin procesar, sus imágenes van aquí', 'these files are served without processing, your images go here': 'estos archivos son servidos sin procesar, sus imágenes van aquí',
'This is the %(filename)s template': 'Esta es la plantilla %(filename)s', 'This is the %(filename)s template': 'Esta es la plantilla %(filename)s',
'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.', 'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.',
@@ -355,14 +358,14 @@
'To create a plugin, name a file/folder plugin_[name]': 'Para crear un plugin, nombre un archivo/carpeta plugin_[nombre]', 'To create a plugin, name a file/folder plugin_[name]': 'Para crear un plugin, nombre un archivo/carpeta plugin_[nombre]',
'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:', 'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:',
'to use the debugger!': 'to use the debugger!', 'to use the debugger!': 'to use the debugger!',
'toggle breakpoint': 'toggle breakpoint', 'toggle breakpoint': 'alternar punto de ruptura',
'Toggle Fullscreen': 'Toggle Fullscreen', 'Toggle Fullscreen': 'Alternar pantalla completa',
'Traceback': 'Traceback', 'Traceback': 'Traceback',
'translation strings for the application': 'cadenas de caracteres de traducción para la aplicación', 'translation strings for the application': 'cadenas de caracteres de traducción para la aplicación',
'Translation strings for the application': 'Translation strings for the application', 'Translation strings for the application': 'Cadenas de caracteres de traducción para la aplicación',
'try': 'intente', 'try': 'intente',
'try something like': 'intente algo como', 'try something like': 'intente algo como',
'Try the mobile interface': 'Try the mobile interface', 'Try the mobile interface': 'Pruebe la interfaz móvil',
'try view': 'try view', 'try view': 'try view',
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.', 'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones', 'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones',
@@ -383,10 +386,10 @@
'Update:': 'Actualice:', 'Update:': 'Actualice:',
'upgrade now to %s': 'upgrade now to %s', 'upgrade now to %s': 'upgrade now to %s',
'upgrade web2py now': 'actualize web2py ahora', 'upgrade web2py now': 'actualize web2py ahora',
'Upload': 'Upload', 'Upload': 'Subir',
'Upload & install packed application': 'Suba e instale aplicación empaquetada', 'Upload & install packed application': 'Suba e instale aplicación empaquetada',
'Upload a package:': 'Upload a package:', 'Upload a package:': 'Subir un paquete:',
'Upload and install packed application': 'Upload and install packed application', 'Upload and install packed application': 'Suba e instale una aplicación empaquetada',
'upload application:': 'subir aplicación:', 'upload application:': 'subir aplicación:',
'Upload existing application': 'Suba esta aplicación', 'Upload existing application': 'Suba esta aplicación',
'upload file:': 'suba archivo:', 'upload file:': 'suba archivo:',
+5
View File
@@ -8,6 +8,7 @@ from gluon.fileutils import read_file
# ## make sure administrator is on localhost or https # ## make sure administrator is on localhost or https
# ########################################################### # ###########################################################
http_host = request.env.http_host.split(':')[0] http_host = request.env.http_host.split(':')[0]
if request.env.web2py_runtime_gae: if request.env.web2py_runtime_gae:
@@ -145,6 +146,10 @@ elif session.is_mobile == 'false':
else: else:
is_mobile = request.user_agent().is_mobile is_mobile = request.user_agent().is_mobile
if DEMO_MODE:
session.authorized = True
session.forget()
if request.controller == "webservices": if request.controller == "webservices":
basic = request.env.http_authorization basic = request.env.http_authorization
if not basic or not basic[:6].lower() == 'basic ': if not basic or not basic[:6].lower() == 'basic ':
-13
View File
@@ -264,16 +264,6 @@
} }
}); });
}, },
trap_link: function (target) {
$('#' + target + ' a.w2p_trap').each(function (i) {
var link = $(this);
link.click(function (e) {
web2py.hide_flash();
web2py.ajax_page('get', link.attr('href'), [], target, $(this));
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) { ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */ /* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document); if(element == undefined) element = $(document);
@@ -307,7 +297,6 @@
web2py.fire(element, 'ajax:complete', [xhr, status], target); web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */ web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target); web2py.trap_form(action, target);
web2py.trap_link(target);
web2py.ajax_init('#' + target); web2py.ajax_init('#' + target);
web2py.after_ajax(xhr); web2py.after_ajax(xhr);
} }
@@ -692,10 +681,8 @@ collapse = jQuery.web2py.collapse;
fade = jQuery.web2py.fade; fade = jQuery.web2py.fade;
/* internals - shouldn't be needed /* internals - shouldn't be needed
web2py_ajax_init = jQuery.web2py.ajax_init; web2py_ajax_init = jQuery.web2py.ajax_init;
web2py_event_handlers = jQuery.web2py.event_handlers; web2py_event_handlers = jQuery.web2py.event_handlers;
web2py_trap_link = jQuery.web2py.trap_link; web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy; web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/ */
-13
View File
@@ -264,16 +264,6 @@
} }
}); });
}, },
trap_link: function (target) {
$('#' + target + ' a.w2p_trap').each(function (i) {
var link = $(this);
link.click(function (e) {
web2py.hide_flash();
web2py.ajax_page('get', link.attr('href'), [], target, $(this));
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) { ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */ /* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document); if(element == undefined) element = $(document);
@@ -307,7 +297,6 @@
web2py.fire(element, 'ajax:complete', [xhr, status], target); web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */ web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target); web2py.trap_form(action, target);
web2py.trap_link(target);
web2py.ajax_init('#' + target); web2py.ajax_init('#' + target);
web2py.after_ajax(xhr); web2py.after_ajax(xhr);
} }
@@ -692,10 +681,8 @@ collapse = jQuery.web2py.collapse;
fade = jQuery.web2py.fade; fade = jQuery.web2py.fade;
/* internals - shouldn't be needed /* internals - shouldn't be needed
web2py_ajax_init = jQuery.web2py.ajax_init; web2py_ajax_init = jQuery.web2py.ajax_init;
web2py_event_handlers = jQuery.web2py.event_handlers; web2py_event_handlers = jQuery.web2py.event_handlers;
web2py_trap_link = jQuery.web2py.trap_link; web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy; web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/ */
-13
View File
@@ -264,16 +264,6 @@
} }
}); });
}, },
trap_link: function (target) {
$('#' + target + ' a.w2p_trap').each(function (i) {
var link = $(this);
link.click(function (e) {
web2py.hide_flash();
web2py.ajax_page('get', link.attr('href'), [], target, $(this));
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) { ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */ /* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document); if(element == undefined) element = $(document);
@@ -307,7 +297,6 @@
web2py.fire(element, 'ajax:complete', [xhr, status], target); web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */ web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target); web2py.trap_form(action, target);
web2py.trap_link(target);
web2py.ajax_init('#' + target); web2py.ajax_init('#' + target);
web2py.after_ajax(xhr); web2py.after_ajax(xhr);
} }
@@ -692,10 +681,8 @@ collapse = jQuery.web2py.collapse;
fade = jQuery.web2py.fade; fade = jQuery.web2py.fade;
/* internals - shouldn't be needed /* internals - shouldn't be needed
web2py_ajax_init = jQuery.web2py.ajax_init; web2py_ajax_init = jQuery.web2py.ajax_init;
web2py_event_handlers = jQuery.web2py.event_handlers; web2py_event_handlers = jQuery.web2py.event_handlers;
web2py_trap_link = jQuery.web2py.trap_link; web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy; web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/ */
+5 -6
View File
@@ -353,7 +353,7 @@ def plugin_install(app, fobj, request, filename):
return False return False
def check_new_version(myversion, version_URL): def check_new_version(myversion, version_url):
""" """
Compares current web2py's version with the latest stable web2py version. Compares current web2py's version with the latest stable web2py version.
@@ -374,7 +374,7 @@ def check_new_version(myversion, version_URL):
""" """
try: try:
from urllib import urlopen from urllib import urlopen
version = urlopen(version_URL).read() version = urlopen(version_url).read()
pversion = parse_version(version) pversion = parse_version(version)
pmyversion = parse_version(myversion) pmyversion = parse_version(myversion)
except IOError: except IOError:
@@ -398,7 +398,7 @@ def unzip(filename, dir, subfolder=''):
raise RuntimeError('Not a valid zipfile') raise RuntimeError('Not a valid zipfile')
zf = zipfile.ZipFile(filename) zf = zipfile.ZipFile(filename)
if not subfolder.endswith('/'): if not subfolder.endswith('/'):
subfolder = subfolder + '/' subfolder += '/'
n = len(subfolder) n = len(subfolder)
for name in sorted(zf.namelist()): for name in sorted(zf.namelist()):
if not name.startswith(subfolder): if not name.startswith(subfolder):
@@ -432,11 +432,11 @@ def upgrade(request, url='http://web2py.com'):
web2py_version = request.env.web2py_version web2py_version = request.env.web2py_version
gluon_parent = request.env.gluon_parent gluon_parent = request.env.gluon_parent
if not gluon_parent.endswith('/'): if not gluon_parent.endswith('/'):
gluon_parent = gluon_parent + '/' gluon_parent += '/'
(check, version) = check_new_version(web2py_version, (check, version) = check_new_version(web2py_version,
url + '/examples/default/version') url + '/examples/default/version')
if not check: if not check:
return (False, 'Already latest version') return False, 'Already latest version'
if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')): if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
version_type = 'win' version_type = 'win'
destination = gluon_parent destination = gluon_parent
@@ -452,7 +452,6 @@ def upgrade(request, url='http://web2py.com'):
full_url = url + '/examples/static/web2py_%s.zip' % version_type full_url = url + '/examples/static/web2py_%s.zip' % version_type
filename = abspath('web2py_%s_downloaded.zip' % version_type) filename = abspath('web2py_%s_downloaded.zip' % version_type)
file = None
try: try:
write_file(filename, urllib.urlopen(full_url).read(), 'wb') write_file(filename, urllib.urlopen(full_url).read(), 'wb')
except Exception, e: except Exception, e:
+1 -3
View File
@@ -19,7 +19,6 @@ When web2py is running on Google App Engine,
caching will be provided by the GAE memcache caching will be provided by the GAE memcache
(see gluon.contrib.gae_memcache) (see gluon.contrib.gae_memcache)
""" """
import traceback
import time import time
import portalocker import portalocker
import shelve import shelve
@@ -278,7 +277,7 @@ class CacheOnDisk(CacheAbstract):
storage = shelve.open(self.shelve_name) storage = shelve.open(self.shelve_name)
except: except:
logger.error('corrupted cache file %s, will try rebuild it' logger.error('corrupted cache file %s, will try rebuild it'
% (self.shelve_name)) % self.shelve_name)
storage = None storage = None
if not storage and os.path.exists(self.shelve_name): if not storage and os.path.exists(self.shelve_name):
os.unlink(self.shelve_name) os.unlink(self.shelve_name)
@@ -479,7 +478,6 @@ class Cache(object):
if not session_ and public_: if not session_ and public_:
cache_control += ', public' cache_control += ', public'
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime('%a, %d %b %Y %H:%M:%S GMT') expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime('%a, %d %b %Y %H:%M:%S GMT')
vary = None
else: else:
cache_control += ', private' cache_control += ', private'
expires = 'Fri, 01 Jan 1990 00:00:00 GMT' expires = 'Fri, 01 Jan 1990 00:00:00 GMT'
+63 -45
View File
@@ -380,7 +380,6 @@ _base_environment_['SQLFORM'] = SQLFORM
_base_environment_['SQLTABLE'] = SQLTABLE _base_environment_['SQLTABLE'] = SQLTABLE
_base_environment_['LOAD'] = LOAD _base_environment_['LOAD'] = LOAD
def build_environment(request, response, session, store_current=True): def build_environment(request, response, session, store_current=True):
""" """
Build the environment dictionary into which web2py files are executed. Build the environment dictionary into which web2py files are executed.
@@ -392,8 +391,11 @@ def build_environment(request, response, session, store_current=True):
request.env = Storage() request.env = Storage()
# Enable standard conditional models (i.e., /*.py, /[controller]/*.py, and # Enable standard conditional models (i.e., /*.py, /[controller]/*.py, and
# /[controller]/[function]/*.py) # /[controller]/[function]/*.py)
response.models_to_run = [r'^\w+\.py$', r'^%s/\w+\.py$' % request.controller, response.models_to_run = [
r'^%s/%s/\w+\.py$' % (request.controller, request.function)] r'^\w+\.py$',
r'^%s/\w+\.py$' % request.controller,
r'^%s/%s/\w+\.py$' % (request.controller, request.function)
]
t = environment['T'] = translator(os.path.join(request.folder,'languages'), t = environment['T'] = translator(os.path.join(request.folder,'languages'),
request.env.http_accept_language) request.env.http_accept_language)
@@ -452,12 +454,12 @@ def compile_views(folder):
""" """
path = pjoin(folder, 'views') path = pjoin(folder, 'views')
for file in listdir(path, '^[\w/\-]+(\.\w+)*$'): for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
try: try:
data = parse_template(file, path) data = parse_template(fname, path)
except Exception, e: except Exception, e:
raise Exception("%s in %s" % (e, file)) raise Exception("%s in %s" % (e, fname))
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_') filename = 'views.%s.py' % fname.replace(os.path.sep, '.')
filename = pjoin(folder, 'compiled', filename) filename = pjoin(folder, 'compiled', filename)
write_file(filename, data) write_file(filename, data)
save_pyc(filename) save_pyc(filename)
@@ -470,9 +472,10 @@ def compile_models(folder):
""" """
path = pjoin(folder, 'models') path = pjoin(folder, 'models')
for file in listdir(path, '.+\.py$'): for fname in listdir(path, '.+\.py$'):
data = read_file(pjoin(path, file)) data = read_file(pjoin(path, fname))
filename = pjoin(folder, 'compiled', 'models', file) modelfile = 'models.'+fname.replace(os.path.sep,'.')
filename = pjoin(folder, 'compiled', modelfile)
mktree(filename) mktree(filename)
write_file(filename, data) write_file(filename, data)
save_pyc(filename) save_pyc(filename)
@@ -485,20 +488,21 @@ def compile_controllers(folder):
""" """
path = pjoin(folder, 'controllers') path = pjoin(folder, 'controllers')
for file in listdir(path, '.+\.py$'): for fname in listdir(path, '.+\.py$'):
### why is this here? save_pyc(pjoin(path, file)) ### why is this here? save_pyc(pjoin(path, file))
data = read_file(pjoin(path, file)) data = read_file(pjoin(path, fname))
exposed = regex_expose.findall(data) exposed = regex_expose.findall(data)
for function in exposed: for function in exposed:
command = data + "\nresponse._vars=response._caller(%s)\n" % \ command = data + "\nresponse._vars=response._caller(%s)\n" % \
function function
filename = pjoin(folder, 'compiled', ('controllers/' filename = pjoin(folder, 'compiled',
+ file[:-3]).replace('/', '_') 'controllers.%s.%s.py' % (fname[:-3],function))
+ '_' + function + '.py')
write_file(filename, command) write_file(filename, command)
save_pyc(filename) save_pyc(filename)
os.unlink(filename) os.unlink(filename)
def model_cmp(a,b):
return cmp(a.count('.'),b.count('.')) or cmp(a,b)
def run_models_in(environment): def run_models_in(environment):
""" """
@@ -509,33 +513,38 @@ def run_models_in(environment):
folder = environment['request'].folder folder = environment['request'].folder
c = environment['request'].controller c = environment['request'].controller
f = environment['request'].function f = environment['request'].function
response = environment['response']
path = pjoin(folder, 'models')
cpath = pjoin(folder, 'compiled') cpath = pjoin(folder, 'compiled')
if os.path.exists(cpath): compiled = os.path.exists(cpath)
for model in listdir(cpath, '^models_\w+\.pyc$', 0): if compiled:
restricted(read_pyc(model), environment, layer=model) models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0),model_cmp)
path = pjoin(cpath, 'models')
models = listdir(path, '^\w+\.pyc$', 0, sort=True)
compiled = True
else: else:
path = pjoin(folder, 'models') models = sorted(listdir(path, '^\w+\.py$', 0, sort=False),model_cmp)
models = listdir(path, '^\w+\.py$', 0, sort=True) n = len(path)+1
compiled = False
n = len(path) + 1 models_to_run = None
for model in models: for model in models:
regex = environment['response'].models_to_run if response.models_to_run != models_to_run:
if isinstance(regex, list): regex = models_to_run = response.models_to_run
regex = re_compile('|'.join(regex)) if isinstance(regex, list):
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py') regex = re_compile('|'.join(regex))
if not regex.search(file) and c != 'appadmin': if models_to_run:
continue if compiled:
elif compiled: fname = model[n:-4].replace('.','/')+'.py'
code = read_pyc(model) else:
elif is_gae: fname = model[n:].replace(os.path.sep,'/')
code = getcfs(model, model, if not regex.search(fname) and c != 'appadmin':
lambda: compile2(read_file(model), model)) continue
else: elif compiled:
code = getcfs(model, model, None) code = read_pyc(model)
restricted(code, environment, layer=model) elif is_gae:
code = getcfs(model, model,
lambda: compile2(read_file(model), model))
else:
code = getcfs(model, model, None)
restricted(code, environment, layer=model)
def run_controller_in(controller, function, environment): def run_controller_in(controller, function, environment):
@@ -551,12 +560,17 @@ def run_controller_in(controller, function, environment):
badc = 'invalid controller (%s/%s)' % (controller, function) badc = 'invalid controller (%s/%s)' % (controller, function)
badf = 'invalid function (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function)
if os.path.exists(path): if os.path.exists(path):
filename = pjoin(path, 'controllers_%s_%s.pyc' filename = pjoin(path, 'controllers.%s.%s.pyc'
% (controller, function)) % (controller, function))
if not os.path.exists(filename): if not os.path.exists(filename):
raise HTTP(404, ### for backward compatibility
rewrite.THREAD_LOCAL.routes.error_message % badf, filename = pjoin(path, 'controllers_%s_%s.pyc'
web2py_error=badf) % (controller, function))
### end for backward compatibility
if not os.path.exists(filename):
raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badf,
web2py_error=badf)
restricted(read_pyc(filename), environment, layer=filename) restricted(read_pyc(filename), environment, layer=filename)
elif function == '_TEST': elif function == '_TEST':
# TESTING: adjust the path to include site packages # TESTING: adjust the path to include site packages
@@ -631,11 +645,15 @@ def run_view_in(environment):
context=environment) context=environment)
restricted(ccode, environment, 'file stream') restricted(ccode, environment, 'file stream')
elif os.path.exists(path): elif os.path.exists(path):
x = view.replace('/', '.')
files = ['views.%s.pyc' % x]
if allow_generic:
files.append('views.generic.%s.pyc' % request.extension)
# for backward compatibility
x = view.replace('/', '_') x = view.replace('/', '_')
files = ['views_%s.pyc' % x] files.append('views_%s.pyc' % x)
if allow_generic: if allow_generic:
files.append('views_generic.%s.pyc' % request.extension) files.append('views_generic.%s.pyc' % request.extension)
# for backward compatibility
if request.extension == 'html': if request.extension == 'html':
files.append('views_%s.pyc' % x[:-5]) files.append('views_%s.pyc' % x[:-5])
if allow_generic: if allow_generic:
+1 -1
View File
@@ -37,7 +37,7 @@ class MemcacheClient(object):
self.client.delete(key) self.client.delete(key)
else: else:
value = f() value = f()
self.client.set(key, (time.time(), value)) self.client.set(key, (time.time(), value), time=time_expire)
return value return value
def increment(self, key, value=1): def increment(self, key, value=1):
+3 -3
View File
@@ -641,9 +641,9 @@ def ldap_auth(server='ldap', port=None,
# bind as anonymous # bind as anonymous
con.simple_bind_s('', '') con.simple_bind_s('', '')
# if username is None, return empty list # if username is None, return empty list
if username is None: if username is None:
return list() return list()
# search for groups where user is in # search for groups where user is in
filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars( filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars(
group_member_attrib group_member_attrib
+16 -8
View File
@@ -6124,7 +6124,7 @@ class IMAPAdapter(NoSQLAdapter):
else: else:
return (uid_list[0], uid_list[-1]) return (uid_list[0], uid_list[-1])
def convert_date(self, date, add=None): def convert_date(self, date, add=None, imf=False):
if add is None: if add is None:
add = datetime.timedelta() add = datetime.timedelta()
""" Convert a date object to a string """ Convert a date object to a string
@@ -6138,7 +6138,10 @@ class IMAPAdapter(NoSQLAdapter):
if isinstance(date, basestring): if isinstance(date, basestring):
# Prevent unexpected date response format # Prevent unexpected date response format
try: try:
dayname, datestring = date.split(",") if "," in date:
dayname, datestring = date.split(",")
else:
dayname, datestring = None, date
date_list = datestring.strip().split() date_list = datestring.strip().split()
year = int(date_list[2]) year = int(date_list[2])
month = months.index(date_list[1].upper()) month = months.index(date_list[1].upper())
@@ -6150,8 +6153,10 @@ class IMAPAdapter(NoSQLAdapter):
LOGGER.error("Could not parse date text: %s. %s" % LOGGER.error("Could not parse date text: %s. %s" %
(date, e)) (date, e))
return None return None
elif isinstance(date, (datetime.datetime, datetime.date)): elif isinstance(date, (datetime.date, datetime.datetime)):
return (date + add).strftime("%d-%b-%Y") if imf: date_format = "%a, %d %b %Y %H:%M:%S %z"
else: date_format = "%d-%b-%Y"
return (date + add).strftime(date_format)
else: else:
return None return None
@@ -6532,7 +6537,8 @@ class IMAPAdapter(NoSQLAdapter):
mailbox = table.mailbox mailbox = table.mailbox
d = dict(((k.name, v) for k, v in fields)) d = dict(((k.name, v) for k, v in fields))
date_time = (d.get("created", datetime.datetime.now())).timetuple() date_time = d.get("created", datetime.datetime.now())
struct_time = date_time.timetuple()
if len(d) > 0: if len(d) > 0:
message = d.get("email", None) message = d.get("email", None)
attachments = d.get("attachments", []) attachments = d.get("attachments", [])
@@ -6547,6 +6553,8 @@ class IMAPAdapter(NoSQLAdapter):
message = Message() message = Message()
message["from"] = d.get("sender", "") message["from"] = d.get("sender", "")
message["subject"] = d.get("subject", "") message["subject"] = d.get("subject", "")
message["date"] = self.convert_date(date_time, imf=True)
if mime: if mime:
message.set_type(mime) message.set_type(mime)
if charset: if charset:
@@ -6569,7 +6577,7 @@ class IMAPAdapter(NoSQLAdapter):
[add_payload(message, c) for c in content] [add_payload(message, c) for c in content]
[add_payload(message, a) for a in attachments] [add_payload(message, a) for a in attachments]
message = message.as_string() message = message.as_string()
return (mailbox, flags, date_time, message) return (mailbox, flags, struct_time, message)
else: else:
raise NotImplementedError("IMAP empty insert is not implemented") raise NotImplementedError("IMAP empty insert is not implemented")
@@ -6918,7 +6926,7 @@ def sqlhtml_validators(field):
elif field_type == 'double' or field_type == 'float': elif field_type == 'double' or field_type == 'float':
requires.append(validators.IS_FLOAT_IN_RANGE(-1e100, 1e100)) requires.append(validators.IS_FLOAT_IN_RANGE(-1e100, 1e100))
elif field_type in ('integer','bigint'): elif field_type in ('integer','bigint'):
requires.append(validators.IS_INT_IN_RANGE(-1e100, 1e100)) requires.append(validators.IS_INT_IN_RANGE(-2**31, 2**31-1))
elif field_type.startswith('decimal'): elif field_type.startswith('decimal'):
requires.append(validators.IS_DECIMAL_IN_RANGE(-10**10, 10**10)) requires.append(validators.IS_DECIMAL_IN_RANGE(-10**10, 10**10))
elif field_type == 'date': elif field_type == 'date':
@@ -10501,7 +10509,7 @@ class Rows(object):
if i is None: if i is None:
return (self.repr(i, fields=fields) for i in range(len(self))) return (self.render(i, fields=fields) for i in range(len(self)))
import sqlhtml import sqlhtml
row = copy.deepcopy(self.records[i]) row = copy.deepcopy(self.records[i])
keys = row.keys() keys = row.keys()
+2 -2
View File
@@ -44,6 +44,7 @@ defined_status = {
416: 'REQUESTED RANGE NOT SATISFIABLE', 416: 'REQUESTED RANGE NOT SATISFIABLE',
417: 'EXPECTATION FAILED', 417: 'EXPECTATION FAILED',
422: 'UNPROCESSABLE ENTITY', 422: 'UNPROCESSABLE ENTITY',
429: 'TOO MANY REQUESTS',
451: 'UNAVAILABLE FOR LEGAL REASONS', # http://www.451unavailable.org/ 451: 'UNAVAILABLE FOR LEGAL REASONS', # http://www.451unavailable.org/
500: 'INTERNAL SERVER ERROR', 500: 'INTERNAL SERVER ERROR',
501: 'NOT IMPLEMENTED', 501: 'NOT IMPLEMENTED',
@@ -53,8 +54,7 @@ defined_status = {
505: 'HTTP VERSION NOT SUPPORTED', 505: 'HTTP VERSION NOT SUPPORTED',
} }
regex_status = re.compile('^\d{3} \w+$') regex_status = re.compile('^\d{3} [0-9A-Z ]+$')
class HTTP(Exception): class HTTP(Exception):
+4 -1
View File
@@ -288,7 +288,10 @@ def run(
else: else:
try: try:
import IPython import IPython
if IPython.__version__ >= '0.11': if IPython.__version__ >= '1.0':
IPython.start_ipython(user_ns=_env)
return
elif IPython.__version__ >= '0.11':
from IPython.frontend.terminal.embed import InteractiveShellEmbed from IPython.frontend.terminal.embed import InteractiveShellEmbed
shell = InteractiveShellEmbed(user_ns=_env) shell = InteractiveShellEmbed(user_ns=_env)
shell() shell()
+39 -25
View File
@@ -45,11 +45,6 @@ except ImportError:
table_field = re.compile('[\w_]+\.[\w_]+') table_field = re.compile('[\w_]+\.[\w_]+')
widget_class = re.compile('^\w*') widget_class = re.compile('^\w*')
def trap_class(_class=None, trap=True):
return (trap and 'w2p_trap' or '') + (_class and ' ' + _class or '')
def represent(field, value, record): def represent(field, value, record):
f = field.represent f = field.represent
if not callable(f): if not callable(f):
@@ -1897,7 +1892,8 @@ class SQLFORM(FORM):
callback=callback, callback=callback,
delete=delete, delete=delete,
noconfirm=noconfirm, noconfirm=noconfirm,
_class=trap_class(ui.get('button'), trap)) _class=ui.get('button'),
cid=request.cid)
else: else:
return A(SPAN(_class=ui.get(buttonclass)), return A(SPAN(_class=ui.get(buttonclass)),
_href=buttonurl, _href=buttonurl,
@@ -1905,7 +1901,8 @@ class SQLFORM(FORM):
delete=delete, delete=delete,
noconfirm=noconfirm, noconfirm=noconfirm,
_title=T(buttontext), _title=T(buttontext),
_class=trap_class(ui.get('buttontext'), trap)) _class=ui.get('buttontext'),
cid=request.cid)
dbset = db(query,ignore_common_filters=ignore_common_filters) dbset = db(query,ignore_common_filters=ignore_common_filters)
tablenames = db._adapter.tables(dbset.query) tablenames = db._adapter.tables(dbset.query)
@@ -1920,14 +1917,14 @@ class SQLFORM(FORM):
else: else:
fields = [] fields = []
columns = [] columns = []
filter1 = lambda f:isinstance(f,Field)
filter2 = lambda f:isinstance(f,Field) and f.readable
for table in tables: for table in tables:
fields += filter(filter1, table)
columns += filter(filter2, table)
for k,f in table.iteritems(): for k,f in table.iteritems():
if not k.startswith('_'): if not k.startswith('_'):
if isinstance(f,Field): if isinstance(f,Field.Virtual) and f.readable:
fields.append(f) # these are selected
if f.readable:
columns.append(f) # these are displayed
elif isinstance(f,Field.Virtual) and f.readable:
f.tablename = table._tablename f.tablename = table._tablename
columns.append(f) columns.append(f)
fields.append(f) fields.append(f)
@@ -2057,7 +2054,22 @@ class SQLFORM(FORM):
if ondelete: if ondelete:
ondelete(table, request.args[-1]) ondelete(table, request.args[-1])
record.delete_record() record.delete_record()
redirect(referrer, client_side=client_side_delete) if request.ajax:
#this means javascript is enabled, so we don't need to do
#a redirect
if not client_side_delete:
#if it's an ajax request and we don't need to reload the
#entire page, let's just inform that there have been no
#exceptions and don't regenerate the grid
raise HTTP(200)
else:
#if it's requested that the grid gets reloaded on delete
#on ajax, the redirect should be on the original location
newloc = request.env.http_web2py_component_location
redirect(newloc, client_side=client_side_delete)
else:
#we need to do a redirect because javascript is not enabled
redirect(referrer, client_side=client_side_delete)
exportManager = dict( exportManager = dict(
csv_with_hidden_cols=(ExporterCSV, 'CSV (hidden cols)'), csv_with_hidden_cols=(ExporterCSV, 'CSV (hidden cols)'),
@@ -2221,7 +2233,7 @@ class SQLFORM(FORM):
marker = sorter_icons[1] marker = sorter_icons[1]
header = A(header, marker, _href=url(vars=dict( header = A(header, marker, _href=url(vars=dict(
keywords=request.vars.keywords or '', keywords=request.vars.keywords or '',
order=key)), _class=trap_class()) order=key)), cid=request.cid)
headcols.append(TH(header, _class=ui.get('default'))) headcols.append(TH(header, _class=ui.get('default')))
toadd = [] toadd = []
@@ -2261,7 +2273,9 @@ class SQLFORM(FORM):
limitby = None limitby = None
try: try:
table_fields = filter(lambda f: f.tablename in tablenames, fields) table_fields = filter(
lambda f: (f.tablename in tablenames) and \
(not(isinstance(f,Field.Virtual))),fields)
if dbset._db._adapter.dbengine=='google:datastore': if dbset._db._adapter.dbengine=='google:datastore':
rows = dbset.select(left=left,orderby=orderby, rows = dbset.select(left=left,orderby=orderby,
groupby=groupby,limitby=limitby, groupby=groupby,limitby=limitby,
@@ -2269,7 +2283,6 @@ class SQLFORM(FORM):
cacheable=True,*table_fields) cacheable=True,*table_fields)
next_cursor = dbset._db.get('_lastcursor', None) next_cursor = dbset._db.get('_lastcursor', None)
else: else:
# print('table_fields: %s' %([f_.name for f_ in table_fields],))
rows = dbset.select(left=left,orderby=orderby, rows = dbset.select(left=left,orderby=orderby,
groupby=groupby,limitby=limitby, groupby=groupby,limitby=limitby,
cacheable=True,*table_fields) cacheable=True,*table_fields)
@@ -2303,7 +2316,7 @@ class SQLFORM(FORM):
if order: d['order']=order if order: d['order']=order
if request.vars.keywords: d['keywords']=request.vars.keywords if request.vars.keywords: d['keywords']=request.vars.keywords
paginator.append(LI( paginator.append(LI(
A('next',_href=url(vars=d),_class=trap_class()))) A('next',_href=url(vars=d),cid=request.cid)))
elif paginate and paginate<nrows: elif paginate and paginate<nrows:
npages, reminder = divmod(nrows, paginate) npages, reminder = divmod(nrows, paginate)
if reminder: if reminder:
@@ -2319,7 +2332,7 @@ class SQLFORM(FORM):
d['order'] = order d['order'] = order
if request.vars.keywords: if request.vars.keywords:
d['keywords'] = request.vars.keywords d['keywords'] = request.vars.keywords
return A(name, _href=url(vars=d), _class=trap_class()) return A(name, _href=url(vars=d), cid=request.cid)
NPAGES = 5 # window is 2*NPAGES NPAGES = 5 # window is 2*NPAGES
if page > NPAGES + 1: if page > NPAGES + 1:
paginator.append(LI(self_link('<<', 0))) paginator.append(LI(self_link('<<', 0)))
@@ -2329,7 +2342,7 @@ class SQLFORM(FORM):
for p in pages: for p in pages:
if p == page: if p == page:
paginator.append(LI(A(p + 1, _onclick='return false'), paginator.append(LI(A(p + 1, _onclick='return false'),
_class=trap_class('current'))) _class='current'))
else: else:
paginator.append(LI(self_link(p + 1, p))) paginator.append(LI(self_link(p + 1, p)))
if page < npages - NPAGES: if page < npages - NPAGES:
@@ -2355,6 +2368,7 @@ class SQLFORM(FORM):
continue continue
if field.type == 'blob': if field.type == 'blob':
continue continue
print row
value = row[str(field)] value = row[str(field)]
maxlength = maxtextlengths.get(str(field), maxtextlength) maxlength = maxtextlengths.get(str(field), maxtextlength)
if field.represent: if field.represent:
@@ -2598,13 +2612,13 @@ class SQLFORM(FORM):
name = format(db[referee],record) name = format(db[referee],record)
breadcrumbs.append( breadcrumbs.append(
LI(A(T(db[referee]._plural), LI(A(T(db[referee]._plural),
_class=trap_class(), cid=request.cid,
_href=url()), _href=url()),
SPAN(divider, _class='divider'), SPAN(divider, _class='divider'),
_class='w2p_grid_breadcrumb_elem')) _class='w2p_grid_breadcrumb_elem'))
if kwargs.get('details', True): if kwargs.get('details', True):
breadcrumbs.append( breadcrumbs.append(
LI(A(name, _class=trap_class(), LI(A(name, cid=request.cid,
_href=url(args=['view', referee, id])), _href=url(args=['view', referee, id])),
SPAN(divider, _class='divider'), SPAN(divider, _class='divider'),
_class='w2p_grid_breadcrumb_elem')) _class='w2p_grid_breadcrumb_elem'))
@@ -2617,7 +2631,7 @@ class SQLFORM(FORM):
# if isinstance(linked_tables, dict): # if isinstance(linked_tables, dict):
# linked_tables = linked_tables.get(table._tablename, []) # linked_tables = linked_tables.get(table._tablename, [])
if linked_tables is None or referee in linked_tables: if linked_tables is None or referee in linked_tables:
field.represent = lambda id, r=None, referee=referee, rep=field.represent: A(callable(rep) and rep(id) or id, _class=trap_class(), _href=url(args=['view', referee, id])) field.represent = lambda id, r=None, referee=referee, rep=field.represent: A(callable(rep) and rep(id) or id, cid=request.cid, _href=url(args=['view', referee, id]))
except (KeyError, ValueError, TypeError): except (KeyError, ValueError, TypeError):
redirect(URL(args=table._tablename)) redirect(URL(args=table._tablename))
if nargs == len(args) + 1: if nargs == len(args) + 1:
@@ -2668,7 +2682,7 @@ class SQLFORM(FORM):
args0 = tablename + '.' + fieldname args0 = tablename + '.' + fieldname
links.append( links.append(
lambda row, t=t, nargs=nargs, args0=args0: lambda row, t=t, nargs=nargs, args0=args0:
A(SPAN(t), _class=trap_class(), _href=url( A(SPAN(t), cid=request.cid, _href=url(
args=[args0, row[id_field_name]]))) args=[args0, row[id_field_name]])))
grid = SQLFORM.grid(query, args=request.args[:nargs], links=links, grid = SQLFORM.grid(query, args=request.args[:nargs], links=links,
@@ -2679,7 +2693,7 @@ class SQLFORM(FORM):
header = table._plural header = table._plural
next = grid.create_form or grid.update_form or grid.view_form next = grid.create_form or grid.update_form or grid.view_form
breadcrumbs.append(LI( breadcrumbs.append(LI(
A(T(header), _class=trap_class(),_href=url()), A(T(header), cid=request.cid,_href=url()),
SPAN(divider, _class='divider') if next else '', SPAN(divider, _class='divider') if next else '',
_class='active w2p_grid_breadcrumb_elem')) _class='active w2p_grid_breadcrumb_elem'))
if grid.create_form: if grid.create_form:
@@ -2694,7 +2708,7 @@ class SQLFORM(FORM):
grid.view_form.record)) grid.view_form.record))
if next: if next:
breadcrumbs.append(LI( breadcrumbs.append(LI(
A(T(header), _class=trap_class(),_href=url()), A(T(header), cid=request.cid,_href=url()),
_class='active w2p_grid_breadcrumb_elem')) _class='active w2p_grid_breadcrumb_elem'))
grid.insert( grid.insert(
0, DIV(UL(*breadcrumbs, **{'_class': breadcrumbs_class}), 0, DIV(UL(*breadcrumbs, **{'_class': breadcrumbs_class}),
+18 -37
View File
@@ -22,6 +22,8 @@ from cStringIO import StringIO
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
from gluon.dal import FieldVirtual, FieldMethod from gluon.dal import FieldVirtual, FieldMethod
regex_isint = re.compile('^\-?\d+$')
JSONErrors = (NameError, TypeError, ValueError, AttributeError, JSONErrors = (NameError, TypeError, ValueError, AttributeError,
KeyError) KeyError)
try: try:
@@ -692,15 +694,15 @@ class IS_INT_IN_RANGE(Validator):
>>> IS_INT_IN_RANGE(1,5)(5) >>> IS_INT_IN_RANGE(1,5)(5)
(5, 'enter an integer between 1 and 4') (5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(1,5)(3.5) >>> IS_INT_IN_RANGE(1,5)(3.5)
(3, 'enter an integer between 1 and 4') (3.5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(None,5)('4') >>> IS_INT_IN_RANGE(None,5)('4')
(4, None) (4, None)
>>> IS_INT_IN_RANGE(None,5)('6') >>> IS_INT_IN_RANGE(None,5)('6')
(6, 'enter an integer less than or equal to 4') ('6', 'enter an integer less than or equal to 4')
>>> IS_INT_IN_RANGE(1,None)('4') >>> IS_INT_IN_RANGE(1,None)('4')
(4, None) (4, None)
>>> IS_INT_IN_RANGE(1,None)('0') >>> IS_INT_IN_RANGE(1,None)('0')
(0, 'enter an integer greater than or equal to 1') ('0', 'enter an integer greater than or equal to 1')
>>> IS_INT_IN_RANGE()(6) >>> IS_INT_IN_RANGE()(6)
(6, None) (6, None)
>>> IS_INT_IN_RANGE()('abc') >>> IS_INT_IN_RANGE()('abc')
@@ -741,24 +743,13 @@ class IS_INT_IN_RANGE(Validator):
% dict(min=self.minimum, max=self.maximum - 1) % dict(min=self.minimum, max=self.maximum - 1)
def __call__(self, value): def __call__(self, value):
try: if value and regex_isint.match(str(value)):
fvalue = float(value) v = int(value)
value = int(value) if ((self.minimum is None or v >= self.minimum) and
if value != fvalue: (self.maximum is None or v < self.maximum)):
return (value, self.error_message) return (v, None)
if self.minimum is None:
if self.maximum is None or value < self.maximum:
return (value, None)
elif self.maximum is None:
if value >= self.minimum:
return (value, None)
elif self.minimum <= value < self.maximum:
return (value, None)
except ValueError:
pass
return (value, self.error_message) return (value, self.error_message)
def str2dec(number): def str2dec(number):
s = str(number) s = str(number)
if not '.' in s: if not '.' in s:
@@ -839,17 +830,12 @@ class IS_FLOAT_IN_RANGE(Validator):
def __call__(self, value): def __call__(self, value):
try: try:
if self.dot == '.': if self.dot == '.':
fvalue = float(value) v = float(value)
else: else:
fvalue = float(str(value).replace(self.dot, '.')) v = float(str(value).replace(self.dot, '.'))
if self.minimum is None: if ((self.minimum is None or v >= self.minimum) and
if self.maximum is None or fvalue <= self.maximum: (self.maximum is None or v <= self.maximum)):
return (fvalue, None) return (v, None)
elif self.maximum is None:
if fvalue >= self.minimum:
return (fvalue, None)
elif self.minimum <= fvalue <= self.maximum:
return (fvalue, None)
except (ValueError, TypeError): except (ValueError, TypeError):
pass pass
return (value, self.error_message) return (value, self.error_message)
@@ -948,14 +934,9 @@ class IS_DECIMAL_IN_RANGE(Validator):
v = value v = value
else: else:
v = decimal.Decimal(str(value).replace(self.dot, '.')) v = decimal.Decimal(str(value).replace(self.dot, '.'))
if self.minimum is None: if ((self.minimum is None or v >= self.minimum) and
if self.maximum is None or v <= self.maximum: (self.maximum is None or v <= self.maximum)):
return (v, None) return (v, None)
elif self.maximum is None:
if v >= self.minimum:
return (v, None)
elif self.minimum <= v <= self.maximum:
return (v, None)
except (ValueError, TypeError, decimal.InvalidOperation): except (ValueError, TypeError, decimal.InvalidOperation):
pass pass
return (value, self.error_message) return (value, self.error_message)
+2 -2
View File
@@ -1005,7 +1005,7 @@ def console():
if not os.path.exists('applications/__init__.py'): if not os.path.exists('applications/__init__.py'):
write_file('applications/__init__.py', '') write_file('applications/__init__.py', '')
return (options, args) return options, args
def check_existent_app(options, appname): def check_existent_app(options, appname):
@@ -1022,7 +1022,7 @@ def get_code_for_scheduler(app, options):
code = code % ("','".join(app[1:])) code = code % ("','".join(app[1:]))
app_ = app[0] app_ = app[0]
if not check_existent_app(options, app_): if not check_existent_app(options, app_):
print "Application '%s' doesn't exist, skipping" % (app_) print "Application '%s' doesn't exist, skipping" % app_
return None, None return None, None
return app_, code return app_, code
+1 -1
View File
@@ -299,7 +299,7 @@ NameVirtualHost *:80
NameVirtualHost *:443 NameVirtualHost *:443
<VirtualHost *:80> <VirtualHost *:80>
WSGIDaemonProcess web2py user=apache group=apache WSGIDaemonProcess web2py user=apache group=apache processes=1 threads=1
WSGIProcessGroup web2py WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
+1 -1
View File
@@ -301,7 +301,7 @@ NameVirtualHost *:80
NameVirtualHost *:443 NameVirtualHost *:443
<VirtualHost *:80> <VirtualHost *:80>
WSGIDaemonProcess web2py user=apache group=apache WSGIDaemonProcess web2py user=apache group=apache processes=1 threads=1
WSGIProcessGroup web2py WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
WSGIPassAuthorization On WSGIPassAuthorization On
+1 -1
View File
@@ -91,7 +91,7 @@ NameVirtualHost *:443
# within a virtual host container, only WSGI applications associated with # within a virtual host container, only WSGI applications associated with
# virtual hosts with the same server name as that virtual host can be # virtual hosts with the same server name as that virtual host can be
# delegated to that set of daemon processes. # delegated to that set of daemon processes.
WSGIDaemonProcess web2py user=www-data group=www-data WSGIDaemonProcess web2py user=www-data group=www-data processes=1 threads=1
<VirtualHost *:80> <VirtualHost *:80>
WSGIProcessGroup web2py WSGIProcessGroup web2py