Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37bc09169f | ||
|
|
1cc2decfdd | ||
|
|
e9eb1689e2 | ||
|
|
0f446833c0 | ||
|
|
cb9c2a8ef9 | ||
|
|
b37ed1c1e0 | ||
|
|
b484955005 | ||
|
|
654626d519 | ||
|
|
ca0313c514 | ||
|
|
fb357eb241 | ||
|
|
1a83487221 | ||
|
|
6cda7a29fc | ||
|
|
17f495e9c5 | ||
|
|
dd32a90844 | ||
|
|
4b2ba185ae | ||
|
|
b716df1a05 | ||
|
|
d552eb2eeb | ||
|
|
de2337dfe3 | ||
|
|
e707cfc67c | ||
|
|
c3c5df6394 | ||
|
|
72739ebb97 | ||
|
|
39c94b8dcf | ||
|
|
5af380223a | ||
|
|
1ea379180a | ||
|
|
ca3d050a0b | ||
|
|
161b2271b3 | ||
|
|
013c94cdf6 | ||
|
|
addbb78151 | ||
|
|
f6789eaf39 | ||
|
|
c13b4f18f7 | ||
|
|
67840e9481 | ||
|
|
41c40974a3 | ||
|
|
9a6ce11f09 | ||
|
|
d404e40508 | ||
|
|
b6a496aae5 | ||
|
|
ecaed07a3d | ||
|
|
30ec8e645b | ||
|
|
3a1ba53a4b | ||
|
|
ab95dfa7cd | ||
|
|
6b9ebb6dc5 | ||
|
|
e2e843d2ed | ||
|
|
d5381d7b36 | ||
|
|
f7c0f0341b | ||
|
|
9f7fd68728 |
@@ -1,3 +1,13 @@
|
|||||||
|
## 2.2.1
|
||||||
|
|
||||||
|
- session.connect(cookie_key='secret', compression_level=9) stores sessions in cookies
|
||||||
|
- T.is_writable = False prevents T from dynamically updating langauge files
|
||||||
|
- all code is more PEP8 compliant
|
||||||
|
- better custom_importer behaviour (now works per app, is smalled and faster)
|
||||||
|
- fixed some bugs
|
||||||
|
- upgraded feedparser.py and rss2.py
|
||||||
|
- codemirror has autoresize
|
||||||
|
|
||||||
## 2.1.0
|
## 2.1.0
|
||||||
|
|
||||||
- overall faster web2py
|
- overall faster web2py
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ update:
|
|||||||
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
|
||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
echo 'Version 2.1.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
echo 'Version 2.2.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
@@ -130,5 +130,5 @@ pip:
|
|||||||
# after upload clean Web2py sources with rm -R ./dist
|
# after upload clean Web2py sources with rm -R ./dist
|
||||||
# http://guide.python-distribute.org/creation.html
|
# http://guide.python-distribute.org/creation.html
|
||||||
python setup.py sdist
|
python setup.py sdist
|
||||||
python setup.py register
|
sudo python setup.py register
|
||||||
python setup.py sdist upload
|
sudo python setup.py sdist upload
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.1.1 (2012-10-15 06:40:52) stable
|
Version 2.2.1 (2012-10-21 10:54:10) stable
|
||||||
|
|||||||
-10
@@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+72
-53
@@ -9,47 +9,54 @@ License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
|||||||
This file is based, although a rewrite, on MIT-licensed code from the Bottle web framework.
|
This file is based, although a rewrite, on MIT-licensed code from the Bottle web framework.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, sys, optparse, urllib
|
import os
|
||||||
|
import sys
|
||||||
|
import optparse
|
||||||
|
import urllib
|
||||||
|
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
os.chdir(path)
|
os.chdir(path)
|
||||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||||
import gluon.main
|
import gluon.main
|
||||||
from gluon.fileutils import read_file, write_file
|
from gluon.fileutils import read_file, write_file
|
||||||
|
|
||||||
|
|
||||||
class Servers:
|
class Servers:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cgi(app, address=None, **options):
|
def cgi(app, address=None, **options):
|
||||||
from wsgiref.handlers import CGIHandler
|
from wsgiref.handlers import CGIHandler
|
||||||
CGIHandler().run(app) # Just ignore host and port here
|
CGIHandler().run(app) # Just ignore host and port here
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def flup(app,address, **options):
|
def flup(app, address, **options):
|
||||||
import flup.server.fcgi
|
import flup.server.fcgi
|
||||||
flup.server.fcgi.WSGIServer(app, bindAddress=address).run()
|
flup.server.fcgi.WSGIServer(app, bindAddress=address).run()
|
||||||
|
|
||||||
@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
|
||||||
|
|
||||||
class QuietHandler(WSGIRequestHandler):
|
class QuietHandler(WSGIRequestHandler):
|
||||||
def log_request(*args, **kw): pass
|
def log_request(*args, **kw):
|
||||||
|
pass
|
||||||
options['handler_class'] = QuietHandler
|
options['handler_class'] = QuietHandler
|
||||||
srv = make_server(address[0],address[1],app,**options)
|
srv = make_server(address[0], address[1], app, **options)
|
||||||
srv.serve_forever()
|
srv.serve_forever()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cherrypy(app,address, **options):
|
def cherrypy(app, address, **options):
|
||||||
from cherrypy import wsgiserver
|
from cherrypy import wsgiserver
|
||||||
server = wsgiserver.CherryPyWSGIServer(address, app)
|
server = wsgiserver.CherryPyWSGIServer(address, app)
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def rocket(app,address, **options):
|
def rocket(app, address, **options):
|
||||||
from gluon.rocket import CherryPyWSGIServer
|
from gluon.rocket import CherryPyWSGIServer
|
||||||
server = CherryPyWSGIServer(address, app)
|
server = CherryPyWSGIServer(address, app)
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def rocket_with_repoze_profiler(app,address, **options):
|
def rocket_with_repoze_profiler(app, address, **options):
|
||||||
from gluon.rocket import CherryPyWSGIServer
|
from gluon.rocket import CherryPyWSGIServer
|
||||||
from repoze.profile.profiler import AccumulatingProfileMiddleware
|
from repoze.profile.profiler import AccumulatingProfileMiddleware
|
||||||
from gluon.settings import global_settings
|
from gluon.settings import global_settings
|
||||||
@@ -59,44 +66,46 @@ class Servers:
|
|||||||
log_filename='wsgi.prof',
|
log_filename='wsgi.prof',
|
||||||
discard_first_request=True,
|
discard_first_request=True,
|
||||||
flush_at_shutdown=True,
|
flush_at_shutdown=True,
|
||||||
path = '/__profile__'
|
path='/__profile__'
|
||||||
)
|
)
|
||||||
server = CherryPyWSGIServer(address, wrapped)
|
server = CherryPyWSGIServer(address, wrapped)
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def paste(app,address,**options):
|
def paste(app, address, **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)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fapws(app,address, **options):
|
def fapws(app, address, **options):
|
||||||
import fapws._evwsgi as evwsgi
|
import fapws._evwsgi as evwsgi
|
||||||
from fapws import base
|
from fapws import base
|
||||||
evwsgi.start(address[0],str(address[1]))
|
evwsgi.start(address[0], str(address[1]))
|
||||||
evwsgi.set_base_module(base)
|
evwsgi.set_base_module(base)
|
||||||
|
|
||||||
def app(environ, start_response):
|
def app(environ, start_response):
|
||||||
environ['wsgi.multiprocess'] = False
|
environ['wsgi.multiprocess'] = False
|
||||||
return app(environ, start_response)
|
return app(environ, start_response)
|
||||||
evwsgi.wsgi_cb(('',app))
|
evwsgi.wsgi_cb(('', app))
|
||||||
evwsgi.run()
|
evwsgi.run()
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def gevent(app,address, **options):
|
def gevent(app, address, **options):
|
||||||
from gevent import monkey; monkey.patch_all()
|
from gevent import monkey
|
||||||
|
monkey.patch_all()
|
||||||
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(int(options.workers)) or 'default').serve_forever()
|
pywsgi.WSGIServer(address, app, spawn='workers' in options and Pool(
|
||||||
|
int(options.workers)) or 'default').serve_forever()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def bjoern(app,address, **options):
|
def bjoern(app, address, **options):
|
||||||
import bjoern
|
import bjoern
|
||||||
bjoern.run(app, *address)
|
bjoern.run(app, *address)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tornado(app,address, **options):
|
def tornado(app, address, **options):
|
||||||
import tornado.wsgi
|
import tornado.wsgi
|
||||||
import tornado.httpserver
|
import tornado.httpserver
|
||||||
import tornado.ioloop
|
import tornado.ioloop
|
||||||
@@ -106,7 +115,7 @@ class Servers:
|
|||||||
tornado.ioloop.IOLoop.instance().start()
|
tornado.ioloop.IOLoop.instance().start()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def twisted(app,address, **options):
|
def twisted(app, address, **options):
|
||||||
from twisted.web import server, wsgi
|
from twisted.web import server, wsgi
|
||||||
from twisted.python.threadpool import ThreadPool
|
from twisted.python.threadpool import ThreadPool
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
@@ -118,42 +127,44 @@ class Servers:
|
|||||||
reactor.run()
|
reactor.run()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def diesel(app,address, **options):
|
def diesel(app, address, **options):
|
||||||
from diesel.protocols.wsgi import WSGIApplication
|
from diesel.protocols.wsgi import WSGIApplication
|
||||||
app = WSGIApplication(app, port=address[1])
|
app = WSGIApplication(app, port=address[1])
|
||||||
app.run()
|
app.run()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def gunicorn(app,address, **options):
|
def gunicorn(app, address, **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)
|
||||||
sys.argv = ['anyserver.py']
|
sys.argv = ['anyserver.py']
|
||||||
|
|
||||||
class GunicornApplication(Application):
|
class GunicornApplication(Application):
|
||||||
def init(self, parser, opts, args):
|
def init(self, parser, opts, args):
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
return app
|
return app
|
||||||
g = GunicornApplication()
|
g = GunicornApplication()
|
||||||
g.run()
|
g.run()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def eventlet(app,address, **options):
|
def eventlet(app, address, **options):
|
||||||
from eventlet import wsgi, listen
|
from eventlet import wsgi, listen
|
||||||
wsgi.server(listen(address), app)
|
wsgi.server(listen(address), app)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mongrel2(app,address,**options):
|
def mongrel2(app, address, **options):
|
||||||
import uuid
|
import uuid
|
||||||
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
|
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
|
||||||
from mongrel2 import handler
|
from mongrel2 import handler
|
||||||
conn = handler.Connection(str(uuid.uuid4()),
|
conn = handler.Connection(str(uuid.uuid4()),
|
||||||
"tcp://127.0.0.1:9997",
|
"tcp://127.0.0.1:9997",
|
||||||
"tcp://127.0.0.1:9996")
|
"tcp://127.0.0.1:9996")
|
||||||
mongrel2_handler(app,conn,debug=False)
|
mongrel2_handler(app, conn, debug=False)
|
||||||
|
|
||||||
|
|
||||||
def run(servername,ip,port,softcron=True,logging=False,profiler=None):
|
def run(servername, ip, port, softcron=True, logging=False, profiler=None):
|
||||||
if logging:
|
if logging:
|
||||||
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
|
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
|
||||||
logfilename='httpserver.log',
|
logfilename='httpserver.log',
|
||||||
@@ -163,9 +174,10 @@ def run(servername,ip,port,softcron=True,logging=False,profiler=None):
|
|||||||
if softcron:
|
if softcron:
|
||||||
from gluon.settings import global_settings
|
from gluon.settings import global_settings
|
||||||
global_settings.web2py_crontype = 'soft'
|
global_settings.web2py_crontype = 'soft'
|
||||||
getattr(Servers,servername)(application,(ip,int(port)))
|
getattr(Servers, servername)(application, (ip, int(port)))
|
||||||
|
|
||||||
def mongrel2_handler(application,conn,debug=False):
|
|
||||||
|
def mongrel2_handler(application, conn, debug=False):
|
||||||
"""
|
"""
|
||||||
Based on :
|
Based on :
|
||||||
https://github.com/berry/Mongrel2-WSGI-Handler/blob/master/wsgi-handler.py
|
https://github.com/berry/Mongrel2-WSGI-Handler/blob/master/wsgi-handler.py
|
||||||
@@ -190,20 +202,23 @@ def mongrel2_handler(application,conn,debug=False):
|
|||||||
# and responses. Unless I have missed something.
|
# and responses. Unless I have missed something.
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if debug: print "WAITING FOR REQUEST"
|
if debug:
|
||||||
|
print "WAITING FOR REQUEST"
|
||||||
|
|
||||||
# receive a request
|
# receive a request
|
||||||
req = conn.recv()
|
req = conn.recv()
|
||||||
if debug: print "REQUEST BODY: %r\n" % req.body
|
if debug:
|
||||||
|
print "REQUEST BODY: %r\n" % req.body
|
||||||
|
|
||||||
if req.is_disconnect():
|
if req.is_disconnect():
|
||||||
if debug: print "DISCONNECT"
|
if debug:
|
||||||
continue #effectively ignore the disconnect from the client
|
print "DISCONNECT"
|
||||||
|
continue # effectively ignore the disconnect from the client
|
||||||
|
|
||||||
# Set a couple of environment attributes a.k.a. header attributes
|
# Set a couple of environment attributes a.k.a. header attributes
|
||||||
# that are a must according to PEP 333
|
# that are a must according to PEP 333
|
||||||
environ = req.headers
|
environ = req.headers
|
||||||
environ['SERVER_PROTOCOL'] = 'HTTP/1.1' # SimpleHandler expects a server_protocol, lets assume it is HTTP 1.1
|
environ['SERVER_PROTOCOL'] = 'HTTP/1.1' # SimpleHandler expects a server_protocol, lets assume it is HTTP 1.1
|
||||||
environ['REQUEST_METHOD'] = environ['METHOD']
|
environ['REQUEST_METHOD'] = environ['METHOD']
|
||||||
if ':' in environ['Host']:
|
if ':' in environ['Host']:
|
||||||
environ['SERVER_NAME'] = environ['Host'].split(':')[0]
|
environ['SERVER_NAME'] = environ['Host'].split(':')[0]
|
||||||
@@ -211,17 +226,19 @@ def mongrel2_handler(application,conn,debug=False):
|
|||||||
else:
|
else:
|
||||||
environ['SERVER_NAME'] = environ['Host']
|
environ['SERVER_NAME'] = environ['Host']
|
||||||
environ['SERVER_PORT'] = ''
|
environ['SERVER_PORT'] = ''
|
||||||
environ['SCRIPT_NAME'] = '' # empty for now
|
environ['SCRIPT_NAME'] = '' # empty for now
|
||||||
environ['PATH_INFO'] = urllib.unquote(environ['PATH'])
|
environ['PATH_INFO'] = urllib.unquote(environ['PATH'])
|
||||||
if '?' in environ['URI']:
|
if '?' in environ['URI']:
|
||||||
environ['QUERY_STRING'] = environ['URI'].split('?')[1]
|
environ['QUERY_STRING'] = environ['URI'].split('?')[1]
|
||||||
else:
|
else:
|
||||||
environ['QUERY_STRING'] = ''
|
environ['QUERY_STRING'] = ''
|
||||||
if environ.has_key('Content-Length'):
|
if 'Content-Length' in environ:
|
||||||
environ['CONTENT_LENGTH'] = environ['Content-Length'] # necessary for POST to work with Django
|
environ['CONTENT_LENGTH'] = environ[
|
||||||
|
'Content-Length'] # necessary for POST to work with Django
|
||||||
environ['wsgi.input'] = req.body
|
environ['wsgi.input'] = req.body
|
||||||
|
|
||||||
if debug: print "ENVIRON: %r\n" % environ
|
if debug:
|
||||||
|
print "ENVIRON: %r\n" % environ
|
||||||
|
|
||||||
# SimpleHandler needs file-like stream objects for
|
# SimpleHandler needs file-like stream objects for
|
||||||
# requests, errors and responses
|
# requests, errors and responses
|
||||||
@@ -230,7 +247,8 @@ def mongrel2_handler(application,conn,debug=False):
|
|||||||
respIO = StringIO.StringIO()
|
respIO = StringIO.StringIO()
|
||||||
|
|
||||||
# execute the application
|
# execute the application
|
||||||
handler = SimpleHandler(reqIO, respIO, errIO, environ, multithread = False, multiprocess = False)
|
handler = SimpleHandler(reqIO, respIO, errIO, environ,
|
||||||
|
multithread=False, multiprocess=False)
|
||||||
handler.run(application)
|
handler.run(application)
|
||||||
|
|
||||||
# Get the response and filter out the response (=data) itself,
|
# Get the response and filter out the response (=data) itself,
|
||||||
@@ -254,11 +272,15 @@ def mongrel2_handler(application,conn,debug=False):
|
|||||||
errors = errIO.getvalue()
|
errors = errIO.getvalue()
|
||||||
|
|
||||||
# return the response
|
# return the response
|
||||||
if debug: print "RESPONSE: %r\n" % response
|
if debug:
|
||||||
|
print "RESPONSE: %r\n" % response
|
||||||
if errors:
|
if errors:
|
||||||
if debug: print "ERRORS: %r" % errors
|
if debug:
|
||||||
|
print "ERRORS: %r" % errors
|
||||||
data = "%s\r\n\r\n%s" % (data, errors)
|
data = "%s\r\n\r\n%s" % (data, errors)
|
||||||
conn.reply_http(req, data, code = code, status = status, headers = headers)
|
conn.reply_http(
|
||||||
|
req, data, code=code, status=status, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
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"
|
||||||
@@ -278,7 +300,7 @@ def main():
|
|||||||
default=False,
|
default=False,
|
||||||
dest='profiler',
|
dest='profiler',
|
||||||
help='profiler filename')
|
help='profiler filename')
|
||||||
servers = ', '.join(x for x in dir(Servers) if not x[0]=='_')
|
servers = ', '.join(x for x in dir(Servers) if not x[0] == '_')
|
||||||
parser.add_option('-s',
|
parser.add_option('-s',
|
||||||
'--server',
|
'--server',
|
||||||
default='rocket',
|
default='rocket',
|
||||||
@@ -300,13 +322,10 @@ def main():
|
|||||||
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...' % (options.server,options.ip,options.port)
|
print 'starting %s on %s:%s...' % (
|
||||||
run(options.server,options.ip,options.port,logging=options.logging,profiler=options.profiler)
|
options.server, options.ip, options.port)
|
||||||
|
run(options.server, options.ip, options.port,
|
||||||
|
logging=options.logging, profiler=options.profiler)
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,3 @@ def webapp_add_wsgi_middleware(app):
|
|||||||
from google.appengine.ext.appstats import recording
|
from google.appengine.ext.appstats import recording
|
||||||
app = recording.appstats_wsgi_middleware(app)
|
app = recording.appstats_wsgi_middleware(app)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
|
|||||||
try:
|
try:
|
||||||
hosts = (http_host, socket.gethostname(),
|
hosts = (http_host, socket.gethostname(),
|
||||||
socket.gethostbyname(http_host),
|
socket.gethostbyname(http_host),
|
||||||
'::1','127.0.0.1','::ffff:127.0.0.1')
|
'::1', '127.0.0.1', '::ffff:127.0.0.1')
|
||||||
except:
|
except:
|
||||||
hosts = (http_host, )
|
hosts = (http_host, )
|
||||||
|
|
||||||
@@ -32,10 +32,10 @@ if request.env.http_x_forwarded_for or request.is_https:
|
|||||||
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
||||||
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
||||||
|
|
||||||
if (request.application=='admin' and not session.authorized) or \
|
if (request.application == 'admin' and not session.authorized) or \
|
||||||
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
|
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||||
redirect(URL('admin', 'default', 'index',
|
redirect(URL('admin', 'default', 'index',
|
||||||
vars=dict(send=URL(args=request.args,vars=request.vars))))
|
vars=dict(send=URL(args=request.args, vars=request.vars))))
|
||||||
|
|
||||||
ignore_rw = True
|
ignore_rw = True
|
||||||
response.view = 'appadmin.html'
|
response.view = 'appadmin.html'
|
||||||
@@ -95,24 +95,23 @@ def get_query(request):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def query_by_table_type(tablename,db,request=request):
|
def query_by_table_type(tablename, db, request=request):
|
||||||
keyed = hasattr(db[tablename],'_primarykey')
|
keyed = hasattr(db[tablename], '_primarykey')
|
||||||
if keyed:
|
if keyed:
|
||||||
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
||||||
cond = '>0'
|
cond = '>0'
|
||||||
if firstkey.type in ['string', 'text']:
|
if firstkey.type in ['string', 'text']:
|
||||||
cond = '!=""'
|
cond = '!=""'
|
||||||
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond)
|
qry = '%s.%s.%s%s' % (
|
||||||
|
request.args[0], request.args[1], firstkey.name, cond)
|
||||||
else:
|
else:
|
||||||
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
||||||
return qry
|
return qry
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
# ## list all databases and tables
|
# ## list all databases and tables
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
return dict(databases=databases)
|
return dict(databases=databases)
|
||||||
|
|
||||||
@@ -127,7 +126,7 @@ def insert():
|
|||||||
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
response.flash = T('new record inserted')
|
response.flash = T('new record inserted')
|
||||||
return dict(form=form,table=db[table])
|
return dict(form=form, table=db[table])
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -138,7 +137,8 @@ def insert():
|
|||||||
def download():
|
def download():
|
||||||
import os
|
import os
|
||||||
db = get_database(request)
|
db = get_database(request)
|
||||||
return response.download(request,db)
|
return response.download(request, db)
|
||||||
|
|
||||||
|
|
||||||
def csv():
|
def csv():
|
||||||
import gluon.contenttype
|
import gluon.contenttype
|
||||||
@@ -149,26 +149,27 @@ def csv():
|
|||||||
if not query:
|
if not query:
|
||||||
return None
|
return None
|
||||||
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
||||||
% tuple(request.vars.query.split('.')[:2])
|
% tuple(request.vars.query.split('.')[:2])
|
||||||
return str(db(query,ignore_common_filters=True).select())
|
return str(db(query, ignore_common_filters=True).select())
|
||||||
|
|
||||||
|
|
||||||
def import_csv(table, file):
|
def import_csv(table, file):
|
||||||
table.import_from_csv_file(file)
|
table.import_from_csv_file(file)
|
||||||
|
|
||||||
|
|
||||||
def select():
|
def select():
|
||||||
import re
|
import re
|
||||||
db = get_database(request)
|
db = get_database(request)
|
||||||
dbname = request.args[0]
|
dbname = request.args[0]
|
||||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
||||||
if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'):
|
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
|
||||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
||||||
if request.vars.query:
|
if request.vars.query:
|
||||||
match = regex.match(request.vars.query)
|
match = regex.match(request.vars.query)
|
||||||
if match:
|
if match:
|
||||||
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
||||||
match.group('table'), match.group('field'),
|
match.group('table'), match.group('field'),
|
||||||
match.group('value'))
|
match.group('value'))
|
||||||
else:
|
else:
|
||||||
request.vars.query = session.last_query
|
request.vars.query = session.last_query
|
||||||
query = get_query(request)
|
query = get_query(request)
|
||||||
@@ -192,46 +193,50 @@ def select():
|
|||||||
session.last_query = request.vars.query
|
session.last_query = request.vars.query
|
||||||
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
||||||
_name='query', _value=request.vars.query or '',
|
_name='query', _value=request.vars.query or '',
|
||||||
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'),
|
requires=IS_NOT_EMPTY(
|
||||||
|
error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||||
INPUT(_name='update_check', _type='checkbox',
|
INPUT(_name='update_check', _type='checkbox',
|
||||||
value=False), INPUT(_style='width:400px',
|
value=False), INPUT(_style='width:400px',
|
||||||
_name='update_fields', _value=request.vars.update_fields
|
_name='update_fields', _value=request.vars.update_fields
|
||||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||||
_class='delete', _type='checkbox', value=False), ''),
|
_class='delete', _type='checkbox', value=False), ''),
|
||||||
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
||||||
_action=URL(r=request,args=request.args))
|
_action=URL(r=request, args=request.args))
|
||||||
|
|
||||||
|
tb = None
|
||||||
if form.accepts(request.vars, formname=None):
|
if form.accepts(request.vars, formname=None):
|
||||||
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
||||||
match = regex.match(form.vars.query.strip())
|
match = regex.match(form.vars.query.strip())
|
||||||
if match:
|
if match:
|
||||||
table = match.group('table')
|
table = match.group('table')
|
||||||
try:
|
try:
|
||||||
tb = None
|
|
||||||
nrows = db(query).count()
|
nrows = db(query).count()
|
||||||
if form.vars.update_check and form.vars.update_fields:
|
if form.vars.update_check and form.vars.update_fields:
|
||||||
db(query).update(**eval_in_global_env('dict(%s)'
|
db(query).update(**eval_in_global_env('dict(%s)'
|
||||||
% form.vars.update_fields))
|
% form.vars.update_fields))
|
||||||
response.flash = T('%s %%{row} updated', nrows)
|
response.flash = T('%s %%{row} updated', nrows)
|
||||||
elif form.vars.delete_check:
|
elif form.vars.delete_check:
|
||||||
db(query).delete()
|
db(query).delete()
|
||||||
response.flash = T('%s %%{row} deleted', nrows)
|
response.flash = T('%s %%{row} deleted', nrows)
|
||||||
nrows = db(query).count()
|
nrows = db(query).count()
|
||||||
if orderby:
|
if orderby:
|
||||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby))
|
rows = db(query, ignore_common_filters=True).select(limitby=(
|
||||||
|
start, stop), orderby=eval_in_global_env(orderby))
|
||||||
else:
|
else:
|
||||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
|
rows = db(query, ignore_common_filters=True).select(
|
||||||
|
limitby=(start, stop))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
import traceback
|
import traceback
|
||||||
tb = traceback.format_exc()
|
tb = traceback.format_exc()
|
||||||
(rows, nrows) = ([], 0)
|
(rows, nrows) = ([], 0)
|
||||||
response.flash = DIV(T('Invalid Query'),PRE(str(e)))
|
response.flash = DIV(T('Invalid Query'), PRE(str(e)))
|
||||||
# begin handle upload csv
|
# begin handle upload csv
|
||||||
csv_table = table or request.vars.table
|
csv_table = table or request.vars.table
|
||||||
if csv_table:
|
if csv_table:
|
||||||
formcsv = FORM(str(T('or import from csv file'))+" ",
|
formcsv = FORM(str(T('or import from csv file')) + " ",
|
||||||
INPUT(_type='file',_name='csvfile'),
|
INPUT(_type='file', _name='csvfile'),
|
||||||
INPUT(_type='hidden',_value=csv_table,_name='table'),
|
INPUT(_type='hidden', _value=csv_table, _name='table'),
|
||||||
INPUT(_type='submit',_value=T('import')))
|
INPUT(_type='submit', _value=T('import')))
|
||||||
else:
|
else:
|
||||||
formcsv = None
|
formcsv = None
|
||||||
if formcsv and formcsv.process().accepted:
|
if formcsv and formcsv.process().accepted:
|
||||||
@@ -240,7 +245,7 @@ def select():
|
|||||||
request.vars.csvfile.file)
|
request.vars.csvfile.file)
|
||||||
response.flash = T('data uploaded')
|
response.flash = T('data uploaded')
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
response.flash = DIV(T('unable to parse csv file'),PRE(str(e)))
|
response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
|
||||||
# end handle upload csv
|
# end handle upload csv
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
@@ -251,9 +256,9 @@ def select():
|
|||||||
nrows=nrows,
|
nrows=nrows,
|
||||||
rows=rows,
|
rows=rows,
|
||||||
query=request.vars.query,
|
query=request.vars.query,
|
||||||
formcsv = formcsv,
|
formcsv=formcsv,
|
||||||
tb = tb,
|
tb=tb,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -263,14 +268,16 @@ def select():
|
|||||||
|
|
||||||
def update():
|
def update():
|
||||||
(db, table) = get_table(request)
|
(db, table) = get_table(request)
|
||||||
keyed = hasattr(db[table],'_primarykey')
|
keyed = hasattr(db[table], '_primarykey')
|
||||||
record = None
|
record = None
|
||||||
if keyed:
|
if keyed:
|
||||||
key = [f for f in request.vars if f in db[table]._primarykey]
|
key = [f for f in request.vars if f in db[table]._primarykey]
|
||||||
if key:
|
if key:
|
||||||
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first()
|
record = db(db[table][key[0]] == request.vars[key[
|
||||||
|
0]], ignore_common_filters=True).select().first()
|
||||||
else:
|
else:
|
||||||
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first()
|
record = db(db[table].id == request.args(
|
||||||
|
2), ignore_common_filters=True).select().first()
|
||||||
|
|
||||||
if not record:
|
if not record:
|
||||||
qry = query_by_table_type(table, db)
|
qry = query_by_table_type(table, db)
|
||||||
@@ -280,20 +287,21 @@ def update():
|
|||||||
|
|
||||||
if keyed:
|
if keyed:
|
||||||
for k in db[table]._primarykey:
|
for k in db[table]._primarykey:
|
||||||
db[table][k].writable=False
|
db[table][k].writable = False
|
||||||
|
|
||||||
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'),
|
form = SQLFORM(
|
||||||
ignore_rw=ignore_rw and not keyed,
|
db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||||
linkto=URL('select',
|
ignore_rw=ignore_rw and not keyed,
|
||||||
|
linkto=URL('select',
|
||||||
args=request.args[:1]), upload=URL(r=request,
|
args=request.args[:1]), upload=URL(r=request,
|
||||||
f='download', args=request.args[:1]))
|
f='download', args=request.args[:1]))
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
session.flash = T('done!')
|
session.flash = T('done!')
|
||||||
qry = query_by_table_type(table, db)
|
qry = query_by_table_type(table, db)
|
||||||
redirect(URL('select', args=request.args[:1],
|
redirect(URL('select', args=request.args[:1],
|
||||||
vars=dict(query=qry)))
|
vars=dict(query=qry)))
|
||||||
return dict(form=form,table=db[table])
|
return dict(form=form, table=db[table])
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -304,11 +312,15 @@ def update():
|
|||||||
def state():
|
def state():
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
|
||||||
def ccache():
|
def ccache():
|
||||||
form = FORM(
|
form = FORM(
|
||||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
P(TAG.BUTTON(
|
||||||
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||||
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
P(TAG.BUTTON(
|
||||||
|
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||||
|
P(TAG.BUTTON(
|
||||||
|
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||||
)
|
)
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
@@ -332,11 +344,16 @@ def ccache():
|
|||||||
redirect(URL(r=request))
|
redirect(URL(r=request))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from guppy import hpy; hp=hpy()
|
from guppy import hpy
|
||||||
|
hp = hpy()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
hp = False
|
hp = False
|
||||||
|
|
||||||
import shelve, os, copy, time, math
|
import shelve
|
||||||
|
import os
|
||||||
|
import copy
|
||||||
|
import time
|
||||||
|
import math
|
||||||
from gluon import portalocker
|
from gluon import portalocker
|
||||||
|
|
||||||
ram = {
|
ram = {
|
||||||
@@ -381,9 +398,10 @@ def ccache():
|
|||||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
|
|
||||||
locker = open(os.path.join(request.folder,
|
locker = open(os.path.join(request.folder,
|
||||||
'cache/cache.lock'), 'a')
|
'cache/cache.lock'), 'a')
|
||||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||||
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve'))
|
disk_storage = shelve.open(
|
||||||
|
os.path.join(request.folder, 'cache/cache.shelve'))
|
||||||
try:
|
try:
|
||||||
for key, value in disk_storage.items():
|
for key, value in disk_storage.items():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
@@ -414,7 +432,8 @@ def ccache():
|
|||||||
total['misses'] = ram['misses'] + disk['misses']
|
total['misses'] = ram['misses'] + disk['misses']
|
||||||
total['keys'] = ram['keys'] + disk['keys']
|
total['keys'] = ram['keys'] + disk['keys']
|
||||||
try:
|
try:
|
||||||
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
|
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||||
|
total['misses'])
|
||||||
except (KeyError, ZeroDivisionError):
|
except (KeyError, ZeroDivisionError):
|
||||||
total['ratio'] = 0
|
total['ratio'] = 0
|
||||||
|
|
||||||
@@ -440,6 +459,3 @@ def ccache():
|
|||||||
|
|
||||||
return dict(form=form, total=total,
|
return dict(form=form, total=total,
|
||||||
ram=ram, disk=disk, object_stats=hp != False)
|
ram=ram, disk=disk, object_stats=hp != False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,35 +5,39 @@ import gluon.contrib.shell
|
|||||||
import gluon.dal
|
import gluon.dal
|
||||||
import gluon.html
|
import gluon.html
|
||||||
import gluon.validators
|
import gluon.validators
|
||||||
import code, thread
|
import code
|
||||||
|
import thread
|
||||||
from gluon.debug import communicate, web_debugger, qdb_debugger
|
from gluon.debug import communicate, web_debugger, qdb_debugger
|
||||||
import pydoc
|
import pydoc
|
||||||
|
|
||||||
|
|
||||||
if DEMO_MODE or MULTI_USER_MODE:
|
if DEMO_MODE or MULTI_USER_MODE:
|
||||||
session.flash = T('disabled in demo mode')
|
session.flash = T('disabled in demo mode')
|
||||||
redirect(URL('default','site'))
|
redirect(URL('default', 'site'))
|
||||||
|
|
||||||
|
FE = 10 ** 9
|
||||||
|
|
||||||
FE=10**9
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
app = request.args(0) or 'admin'
|
app = request.args(0) or 'admin'
|
||||||
reset()
|
reset()
|
||||||
# read buffer
|
# read buffer
|
||||||
data = communicate()
|
data = communicate()
|
||||||
return dict(app=app,data=data)
|
return dict(app=app, data=data)
|
||||||
|
|
||||||
|
|
||||||
def callback():
|
def callback():
|
||||||
app = request.args[0]
|
app = request.args[0]
|
||||||
command = request.vars.statement
|
command = request.vars.statement
|
||||||
session['debug_commands:'+app].append(command)
|
session['debug_commands:' + app].append(command)
|
||||||
output = communicate(command)
|
output = communicate(command)
|
||||||
k = len(session['debug_commands:'+app]) - 1
|
k = len(session['debug_commands:' + app]) - 1
|
||||||
return '[%i] %s%s\n' % (k + 1, command, output)
|
return '[%i] %s%s\n' % (k + 1, command, output)
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
app = request.args(0) or 'admin'
|
app = request.args(0) or 'admin'
|
||||||
session['debug_commands:'+app] = []
|
session['debug_commands:' + app] = []
|
||||||
return 'done'
|
return 'done'
|
||||||
|
|
||||||
|
|
||||||
@@ -50,9 +54,9 @@ def interact():
|
|||||||
filename = web_debugger.filename
|
filename = web_debugger.filename
|
||||||
lineno = web_debugger.lineno
|
lineno = web_debugger.lineno
|
||||||
if filename:
|
if filename:
|
||||||
lines = dict([(i+1, l) for (i, l) in enumerate(
|
lines = dict([(i + 1, l) for (i, l) in enumerate(
|
||||||
[l.strip("\n").strip("\r") for l
|
[l.strip("\n").strip("\r") for l
|
||||||
in open(filename).readlines()])])
|
in open(filename).readlines()])])
|
||||||
filename = os.path.basename(filename)
|
filename = os.path.basename(filename)
|
||||||
else:
|
else:
|
||||||
lines = {}
|
lines = {}
|
||||||
@@ -64,8 +68,8 @@ def interact():
|
|||||||
f_globals = {}
|
f_globals = {}
|
||||||
for name, value in env['globals'].items():
|
for name, value in env['globals'].items():
|
||||||
if name not in gluon.html.__all__ and \
|
if name not in gluon.html.__all__ and \
|
||||||
name not in gluon.validators.__all__ and \
|
name not in gluon.validators.__all__ and \
|
||||||
name not in gluon.dal.__all__:
|
name not in gluon.dal.__all__:
|
||||||
f_globals[name] = pydoc.text.repr(value)
|
f_globals[name] = pydoc.text.repr(value)
|
||||||
else:
|
else:
|
||||||
f_locals = {}
|
f_locals = {}
|
||||||
@@ -76,42 +80,48 @@ def interact():
|
|||||||
response.flash = T('"User Exception" debug mode. '
|
response.flash = T('"User Exception" debug mode. '
|
||||||
'An error ticket could be issued!')
|
'An error ticket could be issued!')
|
||||||
|
|
||||||
return dict(app=app, data="",
|
return dict(app=app, data="",
|
||||||
filename=web_debugger.filename, lines=lines, lineno=lineno,
|
filename=web_debugger.filename, lines=lines, lineno=lineno,
|
||||||
f_globals=f_globals, f_locals=f_locals,
|
f_globals=f_globals, f_locals=f_locals,
|
||||||
exception=web_debugger.exception_info)
|
exception=web_debugger.exception_info)
|
||||||
|
|
||||||
|
|
||||||
def step():
|
def step():
|
||||||
web_debugger.do_step()
|
web_debugger.do_step()
|
||||||
redirect(URL("interact"))
|
redirect(URL("interact"))
|
||||||
|
|
||||||
|
|
||||||
def next():
|
def next():
|
||||||
web_debugger.do_next()
|
web_debugger.do_next()
|
||||||
redirect(URL("interact"))
|
redirect(URL("interact"))
|
||||||
|
|
||||||
|
|
||||||
def cont():
|
def cont():
|
||||||
web_debugger.do_continue()
|
web_debugger.do_continue()
|
||||||
redirect(URL("interact"))
|
redirect(URL("interact"))
|
||||||
|
|
||||||
|
|
||||||
def ret():
|
def ret():
|
||||||
web_debugger.do_return()
|
web_debugger.do_return()
|
||||||
redirect(URL("interact"))
|
redirect(URL("interact"))
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
def stop():
|
||||||
web_debugger.do_quit()
|
web_debugger.do_quit()
|
||||||
redirect(URL("interact"))
|
redirect(URL("interact"))
|
||||||
|
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
app = request.args[0]
|
app = request.args[0]
|
||||||
command = request.vars.statement
|
command = request.vars.statement
|
||||||
session['debug_commands:'+app].append(command)
|
session['debug_commands:' + app].append(command)
|
||||||
try:
|
try:
|
||||||
output = web_debugger.do_exec(command)
|
output = web_debugger.do_exec(command)
|
||||||
if output is None:
|
if output is None:
|
||||||
output = ""
|
output = ""
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
output = T("Exception %s") % str(e)
|
output = T("Exception %s") % str(e)
|
||||||
k = len(session['debug_commands:'+app]) - 1
|
k = len(session['debug_commands:' + app]) - 1
|
||||||
return '[%i] %s%s\n' % (k + 1, command, output)
|
return '[%i] %s%s\n' % (k + 1, command, output)
|
||||||
|
|
||||||
|
|
||||||
@@ -120,51 +130,51 @@ def breakpoints():
|
|||||||
|
|
||||||
# Get all .py files
|
# Get all .py files
|
||||||
files = listdir(apath('', r=request), '.*\.py$')
|
files = listdir(apath('', r=request), '.*\.py$')
|
||||||
files = [filename for filename in files
|
files = [filename for filename in files
|
||||||
if filename and 'languages' not in filename
|
if filename and 'languages' not in filename
|
||||||
and not filename.startswith("admin")
|
and not filename.startswith("admin")
|
||||||
and not filename.startswith("examples")]
|
and not filename.startswith("examples")]
|
||||||
|
|
||||||
form = SQLFORM.factory(
|
form = SQLFORM.factory(
|
||||||
Field('filename', requires=IS_IN_SET(files), label=T("Filename")),
|
Field('filename', requires=IS_IN_SET(files), label=T("Filename")),
|
||||||
Field('lineno', 'integer', label=T("Line number"),
|
Field('lineno', 'integer', label=T("Line number"),
|
||||||
requires=IS_NOT_EMPTY()),
|
requires=IS_NOT_EMPTY()),
|
||||||
Field('temporary', 'boolean', label=T("Temporary"),
|
Field('temporary', 'boolean', label=T("Temporary"),
|
||||||
comment=T("deleted after first hit")),
|
comment=T("deleted after first hit")),
|
||||||
Field('condition', 'string', label=T("Condition"),
|
Field('condition', 'string', label=T("Condition"),
|
||||||
comment=T("honored only if the expression evaluates to true")),
|
comment=T("honored only if the expression evaluates to true")),
|
||||||
)
|
)
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
filename = os.path.join(request.env['applications_parent'],
|
filename = os.path.join(request.env['applications_parent'],
|
||||||
'applications', form.vars.filename)
|
'applications', form.vars.filename)
|
||||||
err = qdb_debugger.do_set_breakpoint(filename,
|
err = qdb_debugger.do_set_breakpoint(filename,
|
||||||
form.vars.lineno,
|
form.vars.lineno,
|
||||||
form.vars.temporary,
|
form.vars.temporary,
|
||||||
form.vars.condition)
|
form.vars.condition)
|
||||||
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
||||||
filename, form.vars.lineno, err or T('successful'))
|
filename, form.vars.lineno, err or T('successful'))
|
||||||
|
|
||||||
for item in request.vars:
|
for item in request.vars:
|
||||||
if item[:7] == 'delete_':
|
if item[:7] == 'delete_':
|
||||||
qdb_debugger.do_clear(item[7:])
|
qdb_debugger.do_clear(item[7:])
|
||||||
|
|
||||||
breakpoints = [{'number': bp[0], 'filename': os.path.basename(bp[1]),
|
breakpoints = [{'number': bp[0], 'filename': os.path.basename(bp[1]),
|
||||||
'path': bp[1], 'lineno': bp[2],
|
'path': bp[1], 'lineno': bp[2],
|
||||||
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
|
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
|
||||||
'condition': bp[6]}
|
'condition': bp[6]}
|
||||||
for bp in qdb_debugger.do_list_breakpoint()]
|
for bp in qdb_debugger.do_list_breakpoint()]
|
||||||
|
|
||||||
return dict(breakpoints=breakpoints, form=form)
|
return dict(breakpoints=breakpoints, form=form)
|
||||||
|
|
||||||
|
|
||||||
def toggle_breakpoint():
|
def toggle_breakpoint():
|
||||||
"Set or clear a breakpoint"
|
"Set or clear a breakpoint"
|
||||||
|
|
||||||
lineno = None
|
lineno = None
|
||||||
ok = None
|
ok = None
|
||||||
try:
|
try:
|
||||||
filename = os.path.join(request.env['applications_parent'],
|
filename = os.path.join(request.env['applications_parent'],
|
||||||
'applications', request.vars.filename)
|
'applications', request.vars.filename)
|
||||||
if not request.vars.data:
|
if not request.vars.data:
|
||||||
# ace send us the line number!
|
# ace send us the line number!
|
||||||
@@ -184,18 +194,17 @@ def toggle_breakpoint():
|
|||||||
no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp
|
no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp
|
||||||
if filename == bp_filename and lineno == bp_lineno:
|
if filename == bp_filename and lineno == bp_lineno:
|
||||||
err = qdb_debugger.do_clear_breakpoint(filename, lineno)
|
err = qdb_debugger.do_clear_breakpoint(filename, lineno)
|
||||||
response.flash = T("Removed Breakpoint on %s at line %s", (
|
response.flash = T("Removed Breakpoint on %s at line %s", (
|
||||||
filename, lineno))
|
filename, lineno))
|
||||||
ok = False
|
ok = False
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
err = qdb_debugger.do_set_breakpoint(filename, lineno)
|
err = qdb_debugger.do_set_breakpoint(filename, lineno)
|
||||||
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
||||||
filename, lineno, err or T('successful'))
|
filename, lineno, err or T('successful'))
|
||||||
ok = True
|
ok = True
|
||||||
else:
|
else:
|
||||||
response.flash = T("Unable to determine the line number!")
|
response.flash = T("Unable to determine the line number!")
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
session.flash = str(e)
|
session.flash = str(e)
|
||||||
return response.json({'ok': ok, 'lineno': lineno})
|
return response.json({'ok': ok, 'lineno': lineno})
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,85 +9,92 @@ try:
|
|||||||
import shutil
|
import shutil
|
||||||
from gluon.fileutils import read_file, write_file
|
from gluon.fileutils import read_file, write_file
|
||||||
except:
|
except:
|
||||||
session.flash='sorry, only on Unix systems'
|
session.flash = 'sorry, only on Unix systems'
|
||||||
redirect(URL(request.application,'default','site'))
|
redirect(URL(request.application, 'default', 'site'))
|
||||||
|
|
||||||
if MULTI_USER_MODE and not is_manager():
|
if MULTI_USER_MODE and not is_manager():
|
||||||
session.flash = 'Not Authorized'
|
session.flash = 'Not Authorized'
|
||||||
redirect(URL('default','site'))
|
redirect(URL('default', 'site'))
|
||||||
|
|
||||||
|
forever = 10 ** 8
|
||||||
|
|
||||||
forever=10**8
|
|
||||||
|
|
||||||
def kill():
|
def kill():
|
||||||
p = cache.ram('gae_upload',lambda:None,forever)
|
p = cache.ram('gae_upload', lambda: None, forever)
|
||||||
if not p or p.poll()!=None:
|
if not p or p.poll() is not None:
|
||||||
return 'oops'
|
return 'oops'
|
||||||
os.kill(p.pid, signal.SIGKILL)
|
os.kill(p.pid, signal.SIGKILL)
|
||||||
cache.ram('gae_upload',lambda:None,-1)
|
cache.ram('gae_upload', lambda: None, -1)
|
||||||
|
|
||||||
|
|
||||||
class EXISTS(object):
|
class EXISTS(object):
|
||||||
def __init__(self, error_message='file not found'):
|
def __init__(self, error_message='file not found'):
|
||||||
self.error_message = error_message
|
self.error_message = error_message
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
if os.path.exists(value):
|
if os.path.exists(value):
|
||||||
return (value,None)
|
return (value, None)
|
||||||
return (value,self.error_message)
|
return (value, self.error_message)
|
||||||
|
|
||||||
|
|
||||||
def deploy():
|
def deploy():
|
||||||
regex = re.compile('^\w+$')
|
regex = re.compile('^\w+$')
|
||||||
apps = sorted(file for file in os.listdir(apath(r=request)) if regex.match(file))
|
apps = sorted(
|
||||||
|
file for file in os.listdir(apath(r=request)) if regex.match(file))
|
||||||
form = SQLFORM.factory(
|
form = SQLFORM.factory(
|
||||||
Field('appcfg',default=GAE_APPCFG,label=T('Path to appcfg.py'),
|
Field('appcfg', default=GAE_APPCFG, label=T('Path to appcfg.py'),
|
||||||
requires=EXISTS(error_message=T('file not found'))),
|
requires=EXISTS(error_message=T('file not found'))),
|
||||||
Field('google_application_id',requires=IS_MATCH('[\w\-]+'),label=T('Google Application Id')),
|
Field('google_application_id', requires=IS_MATCH(
|
||||||
Field('applications','list:string',
|
'[\w\-]+'), label=T('Google Application Id')),
|
||||||
requires=IS_IN_SET(apps,multiple=True),
|
Field('applications', 'list:string',
|
||||||
|
requires=IS_IN_SET(apps, multiple=True),
|
||||||
label=T('web2py apps to deploy')),
|
label=T('web2py apps to deploy')),
|
||||||
Field('email',requires=IS_EMAIL(),label=T('GAE Email')),
|
Field('email', requires=IS_EMAIL(), label=T('GAE Email')),
|
||||||
Field('password','password',requires=IS_NOT_EMPTY(),label=T('GAE Password')))
|
Field('password', 'password', requires=IS_NOT_EMPTY(), label=T('GAE Password')))
|
||||||
cmd = output = errors= ""
|
cmd = output = errors = ""
|
||||||
if form.accepts(request,session):
|
if form.accepts(request, session):
|
||||||
try:
|
try:
|
||||||
kill()
|
kill()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
ignore_apps = [item for item in apps \
|
ignore_apps = [item for item in apps
|
||||||
if not item in form.vars.applications]
|
if not item in form.vars.applications]
|
||||||
regex = re.compile('\(applications/\(.*')
|
regex = re.compile('\(applications/\(.*')
|
||||||
yaml = apath('../app.yaml', r=request)
|
yaml = apath('../app.yaml', r=request)
|
||||||
if not os.path.exists(yaml):
|
if not os.path.exists(yaml):
|
||||||
example = apath('../app.example.yaml', r=request)
|
example = apath('../app.example.yaml', r=request)
|
||||||
shutil.copyfile(example,yaml)
|
shutil.copyfile(example, yaml)
|
||||||
data = read_file(yaml)
|
data = read_file(yaml)
|
||||||
data = re.sub('application:.*','application: %s' % form.vars.google_application_id,data)
|
data = re.sub('application:.*', 'application: %s' %
|
||||||
data = regex.sub('(applications/(%s)/.*)|' % '|'.join(ignore_apps),data)
|
form.vars.google_application_id, data)
|
||||||
|
data = regex.sub(
|
||||||
|
'(applications/(%s)/.*)|' % '|'.join(ignore_apps), data)
|
||||||
write_file(yaml, data)
|
write_file(yaml, data)
|
||||||
|
|
||||||
path = request.env.applications_parent
|
path = request.env.applications_parent
|
||||||
cmd = '%s --email=%s --passin update %s' % \
|
cmd = '%s --email=%s --passin update %s' % \
|
||||||
(form.vars.appcfg, form.vars.email, path)
|
(form.vars.appcfg, form.vars.email, path)
|
||||||
p = cache.ram('gae_upload',
|
p = cache.ram('gae_upload',
|
||||||
lambda s=subprocess,c=cmd:s.Popen(c, shell=True,
|
lambda s=subprocess, c=cmd: s.Popen(c, shell=True,
|
||||||
stdin=s.PIPE,
|
stdin=s.PIPE,
|
||||||
stdout=s.PIPE,
|
stdout=s.PIPE,
|
||||||
stderr=s.PIPE, close_fds=True),-1)
|
stderr=s.PIPE, close_fds=True), -1)
|
||||||
p.stdin.write(form.vars.password+'\n')
|
p.stdin.write(form.vars.password + '\n')
|
||||||
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
|
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
|
||||||
fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
|
fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
|
||||||
return dict(form=form,command=cmd)
|
return dict(form=form, command=cmd)
|
||||||
|
|
||||||
|
|
||||||
def callback():
|
def callback():
|
||||||
p = cache.ram('gae_upload',lambda:None,forever)
|
p = cache.ram('gae_upload', lambda: None, forever)
|
||||||
if not p or p.poll()!=None:
|
if not p or p.poll() is not None:
|
||||||
return '<done/>'
|
return '<done/>'
|
||||||
try:
|
try:
|
||||||
output = p.stdout.read()
|
output = p.stdout.read()
|
||||||
except:
|
except:
|
||||||
output=''
|
output = ''
|
||||||
try:
|
try:
|
||||||
errors = p.stderr.read()
|
errors = p.stderr.read()
|
||||||
except:
|
except:
|
||||||
errors=''
|
errors = ''
|
||||||
return (output+errors).replace('\n','<br/>')
|
return (output + errors).replace('\n', '<br/>')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ from gluon.fileutils import read_file, write_file
|
|||||||
|
|
||||||
if DEMO_MODE or MULTI_USER_MODE:
|
if DEMO_MODE or MULTI_USER_MODE:
|
||||||
session.flash = T('disabled in demo mode')
|
session.flash = T('disabled in demo mode')
|
||||||
redirect(URL('default','site'))
|
redirect(URL('default', 'site'))
|
||||||
if not have_mercurial:
|
if not have_mercurial:
|
||||||
session.flash=T("Sorry, could not find mercurial installed")
|
session.flash = T("Sorry, could not find mercurial installed")
|
||||||
redirect(URL('default','design',args=request.args(0)))
|
redirect(URL('default', 'design', args=request.args(0)))
|
||||||
|
|
||||||
_hgignore_content = """\
|
_hgignore_content = """\
|
||||||
syntax: glob
|
syntax: glob
|
||||||
@@ -22,6 +22,7 @@ sessions/*
|
|||||||
errors/*
|
errors/*
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def hg_repo(path):
|
def hg_repo(path):
|
||||||
import os
|
import os
|
||||||
uio = ui.ui()
|
uio = ui.ui()
|
||||||
@@ -37,13 +38,14 @@ def hg_repo(path):
|
|||||||
write_file(hgignore, _hgignore_content)
|
write_file(hgignore, _hgignore_content)
|
||||||
return repo
|
return repo
|
||||||
|
|
||||||
|
|
||||||
def commit():
|
def commit():
|
||||||
app = request.args(0)
|
app = request.args(0)
|
||||||
path = apath(app, r=request)
|
path = apath(app, r=request)
|
||||||
repo = hg_repo(path)
|
repo = hg_repo(path)
|
||||||
form = FORM('Comment:',INPUT(_name='comment',requires=IS_NOT_EMPTY()),
|
form = FORM('Comment:', INPUT(_name='comment', requires=IS_NOT_EMPTY()),
|
||||||
INPUT(_type='submit',_value=T('Commit')))
|
INPUT(_type='submit', _value=T('Commit')))
|
||||||
if form.accepts(request.vars,session):
|
if form.accepts(request.vars, session):
|
||||||
oldid = repo[repo.lookup('.')]
|
oldid = repo[repo.lookup('.')]
|
||||||
addremove(repo)
|
addremove(repo)
|
||||||
repo.commit(text=form.vars.comment)
|
repo.commit(text=form.vars.comment)
|
||||||
@@ -51,34 +53,33 @@ def commit():
|
|||||||
response.flash = 'no changes'
|
response.flash = 'no changes'
|
||||||
try:
|
try:
|
||||||
files = TABLE(*[TR(file) for file in repo[repo.lookup('.')].files()])
|
files = TABLE(*[TR(file) for file in repo[repo.lookup('.')].files()])
|
||||||
changes = TABLE(TR(TH('revision'),TH('description')))
|
changes = TABLE(TR(TH('revision'), TH('description')))
|
||||||
for change in repo.changelog:
|
for change in repo.changelog:
|
||||||
ctx=repo.changectx(change)
|
ctx = repo.changectx(change)
|
||||||
revision, description = ctx.rev(), ctx.description()
|
revision, description = ctx.rev(), ctx.description()
|
||||||
changes.append(TR(A(revision,_href=URL('revision',
|
changes.append(TR(A(revision, _href=URL('revision',
|
||||||
args=(app,revision))),
|
args=(app, revision))),
|
||||||
description))
|
description))
|
||||||
except:
|
except:
|
||||||
files = []
|
files = []
|
||||||
changes = []
|
changes = []
|
||||||
return dict(form=form,files=files,changes=changes,repo=repo)
|
return dict(form=form, files=files, changes=changes, repo=repo)
|
||||||
|
|
||||||
|
|
||||||
def revision():
|
def revision():
|
||||||
app = request.args(0)
|
app = request.args(0)
|
||||||
path = apath(app, r=request)
|
path = apath(app, r=request)
|
||||||
repo = hg_repo(path)
|
repo = hg_repo(path)
|
||||||
revision = request.args(1)
|
revision = request.args(1)
|
||||||
ctx=repo.changectx(revision)
|
ctx = repo.changectx(revision)
|
||||||
form=FORM(INPUT(_type='submit',_value=T('Revert')))
|
form = FORM(INPUT(_type='submit', _value=T('Revert')))
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
hg.update(repo, revision)
|
hg.update(repo, revision)
|
||||||
session.flash = "reverted to revision %s" % ctx.rev()
|
session.flash = "reverted to revision %s" % ctx.rev()
|
||||||
redirect(URL('default','design',args=app))
|
redirect(URL('default', 'design', args=app))
|
||||||
return dict(
|
return dict(
|
||||||
files=ctx.files(),
|
files=ctx.files(),
|
||||||
rev=str(ctx.rev()),
|
rev=str(ctx.rev()),
|
||||||
desc=ctx.description(),
|
desc=ctx.description(),
|
||||||
form=form
|
form=form
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,36 @@
|
|||||||
import os
|
import os
|
||||||
from distutils import dir_util
|
try:
|
||||||
|
from distutils import dir_util
|
||||||
|
except ImportError:
|
||||||
|
session.flash = T('requires distutils, but not installed')
|
||||||
|
redirect(URL('default', 'site'))
|
||||||
try:
|
try:
|
||||||
from git import *
|
from git import *
|
||||||
except ImportError:
|
except ImportError:
|
||||||
session.flash = T('requires python-git, but not installed')
|
session.flash = T('requires python-git, but not installed')
|
||||||
redirect(URL('default','site'))
|
redirect(URL('default', 'site'))
|
||||||
|
|
||||||
|
|
||||||
def deploy():
|
def deploy():
|
||||||
apps = sorted(file for file in os.listdir(apath(r=request)))
|
apps = sorted(file for file in os.listdir(apath(r=request)))
|
||||||
form = SQLFORM.factory(
|
form = SQLFORM.factory(
|
||||||
Field('osrepo',default='/tmp',label=T('Path to local openshift repo root.'),
|
Field(
|
||||||
requires=EXISTS(error_message=T('directory not found'))),
|
'osrepo', default='/tmp', label=T('Path to local openshift repo root.'),
|
||||||
Field('osname',default='web2py',label=T('WSGI reference name')),
|
requires=EXISTS(error_message=T('directory not found'))),
|
||||||
Field('applications','list:string',
|
Field('osname', default='web2py', label=T('WSGI reference name')),
|
||||||
requires=IS_IN_SET(apps,multiple=True),
|
Field('applications', 'list:string',
|
||||||
|
requires=IS_IN_SET(apps, multiple=True),
|
||||||
label=T('web2py apps to deploy')))
|
label=T('web2py apps to deploy')))
|
||||||
|
|
||||||
cmd = output = errors= ""
|
cmd = output = errors = ""
|
||||||
if form.accepts(request,session):
|
if form.accepts(request, session):
|
||||||
try:
|
try:
|
||||||
kill()
|
kill()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ignore_apps = [item for item in apps if not item in form.vars.applications]
|
ignore_apps = [
|
||||||
|
item for item in apps if not item in form.vars.applications]
|
||||||
regex = re.compile('\(applications/\(.*')
|
regex = re.compile('\(applications/\(.*')
|
||||||
w2p_origin = os.getcwd()
|
w2p_origin = os.getcwd()
|
||||||
osrepo = form.vars.osrepo
|
osrepo = form.vars.osrepo
|
||||||
@@ -34,23 +41,25 @@ def deploy():
|
|||||||
assert repo.bare == False
|
assert repo.bare == False
|
||||||
|
|
||||||
for i in form.vars.applications:
|
for i in form.vars.applications:
|
||||||
appsrc = os.path.join(apath(r=request),i)
|
appsrc = os.path.join(apath(r=request), i)
|
||||||
appdest = os.path.join(osrepo,'wsgi',osname,'applications',i)
|
appdest = os.path.join(osrepo, 'wsgi', osname, 'applications', i)
|
||||||
dir_util.copy_tree(appsrc,appdest)
|
dir_util.copy_tree(appsrc, appdest)
|
||||||
#shutil.copytree(appsrc,appdest)
|
#shutil.copytree(appsrc,appdest)
|
||||||
index.add(['wsgi/'+osname+'/applications/'+i])
|
index.add(['wsgi/' + osname + '/applications/' + i])
|
||||||
new_commit = index.commit("Deploy from Web2py IDE")
|
new_commit = index.commit("Deploy from Web2py IDE")
|
||||||
|
|
||||||
origin = repo.remotes.origin
|
origin = repo.remotes.origin
|
||||||
origin.push
|
origin.push
|
||||||
origin.push()
|
origin.push()
|
||||||
#Git code ends here
|
#Git code ends here
|
||||||
return dict(form=form,command=cmd)
|
return dict(form=form, command=cmd)
|
||||||
|
|
||||||
|
|
||||||
class EXISTS(object):
|
class EXISTS(object):
|
||||||
def __init__(self, error_message='file not found'):
|
def __init__(self, error_message='file not found'):
|
||||||
self.error_message = error_message
|
self.error_message = error_message
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
if os.path.exists(value):
|
if os.path.exists(value):
|
||||||
return (value,None)
|
return (value, None)
|
||||||
return (value,self.error_message)
|
return (value, self.error_message)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
response.files=response.files[:3]
|
response.files = response.files[:3]
|
||||||
response.menu=[]
|
response.menu = []
|
||||||
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
|
|
||||||
def about():
|
def about():
|
||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,29 @@
|
|||||||
import sys
|
import sys
|
||||||
import cStringIO
|
import cStringIO
|
||||||
import gluon.contrib.shell
|
import gluon.contrib.shell
|
||||||
import code, thread
|
import code
|
||||||
|
import thread
|
||||||
from gluon.shell import env
|
from gluon.shell import env
|
||||||
|
|
||||||
if DEMO_MODE or MULTI_USER_MODE:
|
if DEMO_MODE or MULTI_USER_MODE:
|
||||||
session.flash = T('disabled in demo mode')
|
session.flash = T('disabled in demo mode')
|
||||||
redirect(URL('default','site'))
|
redirect(URL('default', 'site'))
|
||||||
|
|
||||||
|
FE = 10 ** 9
|
||||||
|
|
||||||
FE=10**9
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
app = request.args(0) or 'admin'
|
app = request.args(0) or 'admin'
|
||||||
reset()
|
reset()
|
||||||
return dict(app=app)
|
return dict(app=app)
|
||||||
|
|
||||||
|
|
||||||
def callback():
|
def callback():
|
||||||
app = request.args[0]
|
app = request.args[0]
|
||||||
command = request.vars.statement
|
command = request.vars.statement
|
||||||
escape = command[:1]!='!'
|
escape = command[:1] != '!'
|
||||||
history = session['history:'+app] = session.get('history:'+app,gluon.contrib.shell.History())
|
history = session['history:' + app] = session.get(
|
||||||
|
'history:' + app, gluon.contrib.shell.History())
|
||||||
if not escape:
|
if not escape:
|
||||||
command = command[1:]
|
command = command[1:]
|
||||||
if command == '%reset':
|
if command == '%reset':
|
||||||
@@ -27,21 +31,20 @@ def callback():
|
|||||||
return '*** reset ***'
|
return '*** reset ***'
|
||||||
elif command[0] == '%':
|
elif command[0] == '%':
|
||||||
try:
|
try:
|
||||||
command=session['commands:'+app][int(command[1:])]
|
command = session['commands:' + app][int(command[1:])]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return ''
|
return ''
|
||||||
session['commands:'+app].append(command)
|
session['commands:' + app].append(command)
|
||||||
environ=env(app,True)
|
environ = env(app, True)
|
||||||
output = gluon.contrib.shell.run(history,command,environ)
|
output = gluon.contrib.shell.run(history, command, environ)
|
||||||
k = len(session['commands:'+app]) - 1
|
k = len(session['commands:' + app]) - 1
|
||||||
#output = PRE(output)
|
#output = PRE(output)
|
||||||
#return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output))
|
#return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output))
|
||||||
return 'In [%i] : %s%s\n' % (k + 1, command, output)
|
return 'In [%i] : %s%s\n' % (k + 1, command, output)
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
app = request.args(0) or 'admin'
|
app = request.args(0) or 'admin'
|
||||||
session['commands:'+app] = []
|
session['commands:' + app] = []
|
||||||
session['history:'+app] = gluon.contrib.shell.History()
|
session['history:' + app] = gluon.contrib.shell.History()
|
||||||
return 'done'
|
return 'done'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import os
|
|||||||
from gluon.settings import global_settings, read_file
|
from gluon.settings import global_settings, read_file
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
app = request.args(0)
|
app = request.args(0)
|
||||||
return dict(app=app)
|
return dict(app=app)
|
||||||
|
|
||||||
|
|
||||||
def profiler():
|
def profiler():
|
||||||
"""
|
"""
|
||||||
to use the profiler start web2py with -F profiler.log
|
to use the profiler start web2py with -F profiler.log
|
||||||
@@ -19,13 +21,11 @@ def profiler():
|
|||||||
else:
|
else:
|
||||||
size = 0
|
size = 0
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
data = read_file('profiler.log','rb')
|
data = read_file('profiler.log', 'rb')
|
||||||
if size<len(data):
|
if size < len(data):
|
||||||
data = data[size:]
|
data = data[size:]
|
||||||
else:
|
else:
|
||||||
size=0
|
size = 0
|
||||||
size += len(data)
|
size += len(data)
|
||||||
response.cookies[KEY] = size
|
response.cookies[KEY] = size
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def list_apps():
|
|||||||
@service.jsonrpc
|
@service.jsonrpc
|
||||||
def list_files(app, pattern='.*\.py$'):
|
def list_files(app, pattern='.*\.py$'):
|
||||||
files = listdir(apath('%s/' % app, r=request), pattern)
|
files = listdir(apath('%s/' % app, r=request), pattern)
|
||||||
return [x.replace('\\','/') for x in files]
|
return [x.replace('\\', '/') for x in files]
|
||||||
|
|
||||||
|
|
||||||
@service.jsonrpc
|
@service.jsonrpc
|
||||||
@@ -43,7 +43,7 @@ def read_file(filename, b64=False):
|
|||||||
try:
|
try:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
if not b64:
|
if not b64:
|
||||||
data = data.replace('\r','')
|
data = data.replace('\r', '')
|
||||||
else:
|
else:
|
||||||
data = base64.b64encode(data)
|
data = base64.b64encode(data)
|
||||||
finally:
|
finally:
|
||||||
@@ -82,6 +82,7 @@ def install(app_name, filename, data, overwrite=True):
|
|||||||
|
|
||||||
return installed
|
return installed
|
||||||
|
|
||||||
|
|
||||||
@service.jsonrpc
|
@service.jsonrpc
|
||||||
def attach_debugger(host='localhost', port=6000, authkey='secret password'):
|
def attach_debugger(host='localhost', port=6000, authkey='secret password'):
|
||||||
import gluon.contrib.qdb as qdb
|
import gluon.contrib.qdb as qdb
|
||||||
@@ -90,7 +91,7 @@ def attach_debugger(host='localhost', port=6000, authkey='secret password'):
|
|||||||
|
|
||||||
if isinstance(authkey, unicode):
|
if isinstance(authkey, unicode):
|
||||||
authkey = authkey.encode('utf8')
|
authkey = authkey.encode('utf8')
|
||||||
|
|
||||||
if not hasattr(gluon.debug, 'qdb_listener'):
|
if not hasattr(gluon.debug, 'qdb_listener'):
|
||||||
# create a remote debugger server and wait for connection
|
# create a remote debugger server and wait for connection
|
||||||
address = (host, port) # family is deduced to be 'AF_INET'
|
address = (host, port) # family is deduced to be 'AF_INET'
|
||||||
@@ -124,7 +125,7 @@ def detach_debugger():
|
|||||||
gluon.debug.qdb_debugger = None
|
gluon.debug.qdb_debugger = None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def call():
|
def call():
|
||||||
session.forget()
|
session.forget()
|
||||||
return service()
|
return service()
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +1,73 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os, uuid, re, pickle, urllib, glob
|
import os
|
||||||
|
import uuid
|
||||||
|
import re
|
||||||
|
import pickle
|
||||||
|
import urllib
|
||||||
|
import glob
|
||||||
from gluon.admin import app_create, plugin_install
|
from gluon.admin import app_create, plugin_install
|
||||||
from gluon.fileutils import abspath, read_file, write_file
|
from gluon.fileutils import abspath, read_file, write_file
|
||||||
|
|
||||||
def reset(session):
|
|
||||||
session.app={
|
|
||||||
'name':'',
|
|
||||||
'params':[('title','My New App'),
|
|
||||||
('subtitle','powered by web2py'),
|
|
||||||
('author','you'),
|
|
||||||
('author_email','you@example.com'),
|
|
||||||
('keywords',''),
|
|
||||||
('description',''),
|
|
||||||
('layout_theme','Default'),
|
|
||||||
('database_uri','sqlite://storage.sqlite'),
|
|
||||||
('security_key',str(uuid.uuid4())),
|
|
||||||
('email_server','localhost'),
|
|
||||||
('email_sender','you@example.com'),
|
|
||||||
('email_login',''),
|
|
||||||
('login_method','local'),
|
|
||||||
('login_config',''),
|
|
||||||
('plugins',[])],
|
|
||||||
'tables':['auth_user'],
|
|
||||||
'table_auth_user':['username','first_name',
|
|
||||||
'last_name','email','password'],
|
|
||||||
'pages':['index','error'],
|
|
||||||
'page_index':'# Welcome to my new app',
|
|
||||||
'page_error':'# Error: the document does not exist',
|
|
||||||
}
|
|
||||||
|
|
||||||
if not session.app: reset(session)
|
def reset(session):
|
||||||
|
session.app = {
|
||||||
|
'name': '',
|
||||||
|
'params': [('title', 'My New App'),
|
||||||
|
('subtitle', 'powered by web2py'),
|
||||||
|
('author', 'you'),
|
||||||
|
('author_email', 'you@example.com'),
|
||||||
|
('keywords', ''),
|
||||||
|
('description', ''),
|
||||||
|
('layout_theme', 'Default'),
|
||||||
|
('database_uri', 'sqlite://storage.sqlite'),
|
||||||
|
('security_key', str(uuid.uuid4())),
|
||||||
|
('email_server', 'localhost'),
|
||||||
|
('email_sender', 'you@example.com'),
|
||||||
|
('email_login', ''),
|
||||||
|
('login_method', 'local'),
|
||||||
|
('login_config', ''),
|
||||||
|
('plugins', [])],
|
||||||
|
'tables': ['auth_user'],
|
||||||
|
'table_auth_user': ['username', 'first_name',
|
||||||
|
'last_name', 'email', 'password'],
|
||||||
|
'pages': ['index', 'error'],
|
||||||
|
'page_index': '# Welcome to my new app',
|
||||||
|
'page_error': '# Error: the document does not exist',
|
||||||
|
}
|
||||||
|
|
||||||
|
if not session.app:
|
||||||
|
reset(session)
|
||||||
|
|
||||||
|
|
||||||
def listify(x):
|
def listify(x):
|
||||||
if not isinstance(x,(list,tuple)):
|
if not isinstance(x, (list, tuple)):
|
||||||
return x and [x] or []
|
return x and [x] or []
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
def clean(name):
|
def clean(name):
|
||||||
return re.sub('\W+','_',name.strip().lower())
|
return re.sub('\W+', '_', name.strip().lower())
|
||||||
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
reset(session)
|
reset(session)
|
||||||
apps=os.listdir(os.path.join(request.folder,'..'))
|
apps = os.listdir(os.path.join(request.folder, '..'))
|
||||||
form=SQLFORM.factory(Field('name',requires=[IS_NOT_EMPTY(),
|
form = SQLFORM.factory(Field('name', requires=[IS_NOT_EMPTY(),
|
||||||
IS_ALPHANUMERIC()]))
|
IS_ALPHANUMERIC()]))
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
app = form.vars.name
|
app = form.vars.name
|
||||||
session.app['name'] = app
|
session.app['name'] = app
|
||||||
if MULTI_USER_MODE and db(db.app.name==app)\
|
if MULTI_USER_MODE and db(db.app.name == app)(db.app.owner != auth.user.id).count():
|
||||||
(db.app.owner!=auth.user.id).count():
|
|
||||||
session.flash = 'App belongs already to other user'
|
session.flash = 'App belongs already to other user'
|
||||||
elif app in apps:
|
elif app in apps:
|
||||||
meta = os.path.normpath(\
|
meta = os.path.normpath(
|
||||||
os.path.join(os.path.normpath(request.folder),
|
os.path.join(os.path.normpath(request.folder),
|
||||||
'..',app,'wizard.metadata'))
|
'..', app, 'wizard.metadata'))
|
||||||
if os.path.exists(meta):
|
if os.path.exists(meta):
|
||||||
try:
|
try:
|
||||||
metafile = open(meta,'rb')
|
metafile = open(meta, 'rb')
|
||||||
try:
|
try:
|
||||||
session.app = pickle.load(metafile)
|
session.app = pickle.load(metafile)
|
||||||
finally:
|
finally:
|
||||||
@@ -67,14 +76,14 @@ def index():
|
|||||||
except:
|
except:
|
||||||
session.flash = T("The app exists, was NOT created by wizard, continue to overwrite!")
|
session.flash = T("The app exists, was NOT created by wizard, continue to overwrite!")
|
||||||
redirect(URL('step1'))
|
redirect(URL('step1'))
|
||||||
return dict(step='Start',form=form)
|
return dict(step='Start', form=form)
|
||||||
|
|
||||||
|
|
||||||
def step1():
|
def step1():
|
||||||
from gluon.contrib.simplejson import loads
|
from gluon.contrib.simplejson import loads
|
||||||
import urllib
|
import urllib
|
||||||
if not session.themes:
|
if not session.themes:
|
||||||
url=LAYOUTS_APP+'/default/layouts.json'
|
url = LAYOUTS_APP + '/default/layouts.json'
|
||||||
try:
|
try:
|
||||||
data = urllib.urlopen(url).read()
|
data = urllib.urlopen(url).read()
|
||||||
session.themes = ['Default'] + loads(data)['layouts']
|
session.themes = ['Default'] + loads(data)['layouts']
|
||||||
@@ -82,145 +91,158 @@ def step1():
|
|||||||
session.themes = ['Default']
|
session.themes = ['Default']
|
||||||
themes = session.themes
|
themes = session.themes
|
||||||
if not session.plugins:
|
if not session.plugins:
|
||||||
url = PLUGINS_APP+'/default/plugins.json'
|
url = PLUGINS_APP + '/default/plugins.json'
|
||||||
try:
|
try:
|
||||||
data = urllib.urlopen(url).read()
|
data = urllib.urlopen(url).read()
|
||||||
session.plugins = loads(data)['plugins']
|
session.plugins = loads(data)['plugins']
|
||||||
except:
|
except:
|
||||||
session.plugins = []
|
session.plugins = []
|
||||||
plugins = [x.split('.')[2] for x in session.plugins]
|
plugins = [x.split('.')[2] for x in session.plugins]
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
params = dict(session.app['params'])
|
params = dict(session.app['params'])
|
||||||
form=SQLFORM.factory(
|
form = SQLFORM.factory(
|
||||||
Field('title',default=params.get('title',None),
|
Field('title', default=params.get('title', None),
|
||||||
requires=IS_NOT_EMPTY()),
|
requires=IS_NOT_EMPTY()),
|
||||||
Field('subtitle',default=params.get('subtitle',None)),
|
Field('subtitle', default=params.get('subtitle', None)),
|
||||||
Field('author',default=params.get('author',None)),
|
Field('author', default=params.get('author', None)),
|
||||||
Field('author_email',default=params.get('author_email',None)),
|
Field(
|
||||||
Field('keywords',default=params.get('keywords',None)),
|
'author_email', default=params.get('author_email', None)),
|
||||||
Field('description','text',
|
Field('keywords', default=params.get('keywords', None)),
|
||||||
default=params.get('description',None)),
|
Field('description', 'text',
|
||||||
Field('layout_theme',requires=IS_IN_SET(themes),
|
default=params.get('description', None)),
|
||||||
default=params.get('layout_theme',themes[0])),
|
Field('layout_theme', requires=IS_IN_SET(themes),
|
||||||
Field('database_uri',default=params.get('database_uri',None)),
|
default=params.get('layout_theme', themes[0])),
|
||||||
Field('security_key',default=params.get('security_key',None)),
|
Field(
|
||||||
Field('email_server',default=params.get('email_server',None)),
|
'database_uri', default=params.get('database_uri', None)),
|
||||||
Field('email_sender',default=params.get('email_sender',None)),
|
Field(
|
||||||
Field('email_login',default=params.get('email_login',None)),
|
'security_key', default=params.get('security_key', None)),
|
||||||
Field('login_method',requires=IS_IN_SET(('local','janrain')),
|
Field(
|
||||||
default=params.get('login_method','local')),
|
'email_server', default=params.get('email_server', None)),
|
||||||
Field('login_config',default=params.get('login_config',None)),
|
Field(
|
||||||
Field('plugins','list:string',requires=IS_IN_SET(plugins,multiple=True)))
|
'email_sender', default=params.get('email_sender', None)),
|
||||||
|
Field('email_login', default=params.get('email_login', None)),
|
||||||
|
Field('login_method', requires=IS_IN_SET(('local', 'janrain')),
|
||||||
|
default=params.get('login_method', 'local')),
|
||||||
|
Field(
|
||||||
|
'login_config', default=params.get('login_config', None)),
|
||||||
|
Field('plugins', 'list:string', requires=IS_IN_SET(plugins, multiple=True)))
|
||||||
|
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
session.app['params']=[(key,form.vars.get(key,None))
|
session.app['params'] = [(key, form.vars.get(key, None))
|
||||||
for key,value in session.app['params']]
|
for key, value in session.app['params']]
|
||||||
redirect(URL('step2'))
|
redirect(URL('step2'))
|
||||||
return dict(step='1: Setting Parameters',form=form)
|
return dict(step='1: Setting Parameters', form=form)
|
||||||
|
|
||||||
|
|
||||||
def step2():
|
def step2():
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
form=SQLFORM.factory(Field('table_names','list:string',
|
form = SQLFORM.factory(Field('table_names', 'list:string',
|
||||||
default=session.app['tables']))
|
default=session.app['tables']))
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
table_names = [clean(t) for t in listify(form.vars.table_names) \
|
table_names = [clean(t) for t in listify(form.vars.table_names)
|
||||||
if t.strip()]
|
if t.strip()]
|
||||||
if [t for t in table_names if t.startswith('auth_') and \
|
if [t for t in table_names if t.startswith('auth_') and
|
||||||
not t=='auth_user']:
|
not t == 'auth_user']:
|
||||||
form.error.table_names = \
|
form.error.table_names = \
|
||||||
T('invalid table names (auth_* tables already defined)')
|
T('invalid table names (auth_* tables already defined)')
|
||||||
else:
|
else:
|
||||||
session.app['tables']=table_names
|
session.app['tables'] = table_names
|
||||||
for table in session.app['tables']:
|
for table in session.app['tables']:
|
||||||
if not 'table_'+table in session.app:
|
if not 'table_' + table in session.app:
|
||||||
session.app['table_'+table]=['name']
|
session.app['table_' + table] = ['name']
|
||||||
if not table=='auth_user':
|
if not table == 'auth_user':
|
||||||
name = table+'_manage'
|
name = table + '_manage'
|
||||||
if not name in session.app['pages']:
|
if not name in session.app['pages']:
|
||||||
session.app['pages'].append(name)
|
session.app['pages'].append(name)
|
||||||
session.app['page_'+name] = \
|
session.app['page_' + name] = \
|
||||||
'## Manage %s\n\n{{=form}}' % (table)
|
'## Manage %s\n\n{{=form}}' % (table)
|
||||||
if session.app['tables']:
|
if session.app['tables']:
|
||||||
redirect(URL('step3',args=0))
|
redirect(URL('step3', args=0))
|
||||||
else:
|
else:
|
||||||
redirect(URL('step4'))
|
redirect(URL('step4'))
|
||||||
return dict(step='2: Tables',form=form)
|
return dict(step='2: Tables', form=form)
|
||||||
|
|
||||||
|
|
||||||
def step3():
|
def step3():
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
n=int(request.args(0) or 0)
|
n = int(request.args(0) or 0)
|
||||||
m=len(session.app['tables'])
|
m = len(session.app['tables'])
|
||||||
if n>=m: redirect(URL('step2'))
|
if n >= m:
|
||||||
table=session.app['tables'][n]
|
redirect(URL('step2'))
|
||||||
form=SQLFORM.factory(Field('field_names','list:string',
|
table = session.app['tables'][n]
|
||||||
default=session.app.get('table_'+table,[])))
|
form = SQLFORM.factory(Field('field_names', 'list:string',
|
||||||
|
default=session.app.get('table_' + table, [])))
|
||||||
if form.accepts(request.vars) and form.vars.field_names:
|
if form.accepts(request.vars) and form.vars.field_names:
|
||||||
fields=listify(form.vars.field_names)
|
fields = listify(form.vars.field_names)
|
||||||
if table=='auth_user':
|
if table == 'auth_user':
|
||||||
for field in ['first_name','last_name','username','email','password']:
|
for field in ['first_name', 'last_name', 'username', 'email', 'password']:
|
||||||
if not field in fields:
|
if not field in fields:
|
||||||
fields.append(field)
|
fields.append(field)
|
||||||
session.app['table_'+table]=[t.strip().lower()
|
session.app['table_' + table] = [t.strip().lower()
|
||||||
for t in listify(form.vars.field_names)
|
for t in listify(form.vars.field_names)
|
||||||
if t.strip()]
|
if t.strip()]
|
||||||
try:
|
try:
|
||||||
tables=sort_tables(session.app['tables'])
|
tables = sort_tables(session.app['tables'])
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
response.flash=T('invalid circular reference')
|
response.flash = T('invalid circular reference')
|
||||||
else:
|
else:
|
||||||
if n<m-1:
|
if n < m - 1:
|
||||||
redirect(URL('step3',args=n+1))
|
redirect(URL('step3', args=n + 1))
|
||||||
else:
|
else:
|
||||||
redirect(URL('step4'))
|
redirect(URL('step4'))
|
||||||
return dict(step='3: Fields for table "%s" (%s of %s)' \
|
return dict(step='3: Fields for table "%s" (%s of %s)'
|
||||||
% (table,n+1,m),table=table,form=form)
|
% (table, n + 1, m), table=table, form=form)
|
||||||
|
|
||||||
|
|
||||||
def step4():
|
def step4():
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
form=SQLFORM.factory(Field('pages','list:string',
|
form = SQLFORM.factory(Field('pages', 'list:string',
|
||||||
default=session.app['pages']))
|
default=session.app['pages']))
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
session.app['pages']=[clean(t)
|
session.app['pages'] = [clean(t)
|
||||||
for t in listify(form.vars.pages)
|
for t in listify(form.vars.pages)
|
||||||
if t.strip()]
|
if t.strip()]
|
||||||
if session.app['pages']:
|
if session.app['pages']:
|
||||||
redirect(URL('step5',args=0))
|
redirect(URL('step5', args=0))
|
||||||
else:
|
else:
|
||||||
redirect(URL('step6'))
|
redirect(URL('step6'))
|
||||||
return dict(step='4: Pages',form=form)
|
return dict(step='4: Pages', form=form)
|
||||||
|
|
||||||
|
|
||||||
def step5():
|
def step5():
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
n=int(request.args(0) or 0)
|
n = int(request.args(0) or 0)
|
||||||
m=len(session.app['pages'])
|
m = len(session.app['pages'])
|
||||||
if n>=m: redirect(URL('step4'))
|
if n >= m:
|
||||||
page=session.app['pages'][n]
|
redirect(URL('step4'))
|
||||||
markmin_url='http://web2py.com/examples/static/markmin.html'
|
page = session.app['pages'][n]
|
||||||
form=SQLFORM.factory(Field('content','text',
|
markmin_url = 'http://web2py.com/examples/static/markmin.html'
|
||||||
default=session.app.get('page_'+page,[]),
|
form = SQLFORM.factory(Field('content', 'text',
|
||||||
comment=A('use markmin',
|
default=session.app.get('page_' + page, []),
|
||||||
_href=markmin_url,_target='_blank')),
|
comment=A('use markmin',
|
||||||
formstyle='table2cols')
|
_href=markmin_url, _target='_blank')),
|
||||||
|
formstyle='table2cols')
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
session.app['page_'+page]=form.vars.content
|
session.app['page_' + page] = form.vars.content
|
||||||
if n<m-1:
|
if n < m - 1:
|
||||||
redirect(URL('step5',args=n+1))
|
redirect(URL('step5', args=n + 1))
|
||||||
else:
|
else:
|
||||||
redirect(URL('step6'))
|
redirect(URL('step6'))
|
||||||
return dict(step='5: View for page "%s" (%s of %s)' % (page,n+1,m),form=form)
|
return dict(step='5: View for page "%s" (%s of %s)' % (page, n + 1, m), form=form)
|
||||||
|
|
||||||
|
|
||||||
def step6():
|
def step6():
|
||||||
response.view='wizard/step.html'
|
response.view = 'wizard/step.html'
|
||||||
params = dict(session.app['params'])
|
params = dict(session.app['params'])
|
||||||
app = session.app['name']
|
app = session.app['name']
|
||||||
form=SQLFORM.factory(
|
form = SQLFORM.factory(
|
||||||
Field('generate_model','boolean',default=True),
|
Field('generate_model', 'boolean', default=True),
|
||||||
Field('generate_controller','boolean',default=True),
|
Field('generate_controller', 'boolean', default=True),
|
||||||
Field('generate_views','boolean',default=True),
|
Field('generate_views', 'boolean', default=True),
|
||||||
Field('generate_menu','boolean',default=True),
|
Field('generate_menu', 'boolean', default=True),
|
||||||
Field('apply_layout','boolean',default=True),
|
Field('apply_layout', 'boolean', default=True),
|
||||||
Field('erase_database','boolean',default=True),
|
Field('erase_database', 'boolean', default=True),
|
||||||
Field('populate_database','boolean',default=True))
|
Field('populate_database', 'boolean', default=True))
|
||||||
if form.accepts(request.vars):
|
if form.accepts(request.vars):
|
||||||
if DEMO_MODE:
|
if DEMO_MODE:
|
||||||
session.flash = T('Application cannot be generated in demo mode')
|
session.flash = T('Application cannot be generated in demo mode')
|
||||||
@@ -228,159 +250,173 @@ def step6():
|
|||||||
create(form.vars)
|
create(form.vars)
|
||||||
session.flash = 'Application %s created' % app
|
session.flash = 'Application %s created' % app
|
||||||
redirect(URL('generated'))
|
redirect(URL('generated'))
|
||||||
return dict(step='6: Generate app "%s"' % app,form=form)
|
return dict(step='6: Generate app "%s"' % app, form=form)
|
||||||
|
|
||||||
|
|
||||||
def generated():
|
def generated():
|
||||||
return dict(app=session.app['name'])
|
return dict(app=session.app['name'])
|
||||||
|
|
||||||
|
|
||||||
def sort_tables(tables):
|
def sort_tables(tables):
|
||||||
import re
|
import re
|
||||||
regex = re.compile('(%s)' % '|'.join(tables))
|
regex = re.compile('(%s)' % '|'.join(tables))
|
||||||
is_auth_user = 'auth_user' in tables
|
is_auth_user = 'auth_user' in tables
|
||||||
d={}
|
d = {}
|
||||||
for table in tables:
|
for table in tables:
|
||||||
d[table]=[]
|
d[table] = []
|
||||||
for field in session.app['table_%s' % table]:
|
for field in session.app['table_%s' % table]:
|
||||||
d[table]+=regex.findall(field)
|
d[table] += regex.findall(field)
|
||||||
tables=[]
|
tables = []
|
||||||
if is_auth_user:
|
if is_auth_user:
|
||||||
tables.append('auth_user')
|
tables.append('auth_user')
|
||||||
def append(table,trail=[]):
|
|
||||||
|
def append(table, trail=[]):
|
||||||
if table in trail:
|
if table in trail:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
for t in d[table]:
|
for t in d[table]:
|
||||||
# if not t==table: (problem, no dropdown for self references)
|
# if not t==table: (problem, no dropdown for self references)
|
||||||
append(t,trail=trail+[table])
|
append(t, trail=trail + [table])
|
||||||
if not table in tables:
|
if not table in tables:
|
||||||
tables.append(table)
|
tables.append(table)
|
||||||
for table in d: append(table)
|
for table in d:
|
||||||
|
append(table)
|
||||||
return tables
|
return tables
|
||||||
|
|
||||||
def make_table(table,fields):
|
|
||||||
rawtable=table
|
def make_table(table, fields):
|
||||||
if table!='auth_user': table='t_'+table
|
rawtable = table
|
||||||
s=''
|
if table != 'auth_user':
|
||||||
s+='\n'+'#'*40+'\n'
|
table = 't_' + table
|
||||||
s+="db.define_table('%s',\n" % table
|
s = ''
|
||||||
first_field='id'
|
s += '\n' + '#' * 40 + '\n'
|
||||||
|
s += "db.define_table('%s',\n" % table
|
||||||
|
first_field = 'id'
|
||||||
for field in fields:
|
for field in fields:
|
||||||
items=[x.lower() for x in field.split()]
|
items = [x.lower() for x in field.split()]
|
||||||
has = {}
|
has = {}
|
||||||
keys = []
|
keys = []
|
||||||
for key in ['notnull','unique','integer','double','boolean','float',
|
for key in ['notnull', 'unique', 'integer', 'double', 'boolean', 'float',
|
||||||
'boolean', 'date','time','datetime','text','wiki',
|
'boolean', 'date', 'time', 'datetime', 'text', 'wiki',
|
||||||
'html','file','upload','image','true',
|
'html', 'file', 'upload', 'image', 'true',
|
||||||
'hidden','readonly','writeonly','multiple',
|
'hidden', 'readonly', 'writeonly', 'multiple',
|
||||||
'notempty','required']:
|
'notempty', 'required']:
|
||||||
if key in items[1:]:
|
if key in items[1:]:
|
||||||
keys.append(key)
|
keys.append(key)
|
||||||
has[key] = True
|
has[key] = True
|
||||||
tables = session.app['tables']
|
tables = session.app['tables']
|
||||||
refs = [t for t in tables if t in items]
|
refs = [t for t in tables if t in items]
|
||||||
items = items[:1] + [x for x in items[1:] \
|
items = items[:1] + [x for x in items[1:]
|
||||||
if not x in keys and not x in tables]
|
if not x in keys and not x in tables]
|
||||||
barename = name = '_'.join(items)
|
barename = name = '_'.join(items)
|
||||||
if table[:2]=='t_': name='f_'+name
|
if table[:2] == 't_': name = 'f_' + name
|
||||||
if first_field=='id': first_field=name
|
if first_field == 'id':
|
||||||
|
first_field = name
|
||||||
|
|
||||||
### determine field type
|
### determine field type
|
||||||
ftype='string'
|
ftype = 'string'
|
||||||
deftypes={'integer':'integer','double':'double','boolean':'boolean',
|
deftypes = {'integer': 'integer', 'double': 'double', 'boolean': 'boolean',
|
||||||
'float':'double','bool':'boolean',
|
'float': 'double', 'bool': 'boolean',
|
||||||
'date':'date','time':'time','datetime':'datetime',
|
'date': 'date', 'time': 'time', 'datetime': 'datetime',
|
||||||
'text':'text','file':'upload','image':'upload',
|
'text': 'text', 'file': 'upload', 'image': 'upload',
|
||||||
'upload':'upload','wiki':'text', 'html':'text'}
|
'upload': 'upload', 'wiki': 'text', 'html': 'text'}
|
||||||
for key,t in deftypes.items():
|
for key, t in deftypes.items():
|
||||||
if key in has:
|
if key in has:
|
||||||
ftype = t
|
ftype = t
|
||||||
if refs:
|
if refs:
|
||||||
key = refs[0]
|
key = refs[0]
|
||||||
if not key=='auth_user': key='t_'+key
|
if not key == 'auth_user':
|
||||||
|
key = 't_' + key
|
||||||
if 'multiple' in has:
|
if 'multiple' in has:
|
||||||
ftype='list:reference %s' % key
|
ftype = 'list:reference %s' % key
|
||||||
else:
|
else:
|
||||||
ftype='reference %s' % key
|
ftype = 'reference %s' % key
|
||||||
if ftype=='string' and 'multiple' in has:
|
if ftype == 'string' and 'multiple' in has:
|
||||||
ftype='list:string'
|
ftype = 'list:string'
|
||||||
elif ftype=='integer' and 'multiple' in has:
|
elif ftype == 'integer' and 'multiple' in has:
|
||||||
ftype='list:integer'
|
ftype = 'list:integer'
|
||||||
elif name=='password':
|
elif name == 'password':
|
||||||
ftype='password'
|
ftype = 'password'
|
||||||
s+=" Field('%s', type='%s'" % (name, ftype)
|
s += " Field('%s', type='%s'" % (name, ftype)
|
||||||
|
|
||||||
### determine field attributes
|
### determine field attributes
|
||||||
if 'notnull' in has or 'notempty' in has or 'required' in has:
|
if 'notnull' in has or 'notempty' in has or 'required' in has:
|
||||||
s+=', notnull=True'
|
s += ', notnull=True'
|
||||||
if 'unique' in has:
|
if 'unique' in has:
|
||||||
s+=', unique=True'
|
s += ', unique=True'
|
||||||
if ftype=='boolean' and 'true' in has:
|
if ftype == 'boolean' and 'true' in has:
|
||||||
s+=",\n default=True"
|
s += ",\n default=True"
|
||||||
|
|
||||||
### determine field representation
|
### determine field representation
|
||||||
elif 'wiki' in has:
|
elif 'wiki' in has:
|
||||||
s+=",\n represent=lambda x, row: MARKMIN(x)"
|
s += ",\n represent=lambda x, row: MARKMIN(x)"
|
||||||
s+=",\n comment='WIKI (markmin)'"
|
s += ",\n comment='WIKI (markmin)'"
|
||||||
elif 'html' in has:
|
elif 'html' in has:
|
||||||
s+=",\n represent=lambda x, row: XML(x,sanitize=True)"
|
s += ",\n represent=lambda x, row: XML(x,sanitize=True)"
|
||||||
s+=",\n comment='HTML (sanitized)'"
|
s += ",\n comment='HTML (sanitized)'"
|
||||||
### determine field access
|
### determine field access
|
||||||
if name=='password' or 'writeonly' in has:
|
if name == 'password' or 'writeonly' in has:
|
||||||
s+=",\n readable=False"
|
s += ",\n readable=False"
|
||||||
elif 'hidden' in has:
|
elif 'hidden' in has:
|
||||||
s+=",\n writable=False, readable=False"
|
s += ",\n writable=False, readable=False"
|
||||||
elif 'readonly' in has:
|
elif 'readonly' in has:
|
||||||
s+=",\n writable=False"
|
s += ",\n writable=False"
|
||||||
|
|
||||||
### make up a label
|
### make up a label
|
||||||
s+=",\n label=T('%s')),\n" % \
|
s += ",\n label=T('%s')),\n" % \
|
||||||
' '.join(x.capitalize() for x in barename.split('_'))
|
' '.join(x.capitalize() for x in barename.split('_'))
|
||||||
if table=='auth_user':
|
if table == 'auth_user':
|
||||||
s+=" Field('created_on','datetime',default=request.now,\n"
|
s += " Field('created_on','datetime',default=request.now,\n"
|
||||||
s+=" label=T('Created On'),writable=False,readable=False),\n"
|
s += " label=T('Created On'),writable=False,readable=False),\n"
|
||||||
s+=" Field('modified_on','datetime',default=request.now,\n"
|
s += " Field('modified_on','datetime',default=request.now,\n"
|
||||||
s+=" label=T('Modified On'),writable=False,readable=False,\n"
|
s += " label=T('Modified On'),writable=False,readable=False,\n"
|
||||||
s+=" update=request.now),\n"
|
s += " update=request.now),\n"
|
||||||
s+=" Field('registration_key',default='',\n"
|
s += " Field('registration_key',default='',\n"
|
||||||
s+=" writable=False,readable=False),\n"
|
s += " writable=False,readable=False),\n"
|
||||||
s+=" Field('reset_password_key',default='',\n"
|
s += " Field('reset_password_key',default='',\n"
|
||||||
s+=" writable=False,readable=False),\n"
|
s += " writable=False,readable=False),\n"
|
||||||
s+=" Field('registration_id',default='',\n"
|
s += " Field('registration_id',default='',\n"
|
||||||
s+=" writable=False,readable=False),\n"
|
s += " writable=False,readable=False),\n"
|
||||||
elif 'auth_user' in session.app['tables']:
|
elif 'auth_user' in session.app['tables']:
|
||||||
s+=" auth.signature,\n"
|
s += " auth.signature,\n"
|
||||||
s+=" format='%("+first_field+")s',\n"
|
s += " format='%(" + first_field + ")s',\n"
|
||||||
s+=" migrate=settings.migrate)\n\n"
|
s += " migrate=settings.migrate)\n\n"
|
||||||
if table=='auth_user':
|
if table == 'auth_user':
|
||||||
s+="""
|
s += """
|
||||||
db.auth_user.first_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
db.auth_user.first_name.requires = IS_NOT_EMPTY(
|
||||||
db.auth_user.last_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
error_message=auth.messages.is_empty)
|
||||||
db.auth_user.password.requires = CRYPT(key=auth.settings.hmac_key, min_length=4)
|
db.auth_user.last_name.requires = IS_NOT_EMPTY(
|
||||||
|
error_message=auth.messages.is_empty)
|
||||||
|
db.auth_user.password.requires = CRYPT(
|
||||||
|
key=auth.settings.hmac_key, min_length=4)
|
||||||
db.auth_user.username.requires = IS_NOT_IN_DB(db, db.auth_user.username)
|
db.auth_user.username.requires = IS_NOT_IN_DB(db, db.auth_user.username)
|
||||||
db.auth_user.email.requires = (IS_EMAIL(error_message=auth.messages.invalid_email),
|
db.auth_user.email.requires = (
|
||||||
|
IS_EMAIL(error_message=auth.messages.invalid_email),
|
||||||
IS_NOT_IN_DB(db, db.auth_user.email))
|
IS_NOT_IN_DB(db, db.auth_user.email))
|
||||||
"""
|
"""
|
||||||
else:
|
else:
|
||||||
s+="db.define_table('%s_archive',db.%s,Field('current_record','reference %s',readable=False,writable=False))\n" % (table,table,table)
|
s += "db.define_table('%s_archive',db.%s,Field('current_record','reference %s',readable=False,writable=False))\n" % (table, table, table)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def fix_db(filename):
|
def fix_db(filename):
|
||||||
params = dict(session.app['params'])
|
params = dict(session.app['params'])
|
||||||
content = read_file(filename,'rb')
|
content = read_file(filename, 'rb')
|
||||||
if 'auth_user' in session.app['tables']:
|
if 'auth_user' in session.app['tables']:
|
||||||
auth_user = make_table('auth_user',session.app['table_auth_user'])
|
auth_user = make_table('auth_user', session.app['table_auth_user'])
|
||||||
content = content.replace('sqlite://storage.sqlite',
|
content = content.replace('sqlite://storage.sqlite',
|
||||||
params['database_uri'])
|
params['database_uri'])
|
||||||
content = content.replace('auth.define_tables()',\
|
content = content.replace('auth.define_tables()',
|
||||||
auth_user+'auth.define_tables(migrate = settings.migrate)')
|
auth_user + 'auth.define_tables(migrate = settings.migrate)')
|
||||||
content += """
|
content += """
|
||||||
mail.settings.server = settings.email_server
|
mail.settings.server = settings.email_server
|
||||||
mail.settings.sender = settings.email_sender
|
mail.settings.sender = settings.email_sender
|
||||||
mail.settings.login = settings.email_login
|
mail.settings.login = settings.email_login
|
||||||
"""
|
"""
|
||||||
if params['login_method']=='janrain':
|
if params['login_method'] == 'janrain':
|
||||||
content+="""
|
content += """
|
||||||
from gluon.contrib.login_methods.rpx_account import RPXAccount
|
from gluon.contrib.login_methods.rpx_account import RPXAccount
|
||||||
auth.settings.actions_disabled=['register','change_password','request_reset_password']
|
auth.settings.actions_disabled=['register','change_password',
|
||||||
|
'request_reset_password']
|
||||||
auth.settings.login_form = RPXAccount(request,
|
auth.settings.login_form = RPXAccount(request,
|
||||||
api_key = settings.login_config.split(':')[-1],
|
api_key = settings.login_config.split(':')[-1],
|
||||||
domain = settings.login_config.split(':')[0],
|
domain = settings.login_config.split(':')[0],
|
||||||
@@ -388,14 +424,15 @@ auth.settings.login_form = RPXAccount(request,
|
|||||||
"""
|
"""
|
||||||
write_file(filename, content, 'wb')
|
write_file(filename, content, 'wb')
|
||||||
|
|
||||||
|
|
||||||
def make_menu(pages):
|
def make_menu(pages):
|
||||||
s=''
|
s = ''
|
||||||
s+='response.title = settings.title\n'
|
s += 'response.title = settings.title\n'
|
||||||
s+='response.subtitle = settings.subtitle\n'
|
s += 'response.subtitle = settings.subtitle\n'
|
||||||
s+="response.meta.author = '%(author)s <%(author_email)s>' % settings\n"
|
s += "response.meta.author = '%(author)s <%(author_email)s>' % settings\n"
|
||||||
s+='response.meta.keywords = settings.keywords\n'
|
s += 'response.meta.keywords = settings.keywords\n'
|
||||||
s+='response.meta.description = settings.description\n'
|
s += 'response.meta.description = settings.description\n'
|
||||||
s+='response.menu = [\n'
|
s += 'response.menu = [\n'
|
||||||
for page in pages:
|
for page in pages:
|
||||||
if not page.startswith('error'):
|
if not page.startswith('error'):
|
||||||
if page.endswith('_manage'):
|
if page.endswith('_manage'):
|
||||||
@@ -403,65 +440,70 @@ def make_menu(pages):
|
|||||||
else:
|
else:
|
||||||
page_name = page
|
page_name = page
|
||||||
page_name = ' '.join(x.capitalize() for x in page_name.split('_'))
|
page_name = ' '.join(x.capitalize() for x in page_name.split('_'))
|
||||||
s+="(T('%s'),URL('default','%s')==URL(),URL('default','%s'),[]),\n" \
|
s += "(T('%s'),URL('default','%s')==URL(),URL('default','%s'),[]),\n" \
|
||||||
% (page_name,page,page)
|
% (page_name, page, page)
|
||||||
s+=']'
|
s += ']'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def make_page(page,contents):
|
|
||||||
if 'auth_user' in session.app['tables'] and not page in ('index','error'):
|
def make_page(page, contents):
|
||||||
s="@auth.requires_login()\ndef %s():\n" % page
|
if 'auth_user' in session.app['tables'] and not page in ('index', 'error'):
|
||||||
|
s = "@auth.requires_login()\ndef %s():\n" % page
|
||||||
else:
|
else:
|
||||||
s="def %s():\n" % page
|
s = "def %s():\n" % page
|
||||||
items = page.rsplit('_',1)
|
items = page.rsplit('_', 1)
|
||||||
if items[0] in session.app['tables'] and len(items)==2 and items[1]=='manage':
|
if items[0] in session.app['tables'] and len(items) == 2 and items[1] == 'manage':
|
||||||
s+=" form = SQLFORM.smartgrid(db.t_%s,onupdate=auth.archive)\n" % items[0]
|
s += " form = SQLFORM.smartgrid(db.t_%s,onupdate=auth.archive)\n" % items[0]
|
||||||
s+=" return locals()\n\n"
|
s += " return locals()\n\n"
|
||||||
else:
|
else:
|
||||||
s+=" return dict()\n\n"
|
s += " return dict()\n\n"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def make_view(page,contents):
|
|
||||||
s="{{extend 'layout.html'}}\n\n"
|
def make_view(page, contents):
|
||||||
s+=str(MARKMIN(contents))
|
s = "{{extend 'layout.html'}}\n\n"
|
||||||
|
s += str(MARKMIN(contents))
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def populate(tables):
|
def populate(tables):
|
||||||
s = 'from gluon.contrib.populate import populate\n'
|
s = 'from gluon.contrib.populate import populate\n'
|
||||||
s+= 'if db(db.auth_user).isempty():\n'
|
s += 'if db(db.auth_user).isempty():\n'
|
||||||
for table in sort_tables(tables):
|
for table in sort_tables(tables):
|
||||||
t=table=='auth_user' and 'auth_user' or 't_'+table
|
t = table == 'auth_user' and 'auth_user' or 't_' + table
|
||||||
s+=" populate(db.%s,10)\n" % t
|
s += " populate(db.%s,10)\n" % t
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def create(options):
|
def create(options):
|
||||||
if DEMO_MODE:
|
if DEMO_MODE:
|
||||||
session.flash = T('disabled in demo mode')
|
session.flash = T('disabled in demo mode')
|
||||||
redirect(URL('step6'))
|
redirect(URL('step6'))
|
||||||
params = dict(session.app['params'])
|
params = dict(session.app['params'])
|
||||||
app = session.app['name']
|
app = session.app['name']
|
||||||
if app_create(app,request,force=True,key=params['security_key']):
|
if app_create(app, request, force=True, key=params['security_key']):
|
||||||
if MULTI_USER_MODE:
|
if MULTI_USER_MODE:
|
||||||
db.app.insert(name=app,owner=auth.user.id)
|
db.app.insert(name=app, owner=auth.user.id)
|
||||||
else:
|
else:
|
||||||
session.flash = 'Failure to create application'
|
session.flash = 'Failure to create application'
|
||||||
redirect(URL('step6'))
|
redirect(URL('step6'))
|
||||||
|
|
||||||
### save metadata in newapp/wizard.metadata
|
### save metadata in newapp/wizard.metadata
|
||||||
try:
|
try:
|
||||||
meta = os.path.join(request.folder,'..',app,'wizard.metadata')
|
meta = os.path.join(request.folder, '..', app, 'wizard.metadata')
|
||||||
file=open(meta,'wb')
|
file = open(meta, 'wb')
|
||||||
pickle.dump(session.app,file)
|
pickle.dump(session.app, file)
|
||||||
file.close()
|
file.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
session.flash = 'Failure to write wizard metadata'
|
session.flash = 'Failure to write wizard metadata'
|
||||||
redirect(URL('step6'))
|
redirect(URL('step6'))
|
||||||
|
|
||||||
### apply theme
|
### apply theme
|
||||||
if options.apply_layout and params['layout_theme']!='Default':
|
if options.apply_layout and params['layout_theme'] != 'Default':
|
||||||
try:
|
try:
|
||||||
fn = 'web2py.plugin.layout_%s.w2p' % params['layout_theme']
|
fn = 'web2py.plugin.layout_%s.w2p' % params['layout_theme']
|
||||||
theme = urllib.urlopen(LAYOUTS_APP+'/static/plugin_layouts/plugins/'+fn)
|
theme = urllib.urlopen(
|
||||||
|
LAYOUTS_APP + '/static/plugin_layouts/plugins/' + fn)
|
||||||
plugin_install(app, theme, request, fn)
|
plugin_install(app, theme, request, fn)
|
||||||
except:
|
except:
|
||||||
session.flash = T("unable to download layout")
|
session.flash = T("unable to download layout")
|
||||||
@@ -469,55 +511,58 @@ def create(options):
|
|||||||
### apply plugins
|
### apply plugins
|
||||||
for plugin in params['plugins']:
|
for plugin in params['plugins']:
|
||||||
try:
|
try:
|
||||||
plugin_name = 'web2py.plugin.'+plugin+'.w2p'
|
plugin_name = 'web2py.plugin.' + plugin + '.w2p'
|
||||||
stream = urllib.urlopen(PLUGINS_APP+'/static/'+plugin_name)
|
stream = urllib.urlopen(PLUGINS_APP + '/static/' + plugin_name)
|
||||||
plugin_install(app, stream, request, plugin_name)
|
plugin_install(app, stream, request, plugin_name)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
session.flash = T("unable to download plugin: %s" % plugin)
|
session.flash = T("unable to download plugin: %s" % plugin)
|
||||||
|
|
||||||
### write configuration file into newapp/models/0.py
|
### write configuration file into newapp/models/0.py
|
||||||
model = os.path.join(request.folder,'..',app,'models','0.py')
|
model = os.path.join(request.folder, '..', app, 'models', '0.py')
|
||||||
file = open(model, 'wb')
|
file = open(model, 'wb')
|
||||||
try:
|
try:
|
||||||
file.write("from gluon.storage import Storage\n")
|
file.write("from gluon.storage import Storage\n")
|
||||||
file.write("settings = Storage()\n\n")
|
file.write("settings = Storage()\n\n")
|
||||||
file.write("settings.migrate = True\n")
|
file.write("settings.migrate = True\n")
|
||||||
for key,value in session.app['params']:
|
for key, value in session.app['params']:
|
||||||
file.write("settings.%s = %s\n" % (key,repr(value)))
|
file.write("settings.%s = %s\n" % (key, repr(value)))
|
||||||
finally:
|
finally:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
### write configuration file into newapp/models/menu.py
|
### write configuration file into newapp/models/menu.py
|
||||||
if options.generate_menu:
|
if options.generate_menu:
|
||||||
model = os.path.join(request.folder,'..',app,'models','menu.py')
|
model = os.path.join(request.folder, '..', app, 'models', 'menu.py')
|
||||||
file = open(model,'wb')
|
file = open(model, 'wb')
|
||||||
try:
|
try:
|
||||||
file.write(make_menu(session.app['pages']))
|
file.write(make_menu(session.app['pages']))
|
||||||
finally:
|
finally:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
### customize the auth_user table
|
### customize the auth_user table
|
||||||
model = os.path.join(request.folder,'..',app,'models','db.py')
|
model = os.path.join(request.folder, '..', app, 'models', 'db.py')
|
||||||
fix_db(model)
|
fix_db(model)
|
||||||
|
|
||||||
### create newapp/models/db_wizard.py
|
### create newapp/models/db_wizard.py
|
||||||
if options.generate_model:
|
if options.generate_model:
|
||||||
model = os.path.join(request.folder,'..',app,'models','db_wizard.py')
|
model = os.path.join(
|
||||||
file = open(model,'wb')
|
request.folder, '..', app, 'models', 'db_wizard.py')
|
||||||
|
file = open(model, 'wb')
|
||||||
try:
|
try:
|
||||||
file.write('### we prepend t_ to tablenames and f_ to fieldnames for disambiguity\n\n')
|
file.write('### we prepend t_ to tablenames and f_ to fieldnames for disambiguity\n\n')
|
||||||
tables = sort_tables(session.app['tables'])
|
tables = sort_tables(session.app['tables'])
|
||||||
for table in tables:
|
for table in tables:
|
||||||
if table=='auth_user': continue
|
if table == 'auth_user':
|
||||||
file.write(make_table(table,session.app['table_'+table]))
|
continue
|
||||||
|
file.write(make_table(table, session.app['table_' + table]))
|
||||||
finally:
|
finally:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
model = os.path.join(request.folder,'..',app,
|
model = os.path.join(request.folder, '..', app,
|
||||||
'models','db_wizard_populate.py')
|
'models', 'db_wizard_populate.py')
|
||||||
if os.path.exists(model): os.unlink(model)
|
if os.path.exists(model):
|
||||||
|
os.unlink(model)
|
||||||
if options.populate_database and session.app['tables']:
|
if options.populate_database and session.app['tables']:
|
||||||
file = open(model,'wb')
|
file = open(model, 'wb')
|
||||||
try:
|
try:
|
||||||
file.write(populate(session.app['tables']))
|
file.write(populate(session.app['tables']))
|
||||||
finally:
|
finally:
|
||||||
@@ -525,8 +570,9 @@ def create(options):
|
|||||||
|
|
||||||
### create newapp/controllers/default.py
|
### create newapp/controllers/default.py
|
||||||
if options.generate_controller:
|
if options.generate_controller:
|
||||||
controller = os.path.join(request.folder,'..',app,'controllers','default.py')
|
controller = os.path.join(
|
||||||
file = open(controller,'wb')
|
request.folder, '..', app, 'controllers', 'default.py')
|
||||||
|
file = open(controller, 'wb')
|
||||||
try:
|
try:
|
||||||
file.write("""# -*- coding: utf-8 -*-
|
file.write("""# -*- coding: utf-8 -*-
|
||||||
### required - do no delete
|
### required - do no delete
|
||||||
@@ -536,23 +582,24 @@ def call(): return service()
|
|||||||
### end requires
|
### end requires
|
||||||
""")
|
""")
|
||||||
for page in session.app['pages']:
|
for page in session.app['pages']:
|
||||||
file.write(make_page(page,session.app.get('page_'+page,'')))
|
file.write(
|
||||||
|
make_page(page, session.app.get('page_' + page, '')))
|
||||||
finally:
|
finally:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
### create newapp/views/default/*.html
|
### create newapp/views/default/*.html
|
||||||
if options.generate_views:
|
if options.generate_views:
|
||||||
for page in session.app['pages']:
|
for page in session.app['pages']:
|
||||||
view = os.path.join(request.folder,'..',app,'views','default',page+'.html')
|
view = os.path.join(
|
||||||
file = open(view,'wb')
|
request.folder, '..', app, 'views', 'default', page + '.html')
|
||||||
|
file = open(view, 'wb')
|
||||||
try:
|
try:
|
||||||
file.write(make_view(page,session.app.get('page_'+page,'')))
|
file.write(
|
||||||
|
make_view(page, session.app.get('page_' + page, '')))
|
||||||
finally:
|
finally:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
if options.erase_database:
|
if options.erase_database:
|
||||||
path = os.path.join(request.folder,'..',app,'databases','*')
|
path = os.path.join(request.folder, '..', app, 'databases', '*')
|
||||||
for file in glob.glob(path):
|
for file in glob.glob(path):
|
||||||
os.unlink(file)
|
os.unlink(file)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,5 +19,3 @@ for filename in os.listdir(path):
|
|||||||
os.unlink(fullpath)
|
os.unlink(fullpath)
|
||||||
except:
|
except:
|
||||||
logging.exception('failure to check %s'%fullpath)
|
logging.exception('failure to check %s'%fullpath)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,12 @@
|
|||||||
'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані',
|
'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані',
|
||||||
'appadmin': 'Aдм.панель',
|
'appadmin': 'Aдм.панель',
|
||||||
'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку",
|
'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку",
|
||||||
|
'Application': 'Додаток (Application)',
|
||||||
'application "%s" uninstalled': 'додаток "%s" вилучено',
|
'application "%s" uninstalled': 'додаток "%s" вилучено',
|
||||||
'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s',
|
'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s',
|
||||||
'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна',
|
'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна',
|
||||||
'application compiled': 'додаток скомпільовано',
|
'application compiled': 'додаток скомпільовано',
|
||||||
|
'Application exists already': 'Додаток вже існує',
|
||||||
'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна',
|
'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна',
|
||||||
'Application name:': 'Назва додатку:',
|
'Application name:': 'Назва додатку:',
|
||||||
'are not used': 'не використовуються',
|
'are not used': 'не використовуються',
|
||||||
@@ -160,6 +162,7 @@
|
|||||||
'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)',
|
'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)',
|
||||||
'Error ticket': 'Позначка (ticket) про помилку',
|
'Error ticket': 'Позначка (ticket) про помилку',
|
||||||
'Errors': 'Помилки',
|
'Errors': 'Помилки',
|
||||||
|
'Errors in form, please check it out.': 'Помилка у формі, будь-ласка перевірте її.',
|
||||||
'Exception %(extype)s: %(exvalue)s': 'Виключення %(extype)s: %(exvalue)s',
|
'Exception %(extype)s: %(exvalue)s': 'Виключення %(extype)s: %(exvalue)s',
|
||||||
'Exception %s': 'Виключення %s',
|
'Exception %s': 'Виключення %s',
|
||||||
'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)',
|
'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)',
|
||||||
@@ -388,6 +391,7 @@
|
|||||||
'There are no models': 'Моделей, наразі, нема',
|
'There are no models': 'Моделей, наразі, нема',
|
||||||
'There are no modules': 'Модулів поки що нема',
|
'There are no modules': 'Модулів поки що нема',
|
||||||
'There are no plugins': 'Жодної втулки, наразі, не встановлено',
|
'There are no plugins': 'Жодної втулки, наразі, не встановлено',
|
||||||
|
'There are no private files': 'Приватних файлів поки що нема',
|
||||||
'There are no static files': 'Статичних файлів, наразі, нема',
|
'There are no static files': 'Статичних файлів, наразі, нема',
|
||||||
'There are no translators': 'Перекладів нема',
|
'There are no translators': 'Перекладів нема',
|
||||||
'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу',
|
'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу',
|
||||||
@@ -418,6 +422,7 @@
|
|||||||
'Traceback': 'Стек викликів (Traceback)',
|
'Traceback': 'Стек викликів (Traceback)',
|
||||||
'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови',
|
'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови',
|
||||||
'try something like': 'спробуйте щось схоже на',
|
'try something like': 'спробуйте щось схоже на',
|
||||||
|
'Try the mobile interface': 'Спробуйте мобільний інтерфейс',
|
||||||
'try view': 'дивитись результат',
|
'try view': 'дивитись результат',
|
||||||
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
|
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
|
||||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
|
'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
|
||||||
@@ -463,7 +468,7 @@
|
|||||||
'Views': 'Відображення (Views)',
|
'Views': 'Відображення (Views)',
|
||||||
'views': 'відображення',
|
'views': 'відображення',
|
||||||
'WARNING:': 'ПОПЕРЕДЖЕННЯ:',
|
'WARNING:': 'ПОПЕРЕДЖЕННЯ:',
|
||||||
'Web Framework': 'Web Framework',
|
'Web Framework': 'Веб-каркас (Web Framework)',
|
||||||
'web2py apps to deploy': 'Готові до розгортання додатки web2py',
|
'web2py apps to deploy': 'Готові до розгортання додатки web2py',
|
||||||
'web2py Debugger': 'Ладнач web2py',
|
'web2py Debugger': 'Ладнач web2py',
|
||||||
'web2py downgrade': 'повернення на попередню версію web2py',
|
'web2py downgrade': 'повернення на попередню версію web2py',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
EXPIRATION = 60 * 60 # logout after 60 minutes of inactivity
|
EXPIRATION = 60 * 60 # logout after 60 minutes of inactivity
|
||||||
CHECK_VERSION = True
|
CHECK_VERSION = True
|
||||||
WEB2PY_URL = 'http://web2py.com'
|
WEB2PY_URL = 'http://web2py.com'
|
||||||
WEB2PY_VERSION_URL = WEB2PY_URL+'/examples/default/version'
|
WEB2PY_VERSION_URL = WEB2PY_URL + '/examples/default/version'
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Preferences for EditArea
|
# Preferences for EditArea
|
||||||
@@ -13,15 +13,15 @@ TEXT_EDITOR = 'codemirror' or 'ace' or 'edit_area' or 'amy'
|
|||||||
|
|
||||||
## Editor Color scheme (only for ace)
|
## Editor Color scheme (only for ace)
|
||||||
TEXT_EDITOR_THEME = (
|
TEXT_EDITOR_THEME = (
|
||||||
"chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
|
"chrome", "clouds", "clouds_midnight", "cobalt", "crimson_editor", "dawn",
|
||||||
"dreamweaver", "eclipse", "idle_fingers", "kr_theme", "merbivore",
|
"dreamweaver", "eclipse", "idle_fingers", "kr_theme", "merbivore",
|
||||||
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
|
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
|
||||||
"solarized_dark", "solarized_light", "textmate", "tomorrow",
|
"solarized_dark", "solarized_light", "textmate", "tomorrow",
|
||||||
"tomorrow_night", "tomorrow_night_blue", "tomorrow_night_bright",
|
"tomorrow_night", "tomorrow_night_blue", "tomorrow_night_bright",
|
||||||
"tomorrow_night_eighties", "twilight", "vibrant_ink")[0]
|
"tomorrow_night_eighties", "twilight", "vibrant_ink")[0]
|
||||||
|
|
||||||
## Editor Keyboard bindings (only for ace and codemirror)
|
## Editor Keyboard bindings (only for ace and codemirror)
|
||||||
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
|
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
|
||||||
|
|
||||||
### edit_area only
|
### edit_area only
|
||||||
# The default font size, measured in 'points'. The value must be an integer > 0
|
# The default font size, measured in 'points'. The value must be an integer > 0
|
||||||
@@ -59,9 +59,9 @@ GAE_APPCFG = os.path.abspath(os.path.join('/usr/local/bin/appcfg.py'))
|
|||||||
|
|
||||||
# To use web2py as a teaching tool, set MULTI_USER_MODE to True
|
# To use web2py as a teaching tool, set MULTI_USER_MODE to True
|
||||||
MULTI_USER_MODE = False
|
MULTI_USER_MODE = False
|
||||||
EMAIL_SERVER = 'localhost'
|
EMAIL_SERVER = 'localhost'
|
||||||
EMAIL_SENDER = 'professor@example.com'
|
EMAIL_SENDER = 'professor@example.com'
|
||||||
EMAIL_LOGIN = None
|
EMAIL_LOGIN = None
|
||||||
|
|
||||||
# configurable twitterbox, set to None/False to suppress
|
# configurable twitterbox, set to None/False to suppress
|
||||||
TWITTER_HASH = "web2py"
|
TWITTER_HASH = "web2py"
|
||||||
@@ -78,5 +78,3 @@ PLUGINS_APP = 'http://web2py.com/plugins'
|
|||||||
# set the language
|
# set the language
|
||||||
if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage'] is None):
|
if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage'] is None):
|
||||||
T.force(request.cookies['adminLanguage'].value)
|
T.force(request.cookies['adminLanguage'].value)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,5 +28,3 @@ from gluon.languages import findT, update_all_languages
|
|||||||
from gluon.myregex import *
|
from gluon.myregex import *
|
||||||
from gluon.restricted import *
|
from gluon.restricted import *
|
||||||
from gluon.compileapp import compile_application, remove_compiled_application
|
from gluon.compileapp import compile_application, remove_compiled_application
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import base64, os, time
|
import base64
|
||||||
|
import os
|
||||||
|
import time
|
||||||
from gluon import portalocker
|
from gluon import portalocker
|
||||||
from gluon.admin import apath
|
from gluon.admin import apath
|
||||||
from gluon.fileutils import read_file
|
from gluon.fileutils import read_file
|
||||||
@@ -24,7 +26,8 @@ elif not request.is_local and not DEMO_MODE:
|
|||||||
try:
|
try:
|
||||||
_config = {}
|
_config = {}
|
||||||
port = int(request.env.server_port or 0)
|
port = int(request.env.server_port or 0)
|
||||||
restricted(read_file(apath('../parameters_%i.py' % port, request)), _config)
|
restricted(
|
||||||
|
read_file(apath('../parameters_%i.py' % port, request)), _config)
|
||||||
|
|
||||||
if not 'password' in _config or not _config['password']:
|
if not 'password' in _config or not _config['password']:
|
||||||
raise HTTP(200, T('admin disabled because no admin password'))
|
raise HTTP(200, T('admin disabled because no admin password'))
|
||||||
@@ -38,7 +41,8 @@ except IOError:
|
|||||||
raise HTTP(200,
|
raise HTTP(200,
|
||||||
T('admin disabled because not supported on google app engine'))
|
T('admin disabled because not supported on google app engine'))
|
||||||
else:
|
else:
|
||||||
raise HTTP(200, T('admin disabled because unable to access password file'))
|
raise HTTP(
|
||||||
|
200, T('admin disabled because unable to access password file'))
|
||||||
|
|
||||||
|
|
||||||
def verify_password(password):
|
def verify_password(password):
|
||||||
@@ -50,7 +54,7 @@ def verify_password(password):
|
|||||||
elif _config['password'].startswith('pam_user:'):
|
elif _config['password'].startswith('pam_user:'):
|
||||||
session.pam_user = _config['password'][9:].strip()
|
session.pam_user = _config['password'][9:].strip()
|
||||||
import gluon.contrib.pam
|
import gluon.contrib.pam
|
||||||
return gluon.contrib.pam.authenticate(session.pam_user,password)
|
return gluon.contrib.pam.authenticate(session.pam_user, password)
|
||||||
else:
|
else:
|
||||||
return _config['password'] == CRYPT()(password)[0]
|
return _config['password'] == CRYPT()(password)[0]
|
||||||
|
|
||||||
@@ -63,6 +67,7 @@ deny_file = os.path.join(request.folder, 'private', 'hosts.deny')
|
|||||||
allowed_number_of_attempts = 5
|
allowed_number_of_attempts = 5
|
||||||
expiration_failed_logins = 3600
|
expiration_failed_logins = 3600
|
||||||
|
|
||||||
|
|
||||||
def read_hosts_deny():
|
def read_hosts_deny():
|
||||||
import datetime
|
import datetime
|
||||||
hosts = {}
|
hosts = {}
|
||||||
@@ -75,7 +80,7 @@ def read_hosts_deny():
|
|||||||
continue
|
continue
|
||||||
fields = line.strip().split()
|
fields = line.strip().split()
|
||||||
if len(fields) > 2:
|
if len(fields) > 2:
|
||||||
hosts[fields[0].strip()] = ( # ip
|
hosts[fields[0].strip()] = ( # ip
|
||||||
int(fields[1].strip()), # n attemps
|
int(fields[1].strip()), # n attemps
|
||||||
int(fields[2].strip()) # last attempts
|
int(fields[2].strip()) # last attempts
|
||||||
)
|
)
|
||||||
@@ -83,28 +88,30 @@ def read_hosts_deny():
|
|||||||
f.close()
|
f.close()
|
||||||
return hosts
|
return hosts
|
||||||
|
|
||||||
|
|
||||||
def write_hosts_deny(denied_hosts):
|
def write_hosts_deny(denied_hosts):
|
||||||
f = open(deny_file, 'w')
|
f = open(deny_file, 'w')
|
||||||
portalocker.lock(f, portalocker.LOCK_EX)
|
portalocker.lock(f, portalocker.LOCK_EX)
|
||||||
for key, val in denied_hosts.items():
|
for key, val in denied_hosts.items():
|
||||||
if time.time()-val[1] < expiration_failed_logins:
|
if time.time() - val[1] < expiration_failed_logins:
|
||||||
line = '%s %s %s\n' % (key, val[0], val[1])
|
line = '%s %s %s\n' % (key, val[0], val[1])
|
||||||
f.write(line)
|
f.write(line)
|
||||||
portalocker.unlock(f)
|
portalocker.unlock(f)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
def login_record(success=True):
|
def login_record(success=True):
|
||||||
denied_hosts = read_hosts_deny()
|
denied_hosts = read_hosts_deny()
|
||||||
val = (0,0)
|
val = (0, 0)
|
||||||
if success and request.client in denied_hosts:
|
if success and request.client in denied_hosts:
|
||||||
del denied_hosts[request.client]
|
del denied_hosts[request.client]
|
||||||
elif not success and not request.is_local:
|
elif not success and not request.is_local:
|
||||||
val = denied_hosts.get(request.client,(0,0))
|
val = denied_hosts.get(request.client, (0, 0))
|
||||||
if time.time()-val[1]<expiration_failed_logins \
|
if time.time() - val[1] < expiration_failed_logins \
|
||||||
and val[0] >= allowed_number_of_attempts:
|
and val[0] >= allowed_number_of_attempts:
|
||||||
return val[0] # locked out
|
return val[0] # locked out
|
||||||
time.sleep(2**val[0])
|
time.sleep(2 ** val[0])
|
||||||
val = (val[0]+1,int(time.time()))
|
val = (val[0] + 1, int(time.time()))
|
||||||
denied_hosts[request.client] = val
|
denied_hosts[request.client] = val
|
||||||
write_hosts_deny(denied_hosts)
|
write_hosts_deny(denied_hosts)
|
||||||
return val[0]
|
return val[0]
|
||||||
@@ -124,9 +131,9 @@ if session.authorized:
|
|||||||
session.last_time = t0
|
session.last_time = t0
|
||||||
|
|
||||||
|
|
||||||
if request.vars.is_mobile in ('true','false','auto'):
|
if request.vars.is_mobile in ('true', 'false', 'auto'):
|
||||||
session.is_mobile = request.vars.is_mobile or 'auto'
|
session.is_mobile = request.vars.is_mobile or 'auto'
|
||||||
if request.controller=='default' and request.function=='index':
|
if request.controller == 'default' and request.function == 'index':
|
||||||
if not request.vars.is_mobile:
|
if not request.vars.is_mobile:
|
||||||
session.is_mobile = 'auto'
|
session.is_mobile = 'auto'
|
||||||
if not session.is_mobile:
|
if not session.is_mobile:
|
||||||
@@ -141,14 +148,14 @@ else:
|
|||||||
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 ':
|
||||||
raise HTTP(401,"Wrong credentials")
|
raise HTTP(401, "Wrong credentials")
|
||||||
(username, password) = base64.b64decode(basic[6:]).split(':')
|
(username, password) = base64.b64decode(basic[6:]).split(':')
|
||||||
if not verify_password(password) or MULTI_USER_MODE:
|
if not verify_password(password) or MULTI_USER_MODE:
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
raise HTTP(403,"Not authorized")
|
raise HTTP(403, "Not authorized")
|
||||||
elif not session.authorized and not \
|
elif not session.authorized and not \
|
||||||
(request.controller+'/'+request.function in
|
(request.controller + '/' + request.function in
|
||||||
('default/index','default/user','plugin_jqmobile/index','plugin_jqmobile/about')):
|
('default/index', 'default/user', 'plugin_jqmobile/index', 'plugin_jqmobile/about')):
|
||||||
|
|
||||||
if request.env.query_string:
|
if request.env.query_string:
|
||||||
query_string = '?' + request.env.query_string
|
query_string = '?' + request.env.query_string
|
||||||
@@ -165,7 +172,6 @@ elif session.authorized and \
|
|||||||
request.function == 'index':
|
request.function == 'index':
|
||||||
redirect(URL(request.application, 'default', 'site'))
|
redirect(URL(request.application, 'default', 'site'))
|
||||||
|
|
||||||
if request.controller=='appadmin' and DEMO_MODE:
|
if request.controller == 'appadmin' and DEMO_MODE:
|
||||||
session.flash = 'Appadmin disabled in demo mode'
|
session.flash = 'Appadmin disabled in demo mode'
|
||||||
redirect(URL('default','sites'))
|
redirect(URL('default', 'sites'))
|
||||||
|
|
||||||
|
|||||||
@@ -2,37 +2,41 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def A_button(*a,**b):
|
|
||||||
|
def A_button(*a, **b):
|
||||||
b['_data-role'] = 'button'
|
b['_data-role'] = 'button'
|
||||||
b['_data-inline'] = 'true'
|
b['_data-inline'] = 'true'
|
||||||
return A(*a,**b)
|
return A(*a, **b)
|
||||||
|
|
||||||
|
|
||||||
def button(href, label):
|
def button(href, label):
|
||||||
if is_mobile:
|
if is_mobile:
|
||||||
ret = A_button(SPAN(label), _href=href)
|
ret = A_button(SPAN(label), _href=href)
|
||||||
else:
|
else:
|
||||||
ret = A(SPAN(label),_class='button',_href=href)
|
ret = A(SPAN(label), _class='button', _href=href)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def button_enable(href, app):
|
def button_enable(href, app):
|
||||||
if os.path.exists(os.path.join(apath(app,r=request),'DISABLED')):
|
if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')):
|
||||||
label = SPAN(T('Enable'),_style='color:red')
|
label = SPAN(T('Enable'), _style='color:red')
|
||||||
else:
|
else:
|
||||||
label = SPAN(T('Disable'),_style='color:green')
|
label = SPAN(T('Disable'), _style='color:green')
|
||||||
id = 'enable_'+app
|
id = 'enable_' + app
|
||||||
return A(label,_class='button',_id=id,callback=href,target=id)
|
return A(label, _class='button', _id=id, callback=href, target=id)
|
||||||
|
|
||||||
|
|
||||||
def sp_button(href, label):
|
def sp_button(href, label):
|
||||||
if request.user_agent().is_mobile:
|
if request.user_agent().is_mobile:
|
||||||
ret = A_button(SPAN(label), _href=href)
|
ret = A_button(SPAN(label), _href=href)
|
||||||
else:
|
else:
|
||||||
ret = A(SPAN(label),_class='button special',_href=href)
|
ret = A(SPAN(label), _class='button special', _href=href)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def helpicon():
|
def helpicon():
|
||||||
return IMG(_src=URL('static', 'images/help.png'), _alt='help')
|
return IMG(_src=URL('static', 'images/help.png'), _alt='help')
|
||||||
|
|
||||||
|
|
||||||
def searchbox(elementid):
|
def searchbox(elementid):
|
||||||
return TAG[''](LABEL(IMG(_id="search_start",_src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12))
|
return TAG[''](LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,37 +4,39 @@
|
|||||||
if MULTI_USER_MODE:
|
if MULTI_USER_MODE:
|
||||||
db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB
|
db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB
|
||||||
from gluon.tools import *
|
from gluon.tools import *
|
||||||
auth = Auth(globals(),db) # authentication/authorization
|
auth = Auth(
|
||||||
crud = Crud(globals(),db) # for CRUD helpers using auth
|
globals(), db) # authentication/authorization
|
||||||
service = Service(globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
|
crud = Crud(
|
||||||
|
globals(), db) # for CRUD helpers using auth
|
||||||
|
service = Service(
|
||||||
|
globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
|
||||||
plugins = PluginManager()
|
plugins = PluginManager()
|
||||||
|
|
||||||
mail = auth.settings.mailer
|
mail = auth.settings.mailer
|
||||||
mail.settings.server = EMAIL_SERVER
|
mail.settings.server = EMAIL_SERVER
|
||||||
mail.settings.sender = EMAIL_SENDER
|
mail.settings.sender = EMAIL_SENDER
|
||||||
mail.settings.login = EMAIL_LOGIN
|
mail.settings.login = EMAIL_LOGIN
|
||||||
|
|
||||||
auth.settings.extra_fields['auth_user'] = \
|
auth.settings.extra_fields['auth_user'] = \
|
||||||
[Field('is_manager','boolean',default=False,writable=False)]
|
[Field('is_manager', 'boolean', default=False, writable=False)]
|
||||||
auth.define_tables() # creates all needed tables
|
auth.define_tables() # creates all needed tables
|
||||||
auth.settings.registration_requires_verification = False
|
auth.settings.registration_requires_verification = False
|
||||||
auth.settings.registration_requires_approval = True
|
auth.settings.registration_requires_approval = True
|
||||||
auth.settings.reset_password_requires_verification = True
|
auth.settings.reset_password_requires_verification = True
|
||||||
|
|
||||||
db.define_table('app',Field('name'),Field('owner',db.auth_user))
|
db.define_table('app', Field('name'), Field('owner', db.auth_user))
|
||||||
|
|
||||||
if not session.authorized and MULTI_USER_MODE:
|
if not session.authorized and MULTI_USER_MODE:
|
||||||
if auth.user and not request.function=='user':
|
if auth.user and not request.function == 'user':
|
||||||
session.authorized = True
|
session.authorized = True
|
||||||
elif not request.function=='user':
|
elif not request.function == 'user':
|
||||||
redirect(URL('default','user/login'))
|
redirect(URL('default', 'user/login'))
|
||||||
|
|
||||||
|
|
||||||
def is_manager():
|
def is_manager():
|
||||||
if not MULTI_USER_MODE:
|
if not MULTI_USER_MODE:
|
||||||
return True
|
return True
|
||||||
elif auth.user and (auth.user.id==1 or auth.user.is_manager):
|
elif auth.user and (auth.user.id == 1 or auth.user.is_manager):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,31 +7,30 @@ _c = request.controller
|
|||||||
_f = request.function
|
_f = request.function
|
||||||
response.title = '%s %s' % (_f, '/'.join(request.args))
|
response.title = '%s %s' % (_f, '/'.join(request.args))
|
||||||
response.subtitle = 'admin'
|
response.subtitle = 'admin'
|
||||||
response.menu = [(T('Site'), _f == 'site', URL(_a,'default','site'))]
|
response.menu = [(T('Site'), _f == 'site', URL(_a, 'default', 'site'))]
|
||||||
|
|
||||||
if request.vars.app or request.args:
|
if request.vars.app or request.args:
|
||||||
_t = request.vars.app or request.args[0]
|
_t = request.vars.app or request.args[0]
|
||||||
response.menu.append((T('Edit'), _c == 'default' and _f == 'design',
|
response.menu.append((T('Edit'), _c == 'default' and _f == 'design',
|
||||||
URL(_a,'default','design',args=_t)))
|
URL(_a, 'default', 'design', args=_t)))
|
||||||
response.menu.append((T('About'), _c == 'default' and _f == 'about',
|
response.menu.append((T('About'), _c == 'default' and _f == 'about',
|
||||||
URL(_a,'default','about',args=_t,)))
|
URL(_a, 'default', 'about', args=_t,)))
|
||||||
response.menu.append((T('Errors'), _c == 'default' and _f == 'errors',
|
response.menu.append((T('Errors'), _c == 'default' and _f == 'errors',
|
||||||
URL(_a,'default','errors',args=_t)))
|
URL(_a, 'default', 'errors', args=_t)))
|
||||||
response.menu.append((T('Versioning'),
|
response.menu.append((T('Versioning'),
|
||||||
_c == 'mercurial' and _f == 'commit',
|
_c == 'mercurial' and _f == 'commit',
|
||||||
URL(_a,'mercurial','commit',args=_t)))
|
URL(_a, 'mercurial', 'commit', args=_t)))
|
||||||
|
|
||||||
if not session.authorized:
|
if not session.authorized:
|
||||||
response.menu = [(T('Login'), True, URL('site'))]
|
response.menu = [(T('Login'), True, URL('site'))]
|
||||||
else:
|
else:
|
||||||
response.menu.append((T('Logout'), False,
|
response.menu.append((T('Logout'), False,
|
||||||
URL(_a,'default',f='logout')))
|
URL(_a, 'default', f='logout')))
|
||||||
response.menu.append((T('Debug'), False,
|
response.menu.append((T('Debug'), False,
|
||||||
URL(_a, 'debug','interact')))
|
URL(_a, 'debug', 'interact')))
|
||||||
|
|
||||||
if os.path.exists('applications/examples'):
|
if os.path.exists('applications/examples'):
|
||||||
response.menu.append((T('Help'), False, URL('examples','default','index')))
|
response.menu.append(
|
||||||
|
(T('Help'), False, URL('examples', 'default', 'index')))
|
||||||
else:
|
else:
|
||||||
response.menu.append((T('Help'), False, 'http://web2py.com/examples'))
|
response.menu.append((T('Help'), False, 'http://web2py.com/examples'))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
response.files.append(URL('static','plugin_multiselect/jquery.multi-select.js'))
|
response.files.append(
|
||||||
response.files.append(URL('static','plugin_multiselect/multi-select.css'))
|
URL('static', 'plugin_multiselect/jquery.multi-select.js'))
|
||||||
response.files.append(URL('static','plugin_multiselect/start.js'))
|
response.files.append(URL('static', 'plugin_multiselect/multi-select.css'))
|
||||||
|
response.files.append(URL('static', 'plugin_multiselect/start.js'))
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ jQuery(document).ready(function(){
|
|||||||
<textarea style="width: auto; height:400px;direction:ltr;" rows="58" cols="100" -amy-enabled="true" id="body" name="data">{{=data}}</textarea>
|
<textarea style="width: auto; height:400px;direction:ltr;" rows="58" cols="100" -amy-enabled="true" id="body" name="data">{{=data}}</textarea>
|
||||||
<script>window.eamy = eamy;</script>
|
<script>window.eamy = eamy;</script>
|
||||||
{{elif TEXT_EDITOR == 'codemirror':}}
|
{{elif TEXT_EDITOR == 'codemirror':}}
|
||||||
<textarea style="width: auto; height:400px;direction:ltr;" id="body" name="data">{{=data}}</textarea>
|
<textarea style="width: auto; height:auto; direction:ltr;" id="body" name="data">{{=data}}</textarea>
|
||||||
<script>
|
<script>
|
||||||
function isFullScreen(instance) {
|
function isFullScreen(instance) {
|
||||||
return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className);
|
return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className);
|
||||||
@@ -197,6 +197,7 @@ jQuery(document).ready(function(){
|
|||||||
document.getElementById("body"),cm_opts);
|
document.getElementById("body"),cm_opts);
|
||||||
var hlLine = editor.setLineClass(0, "activeline");
|
var hlLine = editor.setLineClass(0, "activeline");
|
||||||
window.mirror = editor;
|
window.mirror = editor;
|
||||||
|
jQuery(function(){jQuery('.CodeMirror-scroll').css("height","auto").css("overflow-x","auto");});
|
||||||
</script>
|
</script>
|
||||||
{{elif TEXT_EDITOR == 'ace':}}
|
{{elif TEXT_EDITOR == 'ace':}}
|
||||||
<div id="editor" style="height: 500px; width: auto; position: relative">{{=data}}</div>
|
<div id="editor" style="height: 500px; width: auto; position: relative">{{=data}}</div>
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
body {
|
body {
|
||||||
background: url('{{=URL('static','plugin_jqmobile/images/iphone.jpg')}}') no-repeat white;
|
background: url('{{=URL('static','plugin_jqmobile/images/iphone.jpg')}}') no-repeat white;
|
||||||
}
|
}
|
||||||
|
#back {
|
||||||
|
z-index: 1000;
|
||||||
|
padding: 10px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
iframe {
|
iframe {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-left: 320px;
|
margin-left: 320px;
|
||||||
@@ -35,6 +42,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe src="{{=URL('default','index',vars=dict(is_mobile='true'))}}"></iframe>
|
<iframe src="{{=URL('default','index',vars=dict(is_mobile='true'))}}"></iframe>
|
||||||
|
<div id="back"><a href="{{=URL('default','index',vars=dict(is_mobile='false'))}}">Back</a></div>
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<h1><a href="http://web2py.com">web2py</a> plugin</h1>
|
<h1><a href="http://web2py.com">web2py</a> plugin</h1>
|
||||||
<h2>for <a href="http://jquerymobile.com/">jQuery Mobile</a></h2>
|
<h2>for <a href="http://jquerymobile.com/">jQuery Mobile</a></h2>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,3 @@ def flash():
|
|||||||
|
|
||||||
def fade():
|
def fade():
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
|
|||||||
try:
|
try:
|
||||||
hosts = (http_host, socket.gethostname(),
|
hosts = (http_host, socket.gethostname(),
|
||||||
socket.gethostbyname(http_host),
|
socket.gethostbyname(http_host),
|
||||||
'::1','127.0.0.1','::ffff:127.0.0.1')
|
'::1', '127.0.0.1', '::ffff:127.0.0.1')
|
||||||
except:
|
except:
|
||||||
hosts = (http_host, )
|
hosts = (http_host, )
|
||||||
|
|
||||||
@@ -32,10 +32,10 @@ if request.env.http_x_forwarded_for or request.is_https:
|
|||||||
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
||||||
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
||||||
|
|
||||||
if (request.application=='admin' and not session.authorized) or \
|
if (request.application == 'admin' and not session.authorized) or \
|
||||||
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
|
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||||
redirect(URL('admin', 'default', 'index',
|
redirect(URL('admin', 'default', 'index',
|
||||||
vars=dict(send=URL(args=request.args,vars=request.vars))))
|
vars=dict(send=URL(args=request.args, vars=request.vars))))
|
||||||
|
|
||||||
ignore_rw = True
|
ignore_rw = True
|
||||||
response.view = 'appadmin.html'
|
response.view = 'appadmin.html'
|
||||||
@@ -95,24 +95,23 @@ def get_query(request):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def query_by_table_type(tablename,db,request=request):
|
def query_by_table_type(tablename, db, request=request):
|
||||||
keyed = hasattr(db[tablename],'_primarykey')
|
keyed = hasattr(db[tablename], '_primarykey')
|
||||||
if keyed:
|
if keyed:
|
||||||
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
||||||
cond = '>0'
|
cond = '>0'
|
||||||
if firstkey.type in ['string', 'text']:
|
if firstkey.type in ['string', 'text']:
|
||||||
cond = '!=""'
|
cond = '!=""'
|
||||||
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond)
|
qry = '%s.%s.%s%s' % (
|
||||||
|
request.args[0], request.args[1], firstkey.name, cond)
|
||||||
else:
|
else:
|
||||||
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
||||||
return qry
|
return qry
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
# ## list all databases and tables
|
# ## list all databases and tables
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
return dict(databases=databases)
|
return dict(databases=databases)
|
||||||
|
|
||||||
@@ -127,7 +126,7 @@ def insert():
|
|||||||
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
response.flash = T('new record inserted')
|
response.flash = T('new record inserted')
|
||||||
return dict(form=form,table=db[table])
|
return dict(form=form, table=db[table])
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -138,7 +137,8 @@ def insert():
|
|||||||
def download():
|
def download():
|
||||||
import os
|
import os
|
||||||
db = get_database(request)
|
db = get_database(request)
|
||||||
return response.download(request,db)
|
return response.download(request, db)
|
||||||
|
|
||||||
|
|
||||||
def csv():
|
def csv():
|
||||||
import gluon.contenttype
|
import gluon.contenttype
|
||||||
@@ -149,26 +149,27 @@ def csv():
|
|||||||
if not query:
|
if not query:
|
||||||
return None
|
return None
|
||||||
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
||||||
% tuple(request.vars.query.split('.')[:2])
|
% tuple(request.vars.query.split('.')[:2])
|
||||||
return str(db(query,ignore_common_filters=True).select())
|
return str(db(query, ignore_common_filters=True).select())
|
||||||
|
|
||||||
|
|
||||||
def import_csv(table, file):
|
def import_csv(table, file):
|
||||||
table.import_from_csv_file(file)
|
table.import_from_csv_file(file)
|
||||||
|
|
||||||
|
|
||||||
def select():
|
def select():
|
||||||
import re
|
import re
|
||||||
db = get_database(request)
|
db = get_database(request)
|
||||||
dbname = request.args[0]
|
dbname = request.args[0]
|
||||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
||||||
if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'):
|
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
|
||||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
||||||
if request.vars.query:
|
if request.vars.query:
|
||||||
match = regex.match(request.vars.query)
|
match = regex.match(request.vars.query)
|
||||||
if match:
|
if match:
|
||||||
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
||||||
match.group('table'), match.group('field'),
|
match.group('table'), match.group('field'),
|
||||||
match.group('value'))
|
match.group('value'))
|
||||||
else:
|
else:
|
||||||
request.vars.query = session.last_query
|
request.vars.query = session.last_query
|
||||||
query = get_query(request)
|
query = get_query(request)
|
||||||
@@ -192,46 +193,50 @@ def select():
|
|||||||
session.last_query = request.vars.query
|
session.last_query = request.vars.query
|
||||||
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
||||||
_name='query', _value=request.vars.query or '',
|
_name='query', _value=request.vars.query or '',
|
||||||
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'),
|
requires=IS_NOT_EMPTY(
|
||||||
|
error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||||
INPUT(_name='update_check', _type='checkbox',
|
INPUT(_name='update_check', _type='checkbox',
|
||||||
value=False), INPUT(_style='width:400px',
|
value=False), INPUT(_style='width:400px',
|
||||||
_name='update_fields', _value=request.vars.update_fields
|
_name='update_fields', _value=request.vars.update_fields
|
||||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||||
_class='delete', _type='checkbox', value=False), ''),
|
_class='delete', _type='checkbox', value=False), ''),
|
||||||
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
||||||
_action=URL(r=request,args=request.args))
|
_action=URL(r=request, args=request.args))
|
||||||
|
|
||||||
|
tb = None
|
||||||
if form.accepts(request.vars, formname=None):
|
if form.accepts(request.vars, formname=None):
|
||||||
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
||||||
match = regex.match(form.vars.query.strip())
|
match = regex.match(form.vars.query.strip())
|
||||||
if match:
|
if match:
|
||||||
table = match.group('table')
|
table = match.group('table')
|
||||||
try:
|
try:
|
||||||
tb = None
|
|
||||||
nrows = db(query).count()
|
nrows = db(query).count()
|
||||||
if form.vars.update_check and form.vars.update_fields:
|
if form.vars.update_check and form.vars.update_fields:
|
||||||
db(query).update(**eval_in_global_env('dict(%s)'
|
db(query).update(**eval_in_global_env('dict(%s)'
|
||||||
% form.vars.update_fields))
|
% form.vars.update_fields))
|
||||||
response.flash = T('%s %%{row} updated', nrows)
|
response.flash = T('%s %%{row} updated', nrows)
|
||||||
elif form.vars.delete_check:
|
elif form.vars.delete_check:
|
||||||
db(query).delete()
|
db(query).delete()
|
||||||
response.flash = T('%s %%{row} deleted', nrows)
|
response.flash = T('%s %%{row} deleted', nrows)
|
||||||
nrows = db(query).count()
|
nrows = db(query).count()
|
||||||
if orderby:
|
if orderby:
|
||||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby))
|
rows = db(query, ignore_common_filters=True).select(limitby=(
|
||||||
|
start, stop), orderby=eval_in_global_env(orderby))
|
||||||
else:
|
else:
|
||||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
|
rows = db(query, ignore_common_filters=True).select(
|
||||||
|
limitby=(start, stop))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
import traceback
|
import traceback
|
||||||
tb = traceback.format_exc()
|
tb = traceback.format_exc()
|
||||||
(rows, nrows) = ([], 0)
|
(rows, nrows) = ([], 0)
|
||||||
response.flash = DIV(T('Invalid Query'),PRE(str(e)))
|
response.flash = DIV(T('Invalid Query'), PRE(str(e)))
|
||||||
# begin handle upload csv
|
# begin handle upload csv
|
||||||
csv_table = table or request.vars.table
|
csv_table = table or request.vars.table
|
||||||
if csv_table:
|
if csv_table:
|
||||||
formcsv = FORM(str(T('or import from csv file'))+" ",
|
formcsv = FORM(str(T('or import from csv file')) + " ",
|
||||||
INPUT(_type='file',_name='csvfile'),
|
INPUT(_type='file', _name='csvfile'),
|
||||||
INPUT(_type='hidden',_value=csv_table,_name='table'),
|
INPUT(_type='hidden', _value=csv_table, _name='table'),
|
||||||
INPUT(_type='submit',_value=T('import')))
|
INPUT(_type='submit', _value=T('import')))
|
||||||
else:
|
else:
|
||||||
formcsv = None
|
formcsv = None
|
||||||
if formcsv and formcsv.process().accepted:
|
if formcsv and formcsv.process().accepted:
|
||||||
@@ -240,7 +245,7 @@ def select():
|
|||||||
request.vars.csvfile.file)
|
request.vars.csvfile.file)
|
||||||
response.flash = T('data uploaded')
|
response.flash = T('data uploaded')
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
response.flash = DIV(T('unable to parse csv file'),PRE(str(e)))
|
response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
|
||||||
# end handle upload csv
|
# end handle upload csv
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
@@ -251,9 +256,9 @@ def select():
|
|||||||
nrows=nrows,
|
nrows=nrows,
|
||||||
rows=rows,
|
rows=rows,
|
||||||
query=request.vars.query,
|
query=request.vars.query,
|
||||||
formcsv = formcsv,
|
formcsv=formcsv,
|
||||||
tb = tb,
|
tb=tb,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -263,14 +268,16 @@ def select():
|
|||||||
|
|
||||||
def update():
|
def update():
|
||||||
(db, table) = get_table(request)
|
(db, table) = get_table(request)
|
||||||
keyed = hasattr(db[table],'_primarykey')
|
keyed = hasattr(db[table], '_primarykey')
|
||||||
record = None
|
record = None
|
||||||
if keyed:
|
if keyed:
|
||||||
key = [f for f in request.vars if f in db[table]._primarykey]
|
key = [f for f in request.vars if f in db[table]._primarykey]
|
||||||
if key:
|
if key:
|
||||||
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first()
|
record = db(db[table][key[0]] == request.vars[key[
|
||||||
|
0]], ignore_common_filters=True).select().first()
|
||||||
else:
|
else:
|
||||||
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first()
|
record = db(db[table].id == request.args(
|
||||||
|
2), ignore_common_filters=True).select().first()
|
||||||
|
|
||||||
if not record:
|
if not record:
|
||||||
qry = query_by_table_type(table, db)
|
qry = query_by_table_type(table, db)
|
||||||
@@ -280,20 +287,21 @@ def update():
|
|||||||
|
|
||||||
if keyed:
|
if keyed:
|
||||||
for k in db[table]._primarykey:
|
for k in db[table]._primarykey:
|
||||||
db[table][k].writable=False
|
db[table][k].writable = False
|
||||||
|
|
||||||
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'),
|
form = SQLFORM(
|
||||||
ignore_rw=ignore_rw and not keyed,
|
db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||||
linkto=URL('select',
|
ignore_rw=ignore_rw and not keyed,
|
||||||
|
linkto=URL('select',
|
||||||
args=request.args[:1]), upload=URL(r=request,
|
args=request.args[:1]), upload=URL(r=request,
|
||||||
f='download', args=request.args[:1]))
|
f='download', args=request.args[:1]))
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
session.flash = T('done!')
|
session.flash = T('done!')
|
||||||
qry = query_by_table_type(table, db)
|
qry = query_by_table_type(table, db)
|
||||||
redirect(URL('select', args=request.args[:1],
|
redirect(URL('select', args=request.args[:1],
|
||||||
vars=dict(query=qry)))
|
vars=dict(query=qry)))
|
||||||
return dict(form=form,table=db[table])
|
return dict(form=form, table=db[table])
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -304,11 +312,15 @@ def update():
|
|||||||
def state():
|
def state():
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
|
||||||
def ccache():
|
def ccache():
|
||||||
form = FORM(
|
form = FORM(
|
||||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
P(TAG.BUTTON(
|
||||||
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||||
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
P(TAG.BUTTON(
|
||||||
|
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||||
|
P(TAG.BUTTON(
|
||||||
|
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||||
)
|
)
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
@@ -332,11 +344,16 @@ def ccache():
|
|||||||
redirect(URL(r=request))
|
redirect(URL(r=request))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from guppy import hpy; hp=hpy()
|
from guppy import hpy
|
||||||
|
hp = hpy()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
hp = False
|
hp = False
|
||||||
|
|
||||||
import shelve, os, copy, time, math
|
import shelve
|
||||||
|
import os
|
||||||
|
import copy
|
||||||
|
import time
|
||||||
|
import math
|
||||||
from gluon import portalocker
|
from gluon import portalocker
|
||||||
|
|
||||||
ram = {
|
ram = {
|
||||||
@@ -381,9 +398,10 @@ def ccache():
|
|||||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
|
|
||||||
locker = open(os.path.join(request.folder,
|
locker = open(os.path.join(request.folder,
|
||||||
'cache/cache.lock'), 'a')
|
'cache/cache.lock'), 'a')
|
||||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||||
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve'))
|
disk_storage = shelve.open(
|
||||||
|
os.path.join(request.folder, 'cache/cache.shelve'))
|
||||||
try:
|
try:
|
||||||
for key, value in disk_storage.items():
|
for key, value in disk_storage.items():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
@@ -414,7 +432,8 @@ def ccache():
|
|||||||
total['misses'] = ram['misses'] + disk['misses']
|
total['misses'] = ram['misses'] + disk['misses']
|
||||||
total['keys'] = ram['keys'] + disk['keys']
|
total['keys'] = ram['keys'] + disk['keys']
|
||||||
try:
|
try:
|
||||||
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
|
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||||
|
total['misses'])
|
||||||
except (KeyError, ZeroDivisionError):
|
except (KeyError, ZeroDivisionError):
|
||||||
total['ratio'] = 0
|
total['ratio'] = 0
|
||||||
|
|
||||||
@@ -440,6 +459,3 @@ def ccache():
|
|||||||
|
|
||||||
return dict(form=form, total=total,
|
return dict(form=form, total=total,
|
||||||
ram=ram, disk=disk, object_stats=hp != False)
|
ram=ram, disk=disk, object_stats=hp != False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
def cache_in_ram():
|
def cache_in_ram():
|
||||||
"""cache the output of the lambda function in ram"""
|
"""cache the output of the lambda function in ram"""
|
||||||
|
|
||||||
t = cache.ram('time', lambda : time.ctime(), time_expire=5)
|
t = cache.ram('time', lambda: time.ctime(), time_expire=5)
|
||||||
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||||
|
|
||||||
|
|
||||||
def cache_on_disk():
|
def cache_on_disk():
|
||||||
"""cache the output of the lambda function on disk"""
|
"""cache the output of the lambda function on disk"""
|
||||||
|
|
||||||
t = cache.disk('time', lambda : time.ctime(), time_expire=5)
|
t = cache.disk('time', lambda: time.ctime(), time_expire=5)
|
||||||
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||||
|
|
||||||
|
|
||||||
def cache_in_ram_and_disk():
|
def cache_in_ram_and_disk():
|
||||||
"""cache the output of the lambda function on disk and in ram"""
|
"""cache the output of the lambda function on disk and in ram"""
|
||||||
|
|
||||||
t = cache.ram('time', lambda : cache.disk('time', lambda : \
|
t = cache.ram('time', lambda: cache.disk('time', lambda:
|
||||||
time.ctime(), time_expire=5), time_expire=5)
|
time.ctime(), time_expire=5), time_expire=5)
|
||||||
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
return dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||||
|
|
||||||
@@ -47,5 +46,3 @@ def cache_controller_and_view():
|
|||||||
t = time.ctime()
|
t = time.ctime()
|
||||||
d = dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
d = dict(time=t, link=A('click to reload', _href=URL(r=request)))
|
||||||
return response.render(d)
|
return response.render(d)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,68 +9,83 @@ response.description = T('web2py Web Framework')
|
|||||||
session.forget()
|
session.forget()
|
||||||
cache_expire = not request.is_local and 300 or 0
|
cache_expire = not request.is_local and 300 or 0
|
||||||
|
|
||||||
|
|
||||||
@cache('index', time_expire=cache_expire)
|
@cache('index', time_expire=cache_expire)
|
||||||
def index():
|
def index():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
@cache('what', time_expire=cache_expire)
|
@cache('what', time_expire=cache_expire)
|
||||||
def what():
|
def what():
|
||||||
import urllib;
|
import urllib
|
||||||
try:
|
try:
|
||||||
images = XML(urllib.urlopen('http://web2py.com/poweredby/default/images').read())
|
images = XML(urllib.urlopen(
|
||||||
|
'http://web2py.com/poweredby/default/images').read())
|
||||||
except:
|
except:
|
||||||
images = []
|
images = []
|
||||||
return response.render(images=images)
|
return response.render(images=images)
|
||||||
|
|
||||||
|
|
||||||
@cache('download', time_expire=cache_expire)
|
@cache('download', time_expire=cache_expire)
|
||||||
def download():
|
def download():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
@cache('who', time_expire=cache_expire)
|
@cache('who', time_expire=cache_expire)
|
||||||
def who():
|
def who():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
@cache('support', time_expire=cache_expire)
|
@cache('support', time_expire=cache_expire)
|
||||||
def support():
|
def support():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
@cache('documentation', time_expire=cache_expire)
|
@cache('documentation', time_expire=cache_expire)
|
||||||
def documentation():
|
def documentation():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
@cache('usergroups', time_expire=cache_expire)
|
@cache('usergroups', time_expire=cache_expire)
|
||||||
def usergroups():
|
def usergroups():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
def contact():
|
def contact():
|
||||||
redirect(URL('default','usergroups'))
|
redirect(URL('default', 'usergroups'))
|
||||||
|
|
||||||
|
|
||||||
@cache('videos', time_expire=cache_expire)
|
@cache('videos', time_expire=cache_expire)
|
||||||
def videos():
|
def videos():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
def security():
|
def security():
|
||||||
redirect('http://www.web2py.com/book/default/chapter/01#security')
|
redirect('http://www.web2py.com/book/default/chapter/01#security')
|
||||||
|
|
||||||
|
|
||||||
def api():
|
def api():
|
||||||
redirect('http://web2py.com/book/default/chapter/04#API')
|
redirect('http://web2py.com/book/default/chapter/04#API')
|
||||||
|
|
||||||
|
|
||||||
@cache('license', time_expire=cache_expire)
|
@cache('license', time_expire=cache_expire)
|
||||||
def license():
|
def license():
|
||||||
import os
|
import os
|
||||||
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
||||||
return response.render(dict(license=MARKMIN(read_file(filename))))
|
return response.render(dict(license=MARKMIN(read_file(filename))))
|
||||||
|
|
||||||
|
|
||||||
def version():
|
def version():
|
||||||
return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version
|
return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version
|
||||||
|
|
||||||
|
|
||||||
@cache('examples', time_expire=cache_expire)
|
@cache('examples', time_expire=cache_expire)
|
||||||
def examples():
|
def examples():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
|
|
||||||
@cache('changelog', time_expire=cache_expire)
|
@cache('changelog', time_expire=cache_expire)
|
||||||
def changelog():
|
def changelog():
|
||||||
import os
|
import os
|
||||||
filename = os.path.join(request.env.gluon_parent, 'CHANGELOG')
|
filename = os.path.join(request.env.gluon_parent, 'CHANGELOG')
|
||||||
return response.render(dict(changelog=MARKMIN(read_file(filename))))
|
return response.render(dict(changelog=MARKMIN(read_file(filename))))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def form():
|
def form():
|
||||||
""" a simple entry form with various types of objects """
|
""" a simple entry form with various types of objects """
|
||||||
|
|
||||||
@@ -15,7 +12,7 @@ def form():
|
|||||||
TR('Profile', TEXTAREA(_name='profile',
|
TR('Profile', TEXTAREA(_name='profile',
|
||||||
value='write something here')),
|
value='write something here')),
|
||||||
TR('', INPUT(_type='submit', _value='SUBMIT')),
|
TR('', INPUT(_type='submit', _value='SUBMIT')),
|
||||||
))
|
))
|
||||||
if form.process().accepted:
|
if form.process().accepted:
|
||||||
response.flash = 'form accepted'
|
response.flash = 'form accepted'
|
||||||
elif form.errors:
|
elif form.errors:
|
||||||
@@ -23,6 +20,3 @@ def form():
|
|||||||
else:
|
else:
|
||||||
response.flash = 'please fill the form'
|
response.flash = 'please fill the form'
|
||||||
return dict(form=form, vars=form.vars)
|
return dict(form=form, vars=form.vars)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
session.forget()
|
session.forget()
|
||||||
|
|
||||||
response.menu = [['home', False, '/%s/default/index'
|
response.menu = [['home', False, '/%s/default/index'
|
||||||
@@ -17,14 +16,14 @@ def vars():
|
|||||||
c,
|
c,
|
||||||
d,
|
d,
|
||||||
value,
|
value,
|
||||||
) = (
|
) = (
|
||||||
'Global variables',
|
'Global variables',
|
||||||
globals(),
|
globals(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
(),
|
(),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
(title, args) = ('globals()', '')
|
(title, args) = ('globals()', '')
|
||||||
elif len(request.args) < 3:
|
elif len(request.args) < 3:
|
||||||
args = '.'.join(request.args)
|
args = '.'.join(request.args)
|
||||||
@@ -76,7 +75,4 @@ def vars():
|
|||||||
d=d,
|
d=d,
|
||||||
doc=doc,
|
doc=doc,
|
||||||
attributes=attributes,
|
attributes=attributes,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
def civilized():
|
def civilized():
|
||||||
response.menu = [['civilized', True, URL('civilized'
|
response.menu = [['civilized', True, URL('civilized'
|
||||||
)], ['slick', False, URL('slick')],
|
)], ['slick', False, URL('slick')],
|
||||||
['basic', False, URL('basic')]]
|
['basic', False, URL('basic')]]
|
||||||
response.flash = 'you clicked on civilized'
|
response.flash = 'you clicked on civilized'
|
||||||
return dict(message='you clicked on civilized')
|
return dict(message='you clicked on civilized')
|
||||||
@@ -8,7 +8,7 @@ def civilized():
|
|||||||
|
|
||||||
def slick():
|
def slick():
|
||||||
response.menu = [['civilized', False, URL('civilized'
|
response.menu = [['civilized', False, URL('civilized'
|
||||||
)], ['slick', True, URL('slick')],
|
)], ['slick', True, URL('slick')],
|
||||||
['basic', False, URL('basic')]]
|
['basic', False, URL('basic')]]
|
||||||
response.flash = 'you clicked on slick'
|
response.flash = 'you clicked on slick'
|
||||||
return dict(message='you clicked on slick')
|
return dict(message='you clicked on slick')
|
||||||
@@ -16,10 +16,7 @@ def slick():
|
|||||||
|
|
||||||
def basic():
|
def basic():
|
||||||
response.menu = [['civilized', False, URL('civilized'
|
response.menu = [['civilized', False, URL('civilized'
|
||||||
)], ['slick', False, URL('slick')],
|
)], ['slick', False, URL('slick')],
|
||||||
['basic', True, URL('basic')]]
|
['basic', True, URL('basic')]]
|
||||||
response.flash = 'you clicked on basic'
|
response.flash = 'you clicked on basic'
|
||||||
return dict(message='you clicked on basic')
|
return dict(message='you clicked on basic')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def counter():
|
def counter():
|
||||||
""" every time you reload, it increases the session.counter """
|
""" every time you reload, it increases the session.counter """
|
||||||
|
|
||||||
@@ -8,6 +5,3 @@ def counter():
|
|||||||
session.counter = 0
|
session.counter = 0
|
||||||
session.counter += 1
|
session.counter += 1
|
||||||
return dict(counter=session.counter)
|
return dict(counter=session.counter)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -102,9 +102,8 @@ def rss_aggregator():
|
|||||||
return rss2.dumps(rss)
|
return rss2.dumps(rss)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ajaxwiki():
|
def ajaxwiki():
|
||||||
default="""
|
default = """
|
||||||
# section
|
# section
|
||||||
|
|
||||||
## subsection
|
## subsection
|
||||||
@@ -129,12 +128,12 @@ Quoted text
|
|||||||
3 | 0 | 0
|
3 | 0 | 0
|
||||||
---------
|
---------
|
||||||
"""
|
"""
|
||||||
form = FORM(TEXTAREA(_id='text',_name='text',value=default),
|
form = FORM(TEXTAREA(_id='text', _name='text', value=default),
|
||||||
INPUT(_type='button',
|
INPUT(_type='button',
|
||||||
_value='markmin',
|
_value='markmin',
|
||||||
_onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
|
_onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
|
||||||
return dict(form=form, html=DIV(_id='html'))
|
return dict(form=form, html=DIV(_id='html'))
|
||||||
|
|
||||||
|
|
||||||
def ajaxwiki_onclick():
|
def ajaxwiki_onclick():
|
||||||
return MARKMIN(request.vars.text).xml()
|
return MARKMIN(request.vars.text).xml()
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from gluon.contrib.spreadsheet import Sheet
|
from gluon.contrib.spreadsheet import Sheet
|
||||||
|
|
||||||
|
|
||||||
def callback():
|
def callback():
|
||||||
return cache.ram('sheet1',lambda:None,None).process(request)
|
return cache.ram('sheet1', lambda: None, None).process(request)
|
||||||
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
sheet = cache.ram('sheet1',lambda:Sheet(10,10,URL('callback')),0)
|
sheet = cache.ram('sheet1', lambda: Sheet(10, 10, URL('callback')), 0)
|
||||||
#sheet.cell('r0c3',value='=r0c0+r0c1+r0c2',readonly=True)
|
#sheet.cell('r0c3',value='=r0c0+r0c1+r0c2',readonly=True)
|
||||||
return dict(sheet=sheet)
|
return dict(sheet=sheet)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def variables():
|
def variables():
|
||||||
return dict(a=10, b=20)
|
return dict(a=10, b=20)
|
||||||
|
|
||||||
@@ -31,6 +28,3 @@ def xml():
|
|||||||
|
|
||||||
def beautify():
|
def beautify():
|
||||||
return dict(message=BEAUTIFY(request))
|
return dict(message=BEAUTIFY(request))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,44 @@
|
|||||||
|
def group_feed_reader(group, mode='div', counter='5'):
|
||||||
def group_feed_reader(group,mode='div',counter='5'):
|
|
||||||
"""parse group feeds"""
|
"""parse group feeds"""
|
||||||
|
|
||||||
url = "http://groups.google.com/group/%s/feed/rss_v2_0_topics.xml?num=%s" %\
|
url = "http://groups.google.com/group/%s/feed/rss_v2_0_topics.xml?num=%s" %\
|
||||||
(group,counter)
|
(group, counter)
|
||||||
from gluon.contrib import feedparser
|
from gluon.contrib import feedparser
|
||||||
g = feedparser.parse(url)
|
g = feedparser.parse(url)
|
||||||
|
|
||||||
if mode == 'div':
|
if mode == 'div':
|
||||||
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title']+' - ' +\
|
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title'] + ' - ' +
|
||||||
entry['author'][entry['author'].rfind('('):],\
|
entry['author'][
|
||||||
_href=entry['link'],_target='_blank'))\
|
entry['author'].rfind('('):],
|
||||||
for entry in g['entries'] ]),\
|
_href=entry['link'], _target='_blank'))
|
||||||
_class="boxInfo",\
|
for entry in g['entries']]),
|
||||||
_style="padding-bottom:5px;"))
|
_class="boxInfo",
|
||||||
|
_style="padding-bottom:5px;"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
html = XML(UL(*[LI(A(entry['title']+' - ' +\
|
html = XML(UL(*[LI(A(entry['title'] + ' - ' +
|
||||||
entry['author'][entry['author'].rfind('('):],\
|
entry['author'][entry['author'].rfind('('):],
|
||||||
_href=entry['link'],_target='_blank'))\
|
_href=entry['link'], _target='_blank'))
|
||||||
for entry in g['entries'] ]))
|
for entry in g['entries']]))
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
|
||||||
def code_feed_reader(project,mode='div'):
|
def code_feed_reader(project, mode='div'):
|
||||||
"""parse code feeds"""
|
"""parse code feeds"""
|
||||||
|
|
||||||
url = "http://code.google.com/feeds/p/%s/hgchanges/basic" % project
|
url = "http://code.google.com/feeds/p/%s/hgchanges/basic" % project
|
||||||
from gluon.contrib import feedparser
|
from gluon.contrib import feedparser
|
||||||
g = feedparser.parse(url)
|
g = feedparser.parse(url)
|
||||||
if mode == 'div':
|
if mode == 'div':
|
||||||
html = XML(DIV(UL(*[LI(A(entry['title'],_href=entry['link'],\
|
html = XML(DIV(UL(*[LI(A(entry['title'], _href=entry['link'],
|
||||||
_target='_blank'))\
|
_target='_blank'))
|
||||||
for entry in g['entries'][0:5]]),\
|
for entry in g['entries'][0:5]]),
|
||||||
_class="boxInfo",\
|
_class="boxInfo",
|
||||||
_style="padding-bottom:5px;"))
|
_style="padding-bottom:5px;"))
|
||||||
else:
|
else:
|
||||||
html = XML(UL(*[LI(A(entry['title'],_href=entry['link'],\
|
html = XML(UL(*[LI(A(entry['title'], _href=entry['link'],
|
||||||
_target='_blank'))\
|
_target='_blank'))
|
||||||
for entry in g['entries'][0:5]]))
|
for entry in g['entries'][0:5]]))
|
||||||
|
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,18 +2,19 @@ import gluon.template
|
|||||||
|
|
||||||
markmin_dict = dict(
|
markmin_dict = dict(
|
||||||
code_python=lambda code: str(CODE(code)),
|
code_python=lambda code: str(CODE(code)),
|
||||||
template=lambda \
|
template=lambda
|
||||||
code:gluon.template.render(code,context=globals()),
|
code: gluon.template.render(code, context=globals()),
|
||||||
sup=lambda \
|
sup=lambda
|
||||||
code:'<sup style="font-size:0.5em;">%s</sup>'%code,
|
code: '<sup style="font-size:0.5em;">%s</sup>' % code,
|
||||||
br=lambda n:'<br>'*int(n),
|
br=lambda n: '<br>' * int(n),
|
||||||
groupdates=lambda group:group_feed_reader(group),
|
groupdates=lambda group: group_feed_reader(group),
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_content(b=None,\
|
|
||||||
c=request.controller,\
|
def get_content(b=None,
|
||||||
f=request.function,\
|
c=request.controller,
|
||||||
l='en',\
|
f=request.function,
|
||||||
|
l='en',
|
||||||
format='markmin'):
|
format='markmin'):
|
||||||
"""Gets and renders the file in
|
"""Gets and renders the file in
|
||||||
<app>/private/content/<lang>/<controller>/<function>/<block>.<format>
|
<app>/private/content/<lang>/<controller>/<function>/<block>.<format>
|
||||||
@@ -21,20 +22,20 @@ def get_content(b=None,\
|
|||||||
|
|
||||||
def openfile():
|
def openfile():
|
||||||
import os
|
import os
|
||||||
path = os.path.join(request.folder,'private','content',l,c,f,b+'.'+format)
|
path = os.path.join(
|
||||||
|
request.folder, 'private', 'content', l, c, f, b + '.' + format)
|
||||||
return open(path)
|
return open(path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
openedfile = openfile()
|
openedfile = openfile()
|
||||||
except Exception, IOError:
|
except Exception, IOError:
|
||||||
l='en'
|
l = 'en'
|
||||||
openedfile = openfile()
|
openedfile = openfile()
|
||||||
|
|
||||||
if format == 'markmin':
|
if format == 'markmin':
|
||||||
html = MARKMIN(str(T(openedfile.read())),markmin_dict)
|
html = MARKMIN(str(T(openedfile.read())), markmin_dict)
|
||||||
else:
|
else:
|
||||||
html = str(T(openedfile.read()))
|
html = str(T(openedfile.read()))
|
||||||
openedfile.close()
|
openedfile.close()
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
response.menu = [
|
response.menu = [
|
||||||
(T('Home'),False,URL('default','index')),
|
(T('Home'), False, URL('default', 'index')),
|
||||||
(T('About'),False,URL('default','what')),
|
(T('About'), False, URL('default', 'what')),
|
||||||
(T('Download'),False,URL('default','download')),
|
(T('Download'), False, URL('default', 'download')),
|
||||||
(T('Docs & Resources'),False,URL('default','documentation')),
|
(T('Docs & Resources'), False, URL('default', 'documentation')),
|
||||||
(T('Support'),False,URL('default','support')),
|
(T('Support'), False, URL('default', 'support')),
|
||||||
(T('Contributors'),False,URL('default','who'))]
|
(T('Contributors'), False, URL('default', 'who'))]
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
## Changes the menu active item
|
## Changes the menu active item
|
||||||
#########################################################################
|
#########################################################################
|
||||||
def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
|
|
||||||
|
|
||||||
|
def toggle_menuclass(cssclass='pressed', menuid='headermenu'):
|
||||||
"""This function changes the menu class to put pressed appearance"""
|
"""This function changes the menu class to put pressed appearance"""
|
||||||
|
|
||||||
positions = dict(
|
positions = dict(
|
||||||
index='',
|
index='',
|
||||||
what='-108px -115px',
|
what='-108px -115px',
|
||||||
download='-211px -115px',
|
download='-211px -115px',
|
||||||
who='-315px -115px',
|
who='-315px -115px',
|
||||||
support='-418px -115px',
|
support='-418px -115px',
|
||||||
documentation='-520px -115px'
|
documentation='-520px -115px'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if request.function in positions.keys():
|
if request.function in positions.keys():
|
||||||
jscript = """
|
jscript = """
|
||||||
@@ -34,12 +35,11 @@ def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
""" % dict(cssclass=cssclass,
|
""" % dict(cssclass=cssclass,
|
||||||
menuid=menuid,
|
menuid=menuid,
|
||||||
function=request.function,
|
function=request.function,
|
||||||
cssposition=positions[request.function]
|
cssposition=positions[request.function]
|
||||||
)
|
)
|
||||||
|
|
||||||
return XML(jscript)
|
return XML(jscript)
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
</li><li>Alvaro Justen (dynamical translations)
|
</li><li>Alvaro Justen (dynamical translations)
|
||||||
</li><li>Anders Roos (file locking)
|
</li><li>Anders Roos (file locking)
|
||||||
</li><li>Andrew Willimott (documentation, TeraData support)
|
</li><li>Andrew Willimott (documentation, TeraData support)
|
||||||
|
</li><li>Andriy Kornatskyy (benchmarks and profiling)
|
||||||
</li><li>Angelo Compagnucci (mobile devices)
|
</li><li>Angelo Compagnucci (mobile devices)
|
||||||
</li><li>Anthony Bastardi (book, poweredby site, multiple contributions)
|
</li><li>Anthony Bastardi (book, poweredby site, multiple contributions)
|
||||||
</li><li>Arun K. Rajeevan (plugin_wiki)
|
</li><li>Arun K. Rajeevan (plugin_wiki)
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
|
|||||||
try:
|
try:
|
||||||
hosts = (http_host, socket.gethostname(),
|
hosts = (http_host, socket.gethostname(),
|
||||||
socket.gethostbyname(http_host),
|
socket.gethostbyname(http_host),
|
||||||
'::1','127.0.0.1','::ffff:127.0.0.1')
|
'::1', '127.0.0.1', '::ffff:127.0.0.1')
|
||||||
except:
|
except:
|
||||||
hosts = (http_host, )
|
hosts = (http_host, )
|
||||||
|
|
||||||
@@ -32,10 +32,10 @@ if request.env.http_x_forwarded_for or request.is_https:
|
|||||||
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"):
|
||||||
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
raise HTTP(200, T('appadmin is disabled because insecure channel'))
|
||||||
|
|
||||||
if (request.application=='admin' and not session.authorized) or \
|
if (request.application == 'admin' and not session.authorized) or \
|
||||||
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
|
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||||
redirect(URL('admin', 'default', 'index',
|
redirect(URL('admin', 'default', 'index',
|
||||||
vars=dict(send=URL(args=request.args,vars=request.vars))))
|
vars=dict(send=URL(args=request.args, vars=request.vars))))
|
||||||
|
|
||||||
ignore_rw = True
|
ignore_rw = True
|
||||||
response.view = 'appadmin.html'
|
response.view = 'appadmin.html'
|
||||||
@@ -95,24 +95,23 @@ def get_query(request):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def query_by_table_type(tablename,db,request=request):
|
def query_by_table_type(tablename, db, request=request):
|
||||||
keyed = hasattr(db[tablename],'_primarykey')
|
keyed = hasattr(db[tablename], '_primarykey')
|
||||||
if keyed:
|
if keyed:
|
||||||
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
firstkey = db[tablename][db[tablename]._primarykey[0]]
|
||||||
cond = '>0'
|
cond = '>0'
|
||||||
if firstkey.type in ['string', 'text']:
|
if firstkey.type in ['string', 'text']:
|
||||||
cond = '!=""'
|
cond = '!=""'
|
||||||
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond)
|
qry = '%s.%s.%s%s' % (
|
||||||
|
request.args[0], request.args[1], firstkey.name, cond)
|
||||||
else:
|
else:
|
||||||
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
qry = '%s.%s.id>0' % tuple(request.args[:2])
|
||||||
return qry
|
return qry
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
# ## list all databases and tables
|
# ## list all databases and tables
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
return dict(databases=databases)
|
return dict(databases=databases)
|
||||||
|
|
||||||
@@ -127,7 +126,7 @@ def insert():
|
|||||||
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
form = SQLFORM(db[table], ignore_rw=ignore_rw)
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
response.flash = T('new record inserted')
|
response.flash = T('new record inserted')
|
||||||
return dict(form=form,table=db[table])
|
return dict(form=form, table=db[table])
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -138,7 +137,8 @@ def insert():
|
|||||||
def download():
|
def download():
|
||||||
import os
|
import os
|
||||||
db = get_database(request)
|
db = get_database(request)
|
||||||
return response.download(request,db)
|
return response.download(request, db)
|
||||||
|
|
||||||
|
|
||||||
def csv():
|
def csv():
|
||||||
import gluon.contenttype
|
import gluon.contenttype
|
||||||
@@ -149,26 +149,27 @@ def csv():
|
|||||||
if not query:
|
if not query:
|
||||||
return None
|
return None
|
||||||
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
|
||||||
% tuple(request.vars.query.split('.')[:2])
|
% tuple(request.vars.query.split('.')[:2])
|
||||||
return str(db(query,ignore_common_filters=True).select())
|
return str(db(query, ignore_common_filters=True).select())
|
||||||
|
|
||||||
|
|
||||||
def import_csv(table, file):
|
def import_csv(table, file):
|
||||||
table.import_from_csv_file(file)
|
table.import_from_csv_file(file)
|
||||||
|
|
||||||
|
|
||||||
def select():
|
def select():
|
||||||
import re
|
import re
|
||||||
db = get_database(request)
|
db = get_database(request)
|
||||||
dbname = request.args[0]
|
dbname = request.args[0]
|
||||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>\d+)')
|
||||||
if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'):
|
if len(request.args) > 1 and hasattr(db[request.args[1]], '_primarykey'):
|
||||||
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
regex = re.compile('(?P<table>\w+)\.(?P<field>\w+)=(?P<value>.+)')
|
||||||
if request.vars.query:
|
if request.vars.query:
|
||||||
match = regex.match(request.vars.query)
|
match = regex.match(request.vars.query)
|
||||||
if match:
|
if match:
|
||||||
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
|
||||||
match.group('table'), match.group('field'),
|
match.group('table'), match.group('field'),
|
||||||
match.group('value'))
|
match.group('value'))
|
||||||
else:
|
else:
|
||||||
request.vars.query = session.last_query
|
request.vars.query = session.last_query
|
||||||
query = get_query(request)
|
query = get_query(request)
|
||||||
@@ -192,46 +193,50 @@ def select():
|
|||||||
session.last_query = request.vars.query
|
session.last_query = request.vars.query
|
||||||
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
|
||||||
_name='query', _value=request.vars.query or '',
|
_name='query', _value=request.vars.query or '',
|
||||||
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'),
|
requires=IS_NOT_EMPTY(
|
||||||
|
error_message=T("Cannot be empty")))), TR(T('Update:'),
|
||||||
INPUT(_name='update_check', _type='checkbox',
|
INPUT(_name='update_check', _type='checkbox',
|
||||||
value=False), INPUT(_style='width:400px',
|
value=False), INPUT(_style='width:400px',
|
||||||
_name='update_fields', _value=request.vars.update_fields
|
_name='update_fields', _value=request.vars.update_fields
|
||||||
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
or '')), TR(T('Delete:'), INPUT(_name='delete_check',
|
||||||
_class='delete', _type='checkbox', value=False), ''),
|
_class='delete', _type='checkbox', value=False), ''),
|
||||||
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
TR('', '', INPUT(_type='submit', _value=T('submit')))),
|
||||||
_action=URL(r=request,args=request.args))
|
_action=URL(r=request, args=request.args))
|
||||||
|
|
||||||
|
tb = None
|
||||||
if form.accepts(request.vars, formname=None):
|
if form.accepts(request.vars, formname=None):
|
||||||
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
|
||||||
match = regex.match(form.vars.query.strip())
|
match = regex.match(form.vars.query.strip())
|
||||||
if match:
|
if match:
|
||||||
table = match.group('table')
|
table = match.group('table')
|
||||||
try:
|
try:
|
||||||
tb = None
|
|
||||||
nrows = db(query).count()
|
nrows = db(query).count()
|
||||||
if form.vars.update_check and form.vars.update_fields:
|
if form.vars.update_check and form.vars.update_fields:
|
||||||
db(query).update(**eval_in_global_env('dict(%s)'
|
db(query).update(**eval_in_global_env('dict(%s)'
|
||||||
% form.vars.update_fields))
|
% form.vars.update_fields))
|
||||||
response.flash = T('%s %%{row} updated', nrows)
|
response.flash = T('%s %%{row} updated', nrows)
|
||||||
elif form.vars.delete_check:
|
elif form.vars.delete_check:
|
||||||
db(query).delete()
|
db(query).delete()
|
||||||
response.flash = T('%s %%{row} deleted', nrows)
|
response.flash = T('%s %%{row} deleted', nrows)
|
||||||
nrows = db(query).count()
|
nrows = db(query).count()
|
||||||
if orderby:
|
if orderby:
|
||||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby))
|
rows = db(query, ignore_common_filters=True).select(limitby=(
|
||||||
|
start, stop), orderby=eval_in_global_env(orderby))
|
||||||
else:
|
else:
|
||||||
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop))
|
rows = db(query, ignore_common_filters=True).select(
|
||||||
|
limitby=(start, stop))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
import traceback
|
import traceback
|
||||||
tb = traceback.format_exc()
|
tb = traceback.format_exc()
|
||||||
(rows, nrows) = ([], 0)
|
(rows, nrows) = ([], 0)
|
||||||
response.flash = DIV(T('Invalid Query'),PRE(str(e)))
|
response.flash = DIV(T('Invalid Query'), PRE(str(e)))
|
||||||
# begin handle upload csv
|
# begin handle upload csv
|
||||||
csv_table = table or request.vars.table
|
csv_table = table or request.vars.table
|
||||||
if csv_table:
|
if csv_table:
|
||||||
formcsv = FORM(str(T('or import from csv file'))+" ",
|
formcsv = FORM(str(T('or import from csv file')) + " ",
|
||||||
INPUT(_type='file',_name='csvfile'),
|
INPUT(_type='file', _name='csvfile'),
|
||||||
INPUT(_type='hidden',_value=csv_table,_name='table'),
|
INPUT(_type='hidden', _value=csv_table, _name='table'),
|
||||||
INPUT(_type='submit',_value=T('import')))
|
INPUT(_type='submit', _value=T('import')))
|
||||||
else:
|
else:
|
||||||
formcsv = None
|
formcsv = None
|
||||||
if formcsv and formcsv.process().accepted:
|
if formcsv and formcsv.process().accepted:
|
||||||
@@ -240,7 +245,7 @@ def select():
|
|||||||
request.vars.csvfile.file)
|
request.vars.csvfile.file)
|
||||||
response.flash = T('data uploaded')
|
response.flash = T('data uploaded')
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
response.flash = DIV(T('unable to parse csv file'),PRE(str(e)))
|
response.flash = DIV(T('unable to parse csv file'), PRE(str(e)))
|
||||||
# end handle upload csv
|
# end handle upload csv
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
@@ -251,9 +256,9 @@ def select():
|
|||||||
nrows=nrows,
|
nrows=nrows,
|
||||||
rows=rows,
|
rows=rows,
|
||||||
query=request.vars.query,
|
query=request.vars.query,
|
||||||
formcsv = formcsv,
|
formcsv=formcsv,
|
||||||
tb = tb,
|
tb=tb,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -263,14 +268,16 @@ def select():
|
|||||||
|
|
||||||
def update():
|
def update():
|
||||||
(db, table) = get_table(request)
|
(db, table) = get_table(request)
|
||||||
keyed = hasattr(db[table],'_primarykey')
|
keyed = hasattr(db[table], '_primarykey')
|
||||||
record = None
|
record = None
|
||||||
if keyed:
|
if keyed:
|
||||||
key = [f for f in request.vars if f in db[table]._primarykey]
|
key = [f for f in request.vars if f in db[table]._primarykey]
|
||||||
if key:
|
if key:
|
||||||
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first()
|
record = db(db[table][key[0]] == request.vars[key[
|
||||||
|
0]], ignore_common_filters=True).select().first()
|
||||||
else:
|
else:
|
||||||
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first()
|
record = db(db[table].id == request.args(
|
||||||
|
2), ignore_common_filters=True).select().first()
|
||||||
|
|
||||||
if not record:
|
if not record:
|
||||||
qry = query_by_table_type(table, db)
|
qry = query_by_table_type(table, db)
|
||||||
@@ -280,20 +287,21 @@ def update():
|
|||||||
|
|
||||||
if keyed:
|
if keyed:
|
||||||
for k in db[table]._primarykey:
|
for k in db[table]._primarykey:
|
||||||
db[table][k].writable=False
|
db[table][k].writable = False
|
||||||
|
|
||||||
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'),
|
form = SQLFORM(
|
||||||
ignore_rw=ignore_rw and not keyed,
|
db[table], record, deletable=True, delete_label=T('Check to delete'),
|
||||||
linkto=URL('select',
|
ignore_rw=ignore_rw and not keyed,
|
||||||
|
linkto=URL('select',
|
||||||
args=request.args[:1]), upload=URL(r=request,
|
args=request.args[:1]), upload=URL(r=request,
|
||||||
f='download', args=request.args[:1]))
|
f='download', args=request.args[:1]))
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
session.flash = T('done!')
|
session.flash = T('done!')
|
||||||
qry = query_by_table_type(table, db)
|
qry = query_by_table_type(table, db)
|
||||||
redirect(URL('select', args=request.args[:1],
|
redirect(URL('select', args=request.args[:1],
|
||||||
vars=dict(query=qry)))
|
vars=dict(query=qry)))
|
||||||
return dict(form=form,table=db[table])
|
return dict(form=form, table=db[table])
|
||||||
|
|
||||||
|
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
@@ -304,11 +312,15 @@ def update():
|
|||||||
def state():
|
def state():
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
|
|
||||||
def ccache():
|
def ccache():
|
||||||
form = FORM(
|
form = FORM(
|
||||||
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
P(TAG.BUTTON(
|
||||||
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
|
||||||
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
P(TAG.BUTTON(
|
||||||
|
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
|
||||||
|
P(TAG.BUTTON(
|
||||||
|
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
|
||||||
)
|
)
|
||||||
|
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
@@ -332,11 +344,16 @@ def ccache():
|
|||||||
redirect(URL(r=request))
|
redirect(URL(r=request))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from guppy import hpy; hp=hpy()
|
from guppy import hpy
|
||||||
|
hp = hpy()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
hp = False
|
hp = False
|
||||||
|
|
||||||
import shelve, os, copy, time, math
|
import shelve
|
||||||
|
import os
|
||||||
|
import copy
|
||||||
|
import time
|
||||||
|
import math
|
||||||
from gluon import portalocker
|
from gluon import portalocker
|
||||||
|
|
||||||
ram = {
|
ram = {
|
||||||
@@ -381,9 +398,10 @@ def ccache():
|
|||||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
|
|
||||||
locker = open(os.path.join(request.folder,
|
locker = open(os.path.join(request.folder,
|
||||||
'cache/cache.lock'), 'a')
|
'cache/cache.lock'), 'a')
|
||||||
portalocker.lock(locker, portalocker.LOCK_EX)
|
portalocker.lock(locker, portalocker.LOCK_EX)
|
||||||
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve'))
|
disk_storage = shelve.open(
|
||||||
|
os.path.join(request.folder, 'cache/cache.shelve'))
|
||||||
try:
|
try:
|
||||||
for key, value in disk_storage.items():
|
for key, value in disk_storage.items():
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
@@ -414,7 +432,8 @@ def ccache():
|
|||||||
total['misses'] = ram['misses'] + disk['misses']
|
total['misses'] = ram['misses'] + disk['misses']
|
||||||
total['keys'] = ram['keys'] + disk['keys']
|
total['keys'] = ram['keys'] + disk['keys']
|
||||||
try:
|
try:
|
||||||
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
|
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||||
|
total['misses'])
|
||||||
except (KeyError, ZeroDivisionError):
|
except (KeyError, ZeroDivisionError):
|
||||||
total['ratio'] = 0
|
total['ratio'] = 0
|
||||||
|
|
||||||
@@ -440,6 +459,3 @@ def ccache():
|
|||||||
|
|
||||||
return dict(form=form, total=total,
|
return dict(form=form, total=total,
|
||||||
ram=ram, disk=disk, object_stats=hp != False)
|
ram=ram, disk=disk, object_stats=hp != False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
## - call exposes all registered services (none by default)
|
## - call exposes all registered services (none by default)
|
||||||
#########################################################################
|
#########################################################################
|
||||||
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
"""
|
"""
|
||||||
example action using the internationalization operator T and flash
|
example action using the internationalization operator T and flash
|
||||||
@@ -20,6 +21,7 @@ def index():
|
|||||||
response.flash = T("Welcome to web2py!")
|
response.flash = T("Welcome to web2py!")
|
||||||
return dict(message=T('Hello World'))
|
return dict(message=T('Hello World'))
|
||||||
|
|
||||||
|
|
||||||
def user():
|
def user():
|
||||||
"""
|
"""
|
||||||
exposes:
|
exposes:
|
||||||
@@ -42,7 +44,7 @@ def download():
|
|||||||
allows downloading of uploaded files
|
allows downloading of uploaded files
|
||||||
http://..../[app]/default/download/[filename]
|
http://..../[app]/default/download/[filename]
|
||||||
"""
|
"""
|
||||||
return response.download(request,db)
|
return response.download(request, db)
|
||||||
|
|
||||||
|
|
||||||
def call():
|
def call():
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
'export as csv file': 'експортувати як файл csv',
|
'export as csv file': 'експортувати як файл csv',
|
||||||
'FAQ': 'ЧаПи (FAQ)',
|
'FAQ': 'ЧаПи (FAQ)',
|
||||||
'First name': "Ім'я",
|
'First name': "Ім'я",
|
||||||
|
'Forgot username?': "Забули ім'я користувача?",
|
||||||
'Forms and Validators': 'Форми та коректність даних',
|
'Forms and Validators': 'Форми та коректність даних',
|
||||||
'Free Applications': 'Вільні додатки',
|
'Free Applications': 'Вільні додатки',
|
||||||
'Group %(group_id)s created': 'Групу %(group_id)s створено',
|
'Group %(group_id)s created': 'Групу %(group_id)s створено',
|
||||||
|
|||||||
@@ -11,12 +11,12 @@
|
|||||||
|
|
||||||
if not request.env.web2py_runtime_gae:
|
if not request.env.web2py_runtime_gae:
|
||||||
## if NOT running on Google App Engine use SQLite or other DB
|
## if NOT running on Google App Engine use SQLite or other DB
|
||||||
db = DAL('sqlite://storage.sqlite')
|
db = DAL('sqlite://storage.sqlite')
|
||||||
else:
|
else:
|
||||||
## connect to Google BigTable (optional 'google:datastore://namespace')
|
## connect to Google BigTable (optional 'google:datastore://namespace')
|
||||||
db = DAL('google:datastore')
|
db = DAL('google:datastore')
|
||||||
## store sessions and tickets there
|
## store sessions and tickets there
|
||||||
session.connect(request, response, db = db)
|
session.connect(request, response, db=db)
|
||||||
## or store session in Memcache, Redis, etc.
|
## or store session in Memcache, Redis, etc.
|
||||||
## from gluon.contrib.memdb import MEMDB
|
## from gluon.contrib.memdb import MEMDB
|
||||||
## from google.appengine.api.memcache import Client
|
## from google.appengine.api.memcache import Client
|
||||||
@@ -47,7 +47,7 @@ crud, service, plugins = Crud(db), Service(), PluginManager()
|
|||||||
auth.define_tables(username=False, signature=False)
|
auth.define_tables(username=False, signature=False)
|
||||||
|
|
||||||
## configure email
|
## configure email
|
||||||
mail=auth.settings.mailer
|
mail = auth.settings.mailer
|
||||||
mail.settings.server = 'logging' or 'smtp.gmail.com:587'
|
mail.settings.server = 'logging' or 'smtp.gmail.com:587'
|
||||||
mail.settings.sender = 'you@gmail.com'
|
mail.settings.sender = 'you@gmail.com'
|
||||||
mail.settings.login = 'username:password'
|
mail.settings.login = 'username:password'
|
||||||
@@ -60,7 +60,7 @@ auth.settings.reset_password_requires_verification = True
|
|||||||
## if you need to use OpenID, Facebook, MySpace, Twitter, Linkedin, etc.
|
## if you need to use OpenID, Facebook, MySpace, Twitter, Linkedin, etc.
|
||||||
## register with janrain.com, write your domain:api_key in private/janrain.key
|
## register with janrain.com, write your domain:api_key in private/janrain.key
|
||||||
from gluon.contrib.login_methods.rpx_account import use_janrain
|
from gluon.contrib.login_methods.rpx_account import use_janrain
|
||||||
use_janrain(auth,filename='private/janrain.key')
|
use_janrain(auth, filename='private/janrain.key')
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
## Define your tables below (or better in another model file) for example
|
## Define your tables below (or better in another model file) for example
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
## Customize your APP title, subtitle and menus here
|
## Customize your APP title, subtitle and menus here
|
||||||
#########################################################################
|
#########################################################################
|
||||||
|
|
||||||
response.title = ' '.join(word.capitalize() for word in request.application.split('_'))
|
response.title = ' '.join(
|
||||||
|
word.capitalize() for word in request.application.split('_'))
|
||||||
response.subtitle = T('customize me!')
|
response.subtitle = T('customize me!')
|
||||||
|
|
||||||
## read more at http://dev.w3.org/html5/markup/meta.name.html
|
## read more at http://dev.w3.org/html5/markup/meta.name.html
|
||||||
@@ -22,80 +23,114 @@ response.google_analytics_id = None
|
|||||||
#########################################################################
|
#########################################################################
|
||||||
|
|
||||||
response.menu = [
|
response.menu = [
|
||||||
(T('Home'), False, URL('default','index'), [])
|
(T('Home'), False, URL('default', 'index'), [])
|
||||||
]
|
]
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
## provide shortcuts for development. remove in production
|
## provide shortcuts for development. remove in production
|
||||||
#########################################################################
|
#########################################################################
|
||||||
|
|
||||||
|
|
||||||
def _():
|
def _():
|
||||||
# shortcuts
|
# shortcuts
|
||||||
app = request.application
|
app = request.application
|
||||||
ctr = request.controller
|
ctr = request.controller
|
||||||
# useful links to internal and external resources
|
# useful links to internal and external resources
|
||||||
response.menu+=[
|
response.menu += [
|
||||||
(SPAN('web2py',_class='highlighted'),False, 'http://web2py.com', [
|
(SPAN('web2py', _class='highlighted'), False, 'http://web2py.com', [
|
||||||
(T('My Sites'),False,URL('admin','default','site')),
|
(T('My Sites'), False, URL('admin', 'default', 'site')),
|
||||||
(T('This App'),False,URL('admin','default','design/%s' % app), [
|
(T('This App'), False, URL('admin', 'default', 'design/%s' % app), [
|
||||||
(T('Controller'),False,
|
(T('Controller'), False,
|
||||||
URL('admin','default','edit/%s/controllers/%s.py' % (app,ctr))),
|
URL(
|
||||||
(T('View'),False,
|
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
|
||||||
URL('admin','default','edit/%s/views/%s' % (app,response.view))),
|
(T('View'), False,
|
||||||
(T('Layout'),False,
|
URL(
|
||||||
URL('admin','default','edit/%s/views/layout.html' % app)),
|
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
|
||||||
(T('Stylesheet'),False,
|
(T('Layout'), False,
|
||||||
URL('admin','default','edit/%s/static/css/web2py.css' % app)),
|
URL(
|
||||||
(T('DB Model'),False,
|
'admin', 'default', 'edit/%s/views/layout.html' % app)),
|
||||||
URL('admin','default','edit/%s/models/db.py' % app)),
|
(T('Stylesheet'), False,
|
||||||
(T('Menu Model'),False,
|
URL(
|
||||||
URL('admin','default','edit/%s/models/menu.py' % app)),
|
'admin', 'default', 'edit/%s/static/css/web2py.css' % app)),
|
||||||
(T('Database'),False, URL(app,'appadmin','index')),
|
(T('DB Model'), False,
|
||||||
(T('Errors'),False, URL('admin','default','errors/' + app)),
|
URL(
|
||||||
(T('About'),False, URL('admin','default','about/' + app)),
|
'admin', 'default', 'edit/%s/models/db.py' % app)),
|
||||||
|
(T('Menu Model'), False,
|
||||||
|
URL(
|
||||||
|
'admin', 'default', 'edit/%s/models/menu.py' % app)),
|
||||||
|
(T('Database'), False, URL(app, 'appadmin', 'index')),
|
||||||
|
(T('Errors'), False, URL(
|
||||||
|
'admin', 'default', 'errors/' + app)),
|
||||||
|
(T('About'), False, URL(
|
||||||
|
'admin', 'default', 'about/' + app)),
|
||||||
|
]),
|
||||||
|
('web2py.com', False, 'http://www.web2py.com', [
|
||||||
|
(T('Download'), False,
|
||||||
|
'http://www.web2py.com/examples/default/download'),
|
||||||
|
(T('Support'), False,
|
||||||
|
'http://www.web2py.com/examples/default/support'),
|
||||||
|
(T('Demo'), False, 'http://web2py.com/demo_admin'),
|
||||||
|
(T('Quick Examples'), False,
|
||||||
|
'http://web2py.com/examples/default/examples'),
|
||||||
|
(T('FAQ'), False, 'http://web2py.com/AlterEgo'),
|
||||||
|
(T('Videos'), False,
|
||||||
|
'http://www.web2py.com/examples/default/videos/'),
|
||||||
|
(T('Free Applications'),
|
||||||
|
False, 'http://web2py.com/appliances'),
|
||||||
|
(T('Plugins'), False, 'http://web2py.com/plugins'),
|
||||||
|
(T('Layouts'), False, 'http://web2py.com/layouts'),
|
||||||
|
(T('Recipes'), False, 'http://web2pyslices.com/'),
|
||||||
|
(T('Semantic'), False, 'http://web2py.com/semantic'),
|
||||||
|
]),
|
||||||
|
(T('Documentation'), False, 'http://www.web2py.com/book', [
|
||||||
|
(T('Preface'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/00'),
|
||||||
|
(T('Introduction'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/01'),
|
||||||
|
(T('Python'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/02'),
|
||||||
|
(T('Overview'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/03'),
|
||||||
|
(T('The Core'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/04'),
|
||||||
|
(T('The Views'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/05'),
|
||||||
|
(T('Database'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/06'),
|
||||||
|
(T('Forms and Validators'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/07'),
|
||||||
|
(T('Email and SMS'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/08'),
|
||||||
|
(T('Access Control'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/09'),
|
||||||
|
(T('Services'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/10'),
|
||||||
|
(T('Ajax Recipes'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/11'),
|
||||||
|
(T('Components and Plugins'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/12'),
|
||||||
|
(T('Deployment Recipes'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/13'),
|
||||||
|
(T('Other Recipes'), False,
|
||||||
|
'http://www.web2py.com/book/default/chapter/14'),
|
||||||
|
(T('Buy this book'), False,
|
||||||
|
'http://stores.lulu.com/web2py'),
|
||||||
|
]),
|
||||||
|
(T('Community'), False, None, [
|
||||||
|
(T('Groups'), False,
|
||||||
|
'http://www.web2py.com/examples/default/usergroups'),
|
||||||
|
(T('Twitter'), False, 'http://twitter.com/web2py'),
|
||||||
|
(T('Live Chat'), False,
|
||||||
|
'http://webchat.freenode.net/?channels=web2py'),
|
||||||
]),
|
]),
|
||||||
('web2py.com',False,'http://www.web2py.com', [
|
(T('Plugins'), False, None, [
|
||||||
(T('Download'),False,'http://www.web2py.com/examples/default/download'),
|
('plugin_wiki', False,
|
||||||
(T('Support'),False,'http://www.web2py.com/examples/default/support'),
|
'http://web2py.com/examples/default/download'),
|
||||||
(T('Demo'),False,'http://web2py.com/demo_admin'),
|
(T('Other Plugins'), False,
|
||||||
(T('Quick Examples'),False,'http://web2py.com/examples/default/examples'),
|
'http://web2py.com/plugins'),
|
||||||
(T('FAQ'),False,'http://web2py.com/AlterEgo'),
|
(T('Layout Plugins'),
|
||||||
(T('Videos'),False,'http://www.web2py.com/examples/default/videos/'),
|
False, 'http://web2py.com/layouts'),
|
||||||
(T('Free Applications'),False,'http://web2py.com/appliances'),
|
|
||||||
(T('Plugins'),False,'http://web2py.com/plugins'),
|
|
||||||
(T('Layouts'),False,'http://web2py.com/layouts'),
|
|
||||||
(T('Recipes'),False,'http://web2pyslices.com/'),
|
|
||||||
(T('Semantic'),False,'http://web2py.com/semantic'),
|
|
||||||
]),
|
|
||||||
(T('Documentation'),False,'http://www.web2py.com/book', [
|
|
||||||
(T('Preface'),False,'http://www.web2py.com/book/default/chapter/00'),
|
|
||||||
(T('Introduction'),False,'http://www.web2py.com/book/default/chapter/01'),
|
|
||||||
(T('Python'),False,'http://www.web2py.com/book/default/chapter/02'),
|
|
||||||
(T('Overview'),False,'http://www.web2py.com/book/default/chapter/03'),
|
|
||||||
(T('The Core'),False,'http://www.web2py.com/book/default/chapter/04'),
|
|
||||||
(T('The Views'),False,'http://www.web2py.com/book/default/chapter/05'),
|
|
||||||
(T('Database'),False,'http://www.web2py.com/book/default/chapter/06'),
|
|
||||||
(T('Forms and Validators'),False,'http://www.web2py.com/book/default/chapter/07'),
|
|
||||||
(T('Email and SMS'),False,'http://www.web2py.com/book/default/chapter/08'),
|
|
||||||
(T('Access Control'),False,'http://www.web2py.com/book/default/chapter/09'),
|
|
||||||
(T('Services'),False,'http://www.web2py.com/book/default/chapter/10'),
|
|
||||||
(T('Ajax Recipes'),False,'http://www.web2py.com/book/default/chapter/11'),
|
|
||||||
(T('Components and Plugins'),False,'http://www.web2py.com/book/default/chapter/12'),
|
|
||||||
(T('Deployment Recipes'),False,'http://www.web2py.com/book/default/chapter/13'),
|
|
||||||
(T('Other Recipes'),False,'http://www.web2py.com/book/default/chapter/14'),
|
|
||||||
(T('Buy this book'),False,'http://stores.lulu.com/web2py'),
|
|
||||||
]),
|
|
||||||
(T('Community'),False, None, [
|
|
||||||
(T('Groups'),False,'http://www.web2py.com/examples/default/usergroups'),
|
|
||||||
(T('Twitter'),False,'http://twitter.com/web2py'),
|
|
||||||
(T('Live Chat'),False,'http://webchat.freenode.net/?channels=web2py'),
|
|
||||||
]),
|
|
||||||
(T('Plugins'),False,None, [
|
|
||||||
('plugin_wiki',False,'http://web2py.com/examples/default/download'),
|
|
||||||
(T('Other Plugins'),False,'http://web2py.com/plugins'),
|
|
||||||
(T('Layout Plugins'),False,'http://web2py.com/layouts'),
|
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
)]
|
)]
|
||||||
_()
|
_()
|
||||||
|
|
||||||
|
|||||||
@@ -37,4 +37,3 @@ routers = {
|
|||||||
#NOTE! To change language in your application using these rules add this line
|
#NOTE! To change language in your application using these rules add this line
|
||||||
#in one of your models files:
|
#in one of your models files:
|
||||||
# if request.uri_language: T.force(request.uri_language)
|
# if request.uri_language: T.force(request.uri_language)
|
||||||
|
|
||||||
|
|||||||
+1
-6
@@ -56,13 +56,8 @@ import wsgiref.handlers
|
|||||||
|
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
os.chdir(path)
|
os.chdir(path)
|
||||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||||
|
|
||||||
import gluon.main
|
import gluon.main
|
||||||
|
|
||||||
wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase)
|
wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-6
@@ -34,7 +34,7 @@ import os
|
|||||||
|
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
os.chdir(path)
|
os.chdir(path)
|
||||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||||
|
|
||||||
import gluon.main
|
import gluon.main
|
||||||
import gluon.contrib.gateways.fcgi as fcgi
|
import gluon.contrib.gateways.fcgi as fcgi
|
||||||
@@ -51,8 +51,3 @@ if SOFTCRON:
|
|||||||
global_settings.web2py_crontype = 'soft'
|
global_settings.web2py_crontype = 'soft'
|
||||||
|
|
||||||
fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run()
|
fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
-7
@@ -33,7 +33,7 @@ import wsgiref.handlers
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
path = os.path.dirname(os.path.abspath(__file__))
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path = [path]+[p for p in sys.path if not p==path]
|
sys.path = [path] + [p for p in sys.path if not p == path]
|
||||||
|
|
||||||
sys.modules['cPickle'] = sys.modules['pickle']
|
sys.modules['cPickle'] = sys.modules['pickle']
|
||||||
|
|
||||||
@@ -78,12 +78,18 @@ def wsgiapp(env, res):
|
|||||||
"""Return the wsgiapp"""
|
"""Return the wsgiapp"""
|
||||||
env['PATH_INFO'] = env['PATH_INFO'].decode('latin1').encode('utf8')
|
env['PATH_INFO'] = env['PATH_INFO'].decode('latin1').encode('utf8')
|
||||||
|
|
||||||
|
#when using the blobstore image uploader GAE dev SDK passes these as unicode
|
||||||
|
# they should be regular strings as they are parts of URLs
|
||||||
|
env['wsgi.url_scheme'] = str(env['wsgi.url_scheme'])
|
||||||
|
env['QUERY_STRING'] = str(env['QUERY_STRING'])
|
||||||
|
env['SERVER_NAME'] = str(env['SERVER_NAME'])
|
||||||
|
|
||||||
#this deals with a problem where GAE development server seems to forget
|
#this deals with a problem where GAE development server seems to forget
|
||||||
# the path between requests
|
# the path between requests
|
||||||
if global_settings.web2py_runtime == 'gae:development':
|
if global_settings.web2py_runtime == 'gae:development':
|
||||||
gluon.admin.create_missing_folders()
|
gluon.admin.create_missing_folders()
|
||||||
|
|
||||||
web2py_path = global_settings.applications_parent # backward compatibility
|
web2py_path = global_settings.applications_parent # backward compatibility
|
||||||
|
|
||||||
return gluon.main.wsgibase(env, res)
|
return gluon.main.wsgibase(env, res)
|
||||||
|
|
||||||
@@ -91,14 +97,10 @@ def wsgiapp(env, res):
|
|||||||
if LOG_STATS or DEBUG:
|
if LOG_STATS or DEBUG:
|
||||||
wsgiapp = log_stats(wsgiapp)
|
wsgiapp = log_stats(wsgiapp)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run the wsgi app"""
|
"""Run the wsgi app"""
|
||||||
run_wsgi_app(wsgiapp)
|
run_wsgi_app(wsgiapp)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-12
@@ -10,7 +10,7 @@ Web2Py framework modules
|
|||||||
========================
|
========================
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['A', 'B', 'BEAUTIFY', 'BODY', 'BR', 'CAT', 'CENTER', 'CLEANUP', 'CODE', 'CRYPT', 'DAL', 'DIV', 'EM', 'EMBED', 'FIELDSET', 'FORM', 'Field', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HR', 'HTML', 'HTTP', 'I', 'IFRAME', 'IMG', 'INPUT', 'IS_ALPHANUMERIC', 'IS_DATE', 'IS_DATETIME', 'IS_DATETIME_IN_RANGE', 'IS_DATE_IN_RANGE', 'IS_DECIMAL_IN_RANGE', 'IS_EMAIL', 'IS_EMPTY_OR', 'IS_EQUAL_TO', 'IS_EXPR', 'IS_FLOAT_IN_RANGE', 'IS_IMAGE', 'IS_INT_IN_RANGE', 'IS_IN_DB', 'IS_IN_SET', 'IS_IPV4', 'IS_LENGTH', 'IS_LIST_OF', 'IS_LOWER', 'IS_MATCH', 'IS_NOT_EMPTY', 'IS_NOT_IN_DB', 'IS_NULL_OR', 'IS_SLUG', 'IS_STRONG', 'IS_TIME', 'IS_UPLOAD_FILENAME', 'IS_UPPER', 'IS_URL', 'LABEL', 'LEGEND', 'LI', 'LINK', 'LOAD', 'MARKMIN', 'MENU', 'META', 'OBJECT', 'OL', 'ON', 'OPTGROUP', 'OPTION', 'P', 'PRE', 'SCRIPT', 'SELECT', 'SPAN', 'SQLFORM', 'SQLTABLE', 'STRONG', 'STYLE', 'TABLE', 'TAG', 'TBODY', 'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TT', 'UL', 'URL', 'XHTML', 'XML','redirect','current','embed64']
|
__all__ = ['A', 'B', 'BEAUTIFY', 'BODY', 'BR', 'CAT', 'CENTER', 'CLEANUP', 'CODE', 'CRYPT', 'DAL', 'DIV', 'EM', 'EMBED', 'FIELDSET', 'FORM', 'Field', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEAD', 'HR', 'HTML', 'HTTP', 'I', 'IFRAME', 'IMG', 'INPUT', 'IS_ALPHANUMERIC', 'IS_DATE', 'IS_DATETIME', 'IS_DATETIME_IN_RANGE', 'IS_DATE_IN_RANGE', 'IS_DECIMAL_IN_RANGE', 'IS_EMAIL', 'IS_EMPTY_OR', 'IS_EQUAL_TO', 'IS_EXPR', 'IS_FLOAT_IN_RANGE', 'IS_IMAGE', 'IS_INT_IN_RANGE', 'IS_IN_DB', 'IS_IN_SET', 'IS_IPV4', 'IS_LENGTH', 'IS_LIST_OF', 'IS_LOWER', 'IS_MATCH', 'IS_NOT_EMPTY', 'IS_NOT_IN_DB', 'IS_NULL_OR', 'IS_SLUG', 'IS_STRONG', 'IS_TIME', 'IS_UPLOAD_FILENAME', 'IS_UPPER', 'IS_URL', 'LABEL', 'LEGEND', 'LI', 'LINK', 'LOAD', 'MARKMIN', 'MENU', 'META', 'OBJECT', 'OL', 'ON', 'OPTGROUP', 'OPTION', 'P', 'PRE', 'SCRIPT', 'SELECT', 'SPAN', 'SQLFORM', 'SQLTABLE', 'STRONG', 'STYLE', 'TABLE', 'TAG', 'TBODY', 'TD', 'TEXTAREA', 'TFOOT', 'TH', 'THEAD', 'TITLE', 'TR', 'TT', 'UL', 'URL', 'XHTML', 'XML', 'redirect', 'current', 'embed64']
|
||||||
|
|
||||||
from globals import current
|
from globals import current
|
||||||
from html import *
|
from html import *
|
||||||
@@ -42,14 +42,3 @@ if 0:
|
|||||||
mail = Mail()
|
mail = Mail()
|
||||||
service = Service()
|
service = Service()
|
||||||
plugins = PluginManager()
|
plugins = PluginManager()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+31
-25
@@ -23,6 +23,7 @@ from http import HTTP
|
|||||||
if not global_settings.web2py_runtime_gae:
|
if not global_settings.web2py_runtime_gae:
|
||||||
import site
|
import site
|
||||||
|
|
||||||
|
|
||||||
def apath(path='', r=None):
|
def apath(path='', r=None):
|
||||||
"""
|
"""
|
||||||
Builds a path inside an application folder
|
Builds a path inside an application folder
|
||||||
@@ -95,6 +96,7 @@ def app_pack_compiled(app, request, raise_ex=False):
|
|||||||
raise
|
raise
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def app_cleanup(app, request):
|
def app_cleanup(app, request):
|
||||||
"""
|
"""
|
||||||
Removes session, cache and error files
|
Removes session, cache and error files
|
||||||
@@ -113,7 +115,7 @@ def app_cleanup(app, request):
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
try:
|
try:
|
||||||
if f[:1]!='.': os.unlink(os.path.join(path,f))
|
if f[:1] != '.': os.unlink(os.path.join(path, f))
|
||||||
except IOError:
|
except IOError:
|
||||||
r = False
|
r = False
|
||||||
|
|
||||||
@@ -122,7 +124,7 @@ def app_cleanup(app, request):
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
try:
|
try:
|
||||||
if f[:1]!='.': recursive_unlink(os.path.join(path,f))
|
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
|
||||||
except IOError:
|
except IOError:
|
||||||
r = False
|
r = False
|
||||||
|
|
||||||
@@ -131,7 +133,7 @@ def app_cleanup(app, request):
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
try:
|
try:
|
||||||
if f[:1]!='.': os.unlink(os.path.join(path,f))
|
if f[:1] != '.': os.unlink(os.path.join(path, f))
|
||||||
except IOError:
|
except IOError:
|
||||||
r = False
|
r = False
|
||||||
return r
|
return r
|
||||||
@@ -158,7 +160,8 @@ def app_compile(app, request):
|
|||||||
remove_compiled_application(folder)
|
remove_compiled_application(folder)
|
||||||
return tb
|
return tb
|
||||||
|
|
||||||
def app_create(app, request,force=False,key=None,info=False):
|
|
||||||
|
def app_create(app, request, force=False, key=None, info=False):
|
||||||
"""
|
"""
|
||||||
Create a copy of welcome.w2p (scaffolding) app
|
Create a copy of welcome.w2p (scaffolding) app
|
||||||
|
|
||||||
@@ -186,17 +189,17 @@ def app_create(app, request,force=False,key=None,info=False):
|
|||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
w2p_unpack('welcome.w2p', path)
|
w2p_unpack('welcome.w2p', path)
|
||||||
for subfolder in ['models','views','controllers', 'databases',
|
for subfolder in ['models', 'views', 'controllers', 'databases',
|
||||||
'modules','cron','errors','sessions',
|
'modules', 'cron', 'errors', 'sessions',
|
||||||
'languages','static','private','uploads']:
|
'languages', 'static', 'private', 'uploads']:
|
||||||
subpath = os.path.join(path,subfolder)
|
subpath = os.path.join(path, subfolder)
|
||||||
if not os.path.exists(subpath):
|
if not os.path.exists(subpath):
|
||||||
os.mkdir(subpath)
|
os.mkdir(subpath)
|
||||||
db = os.path.join(path, 'models', 'db.py')
|
db = os.path.join(path, 'models', 'db.py')
|
||||||
if os.path.exists(db):
|
if os.path.exists(db):
|
||||||
data = read_file(db)
|
data = read_file(db)
|
||||||
data = data.replace('<your secret key>',
|
data = data.replace('<your secret key>',
|
||||||
'sha512:'+(key or web2py_uuid()))
|
'sha512:' + (key or web2py_uuid()))
|
||||||
write_file(db, data)
|
write_file(db, data)
|
||||||
if info:
|
if info:
|
||||||
return True, None
|
return True, None
|
||||||
@@ -283,6 +286,7 @@ def app_uninstall(app, request):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def plugin_pack(app, plugin_name, request):
|
def plugin_pack(app, plugin_name, request):
|
||||||
"""
|
"""
|
||||||
Builds a w2p package for the application
|
Builds a w2p package for the application
|
||||||
@@ -302,12 +306,14 @@ def plugin_pack(app, plugin_name, request):
|
|||||||
filename of the w2p file or None on error
|
filename of the w2p file or None on error
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
filename = apath('../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
|
filename = apath(
|
||||||
|
'../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
|
||||||
w2p_pack_plugin(filename, apath(app, request), plugin_name)
|
w2p_pack_plugin(filename, apath(app, request), plugin_name)
|
||||||
return filename
|
return filename
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def plugin_install(app, fobj, request, filename):
|
def plugin_install(app, fobj, request, filename):
|
||||||
"""
|
"""
|
||||||
Installs an application:
|
Installs an application:
|
||||||
@@ -345,6 +351,7 @@ def plugin_install(app, fobj, request, filename):
|
|||||||
os.unlink(upname)
|
os.unlink(upname)
|
||||||
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.
|
||||||
@@ -375,6 +382,7 @@ def check_new_version(myversion, version_URL):
|
|||||||
else:
|
else:
|
||||||
return False, version
|
return False, version
|
||||||
|
|
||||||
|
|
||||||
def unzip(filename, dir, subfolder=''):
|
def unzip(filename, dir, subfolder=''):
|
||||||
"""
|
"""
|
||||||
Unzips filename into dir (.zip only, no .gz etc)
|
Unzips filename into dir (.zip only, no .gz etc)
|
||||||
@@ -382,7 +390,7 @@ def unzip(filename, dir, subfolder=''):
|
|||||||
"""
|
"""
|
||||||
filename = abspath(filename)
|
filename = abspath(filename)
|
||||||
if not zipfile.is_zipfile(filename):
|
if not zipfile.is_zipfile(filename):
|
||||||
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 = subfolder + '/'
|
||||||
@@ -392,7 +400,7 @@ def unzip(filename, dir, subfolder=''):
|
|||||||
continue
|
continue
|
||||||
#print name[n:]
|
#print name[n:]
|
||||||
if name.endswith('/'):
|
if name.endswith('/'):
|
||||||
folder = os.path.join(dir,name[n:])
|
folder = os.path.join(dir, name[n:])
|
||||||
if not os.path.exists(folder):
|
if not os.path.exists(folder):
|
||||||
os.mkdir(folder)
|
os.mkdir(folder)
|
||||||
else:
|
else:
|
||||||
@@ -421,7 +429,7 @@ def upgrade(request, url='http://web2py.com'):
|
|||||||
if not gluon_parent.endswith('/'):
|
if not gluon_parent.endswith('/'):
|
||||||
gluon_parent = 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')):
|
||||||
@@ -442,42 +450,40 @@ def upgrade(request, url='http://web2py.com'):
|
|||||||
file = None
|
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:
|
||||||
return False, e
|
return False, e
|
||||||
try:
|
try:
|
||||||
unzip(filename, destination, subfolder)
|
unzip(filename, destination, subfolder)
|
||||||
return True, None
|
return True, None
|
||||||
except Exception,e:
|
except Exception, e:
|
||||||
return False, e
|
return False, e
|
||||||
|
|
||||||
|
|
||||||
def add_path_first(path):
|
def add_path_first(path):
|
||||||
sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))]
|
sys.path = [path] + [p for p in sys.path if (
|
||||||
|
not p == path and not p == (path + '/'))]
|
||||||
if not global_settings.web2py_runtime_gae:
|
if not global_settings.web2py_runtime_gae:
|
||||||
site.addsitedir(path)
|
site.addsitedir(path)
|
||||||
|
|
||||||
|
|
||||||
def create_missing_folders():
|
def create_missing_folders():
|
||||||
if not global_settings.web2py_runtime_gae:
|
if not global_settings.web2py_runtime_gae:
|
||||||
for path in ('applications', 'deposit', 'site-packages', 'logs'):
|
for path in ('applications', 'deposit', 'site-packages', 'logs'):
|
||||||
path = abspath(path, gluon=True)
|
path = abspath(path, gluon=True)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
paths = (global_settings.gluon_parent, abspath(
|
||||||
|
'site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
||||||
[add_path_first(path) for path in paths]
|
[add_path_first(path) for path in paths]
|
||||||
|
|
||||||
|
|
||||||
def create_missing_app_folders(request):
|
def create_missing_app_folders(request):
|
||||||
if not global_settings.web2py_runtime_gae:
|
if not global_settings.web2py_runtime_gae:
|
||||||
if request.folder not in global_settings.app_folders:
|
if request.folder not in global_settings.app_folders:
|
||||||
for subfolder in ('models', 'views', 'controllers', 'databases',
|
for subfolder in ('models', 'views', 'controllers', 'databases',
|
||||||
'modules', 'cron', 'errors', 'sessions',
|
'modules', 'cron', 'errors', 'sessions',
|
||||||
'languages', 'static', 'private', 'uploads'):
|
'languages', 'static', 'private', 'uploads'):
|
||||||
path = os.path.join(request.folder, subfolder)
|
path = os.path.join(request.folder, subfolder)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
global_settings.app_folders.add(request.folder)
|
global_settings.app_folders.add(request.folder)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+50
-41
@@ -40,19 +40,20 @@ __all__ = ['Cache', 'lazy_cache']
|
|||||||
|
|
||||||
DEFAULT_TIME_EXPIRE = 300
|
DEFAULT_TIME_EXPIRE = 300
|
||||||
|
|
||||||
|
|
||||||
class CacheAbstract(object):
|
class CacheAbstract(object):
|
||||||
"""
|
"""
|
||||||
Abstract class for cache implementations.
|
Abstract class for cache implementations.
|
||||||
Main function is now to provide referenced api documentation.
|
Main function is now to provide referenced api documentation.
|
||||||
|
|
||||||
Use CacheInRam or CacheOnDisk instead which are derived from this class.
|
Use CacheInRam or CacheOnDisk instead which are derived from this class.
|
||||||
|
|
||||||
Attentions, Michele says:
|
Attentions, Michele says:
|
||||||
|
|
||||||
There are signatures inside gdbm files that are used directly
|
There are signatures inside gdbm files that are used directly
|
||||||
by the python gdbm adapter that often are lagging behind in the
|
by the python gdbm adapter that often are lagging behind in the
|
||||||
detection code in python part.
|
detection code in python part.
|
||||||
On every occasion that a gdbm store is probed by the python adapter,
|
On every occasion that a gdbm store is probed by the python adapter,
|
||||||
the probe fails, because gdbm file version is newer.
|
the probe fails, because gdbm file version is newer.
|
||||||
Using gdbm directly from C would work, because there is backward
|
Using gdbm directly from C would work, because there is backward
|
||||||
compatibility, but not from python!
|
compatibility, but not from python!
|
||||||
@@ -73,7 +74,7 @@ class CacheAbstract(object):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __call__(self, key, f,
|
def __call__(self, key, f,
|
||||||
time_expire = DEFAULT_TIME_EXPIRE):
|
time_expire=DEFAULT_TIME_EXPIRE):
|
||||||
"""
|
"""
|
||||||
Tries retrieve the value corresponding to `key` from the cache of the
|
Tries retrieve the value corresponding to `key` from the cache of the
|
||||||
object exists and if it did not expire, else it called the function `f`
|
object exists and if it did not expire, else it called the function `f`
|
||||||
@@ -130,6 +131,7 @@ class CacheAbstract(object):
|
|||||||
if r.match(str(key)):
|
if r.match(str(key)):
|
||||||
del storage[key]
|
del storage[key]
|
||||||
|
|
||||||
|
|
||||||
class CacheInRam(CacheAbstract):
|
class CacheInRam(CacheAbstract):
|
||||||
"""
|
"""
|
||||||
Ram based caching
|
Ram based caching
|
||||||
@@ -147,8 +149,10 @@ class CacheInRam(CacheAbstract):
|
|||||||
self.request = request
|
self.request = request
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if self.initialized: return
|
if self.initialized:
|
||||||
else: self.initialized = True
|
return
|
||||||
|
else:
|
||||||
|
self.initialized = True
|
||||||
self.locker.acquire()
|
self.locker.acquire()
|
||||||
request = self.request
|
request = self.request
|
||||||
if request:
|
if request:
|
||||||
@@ -172,13 +176,14 @@ class CacheInRam(CacheAbstract):
|
|||||||
self._clear(storage, regex)
|
self._clear(storage, regex)
|
||||||
|
|
||||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
if not CacheAbstract.cache_stats_name in storage.keys():
|
||||||
storage[CacheAbstract.cache_stats_name] = {'hit_total': 0,'misses': 0}
|
storage[CacheAbstract.cache_stats_name] = {
|
||||||
|
'hit_total': 0, 'misses': 0}
|
||||||
|
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
|
|
||||||
def __call__(self, key, f,
|
def __call__(self, key, f,
|
||||||
time_expire = DEFAULT_TIME_EXPIRE,
|
time_expire=DEFAULT_TIME_EXPIRE,
|
||||||
destroyer = None):
|
destroyer=None):
|
||||||
"""
|
"""
|
||||||
Attention! cache.ram does not copy the cached object. It just stores a reference to it.
|
Attention! cache.ram does not copy the cached object. It just stores a reference to it.
|
||||||
Turns out the deepcopying the object has some problems:
|
Turns out the deepcopying the object has some problems:
|
||||||
@@ -258,7 +263,7 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
on self.locker first. Replaces the close method of the
|
on self.locker first. Replaces the close method of the
|
||||||
returned shelf instance with one that releases the lock upon
|
returned shelf instance with one that releases the lock upon
|
||||||
closing."""
|
closing."""
|
||||||
|
|
||||||
storage = None
|
storage = None
|
||||||
locker = None
|
locker = None
|
||||||
locked = False
|
locked = False
|
||||||
@@ -269,14 +274,15 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
try:
|
try:
|
||||||
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)
|
||||||
storage = shelve.open(self.shelve_name)
|
storage = shelve.open(self.shelve_name)
|
||||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
if not CacheAbstract.cache_stats_name in storage.keys():
|
||||||
storage[CacheAbstract.cache_stats_name] = {'hit_total':0, 'misses': 0}
|
storage[CacheAbstract.cache_stats_name] = {
|
||||||
|
'hit_total': 0, 'misses': 0}
|
||||||
storage.sync()
|
storage.sync()
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if storage:
|
if storage:
|
||||||
@@ -286,7 +292,8 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
portalocker.unlock(locker)
|
portalocker.unlock(locker)
|
||||||
locker.close()
|
locker.close()
|
||||||
locked = False
|
locked = False
|
||||||
raise RuntimeError, 'unable to create/re-create cache file %s' % self.shelve_name
|
raise RuntimeError(
|
||||||
|
'unable to create/re-create cache file %s' % self.shelve_name)
|
||||||
self.locker = locker
|
self.locker = locker
|
||||||
self.locked = locked
|
self.locked = locked
|
||||||
self.storage = storage
|
self.storage = storage
|
||||||
@@ -296,10 +303,12 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
self.initialized = False
|
self.initialized = False
|
||||||
self.request = request
|
self.request = request
|
||||||
self.folder = folder
|
self.folder = folder
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if self.initialized: return
|
if self.initialized:
|
||||||
else: self.initialized = True
|
return
|
||||||
|
else:
|
||||||
|
self.initialized = True
|
||||||
folder = self.folder
|
folder = self.folder
|
||||||
request = self.request
|
request = self.request
|
||||||
|
|
||||||
@@ -312,8 +321,8 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
|
|
||||||
### we need this because of a possible bug in shelve that may
|
### we need this because of a possible bug in shelve that may
|
||||||
### or may not lock
|
### or may not lock
|
||||||
self.locker_name = os.path.join(folder,'cache.lock')
|
self.locker_name = os.path.join(folder, 'cache.lock')
|
||||||
self.shelve_name = os.path.join(folder,'cache.shelve')
|
self.shelve_name = os.path.join(folder, 'cache.shelve')
|
||||||
|
|
||||||
def clear(self, regex=None):
|
def clear(self, regex=None):
|
||||||
self.initialize()
|
self.initialize()
|
||||||
@@ -328,7 +337,7 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
self._close_shelve_and_unlock()
|
self._close_shelve_and_unlock()
|
||||||
|
|
||||||
def __call__(self, key, f,
|
def __call__(self, key, f,
|
||||||
time_expire = DEFAULT_TIME_EXPIRE):
|
time_expire=DEFAULT_TIME_EXPIRE):
|
||||||
self.initialize()
|
self.initialize()
|
||||||
dt = time_expire
|
dt = time_expire
|
||||||
storage = self._open_shelve_and_lock()
|
storage = self._open_shelve_and_lock()
|
||||||
@@ -346,7 +355,7 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
else:
|
else:
|
||||||
value = f()
|
value = f()
|
||||||
storage[key] = (now, value)
|
storage[key] = (now, value)
|
||||||
storage[CacheAbstract.cache_stats_name]['misses']+=1
|
storage[CacheAbstract.cache_stats_name]['misses'] += 1
|
||||||
storage.sync()
|
storage.sync()
|
||||||
finally:
|
finally:
|
||||||
self._close_shelve_and_unlock()
|
self._close_shelve_and_unlock()
|
||||||
@@ -365,8 +374,9 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
self._close_shelve_and_unlock()
|
self._close_shelve_and_unlock()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class CacheAction(object):
|
class CacheAction(object):
|
||||||
def __init__(self,func,key,time_expire,cache,cache_model):
|
def __init__(self, func, key, time_expire, cache, cache_model):
|
||||||
self.__name__ = func.__name__
|
self.__name__ = func.__name__
|
||||||
self.__doc__ = func.__doc__
|
self.__doc__ = func.__doc__
|
||||||
self.func = func
|
self.func = func
|
||||||
@@ -374,17 +384,18 @@ class CacheAction(object):
|
|||||||
self.time_expire = time_expire
|
self.time_expire = time_expire
|
||||||
self.cache = cache
|
self.cache = cache
|
||||||
self.cache_model = cache_model
|
self.cache_model = cache_model
|
||||||
def __call__(self,*a,**b):
|
|
||||||
|
def __call__(self, *a, **b):
|
||||||
if not self.key:
|
if not self.key:
|
||||||
key2 = self.__name__+':'+repr(a)+':'+repr(b)
|
key2 = self.__name__ + ':' + repr(a) + ':' + repr(b)
|
||||||
else:
|
else:
|
||||||
key2 = self.key.replace('%(name)s',self.__name__)\
|
key2 = self.key.replace('%(name)s', self.__name__)\
|
||||||
.replace('%(args)s',str(a)).replace('%(vars)s',str(b))
|
.replace('%(args)s', str(a)).replace('%(vars)s', str(b))
|
||||||
cache_model = self.cache_model
|
cache_model = self.cache_model
|
||||||
if not cache_model or isinstance(cache_model,str):
|
if not cache_model or isinstance(cache_model, str):
|
||||||
cache_model = getattr(self.cache,cache_model or 'ram')
|
cache_model = getattr(self.cache, cache_model or 'ram')
|
||||||
return cache_model(key2,
|
return cache_model(key2,
|
||||||
lambda a=a,b=b:self.func(*a,**b),
|
lambda a=a, b=b: self.func(*a, **b),
|
||||||
self.time_expire)
|
self.time_expire)
|
||||||
|
|
||||||
|
|
||||||
@@ -424,9 +435,9 @@ class Cache(object):
|
|||||||
logger.warning('no cache.disk (AttributeError)')
|
logger.warning('no cache.disk (AttributeError)')
|
||||||
|
|
||||||
def __call__(self,
|
def __call__(self,
|
||||||
key = None,
|
key=None,
|
||||||
time_expire = DEFAULT_TIME_EXPIRE,
|
time_expire=DEFAULT_TIME_EXPIRE,
|
||||||
cache_model = None):
|
cache_model=None):
|
||||||
"""
|
"""
|
||||||
Decorator function that can be used to cache any function/method.
|
Decorator function that can be used to cache any function/method.
|
||||||
|
|
||||||
@@ -459,8 +470,8 @@ class Cache(object):
|
|||||||
`request.env.path_info` as key.
|
`request.env.path_info` as key.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def tmp(func,cache=self,cache_model=cache_model):
|
def tmp(func, cache=self, cache_model=cache_model):
|
||||||
return CacheAction(func,key,time_expire,self,cache_model)
|
return CacheAction(func, key, time_expire, self, cache_model)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -468,12 +479,12 @@ class Cache(object):
|
|||||||
"""
|
"""
|
||||||
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
|
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
|
||||||
it will add prefix to all the cache keys used.
|
it will add prefix to all the cache keys used.
|
||||||
"""
|
"""
|
||||||
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix:\
|
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix:\
|
||||||
cache_model(prefix + key, f, time_expire)
|
cache_model(prefix + key, f, time_expire)
|
||||||
|
|
||||||
|
|
||||||
def lazy_cache(key=None,time_expire=None,cache_model='ram'):
|
def lazy_cache(key=None, time_expire=None, cache_model='ram'):
|
||||||
"""
|
"""
|
||||||
can be used to cache any function including in modules,
|
can be used to cache any function including in modules,
|
||||||
as long as the cached function is only called within a web2py request
|
as long as the cached function is only called within a web2py request
|
||||||
@@ -481,14 +492,12 @@ def lazy_cache(key=None,time_expire=None,cache_model='ram'):
|
|||||||
the time_expire defaults to None (no cache expiration)
|
the time_expire defaults to None (no cache expiration)
|
||||||
if cache_model is "ram" then the model is current.cache.ram, etc.
|
if cache_model is "ram" then the model is current.cache.ram, etc.
|
||||||
"""
|
"""
|
||||||
def decorator(f,key=key,time_expire=time_expire,cache_model=cache_model):
|
def decorator(f, key=key, time_expire=time_expire, cache_model=cache_model):
|
||||||
key = key or repr(f)
|
key = key or repr(f)
|
||||||
def g(*c,**d):
|
|
||||||
|
def g(*c, **d):
|
||||||
from gluon import current
|
from gluon import current
|
||||||
return current.cache(key,time_expire,cache_model)(f)(*c,**d)
|
return current.cache(key, time_expire, cache_model)(f)(*c, **d)
|
||||||
g.__name__ = f.__name__
|
g.__name__ = f.__name__
|
||||||
return g
|
return g
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,3 @@ def getcfs(key, filename, filter=None):
|
|||||||
cfs[key] = (t, data)
|
cfs[key] = (t, data)
|
||||||
cfs_lock.release()
|
cfs_lock.release()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+84
-74
@@ -48,7 +48,7 @@ except:
|
|||||||
logger.warning('unable to import py_compile')
|
logger.warning('unable to import py_compile')
|
||||||
|
|
||||||
is_pypy = settings.global_settings.is_pypy
|
is_pypy = settings.global_settings.is_pypy
|
||||||
is_gae = settings.global_settings.web2py_runtime_gae
|
is_gae = settings.global_settings.web2py_runtime_gae
|
||||||
is_jython = settings.global_settings.is_jython
|
is_jython = settings.global_settings.is_jython
|
||||||
|
|
||||||
pjoin = os.path.join
|
pjoin = os.path.join
|
||||||
@@ -95,6 +95,7 @@ _TEST()
|
|||||||
CACHED_REGEXES = {}
|
CACHED_REGEXES = {}
|
||||||
CACHED_REGEXES_MAX_SIZE = 1000
|
CACHED_REGEXES_MAX_SIZE = 1000
|
||||||
|
|
||||||
|
|
||||||
def re_compile(regex):
|
def re_compile(regex):
|
||||||
try:
|
try:
|
||||||
return CACHED_REGEXES[regex]
|
return CACHED_REGEXES[regex]
|
||||||
@@ -104,6 +105,7 @@ def re_compile(regex):
|
|||||||
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
|
||||||
return compiled_regex
|
return compiled_regex
|
||||||
|
|
||||||
|
|
||||||
class mybuiltin(object):
|
class mybuiltin(object):
|
||||||
"""
|
"""
|
||||||
NOTE could simple use a dict and populate it,
|
NOTE could simple use a dict and populate it,
|
||||||
@@ -114,14 +116,16 @@ class mybuiltin(object):
|
|||||||
try:
|
try:
|
||||||
return getattr(__builtin__, key)
|
return getattr(__builtin__, key)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise KeyError, key
|
raise KeyError(key)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
def LOAD(c=None, f='index', args=None, vars=None,
|
def LOAD(c=None, f='index', args=None, vars=None,
|
||||||
extension=None, target=None,ajax=False,ajax_trap=False,
|
extension=None, target=None, ajax=False, ajax_trap=False,
|
||||||
url=None,user_signature=False, timeout=None, times=1,
|
url=None, user_signature=False, timeout=None, times=1,
|
||||||
content='loading...',**attr):
|
content='loading...', **attr):
|
||||||
""" LOAD a component into the action's document
|
""" LOAD a component into the action's document
|
||||||
|
|
||||||
Timing options:
|
Timing options:
|
||||||
@@ -134,13 +138,14 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
|||||||
is added on page loading without delay.
|
is added on page loading without delay.
|
||||||
"""
|
"""
|
||||||
from html import TAG, DIV, URL, SCRIPT, XML
|
from html import TAG, DIV, URL, SCRIPT, XML
|
||||||
if args is None: args = []
|
if args is None:
|
||||||
|
args = []
|
||||||
vars = Storage(vars or {})
|
vars = Storage(vars or {})
|
||||||
target = target or 'c'+str(random.random())[2:]
|
target = target or 'c' + str(random.random())[2:]
|
||||||
attr['_id']=target
|
attr['_id'] = target
|
||||||
request = current.request
|
request = current.request
|
||||||
if '.' in f:
|
if '.' in f:
|
||||||
f, extension = f.rsplit('.',1)
|
f, extension = f.rsplit('.', 1)
|
||||||
if url or ajax:
|
if url or ajax:
|
||||||
url = url or URL(request.application, c, f, r=request,
|
url = url or URL(request.application, c, f, r=request,
|
||||||
args=args, vars=vars, extension=extension,
|
args=args, vars=vars, extension=extension,
|
||||||
@@ -160,19 +165,20 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
|||||||
if not isinstance(timeout, (int, long)):
|
if not isinstance(timeout, (int, long)):
|
||||||
raise ValueError("Timeout argument must be an integer or None")
|
raise ValueError("Timeout argument must be an integer or None")
|
||||||
elif timeout <= 0:
|
elif timeout <= 0:
|
||||||
raise ValueError("Timeout argument must be greater than zero or None")
|
raise ValueError(
|
||||||
|
"Timeout argument must be greater than zero or None")
|
||||||
statement = "web2py_component('%s','%s', %s, %s);" \
|
statement = "web2py_component('%s','%s', %s, %s);" \
|
||||||
% (url, target, timeout, times)
|
% (url, target, timeout, times)
|
||||||
else:
|
else:
|
||||||
statement = "web2py_component('%s','%s');" % (url, target)
|
statement = "web2py_component('%s','%s');" % (url, target)
|
||||||
script = SCRIPT(statement, _type="text/javascript")
|
script = SCRIPT(statement, _type="text/javascript")
|
||||||
if not content is None:
|
if not content is None:
|
||||||
return TAG[''](script, DIV(content,**attr))
|
return TAG[''](script, DIV(content, **attr))
|
||||||
else:
|
else:
|
||||||
return TAG[''](script)
|
return TAG[''](script)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not isinstance(args,(list,tuple)):
|
if not isinstance(args, (list, tuple)):
|
||||||
args = [args]
|
args = [args]
|
||||||
c = c or request.controller
|
c = c or request.controller
|
||||||
other_request = Storage(request)
|
other_request = Storage(request)
|
||||||
@@ -186,17 +192,17 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
|||||||
other_request.post_vars = Storage()
|
other_request.post_vars = Storage()
|
||||||
other_response = Response()
|
other_response = Response()
|
||||||
other_request.env.path_info = '/' + \
|
other_request.env.path_info = '/' + \
|
||||||
'/'.join([request.application,c,f] + \
|
'/'.join([request.application, c, f] +
|
||||||
map(str, other_request.args))
|
map(str, other_request.args))
|
||||||
other_request.env.query_string = \
|
other_request.env.query_string = \
|
||||||
vars and URL(vars=vars).split('?')[1] or ''
|
vars and URL(vars=vars).split('?')[1] or ''
|
||||||
other_request.env.http_web2py_component_location = \
|
other_request.env.http_web2py_component_location = \
|
||||||
request.env.path_info
|
request.env.path_info
|
||||||
other_request.cid = target
|
other_request.cid = target
|
||||||
other_request.env.http_web2py_component_element = target
|
other_request.env.http_web2py_component_element = target
|
||||||
other_response.view = '%s/%s.%s' % (c,f, other_request.extension)
|
other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
|
||||||
|
|
||||||
other_environment = copy.copy(current.globalenv) ### NASTY
|
other_environment = copy.copy(current.globalenv) # NASTY
|
||||||
|
|
||||||
other_response._view_environment = other_environment
|
other_response._view_environment = other_environment
|
||||||
other_response.generic_patterns = \
|
other_response.generic_patterns = \
|
||||||
@@ -218,40 +224,41 @@ def LOAD(c=None, f='index', args=None, vars=None,
|
|||||||
js = None
|
js = None
|
||||||
if ajax_trap:
|
if ajax_trap:
|
||||||
link = URL(request.application, c, f, r=request,
|
link = URL(request.application, c, f, r=request,
|
||||||
args=args, vars=vars, extension=extension,
|
args=args, vars=vars, extension=extension,
|
||||||
user_signature=user_signature)
|
user_signature=user_signature)
|
||||||
js = "web2py_trap_form('%s','%s');" % (link, target)
|
js = "web2py_trap_form('%s','%s');" % (link, target)
|
||||||
script = js and SCRIPT(js,_type="text/javascript") or ''
|
script = js and SCRIPT(js, _type="text/javascript") or ''
|
||||||
return TAG[''](DIV(XML(page),**attr),script)
|
return TAG[''](DIV(XML(page), **attr), script)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LoadFactory(object):
|
class LoadFactory(object):
|
||||||
"""
|
"""
|
||||||
Attention: this helper is new and experimental
|
Attention: this helper is new and experimental
|
||||||
"""
|
"""
|
||||||
def __init__(self,environment):
|
def __init__(self, environment):
|
||||||
self.environment = environment
|
self.environment = environment
|
||||||
|
|
||||||
def __call__(self, c=None, f='index', args=None, vars=None,
|
def __call__(self, c=None, f='index', args=None, vars=None,
|
||||||
extension=None, target=None,ajax=False,ajax_trap=False,
|
extension=None, target=None, ajax=False, ajax_trap=False,
|
||||||
url=None,user_signature=False, content='loading...',**attr):
|
url=None, user_signature=False, content='loading...', **attr):
|
||||||
if args is None: args = []
|
if args is None:
|
||||||
|
args = []
|
||||||
vars = Storage(vars or {})
|
vars = Storage(vars or {})
|
||||||
import globals
|
import globals
|
||||||
target = target or 'c'+str(random.random())[2:]
|
target = target or 'c' + str(random.random())[2:]
|
||||||
attr['_id']=target
|
attr['_id'] = target
|
||||||
request = self.environment['request']
|
request = self.environment['request']
|
||||||
if '.' in f:
|
if '.' in f:
|
||||||
f, extension = f.rsplit('.',1)
|
f, extension = f.rsplit('.', 1)
|
||||||
if url or ajax:
|
if url or ajax:
|
||||||
url = url or html.URL(request.application, c, f, r=request,
|
url = url or html.URL(request.application, c, f, r=request,
|
||||||
args=args, vars=vars, extension=extension,
|
args=args, vars=vars, extension=extension,
|
||||||
user_signature=user_signature)
|
user_signature=user_signature)
|
||||||
script = html.SCRIPT('web2py_component("%s","%s")' % (url, target),
|
script = html.SCRIPT('web2py_component("%s","%s")' % (url, target),
|
||||||
_type="text/javascript")
|
_type="text/javascript")
|
||||||
return html.TAG[''](script, html.DIV(content,**attr))
|
return html.TAG[''](script, html.DIV(content, **attr))
|
||||||
else:
|
else:
|
||||||
if not isinstance(args,(list,tuple)):
|
if not isinstance(args, (list, tuple)):
|
||||||
args = [args]
|
args = [args]
|
||||||
c = c or request.controller
|
c = c or request.controller
|
||||||
|
|
||||||
@@ -266,15 +273,15 @@ class LoadFactory(object):
|
|||||||
other_request.post_vars = Storage()
|
other_request.post_vars = Storage()
|
||||||
other_response = globals.Response()
|
other_response = globals.Response()
|
||||||
other_request.env.path_info = '/' + \
|
other_request.env.path_info = '/' + \
|
||||||
'/'.join([request.application,c,f] + \
|
'/'.join([request.application, c, f] +
|
||||||
map(str, other_request.args))
|
map(str, other_request.args))
|
||||||
other_request.env.query_string = \
|
other_request.env.query_string = \
|
||||||
vars and html.URL(vars=vars).split('?')[1] or ''
|
vars and html.URL(vars=vars).split('?')[1] or ''
|
||||||
other_request.env.http_web2py_component_location = \
|
other_request.env.http_web2py_component_location = \
|
||||||
request.env.path_info
|
request.env.path_info
|
||||||
other_request.cid = target
|
other_request.cid = target
|
||||||
other_request.env.http_web2py_component_element = target
|
other_request.env.http_web2py_component_element = target
|
||||||
other_response.view = '%s/%s.%s' % (c,f, other_request.extension)
|
other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
|
||||||
other_environment = copy.copy(self.environment)
|
other_environment = copy.copy(self.environment)
|
||||||
other_response._view_environment = other_environment
|
other_response._view_environment = other_environment
|
||||||
other_response.generic_patterns = \
|
other_response.generic_patterns = \
|
||||||
@@ -299,8 +306,8 @@ class LoadFactory(object):
|
|||||||
args=args, vars=vars, extension=extension,
|
args=args, vars=vars, extension=extension,
|
||||||
user_signature=user_signature)
|
user_signature=user_signature)
|
||||||
js = "web2py_trap_form('%s','%s');" % (link, target)
|
js = "web2py_trap_form('%s','%s');" % (link, target)
|
||||||
script = js and html.SCRIPT(js,_type="text/javascript") or ''
|
script = js and html.SCRIPT(js, _type="text/javascript") or ''
|
||||||
return html.TAG[''](html.DIV(html.XML(page),**attr),script)
|
return html.TAG[''](html.DIV(html.XML(page), **attr), script)
|
||||||
|
|
||||||
|
|
||||||
def local_import_aux(name, reload_force=False, app='welcome'):
|
def local_import_aux(name, reload_force=False, app='welcome'):
|
||||||
@@ -321,7 +328,7 @@ def local_import_aux(name, reload_force=False, app='welcome'):
|
|||||||
This prevents conflict between applications and un-necessary execs.
|
This prevents conflict between applications and un-necessary execs.
|
||||||
It can be used to import any module, including regular Python modules.
|
It can be used to import any module, including regular Python modules.
|
||||||
"""
|
"""
|
||||||
items = name.replace('/','.')
|
items = name.replace('/', '.')
|
||||||
name = "applications.%s.modules.%s" % (app, items)
|
name = "applications.%s.modules.%s" % (app, items)
|
||||||
module = __import__(name)
|
module = __import__(name)
|
||||||
for item in name.split(".")[1:]:
|
for item in name.split(".")[1:]:
|
||||||
@@ -355,12 +362,14 @@ OLD IMPLEMENTATION:
|
|||||||
file.close()
|
file.close()
|
||||||
imp.release_lock()
|
imp.release_lock()
|
||||||
if not module:
|
if not module:
|
||||||
raise ImportError, "cannot find module %s in %s" % (filename, modulepath)
|
raise ImportError, "cannot find module %s in %s" % (
|
||||||
|
filename, modulepath)
|
||||||
return module
|
return module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_base_environment_ = dict((k,getattr(html,k)) for k in html.__all__)
|
_base_environment_ = dict((k, getattr(html, k)) for k in html.__all__)
|
||||||
_base_environment_.update((k,getattr(validators,k)) for k in validators.__all__)
|
_base_environment_.update(
|
||||||
|
(k, getattr(validators, k)) for k in validators.__all__)
|
||||||
_base_environment_['__builtins__'] = __builtins__
|
_base_environment_['__builtins__'] = __builtins__
|
||||||
_base_environment_['HTTP'] = HTTP
|
_base_environment_['HTTP'] = HTTP
|
||||||
_base_environment_['redirect'] = redirect
|
_base_environment_['redirect'] = redirect
|
||||||
@@ -371,7 +380,8 @@ _base_environment_['SQLField'] = SQLField # for backward compatibility
|
|||||||
_base_environment_['SQLFORM'] = SQLFORM
|
_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.
|
||||||
@@ -384,7 +394,7 @@ def build_environment(request, response, session, store_current=True):
|
|||||||
# 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'^\w+\.py$', r'^%s/\w+\.py$' % request.controller,
|
||||||
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
|
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
|
||||||
|
|
||||||
t = environment['T'] = translator(request)
|
t = environment['T'] = translator(request)
|
||||||
c = environment['cache'] = Cache(request)
|
c = environment['cache'] = Cache(request)
|
||||||
@@ -398,23 +408,24 @@ def build_environment(request, response, session, store_current=True):
|
|||||||
current.cache = c
|
current.cache = c
|
||||||
|
|
||||||
global __builtins__
|
global __builtins__
|
||||||
if is_jython: # jython hack
|
if is_jython: # jython hack
|
||||||
__builtins__ = mybuiltin()
|
__builtins__ = mybuiltin()
|
||||||
elif is_pypy: # apply the same hack to pypy too
|
elif is_pypy: # apply the same hack to pypy too
|
||||||
__builtins__ = mybuiltin()
|
__builtins__ = mybuiltin()
|
||||||
else:
|
else:
|
||||||
__builtins__['__import__'] = __builtin__.__import__ ### WHY?
|
__builtins__['__import__'] = __builtin__.__import__ # WHY?
|
||||||
environment['request'] = request
|
environment['request'] = request
|
||||||
environment['response'] = response
|
environment['response'] = response
|
||||||
environment['session'] = session
|
environment['session'] = session
|
||||||
environment['local_import'] = \
|
environment['local_import'] = \
|
||||||
lambda name, reload=False, app=request.application:\
|
lambda name, reload=False, app=request.application:\
|
||||||
local_import_aux(name,reload,app)
|
local_import_aux(name, reload, app)
|
||||||
BaseAdapter.set_folder(pjoin(request.folder, 'databases'))
|
BaseAdapter.set_folder(pjoin(request.folder, 'databases'))
|
||||||
response._view_environment = copy.copy(environment)
|
response._view_environment = copy.copy(environment)
|
||||||
custom_import_install()
|
custom_import_install()
|
||||||
return environment
|
return environment
|
||||||
|
|
||||||
|
|
||||||
def save_pyc(filename):
|
def save_pyc(filename):
|
||||||
"""
|
"""
|
||||||
Bytecode compiles the file `filename`
|
Bytecode compiles the file `filename`
|
||||||
@@ -431,7 +442,7 @@ def read_pyc(filename):
|
|||||||
"""
|
"""
|
||||||
data = read_file(filename, 'rb')
|
data = read_file(filename, 'rb')
|
||||||
if not is_gae and data[:4] != imp.get_magic():
|
if not is_gae and data[:4] != imp.get_magic():
|
||||||
raise SystemError, 'compiled code is incompatible'
|
raise SystemError('compiled code is incompatible')
|
||||||
return marshal.loads(data[8:])
|
return marshal.loads(data[8:])
|
||||||
|
|
||||||
|
|
||||||
@@ -442,7 +453,10 @@ def compile_views(folder):
|
|||||||
|
|
||||||
path = pjoin(folder, 'views')
|
path = pjoin(folder, 'views')
|
||||||
for file in listdir(path, '^[\w/\-]+(\.\w+)+$'):
|
for file in listdir(path, '^[\w/\-]+(\.\w+)+$'):
|
||||||
data = parse_template(file, path)
|
try:
|
||||||
|
data = parse_template(file, path)
|
||||||
|
except Exception, e:
|
||||||
|
raise Exception("%s in %s" % (e, file))
|
||||||
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
|
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
|
||||||
filename = pjoin(folder, 'compiled', filename)
|
filename = pjoin(folder, 'compiled', filename)
|
||||||
write_file(filename, data)
|
write_file(filename, data)
|
||||||
@@ -458,7 +472,7 @@ def compile_models(folder):
|
|||||||
path = pjoin(folder, 'models')
|
path = pjoin(folder, 'models')
|
||||||
for file in listdir(path, '.+\.py$'):
|
for file in listdir(path, '.+\.py$'):
|
||||||
data = read_file(pjoin(path, file))
|
data = read_file(pjoin(path, file))
|
||||||
filename = pjoin(folder, 'compiled','models',file)
|
filename = pjoin(folder, 'compiled', 'models', file)
|
||||||
mktree(filename)
|
mktree(filename)
|
||||||
write_file(filename, data)
|
write_file(filename, data)
|
||||||
save_pyc(filename)
|
save_pyc(filename)
|
||||||
@@ -473,14 +487,14 @@ def compile_controllers(folder):
|
|||||||
path = pjoin(folder, 'controllers')
|
path = pjoin(folder, 'controllers')
|
||||||
for file in listdir(path, '.+\.py$'):
|
for file 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, file))
|
||||||
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', ('controllers/'
|
||||||
+ file[:-3]).replace('/', '_')
|
+ file[:-3]).replace('/', '_')
|
||||||
+ '_' + function + '.py')
|
+ '_' + function + '.py')
|
||||||
write_file(filename, command)
|
write_file(filename, command)
|
||||||
save_pyc(filename)
|
save_pyc(filename)
|
||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
@@ -500,19 +514,19 @@ def run_models_in(environment):
|
|||||||
for model in listdir(cpath, '^models_\w+\.pyc$', 0):
|
for model in listdir(cpath, '^models_\w+\.pyc$', 0):
|
||||||
restricted(read_pyc(model), environment, layer=model)
|
restricted(read_pyc(model), environment, layer=model)
|
||||||
path = pjoin(cpath, 'models')
|
path = pjoin(cpath, 'models')
|
||||||
models = listdir(path, '^\w+\.pyc$',0,sort=False)
|
models = listdir(path, '^\w+\.pyc$', 0, sort=False)
|
||||||
compiled=True
|
compiled = True
|
||||||
else:
|
else:
|
||||||
path = pjoin(folder, 'models')
|
path = pjoin(folder, 'models')
|
||||||
models = listdir(path, '^\w+\.py$',0,sort=False)
|
models = listdir(path, '^\w+\.py$', 0, sort=False)
|
||||||
compiled=False
|
compiled = False
|
||||||
n = len(path) + 1
|
n = len(path) + 1
|
||||||
for model in models:
|
for model in models:
|
||||||
regex = environment['response'].models_to_run
|
regex = environment['response'].models_to_run
|
||||||
if isinstance(regex, list):
|
if isinstance(regex, list):
|
||||||
regex = re_compile('|'.join(regex))
|
regex = re_compile('|'.join(regex))
|
||||||
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py')
|
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py')
|
||||||
if not regex.search(file) and c!= 'appadmin':
|
if not regex.search(file) and c != 'appadmin':
|
||||||
continue
|
continue
|
||||||
elif compiled:
|
elif compiled:
|
||||||
code = read_pyc(model)
|
code = read_pyc(model)
|
||||||
@@ -538,7 +552,7 @@ def run_controller_in(controller, function, environment):
|
|||||||
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,
|
raise HTTP(404,
|
||||||
rewrite.THREAD_LOCAL.routes.error_message % badf,
|
rewrite.THREAD_LOCAL.routes.error_message % badf,
|
||||||
@@ -548,7 +562,8 @@ def run_controller_in(controller, function, environment):
|
|||||||
# TESTING: adjust the path to include site packages
|
# TESTING: adjust the path to include site packages
|
||||||
from settings import global_settings
|
from settings import global_settings
|
||||||
from admin import abspath, add_path_first
|
from admin import abspath, add_path_first
|
||||||
paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
paths = (global_settings.gluon_parent, abspath(
|
||||||
|
'site-packages', gluon=True), abspath('gluon', gluon=True), '')
|
||||||
[add_path_first(path) for path in paths]
|
[add_path_first(path) for path in paths]
|
||||||
# TESTING END
|
# TESTING END
|
||||||
|
|
||||||
@@ -578,18 +593,19 @@ def run_controller_in(controller, function, environment):
|
|||||||
code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function)
|
code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function)
|
||||||
if is_gae:
|
if is_gae:
|
||||||
layer = filename + ':' + function
|
layer = filename + ':' + function
|
||||||
code = getcfs(layer, filename, lambda: compile2(code,layer))
|
code = getcfs(layer, filename, lambda: compile2(code, layer))
|
||||||
restricted(code, environment, filename)
|
restricted(code, environment, filename)
|
||||||
response = environment['response']
|
response = environment['response']
|
||||||
vars=response._vars
|
vars = response._vars
|
||||||
if response.postprocessing:
|
if response.postprocessing:
|
||||||
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
|
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
|
||||||
if isinstance(vars,unicode):
|
if isinstance(vars, unicode):
|
||||||
vars = vars.encode('utf8')
|
vars = vars.encode('utf8')
|
||||||
elif hasattr(vars,'xml') and callable(vars.xml):
|
elif hasattr(vars, 'xml') and callable(vars.xml):
|
||||||
vars = vars.xml()
|
vars = vars.xml()
|
||||||
return vars
|
return vars
|
||||||
|
|
||||||
|
|
||||||
def run_view_in(environment):
|
def run_view_in(environment):
|
||||||
"""
|
"""
|
||||||
Executes the view for the requested action.
|
Executes the view for the requested action.
|
||||||
@@ -606,7 +622,7 @@ def run_view_in(environment):
|
|||||||
if response.generic_patterns:
|
if response.generic_patterns:
|
||||||
patterns = response.generic_patterns
|
patterns = response.generic_patterns
|
||||||
regex = re_compile('|'.join(map(fnmatch.translate, patterns)))
|
regex = re_compile('|'.join(map(fnmatch.translate, patterns)))
|
||||||
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
short_action = '%(controller)s/%(function)s.%(extension)s' % request
|
||||||
allow_generic = regex.search(short_action)
|
allow_generic = regex.search(short_action)
|
||||||
else:
|
else:
|
||||||
allow_generic = False
|
allow_generic = False
|
||||||
@@ -626,7 +642,7 @@ def run_view_in(environment):
|
|||||||
files.append('views_generic.pyc')
|
files.append('views_generic.pyc')
|
||||||
# end backward compatibility code
|
# end backward compatibility code
|
||||||
for f in files:
|
for f in files:
|
||||||
filename = pjoin(path,f)
|
filename = pjoin(path, f)
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
code = read_pyc(filename)
|
code = read_pyc(filename)
|
||||||
restricted(code, environment, layer=filename)
|
restricted(code, environment, layer=filename)
|
||||||
@@ -648,13 +664,14 @@ def run_view_in(environment):
|
|||||||
ccode = getcfs(layer, filename,
|
ccode = getcfs(layer, filename,
|
||||||
lambda: compile2(parse_template(view,
|
lambda: compile2(parse_template(view,
|
||||||
pjoin(folder, 'views'),
|
pjoin(folder, 'views'),
|
||||||
context=environment),layer))
|
context=environment), layer))
|
||||||
else:
|
else:
|
||||||
ccode = parse_template(view,
|
ccode = parse_template(view,
|
||||||
pjoin(folder, 'views'),
|
pjoin(folder, 'views'),
|
||||||
context=environment)
|
context=environment)
|
||||||
restricted(ccode, environment, layer)
|
restricted(ccode, environment, layer)
|
||||||
|
|
||||||
|
|
||||||
def remove_compiled_application(folder):
|
def remove_compiled_application(folder):
|
||||||
"""
|
"""
|
||||||
Deletes the folder `compiled` containing the compiled application.
|
Deletes the folder `compiled` containing the compiled application.
|
||||||
@@ -662,7 +679,7 @@ def remove_compiled_application(folder):
|
|||||||
try:
|
try:
|
||||||
shutil.rmtree(pjoin(folder, 'compiled'))
|
shutil.rmtree(pjoin(folder, 'compiled'))
|
||||||
path = pjoin(folder, 'controllers')
|
path = pjoin(folder, 'controllers')
|
||||||
for file in listdir(path,'.*\.pyc$',drop=False):
|
for file in listdir(path, '.*\.pyc$', drop=False):
|
||||||
os.unlink(file)
|
os.unlink(file)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
@@ -700,10 +717,3 @@ def test():
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
-12
@@ -700,7 +700,7 @@ CONTENT_TYPE = {
|
|||||||
'.zabw': 'application/x-abiword',
|
'.zabw': 'application/x-abiword',
|
||||||
'.zip': 'application/zip',
|
'.zip': 'application/zip',
|
||||||
'.zoo': 'application/x-zoo',
|
'.zoo': 'application/x-zoo',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def contenttype(filename, default='text/plain'):
|
def contenttype(filename, default='text/plain'):
|
||||||
@@ -709,18 +709,11 @@ def contenttype(filename, default='text/plain'):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
i = filename.rfind('.')
|
i = filename.rfind('.')
|
||||||
if i>=0:
|
if i >= 0:
|
||||||
default = CONTENT_TYPE.get(filename[i:].lower(),default)
|
default = CONTENT_TYPE.get(filename[i:].lower(), default)
|
||||||
j = filename.rfind('.', 0, i)
|
j = filename.rfind('.', 0, i)
|
||||||
if j>=0:
|
if j >= 0:
|
||||||
default = CONTENT_TYPE.get(filename[j:].lower(),default)
|
default = CONTENT_TYPE.get(filename[j:].lower(), default)
|
||||||
if default.startswith('text/'):
|
if default.startswith('text/'):
|
||||||
default += '; charset=utf-8'
|
default += '; charset=utf-8'
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import urllib
|
|||||||
|
|
||||||
_known_tuple_types = {}
|
_known_tuple_types = {}
|
||||||
|
|
||||||
|
|
||||||
class NamedTupleBase(tuple):
|
class NamedTupleBase(tuple):
|
||||||
"""Base class for named tuples with the __new__ operator set, named tuples
|
"""Base class for named tuples with the __new__ operator set, named tuples
|
||||||
yielded by the namedtuple() function will subclass this and add
|
yielded by the namedtuple() function will subclass this and add
|
||||||
@@ -29,7 +30,7 @@ class NamedTupleBase(tuple):
|
|||||||
"""Create a new instance of this fielded tuple"""
|
"""Create a new instance of this fielded tuple"""
|
||||||
# May need to unpack named field values here
|
# May need to unpack named field values here
|
||||||
if kws:
|
if kws:
|
||||||
values = list(args) + [None]*(len(cls._fields) - len(args))
|
values = list(args) + [None] * (len(cls._fields) - len(args))
|
||||||
fields = dict((val, idx) for idx, val in enumerate(cls._fields))
|
fields = dict((val, idx) for idx, val in enumerate(cls._fields))
|
||||||
for kw, val in kws.iteritems():
|
for kw, val in kws.iteritems():
|
||||||
assert kw in kws, "%r not in field list" % kw
|
assert kw in kws, "%r not in field list" % kw
|
||||||
@@ -37,6 +38,7 @@ class NamedTupleBase(tuple):
|
|||||||
args = tuple(values)
|
args = tuple(values)
|
||||||
return tuple.__new__(cls, args)
|
return tuple.__new__(cls, args)
|
||||||
|
|
||||||
|
|
||||||
def namedtuple(typename, fieldnames):
|
def namedtuple(typename, fieldnames):
|
||||||
"""
|
"""
|
||||||
>>> import namedtuples
|
>>> import namedtuples
|
||||||
@@ -75,24 +77,26 @@ def namedtuple(typename, fieldnames):
|
|||||||
# Done
|
# Done
|
||||||
return new_tuple_type
|
return new_tuple_type
|
||||||
|
|
||||||
|
|
||||||
class AIM:
|
class AIM:
|
||||||
|
|
||||||
class AIMError(Exception):
|
class AIMError(Exception):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.parameter = value
|
self.parameter = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.parameter)
|
return str(self.parameter)
|
||||||
|
|
||||||
def __init__(self, login, transkey, testmode=False):
|
def __init__(self, login, transkey, testmode=False):
|
||||||
if str(login).strip() == '' or login == None:
|
if str(login).strip() == '' or login is None:
|
||||||
raise AIM.AIMError('No login name provided')
|
raise AIM.AIMError('No login name provided')
|
||||||
if str(transkey).strip() == '' or transkey == None:
|
if str(transkey).strip() == '' or transkey is None:
|
||||||
raise AIM.AIMError('No transaction key provided')
|
raise AIM.AIMError('No transaction key provided')
|
||||||
if testmode != True and testmode != False:
|
if testmode != True and testmode != False:
|
||||||
raise AIM.AIMError('Invalid value for testmode. Must be True or False. "{0}" given.'.format(testmode))
|
raise AIM.AIMError('Invalid value for testmode. Must be True or False. "{0}" given.'.format(testmode))
|
||||||
|
|
||||||
self.testmode = testmode
|
self.testmode = testmode
|
||||||
self.proxy = None;
|
self.proxy = None
|
||||||
self.delimiter = '|'
|
self.delimiter = '|'
|
||||||
self.results = []
|
self.results = []
|
||||||
self.error = True
|
self.error = True
|
||||||
@@ -117,8 +121,9 @@ class AIM:
|
|||||||
else:
|
else:
|
||||||
url = 'https://secure.authorize.net/gateway/transact.dll'
|
url = 'https://secure.authorize.net/gateway/transact.dll'
|
||||||
|
|
||||||
if self.proxy == None:
|
if self.proxy is None:
|
||||||
self.results += str(urllib.urlopen(url, encoded_args).read()).split(self.delimiter)
|
self.results += str(urllib.urlopen(
|
||||||
|
url, encoded_args).read()).split(self.delimiter)
|
||||||
else:
|
else:
|
||||||
opener = urllib.FancyURLopener(self.proxy)
|
opener = urllib.FancyURLopener(self.proxy)
|
||||||
opened = opener.open(url, encoded_args)
|
opened = opener.open(url, encoded_args)
|
||||||
@@ -147,36 +152,37 @@ class AIM:
|
|||||||
raise AIM.AIMError(self.response.ResponseText)
|
raise AIM.AIMError(self.response.ResponseText)
|
||||||
|
|
||||||
def setTransaction(self, creditcard, expiration, total, cvv=None, tax=None, invoice=None):
|
def setTransaction(self, creditcard, expiration, total, cvv=None, tax=None, invoice=None):
|
||||||
if str(creditcard).strip() == '' or creditcard == None:
|
if str(creditcard).strip() == '' or creditcard is None:
|
||||||
raise AIM.AIMError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
|
raise AIM.AIMError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
|
||||||
if str(expiration).strip() == '' or expiration == None:
|
if str(expiration).strip() == '' or expiration is None:
|
||||||
raise AIM.AIMError('No expiration number to setTransaction(): {0}'.format(expiration))
|
raise AIM.AIMError('No expiration number to setTransaction(): {0}'.format(expiration))
|
||||||
if str(total).strip() == '' or total == None:
|
if str(total).strip() == '' or total is None:
|
||||||
raise AIM.AIMError('No total amount passed to setTransaction(): {0}'.format(total))
|
raise AIM.AIMError('No total amount passed to setTransaction(): {0}'.format(total))
|
||||||
|
|
||||||
self.setParameter('x_card_num', creditcard)
|
self.setParameter('x_card_num', creditcard)
|
||||||
self.setParameter('x_exp_date', expiration)
|
self.setParameter('x_exp_date', expiration)
|
||||||
self.setParameter('x_amount', total)
|
self.setParameter('x_amount', total)
|
||||||
if cvv != None:
|
if cvv is not None:
|
||||||
self.setParameter('x_card_code', cvv)
|
self.setParameter('x_card_code', cvv)
|
||||||
if tax != None:
|
if tax is not None:
|
||||||
self.setParameter('x_tax', tax)
|
self.setParameter('x_tax', tax)
|
||||||
if invoice != None:
|
if invoice is not None:
|
||||||
self.setParameter('x_invoice_num', invoice)
|
self.setParameter('x_invoice_num', invoice)
|
||||||
|
|
||||||
def setTransactionType(self, transtype=None):
|
def setTransactionType(self, transtype=None):
|
||||||
types = ['AUTH_CAPTURE', 'AUTH_ONLY', 'PRIOR_AUTH_CAPTURE', 'CREDIT', 'CAPTURE_ONLY', 'VOID']
|
types = ['AUTH_CAPTURE', 'AUTH_ONLY', 'PRIOR_AUTH_CAPTURE',
|
||||||
|
'CREDIT', 'CAPTURE_ONLY', 'VOID']
|
||||||
if transtype.upper() not in types:
|
if transtype.upper() not in types:
|
||||||
raise AIM.AIMError('Incorrect Transaction Type passed to setTransactionType(): {0}'.format(transtype))
|
raise AIM.AIMError('Incorrect Transaction Type passed to setTransactionType(): {0}'.format(transtype))
|
||||||
self.setParameter('x_type', transtype.upper())
|
self.setParameter('x_type', transtype.upper())
|
||||||
|
|
||||||
def setProxy(self, proxy=None):
|
def setProxy(self, proxy=None):
|
||||||
if str(proxy).strip() == '' or proxy == None:
|
if str(proxy).strip() == '' or proxy is None:
|
||||||
raise AIM.AIMError('No proxy passed to setProxy()')
|
raise AIM.AIMError('No proxy passed to setProxy()')
|
||||||
self.proxy = {'http': str(proxy).strip()}
|
self.proxy = {'http': str(proxy).strip()}
|
||||||
|
|
||||||
def setParameter(self, key=None, value=None):
|
def setParameter(self, key=None, value=None):
|
||||||
if key != None and value != None and str(key).strip() != '' and str(value).strip() != '':
|
if key is not None and value is not None and str(key).strip() != '' and str(value).strip() != '':
|
||||||
self.parameters[key] = str(value).strip()
|
self.parameters[key] = str(value).strip()
|
||||||
else:
|
else:
|
||||||
raise AIM.AIMError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
|
raise AIM.AIMError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
|
||||||
@@ -194,10 +200,11 @@ class AIM:
|
|||||||
responses = ['', 'Approved', 'Declined', 'Error']
|
responses = ['', 'Approved', 'Declined', 'Error']
|
||||||
return responses[int(self.results[0])]
|
return responses[int(self.results[0])]
|
||||||
|
|
||||||
def process(creditcard,expiration,total,cvv=None,tax=None,invoice=None,
|
|
||||||
login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ',testmode=True):
|
def process(creditcard, expiration, total, cvv=None, tax=None, invoice=None,
|
||||||
payment = AIM(login,transkey,testmode)
|
login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True):
|
||||||
expiration = expiration.replace('/','')
|
payment = AIM(login, transkey, testmode)
|
||||||
|
expiration = expiration.replace('/', '')
|
||||||
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
|
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
|
||||||
try:
|
try:
|
||||||
payment.process()
|
payment.process()
|
||||||
@@ -205,6 +212,7 @@ def process(creditcard,expiration,total,cvv=None,tax=None,invoice=None,
|
|||||||
except AIM.AIMError:
|
except AIM.AIMError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
@@ -215,12 +223,14 @@ def test():
|
|||||||
total = '1.00'
|
total = '1.00'
|
||||||
cvv = '123'
|
cvv = '123'
|
||||||
tax = '0.00'
|
tax = '0.00'
|
||||||
invoice = str(time())[4:10] # get a random invoice number
|
invoice = str(time())[4:10] # get a random invoice number
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True)
|
payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True)
|
||||||
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
|
payment.setTransaction(
|
||||||
payment.setParameter('x_duplicate_window', 180) # three minutes duplicate windows
|
creditcard, expiration, total, cvv, tax, invoice)
|
||||||
|
payment.setParameter(
|
||||||
|
'x_duplicate_window', 180) # three minutes duplicate windows
|
||||||
payment.setParameter('x_cust_id', '1324') # customer ID
|
payment.setParameter('x_cust_id', '1324') # customer ID
|
||||||
payment.setParameter('x_first_name', 'John')
|
payment.setParameter('x_first_name', 'John')
|
||||||
payment.setParameter('x_last_name', 'Conde')
|
payment.setParameter('x_last_name', 'Conde')
|
||||||
@@ -232,7 +242,8 @@ def test():
|
|||||||
payment.setParameter('x_country', 'US')
|
payment.setParameter('x_country', 'US')
|
||||||
payment.setParameter('x_phone', '800-555-1234')
|
payment.setParameter('x_phone', '800-555-1234')
|
||||||
payment.setParameter('x_description', 'Test Transaction')
|
payment.setParameter('x_description', 'Test Transaction')
|
||||||
payment.setParameter('x_customer_ip', socket.gethostbyname(socket.gethostname()))
|
payment.setParameter(
|
||||||
|
'x_customer_ip', socket.gethostbyname(socket.gethostname()))
|
||||||
payment.setParameter('x_email', 'john@example.com')
|
payment.setParameter('x_email', 'john@example.com')
|
||||||
payment.setParameter('x_email_customer', False)
|
payment.setParameter('x_email_customer', False)
|
||||||
payment.process()
|
payment.process()
|
||||||
@@ -251,16 +262,9 @@ def test():
|
|||||||
except AIM.AIMError, e:
|
except AIM.AIMError, e:
|
||||||
print "Exception thrown:", e
|
print "Exception thrown:", e
|
||||||
print 'An error occured'
|
print 'An error occured'
|
||||||
print 'approved',payment.isApproved()
|
print 'approved', payment.isApproved()
|
||||||
print 'declined',payment.isDeclined()
|
print 'declined', payment.isDeclined()
|
||||||
print 'error',payment.isError()
|
print 'error', payment.isError()
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__ == '__main__':
|
||||||
test()
|
test()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,25 +15,27 @@ __all__ = ['DowCommerce']
|
|||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
|
||||||
class DowCommerce:
|
class DowCommerce:
|
||||||
|
|
||||||
class DowCommerceError(Exception):
|
class DowCommerceError(Exception):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.parameter = value
|
self.parameter = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.parameter)
|
return str(self.parameter)
|
||||||
|
|
||||||
def __init__(self, username=None, password=None, demomode=False):
|
def __init__(self, username=None, password=None, demomode=False):
|
||||||
if not demomode:
|
if not demomode:
|
||||||
if str(username).strip() == '' or username == None:
|
if str(username).strip() == '' or username is None:
|
||||||
raise DowCommerce.DowCommerceError('No username provided')
|
raise DowCommerce.DowCommerceError('No username provided')
|
||||||
if str(password).strip() == '' or password == None:
|
if str(password).strip() == '' or password is None:
|
||||||
raise DowCommerce.DowCommerceError('No password provided')
|
raise DowCommerce.DowCommerceError('No password provided')
|
||||||
else:
|
else:
|
||||||
username = 'demo'
|
username = 'demo'
|
||||||
password = 'password'
|
password = 'password'
|
||||||
|
|
||||||
self.proxy = None;
|
self.proxy = None
|
||||||
self.delimiter = '&'
|
self.delimiter = '&'
|
||||||
self.results = {}
|
self.results = {}
|
||||||
self.error = True
|
self.error = True
|
||||||
@@ -45,11 +47,11 @@ class DowCommerce:
|
|||||||
self.setParameter('username', username)
|
self.setParameter('username', username)
|
||||||
self.setParameter('password', password)
|
self.setParameter('password', password)
|
||||||
|
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
encoded_args = urllib.urlencode(self.parameters)
|
encoded_args = urllib.urlencode(self.parameters)
|
||||||
if self.proxy == None:
|
if self.proxy is None:
|
||||||
results = str(urllib.urlopen(self.url, encoded_args).read()).split(self.delimiter)
|
results = str(urllib.urlopen(
|
||||||
|
self.url, encoded_args).read()).split(self.delimiter)
|
||||||
else:
|
else:
|
||||||
opener = urllib.FancyURLopener(self.proxy)
|
opener = urllib.FancyURLopener(self.proxy)
|
||||||
opened = opener.open(self.url, encoded_args)
|
opened = opener.open(self.url, encoded_args)
|
||||||
@@ -59,7 +61,7 @@ class DowCommerce:
|
|||||||
opened.close()
|
opened.close()
|
||||||
|
|
||||||
for result in results:
|
for result in results:
|
||||||
(key,val) = result.split('=')
|
(key, val) = result.split('=')
|
||||||
self.results[key] = val
|
self.results[key] = val
|
||||||
|
|
||||||
if self.results['response'] == '1':
|
if self.results['response'] == '1':
|
||||||
@@ -80,17 +82,18 @@ class DowCommerce:
|
|||||||
self.declined = False
|
self.declined = False
|
||||||
raise DowCommerce.DowCommerceError(self.results)
|
raise DowCommerce.DowCommerceError(self.results)
|
||||||
|
|
||||||
def setTransaction(self, creditcard, expiration, total, cvv=None, orderid=None, orderdescription=None,
|
def setTransaction(
|
||||||
ipaddress=None, tax=None, shipping=None,
|
self, creditcard, expiration, total, cvv=None, orderid=None, orderdescription=None,
|
||||||
firstname=None, lastname=None, company=None, address1=None, address2=None, city=None, state=None, zipcode=None,
|
ipaddress=None, tax=None, shipping=None,
|
||||||
country=None, phone=None, fax=None, emailaddress=None, website=None,
|
firstname=None, lastname=None, company=None, address1=None, address2=None, city=None, state=None, zipcode=None,
|
||||||
shipping_firstname=None, shipping_lastname=None, shipping_company=None, shipping_address1=None, shipping_address2=None,
|
country=None, phone=None, fax=None, emailaddress=None, website=None,
|
||||||
shipping_city=None, shipping_state=None, shipping_zipcode = None, shipping_country=None, shipping_emailaddress=None):
|
shipping_firstname=None, shipping_lastname=None, shipping_company=None, shipping_address1=None, shipping_address2=None,
|
||||||
if str(creditcard).strip() == '' or creditcard == None:
|
shipping_city=None, shipping_state=None, shipping_zipcode=None, shipping_country=None, shipping_emailaddress=None):
|
||||||
|
if str(creditcard).strip() == '' or creditcard is None:
|
||||||
raise DowCommerce.DowCommerceError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
|
raise DowCommerce.DowCommerceError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
|
||||||
if str(expiration).strip() == '' or expiration == None:
|
if str(expiration).strip() == '' or expiration is None:
|
||||||
raise DowCommerce.DowCommerceError('No expiration number passed to setTransaction(): {0}'.format(expiration))
|
raise DowCommerce.DowCommerceError('No expiration number passed to setTransaction(): {0}'.format(expiration))
|
||||||
if str(total).strip() == '' or total == None:
|
if str(total).strip() == '' or total is None:
|
||||||
raise DowCommerce.DowCommerceError('No total amount passed to setTransaction(): {0}'.format(total))
|
raise DowCommerce.DowCommerceError('No total amount passed to setTransaction(): {0}'.format(total))
|
||||||
|
|
||||||
self.setParameter('ccnumber', creditcard)
|
self.setParameter('ccnumber', creditcard)
|
||||||
@@ -165,12 +168,12 @@ class DowCommerce:
|
|||||||
self.setParameter('type', transtype.lower())
|
self.setParameter('type', transtype.lower())
|
||||||
|
|
||||||
def setProxy(self, proxy=None):
|
def setProxy(self, proxy=None):
|
||||||
if str(proxy).strip() == '' or proxy == None:
|
if str(proxy).strip() == '' or proxy is None:
|
||||||
raise DowCommerce.DowCommerceError('No proxy passed to setProxy()')
|
raise DowCommerce.DowCommerceError('No proxy passed to setProxy()')
|
||||||
self.proxy = {'http': str(proxy).strip()}
|
self.proxy = {'http': str(proxy).strip()}
|
||||||
|
|
||||||
def setParameter(self, key=None, value=None):
|
def setParameter(self, key=None, value=None):
|
||||||
if key != None and value != None and str(key).strip() != '' and str(value).strip() != '':
|
if key is not None and value is not None and str(key).strip() != '' and str(value).strip() != '':
|
||||||
self.parameters[key] = str(value).strip()
|
self.parameters[key] = str(value).strip()
|
||||||
else:
|
else:
|
||||||
raise DowCommerce.DowCommerceError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
|
raise DowCommerce.DowCommerceError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
|
||||||
@@ -194,6 +197,7 @@ class DowCommerce:
|
|||||||
def getResponseText(self):
|
def getResponseText(self):
|
||||||
return self.results['responsetext']
|
return self.results['responsetext']
|
||||||
|
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
@@ -212,13 +216,14 @@ def test():
|
|||||||
total = '1.00'
|
total = '1.00'
|
||||||
cvv = '999'
|
cvv = '999'
|
||||||
tax = '0.00'
|
tax = '0.00'
|
||||||
orderid = str(time())[4:10] # get a random invoice number
|
orderid = str(time())[4:10] # get a random invoice number
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payment = DowCommerce(demomode=True)
|
payment = DowCommerce(demomode=True)
|
||||||
payment.setTransaction(creditcard, expiration, total, cvv=cvv, tax=tax, orderid=orderid, orderdescription='Test Transaction',
|
payment.setTransaction(
|
||||||
firstname='John', lastname='Doe', company='Acme', address1='123 Min Street', city='Hometown', state='VA',
|
creditcard, expiration, total, cvv=cvv, tax=tax, orderid=orderid, orderdescription='Test Transaction',
|
||||||
zipcode='12345', country='US', phone='888-555-1212', emailaddress='john@noemail.local', ipaddress='192.168.1.1')
|
firstname='John', lastname='Doe', company='Acme', address1='123 Min Street', city='Hometown', state='VA',
|
||||||
|
zipcode='12345', country='US', phone='888-555-1212', emailaddress='john@noemail.local', ipaddress='192.168.1.1')
|
||||||
|
|
||||||
payment.process()
|
payment.process()
|
||||||
if payment.isApproved():
|
if payment.isApproved():
|
||||||
@@ -231,16 +236,9 @@ def test():
|
|||||||
except DowCommerce.DowCommerceError, e:
|
except DowCommerce.DowCommerceError, e:
|
||||||
print "Exception thrown:", e
|
print "Exception thrown:", e
|
||||||
print 'An error occured'
|
print 'An error occured'
|
||||||
print 'approved',payment.isApproved()
|
print 'approved', payment.isApproved()
|
||||||
print 'declined',payment.isDeclined()
|
print 'declined', payment.isDeclined()
|
||||||
print 'error',payment.isError()
|
print 'error', payment.isError()
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__ == '__main__':
|
||||||
test()
|
test()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -500,5 +500,3 @@ aes_Rcon = array('B',
|
|||||||
'c697356ad4b37dfaefc5913972e4d3bd'
|
'c697356ad4b37dfaefc5913972e4d3bd'
|
||||||
'61c29f254a943366cc831d3a74e8cb'.decode('hex')
|
'61c29f254a943366cc831d3a74e8cb'.decode('hex')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+29
-18
@@ -42,7 +42,9 @@ revision3.com
|
|||||||
viddler.com
|
viddler.com
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re, cgi, sys
|
import re
|
||||||
|
import cgi
|
||||||
|
import sys
|
||||||
from simplejson import loads
|
from simplejson import loads
|
||||||
import urllib
|
import urllib
|
||||||
import uuid
|
import uuid
|
||||||
@@ -75,23 +77,28 @@ EMBED_MAPS = [
|
|||||||
'http://revision3.com/api/oembed/'),
|
'http://revision3.com/api/oembed/'),
|
||||||
(re.compile('http://\S+.viddler.com/\S+'),
|
(re.compile('http://\S+.viddler.com/\S+'),
|
||||||
'http://lab.viddler.com/services/oembed/'),
|
'http://lab.viddler.com/services/oembed/'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def image(url):
|
def image(url):
|
||||||
return '<img src="%s" style="max-width:100%%"/>' % url
|
return '<img src="%s" style="max-width:100%%"/>' % url
|
||||||
|
|
||||||
|
|
||||||
def audio(url):
|
def audio(url):
|
||||||
return '<audio controls="controls" style="max-width:100%%"><source src="%s" /></audio>' % url
|
return '<audio controls="controls" style="max-width:100%%"><source src="%s" /></audio>' % url
|
||||||
|
|
||||||
|
|
||||||
def video(url):
|
def video(url):
|
||||||
return '<video controls="controls" style="max-width:100%%"><source src="%s" /></video>' % url
|
return '<video controls="controls" style="max-width:100%%"><source src="%s" /></video>' % url
|
||||||
|
|
||||||
|
|
||||||
def googledoc_viewer(url):
|
def googledoc_viewer(url):
|
||||||
return '<iframe src="http://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
|
return '<iframe src="http://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
|
||||||
|
|
||||||
|
|
||||||
def web2py_component(url):
|
def web2py_component(url):
|
||||||
code = str(uuid.uuid4())
|
code = str(uuid.uuid4())
|
||||||
return '<div id="%s"></div><script>\nweb2py_component("%s","%s");\n</script>' % (code,url,code)
|
return '<div id="%s"></div><script>\nweb2py_component("%s","%s");\n</script>' % (code, url, code)
|
||||||
|
|
||||||
EXTENSION_MAPS = {
|
EXTENSION_MAPS = {
|
||||||
'png': image,
|
'png': image,
|
||||||
@@ -126,33 +133,37 @@ EXTENSION_MAPS = {
|
|||||||
'xps': googledoc_viewer,
|
'xps': googledoc_viewer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class VimeoURLOpener(urllib.FancyURLopener):
|
class VimeoURLOpener(urllib.FancyURLopener):
|
||||||
"Vimeo blocks the urllib user agent for some reason"
|
"Vimeo blocks the urllib user agent for some reason"
|
||||||
version = "Mozilla/4.0"
|
version = "Mozilla/4.0"
|
||||||
urllib._urlopener = VimeoURLOpener()
|
urllib._urlopener = VimeoURLOpener()
|
||||||
|
|
||||||
|
|
||||||
def oembed(url):
|
def oembed(url):
|
||||||
for k,v in EMBED_MAPS:
|
for k, v in EMBED_MAPS:
|
||||||
if k.match(url):
|
if k.match(url):
|
||||||
oembed = v+'?format=json&url='+cgi.escape(url)
|
oembed = v + '?format=json&url=' + cgi.escape(url)
|
||||||
try:
|
try:
|
||||||
data = urllib.urlopen(oembed).read()
|
data = urllib.urlopen(oembed).read()
|
||||||
print data
|
print data
|
||||||
return loads(data) # json!
|
return loads(data) # json!
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def extension(url):
|
def extension(url):
|
||||||
return url.split('?')[0].split('.')[-1].lower()
|
return url.split('?')[0].split('.')[-1].lower()
|
||||||
|
|
||||||
def expand_one(url,cdict):
|
|
||||||
|
def expand_one(url, cdict):
|
||||||
# try ombed but first check in cache
|
# try ombed but first check in cache
|
||||||
if cdict and url in cdict:
|
if cdict and url in cdict:
|
||||||
r = cdict[url]
|
r = cdict[url]
|
||||||
else:
|
else:
|
||||||
r = oembed(url)
|
r = oembed(url)
|
||||||
if isinstance(cdict,dict):
|
if isinstance(cdict, dict):
|
||||||
cdict[url] = r
|
cdict[url] = r
|
||||||
# if oembed service
|
# if oembed service
|
||||||
if 'html' in r:
|
if 'html' in r:
|
||||||
@@ -170,21 +181,23 @@ def expand_one(url,cdict):
|
|||||||
# else regular link
|
# else regular link
|
||||||
return '<a href="%(u)s">%(u)s</a>' % dict(u=url)
|
return '<a href="%(u)s">%(u)s</a>' % dict(u=url)
|
||||||
|
|
||||||
def expand_html(html,cdict=None):
|
|
||||||
|
def expand_html(html, cdict=None):
|
||||||
if not have_soup:
|
if not have_soup:
|
||||||
raise RuntimeError, "Missing BeautifulSoup"
|
raise RuntimeError("Missing BeautifulSoup")
|
||||||
soup = BeautifulSoup(html)
|
soup = BeautifulSoup(html)
|
||||||
comments = soup.findAll(text=lambda text:isinstance(text, Comment))
|
comments = soup.findAll(text=lambda text: isinstance(text, Comment))
|
||||||
[comment.extract() for comment in comments]
|
[comment.extract() for comment in comments]
|
||||||
for txt in soup.findAll(text=True):
|
for txt in soup.findAll(text=True):
|
||||||
if not txt.parent.name in ('a','script','pre','code','embed','object','audio','video'):
|
if not txt.parent.name in ('a', 'script', 'pre', 'code', 'embed', 'object', 'audio', 'video'):
|
||||||
ntxt = regex_link.sub(
|
ntxt = regex_link.sub(
|
||||||
lambda match: expand_one(match.group(0),cdict), txt)
|
lambda match: expand_one(match.group(0), cdict), txt)
|
||||||
txt.replaceWith(BeautifulSoup(ntxt))
|
txt.replaceWith(BeautifulSoup(ntxt))
|
||||||
return str(soup)
|
return str(soup)
|
||||||
|
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
example="""
|
example = """
|
||||||
<h3>Fringilla nisi parturient nullam</h3>
|
<h3>Fringilla nisi parturient nullam</h3>
|
||||||
<p>http://www.youtube.com/watch?v=IWBFiI5RrA0</p>
|
<p>http://www.youtube.com/watch?v=IWBFiI5RrA0</p>
|
||||||
<p>http://www.web2py.com/examples/static/images/logo_bw.png</p>
|
<p>http://www.web2py.com/examples/static/images/logo_bw.png</p>
|
||||||
@@ -198,10 +211,8 @@ laoreet tortor.</p>
|
|||||||
"""
|
"""
|
||||||
return expand_html(example)
|
return expand_html(example)
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__ == "__main__":
|
||||||
if len(sys.argv)>1:
|
if len(sys.argv) > 1:
|
||||||
print expand_html(open(sys.argv[1]).read())
|
print expand_html(open(sys.argv[1]).read())
|
||||||
else:
|
else:
|
||||||
print test()
|
print test()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+704
-630
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ cache.ram=cache.disk=MemcacheClient(request)
|
|||||||
import time
|
import time
|
||||||
from google.appengine.api.memcache import Client
|
from google.appengine.api.memcache import Client
|
||||||
|
|
||||||
|
|
||||||
class MemcacheClient(object):
|
class MemcacheClient(object):
|
||||||
|
|
||||||
client = Client()
|
client = Client()
|
||||||
@@ -24,12 +25,12 @@ class MemcacheClient(object):
|
|||||||
key,
|
key,
|
||||||
f,
|
f,
|
||||||
time_expire=300,
|
time_expire=300,
|
||||||
):
|
):
|
||||||
key = '%s/%s' % (self.request.application, key)
|
key = '%s/%s' % (self.request.application, key)
|
||||||
dt = time_expire
|
dt = time_expire
|
||||||
value = None
|
value = None
|
||||||
obj = self.client.get(key)
|
obj = self.client.get(key)
|
||||||
if obj and (dt == None or obj[0] > time.time() - dt):
|
if obj and (dt is None or obj[0] > time.time() - dt):
|
||||||
value = obj[1]
|
value = obj[1]
|
||||||
elif f is None:
|
elif f is None:
|
||||||
if obj:
|
if obj:
|
||||||
@@ -44,24 +45,24 @@ class MemcacheClient(object):
|
|||||||
obj = self.client.get(key)
|
obj = self.client.get(key)
|
||||||
if obj:
|
if obj:
|
||||||
value = obj[1] + value
|
value = obj[1] + value
|
||||||
self.client.set(key, (time.time(), value))
|
self.client.set(key, (time.time(), value))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def clear(self, key = None):
|
def clear(self, key=None):
|
||||||
if key:
|
if key:
|
||||||
key = '%s/%s' % (self.request.application, key)
|
key = '%s/%s' % (self.request.application, key)
|
||||||
self.client.delete(key)
|
self.client.delete(key)
|
||||||
else:
|
else:
|
||||||
self.client.flush_all()
|
self.client.flush_all()
|
||||||
|
|
||||||
def delete(self,*a,**b):
|
def delete(self, *a, **b):
|
||||||
return self.client.delete(*a,**b)
|
return self.client.delete(*a, **b)
|
||||||
|
|
||||||
def get(self,*a,**b):
|
def get(self, *a, **b):
|
||||||
return self.client.delete(*a,**b)
|
return self.client.delete(*a, **b)
|
||||||
|
|
||||||
def set(self,*a,**b):
|
def set(self, *a, **b):
|
||||||
return self.client.delete(*a,**b)
|
return self.client.delete(*a, **b)
|
||||||
|
|
||||||
def flush_all(self,*a,**b):
|
def flush_all(self, *a, **b):
|
||||||
return self.client.delete(*a,**b)
|
return self.client.delete(*a, **b)
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
|
|||||||
:param exponent: rate of exponential back-off.
|
:param exponent: rate of exponential back-off.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import time, logging
|
import time
|
||||||
|
import logging
|
||||||
from google.appengine.api import apiproxy_stub_map
|
from google.appengine.api import apiproxy_stub_map
|
||||||
from google.appengine.runtime import apiproxy_errors
|
from google.appengine.runtime import apiproxy_errors
|
||||||
from google.appengine.datastore import datastore_pb
|
from google.appengine.datastore import datastore_pb
|
||||||
@@ -60,8 +61,8 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
|
|||||||
interval = float(interval)
|
interval = float(interval)
|
||||||
exponent = float(exponent)
|
exponent = float(exponent)
|
||||||
wrapped = apiproxy_stub_map.MakeSyncCall
|
wrapped = apiproxy_stub_map.MakeSyncCall
|
||||||
errors = {datastore_pb.Error.TIMEOUT:'Timeout',
|
errors = {datastore_pb.Error.TIMEOUT: 'Timeout',
|
||||||
datastore_pb.Error.CONCURRENT_TRANSACTION:'TransactionFailedError'}
|
datastore_pb.Error.CONCURRENT_TRANSACTION: 'TransactionFailedError'}
|
||||||
|
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
count = 0.0
|
count = 0.0
|
||||||
@@ -70,10 +71,12 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
|
|||||||
return wrapped(*args, **kwargs)
|
return wrapped(*args, **kwargs)
|
||||||
except apiproxy_errors.ApplicationError, err:
|
except apiproxy_errors.ApplicationError, err:
|
||||||
errno = err.application_error
|
errno = err.application_error
|
||||||
if errno not in errors: raise
|
if errno not in errors:
|
||||||
|
raise
|
||||||
sleep = (exponent ** count) * interval
|
sleep = (exponent ** count) * interval
|
||||||
count += 1.0
|
count += 1.0
|
||||||
if count > attempts: raise
|
if count > attempts:
|
||||||
|
raise
|
||||||
msg = "Datastore %s: retry #%d in %s seconds.\n%s"
|
msg = "Datastore %s: retry #%d in %s seconds.\n%s"
|
||||||
vals = ''
|
vals = ''
|
||||||
if count == 1.0:
|
if count == 1.0:
|
||||||
@@ -84,10 +87,3 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
|
|||||||
setattr(wrapper, '_autoretry_datastore_timeouts', False)
|
setattr(wrapper, '_autoretry_datastore_timeouts', False)
|
||||||
if getattr(wrapped, '_autoretry_datastore_timeouts', True):
|
if getattr(wrapped, '_autoretry_datastore_timeouts', True):
|
||||||
apiproxy_stub_map.MakeSyncCall = wrapper
|
apiproxy_stub_map.MakeSyncCall = wrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+25
-23
@@ -12,6 +12,7 @@ from gluon.sanitizer import sanitize
|
|||||||
from gluon.contrib.markmin.markmin2latex import markmin2latex
|
from gluon.contrib.markmin.markmin2latex import markmin2latex
|
||||||
from gluon.contrib.markmin.markmin2pdf import markmin2pdf
|
from gluon.contrib.markmin.markmin2pdf import markmin2pdf
|
||||||
|
|
||||||
|
|
||||||
def wrapper(f):
|
def wrapper(f):
|
||||||
def g(data):
|
def g(data):
|
||||||
try:
|
try:
|
||||||
@@ -25,46 +26,47 @@ def wrapper(f):
|
|||||||
raise HTTP(405, '%s error' % e)
|
raise HTTP(405, '%s error' % e)
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
|
||||||
def latex_from_html(html):
|
def latex_from_html(html):
|
||||||
markmin=TAG(html).element('body').flatten(markmin_serializer)
|
markmin = TAG(html).element('body').flatten(markmin_serializer)
|
||||||
return XML(markmin2latex(markmin))
|
return XML(markmin2latex(markmin))
|
||||||
|
|
||||||
|
|
||||||
def pdflatex_from_html(html):
|
def pdflatex_from_html(html):
|
||||||
if os.system('which pdflatex > /dev/null')==0:
|
if os.system('which pdflatex > /dev/null') == 0:
|
||||||
markmin=TAG(html).element('body').flatten(markmin_serializer)
|
markmin = TAG(html).element('body').flatten(markmin_serializer)
|
||||||
out,warnings,errors=markmin2pdf(markmin)
|
out, warnings, errors = markmin2pdf(markmin)
|
||||||
if errors:
|
if errors:
|
||||||
current.response.headers['Content-Type']='text/html'
|
current.response.headers['Content-Type'] = 'text/html'
|
||||||
raise HTTP(405,HTML(BODY(H1('errors'),
|
raise HTTP(405, HTML(BODY(H1('errors'),
|
||||||
UL(*errors),
|
UL(*errors),
|
||||||
H1('warnings'),
|
H1('warnings'),
|
||||||
UL(*warnings))).xml())
|
UL(*warnings))).xml())
|
||||||
else:
|
else:
|
||||||
return XML(out)
|
return XML(out)
|
||||||
|
|
||||||
|
|
||||||
def pyfpdf_from_html(html):
|
def pyfpdf_from_html(html):
|
||||||
request = current.request
|
request = current.request
|
||||||
|
|
||||||
def image_map(path):
|
def image_map(path):
|
||||||
if path.startswith('/%s/static/' % request.application):
|
if path.startswith('/%s/static/' % request.application):
|
||||||
return os.path.join(request.folder,path.split('/',2)[2])
|
return os.path.join(request.folder, path.split('/', 2)[2])
|
||||||
return 'http%s://%s%s' % (request.is_https and 's' or '',request.env.http_host, path)
|
return 'http%s://%s%s' % (request.is_https and 's' or '', request.env.http_host, path)
|
||||||
class MyFPDF(FPDF, HTMLMixin): pass
|
|
||||||
pdf=MyFPDF()
|
class MyFPDF(FPDF, HTMLMixin):
|
||||||
|
pass
|
||||||
|
pdf = MyFPDF()
|
||||||
pdf.add_page()
|
pdf.add_page()
|
||||||
html = sanitize(html, escape=False) #### should have better list of allowed tags
|
html = sanitize(
|
||||||
pdf.write_html(html,image_map=image_map)
|
html, escape=False) # should have better list of allowed tags
|
||||||
|
pdf.write_html(html, image_map=image_map)
|
||||||
return XML(pdf.output(dest='S'))
|
return XML(pdf.output(dest='S'))
|
||||||
|
|
||||||
|
|
||||||
def pdf_from_html(html):
|
def pdf_from_html(html):
|
||||||
# try use latex and pdflatex
|
# try use latex and pdflatex
|
||||||
if os.system('which pdflatex > /dev/null')==0:
|
if os.system('which pdflatex > /dev/null') == 0:
|
||||||
return pdflatex_from_html(html)
|
return pdflatex_from_html(html)
|
||||||
else:
|
else:
|
||||||
return pyfpdf_from_html(html)
|
return pyfpdf_from_html(html)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from gluon import XML
|
from gluon import XML
|
||||||
|
|
||||||
|
|
||||||
def button(merchant_id="123456789012345",
|
def button(merchant_id="123456789012345",
|
||||||
products=[dict(name="shoes",
|
products=[dict(name="shoes",
|
||||||
quantity=1,
|
quantity=1,
|
||||||
@@ -8,15 +9,8 @@ def button(merchant_id="123456789012345",
|
|||||||
description="running shoes black")]):
|
description="running shoes black")]):
|
||||||
t = '<input name="item_%(key)s_%(k)s" type="hidden" value="%(value)s"/>'
|
t = '<input name="item_%(key)s_%(k)s" type="hidden" value="%(value)s"/>'
|
||||||
list_products = ''
|
list_products = ''
|
||||||
for k,product in enumerate(products):
|
for k, product in enumerate(products):
|
||||||
for key,value in product.items():
|
for key, value in product.items():
|
||||||
list_products += t % dict(k=k+1,key=key,value=value)
|
list_products += t % dict(k=k + 1, key=key, value=value)
|
||||||
button = '<form action="https://checkout.google.com/api/checkout/v2/checkoutForm/Merchant/%s" id="BB_BuyButtonForm" method="post" name="BB_BuyButtonForm" target="_top">%s<input name="_charset_" type="hidden" value="utf-8"/><input alt="" src="https://checkout.google.com/buttons/buy.gif?merchant_id=%s&w=117&h=48&style=white&variant=text&loc=en_US" type="image"/></form>' % (merchant_id, list_products, merchant_id)
|
button = '<form action="https://checkout.google.com/api/checkout/v2/checkoutForm/Merchant/%s" id="BB_BuyButtonForm" method="post" name="BB_BuyButtonForm" target="_top">%s<input name="_charset_" type="hidden" value="utf-8"/><input alt="" src="https://checkout.google.com/buttons/buy.gif?merchant_id=%s&w=117&h=48&style=white&variant=text&loc=en_US" type="image"/></form>' % (merchant_id, list_products, merchant_id)
|
||||||
return XML(button)
|
return XML(button)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
# this file exists for backward compatibility
|
# this file exists for backward compatibility
|
||||||
|
|
||||||
__all__ = ['DAL','Field','drivers','gae']
|
__all__ = ['DAL', 'Field', 'drivers', 'gae']
|
||||||
|
|
||||||
from gluon.dal import DAL, Field, Table, Query, Set, Expression, Row, Rows, drivers, BaseAdapter, SQLField, SQLTable, SQLXorable, SQLQuery, SQLSet, SQLRows, SQLStorage, SQLDB, GQLDB, SQLALL, SQLCustomType, gae
|
from gluon.dal import DAL, Field, Table, Query, Set, Expression, Row, Rows, drivers, BaseAdapter, SQLField, SQLTable, SQLXorable, SQLQuery, SQLSet, SQLRows, SQLStorage, SQLDB, GQLDB, SQLALL, SQLCustomType, gae
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#########################################################################
|
#########################################################################
|
||||||
from gluon import current
|
from gluon import current
|
||||||
|
|
||||||
|
|
||||||
class RESIZE(object):
|
class RESIZE(object):
|
||||||
def __init__(self, nx=160, ny=80, error_message=' image resize'):
|
def __init__(self, nx=160, ny=80, error_message=' image resize'):
|
||||||
(self.nx, self.ny, self.error_message) = (nx, ny, error_message)
|
(self.nx, self.ny, self.error_message) = (nx, ny, error_message)
|
||||||
@@ -43,6 +44,7 @@ class RESIZE(object):
|
|||||||
else:
|
else:
|
||||||
return (value, None)
|
return (value, None)
|
||||||
|
|
||||||
|
|
||||||
def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
|
def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
|
||||||
if image:
|
if image:
|
||||||
if not gae:
|
if not gae:
|
||||||
@@ -57,5 +59,3 @@ def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
|
|||||||
return thumb
|
return thumb
|
||||||
else:
|
else:
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ def basic_auth(server="http://127.0.0.1"):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def basic_login_aux(username,
|
def basic_login_aux(username,
|
||||||
password,
|
password,
|
||||||
server=server):
|
server=server):
|
||||||
key = base64.b64encode(username+':'+password)
|
key = base64.b64encode(username + ':' + password)
|
||||||
headers = {'Authorization': 'Basic ' + key}
|
headers = {'Authorization': 'Basic ' + key}
|
||||||
request = urllib2.Request(server, None, headers)
|
request = urllib2.Request(server, None, headers)
|
||||||
try:
|
try:
|
||||||
@@ -22,5 +22,3 @@ def basic_auth(server="http://127.0.0.1"):
|
|||||||
except (urllib2.URLError, urllib2.HTTPError):
|
except (urllib2.URLError, urllib2.HTTPError):
|
||||||
return False
|
return False
|
||||||
return basic_login_aux
|
return basic_login_aux
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from gluon.storage import Storage
|
|||||||
from gluon.tools import fetch
|
from gluon.tools import fetch
|
||||||
import gluon.contrib.simplejson as json
|
import gluon.contrib.simplejson as json
|
||||||
|
|
||||||
|
|
||||||
class BrowserID(object):
|
class BrowserID(object):
|
||||||
"""
|
"""
|
||||||
from gluon.contrib.login_methods.browserid_account import BrowserID
|
from gluon.contrib.login_methods.browserid_account import BrowserID
|
||||||
@@ -34,17 +35,17 @@ class BrowserID(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
request,
|
request,
|
||||||
audience = "",
|
audience="",
|
||||||
assertion_post_url = "",
|
assertion_post_url="",
|
||||||
prompt = "BrowserID Login",
|
prompt="BrowserID Login",
|
||||||
issuer = "browserid.org",
|
issuer="browserid.org",
|
||||||
verify_url = "https://browserid.org/verify",
|
verify_url="https://browserid.org/verify",
|
||||||
browserid_js = "https://browserid.org/include.js",
|
browserid_js="https://browserid.org/include.js",
|
||||||
browserid_button = "https://browserid.org/i/sign_in_red.png",
|
browserid_button="https://browserid.org/i/sign_in_red.png",
|
||||||
crypto_js = "https://crypto-js.googlecode.com/files/2.2.0-crypto-md5.js",
|
crypto_js="https://crypto-js.googlecode.com/files/2.2.0-crypto-md5.js",
|
||||||
on_login_failure = None,
|
on_login_failure=None,
|
||||||
):
|
):
|
||||||
|
|
||||||
self.request = request
|
self.request = request
|
||||||
self.audience = audience
|
self.audience = audience
|
||||||
@@ -67,13 +68,13 @@ class BrowserID(object):
|
|||||||
if request.vars.assertion:
|
if request.vars.assertion:
|
||||||
audience = self.audience
|
audience = self.audience
|
||||||
issuer = self.issuer
|
issuer = self.issuer
|
||||||
assertion = XML(request.vars.assertion,sanitize=True)
|
assertion = XML(request.vars.assertion, sanitize=True)
|
||||||
verify_data = {'assertion':assertion,'audience':audience}
|
verify_data = {'assertion': assertion, 'audience': audience}
|
||||||
auth_info_json = fetch(self.verify_url,data=verify_data)
|
auth_info_json = fetch(self.verify_url, data=verify_data)
|
||||||
j = json.loads(auth_info_json)
|
j = json.loads(auth_info_json)
|
||||||
epoch_time = int(time.time()*1000) # we need 13 digit epoch time
|
epoch_time = int(time.time() * 1000) # we need 13 digit epoch time
|
||||||
if j["status"] == "okay" and j["audience"] == audience and j['issuer'] == issuer and j['expires'] >= epoch_time:
|
if j["status"] == "okay" and j["audience"] == audience and j['issuer'] == issuer and j['expires'] >= epoch_time:
|
||||||
return dict(email = j['email'])
|
return dict(email=j['email'])
|
||||||
elif self.on_login_failure:
|
elif self.on_login_failure:
|
||||||
redirect('http://google.com')
|
redirect('http://google.com')
|
||||||
else:
|
else:
|
||||||
@@ -83,9 +84,8 @@ class BrowserID(object):
|
|||||||
def login_form(self):
|
def login_form(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
onclick = "javascript:navigator.id.getVerifiedEmail(gotVerifiedEmail) ; return false"
|
onclick = "javascript:navigator.id.getVerifiedEmail(gotVerifiedEmail) ; return false"
|
||||||
form = DIV(SCRIPT(_src=self.browserid_js,_type="text/javascript"),
|
form = DIV(SCRIPT(_src=self.browserid_js, _type="text/javascript"),
|
||||||
SCRIPT(_src=self.crypto_js,_type="text/javascript"),
|
SCRIPT(_src=self.crypto_js, _type="text/javascript"),
|
||||||
A(IMG(_src=self.browserid_button,_alt=self.prompt),_href="#",_onclick=onclick,_class="browserid",_title="Login With BrowserID"),
|
A(IMG(_src=self.browserid_button, _alt=self.prompt), _href="#", _onclick=onclick, _class="browserid", _title="Login With BrowserID"),
|
||||||
SCRIPT(self.asertion_js))
|
SCRIPT(self.asertion_js))
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ Tinkered by Szabolcs Gyuris < szimszo n @ o regpreshaz dot eu>
|
|||||||
|
|
||||||
from gluon import current, redirect
|
from gluon import current, redirect
|
||||||
|
|
||||||
class CasAuth( object ):
|
|
||||||
|
class CasAuth(object):
|
||||||
"""
|
"""
|
||||||
Login will be done via Web2py's CAS application, instead of web2py's
|
Login will be done via Web2py's CAS application, instead of web2py's
|
||||||
login form.
|
login form.
|
||||||
@@ -39,101 +40,105 @@ class CasAuth( object ):
|
|||||||
user's username.
|
user's username.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, g=None, ### g for backward compatibility ###
|
def __init__(self, g=None, # g for backward compatibility ###
|
||||||
urlbase = "https://web2py.com/cas/cas",
|
urlbase="https://web2py.com/cas/cas",
|
||||||
actions=['login','validate','logout'],
|
actions=['login', 'validate', 'logout'],
|
||||||
maps=dict(username=lambda v:v.get('username',v['user']),
|
maps=dict(username=lambda v: v.get('username', v['user']),
|
||||||
email=lambda v:v.get('email',None),
|
email=lambda v: v.get('email', None),
|
||||||
user_id=lambda v:v['user']),
|
user_id=lambda v: v['user']),
|
||||||
casversion = 1,
|
casversion=1,
|
||||||
casusername = 'cas:user'
|
casusername='cas:user'
|
||||||
):
|
):
|
||||||
self.urlbase=urlbase
|
self.urlbase = urlbase
|
||||||
self.cas_login_url="%s/%s"%(self.urlbase,actions[0])
|
self.cas_login_url = "%s/%s" % (self.urlbase, actions[0])
|
||||||
self.cas_check_url="%s/%s"%(self.urlbase,actions[1])
|
self.cas_check_url = "%s/%s" % (self.urlbase, actions[1])
|
||||||
self.cas_logout_url="%s/%s"%(self.urlbase,actions[2])
|
self.cas_logout_url = "%s/%s" % (self.urlbase, actions[2])
|
||||||
self.maps=maps
|
self.maps = maps
|
||||||
self.casversion = casversion
|
self.casversion = casversion
|
||||||
self.casusername = casusername
|
self.casusername = casusername
|
||||||
http_host=current.request.env.http_x_forwarded_host
|
http_host = current.request.env.http_x_forwarded_host
|
||||||
if not http_host: http_host=current.request.env.http_host
|
if not http_host:
|
||||||
if current.request.env.wsgi_url_scheme in [ 'https', 'HTTPS' ]:
|
http_host = current.request.env.http_host
|
||||||
|
if current.request.env.wsgi_url_scheme in ['https', 'HTTPS']:
|
||||||
scheme = 'https'
|
scheme = 'https'
|
||||||
else:
|
else:
|
||||||
scheme = 'http'
|
scheme = 'http'
|
||||||
self.cas_my_url='%s://%s%s'%( scheme, http_host, current.request.env.path_info )
|
self.cas_my_url = '%s://%s%s' % (
|
||||||
|
scheme, http_host, current.request.env.path_info)
|
||||||
|
|
||||||
def login_url( self, next = "/" ):
|
def login_url(self, next="/"):
|
||||||
current.session.token=self._CAS_login()
|
current.session.token = self._CAS_login()
|
||||||
return next
|
return next
|
||||||
def logout_url( self, next = "/" ):
|
|
||||||
current.session.token=None
|
def logout_url(self, next="/"):
|
||||||
current.session.auth=None
|
current.session.token = None
|
||||||
|
current.session.auth = None
|
||||||
self._CAS_logout()
|
self._CAS_logout()
|
||||||
return next
|
return next
|
||||||
def get_user( self ):
|
|
||||||
user=current.session.token
|
def get_user(self):
|
||||||
|
user = current.session.token
|
||||||
if user:
|
if user:
|
||||||
d = {'source':'web2py cas'}
|
d = {'source': 'web2py cas'}
|
||||||
for key in self.maps:
|
for key in self.maps:
|
||||||
d[key]=self.maps[key](user)
|
d[key] = self.maps[key](user)
|
||||||
return d
|
return d
|
||||||
return None
|
return None
|
||||||
def _CAS_login( self ):
|
|
||||||
|
def _CAS_login(self):
|
||||||
"""
|
"""
|
||||||
exposed as CAS.login(request)
|
exposed as CAS.login(request)
|
||||||
returns a token on success, None on failed authentication
|
returns a token on success, None on failed authentication
|
||||||
"""
|
"""
|
||||||
import urllib
|
import urllib
|
||||||
self.ticket=current.request.vars.ticket
|
self.ticket = current.request.vars.ticket
|
||||||
if not current.request.vars.ticket:
|
if not current.request.vars.ticket:
|
||||||
redirect( "%s?service=%s"% (self.cas_login_url,
|
redirect("%s?service=%s" % (self.cas_login_url,
|
||||||
self.cas_my_url))
|
self.cas_my_url))
|
||||||
else:
|
else:
|
||||||
url="%s?service=%s&ticket=%s" % (self.cas_check_url,
|
url = "%s?service=%s&ticket=%s" % (self.cas_check_url,
|
||||||
self.cas_my_url,
|
self.cas_my_url,
|
||||||
self.ticket )
|
self.ticket)
|
||||||
data=urllib.urlopen( url ).read()
|
data = urllib.urlopen(url).read()
|
||||||
if data.startswith('yes') or data.startswith('no'):
|
if data.startswith('yes') or data.startswith('no'):
|
||||||
data = data.split('\n')
|
data = data.split('\n')
|
||||||
if data[0]=='yes':
|
if data[0] == 'yes':
|
||||||
if ':' in data[1]: # for Compatibility with Custom CAS
|
if ':' in data[1]: # for Compatibility with Custom CAS
|
||||||
items = data[1].split(':')
|
items = data[1].split(':')
|
||||||
a = items[0]
|
a = items[0]
|
||||||
b = len(items)>1 and items[1] or a
|
b = len(items) > 1 and items[1] or a
|
||||||
c = len(items)>2 and items[2] or b
|
c = len(items) > 2 and items[2] or b
|
||||||
else:
|
else:
|
||||||
a = b = c = data[1]
|
a = b = c = data[1]
|
||||||
return dict(user=a,email=b,username=c)
|
return dict(user=a, email=b, username=c)
|
||||||
return None
|
return None
|
||||||
import xml.dom.minidom as dom
|
import xml.dom.minidom as dom
|
||||||
import xml.parsers.expat as expat
|
import xml.parsers.expat as expat
|
||||||
try:
|
try:
|
||||||
dxml=dom.parseString(data)
|
dxml = dom.parseString(data)
|
||||||
envelop = dxml.getElementsByTagName("cas:authenticationSuccess")
|
envelop = dxml.getElementsByTagName(
|
||||||
if len(envelop)>0:
|
"cas:authenticationSuccess")
|
||||||
|
if len(envelop) > 0:
|
||||||
res = dict()
|
res = dict()
|
||||||
for x in envelop[0].childNodes:
|
for x in envelop[0].childNodes:
|
||||||
if x.nodeName.startswith('cas:') and len(x.childNodes):
|
if x.nodeName.startswith('cas:') and len(x.childNodes):
|
||||||
key = x.nodeName[4:].encode('utf8')
|
key = x.nodeName[4:].encode('utf8')
|
||||||
value = x.childNodes[0].nodeValue.encode('utf8')
|
value = x.childNodes[0].nodeValue.encode('utf8')
|
||||||
if not key in res:
|
if not key in res:
|
||||||
res[key]=value
|
res[key] = value
|
||||||
else:
|
else:
|
||||||
if not isinstance(res[key],list):
|
if not isinstance(res[key], list):
|
||||||
res[key]=[res[key]]
|
res[key] = [res[key]]
|
||||||
res[key].append(value)
|
res[key].append(value)
|
||||||
return res
|
return res
|
||||||
except expat.ExpatError: pass
|
except expat.ExpatError:
|
||||||
return None # fallback
|
pass
|
||||||
|
return None # fallback
|
||||||
|
|
||||||
|
def _CAS_logout(self):
|
||||||
def _CAS_logout( self ):
|
|
||||||
"""
|
"""
|
||||||
exposed CAS.logout()
|
exposed CAS.logout()
|
||||||
redirects to the CAS logout page
|
redirects to the CAS logout page
|
||||||
"""
|
"""
|
||||||
import urllib
|
import urllib
|
||||||
redirect("%s?service=%s" % (self.cas_logout_url,self.cas_my_url))
|
redirect("%s?service=%s" % (self.cas_logout_url, self.cas_my_url))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ from gluon.tools import fetch
|
|||||||
from gluon.storage import Storage
|
from gluon.storage import Storage
|
||||||
import gluon.contrib.simplejson as json
|
import gluon.contrib.simplejson as json
|
||||||
|
|
||||||
|
|
||||||
class DropboxAccount(object):
|
class DropboxAccount(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from gluon.contrib.login_methods.dropbox_account import DropboxAccount
|
from gluon.contrib.login_methods.dropbox_account import DropboxAccount
|
||||||
auth.settings.actions_disabled=['register','change_password','request_reset_password']
|
auth.settings.actions_disabled=['register','change_password',
|
||||||
|
'request_reset_password']
|
||||||
auth.settings.login_form = DropboxAccount(request,
|
auth.settings.login_form = DropboxAccount(request,
|
||||||
key="...",
|
key="...",
|
||||||
secret="...",
|
secret="...",
|
||||||
@@ -34,47 +36,45 @@ class DropboxAccount(object):
|
|||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
request,
|
request,
|
||||||
key = "",
|
key="",
|
||||||
secret = "",
|
secret="",
|
||||||
access_type="app_folder",
|
access_type="app_folder",
|
||||||
login_url = "",
|
login_url="",
|
||||||
on_login_failure=None,
|
on_login_failure=None,
|
||||||
):
|
):
|
||||||
|
|
||||||
self.request=request
|
self.request = request
|
||||||
self.key=key
|
self.key = key
|
||||||
self.secret=secret
|
self.secret = secret
|
||||||
self.access_type=access_type
|
self.access_type = access_type
|
||||||
self.login_url = login_url
|
self.login_url = login_url
|
||||||
self.on_login_failure = on_login_failure
|
self.on_login_failure = on_login_failure
|
||||||
self.sess = session.DropboxSession(
|
self.sess = session.DropboxSession(
|
||||||
self.key,self.secret,self.access_type)
|
self.key, self.secret, self.access_type)
|
||||||
|
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
if not current.session.dropbox_request_token:
|
if not current.session.dropbox_request_token:
|
||||||
return None
|
return None
|
||||||
elif not current.session.dropbox_access_token:
|
elif not current.session.dropbox_access_token:
|
||||||
|
|
||||||
request_token = current.session.dropbox_request_token
|
request_token = current.session.dropbox_request_token
|
||||||
self.sess.set_request_token(request_token[0],request_token[1])
|
self.sess.set_request_token(request_token[0], request_token[1])
|
||||||
access_token = self.sess.obtain_access_token(self.sess.token)
|
access_token = self.sess.obtain_access_token(self.sess.token)
|
||||||
current.session.dropbox_access_token = \
|
current.session.dropbox_access_token = \
|
||||||
(access_token.key,access_token.secret)
|
(access_token.key, access_token.secret)
|
||||||
else:
|
else:
|
||||||
access_token = current.session.dropbox_access_token
|
access_token = current.session.dropbox_access_token
|
||||||
self.sess.set_token(access_token[0],access_token[1])
|
self.sess.set_token(access_token[0], access_token[1])
|
||||||
|
|
||||||
|
|
||||||
user = Storage()
|
user = Storage()
|
||||||
self.client = client.DropboxClient(self.sess)
|
self.client = client.DropboxClient(self.sess)
|
||||||
data = self.client.account_info()
|
data = self.client.account_info()
|
||||||
display_name = data.get('display_name','').split(' ',1)
|
display_name = data.get('display_name', '').split(' ', 1)
|
||||||
user = dict(email = data.get('email',None),
|
user = dict(email=data.get('email', None),
|
||||||
first_name = display_name[0],
|
first_name=display_name[0],
|
||||||
last_name = display_name[-1],
|
last_name=display_name[-1],
|
||||||
registration_id = data.get('uid',None))
|
registration_id=data.get('uid', None))
|
||||||
if not user['registration_id'] and self.on_login_failure:
|
if not user['registration_id'] and self.on_login_failure:
|
||||||
redirect(self.on_login_failure)
|
redirect(self.on_login_failure)
|
||||||
return user
|
return user
|
||||||
@@ -83,7 +83,7 @@ class DropboxAccount(object):
|
|||||||
|
|
||||||
request_token = self.sess.obtain_request_token()
|
request_token = self.sess.obtain_request_token()
|
||||||
current.session.dropbox_request_token = \
|
current.session.dropbox_request_token = \
|
||||||
(request_token.key,request_token.secret)
|
(request_token.key, request_token.secret)
|
||||||
dropbox_url = self.sess.build_authorize_url(request_token,
|
dropbox_url = self.sess.build_authorize_url(request_token,
|
||||||
self.login_url)
|
self.login_url)
|
||||||
redirect(dropbox_url)
|
redirect(dropbox_url)
|
||||||
@@ -93,29 +93,32 @@ class DropboxAccount(object):
|
|||||||
_style="width:400px;height:240px;")
|
_style="width:400px;height:240px;")
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def logout_url(self, next = "/"):
|
def logout_url(self, next="/"):
|
||||||
current.session.dropbox_request_token=None
|
current.session.dropbox_request_token = None
|
||||||
current.session.auth=None
|
current.session.auth = None
|
||||||
redirect('https://www.dropbox.com/logout')
|
redirect('https://www.dropbox.com/logout')
|
||||||
return next
|
return next
|
||||||
def put(self,filename,file):
|
|
||||||
return json.loads(self.client.put_file(filename,file))['bytes']
|
def put(self, filename, file):
|
||||||
def get(self,filename,file):
|
return json.loads(self.client.put_file(filename, file))['bytes']
|
||||||
|
|
||||||
|
def get(self, filename, file):
|
||||||
return self.client.get_file(filename)
|
return self.client.get_file(filename)
|
||||||
def dir(self,path):
|
|
||||||
|
def dir(self, path):
|
||||||
return json.loads(self.client.metadata(path))
|
return json.loads(self.client.metadata(path))
|
||||||
|
|
||||||
def use_dropbox(auth,filename='private/dropbox.key',**kwargs):
|
|
||||||
path = os.path.join(current.request.folder,filename)
|
def use_dropbox(auth, filename='private/dropbox.key', **kwargs):
|
||||||
|
path = os.path.join(current.request.folder, filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
request = current.request
|
request = current.request
|
||||||
key,secret,access_type = open(path,'r').read().strip().split(':')
|
key, secret, access_type = open(path, 'r').read().strip().split(':')
|
||||||
host = current.request.env.http_host
|
host = current.request.env.http_host
|
||||||
login_url = "http://%s/%s/default/user/login" % \
|
login_url = "http://%s/%s/default/user/login" % \
|
||||||
(host,request.application)
|
(host, request.application)
|
||||||
auth.settings.actions_disabled = \
|
auth.settings.actions_disabled = \
|
||||||
['register','change_password','request_reset_password']
|
['register', 'change_password', 'request_reset_password']
|
||||||
auth.settings.login_form = DropboxAccount(
|
auth.settings.login_form = DropboxAccount(
|
||||||
request,key=key,secret=secret,access_type=access_type,
|
request, key=key, secret=secret, access_type=access_type,
|
||||||
login_url = login_url,**kwargs)
|
login_url=login_url, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import smtplib
|
import smtplib
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def email_auth(server="smtp.gmail.com:587",
|
def email_auth(server="smtp.gmail.com:587",
|
||||||
domain="@gmail.com",
|
domain="@gmail.com",
|
||||||
tls_mode=None):
|
tls_mode=None):
|
||||||
@@ -17,9 +18,9 @@ def email_auth(server="smtp.gmail.com:587",
|
|||||||
domain=domain,
|
domain=domain,
|
||||||
tls_mode=tls_mode):
|
tls_mode=tls_mode):
|
||||||
if domain:
|
if domain:
|
||||||
if not isinstance(domain,(list,tuple)):
|
if not isinstance(domain, (list, tuple)):
|
||||||
domain=[str(domain)]
|
domain = [str(domain)]
|
||||||
if not [d for d in domain if email[-len(d):]==d]:
|
if not [d for d in domain if email[-len(d):] == d]:
|
||||||
return False
|
return False
|
||||||
(host, port) = server.split(':')
|
(host, port) = server.split(':')
|
||||||
if tls_mode is None: # then auto detect
|
if tls_mode is None: # then auto detect
|
||||||
@@ -43,4 +44,3 @@ def email_auth(server="smtp.gmail.com:587",
|
|||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
return email_auth_aux
|
return email_auth_aux
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ So user can choose the built-in login or extended login methods.
|
|||||||
|
|
||||||
from gluon import current, DIV
|
from gluon import current, DIV
|
||||||
|
|
||||||
|
|
||||||
class ExtendedLoginForm(object):
|
class ExtendedLoginForm(object):
|
||||||
"""
|
"""
|
||||||
Put extended_login_form under web2py/gluon/contrib/login_methods folder.
|
Put extended_login_form under web2py/gluon/contrib/login_methods folder.
|
||||||
@@ -22,7 +23,8 @@ class ExtendedLoginForm(object):
|
|||||||
api_key="...",
|
api_key="...",
|
||||||
domain="...",
|
domain="...",
|
||||||
url = "http://localhost:8000/%s/default/user/login" % request.application)
|
url = "http://localhost:8000/%s/default/user/login" % request.application)
|
||||||
extended_login_form = ExtendedLoginForm(auth, alt_login_form, signals=['token'])
|
extended_login_form = ExtendedLoginForm(
|
||||||
|
auth, alt_login_form, signals=['token'])
|
||||||
|
|
||||||
auth.settings.login_form = extended_login_form
|
auth.settings.login_form = extended_login_form
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ class ExtendedLoginForm(object):
|
|||||||
auth,
|
auth,
|
||||||
alt_login_form,
|
alt_login_form,
|
||||||
signals=[],
|
signals=[],
|
||||||
login_arg = 'login'
|
login_arg='login'
|
||||||
):
|
):
|
||||||
self.auth = auth
|
self.auth = auth
|
||||||
self.alt_login_form = alt_login_form
|
self.alt_login_form = alt_login_form
|
||||||
@@ -50,7 +52,7 @@ class ExtendedLoginForm(object):
|
|||||||
"""
|
"""
|
||||||
if hasattr(self.alt_login_form, 'get_user'):
|
if hasattr(self.alt_login_form, 'get_user'):
|
||||||
return self.alt_login_form.get_user()
|
return self.alt_login_form.get_user()
|
||||||
return None # let gluon.tools.Auth.get_or_create_user do the rest
|
return None # let gluon.tools.Auth.get_or_create_user do the rest
|
||||||
|
|
||||||
def login_url(self, next):
|
def login_url(self, next):
|
||||||
"""
|
"""
|
||||||
@@ -91,8 +93,8 @@ class ExtendedLoginForm(object):
|
|||||||
args = request.args
|
args = request.args
|
||||||
|
|
||||||
if (self.signals and
|
if (self.signals and
|
||||||
any([True for signal in self.signals if request.vars.has_key(signal)])
|
any([True for signal in self.signals if signal in request.vars])
|
||||||
):
|
):
|
||||||
return self.alt_login_form.login_form()
|
return self.alt_login_form.login_form()
|
||||||
|
|
||||||
self.auth.settings.login_form = self.auth
|
self.auth.settings.login_form = self.auth
|
||||||
@@ -101,5 +103,3 @@ class ExtendedLoginForm(object):
|
|||||||
|
|
||||||
form.components.append(self.alt_login_form.login_form())
|
form.components.append(self.alt_login_form.login_form())
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Thanks to Hans Donner <hans.donner@pobox.com> for GaeGoogleAccount.
|
|||||||
|
|
||||||
from google.appengine.api import users
|
from google.appengine.api import users
|
||||||
|
|
||||||
|
|
||||||
class GaeGoogleAccount(object):
|
class GaeGoogleAccount(object):
|
||||||
"""
|
"""
|
||||||
Login will be done via Google's Appengine login object, instead of web2py's
|
Login will be done via Google's Appengine login object, instead of web2py's
|
||||||
@@ -35,5 +36,3 @@ class GaeGoogleAccount(object):
|
|||||||
if user:
|
if user:
|
||||||
return dict(nickname=user.nickname(), email=user.email(),
|
return dict(nickname=user.nickname(), email=user.email(),
|
||||||
user_id=user.user_id(), source="google account")
|
user_id=user.user_id(), source="google account")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -188,18 +188,23 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
str(custom_scope), str(manage_groups)))
|
str(custom_scope), str(manage_groups)))
|
||||||
if manage_user:
|
if manage_user:
|
||||||
if user_firstname_attrib.count(':') > 0:
|
if user_firstname_attrib.count(':') > 0:
|
||||||
(user_firstname_attrib, user_firstname_part) = user_firstname_attrib.split(':', 1)
|
(user_firstname_attrib,
|
||||||
|
user_firstname_part) = user_firstname_attrib.split(':', 1)
|
||||||
user_firstname_part = (int(user_firstname_part) - 1)
|
user_firstname_part = (int(user_firstname_part) - 1)
|
||||||
else:
|
else:
|
||||||
user_firstname_part = None
|
user_firstname_part = None
|
||||||
if user_lastname_attrib.count(':') > 0:
|
if user_lastname_attrib.count(':') > 0:
|
||||||
(user_lastname_attrib, user_lastname_part) = user_lastname_attrib.split(':', 1)
|
(user_lastname_attrib,
|
||||||
|
user_lastname_part) = user_lastname_attrib.split(':', 1)
|
||||||
user_lastname_part = (int(user_lastname_part) - 1)
|
user_lastname_part = (int(user_lastname_part) - 1)
|
||||||
else:
|
else:
|
||||||
user_lastname_part = None
|
user_lastname_part = None
|
||||||
user_firstname_attrib = ldap.filter.escape_filter_chars(user_firstname_attrib)
|
user_firstname_attrib = ldap.filter.escape_filter_chars(
|
||||||
user_lastname_attrib = ldap.filter.escape_filter_chars(user_lastname_attrib)
|
user_firstname_attrib)
|
||||||
user_mail_attrib = ldap.filter.escape_filter_chars(user_mail_attrib)
|
user_lastname_attrib = ldap.filter.escape_filter_chars(
|
||||||
|
user_lastname_attrib)
|
||||||
|
user_mail_attrib = ldap.filter.escape_filter_chars(
|
||||||
|
user_mail_attrib)
|
||||||
try:
|
try:
|
||||||
if allowed_groups:
|
if allowed_groups:
|
||||||
if not is_user_in_allowed_groups(username, password):
|
if not is_user_in_allowed_groups(username, password):
|
||||||
@@ -310,7 +315,8 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
basedns = ldap_basedn
|
basedns = ldap_basedn
|
||||||
else:
|
else:
|
||||||
basedns = [ldap_basedn]
|
basedns = [ldap_basedn]
|
||||||
filter = '(&(uid=%s)(%s))' % (ldap.filter.escape_filter_chars(username), filterstr)
|
filter = '(&(uid=%s)(%s))' % (
|
||||||
|
ldap.filter.escape_filter_chars(username), filterstr)
|
||||||
found = False
|
found = False
|
||||||
for basedn in basedns:
|
for basedn in basedns:
|
||||||
try:
|
try:
|
||||||
@@ -338,7 +344,8 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
else:
|
else:
|
||||||
basedns = [ldap_basedn]
|
basedns = [ldap_basedn]
|
||||||
filter = '(&(%s=%s)(%s))' % (username_attrib,
|
filter = '(&(%s=%s)(%s))' % (username_attrib,
|
||||||
ldap.filter.escape_filter_chars(username),
|
ldap.filter.escape_filter_chars(
|
||||||
|
username),
|
||||||
filterstr)
|
filterstr)
|
||||||
if custom_scope == 'subtree':
|
if custom_scope == 'subtree':
|
||||||
ldap_scope = ldap.SCOPE_SUBTREE
|
ldap_scope = ldap.SCOPE_SUBTREE
|
||||||
@@ -368,14 +375,16 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
logger.info('[%s] Manage user data' % str(username))
|
logger.info('[%s] Manage user data' % str(username))
|
||||||
try:
|
try:
|
||||||
if user_firstname_part is not None:
|
if user_firstname_part is not None:
|
||||||
store_user_firstname = result[user_firstname_attrib][0].split(' ', 1)[user_firstname_part]
|
store_user_firstname = result[user_firstname_attrib][
|
||||||
|
0].split(' ', 1)[user_firstname_part]
|
||||||
else:
|
else:
|
||||||
store_user_firstname = result[user_firstname_attrib][0]
|
store_user_firstname = result[user_firstname_attrib][0]
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
store_user_firstname = None
|
store_user_firstname = None
|
||||||
try:
|
try:
|
||||||
if user_lastname_part is not None:
|
if user_lastname_part is not None:
|
||||||
store_user_lastname = result[user_lastname_attrib][0].split(' ', 1)[user_lastname_part]
|
store_user_lastname = result[user_lastname_attrib][
|
||||||
|
0].split(' ', 1)[user_lastname_part]
|
||||||
else:
|
else:
|
||||||
store_user_lastname = result[user_lastname_attrib][0]
|
store_user_lastname = result[user_lastname_attrib][0]
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
@@ -464,16 +473,19 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
#
|
#
|
||||||
# Get all group name where the user is in actually in ldap
|
# Get all group name where the user is in actually in ldap
|
||||||
# #########################################################
|
# #########################################################
|
||||||
ldap_groups_of_the_user = get_user_groups_from_ldap(username, password)
|
ldap_groups_of_the_user = get_user_groups_from_ldap(
|
||||||
|
username, password)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get all group name where the user is in actually in local db
|
# Get all group name where the user is in actually in local db
|
||||||
# #############################################################
|
# #############################################################
|
||||||
try:
|
try:
|
||||||
db_user_id = db(db.auth_user.username == username).select(db.auth_user.id).first().id
|
db_user_id = db(db.auth_user.username == username).select(
|
||||||
|
db.auth_user.id).first().id
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
db_user_id = db(db.auth_user.email == username).select(db.auth_user.id).first().id
|
db_user_id = db(db.auth_user.email == username).select(
|
||||||
|
db.auth_user.id).first().id
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
#
|
#
|
||||||
# There is no user in local db
|
# There is no user in local db
|
||||||
@@ -486,7 +498,8 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
db_user_id = db.auth_user.insert(email=username,
|
db_user_id = db.auth_user.insert(email=username,
|
||||||
first_name=username)
|
first_name=username)
|
||||||
if not db_user_id:
|
if not db_user_id:
|
||||||
logging.error('There is no username or email for %s!' % username)
|
logging.error(
|
||||||
|
'There is no username or email for %s!' % username)
|
||||||
raise
|
raise
|
||||||
db_group_search = db((db.auth_membership.user_id == db_user_id) &
|
db_group_search = db((db.auth_membership.user_id == db_user_id) &
|
||||||
(db.auth_user.id == db.auth_membership.user_id) &
|
(db.auth_user.id == db.auth_membership.user_id) &
|
||||||
@@ -520,7 +533,8 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
gid = db.auth_group.insert(role=group_to_add,
|
gid = db.auth_group.insert(role=group_to_add,
|
||||||
description='Generated from LDAP')
|
description='Generated from LDAP')
|
||||||
else:
|
else:
|
||||||
gid = db(db.auth_group.role == group_to_add).select(db.auth_group.id).first().id
|
gid = db(db.auth_group.role == group_to_add).select(
|
||||||
|
db.auth_group.id).first().id
|
||||||
db.auth_membership.insert(user_id=db_user_id,
|
db.auth_membership.insert(user_id=db_user_id,
|
||||||
group_id=gid)
|
group_id=gid)
|
||||||
except:
|
except:
|
||||||
@@ -634,4 +648,3 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
if filterstr[0] == '(' and filterstr[-1] == ')': # rfc4515 syntax
|
if filterstr[0] == '(' and filterstr[-1] == ')': # rfc4515 syntax
|
||||||
filterstr = filterstr[1:-1] # parens added again where used
|
filterstr = filterstr[1:-1] # parens added again where used
|
||||||
return ldap_auth_aux
|
return ldap_auth_aux
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from gluon.http import HTTP
|
|||||||
try:
|
try:
|
||||||
import linkedin
|
import linkedin
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise HTTP(400,"linkedin module not found")
|
raise HTTP(400, "linkedin module not found")
|
||||||
|
|
||||||
|
|
||||||
class LinkedInAccount(object):
|
class LinkedInAccount(object):
|
||||||
"""
|
"""
|
||||||
@@ -28,9 +29,9 @@ class LinkedInAccount(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,request,key,secret,return_url):
|
def __init__(self, request, key, secret, return_url):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.api = linkedin.LinkedIn(key,secret,return_url)
|
self.api = linkedin.LinkedIn(key, secret, return_url)
|
||||||
self.token = result = self.api.requestToken()
|
self.token = result = self.api.requestToken()
|
||||||
|
|
||||||
def login_url(self, next="/"):
|
def login_url(self, next="/"):
|
||||||
@@ -40,13 +41,12 @@ class LinkedInAccount(object):
|
|||||||
return ''
|
return ''
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
result = self.request.vars.verifier and self.api.accessToken(verifier = self.request.vars.verifier )
|
result = self.request.vars.verifier and self.api.accessToken(
|
||||||
|
verifier=self.request.vars.verifier)
|
||||||
if result:
|
if result:
|
||||||
profile = self.api.GetProfile()
|
profile = self.api.GetProfile()
|
||||||
profile = self.api.GetProfile(profile).public_url = "http://www.linkedin.com/in/ozgurv"
|
profile = self.api.GetProfile(
|
||||||
return dict(first_name = profile.first_name,
|
profile).public_url = "http://www.linkedin.com/in/ozgurv"
|
||||||
last_name = profile.last_name,
|
return dict(first_name=profile.first_name,
|
||||||
username = profile.id)
|
last_name=profile.last_name,
|
||||||
|
username=profile.id)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from gluon.tools import fetch
|
|||||||
from gluon.storage import Storage
|
from gluon.storage import Storage
|
||||||
import gluon.contrib.simplejson as json
|
import gluon.contrib.simplejson as json
|
||||||
|
|
||||||
|
|
||||||
class Loginza(object):
|
class Loginza(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -23,13 +24,13 @@ class Loginza(object):
|
|||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
request,
|
request,
|
||||||
url = "",
|
url="",
|
||||||
embed = True,
|
embed=True,
|
||||||
auth_url = "http://loginza.ru/api/authinfo",
|
auth_url="http://loginza.ru/api/authinfo",
|
||||||
language = "en",
|
language="en",
|
||||||
prompt = "loginza",
|
prompt="loginza",
|
||||||
on_login_failure = None,
|
on_login_failure=None,
|
||||||
):
|
):
|
||||||
|
|
||||||
self.request = request
|
self.request = request
|
||||||
self.token_url = url
|
self.token_url = url
|
||||||
@@ -46,49 +47,50 @@ class Loginza(object):
|
|||||||
# FIXME: what if email is unique=True
|
# FIXME: what if email is unique=True
|
||||||
|
|
||||||
self.mappings["http://twitter.com/"] = lambda profile:\
|
self.mappings["http://twitter.com/"] = lambda profile:\
|
||||||
dict(registration_id = profile.get("identity",""),
|
dict(registration_id=profile.get("identity", ""),
|
||||||
username = profile.get("nickname",""),
|
username=profile.get("nickname", ""),
|
||||||
email = profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
last_name = profile.get("name","").get("full_name",""),
|
last_name=profile.get("name", "").get("full_name", ""),
|
||||||
#avatar = profile.get("photo",""),
|
#avatar = profile.get("photo",""),
|
||||||
)
|
)
|
||||||
self.mappings["https://www.google.com/accounts/o8/ud"] = lambda profile:\
|
self.mappings["https://www.google.com/accounts/o8/ud"] = lambda profile:\
|
||||||
dict(registration_id = profile.get("identity",""),
|
dict(registration_id=profile.get("identity", ""),
|
||||||
username = profile.get("name","").get("full_name",""),
|
username=profile.get("name", "").get("full_name", ""),
|
||||||
email = profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
first_name = profile.get("name","").get("first_name",""),
|
first_name=profile.get("name", "").get("first_name", ""),
|
||||||
last_name = profile.get("name","").get("last_name",""),
|
last_name=profile.get("name", "").get("last_name", ""),
|
||||||
#avatar = profile.get("photo",""),
|
#avatar = profile.get("photo",""),
|
||||||
)
|
)
|
||||||
self.mappings["http://vkontakte.ru/"] = lambda profile:\
|
self.mappings["http://vkontakte.ru/"] = lambda profile:\
|
||||||
dict(registration_id=profile.get("identity",""),
|
dict(registration_id=profile.get("identity", ""),
|
||||||
username = profile.get("name","").get("full_name",""),
|
username=profile.get("name", "").get("full_name", ""),
|
||||||
email = profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
first_name = profile.get("name","").get("first_name",""),
|
first_name=profile.get("name", "").get("first_name", ""),
|
||||||
last_name = profile.get("name","").get("last_name",""),
|
last_name=profile.get("name", "").get("last_name", ""),
|
||||||
#avatar = profile.get("photo",""),
|
#avatar = profile.get("photo",""),
|
||||||
)
|
)
|
||||||
self.mappings.default = lambda profile:\
|
self.mappings.default = lambda profile:\
|
||||||
dict(registration_id = profile.get("identity",""),
|
dict(registration_id=profile.get("identity", ""),
|
||||||
username = profile.get("name","").get("full_name"),
|
username=profile.get("name", "").get("full_name"),
|
||||||
email = profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
first_name = profile.get("name","").get("first_name",""),
|
first_name=profile.get("name", "").get("first_name", ""),
|
||||||
last_name = profile.get("name","").get("last_name",""),
|
last_name=profile.get("name", "").get("last_name", ""),
|
||||||
#avatar = profile.get("photo",""),
|
#avatar = profile.get("photo",""),
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
if request.vars.token:
|
if request.vars.token:
|
||||||
user = Storage()
|
user = Storage()
|
||||||
data = urllib.urlencode(dict(token = request.vars.token))
|
data = urllib.urlencode(dict(token=request.vars.token))
|
||||||
auth_info_json = fetch(self.auth_url+'?'+data)
|
auth_info_json = fetch(self.auth_url + '?' + data)
|
||||||
#print auth_info_json
|
#print auth_info_json
|
||||||
auth_info = json.loads(auth_info_json)
|
auth_info = json.loads(auth_info_json)
|
||||||
if auth_info["identity"] != None:
|
if auth_info["identity"] is not None:
|
||||||
self.profile = auth_info
|
self.profile = auth_info
|
||||||
provider = self.profile["provider"]
|
provider = self.profile["provider"]
|
||||||
user = self.mappings.get(provider, self.mappings.default)(self.profile)
|
user = self.mappings.get(
|
||||||
|
provider, self.mappings.default)(self.profile)
|
||||||
#user["password"] = ???
|
#user["password"] = ???
|
||||||
#user["avatar"] = ???
|
#user["avatar"] = ???
|
||||||
return user
|
return user
|
||||||
@@ -106,8 +108,8 @@ class Loginza(object):
|
|||||||
_frameborder="no",
|
_frameborder="no",
|
||||||
_style="width:359px;height:300px;")
|
_style="width:359px;height:300px;")
|
||||||
else:
|
else:
|
||||||
form = DIV(A(self.prompt, _href=LOGINZA_URL % (self.language, self.token_url), _class="loginza"),
|
form = DIV(
|
||||||
SCRIPT(_src="https://s3-eu-west-1.amazonaws.com/s1.loginza.ru/js/widget.js", _type="text/javascript"))
|
A(self.prompt, _href=LOGINZA_URL % (
|
||||||
|
self.language, self.token_url), _class="loginza"),
|
||||||
|
SCRIPT(_src="https://s3-eu-west-1.amazonaws.com/s1.loginza.ru/js/widget.js", _type="text/javascript"))
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import time
|
|||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from gluon.dal import DAL
|
from gluon.dal import DAL
|
||||||
|
|
||||||
|
|
||||||
def motp_auth(db=DAL('sqlite://storage.sqlite'),
|
def motp_auth(db=DAL('sqlite://storage.sqlite'),
|
||||||
time_offset=60):
|
time_offset=60):
|
||||||
|
|
||||||
@@ -44,7 +45,8 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
|
|||||||
writable=False, readable=False, default=''))
|
writable=False, readable=False, default=''))
|
||||||
|
|
||||||
##validators
|
##validators
|
||||||
custom_auth_table = db[auth.settings.table_user_name] # get the custom_auth_table
|
custom_auth_table = db[auth.settings.table_user_name]
|
||||||
|
# get the custom_auth_table
|
||||||
custom_auth_table.first_name.requires = \
|
custom_auth_table.first_name.requires = \
|
||||||
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
|
||||||
custom_auth_table.last_name.requires = \
|
custom_auth_table.last_name.requires = \
|
||||||
@@ -76,14 +78,15 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
|
|||||||
- as of now user field is hardcoded to email. Some way of selecting user table and user field.
|
- as of now user field is hardcoded to email. Some way of selecting user table and user field.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def verify_otp(otp,pin,secret,offset=60):
|
def verify_otp(otp, pin, secret, offset=60):
|
||||||
epoch_time = int(time.time())
|
epoch_time = int(time.time())
|
||||||
time_start = int(str(epoch_time - offset)[:-1])
|
time_start = int(str(epoch_time - offset)[:-1])
|
||||||
time_end = int(str(epoch_time + offset)[:-1])
|
time_end = int(str(epoch_time + offset)[:-1])
|
||||||
for t in range(time_start-1,time_end+1):
|
for t in range(time_start - 1, time_end + 1):
|
||||||
to_hash = str(t)+secret+pin
|
to_hash = str(t) + secret + pin
|
||||||
hash = md5(to_hash).hexdigest()[:6]
|
hash = md5(to_hash).hexdigest()[:6]
|
||||||
if otp == hash: return True
|
if otp == hash:
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def motp_auth_aux(email,
|
def motp_auth_aux(email,
|
||||||
@@ -91,15 +94,18 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
|
|||||||
db=db,
|
db=db,
|
||||||
offset=time_offset):
|
offset=time_offset):
|
||||||
if db:
|
if db:
|
||||||
user_data = db(db.auth_user.email == email ).select().first()
|
user_data = db(db.auth_user.email == email).select().first()
|
||||||
if user_data:
|
if user_data:
|
||||||
if user_data['motp_secret'] and user_data['motp_pin']:
|
if user_data['motp_secret'] and user_data['motp_pin']:
|
||||||
motp_secret = user_data['motp_secret']
|
motp_secret = user_data['motp_secret']
|
||||||
motp_pin = user_data['motp_pin']
|
motp_pin = user_data['motp_pin']
|
||||||
otp_check = verify_otp(password,motp_pin,motp_secret,offset=offset)
|
otp_check = verify_otp(
|
||||||
if otp_check: return True
|
password, motp_pin, motp_secret, offset=offset)
|
||||||
else: return False
|
if otp_check:
|
||||||
else: return False
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False
|
||||||
return False
|
return False
|
||||||
return motp_auth_aux
|
return motp_auth_aux
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from urllib2 import urlopen
|
|||||||
import urllib2
|
import urllib2
|
||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
|
|
||||||
|
|
||||||
class OAuthAccount(object):
|
class OAuthAccount(object):
|
||||||
"""
|
"""
|
||||||
Login will be done via OAuth Framework, instead of web2py's
|
Login will be done via OAuth Framework, instead of web2py's
|
||||||
@@ -51,7 +52,8 @@ class OAuthAccount(object):
|
|||||||
TOKEN_URL="..."
|
TOKEN_URL="..."
|
||||||
ACCESS_TOKEN_URL="..."
|
ACCESS_TOKEN_URL="..."
|
||||||
from gluon.contrib.login_methods.oauth10a_account import OAuthAccount
|
from gluon.contrib.login_methods.oauth10a_account import OAuthAccount
|
||||||
auth.settings.login_form=OAuthAccount(globals(),CLIENT_ID,CLIENT_SECRET, AUTH_URL, TOKEN_URL, ACCESS_TOKEN_URL)
|
auth.settings.login_form=OAuthAccount(globals(
|
||||||
|
),CLIENT_ID,CLIENT_SECRET, AUTH_URL, TOKEN_URL, ACCESS_TOKEN_URL)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -61,20 +63,20 @@ class OAuthAccount(object):
|
|||||||
Appends the _next action to the generated url so the flows continues.
|
Appends the _next action to the generated url so the flows continues.
|
||||||
"""
|
"""
|
||||||
r = self.request
|
r = self.request
|
||||||
http_host=r.env.http_x_forwarded_for
|
http_host = r.env.http_x_forwarded_for
|
||||||
if not http_host: http_host=r.env.http_host
|
if not http_host:
|
||||||
|
http_host = r.env.http_host
|
||||||
|
|
||||||
url_scheme = r.env.wsgi_url_scheme
|
url_scheme = r.env.wsgi_url_scheme
|
||||||
if next:
|
if next:
|
||||||
path_info = next
|
path_info = next
|
||||||
else:
|
else:
|
||||||
path_info = r.env.path_info
|
path_info = r.env.path_info
|
||||||
uri = '%s://%s%s' %(url_scheme, http_host, path_info)
|
uri = '%s://%s%s' % (url_scheme, http_host, path_info)
|
||||||
if r.get_vars and not next:
|
if r.get_vars and not next:
|
||||||
uri += '?' + urlencode(r.get_vars)
|
uri += '?' + urlencode(r.get_vars)
|
||||||
return uri
|
return uri
|
||||||
|
|
||||||
|
|
||||||
def accessToken(self):
|
def accessToken(self):
|
||||||
"""Return the access token generated by the authenticating server.
|
"""Return the access token generated by the authenticating server.
|
||||||
|
|
||||||
@@ -97,12 +99,11 @@ class OAuthAccount(object):
|
|||||||
token.set_verifier(self.request.vars.oauth_verifier)
|
token.set_verifier(self.request.vars.oauth_verifier)
|
||||||
client = oauth.Client(self.consumer, token)
|
client = oauth.Client(self.consumer, token)
|
||||||
|
|
||||||
|
|
||||||
resp, content = client.request(self.access_token_url, "POST")
|
resp, content = client.request(self.access_token_url, "POST")
|
||||||
if str(resp['status']) != '200':
|
if str(resp['status']) != '200':
|
||||||
self.session.request_token = None
|
self.session.request_token = None
|
||||||
self.globals['redirect'](self.globals['URL'](f='user',args='logout'))
|
self.globals['redirect'](self.globals[
|
||||||
|
'URL'](f='user', args='logout'))
|
||||||
|
|
||||||
self.session.access_token = oauth.Token.from_string(content)
|
self.session.access_token = oauth.Token.from_string(content)
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ class OAuthAccount(object):
|
|||||||
self.session.access_token = None
|
self.session.access_token = None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __init__(self, g, client_id, client_secret, auth_url, token_url, access_token_url):
|
def __init__(self, g, client_id, client_secret, auth_url, token_url, access_token_url):
|
||||||
self.globals = g
|
self.globals = g
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
self.client_secret = client_secret
|
self.client_secret = client_secret
|
||||||
@@ -125,7 +126,6 @@ class OAuthAccount(object):
|
|||||||
# consumer init
|
# consumer init
|
||||||
self.consumer = oauth.Consumer(self.client_id, self.client_secret)
|
self.consumer = oauth.Consumer(self.client_id, self.client_secret)
|
||||||
|
|
||||||
|
|
||||||
def login_url(self, next="/"):
|
def login_url(self, next="/"):
|
||||||
self.__oauth_login(next)
|
self.__oauth_login(next)
|
||||||
return next
|
return next
|
||||||
@@ -142,7 +142,7 @@ class OAuthAccount(object):
|
|||||||
is, this function must be implemented for the specific
|
is, this function must be implemented for the specific
|
||||||
provider.
|
provider.
|
||||||
'''
|
'''
|
||||||
raise NotImplementedError, "Must override get_user()"
|
raise NotImplementedError("Must override get_user()")
|
||||||
|
|
||||||
def __oauth_login(self, next):
|
def __oauth_login(self, next):
|
||||||
'''This method redirects the user to the authenticating form
|
'''This method redirects the user to the authenticating form
|
||||||
@@ -163,10 +163,11 @@ class OAuthAccount(object):
|
|||||||
# putting it in the body seems to work.
|
# putting it in the body seems to work.
|
||||||
callback_url = self.__redirect_uri(next)
|
callback_url = self.__redirect_uri(next)
|
||||||
data = urlencode(dict(oauth_callback=callback_url))
|
data = urlencode(dict(oauth_callback=callback_url))
|
||||||
resp, content = client.request(self.token_url, "POST", body=data)
|
resp, content = client.request(self.token_url, "POST", body=data)
|
||||||
if resp['status'] != '200':
|
if resp['status'] != '200':
|
||||||
self.session.request_token = None
|
self.session.request_token = None
|
||||||
self.globals['redirect'](self.globals['URL'](f='user',args='logout'))
|
self.globals['redirect'](self.globals[
|
||||||
|
'URL'](f='user', args='logout'))
|
||||||
|
|
||||||
# Store the request token in session.
|
# Store the request token in session.
|
||||||
request_token = self.session.request_token = oauth.Token.from_string(content)
|
request_token = self.session.request_token = oauth.Token.from_string(content)
|
||||||
@@ -174,18 +175,12 @@ class OAuthAccount(object):
|
|||||||
# Redirect the user to the authentication URL and pass the callback url.
|
# Redirect the user to the authentication URL and pass the callback url.
|
||||||
data = urlencode(dict(oauth_token=request_token.key,
|
data = urlencode(dict(oauth_token=request_token.key,
|
||||||
oauth_callback=callback_url))
|
oauth_callback=callback_url))
|
||||||
auth_request_url = self.auth_url + '?' +data
|
auth_request_url = self.auth_url + '?' + data
|
||||||
|
|
||||||
|
|
||||||
HTTP = self.globals['HTTP']
|
HTTP = self.globals['HTTP']
|
||||||
|
|
||||||
|
|
||||||
raise HTTP(307,
|
raise HTTP(307,
|
||||||
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
|
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
|
||||||
Location=auth_request_url)
|
Location=auth_request_url)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import urllib2
|
|||||||
from urllib import urlencode
|
from urllib import urlencode
|
||||||
from gluon import current, redirect, HTTP
|
from gluon import current, redirect, HTTP
|
||||||
|
|
||||||
|
|
||||||
class OAuthAccount(object):
|
class OAuthAccount(object):
|
||||||
"""
|
"""
|
||||||
Login will be done via OAuth Framework, instead of web2py's
|
Login will be done via OAuth Framework, instead of web2py's
|
||||||
@@ -84,7 +85,8 @@ class OAuthAccount(object):
|
|||||||
username = user['id'])
|
username = user['id'])
|
||||||
|
|
||||||
|
|
||||||
auth.settings.actions_disabled=['register','change_password','request_reset_password','profile']
|
auth.settings.actions_disabled=['register',
|
||||||
|
'change_password','request_reset_password','profile']
|
||||||
auth.settings.login_form=FaceBookAccount()
|
auth.settings.login_form=FaceBookAccount()
|
||||||
|
|
||||||
Any optional arg in the constructor will be passed asis to remote
|
Any optional arg in the constructor will be passed asis to remote
|
||||||
@@ -99,8 +101,9 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
r = current.request
|
r = current.request
|
||||||
http_host=r.env.http_x_forwarded_for
|
http_host = r.env.http_x_forwarded_for
|
||||||
if not http_host: http_host=r.env.http_host
|
if not http_host:
|
||||||
|
http_host = r.env.http_host
|
||||||
|
|
||||||
url_scheme = r.env.wsgi_url_scheme
|
url_scheme = r.env.wsgi_url_scheme
|
||||||
if next:
|
if next:
|
||||||
@@ -112,7 +115,6 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
uri += '?' + urlencode(r.get_vars)
|
uri += '?' + urlencode(r.get_vars)
|
||||||
return uri
|
return uri
|
||||||
|
|
||||||
|
|
||||||
def __build_url_opener(self, uri):
|
def __build_url_opener(self, uri):
|
||||||
"""
|
"""
|
||||||
Build the url opener for managing HTTP Basic Athentication
|
Build the url opener for managing HTTP Basic Athentication
|
||||||
@@ -128,7 +130,6 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
opener = urllib2.build_opener(auth_handler)
|
opener = urllib2.build_opener(auth_handler)
|
||||||
return opener
|
return opener
|
||||||
|
|
||||||
|
|
||||||
def accessToken(self):
|
def accessToken(self):
|
||||||
"""
|
"""
|
||||||
Return the access token generated by the authenticating server.
|
Return the access token generated by the authenticating server.
|
||||||
@@ -137,7 +138,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
Otherwise the token is fetched from the auth server.
|
Otherwise the token is fetched from the auth server.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if current.session.token and current.session.token.has_key('expires'):
|
if current.session.token and 'expires' in current.session.token:
|
||||||
expires = current.session.token['expires']
|
expires = current.session.token['expires']
|
||||||
# reuse token until expiration
|
# reuse token until expiration
|
||||||
if expires == 0 or expires > time.time():
|
if expires == 0 or expires > time.time():
|
||||||
@@ -159,19 +160,19 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
print tmp
|
print tmp
|
||||||
raise Exception(tmp)
|
raise Exception(tmp)
|
||||||
finally:
|
finally:
|
||||||
del current.session.code # throw it away
|
del current.session.code # throw it away
|
||||||
|
|
||||||
if open_url:
|
if open_url:
|
||||||
try:
|
try:
|
||||||
data = open_url.read()
|
data = open_url.read()
|
||||||
tokendata = cgi.parse_qs(data)
|
tokendata = cgi.parse_qs(data)
|
||||||
current.session.token = \
|
current.session.token = \
|
||||||
dict([(k,v[-1]) for k,v in tokendata.items()])
|
dict([(k, v[-1]) for k, v in tokendata.items()])
|
||||||
# set expiration absolute time try to avoid broken
|
# set expiration absolute time try to avoid broken
|
||||||
# implementations where "expires_in" becomes "expires"
|
# implementations where "expires_in" becomes "expires"
|
||||||
if current.session.token.has_key('expires_in'):
|
if 'expires_in' in current.session.token:
|
||||||
exps = 'expires_in'
|
exps = 'expires_in'
|
||||||
elif current.session.token.has_key('expires'):
|
elif 'expires' in current.session.token:
|
||||||
exps = 'expires'
|
exps = 'expires'
|
||||||
else:
|
else:
|
||||||
exps = None
|
exps = None
|
||||||
@@ -217,11 +218,12 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
Override this method by sublcassing the class.
|
Override this method by sublcassing the class.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not current.session.token: return None
|
if not current.session.token:
|
||||||
return dict(first_name = 'Pinco',
|
return None
|
||||||
last_name = 'Pallino',
|
return dict(first_name='Pinco',
|
||||||
username = 'pincopallino')
|
last_name='Pallino',
|
||||||
raise NotImplementedError, "Must override get_user()"
|
username='pincopallino')
|
||||||
|
raise NotImplementedError("Must override get_user()")
|
||||||
|
|
||||||
# Following code is never executed. It can be used as example
|
# Following code is never executed. It can be used as example
|
||||||
# for overriding in subclasses.
|
# for overriding in subclasses.
|
||||||
@@ -239,10 +241,9 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
self.graph = None
|
self.graph = None
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
return dict(first_name = user['first_name'],
|
return dict(first_name=user['first_name'],
|
||||||
last_name = user['last_name'],
|
last_name=user['last_name'],
|
||||||
username = user['id'])
|
username=user['id'])
|
||||||
|
|
||||||
|
|
||||||
def __oauth_login(self, next):
|
def __oauth_login(self, next):
|
||||||
"""
|
"""
|
||||||
@@ -258,13 +259,13 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
|
|
||||||
if not self.accessToken():
|
if not self.accessToken():
|
||||||
if not current.request.vars.code:
|
if not current.request.vars.code:
|
||||||
current.session.redirect_uri=self.__redirect_uri(next)
|
current.session.redirect_uri = self.__redirect_uri(next)
|
||||||
data = dict(redirect_uri=current.session.redirect_uri,
|
data = dict(redirect_uri=current.session.redirect_uri,
|
||||||
response_type='code',
|
response_type='code',
|
||||||
client_id=self.client_id)
|
client_id=self.client_id)
|
||||||
if self.args:
|
if self.args:
|
||||||
data.update(self.args)
|
data.update(self.args)
|
||||||
auth_request_url = self.auth_url + "?" +urlencode(data)
|
auth_request_url = self.auth_url + "?" + urlencode(data)
|
||||||
raise HTTP(307,
|
raise HTTP(307,
|
||||||
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
|
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
|
||||||
Location=auth_request_url)
|
Location=auth_request_url)
|
||||||
@@ -273,5 +274,3 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
self.accessToken()
|
self.accessToken()
|
||||||
return current.session.code
|
return current.session.code
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ except ImportError, err:
|
|||||||
|
|
||||||
DEFAULT = lambda: None
|
DEFAULT = lambda: None
|
||||||
|
|
||||||
|
|
||||||
class OpenIDAuth(object):
|
class OpenIDAuth(object):
|
||||||
"""
|
"""
|
||||||
OpenIDAuth
|
OpenIDAuth
|
||||||
@@ -94,7 +95,7 @@ class OpenIDAuth(object):
|
|||||||
if not auth.settings.table_user:
|
if not auth.settings.table_user:
|
||||||
raise
|
raise
|
||||||
self.table_user = self.auth.settings.table_user
|
self.table_user = self.auth.settings.table_user
|
||||||
self.openid_expiration = 15 #minutes
|
self.openid_expiration = 15 # minutes
|
||||||
|
|
||||||
self.messages = self._define_messages()
|
self.messages = self._define_messages()
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ class OpenIDAuth(object):
|
|||||||
messages.flash_openid_associated = 'OpenID associated'
|
messages.flash_openid_associated = 'OpenID associated'
|
||||||
messages.flash_associate_openid = 'Please login or register an account for this OpenID.'
|
messages.flash_associate_openid = 'Please login or register an account for this OpenID.'
|
||||||
messages.p_openid_not_registered = "This Open ID haven't be registered. " \
|
messages.p_openid_not_registered = "This Open ID haven't be registered. " \
|
||||||
+ "Please login to associate with it or register an account for it."
|
+ "Please login to associate with it or register an account for it."
|
||||||
messages.flash_openid_authenticated = 'OpenID authenticated successfully.'
|
messages.flash_openid_authenticated = 'OpenID authenticated successfully.'
|
||||||
messages.flash_openid_fail_authentication = 'OpenID authentication failed. (Error message: %s)'
|
messages.flash_openid_fail_authentication = 'OpenID authentication failed. (Error message: %s)'
|
||||||
messages.flash_openid_canceled = 'OpenID authentication canceled by user.'
|
messages.flash_openid_canceled = 'OpenID authentication canceled by user.'
|
||||||
@@ -158,7 +159,7 @@ class OpenIDAuth(object):
|
|||||||
and not processed yet. Else return the OpenID form for login.
|
and not processed yet. Else return the OpenID form for login.
|
||||||
"""
|
"""
|
||||||
request = current.request
|
request = current.request
|
||||||
if request.vars.has_key('janrain_nonce') and not self._processed():
|
if 'janrain_nonce' in request.vars and not self._processed():
|
||||||
self._process_response()
|
self._process_response()
|
||||||
return self.auth()
|
return self.auth()
|
||||||
return self._form()
|
return self._form()
|
||||||
@@ -172,12 +173,12 @@ class OpenIDAuth(object):
|
|||||||
args = request.args
|
args = request.args
|
||||||
|
|
||||||
if args[0] == 'logout':
|
if args[0] == 'logout':
|
||||||
return True # Let logout_url got called
|
return True # Let logout_url got called
|
||||||
|
|
||||||
if current.session.w2popenid:
|
if current.session.w2popenid:
|
||||||
w2popenid = current.session.w2popenid
|
w2popenid = current.session.w2popenid
|
||||||
db = self.db
|
db = self.db
|
||||||
if (w2popenid.ok is True and w2popenid.oid): # OpenID authenticated
|
if (w2popenid.ok is True and w2popenid.oid): # OpenID authenticated
|
||||||
if self._w2popenid_expired(w2popenid):
|
if self._w2popenid_expired(w2popenid):
|
||||||
del(current.session.w2popenid)
|
del(current.session.w2popenid)
|
||||||
flash = self.messages.flash_openid_expired
|
flash = self.messages.flash_openid_expired
|
||||||
@@ -196,22 +197,23 @@ class OpenIDAuth(object):
|
|||||||
if current.session.w2popenid:
|
if current.session.w2popenid:
|
||||||
del(current.session.w2popenid)
|
del(current.session.w2popenid)
|
||||||
current.session.flash = self.messages.flash_openid_associated
|
current.session.flash = self.messages.flash_openid_associated
|
||||||
if request.vars.has_key(nextvar):
|
if nextvar in request.vars:
|
||||||
redirect(request.vars[nextvar])
|
redirect(request.vars[nextvar])
|
||||||
redirect(self.auth.settings.login_next)
|
redirect(self.auth.settings.login_next)
|
||||||
|
|
||||||
if not request.vars.has_key(nextvar):
|
if nextvar not in request.vars:
|
||||||
# no next var, add it and do login again
|
# no next var, add it and do login again
|
||||||
# so if user login or register can go back here to associate the OpenID
|
# so if user login or register can go back here to associate the OpenID
|
||||||
redirect(URL(r=request,
|
redirect(URL(r=request,
|
||||||
args=['login'],
|
args=['login'],
|
||||||
vars={nextvar:self.login_url}))
|
vars={nextvar: self.login_url}))
|
||||||
self.login_form = self._form_with_notification()
|
self.login_form = self._form_with_notification()
|
||||||
current.session.flash = self.messages.flash_associate_openid
|
current.session.flash = self.messages.flash_associate_openid
|
||||||
return None # need to login or register to associate this openid
|
return None # need to login or register to associate this openid
|
||||||
|
|
||||||
# Get existed OpenID user
|
# Get existed OpenID user
|
||||||
user = db(self.table_user.id==alt_login.user).select().first()
|
user = db(
|
||||||
|
self.table_user.id == alt_login.user).select().first()
|
||||||
if user:
|
if user:
|
||||||
if current.session.w2popenid:
|
if current.session.w2popenid:
|
||||||
del(current.session.w2popenid)
|
del(current.session.w2popenid)
|
||||||
@@ -219,16 +221,17 @@ class OpenIDAuth(object):
|
|||||||
username = 'username'
|
username = 'username'
|
||||||
elif 'email' in self.table_user.fields():
|
elif 'email' in self.table_user.fields():
|
||||||
username = 'email'
|
username = 'email'
|
||||||
return {username: user[username]} if user else None # login success (almost)
|
return {username: user[username]} if user else None # login success (almost)
|
||||||
|
|
||||||
return None # just start to login
|
return None # just start to login
|
||||||
|
|
||||||
def _find_matched_openid(self, db, oid, type_='openid'):
|
def _find_matched_openid(self, db, oid, type_='openid'):
|
||||||
"""
|
"""
|
||||||
Get the matched OpenID for given
|
Get the matched OpenID for given
|
||||||
"""
|
"""
|
||||||
query = ((db.alt_logins.username == oid) & (db.alt_logins.type == type_))
|
query = (
|
||||||
alt_login = db(query).select().first() # Get the OpenID record
|
(db.alt_logins.username == oid) & (db.alt_logins.type == type_))
|
||||||
|
alt_login = db(query).select().first() # Get the OpenID record
|
||||||
return alt_login
|
return alt_login
|
||||||
|
|
||||||
def _associate_user_openid(self, user, oid):
|
def _associate_user_openid(self, user, oid):
|
||||||
@@ -275,7 +278,6 @@ class OpenIDAuth(object):
|
|||||||
self.db)
|
self.db)
|
||||||
return self.consumerhelper
|
return self.consumerhelper
|
||||||
|
|
||||||
|
|
||||||
def _form(self, style=None):
|
def _form(self, style=None):
|
||||||
form = DIV(H3(self.messages.h_openid_login), self._login_form(style))
|
form = DIV(H3(self.messages.h_openid_login), self._login_form(style))
|
||||||
return form
|
return form
|
||||||
@@ -300,7 +302,7 @@ background-color: transparent;
|
|||||||
padding-left: 18px;
|
padding-left: 18px;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
"""
|
"""
|
||||||
style = style.replace("\n","")
|
style = style.replace("\n", "")
|
||||||
|
|
||||||
request = current.request
|
request = current.request
|
||||||
session = current.session
|
session = current.session
|
||||||
@@ -308,21 +310,25 @@ width: 400px;
|
|||||||
hidden_next_input = ""
|
hidden_next_input = ""
|
||||||
if _next == 'profile':
|
if _next == 'profile':
|
||||||
profile_url = URL(r=request, f='user', args=['profile'])
|
profile_url = URL(r=request, f='user', args=['profile'])
|
||||||
hidden_next_input = INPUT(_type="hidden", _name="_next", _value=profile_url)
|
hidden_next_input = INPUT(
|
||||||
form = FORM(openid_field_label or self.messages.label_alt_login_username,
|
_type="hidden", _name="_next", _value=profile_url)
|
||||||
INPUT(_type="input", _name="oid",
|
form = FORM(
|
||||||
requires=IS_NOT_EMPTY(error_message=messages.openid_fail_discover),
|
openid_field_label or self.messages.label_alt_login_username,
|
||||||
_style=style),
|
INPUT(_type="input", _name="oid",
|
||||||
hidden_next_input,
|
requires=IS_NOT_EMPTY(
|
||||||
INPUT(_type="submit", _value=submit_button or messages.submit_button),
|
error_message=messages.openid_fail_discover),
|
||||||
" ",
|
_style=style),
|
||||||
A(messages.comment_openid_signin,
|
hidden_next_input,
|
||||||
_href=messages.comment_openid_help_url,
|
INPUT(_type="submit",
|
||||||
_title=messages.comment_openid_help_title,
|
_value=submit_button or messages.submit_button),
|
||||||
_class='openid-identifier',
|
" ",
|
||||||
_target="_blank"),
|
A(messages.comment_openid_signin,
|
||||||
_action=self.login_url
|
_href=messages.comment_openid_help_url,
|
||||||
)
|
_title=messages.comment_openid_help_title,
|
||||||
|
_class='openid-identifier',
|
||||||
|
_target="_blank"),
|
||||||
|
_action=self.login_url
|
||||||
|
)
|
||||||
if form.accepts(request.vars, session):
|
if form.accepts(request.vars, session):
|
||||||
oid = request.vars.oid
|
oid = request.vars.oid
|
||||||
consumerhelper = self._init_consumerhelper()
|
consumerhelper = self._init_consumerhelper()
|
||||||
@@ -332,8 +338,9 @@ width: 400px;
|
|||||||
warning_openid_fail(session)
|
warning_openid_fail(session)
|
||||||
redirect(url)
|
redirect(url)
|
||||||
try:
|
try:
|
||||||
if request.vars.has_key('_next'):
|
if '_next' in request.vars:
|
||||||
return_to_url = self.return_to_url + '?_next=' + request.vars._next
|
return_to_url = self.return_to_url + \
|
||||||
|
'?_next=' + request.vars._next
|
||||||
url = consumerhelper.begin(oid, self.realm, return_to_url)
|
url = consumerhelper.begin(oid, self.realm, return_to_url)
|
||||||
except DiscoveryFailure:
|
except DiscoveryFailure:
|
||||||
warning_openid_fail(session)
|
warning_openid_fail(session)
|
||||||
@@ -353,7 +360,8 @@ width: 400px;
|
|||||||
"""
|
"""
|
||||||
Set expiration for OpenID authentication.
|
Set expiration for OpenID authentication.
|
||||||
"""
|
"""
|
||||||
w2popenid.expiration = datetime.now() + timedelta(minutes=self.openid_expiration)
|
w2popenid.expiration = datetime.now(
|
||||||
|
) + timedelta(minutes=self.openid_expiration)
|
||||||
|
|
||||||
def _w2popenid_expired(self, w2popenid):
|
def _w2popenid_expired(self, w2popenid):
|
||||||
"""
|
"""
|
||||||
@@ -369,7 +377,8 @@ width: 400px;
|
|||||||
request = current.request
|
request = current.request
|
||||||
request_vars = request.vars
|
request_vars = request.vars
|
||||||
consumerhelper = self._init_consumerhelper()
|
consumerhelper = self._init_consumerhelper()
|
||||||
process_status = consumerhelper.process_response(request_vars, self.return_to_url)
|
process_status = consumerhelper.process_response(
|
||||||
|
request_vars, self.return_to_url)
|
||||||
if process_status == "success":
|
if process_status == "success":
|
||||||
w2popenid = current.session.w2popenid
|
w2popenid = current.session.w2popenid
|
||||||
user_data = self.consumerhelper.sreg()
|
user_data = self.consumerhelper.sreg()
|
||||||
@@ -388,7 +397,7 @@ width: 400px;
|
|||||||
def list_user_openids(self):
|
def list_user_openids(self):
|
||||||
messages = self.messages
|
messages = self.messages
|
||||||
request = current.request
|
request = current.request
|
||||||
if request.vars.has_key('delete_openid'):
|
if 'delete_openid' in request.vars:
|
||||||
self.remove_openid(request.vars.delete_openid)
|
self.remove_openid(request.vars.delete_openid)
|
||||||
|
|
||||||
query = self.db.alt_logins.user == self.auth.user.id
|
query = self.db.alt_logins.user == self.auth.user.id
|
||||||
@@ -397,8 +406,8 @@ width: 400px;
|
|||||||
for alt_login in alt_logins:
|
for alt_login in alt_logins:
|
||||||
username = alt_login.username
|
username = alt_login.username
|
||||||
delete_href = URL(r=request, f='user',
|
delete_href = URL(r=request, f='user',
|
||||||
args=['profile'],
|
args=['profile'],
|
||||||
vars={'delete_openid': username})
|
vars={'delete_openid': username})
|
||||||
delete_link = A(messages.a_delete, _href=delete_href)
|
delete_link = A(messages.a_delete, _href=delete_href)
|
||||||
l.append(LI(username, " ", delete_link))
|
l.append(LI(username, " ", delete_link))
|
||||||
|
|
||||||
@@ -409,23 +418,23 @@ width: 400px;
|
|||||||
_next='profile',
|
_next='profile',
|
||||||
submit_button=messages.submit_button_add,
|
submit_button=messages.submit_button_add,
|
||||||
openid_field_label=messages.label_add_alt_login_username)
|
openid_field_label=messages.label_add_alt_login_username)
|
||||||
)
|
)
|
||||||
return openid_list
|
return openid_list
|
||||||
|
|
||||||
|
|
||||||
def remove_openid(self, openid):
|
def remove_openid(self, openid):
|
||||||
query = self.db.alt_logins.username == openid
|
query = self.db.alt_logins.username == openid
|
||||||
self.db(query).delete()
|
self.db(query).delete()
|
||||||
|
|
||||||
|
|
||||||
class ConsumerHelper(object):
|
class ConsumerHelper(object):
|
||||||
"""
|
"""
|
||||||
ConsumerHelper knows the python-openid and
|
ConsumerHelper knows the python-openid and
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, session, db):
|
def __init__(self, session, db):
|
||||||
self.session = session
|
self.session = session
|
||||||
store = self._init_store(db)
|
store = self._init_store(db)
|
||||||
self.consumer = openid.consumer.consumer.Consumer(session, store)
|
self.consumer = openid.consumer.consumer.Consumer(session, store)
|
||||||
|
|
||||||
def _init_store(self, db):
|
def _init_store(self, db):
|
||||||
"""
|
"""
|
||||||
@@ -434,7 +443,7 @@ class ConsumerHelper(object):
|
|||||||
if not hasattr(self, "store"):
|
if not hasattr(self, "store"):
|
||||||
store = Web2pyStore(db)
|
store = Web2pyStore(db)
|
||||||
session = self.session
|
session = self.session
|
||||||
if not session.has_key('w2popenid'):
|
if 'w2popenid' not in session:
|
||||||
session.w2popenid = Storage()
|
session.w2popenid = Storage()
|
||||||
self.store = store
|
self.store = store
|
||||||
return self.store
|
return self.store
|
||||||
@@ -446,7 +455,7 @@ class ConsumerHelper(object):
|
|||||||
w2popenid = self.session.w2popenid
|
w2popenid = self.session.w2popenid
|
||||||
w2popenid.oid = oid
|
w2popenid.oid = oid
|
||||||
auth_req = self.consumer.begin(oid)
|
auth_req = self.consumer.begin(oid)
|
||||||
auth_req.addExtension(SRegRequest(required=['email','nickname']))
|
auth_req.addExtension(SRegRequest(required=['email', 'nickname']))
|
||||||
url = auth_req.redirectURL(return_to=return_to_url, realm=realm)
|
url = auth_req.redirectURL(return_to=return_to_url, realm=realm)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@@ -504,19 +513,27 @@ class Web2pyStore(OpenIDStore):
|
|||||||
|
|
||||||
if self.table_oid_associations_name not in self.database:
|
if self.table_oid_associations_name not in self.database:
|
||||||
self.database.define_table(self.table_oid_associations_name,
|
self.database.define_table(self.table_oid_associations_name,
|
||||||
Field('server_url', 'string', length=2047, required=True),
|
Field('server_url',
|
||||||
Field('handle', 'string', length=255, required=True),
|
'string', length=2047, required=True),
|
||||||
Field('secret', 'blob', required=True),
|
Field('handle',
|
||||||
Field('issued', 'integer', required=True),
|
'string', length=255, required=True),
|
||||||
Field('lifetime', 'integer', required=True),
|
Field('secret', 'blob', required=True),
|
||||||
Field('assoc_type', 'string', length=64, required=True)
|
Field('issued',
|
||||||
)
|
'integer', required=True),
|
||||||
|
Field('lifetime',
|
||||||
|
'integer', required=True),
|
||||||
|
Field('assoc_type',
|
||||||
|
'string', length=64, required=True)
|
||||||
|
)
|
||||||
if self.table_oid_nonces_name not in self.database:
|
if self.table_oid_nonces_name not in self.database:
|
||||||
self.database.define_table(self.table_oid_nonces_name,
|
self.database.define_table(self.table_oid_nonces_name,
|
||||||
Field('server_url', 'string', length=2047, required=True),
|
Field('server_url',
|
||||||
Field('timestamp', 'integer', required=True),
|
'string', length=2047, required=True),
|
||||||
Field('salt', 'string', length=40, required=True)
|
Field('timestamp',
|
||||||
)
|
'integer', required=True),
|
||||||
|
Field('salt', 'string',
|
||||||
|
length=40, required=True)
|
||||||
|
)
|
||||||
|
|
||||||
def storeAssociation(self, server_url, association):
|
def storeAssociation(self, server_url, association):
|
||||||
"""
|
"""
|
||||||
@@ -525,14 +542,15 @@ class Web2pyStore(OpenIDStore):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
db = self.database
|
db = self.database
|
||||||
query = (db.oid_associations.server_url == server_url) & (db.oid_associations.handle == association.handle)
|
query = (db.oid_associations.server_url == server_url) & (
|
||||||
|
db.oid_associations.handle == association.handle)
|
||||||
db(query).delete()
|
db(query).delete()
|
||||||
db.oid_associations.insert(server_url = server_url,
|
db.oid_associations.insert(server_url=server_url,
|
||||||
handle = association.handle,
|
handle=association.handle,
|
||||||
secret = association.secret,
|
secret=association.secret,
|
||||||
issued = association.issued,
|
issued=association.issued,
|
||||||
lifetime = association.lifetime,
|
lifetime=association.lifetime,
|
||||||
assoc_type = association.assoc_type), 'insert '*10
|
assoc_type=association.assoc_type), 'insert ' * 10
|
||||||
|
|
||||||
def getAssociation(self, server_url, handle=None):
|
def getAssociation(self, server_url, handle=None):
|
||||||
"""
|
"""
|
||||||
@@ -550,7 +568,8 @@ class Web2pyStore(OpenIDStore):
|
|||||||
if len(keep_assoc) == 0:
|
if len(keep_assoc) == 0:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
assoc = keep_assoc.pop() # pop the last one as it should be the latest one
|
assoc = keep_assoc.pop(
|
||||||
|
) # pop the last one as it should be the latest one
|
||||||
return Association(assoc['handle'],
|
return Association(assoc['handle'],
|
||||||
assoc['secret'],
|
assoc['secret'],
|
||||||
assoc['issued'],
|
assoc['issued'],
|
||||||
@@ -559,8 +578,9 @@ class Web2pyStore(OpenIDStore):
|
|||||||
|
|
||||||
def removeAssociation(self, server_url, handle):
|
def removeAssociation(self, server_url, handle):
|
||||||
db = self.database
|
db = self.database
|
||||||
query = (db.oid_associations.server_url == server_url) & (db.oid_associations.handle == handle)
|
query = (db.oid_associations.server_url == server_url) & (
|
||||||
return db(query).delete() != None
|
db.oid_associations.handle == handle)
|
||||||
|
return db(query).delete() is not None
|
||||||
|
|
||||||
def useNonce(self, server_url, timestamp, salt):
|
def useNonce(self, server_url, timestamp, salt):
|
||||||
"""
|
"""
|
||||||
@@ -575,10 +595,10 @@ class Web2pyStore(OpenIDStore):
|
|||||||
if db(query).count() > 0:
|
if db(query).count() > 0:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
db.oid_nonces.insert(server_url = server_url,
|
db.oid_nonces.insert(server_url=server_url,
|
||||||
timestamp = timestamp,
|
timestamp=timestamp,
|
||||||
salt = salt)
|
salt=salt)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _removeExpiredAssocations(self, rows):
|
def _removeExpiredAssocations(self, rows):
|
||||||
"""
|
"""
|
||||||
@@ -599,7 +619,7 @@ class Web2pyStore(OpenIDStore):
|
|||||||
keep_assoc.append(r)
|
keep_assoc.append(r)
|
||||||
for r in remove_assoc:
|
for r in remove_assoc:
|
||||||
del db.oid_associations[r['id']]
|
del db.oid_associations[r['id']]
|
||||||
return (keep_assoc, len(remove_assoc)) # return tuple (list of valid associations, number of deleted associations)
|
return (keep_assoc, len(remove_assoc)) # return tuple (list of valid associations, number of deleted associations)
|
||||||
|
|
||||||
def cleanupNonces(self):
|
def cleanupNonces(self):
|
||||||
"""
|
"""
|
||||||
@@ -619,7 +639,7 @@ class Web2pyStore(OpenIDStore):
|
|||||||
|
|
||||||
db = self.database
|
db = self.database
|
||||||
query = (db.oid_associations.id > 0)
|
query = (db.oid_associations.id > 0)
|
||||||
return self._removeExpiredAssocations(db(query).select())[1] #return number of assoc removed
|
return self._removeExpiredAssocations(db(query).select())[1] # return number of assoc removed
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
"""
|
"""
|
||||||
@@ -628,6 +648,3 @@ class Web2pyStore(OpenIDStore):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return self.cleanupNonces(), self.cleanupAssociations()
|
return self.cleanupNonces(), self.cleanupAssociations()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from gluon.contrib.pam import authenticate
|
from gluon.contrib.pam import authenticate
|
||||||
|
|
||||||
|
|
||||||
def pam_auth():
|
def pam_auth():
|
||||||
"""
|
"""
|
||||||
to use pam_login:
|
to use pam_login:
|
||||||
@@ -19,5 +20,3 @@ def pam_auth():
|
|||||||
return authenticate(username, password)
|
return authenticate(username, password)
|
||||||
|
|
||||||
return pam_auth_aux
|
return pam_auth_aux
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,13 @@ from gluon.tools import fetch
|
|||||||
from gluon.storage import Storage
|
from gluon.storage import Storage
|
||||||
import gluon.contrib.simplejson as json
|
import gluon.contrib.simplejson as json
|
||||||
|
|
||||||
|
|
||||||
class RPXAccount(object):
|
class RPXAccount(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from gluon.contrib.login_methods.rpx_account import RPXAccount
|
from gluon.contrib.login_methods.rpx_account import RPXAccount
|
||||||
auth.settings.actions_disabled=['register','change_password','request_reset_password']
|
auth.settings.actions_disabled=['register','change_password',
|
||||||
|
'request_reset_password']
|
||||||
auth.settings.login_form = RPXAccount(request,
|
auth.settings.login_form = RPXAccount(request,
|
||||||
api_key="...",
|
api_key="...",
|
||||||
domain="...",
|
domain="...",
|
||||||
@@ -32,18 +34,18 @@ class RPXAccount(object):
|
|||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
request,
|
request,
|
||||||
api_key = "",
|
api_key="",
|
||||||
domain = "",
|
domain="",
|
||||||
url = "",
|
url="",
|
||||||
embed = True,
|
embed=True,
|
||||||
auth_url = "https://rpxnow.com/api/v2/auth_info",
|
auth_url="https://rpxnow.com/api/v2/auth_info",
|
||||||
language= "en",
|
language="en",
|
||||||
prompt='rpx',
|
prompt='rpx',
|
||||||
on_login_failure = None,
|
on_login_failure=None,
|
||||||
):
|
):
|
||||||
|
|
||||||
self.request=request
|
self.request = request
|
||||||
self.api_key=api_key
|
self.api_key = api_key
|
||||||
self.embed = embed
|
self.embed = embed
|
||||||
self.auth_url = auth_url
|
self.auth_url = auth_url
|
||||||
self.domain = domain
|
self.domain = domain
|
||||||
@@ -54,38 +56,40 @@ class RPXAccount(object):
|
|||||||
self.on_login_failure = on_login_failure
|
self.on_login_failure = on_login_failure
|
||||||
self.mappings = Storage()
|
self.mappings = Storage()
|
||||||
|
|
||||||
dn = {'givenName':'','familyName':''}
|
dn = {'givenName': '', 'familyName': ''}
|
||||||
self.mappings.Facebook = lambda profile, dn=dn:\
|
self.mappings.Facebook = lambda profile, dn=dn:\
|
||||||
dict(registration_id = profile.get("identifier",""),
|
dict(registration_id=profile.get("identifier", ""),
|
||||||
username = profile.get("preferredUsername",""),
|
username=profile.get("preferredUsername", ""),
|
||||||
email = profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
first_name = profile.get("name",dn).get("givenName",""),
|
first_name=profile.get("name", dn).get("givenName", ""),
|
||||||
last_name = profile.get("name",dn).get("familyName",""))
|
last_name=profile.get("name", dn).get("familyName", ""))
|
||||||
self.mappings.Google = lambda profile, dn=dn:\
|
self.mappings.Google = lambda profile, dn=dn:\
|
||||||
dict(registration_id=profile.get("identifier",""),
|
dict(registration_id=profile.get("identifier", ""),
|
||||||
username=profile.get("preferredUsername",""),
|
username=profile.get("preferredUsername", ""),
|
||||||
email=profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
first_name=profile.get("name",dn).get("givenName",""),
|
first_name=profile.get("name", dn).get("givenName", ""),
|
||||||
last_name=profile.get("name",dn).get("familyName",""))
|
last_name=profile.get("name", dn).get("familyName", ""))
|
||||||
self.mappings.default = lambda profile:\
|
self.mappings.default = lambda profile:\
|
||||||
dict(registration_id=profile.get("identifier",""),
|
dict(registration_id=profile.get("identifier", ""),
|
||||||
username=profile.get("preferredUsername",""),
|
username=profile.get("preferredUsername", ""),
|
||||||
email=profile.get("email",""),
|
email=profile.get("email", ""),
|
||||||
first_name=profile.get("preferredUsername",""),
|
first_name=profile.get("preferredUsername", ""),
|
||||||
last_name='')
|
last_name='')
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
request = self.request
|
request = self.request
|
||||||
if request.vars.token:
|
if request.vars.token:
|
||||||
user = Storage()
|
user = Storage()
|
||||||
data = urllib.urlencode(dict(apiKey = self.api_key, token=request.vars.token))
|
data = urllib.urlencode(
|
||||||
auth_info_json = fetch(self.auth_url+'?'+data)
|
dict(apiKey=self.api_key, token=request.vars.token))
|
||||||
|
auth_info_json = fetch(self.auth_url + '?' + data)
|
||||||
auth_info = json.loads(auth_info_json)
|
auth_info = json.loads(auth_info_json)
|
||||||
|
|
||||||
if auth_info['stat'] == 'ok':
|
if auth_info['stat'] == 'ok':
|
||||||
self.profile = auth_info['profile']
|
self.profile = auth_info['profile']
|
||||||
provider = re.sub('[^\w\-]','',self.profile['providerName'])
|
provider = re.sub('[^\w\-]', '', self.profile['providerName'])
|
||||||
user = self.mappings.get(provider,self.mappings.default)(self.profile)
|
user = self.mappings.get(
|
||||||
|
provider, self.mappings.default)(self.profile)
|
||||||
return user
|
return user
|
||||||
elif self.on_login_failure:
|
elif self.on_login_failure:
|
||||||
redirect(self.on_login_failure)
|
redirect(self.on_login_failure)
|
||||||
@@ -95,12 +99,14 @@ class RPXAccount(object):
|
|||||||
request = self.request
|
request = self.request
|
||||||
args = request.args
|
args = request.args
|
||||||
if self.embed:
|
if self.embed:
|
||||||
JANRAIN_URL = \
|
JANRAIN_URL = \
|
||||||
"https://%s.rpxnow.com/openid/embed?token_url=%s&language_preference=%s"
|
"https://%s.rpxnow.com/openid/embed?token_url=%s&language_preference=%s"
|
||||||
rpxform = IFRAME(_src=JANRAIN_URL % (self.domain,self.token_url,self.language),
|
rpxform = IFRAME(
|
||||||
_scrolling="no",
|
_src=JANRAIN_URL % (
|
||||||
_frameborder="no",
|
self.domain, self.token_url, self.language),
|
||||||
_style="width:400px;height:240px;")
|
_scrolling="no",
|
||||||
|
_frameborder="no",
|
||||||
|
_style="width:400px;height:240px;")
|
||||||
else:
|
else:
|
||||||
JANRAIN_URL = \
|
JANRAIN_URL = \
|
||||||
"https://%s.rpxnow.com/openid/v2/signin?token_url=%s"
|
"https://%s.rpxnow.com/openid/v2/signin?token_url=%s"
|
||||||
@@ -114,15 +120,15 @@ class RPXAccount(object):
|
|||||||
_type="text/javascript"))
|
_type="text/javascript"))
|
||||||
return rpxform
|
return rpxform
|
||||||
|
|
||||||
def use_janrain(auth,filename='private/janrain.key',**kwargs):
|
|
||||||
path = os.path.join(current.request.folder,filename)
|
def use_janrain(auth, filename='private/janrain.key', **kwargs):
|
||||||
|
path = os.path.join(current.request.folder, filename)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
request = current.request
|
request = current.request
|
||||||
domain,key = open(path,'r').read().strip().split(':')
|
domain, key = open(path, 'r').read().strip().split(':')
|
||||||
host = current.request.env.http_host
|
host = current.request.env.http_host
|
||||||
url = URL('default', 'user', args='login', scheme=True)
|
url = URL('default', 'user', args='login', scheme=True)
|
||||||
auth.settings.actions_disabled = \
|
auth.settings.actions_disabled = \
|
||||||
['register','change_password','request_reset_password']
|
['register', 'change_password', 'request_reset_password']
|
||||||
auth.settings.login_form = RPXAccount(
|
auth.settings.login_form = RPXAccount(
|
||||||
request, api_key=key,domain=domain, url = url,**kwargs)
|
request, api_key=key, domain=domain, url=url, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,12 @@ Adds support for x509 authentication.
|
|||||||
|
|
||||||
from gluon.globals import current
|
from gluon.globals import current
|
||||||
from gluon.storage import Storage
|
from gluon.storage import Storage
|
||||||
from gluon.http import HTTP,redirect
|
from gluon.http import HTTP, redirect
|
||||||
|
|
||||||
#requires M2Crypto
|
#requires M2Crypto
|
||||||
from M2Crypto import X509
|
from M2Crypto import X509
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class X509Auth(object):
|
class X509Auth(object):
|
||||||
"""
|
"""
|
||||||
Login using x509 cert from client.
|
Login using x509 cert from client.
|
||||||
@@ -29,8 +28,6 @@ class X509Auth(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.request = current.request
|
self.request = current.request
|
||||||
self.ssl_client_raw_cert = self.request.env.ssl_client_raw_cert
|
self.ssl_client_raw_cert = self.request.env.ssl_client_raw_cert
|
||||||
@@ -41,10 +38,11 @@ class X509Auth(object):
|
|||||||
|
|
||||||
if self.ssl_client_raw_cert:
|
if self.ssl_client_raw_cert:
|
||||||
|
|
||||||
x509=X509.load_cert_string(self.ssl_client_raw_cert, X509.FORMAT_PEM)
|
x509 = X509.load_cert_string(
|
||||||
|
self.ssl_client_raw_cert, X509.FORMAT_PEM)
|
||||||
# extract it from the cert
|
# extract it from the cert
|
||||||
self.serial = self.request.env.ssl_client_serial or ('%x' % x509.get_serial_number()).upper()
|
self.serial = self.request.env.ssl_client_serial or (
|
||||||
|
'%x' % x509.get_serial_number()).upper()
|
||||||
|
|
||||||
subject = x509.get_subject()
|
subject = x509.get_subject()
|
||||||
|
|
||||||
@@ -53,23 +51,17 @@ class X509Auth(object):
|
|||||||
# cn = self.subject.cn
|
# cn = self.subject.cn
|
||||||
self.subject = Storage(filter(None,
|
self.subject = Storage(filter(None,
|
||||||
map(lambda x:
|
map(lambda x:
|
||||||
(x,map(lambda y:
|
(x, map(lambda y:
|
||||||
y.get_data().as_text(),
|
y.get_data(
|
||||||
subject.get_entries_by_nid(subject.nid[x]))),
|
).as_text(),
|
||||||
|
subject.get_entries_by_nid(subject.nid[x]))),
|
||||||
subject.nid.keys())))
|
subject.nid.keys())))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def login_form(self, **args):
|
def login_form(self, **args):
|
||||||
raise HTTP(403,'Login not allowed. No valid x509 crentials')
|
raise HTTP(403, 'Login not allowed. No valid x509 crentials')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def login_url(self, next="/"):
|
def login_url(self, next="/"):
|
||||||
raise HTTP(403,'Login not allowed. No valid x509 crentials')
|
raise HTTP(403, 'Login not allowed. No valid x509 crentials')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def logout_url(self, next="/"):
|
def logout_url(self, next="/"):
|
||||||
return next
|
return next
|
||||||
@@ -86,10 +78,14 @@ class X509Auth(object):
|
|||||||
|
|
||||||
p = profile = dict()
|
p = profile = dict()
|
||||||
|
|
||||||
username = p['username'] = reduce(lambda a,b: '%s | %s' % (a,b), self.subject.CN or self.subject.commonName)
|
username = p['username'] = reduce(lambda a, b: '%s | %s' % (
|
||||||
p['first_name'] = reduce(lambda a,b: '%s | %s' % (a,b),self.subject.givenName or username)
|
a, b), self.subject.CN or self.subject.commonName)
|
||||||
p['last_name'] = reduce(lambda a,b: '%s | %s' % (a,b),self.subject.surname)
|
p['first_name'] = reduce(lambda a, b: '%s | %s' % (a, b),
|
||||||
p['email'] = reduce(lambda a,b: '%s | %s' % (a,b),self.subject.Email or self.subject.emailAddress)
|
self.subject.givenName or username)
|
||||||
|
p['last_name'] = reduce(
|
||||||
|
lambda a, b: '%s | %s' % (a, b), self.subject.surname)
|
||||||
|
p['email'] = reduce(lambda a, b: '%s | %s' % (
|
||||||
|
a, b), self.subject.Email or self.subject.emailAddress)
|
||||||
|
|
||||||
# IMPORTANT WE USE THE CERT SERIAL AS UNIQUE KEY FOR THE USER
|
# IMPORTANT WE USE THE CERT SERIAL AS UNIQUE KEY FOR THE USER
|
||||||
p['registration_id'] = self.serial
|
p['registration_id'] = self.serial
|
||||||
@@ -100,6 +96,3 @@ class X509Auth(object):
|
|||||||
p['certificate'] = self.ssl_client_raw_cert
|
p['certificate'] = self.ssl_client_raw_cert
|
||||||
|
|
||||||
return profile
|
return profile
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -545,14 +545,14 @@ regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
|
|||||||
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
|
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
|
||||||
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
||||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
|
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
|
||||||
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]')
|
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]',re.S)
|
||||||
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$')
|
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$',re.S)
|
||||||
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$')
|
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$',re.S)
|
||||||
|
|
||||||
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#])")
|
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])")
|
||||||
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#])")
|
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])")
|
||||||
ttab_in = maketrans("'`:*~\\[]{}@$+-.#", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b')
|
ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05')
|
||||||
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b',"'`:*~\\[]{}@$+-.#")
|
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05',"'`:*~\\[]{}@$+-.#\n")
|
||||||
|
|
||||||
def markmin_escape(text):
|
def markmin_escape(text):
|
||||||
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
|
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
|
||||||
@@ -686,6 +686,15 @@ def render(text,
|
|||||||
>>> render("----\\nhello world\\n----\\n")
|
>>> render("----\\nhello world\\n----\\n")
|
||||||
'<blockquote>hello world</blockquote>'
|
'<blockquote>hello world</blockquote>'
|
||||||
|
|
||||||
|
>>> render('[[http://example.com]]')
|
||||||
|
'<p><span class="anchor" id="markmin_http://example.com"></span></p>'
|
||||||
|
|
||||||
|
>>> render('[[ http://example.com]]')
|
||||||
|
'<p><a href="http://example.com">http://example.com</a></p>'
|
||||||
|
|
||||||
|
>>> render('[[bookmark [http://example.com] ]]')
|
||||||
|
'<p><span class="anchor" id="markmin_bookmark"><a href="http://example.com">http://example.com</a></span></p>'
|
||||||
|
|
||||||
>>> render('[[this is a link http://example.com]]')
|
>>> render('[[this is a link http://example.com]]')
|
||||||
'<p><a href="http://example.com">this is a link</a></p>'
|
'<p><a href="http://example.com">this is a link</a></p>'
|
||||||
|
|
||||||
@@ -701,6 +710,9 @@ def render(text,
|
|||||||
>>> render("[[Your browser doesn't support <audio> HTML5 tag http://example.com audio]]")
|
>>> render("[[Your browser doesn't support <audio> HTML5 tag http://example.com audio]]")
|
||||||
'<p><audio controls="controls"><source src="http://example.com" />Your browser doesn\\'t support <audio> HTML5 tag</audio></p>'
|
'<p><audio controls="controls"><source src="http://example.com" />Your browser doesn\\'t support <audio> HTML5 tag</audio></p>'
|
||||||
|
|
||||||
|
>>> render("[[Your\\nbrowser\\ndoesn't\\nsupport\\n<audio> HTML5 tag http://exam\\\\\\nple.com\\naudio]]")
|
||||||
|
'<p><audio controls="controls"><source src="http://example.com" />Your browser doesn\\'t support <audio> HTML5 tag</audio></p>'
|
||||||
|
|
||||||
>>> render('[[this is a **link** http://example.com]]')
|
>>> render('[[this is a **link** http://example.com]]')
|
||||||
'<p><a href="http://example.com">this is a <strong>link</strong></a></p>'
|
'<p><a href="http://example.com">this is a <strong>link</strong></a></p>'
|
||||||
|
|
||||||
@@ -850,6 +862,7 @@ def render(text,
|
|||||||
pp='\n' if pretty_print else ''
|
pp='\n' if pretty_print else ''
|
||||||
text = str(text or '')
|
text = str(text or '')
|
||||||
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
|
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
|
||||||
|
text = text.replace('\x05','') # concatenate strings separeted by \\n
|
||||||
|
|
||||||
if URL is not None:
|
if URL is not None:
|
||||||
text = replace_at_urls(text,URL)
|
text = replace_at_urls(text,URL)
|
||||||
@@ -1254,8 +1267,8 @@ def render(text,
|
|||||||
k = escape(k)
|
k = escape(k)
|
||||||
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
|
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
|
||||||
target = ' target="_blank"' if p == 'popup' else ''
|
target = ' target="_blank"' if p == 'popup' else ''
|
||||||
t = render(t, {}, {}, 'br', URL, environment, latex, autolinks,
|
t = render(t, {}, {}, 'br', URL, environment, latex, None,
|
||||||
protolinks, class_prefix, id_prefix, pretty_print) if t else k
|
None, class_prefix, id_prefix, pretty_print) if t else k
|
||||||
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
|
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
|
||||||
% dict(k=k, title=title, target=target, t=t)
|
% dict(k=k, title=title, target=target, t=t)
|
||||||
if t == 'NEWLINE' and not a:
|
if t == 'NEWLINE' and not a:
|
||||||
|
|||||||
+61
-69
@@ -44,22 +44,21 @@ SQL_DIALECTS = {'memcache': {
|
|||||||
'is not null': 'IS NOT NULL',
|
'is not null': 'IS NOT NULL',
|
||||||
'extract': None,
|
'extract': None,
|
||||||
'left join': None,
|
'left join': None,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
def cleanup(text):
|
def cleanup(text):
|
||||||
if re.compile('[^0-9a-zA-Z_]').findall(text):
|
if re.compile('[^0-9a-zA-Z_]').findall(text):
|
||||||
raise SyntaxError, \
|
raise SyntaxError('Can\'t cleanup \'%s\': only [0-9a-zA-Z_] allowed in table and field names' % text)
|
||||||
'Can\'t cleanup \'%s\': only [0-9a-zA-Z_] allowed in table and field names' % text
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def assert_filter_fields(*fields):
|
def assert_filter_fields(*fields):
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if isinstance(field, (Field, Expression)) and field.type\
|
if isinstance(field, (Field, Expression)) and field.type\
|
||||||
in ['text', 'blob']:
|
in ['text', 'blob']:
|
||||||
raise SyntaxError, 'AppEngine does not index by: %s'\
|
raise SyntaxError('AppEngine does not index by: %s'
|
||||||
% field.type
|
% field.type)
|
||||||
|
|
||||||
|
|
||||||
def dateobj_to_datetime(object):
|
def dateobj_to_datetime(object):
|
||||||
@@ -78,7 +77,7 @@ def dateobj_to_datetime(object):
|
|||||||
object.minute,
|
object.minute,
|
||||||
object.second,
|
object.second,
|
||||||
object.microsecond,
|
object.microsecond,
|
||||||
)
|
)
|
||||||
return object
|
return object
|
||||||
|
|
||||||
|
|
||||||
@@ -96,7 +95,7 @@ def sqlhtml_validators(field_type, length):
|
|||||||
'time': validators.IS_TIME(),
|
'time': validators.IS_TIME(),
|
||||||
'datetime': validators.IS_DATETIME(),
|
'datetime': validators.IS_DATETIME(),
|
||||||
'reference': validators.IS_INT_IN_RANGE(0, 1e100),
|
'reference': validators.IS_INT_IN_RANGE(0, 1e100),
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
return v[field_type[:9]]
|
return v[field_type[:9]]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -114,7 +113,8 @@ class DALStorage(dict):
|
|||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
if key in self:
|
if key in self:
|
||||||
raise SyntaxError, 'Object \'%s\'exists and cannot be redefined' % key
|
raise SyntaxError(
|
||||||
|
'Object \'%s\'exists and cannot be redefined' % key)
|
||||||
self[key] = value
|
self[key] = value
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -151,14 +151,14 @@ class MEMDB(DALStorage):
|
|||||||
tablename,
|
tablename,
|
||||||
*fields,
|
*fields,
|
||||||
**args
|
**args
|
||||||
):
|
):
|
||||||
tablename = cleanup(tablename)
|
tablename = cleanup(tablename)
|
||||||
if tablename in dir(self) or tablename[0] == '_':
|
if tablename in dir(self) or tablename[0] == '_':
|
||||||
raise SyntaxError, 'invalid table name: %s' % tablename
|
raise SyntaxError('invalid table name: %s' % tablename)
|
||||||
if not tablename in self.tables:
|
if not tablename in self.tables:
|
||||||
self.tables.append(tablename)
|
self.tables.append(tablename)
|
||||||
else:
|
else:
|
||||||
raise SyntaxError, 'table already defined: %s' % tablename
|
raise SyntaxError('table already defined: %s' % tablename)
|
||||||
t = self[tablename] = Table(self, tablename, *fields)
|
t = self[tablename] = Table(self, tablename, *fields)
|
||||||
t._create()
|
t._create()
|
||||||
return t
|
return t
|
||||||
@@ -190,7 +190,7 @@ class Table(DALStorage):
|
|||||||
db,
|
db,
|
||||||
tablename,
|
tablename,
|
||||||
*fields
|
*fields
|
||||||
):
|
):
|
||||||
self._db = db
|
self._db = db
|
||||||
self._tablename = tablename
|
self._tablename = tablename
|
||||||
self.fields = SQLCallableList()
|
self.fields = SQLCallableList()
|
||||||
@@ -219,24 +219,24 @@ class Table(DALStorage):
|
|||||||
if field.type[:9] == 'reference':
|
if field.type[:9] == 'reference':
|
||||||
referenced = field.type[10:].strip()
|
referenced = field.type[10:].strip()
|
||||||
if not referenced:
|
if not referenced:
|
||||||
raise SyntaxError, \
|
raise SyntaxError('Table %s: reference \'%s\' to nothing!' % (
|
||||||
'Table %s: reference \'%s\' to nothing!' % (self._tablename, k)
|
self._tablename, k))
|
||||||
if not referenced in self._db:
|
if not referenced in self._db:
|
||||||
raise SyntaxError, \
|
raise SyntaxError(
|
||||||
'Table: table %s does not exist' % referenced
|
'Table: table %s does not exist' % referenced)
|
||||||
referee = self._db[referenced]
|
referee = self._db[referenced]
|
||||||
ftype = \
|
ftype = \
|
||||||
self._db._translator[field.type[:9]](
|
self._db._translator[field.type[:9]](
|
||||||
self._db[referenced]._tableobj)
|
self._db[referenced]._tableobj)
|
||||||
if self._tablename in referee.fields: # ## THIS IS OK
|
if self._tablename in referee.fields: # ## THIS IS OK
|
||||||
raise SyntaxError, \
|
raise SyntaxError('Field: table \'%s\' has same name as a field '
|
||||||
'Field: table \'%s\' has same name as a field ' \
|
'in referenced table \'%s\'' % (
|
||||||
'in referenced table \'%s\'' % (self._tablename, referenced)
|
self._tablename, referenced))
|
||||||
self._db[referenced]._referenced_by.append((self._tablename,
|
self._db[referenced]._referenced_by.append((self._tablename,
|
||||||
field.name))
|
field.name))
|
||||||
elif not field.type in self._db._translator\
|
elif not field.type in self._db._translator\
|
||||||
or not self._db._translator[field.type]:
|
or not self._db._translator[field.type]:
|
||||||
raise SyntaxError, 'Field: unkown field type %s' % field.type
|
raise SyntaxError('Field: unkown field type %s' % field.type)
|
||||||
self._tableobj = self._db.client
|
self._tableobj = self._db.client
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -269,11 +269,11 @@ class Table(DALStorage):
|
|||||||
def update(self, id, **fields):
|
def update(self, id, **fields):
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if not field in fields and self[field].default\
|
if not field in fields and self[field].default\
|
||||||
!= None:
|
is not None:
|
||||||
fields[field] = self[field].default
|
fields[field] = self[field].default
|
||||||
if field in fields:
|
if field in fields:
|
||||||
fields[field] = obj_represent(fields[field],
|
fields[field] = obj_represent(fields[field],
|
||||||
self[field].type, self._db)
|
self[field].type, self._db)
|
||||||
return self._tableobj.set(self._id_to_key(id), fields)
|
return self._tableobj.set(self._id_to_key(id), fields)
|
||||||
|
|
||||||
def delete(self, id):
|
def delete(self, id):
|
||||||
@@ -293,7 +293,7 @@ class Table(DALStorage):
|
|||||||
if self._tableobj.set(shard_id, '0'):
|
if self._tableobj.set(shard_id, '0'):
|
||||||
id = 0
|
id = 0
|
||||||
else:
|
else:
|
||||||
raise Exception, 'cannot set memcache'
|
raise Exception('cannot set memcache')
|
||||||
return long(str(shard) + str(id))
|
return long(str(shard) + str(id))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -307,7 +307,7 @@ class Expression(object):
|
|||||||
name,
|
name,
|
||||||
type='string',
|
type='string',
|
||||||
db=None,
|
db=None,
|
||||||
):
|
):
|
||||||
(self.name, self.type, self._db) = (name, type, db)
|
(self.name, self.type, self._db) = (name, type, db)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -393,11 +393,11 @@ class Field(Expression):
|
|||||||
notnull=False,
|
notnull=False,
|
||||||
unique=False,
|
unique=False,
|
||||||
uploadfield=True,
|
uploadfield=True,
|
||||||
):
|
):
|
||||||
|
|
||||||
self.name = cleanup(fieldname)
|
self.name = cleanup(fieldname)
|
||||||
if fieldname in dir(Table) or fieldname[0] == '_':
|
if fieldname in dir(Table) or fieldname[0] == '_':
|
||||||
raise SyntaxError, 'Field: invalid field name: %s' % fieldname
|
raise SyntaxError('Field: invalid field name: %s' % fieldname)
|
||||||
if isinstance(type, Table):
|
if isinstance(type, Table):
|
||||||
type = 'reference ' + type._tablename
|
type = 'reference ' + type._tablename
|
||||||
if not length:
|
if not length:
|
||||||
@@ -437,9 +437,9 @@ MEMDB.Field = Field # ## required by gluon/globals.py session.connect
|
|||||||
|
|
||||||
|
|
||||||
def obj_represent(object, fieldtype, db):
|
def obj_represent(object, fieldtype, db):
|
||||||
if object != None:
|
if object is not None:
|
||||||
if fieldtype == 'date' and not isinstance(object,
|
if fieldtype == 'date' and not isinstance(object,
|
||||||
datetime.date):
|
datetime.date):
|
||||||
(y, m, d) = [int(x) for x in str(object).strip().split('-')]
|
(y, m, d) = [int(x) for x in str(object).strip().split('-')]
|
||||||
object = datetime.date(y, m, d)
|
object = datetime.date(y, m, d)
|
||||||
elif fieldtype == 'time' and not isinstance(object, datetime.time):
|
elif fieldtype == 'time' and not isinstance(object, datetime.time):
|
||||||
@@ -450,7 +450,7 @@ def obj_represent(object, fieldtype, db):
|
|||||||
(h, mi, s) = time_items + [0]
|
(h, mi, s) = time_items + [0]
|
||||||
object = datetime.time(h, mi, s)
|
object = datetime.time(h, mi, s)
|
||||||
elif fieldtype == 'datetime' and not isinstance(object,
|
elif fieldtype == 'datetime' and not isinstance(object,
|
||||||
datetime.datetime):
|
datetime.datetime):
|
||||||
(y, m, d) = [int(x) for x in
|
(y, m, d) = [int(x) for x in
|
||||||
str(object)[:10].strip().split('-')]
|
str(object)[:10].strip().split('-')]
|
||||||
time_items = [int(x) for x in
|
time_items = [int(x) for x in
|
||||||
@@ -466,7 +466,7 @@ def obj_represent(object, fieldtype, db):
|
|||||||
h,
|
h,
|
||||||
mi,
|
mi,
|
||||||
s,
|
s,
|
||||||
)
|
)
|
||||||
elif fieldtype == 'integer' and not isinstance(object, long):
|
elif fieldtype == 'integer' and not isinstance(object, long):
|
||||||
object = long(object)
|
object = long(object)
|
||||||
|
|
||||||
@@ -496,10 +496,10 @@ class Query(object):
|
|||||||
left,
|
left,
|
||||||
op=None,
|
op=None,
|
||||||
right=None,
|
right=None,
|
||||||
):
|
):
|
||||||
if isinstance(right, (Field, Expression)):
|
if isinstance(right, (Field, Expression)):
|
||||||
raise SyntaxError, \
|
raise SyntaxError(
|
||||||
'Query: right side of filter must be a value or entity'
|
'Query: right side of filter must be a value or entity')
|
||||||
if isinstance(left, Field) and left.name == 'id':
|
if isinstance(left, Field) and left.name == 'id':
|
||||||
if op == '=':
|
if op == '=':
|
||||||
self.get_one = \
|
self.get_one = \
|
||||||
@@ -507,8 +507,8 @@ class Query(object):
|
|||||||
id=long(right))
|
id=long(right))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise SyntaxError, 'only equality by id is supported'
|
raise SyntaxError('only equality by id is supported')
|
||||||
raise SyntaxError, 'not supported'
|
raise SyntaxError('not supported')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.left)
|
return str(self.left)
|
||||||
@@ -539,7 +539,7 @@ class Set(object):
|
|||||||
self.where = where
|
self.where = where
|
||||||
self._tables.insert(0, where.get_all)
|
self._tables.insert(0, where.get_all)
|
||||||
elif hasattr(where, 'get_one') and isinstance(where.get_one,
|
elif hasattr(where, 'get_one') and isinstance(where.get_one,
|
||||||
QueryException):
|
QueryException):
|
||||||
self.where = where.get_one
|
self.where = where.get_one
|
||||||
else:
|
else:
|
||||||
|
|
||||||
@@ -553,9 +553,8 @@ class Set(object):
|
|||||||
|
|
||||||
def __call__(self, where):
|
def __call__(self, where):
|
||||||
if isinstance(self.where, QueryException) or isinstance(where,
|
if isinstance(self.where, QueryException) or isinstance(where,
|
||||||
QueryException):
|
QueryException):
|
||||||
raise SyntaxError, \
|
raise SyntaxError('neither self.where nor where can be a QueryException instance')
|
||||||
'neither self.where nor where can be a QueryException instance'
|
|
||||||
if self.where:
|
if self.where:
|
||||||
return Set(self._db, self.where & where)
|
return Set(self._db, self.where & where)
|
||||||
else:
|
else:
|
||||||
@@ -564,9 +563,9 @@ class Set(object):
|
|||||||
def _get_table_or_raise(self):
|
def _get_table_or_raise(self):
|
||||||
tablenames = list(set(self._tables)) # unique
|
tablenames = list(set(self._tables)) # unique
|
||||||
if len(tablenames) < 1:
|
if len(tablenames) < 1:
|
||||||
raise SyntaxError, 'Set: no tables selected'
|
raise SyntaxError('Set: no tables selected')
|
||||||
if len(tablenames) > 1:
|
if len(tablenames) > 1:
|
||||||
raise SyntaxError, 'Set: no join in appengine'
|
raise SyntaxError('Set: no join in appengine')
|
||||||
return self._db[tablenames[0]]._tableobj
|
return self._db[tablenames[0]]._tableobj
|
||||||
|
|
||||||
def _getitem_exception(self):
|
def _getitem_exception(self):
|
||||||
@@ -597,7 +596,7 @@ class Set(object):
|
|||||||
if isinstance(self.where, QueryException):
|
if isinstance(self.where, QueryException):
|
||||||
return self._select_except()
|
return self._select_except()
|
||||||
else:
|
else:
|
||||||
raise SyntaxError, 'select arguments not supported'
|
raise SyntaxError('select arguments not supported')
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
return len(self.select())
|
return len(self.select())
|
||||||
@@ -609,7 +608,7 @@ class Set(object):
|
|||||||
return
|
return
|
||||||
self._db[tablename].delete(id)
|
self._db[tablename].delete(id)
|
||||||
else:
|
else:
|
||||||
raise Exception, 'deletion not implemented'
|
raise Exception('deletion not implemented')
|
||||||
|
|
||||||
def update(self, **update_fields):
|
def update(self, **update_fields):
|
||||||
if isinstance(self.where, QueryException):
|
if isinstance(self.where, QueryException):
|
||||||
@@ -620,7 +619,7 @@ class Set(object):
|
|||||||
setattr(item, key, value)
|
setattr(item, key, value)
|
||||||
self._db[tablename].update(id, **item)
|
self._db[tablename].update(id, **item)
|
||||||
else:
|
else:
|
||||||
raise Exception, 'update not implemented'
|
raise Exception('update not implemented')
|
||||||
|
|
||||||
|
|
||||||
def update_record(
|
def update_record(
|
||||||
@@ -628,7 +627,7 @@ def update_record(
|
|||||||
s,
|
s,
|
||||||
id,
|
id,
|
||||||
a,
|
a,
|
||||||
):
|
):
|
||||||
item = s.get(id)
|
item = s.get(id)
|
||||||
for (key, value) in a.items():
|
for (key, value) in a.items():
|
||||||
t[key] = value
|
t[key] = value
|
||||||
@@ -650,7 +649,7 @@ class Rows(object):
|
|||||||
db,
|
db,
|
||||||
response,
|
response,
|
||||||
*colnames
|
*colnames
|
||||||
):
|
):
|
||||||
self._db = db
|
self._db = db
|
||||||
self.colnames = colnames
|
self.colnames = colnames
|
||||||
self.response = response
|
self.response = response
|
||||||
@@ -660,9 +659,9 @@ class Rows(object):
|
|||||||
|
|
||||||
def __getitem__(self, i):
|
def __getitem__(self, i):
|
||||||
if i >= len(self.response) or i < 0:
|
if i >= len(self.response) or i < 0:
|
||||||
raise SyntaxError, 'Rows: no such row: %i' % i
|
raise SyntaxError('Rows: no such row: %i' % i)
|
||||||
if len(self.response[0]) != len(self.colnames):
|
if len(self.response[0]) != len(self.colnames):
|
||||||
raise SyntaxError, 'Rows: internal error'
|
raise SyntaxError('Rows: internal error')
|
||||||
row = DALStorage()
|
row = DALStorage()
|
||||||
for j in xrange(len(self.colnames)):
|
for j in xrange(len(self.colnames)):
|
||||||
value = self.response[i][j]
|
value = self.response[i][j]
|
||||||
@@ -684,7 +683,7 @@ class Rows(object):
|
|||||||
referee = field.type[10:].strip()
|
referee = field.type[10:].strip()
|
||||||
rid = value
|
rid = value
|
||||||
row[tablename][fieldname] = rid
|
row[tablename][fieldname] = rid
|
||||||
elif field.type == 'boolean' and value != None:
|
elif field.type == 'boolean' and value is not None:
|
||||||
|
|
||||||
# row[tablename][fieldname]=Set(self._db[referee].id==rid)
|
# row[tablename][fieldname]=Set(self._db[referee].id==rid)
|
||||||
|
|
||||||
@@ -692,13 +691,13 @@ class Rows(object):
|
|||||||
row[tablename][fieldname] = True
|
row[tablename][fieldname] = True
|
||||||
else:
|
else:
|
||||||
row[tablename][fieldname] = False
|
row[tablename][fieldname] = False
|
||||||
elif field.type == 'date' and value != None\
|
elif field.type == 'date' and value is not None\
|
||||||
and not isinstance(value, datetime.date):
|
and not isinstance(value, datetime.date):
|
||||||
(y, m, d) = [int(x) for x in
|
(y, m, d) = [int(x) for x in
|
||||||
str(value).strip().split('-')]
|
str(value).strip().split('-')]
|
||||||
row[tablename][fieldname] = datetime.date(y, m, d)
|
row[tablename][fieldname] = datetime.date(y, m, d)
|
||||||
elif field.type == 'time' and value != None\
|
elif field.type == 'time' and value is not None\
|
||||||
and not isinstance(value, datetime.time):
|
and not isinstance(value, datetime.time):
|
||||||
time_items = [int(x) for x in
|
time_items = [int(x) for x in
|
||||||
str(value).strip().split(':')[:3]]
|
str(value).strip().split(':')[:3]]
|
||||||
if len(time_items) == 3:
|
if len(time_items) == 3:
|
||||||
@@ -706,8 +705,8 @@ class Rows(object):
|
|||||||
else:
|
else:
|
||||||
(h, mi, s) = time_items + [0]
|
(h, mi, s) = time_items + [0]
|
||||||
row[tablename][fieldname] = datetime.time(h, mi, s)
|
row[tablename][fieldname] = datetime.time(h, mi, s)
|
||||||
elif field.type == 'datetime' and value != None\
|
elif field.type == 'datetime' and value is not None\
|
||||||
and not isinstance(value, datetime.datetime):
|
and not isinstance(value, datetime.datetime):
|
||||||
(y, m, d) = [int(x) for x in
|
(y, m, d) = [int(x) for x in
|
||||||
str(value)[:10].strip().split('-')]
|
str(value)[:10].strip().split('-')]
|
||||||
time_items = [int(x) for x in
|
time_items = [int(x) for x in
|
||||||
@@ -723,19 +722,19 @@ class Rows(object):
|
|||||||
h,
|
h,
|
||||||
mi,
|
mi,
|
||||||
s,
|
s,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
row[tablename][fieldname] = value
|
row[tablename][fieldname] = value
|
||||||
if fieldname == 'id':
|
if fieldname == 'id':
|
||||||
id = row[tablename].id
|
id = row[tablename].id
|
||||||
row[tablename].update_record = lambda t = row[tablename], \
|
row[tablename].update_record = lambda t = row[tablename], \
|
||||||
s = self._db[tablename], id = id, **a: update_record(t,
|
s = self._db[tablename], id = id, **a: update_record(t,
|
||||||
s, id, a)
|
s, id, a)
|
||||||
for (referee_table, referee_name) in \
|
for (referee_table, referee_name) in \
|
||||||
table._referenced_by:
|
table._referenced_by:
|
||||||
s = self._db[referee_table][referee_name]
|
s = self._db[referee_table][referee_name]
|
||||||
row[tablename][referee_table] = Set(self._db, s
|
row[tablename][referee_table] = Set(self._db, s
|
||||||
== id)
|
== id)
|
||||||
if len(row.keys()) == 1:
|
if len(row.keys()) == 1:
|
||||||
return row[row.keys()[0]]
|
return row[row.keys()[0]]
|
||||||
return row
|
return row
|
||||||
@@ -905,10 +904,3 @@ SQLStorage = DALStorage
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Modified for inclusion into web2py by: Ross Peoples <ross.peoples@gmail.com>
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from StringIO import StringIO # The pure-Python StringIO supports unicode.
|
from StringIO import StringIO # The pure-Python StringIO supports unicode.
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ __version__ = '0.1.4'
|
|||||||
|
|
||||||
def remove_comments(css):
|
def remove_comments(css):
|
||||||
"""Remove all CSS comment blocks."""
|
"""Remove all CSS comment blocks."""
|
||||||
|
|
||||||
iemac = False
|
iemac = False
|
||||||
preserve = False
|
preserve = False
|
||||||
comment_start = css.find("/*")
|
comment_start = css.find("/*")
|
||||||
@@ -28,7 +28,7 @@ def remove_comments(css):
|
|||||||
# Preserve comments that look like `/*!...*/`.
|
# Preserve comments that look like `/*!...*/`.
|
||||||
# Slicing is used to make sure we don"t get an IndexError.
|
# Slicing is used to make sure we don"t get an IndexError.
|
||||||
preserve = css[comment_start + 2:comment_start + 3] == "!"
|
preserve = css[comment_start + 2:comment_start + 3] == "!"
|
||||||
|
|
||||||
comment_end = css.find("*/", comment_start + 2)
|
comment_end = css.find("*/", comment_start + 2)
|
||||||
if comment_end < 0:
|
if comment_end < 0:
|
||||||
if not preserve:
|
if not preserve:
|
||||||
@@ -48,22 +48,22 @@ def remove_comments(css):
|
|||||||
else:
|
else:
|
||||||
comment_start = comment_end + 2
|
comment_start = comment_end + 2
|
||||||
comment_start = css.find("/*", comment_start)
|
comment_start = css.find("/*", comment_start)
|
||||||
|
|
||||||
return css
|
return css
|
||||||
|
|
||||||
|
|
||||||
def remove_unnecessary_whitespace(css):
|
def remove_unnecessary_whitespace(css):
|
||||||
"""Remove unnecessary whitespace characters."""
|
"""Remove unnecessary whitespace characters."""
|
||||||
|
|
||||||
def pseudoclasscolon(css):
|
def pseudoclasscolon(css):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Prevents 'p :link' from becoming 'p:link'.
|
Prevents 'p :link' from becoming 'p:link'.
|
||||||
|
|
||||||
Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is
|
Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is
|
||||||
translated back again later.
|
translated back again later.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)")
|
regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)")
|
||||||
match = regex.search(css)
|
match = regex.search(css)
|
||||||
while match:
|
while match:
|
||||||
@@ -73,43 +73,43 @@ def remove_unnecessary_whitespace(css):
|
|||||||
css[match.end():]])
|
css[match.end():]])
|
||||||
match = regex.search(css)
|
match = regex.search(css)
|
||||||
return css
|
return css
|
||||||
|
|
||||||
css = pseudoclasscolon(css)
|
css = pseudoclasscolon(css)
|
||||||
# Remove spaces from before things.
|
# Remove spaces from before things.
|
||||||
css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css)
|
css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css)
|
||||||
|
|
||||||
# If there is a `@charset`, then only allow one, and move to the beginning.
|
# If there is a `@charset`, then only allow one, and move to the beginning.
|
||||||
css = re.sub(r"^(.*)(@charset \"[^\"]*\";)", r"\2\1", css)
|
css = re.sub(r"^(.*)(@charset \"[^\"]*\";)", r"\2\1", css)
|
||||||
css = re.sub(r"^(\s*@charset [^;]+;\s*)+", r"\1", css)
|
css = re.sub(r"^(\s*@charset [^;]+;\s*)+", r"\1", css)
|
||||||
|
|
||||||
# Put the space back in for a few cases, such as `@media screen` and
|
# Put the space back in for a few cases, such as `@media screen` and
|
||||||
# `(-webkit-min-device-pixel-ratio:0)`.
|
# `(-webkit-min-device-pixel-ratio:0)`.
|
||||||
css = re.sub(r"\band\(", "and (", css)
|
css = re.sub(r"\band\(", "and (", css)
|
||||||
|
|
||||||
# Put the colons back.
|
# Put the colons back.
|
||||||
css = css.replace('___PSEUDOCLASSCOLON___', ':')
|
css = css.replace('___PSEUDOCLASSCOLON___', ':')
|
||||||
|
|
||||||
# Remove spaces from after things.
|
# Remove spaces from after things.
|
||||||
css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css)
|
css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css)
|
||||||
|
|
||||||
return css
|
return css
|
||||||
|
|
||||||
|
|
||||||
def remove_unnecessary_semicolons(css):
|
def remove_unnecessary_semicolons(css):
|
||||||
"""Remove unnecessary semicolons."""
|
"""Remove unnecessary semicolons."""
|
||||||
|
|
||||||
return re.sub(r";+\}", "}", css)
|
return re.sub(r";+\}", "}", css)
|
||||||
|
|
||||||
|
|
||||||
def remove_empty_rules(css):
|
def remove_empty_rules(css):
|
||||||
"""Remove empty rules."""
|
"""Remove empty rules."""
|
||||||
|
|
||||||
return re.sub(r"[^\}\{]+\{\}", "", css)
|
return re.sub(r"[^\}\{]+\{\}", "", css)
|
||||||
|
|
||||||
|
|
||||||
def normalize_rgb_colors_to_hex(css):
|
def normalize_rgb_colors_to_hex(css):
|
||||||
"""Convert `rgb(51,102,153)` to `#336699`."""
|
"""Convert `rgb(51,102,153)` to `#336699`."""
|
||||||
|
|
||||||
regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)")
|
regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)")
|
||||||
match = regex.search(css)
|
match = regex.search(css)
|
||||||
while match:
|
while match:
|
||||||
@@ -122,39 +122,40 @@ def normalize_rgb_colors_to_hex(css):
|
|||||||
|
|
||||||
def condense_zero_units(css):
|
def condense_zero_units(css):
|
||||||
"""Replace `0(px, em, %, etc)` with `0`."""
|
"""Replace `0(px, em, %, etc)` with `0`."""
|
||||||
|
|
||||||
return re.sub(r"([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", r"\1\2", css)
|
return re.sub(r"([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", r"\1\2", css)
|
||||||
|
|
||||||
|
|
||||||
def condense_multidimensional_zeros(css):
|
def condense_multidimensional_zeros(css):
|
||||||
"""Replace `:0 0 0 0;`, `:0 0 0;` etc. with `:0;`."""
|
"""Replace `:0 0 0 0;`, `:0 0 0;` etc. with `:0;`."""
|
||||||
|
|
||||||
css = css.replace(":0 0 0 0;", ":0;")
|
css = css.replace(":0 0 0 0;", ":0;")
|
||||||
css = css.replace(":0 0 0;", ":0;")
|
css = css.replace(":0 0 0;", ":0;")
|
||||||
css = css.replace(":0 0;", ":0;")
|
css = css.replace(":0 0;", ":0;")
|
||||||
|
|
||||||
# Revert `background-position:0;` to the valid `background-position:0 0;`.
|
# Revert `background-position:0;` to the valid `background-position:0 0;`.
|
||||||
css = css.replace("background-position:0;", "background-position:0 0;")
|
css = css.replace("background-position:0;", "background-position:0 0;")
|
||||||
|
|
||||||
return css
|
return css
|
||||||
|
|
||||||
|
|
||||||
def condense_floating_points(css):
|
def condense_floating_points(css):
|
||||||
"""Replace `0.6` with `.6` where possible."""
|
"""Replace `0.6` with `.6` where possible."""
|
||||||
|
|
||||||
return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css)
|
return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css)
|
||||||
|
|
||||||
|
|
||||||
def condense_hex_colors(css):
|
def condense_hex_colors(css):
|
||||||
"""Shorten colors from #AABBCC to #ABC where possible."""
|
"""Shorten colors from #AABBCC to #ABC where possible."""
|
||||||
|
|
||||||
regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])")
|
regex = re.compile(r"([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])")
|
||||||
match = regex.search(css)
|
match = regex.search(css)
|
||||||
while match:
|
while match:
|
||||||
first = match.group(3) + match.group(5) + match.group(7)
|
first = match.group(3) + match.group(5) + match.group(7)
|
||||||
second = match.group(4) + match.group(6) + match.group(8)
|
second = match.group(4) + match.group(6) + match.group(8)
|
||||||
if first.lower() == second.lower():
|
if first.lower() == second.lower():
|
||||||
css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first)
|
css = css.replace(
|
||||||
|
match.group(), match.group(1) + match.group(2) + '#' + first)
|
||||||
match = regex.search(css, match.end() - 3)
|
match = regex.search(css, match.end() - 3)
|
||||||
else:
|
else:
|
||||||
match = regex.search(css, match.end())
|
match = regex.search(css, match.end())
|
||||||
@@ -163,19 +164,19 @@ def condense_hex_colors(css):
|
|||||||
|
|
||||||
def condense_whitespace(css):
|
def condense_whitespace(css):
|
||||||
"""Condense multiple adjacent whitespace characters into one."""
|
"""Condense multiple adjacent whitespace characters into one."""
|
||||||
|
|
||||||
return re.sub(r"\s+", " ", css)
|
return re.sub(r"\s+", " ", css)
|
||||||
|
|
||||||
|
|
||||||
def condense_semicolons(css):
|
def condense_semicolons(css):
|
||||||
"""Condense multiple adjacent semicolon characters into one."""
|
"""Condense multiple adjacent semicolon characters into one."""
|
||||||
|
|
||||||
return re.sub(r";;+", ";", css)
|
return re.sub(r";;+", ";", css)
|
||||||
|
|
||||||
|
|
||||||
def wrap_css_lines(css, line_length):
|
def wrap_css_lines(css, line_length):
|
||||||
"""Wrap the lines of the given CSS to an approximate length."""
|
"""Wrap the lines of the given CSS to an approximate length."""
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
line_start = 0
|
line_start = 0
|
||||||
for i, char in enumerate(css):
|
for i, char in enumerate(css):
|
||||||
@@ -183,7 +184,7 @@ def wrap_css_lines(css, line_length):
|
|||||||
if char == '}' and (i - line_start >= line_length):
|
if char == '}' and (i - line_start >= line_length):
|
||||||
lines.append(css[line_start:i + 1])
|
lines.append(css[line_start:i + 1])
|
||||||
line_start = i + 1
|
line_start = i + 1
|
||||||
|
|
||||||
if line_start < len(css):
|
if line_start < len(css):
|
||||||
lines.append(css[line_start:])
|
lines.append(css[line_start:])
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
@@ -212,19 +213,19 @@ def cssmin(css, wrap=None):
|
|||||||
def main():
|
def main():
|
||||||
import optparse
|
import optparse
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
p = optparse.OptionParser(
|
p = optparse.OptionParser(
|
||||||
prog="cssmin", version=__version__,
|
prog="cssmin", version=__version__,
|
||||||
usage="%prog [--wrap N]",
|
usage="%prog [--wrap N]",
|
||||||
description="""Reads raw CSS from stdin, and writes compressed CSS to stdout.""")
|
description="""Reads raw CSS from stdin, and writes compressed CSS to stdout.""")
|
||||||
|
|
||||||
p.add_option(
|
p.add_option(
|
||||||
'-w', '--wrap', type='int', default=None, metavar='N',
|
'-w', '--wrap', type='int', default=None, metavar='N',
|
||||||
help="Wrap output to approximately N chars per line.")
|
help="Wrap output to approximately N chars per line.")
|
||||||
|
|
||||||
options, args = p.parse_args()
|
options, args = p.parse_args()
|
||||||
sys.stdout.write(cssmin(sys.stdin.read(), wrap=options.wrap))
|
sys.stdout.write(cssmin(sys.stdin.read(), wrap=options.wrap))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def minify(response):
|
def minify(response):
|
||||||
def _replace(match):
|
def _replace(match):
|
||||||
match = match.group()
|
match = match.group()
|
||||||
# save whole <pre>, <textarea> tags, and opening <!-- (so it doesn't break <script>)
|
# save whole <pre>, <textarea> tags, and opening <!-- (so it doesn't break <script>)
|
||||||
# otherwise, replace all whitespace with a single space character
|
# otherwise, replace all whitespace with a single space character
|
||||||
return match if match.startswith(('<pre', '<textarea', '<!--')) else ' '
|
return match if match.startswith(('<pre', '<textarea', '<!--')) else ' '
|
||||||
|
|
||||||
cpat = re.compile(r'\s+|<pre(.*?)</pre>|<textarea(.*?)</textarea>|<!--\s', re.DOTALL)
|
cpat = re.compile(
|
||||||
return cpat.sub(_replace, response)
|
r'\s+|<pre(.*?)</pre>|<textarea(.*?)</textarea>|<!--\s', re.DOTALL)
|
||||||
|
return cpat.sub(_replace, response)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Both python 2 and python 3 are supported.
|
|||||||
|
|
||||||
.. _jsmin.c by Douglas Crockford:
|
.. _jsmin.c by Douglas Crockford:
|
||||||
http://www.crockford.com/javascript/jsmin.c
|
http://www.crockford.com/javascript/jsmin.c
|
||||||
|
|
||||||
Original author of Python version: Andr\xe9 Malo
|
Original author of Python version: Andr\xe9 Malo
|
||||||
Home page: http://opensource.perlig.de/rjsmin/
|
Home page: http://opensource.perlig.de/rjsmin/
|
||||||
Modified by Ross Peoples <ross.peoples@gmail.com> for inclusion into web2py.
|
Modified by Ross Peoples <ross.peoples@gmail.com> for inclusion into web2py.
|
||||||
@@ -96,7 +96,7 @@ def _make_jsmin(extended=True, python_only=True):
|
|||||||
try:
|
try:
|
||||||
xrange
|
xrange
|
||||||
except NameError:
|
except NameError:
|
||||||
xrange = range # pylint: disable = W0622
|
xrange = range # pylint: disable = W0622
|
||||||
|
|
||||||
space_chars = r'[\000-\011\013\014\016-\040]'
|
space_chars = r'[\000-\011\013\014\016-\040]'
|
||||||
|
|
||||||
@@ -151,13 +151,13 @@ def _make_jsmin(extended=True, python_only=True):
|
|||||||
last != first and chr(last) or ''
|
last != first and chr(last) or ''
|
||||||
) for first, last in result])
|
) for first, last in result])
|
||||||
|
|
||||||
return _re.sub(r'([\000-\040\047])', # for better portability
|
return _re.sub(r'([\000-\040\047])', # for better portability
|
||||||
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
|
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
|
||||||
.replace('\\', '\\\\')
|
.replace('\\', '\\\\')
|
||||||
.replace('[', '\\[')
|
.replace('[', '\\[')
|
||||||
.replace(']', '\\]')
|
.replace(']', '\\]')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def id_literal_(what):
|
def id_literal_(what):
|
||||||
""" Make id_literal like char class """
|
""" Make id_literal like char class """
|
||||||
@@ -190,25 +190,33 @@ def _make_jsmin(extended=True, python_only=True):
|
|||||||
r'|(?:(?<=%(preregex1)s)%(space)s*(%(regex)s[^\047"/\000-\040]*))'
|
r'|(?:(?<=%(preregex1)s)%(space)s*(%(regex)s[^\047"/\000-\040]*))'
|
||||||
r'|(?:(?<=%(preregex2)s)%(space)s*(%(regex)s[^\047"/\000-\040]*))'
|
r'|(?:(?<=%(preregex2)s)%(space)s*(%(regex)s[^\047"/\000-\040]*))'
|
||||||
r'|(?<=%(id_literal_close)s)'
|
r'|(?<=%(id_literal_close)s)'
|
||||||
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
|
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
|
||||||
r'(?=%(id_literal_open)s)'
|
r'(?=%(id_literal_open)s)'
|
||||||
r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)'
|
r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)'
|
||||||
r'|%(space)s+'
|
r'|%(space)s+'
|
||||||
r'|(?:%(newline)s%(space)s*)+'
|
r'|(?:%(newline)s%(space)s*)+'
|
||||||
) % locals()).sub
|
) % locals()).sub
|
||||||
|
|
||||||
def space_subber(match):
|
def space_subber(match):
|
||||||
""" Substitution callback """
|
""" Substitution callback """
|
||||||
# pylint: disable = C0321, R0911
|
# pylint: disable = C0321, R0911
|
||||||
groups = match.groups()
|
groups = match.groups()
|
||||||
if groups[0]: return groups[0]
|
if groups[0]:
|
||||||
elif groups[1]: return groups[1]
|
return groups[0]
|
||||||
elif groups[2]: return groups[2]
|
elif groups[1]:
|
||||||
elif groups[3]: return groups[3]
|
return groups[1]
|
||||||
elif groups[4]: return '\n'
|
elif groups[2]:
|
||||||
elif groups[5]: return ' '
|
return groups[2]
|
||||||
else: return ''
|
elif groups[3]:
|
||||||
|
return groups[3]
|
||||||
|
elif groups[4]:
|
||||||
|
return '\n'
|
||||||
|
elif groups[5]:
|
||||||
|
return ' '
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
def jsmin(script): # pylint: disable = W0621
|
def jsmin(script): # pylint: disable = W0621
|
||||||
r"""
|
r"""
|
||||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
||||||
|
|
||||||
@@ -239,20 +247,26 @@ def _make_jsmin(extended=True, python_only=True):
|
|||||||
r'|(%(space)s)+'
|
r'|(%(space)s)+'
|
||||||
r'|(?:(%(newline)s)%(space)s*)+'
|
r'|(?:(%(newline)s)%(space)s*)+'
|
||||||
) % locals()).sub
|
) % locals()).sub
|
||||||
|
|
||||||
def space_norm_subber(match):
|
def space_norm_subber(match):
|
||||||
""" Substitution callback """
|
""" Substitution callback """
|
||||||
# pylint: disable = C0321
|
# pylint: disable = C0321
|
||||||
groups = match.groups()
|
groups = match.groups()
|
||||||
if groups[0]: return groups[0]
|
if groups[0]:
|
||||||
elif groups[1]: return groups[1].replace('\r', '\n') + groups[2]
|
return groups[0]
|
||||||
elif groups[3]: return ' '
|
elif groups[1]:
|
||||||
elif groups[4]: return '\n'
|
return groups[1].replace('\r', '\n') + groups[2]
|
||||||
|
elif groups[3]:
|
||||||
|
return ' '
|
||||||
|
elif groups[4]:
|
||||||
|
return '\n'
|
||||||
|
|
||||||
space_sub1 = _re.compile((
|
space_sub1 = _re.compile((
|
||||||
r'[\040\n]?(%(strings)s|%(pre_regex)s%(regex)s)'
|
r'[\040\n]?(%(strings)s|%(pre_regex)s%(regex)s)'
|
||||||
r'|\040(%(not_id_literal)s)'
|
r'|\040(%(not_id_literal)s)'
|
||||||
r'|\n(%(not_id_literal_open)s)'
|
r'|\n(%(not_id_literal_open)s)'
|
||||||
) % locals()).sub
|
) % locals()).sub
|
||||||
|
|
||||||
def space_subber1(match):
|
def space_subber1(match):
|
||||||
""" Substitution callback """
|
""" Substitution callback """
|
||||||
groups = match.groups()
|
groups = match.groups()
|
||||||
@@ -264,6 +278,7 @@ def _make_jsmin(extended=True, python_only=True):
|
|||||||
r'|(%(not_id_literal)s)\040'
|
r'|(%(not_id_literal)s)\040'
|
||||||
r'|(%(not_id_literal_close)s)\n'
|
r'|(%(not_id_literal_close)s)\n'
|
||||||
) % locals()).sub
|
) % locals()).sub
|
||||||
|
|
||||||
def space_subber2(match):
|
def space_subber2(match):
|
||||||
""" Substitution callback """
|
""" Substitution callback """
|
||||||
groups = match.groups()
|
groups = match.groups()
|
||||||
@@ -295,10 +310,11 @@ def _make_jsmin(extended=True, python_only=True):
|
|||||||
:Rtype: ``str``
|
:Rtype: ``str``
|
||||||
"""
|
"""
|
||||||
return space_sub2(space_subber2,
|
return space_sub2(space_subber2,
|
||||||
space_sub1(space_subber1,
|
space_sub1(space_subber1,
|
||||||
space_norm_sub(space_norm_subber, '\n%s\n' % script)
|
space_norm_sub(space_norm_subber,
|
||||||
)
|
'\n%s\n' % script)
|
||||||
).strip()
|
)
|
||||||
|
).strip()
|
||||||
return jsmin
|
return jsmin
|
||||||
|
|
||||||
jsmin = _make_jsmin()
|
jsmin = _make_jsmin()
|
||||||
@@ -311,6 +327,7 @@ jsmin = _make_jsmin()
|
|||||||
# jsmin.jsmin(script)
|
# jsmin.jsmin(script)
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
def jsmin_for_posers(script):
|
def jsmin_for_posers(script):
|
||||||
r"""
|
r"""
|
||||||
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
|
||||||
|
|||||||
@@ -14,24 +14,27 @@ import os
|
|||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def read_binary_file(filename):
|
def read_binary_file(filename):
|
||||||
f = open(filename,'rb')
|
f = open(filename, 'rb')
|
||||||
data = f.read()
|
data = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def write_binary_file(filename,data):
|
|
||||||
f =open(filename,'wb')
|
def write_binary_file(filename, data):
|
||||||
|
f = open(filename, 'wb')
|
||||||
f.write(data)
|
f.write(data)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
def fix_links(css,static_path):
|
|
||||||
|
def fix_links(css, static_path):
|
||||||
return re.sub(r'url\((["\'])\.\./', 'url(\\1' + static_path, css)
|
return re.sub(r'url\((["\'])\.\./', 'url(\\1' + static_path, css)
|
||||||
|
|
||||||
|
|
||||||
def minify(files, path_info, folder, optimize_css, optimize_js,
|
def minify(files, path_info, folder, optimize_css, optimize_js,
|
||||||
ignore_concat = [],
|
ignore_concat=[],
|
||||||
ignore_minify = ['/jquery.js', '/anytime.js']):
|
ignore_minify=['/jquery.js', '/anytime.js']):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Input:
|
Input:
|
||||||
@@ -45,7 +48,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
|
|||||||
Returns a new list of:
|
Returns a new list of:
|
||||||
- filename (absolute or relative, css or js, actual or temporary) or
|
- filename (absolute or relative, css or js, actual or temporary) or
|
||||||
- ('css:inline','...css..')
|
- ('css:inline','...css..')
|
||||||
- ('js:inline','...js..')
|
- ('js:inline','...js..')
|
||||||
"""
|
"""
|
||||||
optimize_css = optimize_css or ''
|
optimize_css = optimize_css or ''
|
||||||
optimize_js = optimize_js or ''
|
optimize_js = optimize_js or ''
|
||||||
@@ -55,27 +58,27 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
|
|||||||
concat_js = 'concat' in optimize_js
|
concat_js = 'concat' in optimize_js
|
||||||
minify_js = 'minify' in optimize_js
|
minify_js = 'minify' in optimize_js
|
||||||
inline_js = 'inline' in optimize_js
|
inline_js = 'inline' in optimize_js
|
||||||
static_path,temp = path_info.rsplit('/',1)
|
static_path, temp = path_info.rsplit('/', 1)
|
||||||
new_files = []
|
new_files = []
|
||||||
css = []
|
css = []
|
||||||
js = []
|
js = []
|
||||||
processed = []
|
processed = []
|
||||||
for k,filename in enumerate(files):
|
for k, filename in enumerate(files):
|
||||||
if not filename.startswith('/') or \
|
if not filename.startswith('/') or \
|
||||||
any(filename.endswith(x) \
|
any(filename.endswith(x)
|
||||||
for x in ignore_concat):
|
for x in ignore_concat):
|
||||||
new_files.append(filename)
|
new_files.append(filename)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
abs_filename = os.path.join(
|
abs_filename = os.path.join(
|
||||||
folder,'static', filename[len(static_path)+1:])
|
folder, 'static', filename[len(static_path) + 1:])
|
||||||
|
|
||||||
if filename.lower().endswith('.css'):
|
if filename.lower().endswith('.css'):
|
||||||
processed.append(filename)
|
processed.append(filename)
|
||||||
spath_info, sfilename = \
|
spath_info, sfilename = \
|
||||||
path_info.split('/'), filename.split('/')
|
path_info.split('/'), filename.split('/')
|
||||||
u = 0
|
u = 0
|
||||||
for i,a in enumerate(sfilename):
|
for i, a in enumerate(sfilename):
|
||||||
try:
|
try:
|
||||||
if a != spath_info[i]:
|
if a != spath_info[i]:
|
||||||
u = i
|
u = i
|
||||||
@@ -99,8 +102,8 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
|
|||||||
|
|
||||||
if minify_js and \
|
if minify_js and \
|
||||||
not filename.endswith('.min.js') and \
|
not filename.endswith('.min.js') and \
|
||||||
not any(filename.endswith(x) \
|
not any(filename.endswith(x)
|
||||||
for x in ignore_minify):
|
for x in ignore_minify):
|
||||||
js.append(jsmin.jsmin(contents))
|
js.append(jsmin.jsmin(contents))
|
||||||
else:
|
else:
|
||||||
js.append(contents)
|
js.append(contents)
|
||||||
@@ -110,32 +113,31 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
|
|||||||
if css and concat_css:
|
if css and concat_css:
|
||||||
css = '\n\n'.join(contents for contents in css)
|
css = '\n\n'.join(contents for contents in css)
|
||||||
if not inline_css:
|
if not inline_css:
|
||||||
temppath = os.path.join(folder,'static',temp)
|
temppath = os.path.join(folder, 'static', temp)
|
||||||
if not os.path.exists(temppath):
|
if not os.path.exists(temppath):
|
||||||
os.mkdir(temppath)
|
os.mkdir(temppath)
|
||||||
dest = "compressed_%s.css" % dest_key
|
dest = "compressed_%s.css" % dest_key
|
||||||
tempfile = os.path.join(temppath, dest)
|
tempfile = os.path.join(temppath, dest)
|
||||||
write_binary_file(tempfile,css)
|
write_binary_file(tempfile, css)
|
||||||
css = path_info+'/%s' % dest
|
css = path_info + '/%s' % dest
|
||||||
new_files.append(css)
|
new_files.append(css)
|
||||||
else:
|
else:
|
||||||
new_files.append(('css:inline',css))
|
new_files.append(('css:inline', css))
|
||||||
else:
|
else:
|
||||||
new_files += css
|
new_files += css
|
||||||
if js and concat_js:
|
if js and concat_js:
|
||||||
js = '\n'.join(contents for contents in js)
|
js = '\n'.join(contents for contents in js)
|
||||||
if inline_js:
|
if inline_js:
|
||||||
js = ('js:inline',js)
|
js = ('js:inline', js)
|
||||||
else:
|
else:
|
||||||
temppath = os.path.join(folder,'static',temp)
|
temppath = os.path.join(folder, 'static', temp)
|
||||||
if not os.path.exists(temppath):
|
if not os.path.exists(temppath):
|
||||||
os.mkdir(temppath)
|
os.mkdir(temppath)
|
||||||
dest = "compressed_%s.js" % dest_key
|
dest = "compressed_%s.js" % dest_key
|
||||||
tempfile = os.path.join(folder,'static',temp,dest)
|
tempfile = os.path.join(folder, 'static', temp, dest)
|
||||||
write_binary_file(tempfile,js)
|
write_binary_file(tempfile, js)
|
||||||
js = path_info+'/%s' % dest
|
js = path_info + '/%s' % dest
|
||||||
new_files.append(js)
|
new_files.append(js)
|
||||||
else:
|
else:
|
||||||
new_files += js
|
new_files += js
|
||||||
return new_files
|
return new_files
|
||||||
|
|
||||||
|
|||||||
+20
-22
@@ -24,7 +24,7 @@ CALLOC.argtypes = [c_uint, c_uint]
|
|||||||
|
|
||||||
STRDUP = LIBC.strdup
|
STRDUP = LIBC.strdup
|
||||||
STRDUP.argstypes = [c_char_p]
|
STRDUP.argstypes = [c_char_p]
|
||||||
STRDUP.restype = POINTER(c_char) # NOT c_char_p !!!!
|
STRDUP.restype = POINTER(c_char) # NOT c_char_p !!!!
|
||||||
|
|
||||||
# Various constants
|
# Various constants
|
||||||
PAM_PROMPT_ECHO_OFF = 1
|
PAM_PROMPT_ECHO_OFF = 1
|
||||||
@@ -32,56 +32,61 @@ PAM_PROMPT_ECHO_ON = 2
|
|||||||
PAM_ERROR_MSG = 3
|
PAM_ERROR_MSG = 3
|
||||||
PAM_TEXT_INFO = 4
|
PAM_TEXT_INFO = 4
|
||||||
|
|
||||||
|
|
||||||
class PamHandle(Structure):
|
class PamHandle(Structure):
|
||||||
"""wrapper class for pam_handle_t"""
|
"""wrapper class for pam_handle_t"""
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("handle", c_void_p)
|
("handle", c_void_p)
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Structure.__init__(self)
|
Structure.__init__(self)
|
||||||
self.handle = 0
|
self.handle = 0
|
||||||
|
|
||||||
|
|
||||||
class PamMessage(Structure):
|
class PamMessage(Structure):
|
||||||
"""wrapper class for pam_message structure"""
|
"""wrapper class for pam_message structure"""
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("msg_style", c_int),
|
("msg_style", c_int),
|
||||||
("msg", c_char_p),
|
("msg", c_char_p),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<PamMessage %i '%s'>" % (self.msg_style, self.msg)
|
return "<PamMessage %i '%s'>" % (self.msg_style, self.msg)
|
||||||
|
|
||||||
|
|
||||||
class PamResponse(Structure):
|
class PamResponse(Structure):
|
||||||
"""wrapper class for pam_response structure"""
|
"""wrapper class for pam_response structure"""
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("resp", c_char_p),
|
("resp", c_char_p),
|
||||||
("resp_retcode", c_int),
|
("resp_retcode", c_int),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<PamResponse %i '%s'>" % (self.resp_retcode, self.resp)
|
return "<PamResponse %i '%s'>" % (self.resp_retcode, self.resp)
|
||||||
|
|
||||||
CONV_FUNC = CFUNCTYPE(c_int,
|
CONV_FUNC = CFUNCTYPE(c_int,
|
||||||
c_int, POINTER(POINTER(PamMessage)),
|
c_int, POINTER(POINTER(PamMessage)),
|
||||||
POINTER(POINTER(PamResponse)), c_void_p)
|
POINTER(POINTER(PamResponse)), c_void_p)
|
||||||
|
|
||||||
|
|
||||||
class PamConv(Structure):
|
class PamConv(Structure):
|
||||||
"""wrapper class for pam_conv structure"""
|
"""wrapper class for pam_conv structure"""
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("conv", CONV_FUNC),
|
("conv", CONV_FUNC),
|
||||||
("appdata_ptr", c_void_p)
|
("appdata_ptr", c_void_p)
|
||||||
]
|
]
|
||||||
|
|
||||||
PAM_START = LIBPAM.pam_start
|
PAM_START = LIBPAM.pam_start
|
||||||
PAM_START.restype = c_int
|
PAM_START.restype = c_int
|
||||||
PAM_START.argtypes = [c_char_p, c_char_p, POINTER(PamConv),
|
PAM_START.argtypes = [c_char_p, c_char_p, POINTER(PamConv),
|
||||||
POINTER(PamHandle)]
|
POINTER(PamHandle)]
|
||||||
|
|
||||||
PAM_AUTHENTICATE = LIBPAM.pam_authenticate
|
PAM_AUTHENTICATE = LIBPAM.pam_authenticate
|
||||||
PAM_AUTHENTICATE.restype = c_int
|
PAM_AUTHENTICATE.restype = c_int
|
||||||
PAM_AUTHENTICATE.argtypes = [PamHandle, c_int]
|
PAM_AUTHENTICATE.argtypes = [PamHandle, c_int]
|
||||||
|
|
||||||
|
|
||||||
def authenticate(username, password, service='login'):
|
def authenticate(username, password, service='login'):
|
||||||
"""Returns True if the given username and password authenticate for the
|
"""Returns True if the given username and password authenticate for the
|
||||||
given service. Returns False otherwise
|
given service. Returns False otherwise
|
||||||
@@ -121,10 +126,3 @@ def authenticate(username, password, service='login'):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import getpass
|
import getpass
|
||||||
print authenticate(getpass.getuser(), getpass.getpass())
|
print authenticate(getpass.getuser(), getpass.getpass())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user