Compare commits

...

44 Commits

Author SHA1 Message Date
mdipierro 37bc09169f R-2.2.1 2012-10-21 10:54:13 -05:00
mdipierro 1cc2decfdd assign_task takes better care for group_names, thanks Niphlod 2012-10-21 09:23:26 -05:00
mdipierro e9eb1689e2 fixed a problem with capitalization in wiki 2012-10-20 19:38:54 -05:00
mdipierro 0f446833c0 assign_task takes better care for group_names, thanks Niphlod 2012-10-20 15:27:13 -05:00
mdipierro cb9c2a8ef9 fixed issue 1102, thanks howesc 2012-10-20 10:12:04 -05:00
mdipierro b37ed1c1e0 fixed issue 1109, thanks Niphlod 2012-10-20 10:11:08 -05:00
mdipierro b484955005 fixed issue 1100, thanks sherdim 2012-10-20 10:08:58 -05:00
mdipierro 654626d519 removed print statements from scheduler, thanks Niphlod 2012-10-20 10:03:57 -05:00
mdipierro ca0313c514 back button in mobile admin demo 2012-10-19 18:43:14 -05:00
mdipierro fb357eb241 fixed problem with new importer and custom import 2012-10-19 18:36:39 -05:00
mdipierro 1a83487221 populate fix and pep8 2012-10-19 14:59:30 -05:00
mdipierro 6cda7a29fc pep8 in scripts/*.py 2012-10-19 14:22:42 -05:00
mdipierro 17f495e9c5 fixed pep8 in apps 2012-10-19 14:13:37 -05:00
mdipierro dd32a90844 upgraded feedparer and PyRSS2Gen 2012-10-19 12:59:58 -05:00
mdipierro 4b2ba185ae many pep8 improvements 2012-10-19 12:33:53 -05:00
mdipierro b716df1a05 some pep8 changes (fixed spacing at end) 2012-10-19 10:37:07 -05:00
mdipierro d552eb2eeb fixed some pep8 stuff 2012-10-19 09:40:17 -05:00
mdipierro de2337dfe3 scheduler.queue_task, thank Niphlod 2012-10-18 18:20:51 -05:00
mdipierro e707cfc67c codemirror autoresize 2012-10-18 13:42:49 -05:00
mdipierro c3c5df6394 scheduler.queue_task(...), thanks Niphlod 2012-10-18 13:02:19 -05:00
mdipierro 72739ebb97 better openshift error 2012-10-17 17:00:50 -05:00
mdipierro 39c94b8dcf faster scheduler, thanks Niphlod 2012-10-17 16:01:29 -05:00
mdipierro 5af380223a remove excessive session saving with caching of mobile_agent 2012-10-17 14:33:52 -05:00
mdipierro 1ea379180a fixed appadmin bug and excessive session saving 2012-10-17 14:30:02 -05:00
mdipierro ca3d050a0b fixed problem with session in cookie, thanks Niphlod 2012-10-17 12:04:19 -05:00
mdipierro 161b2271b3 T.is_writable, thanks Fran 2012-10-17 09:13:48 -05:00
Massimo 013c94cdf6 inlined sluggify 2012-10-16 11:47:16 -05:00
Massimo addbb78151 customizable session cookie expriration 2012-10-16 11:23:41 -05:00
Massimo f6789eaf39 session cookie data no expires by default 2012-10-16 11:14:52 -05:00
Massimo c13b4f18f7 fixed auth.impersonating again, thanks Ricardo 2012-10-16 11:08:42 -05:00
Massimo 67840e9481 current.T.is_writable=False no languages write, thanks Fran 2012-10-16 10:54:33 -05:00
Massimo 41c40974a3 fixed issue 1092, thanks nicozanf 2012-10-16 10:34:36 -05:00
Massimo 9a6ce11f09 users can switch between sessions storage types 2012-10-16 10:25:28 -05:00
mdipierro d404e40508 improved session data in cookie 2012-10-16 07:44:22 -05:00
mdipierro b6a496aae5 improved session data in cookie 2012-10-16 07:10:33 -05:00
mdipierro ecaed07a3d fixed bug with auth.impersonate(0) 2012-10-16 06:19:39 -05:00
mdipierro 30ec8e645b sessions in secure cookies, session.connect(cookie_key='mypassword') 2012-10-16 06:15:45 -05:00
mdipierro 3a1ba53a4b reverting some test but session.__hash needs work 2012-10-15 21:49:43 -05:00
mdipierro ab95dfa7cd fixed problem with session __hash 2012-10-15 20:43:51 -05:00
mdipierro 6b9ebb6dc5 fixed issue with storing Row in session 2012-10-15 19:39:25 -05:00
mdipierro e2e843d2ed more languages patches, thanks Vladyslav 2012-10-15 16:28:51 -05:00
mdipierro d5381d7b36 fixed make pip 2012-10-15 14:48:45 -05:00
mdipierro f7c0f0341b who page 2012-10-15 14:44:04 -05:00
mdipierro 9f7fd68728 better markmin with links in links, thanks Vladyslav 2012-10-15 07:43:23 -05:00
200 changed files with 10729 additions and 9126 deletions
+10
View File
@@ -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
- overall faster web2py
+3 -3
View File
@@ -29,7 +29,7 @@ update:
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
echo "remember that pymysql was tweaked"
src:
echo 'Version 2.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
make clean
### clean up baisc apps
@@ -130,5 +130,5 @@ pip:
# after upload clean Web2py sources with rm -R ./dist
# http://guide.python-distribute.org/creation.html
python setup.py sdist
python setup.py register
python setup.py sdist upload
sudo python setup.py register
sudo python setup.py sdist upload
+1 -1
View File
@@ -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
View File
@@ -1,10 +0,0 @@
+72 -53
View File
@@ -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.
"""
import os, sys, optparse, urllib
import os
import sys
import optparse
import urllib
path = os.path.dirname(os.path.abspath(__file__))
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
from gluon.fileutils import read_file, write_file
class Servers:
@staticmethod
def cgi(app, address=None, **options):
from wsgiref.handlers import CGIHandler
CGIHandler().run(app) # Just ignore host and port here
CGIHandler().run(app) # Just ignore host and port here
@staticmethod
def flup(app,address, **options):
def flup(app, address, **options):
import flup.server.fcgi
flup.server.fcgi.WSGIServer(app, bindAddress=address).run()
@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
class QuietHandler(WSGIRequestHandler):
def log_request(*args, **kw): pass
def log_request(*args, **kw):
pass
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()
@staticmethod
def cherrypy(app,address, **options):
def cherrypy(app, address, **options):
from cherrypy import wsgiserver
server = wsgiserver.CherryPyWSGIServer(address, app)
server.start()
@staticmethod
def rocket(app,address, **options):
def rocket(app, address, **options):
from gluon.rocket import CherryPyWSGIServer
server = CherryPyWSGIServer(address, app)
server.start()
@staticmethod
def rocket_with_repoze_profiler(app,address, **options):
def rocket_with_repoze_profiler(app, address, **options):
from gluon.rocket import CherryPyWSGIServer
from repoze.profile.profiler import AccumulatingProfileMiddleware
from gluon.settings import global_settings
@@ -59,44 +66,46 @@ class Servers:
log_filename='wsgi.prof',
discard_first_request=True,
flush_at_shutdown=True,
path = '/__profile__'
)
path='/__profile__'
)
server = CherryPyWSGIServer(address, wrapped)
server.start()
@staticmethod
def paste(app,address,**options):
def paste(app, address, **options):
from paste import httpserver
from paste.translogger import TransLogger
httpserver.serve(app, host=address[0], port=address[1], **options)
@staticmethod
def fapws(app,address, **options):
def fapws(app, address, **options):
import fapws._evwsgi as evwsgi
from fapws import base
evwsgi.start(address[0],str(address[1]))
evwsgi.start(address[0], str(address[1]))
evwsgi.set_base_module(base)
def app(environ, start_response):
environ['wsgi.multiprocess'] = False
return app(environ, start_response)
evwsgi.wsgi_cb(('',app))
evwsgi.wsgi_cb(('', app))
evwsgi.run()
@staticmethod
def gevent(app,address, **options):
from gevent import monkey; monkey.patch_all()
def gevent(app, address, **options):
from gevent import monkey
monkey.patch_all()
from gevent import pywsgi
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
def bjoern(app,address, **options):
def bjoern(app, address, **options):
import bjoern
bjoern.run(app, *address)
@staticmethod
def tornado(app,address, **options):
def tornado(app, address, **options):
import tornado.wsgi
import tornado.httpserver
import tornado.ioloop
@@ -106,7 +115,7 @@ class Servers:
tornado.ioloop.IOLoop.instance().start()
@staticmethod
def twisted(app,address, **options):
def twisted(app, address, **options):
from twisted.web import server, wsgi
from twisted.python.threadpool import ThreadPool
from twisted.internet import reactor
@@ -118,42 +127,44 @@ class Servers:
reactor.run()
@staticmethod
def diesel(app,address, **options):
def diesel(app, address, **options):
from diesel.protocols.wsgi import WSGIApplication
app = WSGIApplication(app, port=address[1])
app.run()
@staticmethod
def gunicorn(app,address, **options):
def gunicorn(app, address, **options):
from gunicorn.app.base import Application
config = {'bind': "%s:%d" % address}
config.update(options)
sys.argv = ['anyserver.py']
class GunicornApplication(Application):
def init(self, parser, opts, args):
return config
def load(self):
return app
g = GunicornApplication()
g.run()
@staticmethod
def eventlet(app,address, **options):
def eventlet(app, address, **options):
from eventlet import wsgi, listen
wsgi.server(listen(address), app)
@staticmethod
def mongrel2(app,address,**options):
def mongrel2(app, address, **options):
import uuid
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
from mongrel2 import handler
conn = handler.Connection(str(uuid.uuid4()),
"tcp://127.0.0.1:9997",
"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:
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
logfilename='httpserver.log',
@@ -163,9 +174,10 @@ def run(servername,ip,port,softcron=True,logging=False,profiler=None):
if softcron:
from gluon.settings import global_settings
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 :
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.
while True:
if debug: print "WAITING FOR REQUEST"
if debug:
print "WAITING FOR REQUEST"
# receive a request
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 debug: print "DISCONNECT"
continue #effectively ignore the disconnect from the client
if debug:
print "DISCONNECT"
continue # effectively ignore the disconnect from the client
# Set a couple of environment attributes a.k.a. header attributes
# that are a must according to PEP 333
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']
if ':' in environ['Host']:
environ['SERVER_NAME'] = environ['Host'].split(':')[0]
@@ -211,17 +226,19 @@ def mongrel2_handler(application,conn,debug=False):
else:
environ['SERVER_NAME'] = environ['Host']
environ['SERVER_PORT'] = ''
environ['SCRIPT_NAME'] = '' # empty for now
environ['SCRIPT_NAME'] = '' # empty for now
environ['PATH_INFO'] = urllib.unquote(environ['PATH'])
if '?' in environ['URI']:
environ['QUERY_STRING'] = environ['URI'].split('?')[1]
else:
environ['QUERY_STRING'] = ''
if environ.has_key('Content-Length'):
environ['CONTENT_LENGTH'] = environ['Content-Length'] # necessary for POST to work with Django
if 'Content-Length' in environ:
environ['CONTENT_LENGTH'] = environ[
'Content-Length'] # necessary for POST to work with Django
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
# requests, errors and responses
@@ -230,7 +247,8 @@ def mongrel2_handler(application,conn,debug=False):
respIO = StringIO.StringIO()
# 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)
# Get the response and filter out the response (=data) itself,
@@ -254,11 +272,15 @@ def mongrel2_handler(application,conn,debug=False):
errors = errIO.getvalue()
# return the response
if debug: print "RESPONSE: %r\n" % response
if debug:
print "RESPONSE: %r\n" % response
if errors:
if debug: print "ERRORS: %r" % errors
if debug:
print "ERRORS: %r" % 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():
usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P"
@@ -278,7 +300,7 @@ def main():
default=False,
dest='profiler',
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',
'--server',
default='rocket',
@@ -300,13 +322,10 @@ def main():
dest='workers',
help='number of workers number')
(options, args) = parser.parse_args()
print 'starting %s on %s:%s...' % (options.server,options.ip,options.port)
run(options.server,options.ip,options.port,logging=options.logging,profiler=options.profiler)
print 'starting %s on %s:%s...' % (
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()
-5
View File
@@ -2,8 +2,3 @@ def webapp_add_wsgi_middleware(app):
from google.appengine.ext.appstats import recording
app = recording.appstats_wsgi_middleware(app)
return app
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+68 -52
View File
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
try:
hosts = (http_host, socket.gethostname(),
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:
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"):
raise HTTP(200, T('appadmin is disabled because insecure channel'))
if (request.application=='admin' and not session.authorized) or \
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
if (request.application == 'admin' and not session.authorized) or \
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
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
response.view = 'appadmin.html'
@@ -95,24 +95,23 @@ def get_query(request):
return None
def query_by_table_type(tablename,db,request=request):
keyed = hasattr(db[tablename],'_primarykey')
def query_by_table_type(tablename, db, request=request):
keyed = hasattr(db[tablename], '_primarykey')
if keyed:
firstkey = db[tablename][db[tablename]._primarykey[0]]
cond = '>0'
if firstkey.type in ['string', 'text']:
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:
qry = '%s.%s.id>0' % tuple(request.args[:2])
return qry
# ##########################################################
# ## list all databases and tables
# ###########################################################
def index():
return dict(databases=databases)
@@ -127,7 +126,7 @@ def insert():
form = SQLFORM(db[table], ignore_rw=ignore_rw)
if form.accepts(request.vars, session):
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():
import os
db = get_database(request)
return response.download(request,db)
return response.download(request, db)
def csv():
import gluon.contenttype
@@ -149,26 +149,27 @@ def csv():
if not query:
return None
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
% tuple(request.vars.query.split('.')[:2])
return str(db(query,ignore_common_filters=True).select())
% tuple(request.vars.query.split('.')[:2])
return str(db(query, ignore_common_filters=True).select())
def import_csv(table, file):
table.import_from_csv_file(file)
def select():
import re
db = get_database(request)
dbname = request.args[0]
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>.+)')
if request.vars.query:
match = regex.match(request.vars.query)
if match:
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
match.group('table'), match.group('field'),
match.group('value'))
match.group('table'), match.group('field'),
match.group('value'))
else:
request.vars.query = session.last_query
query = get_query(request)
@@ -192,46 +193,50 @@ def select():
session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_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',
value=False), INPUT(_style='width:400px',
_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), ''),
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):
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
match = regex.match(form.vars.query.strip())
if match:
table = match.group('table')
try:
tb = None
nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)'
% form.vars.update_fields))
% form.vars.update_fields))
response.flash = T('%s %%{row} updated', nrows)
elif form.vars.delete_check:
db(query).delete()
response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count()
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:
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:
import traceback
tb = traceback.format_exc()
(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
csv_table = table or request.vars.table
if csv_table:
formcsv = FORM(str(T('or import from csv file'))+" ",
INPUT(_type='file',_name='csvfile'),
INPUT(_type='hidden',_value=csv_table,_name='table'),
INPUT(_type='submit',_value=T('import')))
formcsv = FORM(str(T('or import from csv file')) + " ",
INPUT(_type='file', _name='csvfile'),
INPUT(_type='hidden', _value=csv_table, _name='table'),
INPUT(_type='submit', _value=T('import')))
else:
formcsv = None
if formcsv and formcsv.process().accepted:
@@ -240,7 +245,7 @@ def select():
request.vars.csvfile.file)
response.flash = T('data uploaded')
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
return dict(
@@ -251,9 +256,9 @@ def select():
nrows=nrows,
rows=rows,
query=request.vars.query,
formcsv = formcsv,
tb = tb,
)
formcsv=formcsv,
tb=tb,
)
# ##########################################################
@@ -263,14 +268,16 @@ def select():
def update():
(db, table) = get_table(request)
keyed = hasattr(db[table],'_primarykey')
keyed = hasattr(db[table], '_primarykey')
record = None
if keyed:
key = [f for f in request.vars if f in db[table]._primarykey]
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:
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:
qry = query_by_table_type(table, db)
@@ -280,20 +287,21 @@ def update():
if keyed:
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'),
ignore_rw=ignore_rw and not keyed,
linkto=URL('select',
form = SQLFORM(
db[table], record, deletable=True, delete_label=T('Check to delete'),
ignore_rw=ignore_rw and not keyed,
linkto=URL('select',
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):
session.flash = T('done!')
qry = query_by_table_type(table, db)
redirect(URL('select', args=request.args[:1],
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():
return dict()
def ccache():
form = FORM(
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
P(TAG.BUTTON(
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
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):
@@ -332,11 +344,16 @@ def ccache():
redirect(URL(r=request))
try:
from guppy import hpy; hp=hpy()
from guppy import hpy
hp = hpy()
except ImportError:
hp = False
import shelve, os, copy, time, math
import shelve
import os
import copy
import time
import math
from gluon import portalocker
ram = {
@@ -381,9 +398,10 @@ def ccache():
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
locker = open(os.path.join(request.folder,
'cache/cache.lock'), 'a')
'cache/cache.lock'), 'a')
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:
for key, value in disk_storage.items():
if isinstance(value, dict):
@@ -414,7 +432,8 @@ def ccache():
total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys']
try:
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
except (KeyError, ZeroDivisionError):
total['ratio'] = 0
@@ -440,6 +459,3 @@ def ccache():
return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False)
+49 -40
View File
@@ -5,35 +5,39 @@ import gluon.contrib.shell
import gluon.dal
import gluon.html
import gluon.validators
import code, thread
import code
import thread
from gluon.debug import communicate, web_debugger, qdb_debugger
import pydoc
if DEMO_MODE or MULTI_USER_MODE:
session.flash = T('disabled in demo mode')
redirect(URL('default','site'))
redirect(URL('default', 'site'))
FE = 10 ** 9
FE=10**9
def index():
app = request.args(0) or 'admin'
reset()
# read buffer
data = communicate()
return dict(app=app,data=data)
return dict(app=app, data=data)
def callback():
app = request.args[0]
command = request.vars.statement
session['debug_commands:'+app].append(command)
session['debug_commands:' + app].append(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)
def reset():
app = request.args(0) or 'admin'
session['debug_commands:'+app] = []
session['debug_commands:' + app] = []
return 'done'
@@ -50,9 +54,9 @@ def interact():
filename = web_debugger.filename
lineno = web_debugger.lineno
if filename:
lines = dict([(i+1, l) for (i, l) in enumerate(
[l.strip("\n").strip("\r") for l
in open(filename).readlines()])])
lines = dict([(i + 1, l) for (i, l) in enumerate(
[l.strip("\n").strip("\r") for l
in open(filename).readlines()])])
filename = os.path.basename(filename)
else:
lines = {}
@@ -64,8 +68,8 @@ def interact():
f_globals = {}
for name, value in env['globals'].items():
if name not in gluon.html.__all__ and \
name not in gluon.validators.__all__ and \
name not in gluon.dal.__all__:
name not in gluon.validators.__all__ and \
name not in gluon.dal.__all__:
f_globals[name] = pydoc.text.repr(value)
else:
f_locals = {}
@@ -76,42 +80,48 @@ def interact():
response.flash = T('"User Exception" debug mode. '
'An error ticket could be issued!')
return dict(app=app, data="",
filename=web_debugger.filename, lines=lines, lineno=lineno,
f_globals=f_globals, f_locals=f_locals,
return dict(app=app, data="",
filename=web_debugger.filename, lines=lines, lineno=lineno,
f_globals=f_globals, f_locals=f_locals,
exception=web_debugger.exception_info)
def step():
web_debugger.do_step()
redirect(URL("interact"))
def next():
web_debugger.do_next()
redirect(URL("interact"))
def cont():
web_debugger.do_continue()
redirect(URL("interact"))
def ret():
web_debugger.do_return()
redirect(URL("interact"))
def stop():
web_debugger.do_quit()
redirect(URL("interact"))
def execute():
app = request.args[0]
command = request.vars.statement
session['debug_commands:'+app].append(command)
session['debug_commands:' + app].append(command)
try:
output = web_debugger.do_exec(command)
if output is None:
output = ""
except Exception, e:
output = T("Exception %s") % str(e)
k = len(session['debug_commands:'+app]) - 1
output = T("Exception %s") % str(e)
k = len(session['debug_commands:' + app]) - 1
return '[%i] %s%s\n' % (k + 1, command, output)
@@ -120,51 +130,51 @@ def breakpoints():
# Get all .py files
files = listdir(apath('', r=request), '.*\.py$')
files = [filename for filename in files
if filename and 'languages' not in filename
and not filename.startswith("admin")
and not filename.startswith("examples")]
files = [filename for filename in files
if filename and 'languages' not in filename
and not filename.startswith("admin")
and not filename.startswith("examples")]
form = SQLFORM.factory(
Field('filename', requires=IS_IN_SET(files), label=T("Filename")),
Field('lineno', 'integer', label=T("Line number"),
requires=IS_NOT_EMPTY()),
Field('temporary', 'boolean', label=T("Temporary"),
Field('temporary', 'boolean', label=T("Temporary"),
comment=T("deleted after first hit")),
Field('condition', 'string', label=T("Condition"),
comment=T("honored only if the expression evaluates to true")),
)
)
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)
err = qdb_debugger.do_set_breakpoint(filename,
form.vars.lineno,
form.vars.temporary,
form.vars.condition)
err = qdb_debugger.do_set_breakpoint(filename,
form.vars.lineno,
form.vars.temporary,
form.vars.condition)
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:
if item[:7] == 'delete_':
qdb_debugger.do_clear(item[7:])
breakpoints = [{'number': bp[0], 'filename': os.path.basename(bp[1]),
'path': bp[1], 'lineno': bp[2],
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
'condition': bp[6]}
for bp in qdb_debugger.do_list_breakpoint()]
'path': bp[1], 'lineno': bp[2],
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
'condition': bp[6]}
for bp in qdb_debugger.do_list_breakpoint()]
return dict(breakpoints=breakpoints, form=form)
def toggle_breakpoint():
"Set or clear a breakpoint"
lineno = None
ok = None
try:
filename = os.path.join(request.env['applications_parent'],
filename = os.path.join(request.env['applications_parent'],
'applications', request.vars.filename)
if not request.vars.data:
# ace send us the line number!
@@ -184,18 +194,17 @@ def toggle_breakpoint():
no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp
if filename == bp_filename and lineno == bp_lineno:
err = qdb_debugger.do_clear_breakpoint(filename, lineno)
response.flash = T("Removed Breakpoint on %s at line %s", (
filename, lineno))
response.flash = T("Removed Breakpoint on %s at line %s", (
filename, lineno))
ok = False
break
else:
err = qdb_debugger.do_set_breakpoint(filename, lineno)
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
else:
response.flash = T("Unable to determine the line number!")
except Exception, e:
session.flash = str(e)
return response.json({'ok': ok, 'lineno': lineno})
File diff suppressed because it is too large Load Diff
+43 -36
View File
@@ -9,85 +9,92 @@ try:
import shutil
from gluon.fileutils import read_file, write_file
except:
session.flash='sorry, only on Unix systems'
redirect(URL(request.application,'default','site'))
session.flash = 'sorry, only on Unix systems'
redirect(URL(request.application, 'default', 'site'))
if MULTI_USER_MODE and not is_manager():
session.flash = 'Not Authorized'
redirect(URL('default','site'))
redirect(URL('default', 'site'))
forever = 10 ** 8
forever=10**8
def kill():
p = cache.ram('gae_upload',lambda:None,forever)
if not p or p.poll()!=None:
p = cache.ram('gae_upload', lambda: None, forever)
if not p or p.poll() is not None:
return 'oops'
os.kill(p.pid, signal.SIGKILL)
cache.ram('gae_upload',lambda:None,-1)
cache.ram('gae_upload', lambda: None, -1)
class EXISTS(object):
def __init__(self, error_message='file not found'):
self.error_message = error_message
def __call__(self, value):
if os.path.exists(value):
return (value,None)
return (value,self.error_message)
return (value, None)
return (value, self.error_message)
def deploy():
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(
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'))),
Field('google_application_id',requires=IS_MATCH('[\w\-]+'),label=T('Google Application Id')),
Field('applications','list:string',
requires=IS_IN_SET(apps,multiple=True),
Field('google_application_id', requires=IS_MATCH(
'[\w\-]+'), label=T('Google Application Id')),
Field('applications', 'list:string',
requires=IS_IN_SET(apps, multiple=True),
label=T('web2py apps to deploy')),
Field('email',requires=IS_EMAIL(),label=T('GAE Email')),
Field('password','password',requires=IS_NOT_EMPTY(),label=T('GAE Password')))
cmd = output = errors= ""
if form.accepts(request,session):
Field('email', requires=IS_EMAIL(), label=T('GAE Email')),
Field('password', 'password', requires=IS_NOT_EMPTY(), label=T('GAE Password')))
cmd = output = errors = ""
if form.accepts(request, session):
try:
kill()
except:
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/\(.*')
yaml = apath('../app.yaml', r=request)
if not os.path.exists(yaml):
example = apath('../app.example.yaml', r=request)
shutil.copyfile(example,yaml)
shutil.copyfile(example, yaml)
data = read_file(yaml)
data = re.sub('application:.*','application: %s' % form.vars.google_application_id,data)
data = regex.sub('(applications/(%s)/.*)|' % '|'.join(ignore_apps),data)
data = re.sub('application:.*', 'application: %s' %
form.vars.google_application_id, data)
data = regex.sub(
'(applications/(%s)/.*)|' % '|'.join(ignore_apps), data)
write_file(yaml, data)
path = request.env.applications_parent
cmd = '%s --email=%s --passin update %s' % \
(form.vars.appcfg, form.vars.email, path)
p = cache.ram('gae_upload',
lambda s=subprocess,c=cmd:s.Popen(c, shell=True,
stdin=s.PIPE,
stdout=s.PIPE,
stderr=s.PIPE, close_fds=True),-1)
p.stdin.write(form.vars.password+'\n')
lambda s=subprocess, c=cmd: s.Popen(c, shell=True,
stdin=s.PIPE,
stdout=s.PIPE,
stderr=s.PIPE, close_fds=True), -1)
p.stdin.write(form.vars.password + '\n')
fcntl.fcntl(p.stdout.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():
p = cache.ram('gae_upload',lambda:None,forever)
if not p or p.poll()!=None:
p = cache.ram('gae_upload', lambda: None, forever)
if not p or p.poll() is not None:
return '<done/>'
try:
output = p.stdout.read()
except:
output=''
output = ''
try:
errors = p.stderr.read()
except:
errors=''
return (output+errors).replace('\n','<br/>')
errors = ''
return (output + errors).replace('\n', '<br/>')
+18 -17
View File
@@ -2,10 +2,10 @@ from gluon.fileutils import read_file, write_file
if DEMO_MODE or MULTI_USER_MODE:
session.flash = T('disabled in demo mode')
redirect(URL('default','site'))
redirect(URL('default', 'site'))
if not have_mercurial:
session.flash=T("Sorry, could not find mercurial installed")
redirect(URL('default','design',args=request.args(0)))
session.flash = T("Sorry, could not find mercurial installed")
redirect(URL('default', 'design', args=request.args(0)))
_hgignore_content = """\
syntax: glob
@@ -22,6 +22,7 @@ sessions/*
errors/*
"""
def hg_repo(path):
import os
uio = ui.ui()
@@ -37,13 +38,14 @@ def hg_repo(path):
write_file(hgignore, _hgignore_content)
return repo
def commit():
app = request.args(0)
path = apath(app, r=request)
repo = hg_repo(path)
form = FORM('Comment:',INPUT(_name='comment',requires=IS_NOT_EMPTY()),
INPUT(_type='submit',_value=T('Commit')))
if form.accepts(request.vars,session):
form = FORM('Comment:', INPUT(_name='comment', requires=IS_NOT_EMPTY()),
INPUT(_type='submit', _value=T('Commit')))
if form.accepts(request.vars, session):
oldid = repo[repo.lookup('.')]
addremove(repo)
repo.commit(text=form.vars.comment)
@@ -51,34 +53,33 @@ def commit():
response.flash = 'no changes'
try:
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:
ctx=repo.changectx(change)
ctx = repo.changectx(change)
revision, description = ctx.rev(), ctx.description()
changes.append(TR(A(revision,_href=URL('revision',
args=(app,revision))),
changes.append(TR(A(revision, _href=URL('revision',
args=(app, revision))),
description))
except:
files = []
changes = []
return dict(form=form,files=files,changes=changes,repo=repo)
return dict(form=form, files=files, changes=changes, repo=repo)
def revision():
app = request.args(0)
path = apath(app, r=request)
repo = hg_repo(path)
revision = request.args(1)
ctx=repo.changectx(revision)
form=FORM(INPUT(_type='submit',_value=T('Revert')))
ctx = repo.changectx(revision)
form = FORM(INPUT(_type='submit', _value=T('Revert')))
if form.accepts(request.vars):
hg.update(repo, revision)
session.flash = "reverted to revision %s" % ctx.rev()
redirect(URL('default','design',args=app))
redirect(URL('default', 'design', args=app))
return dict(
files=ctx.files(),
rev=str(ctx.rev()),
desc=ctx.description(),
form=form
)
)
+29 -20
View File
@@ -1,29 +1,36 @@
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:
from git import *
except ImportError:
session.flash = T('requires python-git, but not installed')
redirect(URL('default','site'))
redirect(URL('default', 'site'))
def deploy():
apps = sorted(file for file in os.listdir(apath(r=request)))
form = SQLFORM.factory(
Field('osrepo',default='/tmp',label=T('Path to local openshift repo root.'),
requires=EXISTS(error_message=T('directory not found'))),
Field('osname',default='web2py',label=T('WSGI reference name')),
Field('applications','list:string',
requires=IS_IN_SET(apps,multiple=True),
Field(
'osrepo', default='/tmp', label=T('Path to local openshift repo root.'),
requires=EXISTS(error_message=T('directory not found'))),
Field('osname', default='web2py', label=T('WSGI reference name')),
Field('applications', 'list:string',
requires=IS_IN_SET(apps, multiple=True),
label=T('web2py apps to deploy')))
cmd = output = errors= ""
if form.accepts(request,session):
cmd = output = errors = ""
if form.accepts(request, session):
try:
kill()
except:
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/\(.*')
w2p_origin = os.getcwd()
osrepo = form.vars.osrepo
@@ -34,23 +41,25 @@ def deploy():
assert repo.bare == False
for i in form.vars.applications:
appsrc = os.path.join(apath(r=request),i)
appdest = os.path.join(osrepo,'wsgi',osname,'applications',i)
dir_util.copy_tree(appsrc,appdest)
appsrc = os.path.join(apath(r=request), i)
appdest = os.path.join(osrepo, 'wsgi', osname, 'applications', i)
dir_util.copy_tree(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")
origin = repo.remotes.origin
origin.push
origin.push()
#Git code ends here
return dict(form=form,command=cmd)
return dict(form=form, command=cmd)
class EXISTS(object):
def __init__(self, error_message='file not found'):
self.error_message = error_message
def __call__(self, value):
if os.path.exists(value):
return (value,None)
return (value,self.error_message)
return (value, None)
return (value, self.error_message)
@@ -1,10 +1,10 @@
response.files=response.files[:3]
response.menu=[]
response.files = response.files[:3]
response.menu = []
def index():
return locals()
def about():
return locals()
+17 -14
View File
@@ -1,25 +1,29 @@
import sys
import cStringIO
import gluon.contrib.shell
import code, thread
import code
import thread
from gluon.shell import env
if DEMO_MODE or MULTI_USER_MODE:
session.flash = T('disabled in demo mode')
redirect(URL('default','site'))
redirect(URL('default', 'site'))
FE = 10 ** 9
FE=10**9
def index():
app = request.args(0) or 'admin'
reset()
return dict(app=app)
def callback():
app = request.args[0]
command = request.vars.statement
escape = command[:1]!='!'
history = session['history:'+app] = session.get('history:'+app,gluon.contrib.shell.History())
escape = command[:1] != '!'
history = session['history:' + app] = session.get(
'history:' + app, gluon.contrib.shell.History())
if not escape:
command = command[1:]
if command == '%reset':
@@ -27,21 +31,20 @@ def callback():
return '*** reset ***'
elif command[0] == '%':
try:
command=session['commands:'+app][int(command[1:])]
command = session['commands:' + app][int(command[1:])]
except ValueError:
return ''
session['commands:'+app].append(command)
environ=env(app,True)
output = gluon.contrib.shell.run(history,command,environ)
k = len(session['commands:'+app]) - 1
session['commands:' + app].append(command)
environ = env(app, True)
output = gluon.contrib.shell.run(history, command, environ)
k = len(session['commands:' + app]) - 1
#output = PRE(output)
#return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output))
return 'In [%i] : %s%s\n' % (k + 1, command, output)
def reset():
app = request.args(0) or 'admin'
session['commands:'+app] = []
session['history:'+app] = gluon.contrib.shell.History()
session['commands:' + app] = []
session['history:' + app] = gluon.contrib.shell.History()
return 'done'
+5 -5
View File
@@ -2,10 +2,12 @@ import os
from gluon.settings import global_settings, read_file
#
def index():
app = request.args(0)
return dict(app=app)
def profiler():
"""
to use the profiler start web2py with -F profiler.log
@@ -19,13 +21,11 @@ def profiler():
else:
size = 0
if os.path.exists(filename):
data = read_file('profiler.log','rb')
if size<len(data):
data = read_file('profiler.log', 'rb')
if size < len(data):
data = data[size:]
else:
size=0
size = 0
size += len(data)
response.cookies[KEY] = size
return data
@@ -33,7 +33,7 @@ def list_apps():
@service.jsonrpc
def list_files(app, pattern='.*\.py$'):
files = listdir(apath('%s/' % app, r=request), pattern)
return [x.replace('\\','/') for x in files]
return [x.replace('\\', '/') for x in files]
@service.jsonrpc
@@ -43,7 +43,7 @@ def read_file(filename, b64=False):
try:
data = f.read()
if not b64:
data = data.replace('\r','')
data = data.replace('\r', '')
else:
data = base64.b64encode(data)
finally:
@@ -82,6 +82,7 @@ def install(app_name, filename, data, overwrite=True):
return installed
@service.jsonrpc
def attach_debugger(host='localhost', port=6000, authkey='secret password'):
import gluon.contrib.qdb as qdb
@@ -90,7 +91,7 @@ def attach_debugger(host='localhost', port=6000, authkey='secret password'):
if isinstance(authkey, unicode):
authkey = authkey.encode('utf8')
if not hasattr(gluon.debug, 'qdb_listener'):
# create a remote debugger server and wait for connection
address = (host, port) # family is deduced to be 'AF_INET'
@@ -124,7 +125,7 @@ def detach_debugger():
gluon.debug.qdb_debugger = None
return True
def call():
session.forget()
return service()
+320 -273
View File
@@ -1,64 +1,73 @@
# -*- 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.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):
if not isinstance(x,(list,tuple)):
if not isinstance(x, (list, tuple)):
return x and [x] or []
return x
def clean(name):
return re.sub('\W+','_',name.strip().lower())
return re.sub('\W+', '_', name.strip().lower())
def index():
response.view='wizard/step.html'
response.view = 'wizard/step.html'
reset(session)
apps=os.listdir(os.path.join(request.folder,'..'))
form=SQLFORM.factory(Field('name',requires=[IS_NOT_EMPTY(),
IS_ALPHANUMERIC()]))
apps = os.listdir(os.path.join(request.folder, '..'))
form = SQLFORM.factory(Field('name', requires=[IS_NOT_EMPTY(),
IS_ALPHANUMERIC()]))
if form.accepts(request.vars):
app = form.vars.name
session.app['name'] = app
if MULTI_USER_MODE and db(db.app.name==app)\
(db.app.owner!=auth.user.id).count():
if MULTI_USER_MODE and db(db.app.name == app)(db.app.owner != auth.user.id).count():
session.flash = 'App belongs already to other user'
elif app in apps:
meta = os.path.normpath(\
meta = os.path.normpath(
os.path.join(os.path.normpath(request.folder),
'..',app,'wizard.metadata'))
'..', app, 'wizard.metadata'))
if os.path.exists(meta):
try:
metafile = open(meta,'rb')
metafile = open(meta, 'rb')
try:
session.app = pickle.load(metafile)
finally:
@@ -67,14 +76,14 @@ def index():
except:
session.flash = T("The app exists, was NOT created by wizard, continue to overwrite!")
redirect(URL('step1'))
return dict(step='Start',form=form)
return dict(step='Start', form=form)
def step1():
from gluon.contrib.simplejson import loads
import urllib
if not session.themes:
url=LAYOUTS_APP+'/default/layouts.json'
url = LAYOUTS_APP + '/default/layouts.json'
try:
data = urllib.urlopen(url).read()
session.themes = ['Default'] + loads(data)['layouts']
@@ -82,145 +91,158 @@ def step1():
session.themes = ['Default']
themes = session.themes
if not session.plugins:
url = PLUGINS_APP+'/default/plugins.json'
url = PLUGINS_APP + '/default/plugins.json'
try:
data = urllib.urlopen(url).read()
session.plugins = loads(data)['plugins']
except:
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'])
form=SQLFORM.factory(
Field('title',default=params.get('title',None),
requires=IS_NOT_EMPTY()),
Field('subtitle',default=params.get('subtitle',None)),
Field('author',default=params.get('author',None)),
Field('author_email',default=params.get('author_email',None)),
Field('keywords',default=params.get('keywords',None)),
Field('description','text',
default=params.get('description',None)),
Field('layout_theme',requires=IS_IN_SET(themes),
default=params.get('layout_theme',themes[0])),
Field('database_uri',default=params.get('database_uri',None)),
Field('security_key',default=params.get('security_key',None)),
Field('email_server',default=params.get('email_server',None)),
Field('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)))
form = SQLFORM.factory(
Field('title', default=params.get('title', None),
requires=IS_NOT_EMPTY()),
Field('subtitle', default=params.get('subtitle', None)),
Field('author', default=params.get('author', None)),
Field(
'author_email', default=params.get('author_email', None)),
Field('keywords', default=params.get('keywords', None)),
Field('description', 'text',
default=params.get('description', None)),
Field('layout_theme', requires=IS_IN_SET(themes),
default=params.get('layout_theme', themes[0])),
Field(
'database_uri', default=params.get('database_uri', None)),
Field(
'security_key', default=params.get('security_key', None)),
Field(
'email_server', default=params.get('email_server', None)),
Field(
'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):
session.app['params']=[(key,form.vars.get(key,None))
for key,value in session.app['params']]
session.app['params'] = [(key, form.vars.get(key, None))
for key, value in session.app['params']]
redirect(URL('step2'))
return dict(step='1: Setting Parameters',form=form)
return dict(step='1: Setting Parameters', form=form)
def step2():
response.view='wizard/step.html'
form=SQLFORM.factory(Field('table_names','list:string',
default=session.app['tables']))
response.view = 'wizard/step.html'
form = SQLFORM.factory(Field('table_names', 'list:string',
default=session.app['tables']))
if form.accepts(request.vars):
table_names = [clean(t) for t in listify(form.vars.table_names) \
if t.strip()]
if [t for t in table_names if t.startswith('auth_') and \
not t=='auth_user']:
table_names = [clean(t) for t in listify(form.vars.table_names)
if t.strip()]
if [t for t in table_names if t.startswith('auth_') and
not t == 'auth_user']:
form.error.table_names = \
T('invalid table names (auth_* tables already defined)')
else:
session.app['tables']=table_names
session.app['tables'] = table_names
for table in session.app['tables']:
if not 'table_'+table in session.app:
session.app['table_'+table]=['name']
if not table=='auth_user':
name = table+'_manage'
if not 'table_' + table in session.app:
session.app['table_' + table] = ['name']
if not table == 'auth_user':
name = table + '_manage'
if not name in session.app['pages']:
session.app['pages'].append(name)
session.app['page_'+name] = \
session.app['page_' + name] = \
'## Manage %s\n\n{{=form}}' % (table)
if session.app['tables']:
redirect(URL('step3',args=0))
redirect(URL('step3', args=0))
else:
redirect(URL('step4'))
return dict(step='2: Tables',form=form)
return dict(step='2: Tables', form=form)
def step3():
response.view='wizard/step.html'
n=int(request.args(0) or 0)
m=len(session.app['tables'])
if n>=m: redirect(URL('step2'))
table=session.app['tables'][n]
form=SQLFORM.factory(Field('field_names','list:string',
default=session.app.get('table_'+table,[])))
response.view = 'wizard/step.html'
n = int(request.args(0) or 0)
m = len(session.app['tables'])
if n >= m:
redirect(URL('step2'))
table = session.app['tables'][n]
form = SQLFORM.factory(Field('field_names', 'list:string',
default=session.app.get('table_' + table, [])))
if form.accepts(request.vars) and form.vars.field_names:
fields=listify(form.vars.field_names)
if table=='auth_user':
for field in ['first_name','last_name','username','email','password']:
fields = listify(form.vars.field_names)
if table == 'auth_user':
for field in ['first_name', 'last_name', 'username', 'email', 'password']:
if not field in fields:
fields.append(field)
session.app['table_'+table]=[t.strip().lower()
for t in listify(form.vars.field_names)
if t.strip()]
session.app['table_' + table] = [t.strip().lower()
for t in listify(form.vars.field_names)
if t.strip()]
try:
tables=sort_tables(session.app['tables'])
tables = sort_tables(session.app['tables'])
except RuntimeError:
response.flash=T('invalid circular reference')
response.flash = T('invalid circular reference')
else:
if n<m-1:
redirect(URL('step3',args=n+1))
if n < m - 1:
redirect(URL('step3', args=n + 1))
else:
redirect(URL('step4'))
return dict(step='3: Fields for table "%s" (%s of %s)' \
% (table,n+1,m),table=table,form=form)
return dict(step='3: Fields for table "%s" (%s of %s)'
% (table, n + 1, m), table=table, form=form)
def step4():
response.view='wizard/step.html'
form=SQLFORM.factory(Field('pages','list:string',
default=session.app['pages']))
response.view = 'wizard/step.html'
form = SQLFORM.factory(Field('pages', 'list:string',
default=session.app['pages']))
if form.accepts(request.vars):
session.app['pages']=[clean(t)
for t in listify(form.vars.pages)
if t.strip()]
session.app['pages'] = [clean(t)
for t in listify(form.vars.pages)
if t.strip()]
if session.app['pages']:
redirect(URL('step5',args=0))
redirect(URL('step5', args=0))
else:
redirect(URL('step6'))
return dict(step='4: Pages',form=form)
return dict(step='4: Pages', form=form)
def step5():
response.view='wizard/step.html'
n=int(request.args(0) or 0)
m=len(session.app['pages'])
if n>=m: redirect(URL('step4'))
page=session.app['pages'][n]
markmin_url='http://web2py.com/examples/static/markmin.html'
form=SQLFORM.factory(Field('content','text',
default=session.app.get('page_'+page,[]),
comment=A('use markmin',
_href=markmin_url,_target='_blank')),
formstyle='table2cols')
response.view = 'wizard/step.html'
n = int(request.args(0) or 0)
m = len(session.app['pages'])
if n >= m:
redirect(URL('step4'))
page = session.app['pages'][n]
markmin_url = 'http://web2py.com/examples/static/markmin.html'
form = SQLFORM.factory(Field('content', 'text',
default=session.app.get('page_' + page, []),
comment=A('use markmin',
_href=markmin_url, _target='_blank')),
formstyle='table2cols')
if form.accepts(request.vars):
session.app['page_'+page]=form.vars.content
if n<m-1:
redirect(URL('step5',args=n+1))
session.app['page_' + page] = form.vars.content
if n < m - 1:
redirect(URL('step5', args=n + 1))
else:
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():
response.view='wizard/step.html'
response.view = 'wizard/step.html'
params = dict(session.app['params'])
app = session.app['name']
form=SQLFORM.factory(
Field('generate_model','boolean',default=True),
Field('generate_controller','boolean',default=True),
Field('generate_views','boolean',default=True),
Field('generate_menu','boolean',default=True),
Field('apply_layout','boolean',default=True),
Field('erase_database','boolean',default=True),
Field('populate_database','boolean',default=True))
form = SQLFORM.factory(
Field('generate_model', 'boolean', default=True),
Field('generate_controller', 'boolean', default=True),
Field('generate_views', 'boolean', default=True),
Field('generate_menu', 'boolean', default=True),
Field('apply_layout', 'boolean', default=True),
Field('erase_database', 'boolean', default=True),
Field('populate_database', 'boolean', default=True))
if form.accepts(request.vars):
if DEMO_MODE:
session.flash = T('Application cannot be generated in demo mode')
@@ -228,159 +250,173 @@ def step6():
create(form.vars)
session.flash = 'Application %s created' % app
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():
return dict(app=session.app['name'])
def sort_tables(tables):
import re
regex = re.compile('(%s)' % '|'.join(tables))
is_auth_user = 'auth_user' in tables
d={}
d = {}
for table in tables:
d[table]=[]
d[table] = []
for field in session.app['table_%s' % table]:
d[table]+=regex.findall(field)
tables=[]
d[table] += regex.findall(field)
tables = []
if is_auth_user:
tables.append('auth_user')
def append(table,trail=[]):
def append(table, trail=[]):
if table in trail:
raise RuntimeError
for t in d[table]:
# 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:
tables.append(table)
for table in d: append(table)
for table in d:
append(table)
return tables
def make_table(table,fields):
rawtable=table
if table!='auth_user': table='t_'+table
s=''
s+='\n'+'#'*40+'\n'
s+="db.define_table('%s',\n" % table
first_field='id'
def make_table(table, fields):
rawtable = table
if table != 'auth_user':
table = 't_' + table
s = ''
s += '\n' + '#' * 40 + '\n'
s += "db.define_table('%s',\n" % table
first_field = 'id'
for field in fields:
items=[x.lower() for x in field.split()]
items = [x.lower() for x in field.split()]
has = {}
keys = []
for key in ['notnull','unique','integer','double','boolean','float',
'boolean', 'date','time','datetime','text','wiki',
'html','file','upload','image','true',
'hidden','readonly','writeonly','multiple',
'notempty','required']:
for key in ['notnull', 'unique', 'integer', 'double', 'boolean', 'float',
'boolean', 'date', 'time', 'datetime', 'text', 'wiki',
'html', 'file', 'upload', 'image', 'true',
'hidden', 'readonly', 'writeonly', 'multiple',
'notempty', 'required']:
if key in items[1:]:
keys.append(key)
has[key] = True
tables = session.app['tables']
refs = [t for t in tables if t in items]
items = items[:1] + [x for x in items[1:] \
if not x in keys and not x in tables]
items = items[:1] + [x for x in items[1:]
if not x in keys and not x in tables]
barename = name = '_'.join(items)
if table[:2]=='t_': name='f_'+name
if first_field=='id': first_field=name
if table[:2] == 't_': name = 'f_' + name
if first_field == 'id':
first_field = name
### determine field type
ftype='string'
deftypes={'integer':'integer','double':'double','boolean':'boolean',
'float':'double','bool':'boolean',
'date':'date','time':'time','datetime':'datetime',
'text':'text','file':'upload','image':'upload',
'upload':'upload','wiki':'text', 'html':'text'}
for key,t in deftypes.items():
ftype = 'string'
deftypes = {'integer': 'integer', 'double': 'double', 'boolean': 'boolean',
'float': 'double', 'bool': 'boolean',
'date': 'date', 'time': 'time', 'datetime': 'datetime',
'text': 'text', 'file': 'upload', 'image': 'upload',
'upload': 'upload', 'wiki': 'text', 'html': 'text'}
for key, t in deftypes.items():
if key in has:
ftype = t
if refs:
key = refs[0]
if not key=='auth_user': key='t_'+key
if not key == 'auth_user':
key = 't_' + key
if 'multiple' in has:
ftype='list:reference %s' % key
ftype = 'list:reference %s' % key
else:
ftype='reference %s' % key
if ftype=='string' and 'multiple' in has:
ftype='list:string'
elif ftype=='integer' and 'multiple' in has:
ftype='list:integer'
elif name=='password':
ftype='password'
s+=" Field('%s', type='%s'" % (name, ftype)
ftype = 'reference %s' % key
if ftype == 'string' and 'multiple' in has:
ftype = 'list:string'
elif ftype == 'integer' and 'multiple' in has:
ftype = 'list:integer'
elif name == 'password':
ftype = 'password'
s += " Field('%s', type='%s'" % (name, ftype)
### determine field attributes
if 'notnull' in has or 'notempty' in has or 'required' in has:
s+=', notnull=True'
s += ', notnull=True'
if 'unique' in has:
s+=', unique=True'
if ftype=='boolean' and 'true' in has:
s+=",\n default=True"
s += ', unique=True'
if ftype == 'boolean' and 'true' in has:
s += ",\n default=True"
### determine field representation
elif 'wiki' in has:
s+=",\n represent=lambda x, row: MARKMIN(x)"
s+=",\n comment='WIKI (markmin)'"
s += ",\n represent=lambda x, row: MARKMIN(x)"
s += ",\n comment='WIKI (markmin)'"
elif 'html' in has:
s+=",\n represent=lambda x, row: XML(x,sanitize=True)"
s+=",\n comment='HTML (sanitized)'"
s += ",\n represent=lambda x, row: XML(x,sanitize=True)"
s += ",\n comment='HTML (sanitized)'"
### determine field access
if name=='password' or 'writeonly' in has:
s+=",\n readable=False"
if name == 'password' or 'writeonly' in has:
s += ",\n readable=False"
elif 'hidden' in has:
s+=",\n writable=False, readable=False"
s += ",\n writable=False, readable=False"
elif 'readonly' in has:
s+=",\n writable=False"
s += ",\n writable=False"
### make up a label
s+=",\n label=T('%s')),\n" % \
s += ",\n label=T('%s')),\n" % \
' '.join(x.capitalize() for x in barename.split('_'))
if table=='auth_user':
s+=" Field('created_on','datetime',default=request.now,\n"
s+=" label=T('Created On'),writable=False,readable=False),\n"
s+=" Field('modified_on','datetime',default=request.now,\n"
s+=" label=T('Modified On'),writable=False,readable=False,\n"
s+=" update=request.now),\n"
s+=" Field('registration_key',default='',\n"
s+=" writable=False,readable=False),\n"
s+=" Field('reset_password_key',default='',\n"
s+=" writable=False,readable=False),\n"
s+=" Field('registration_id',default='',\n"
s+=" writable=False,readable=False),\n"
if table == 'auth_user':
s += " Field('created_on','datetime',default=request.now,\n"
s += " label=T('Created On'),writable=False,readable=False),\n"
s += " Field('modified_on','datetime',default=request.now,\n"
s += " label=T('Modified On'),writable=False,readable=False,\n"
s += " update=request.now),\n"
s += " Field('registration_key',default='',\n"
s += " writable=False,readable=False),\n"
s += " Field('reset_password_key',default='',\n"
s += " writable=False,readable=False),\n"
s += " Field('registration_id',default='',\n"
s += " writable=False,readable=False),\n"
elif 'auth_user' in session.app['tables']:
s+=" auth.signature,\n"
s+=" format='%("+first_field+")s',\n"
s+=" migrate=settings.migrate)\n\n"
if table=='auth_user':
s+="""
db.auth_user.first_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty)
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)
s += " auth.signature,\n"
s += " format='%(" + first_field + ")s',\n"
s += " migrate=settings.migrate)\n\n"
if table == 'auth_user':
s += """
db.auth_user.first_name.requires = IS_NOT_EMPTY(
error_message=auth.messages.is_empty)
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.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))
"""
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
def fix_db(filename):
params = dict(session.app['params'])
content = read_file(filename,'rb')
content = read_file(filename, 'rb')
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',
params['database_uri'])
content = content.replace('auth.define_tables()',\
auth_user+'auth.define_tables(migrate = settings.migrate)')
params['database_uri'])
content = content.replace('auth.define_tables()',
auth_user + 'auth.define_tables(migrate = settings.migrate)')
content += """
mail.settings.server = settings.email_server
mail.settings.sender = settings.email_sender
mail.settings.login = settings.email_login
"""
if params['login_method']=='janrain':
content+="""
if params['login_method'] == 'janrain':
content += """
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,
api_key = settings.login_config.split(':')[-1],
domain = settings.login_config.split(':')[0],
@@ -388,14 +424,15 @@ auth.settings.login_form = RPXAccount(request,
"""
write_file(filename, content, 'wb')
def make_menu(pages):
s=''
s+='response.title = settings.title\n'
s+='response.subtitle = settings.subtitle\n'
s+="response.meta.author = '%(author)s <%(author_email)s>' % settings\n"
s+='response.meta.keywords = settings.keywords\n'
s+='response.meta.description = settings.description\n'
s+='response.menu = [\n'
s = ''
s += 'response.title = settings.title\n'
s += 'response.subtitle = settings.subtitle\n'
s += "response.meta.author = '%(author)s <%(author_email)s>' % settings\n"
s += 'response.meta.keywords = settings.keywords\n'
s += 'response.meta.description = settings.description\n'
s += 'response.menu = [\n'
for page in pages:
if not page.startswith('error'):
if page.endswith('_manage'):
@@ -403,65 +440,70 @@ def make_menu(pages):
else:
page_name = page
page_name = ' '.join(x.capitalize() for x in page_name.split('_'))
s+="(T('%s'),URL('default','%s')==URL(),URL('default','%s'),[]),\n" \
% (page_name,page,page)
s+=']'
s += "(T('%s'),URL('default','%s')==URL(),URL('default','%s'),[]),\n" \
% (page_name, page, page)
s += ']'
return s
def make_page(page,contents):
if 'auth_user' in session.app['tables'] and not page in ('index','error'):
s="@auth.requires_login()\ndef %s():\n" % page
def make_page(page, contents):
if 'auth_user' in session.app['tables'] and not page in ('index', 'error'):
s = "@auth.requires_login()\ndef %s():\n" % page
else:
s="def %s():\n" % page
items = page.rsplit('_',1)
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+=" return locals()\n\n"
s = "def %s():\n" % page
items = page.rsplit('_', 1)
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 += " return locals()\n\n"
else:
s+=" return dict()\n\n"
s += " return dict()\n\n"
return s
def make_view(page,contents):
s="{{extend 'layout.html'}}\n\n"
s+=str(MARKMIN(contents))
def make_view(page, contents):
s = "{{extend 'layout.html'}}\n\n"
s += str(MARKMIN(contents))
return s
def populate(tables):
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):
t=table=='auth_user' and 'auth_user' or 't_'+table
s+=" populate(db.%s,10)\n" % t
t = table == 'auth_user' and 'auth_user' or 't_' + table
s += " populate(db.%s,10)\n" % t
return s
def create(options):
if DEMO_MODE:
session.flash = T('disabled in demo mode')
redirect(URL('step6'))
params = dict(session.app['params'])
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:
db.app.insert(name=app,owner=auth.user.id)
db.app.insert(name=app, owner=auth.user.id)
else:
session.flash = 'Failure to create application'
redirect(URL('step6'))
### save metadata in newapp/wizard.metadata
try:
meta = os.path.join(request.folder,'..',app,'wizard.metadata')
file=open(meta,'wb')
pickle.dump(session.app,file)
meta = os.path.join(request.folder, '..', app, 'wizard.metadata')
file = open(meta, 'wb')
pickle.dump(session.app, file)
file.close()
except IOError:
session.flash = 'Failure to write wizard metadata'
redirect(URL('step6'))
### apply theme
if options.apply_layout and params['layout_theme']!='Default':
if options.apply_layout and params['layout_theme'] != 'Default':
try:
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)
except:
session.flash = T("unable to download layout")
@@ -469,55 +511,58 @@ def create(options):
### apply plugins
for plugin in params['plugins']:
try:
plugin_name = 'web2py.plugin.'+plugin+'.w2p'
stream = urllib.urlopen(PLUGINS_APP+'/static/'+plugin_name)
plugin_name = 'web2py.plugin.' + plugin + '.w2p'
stream = urllib.urlopen(PLUGINS_APP + '/static/' + plugin_name)
plugin_install(app, stream, request, plugin_name)
except Exception, e:
session.flash = T("unable to download plugin: %s" % plugin)
### 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')
try:
file.write("from gluon.storage import Storage\n")
file.write("settings = Storage()\n\n")
file.write("settings.migrate = True\n")
for key,value in session.app['params']:
file.write("settings.%s = %s\n" % (key,repr(value)))
for key, value in session.app['params']:
file.write("settings.%s = %s\n" % (key, repr(value)))
finally:
file.close()
### write configuration file into newapp/models/menu.py
if options.generate_menu:
model = os.path.join(request.folder,'..',app,'models','menu.py')
file = open(model,'wb')
model = os.path.join(request.folder, '..', app, 'models', 'menu.py')
file = open(model, 'wb')
try:
file.write(make_menu(session.app['pages']))
finally:
file.close()
### 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)
### create newapp/models/db_wizard.py
if options.generate_model:
model = os.path.join(request.folder,'..',app,'models','db_wizard.py')
file = open(model,'wb')
model = os.path.join(
request.folder, '..', app, 'models', 'db_wizard.py')
file = open(model, 'wb')
try:
file.write('### we prepend t_ to tablenames and f_ to fieldnames for disambiguity\n\n')
tables = sort_tables(session.app['tables'])
for table in tables:
if table=='auth_user': continue
file.write(make_table(table,session.app['table_'+table]))
if table == 'auth_user':
continue
file.write(make_table(table, session.app['table_' + table]))
finally:
file.close()
model = os.path.join(request.folder,'..',app,
'models','db_wizard_populate.py')
if os.path.exists(model): os.unlink(model)
model = os.path.join(request.folder, '..', app,
'models', 'db_wizard_populate.py')
if os.path.exists(model):
os.unlink(model)
if options.populate_database and session.app['tables']:
file = open(model,'wb')
file = open(model, 'wb')
try:
file.write(populate(session.app['tables']))
finally:
@@ -525,8 +570,9 @@ def create(options):
### create newapp/controllers/default.py
if options.generate_controller:
controller = os.path.join(request.folder,'..',app,'controllers','default.py')
file = open(controller,'wb')
controller = os.path.join(
request.folder, '..', app, 'controllers', 'default.py')
file = open(controller, 'wb')
try:
file.write("""# -*- coding: utf-8 -*-
### required - do no delete
@@ -536,23 +582,24 @@ def call(): return service()
### end requires
""")
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:
file.close()
### create newapp/views/default/*.html
if options.generate_views:
for page in session.app['pages']:
view = os.path.join(request.folder,'..',app,'views','default',page+'.html')
file = open(view,'wb')
view = os.path.join(
request.folder, '..', app, 'views', 'default', page + '.html')
file = open(view, 'wb')
try:
file.write(make_view(page,session.app.get('page_'+page,'')))
file.write(
make_view(page, session.app.get('page_' + page, '')))
finally:
file.close()
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):
os.unlink(file)
@@ -19,5 +19,3 @@ for filename in os.listdir(path):
os.unlink(fullpath)
except:
logging.exception('failure to check %s'%fullpath)
+6 -1
View File
@@ -34,10 +34,12 @@
'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані',
'appadmin': 'Aдм.панель',
'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку",
'Application': 'Додаток (Application)',
'application "%s" uninstalled': 'додаток "%s" вилучено',
'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s',
'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна',
'application compiled': 'додаток скомпільовано',
'Application exists already': 'Додаток вже існує',
'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна',
'Application name:': 'Назва додатку:',
'are not used': 'не використовуються',
@@ -160,6 +162,7 @@
'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)',
'Error ticket': 'Позначка (ticket) про помилку',
'Errors': 'Помилки',
'Errors in form, please check it out.': 'Помилка у формі, будь-ласка перевірте її.',
'Exception %(extype)s: %(exvalue)s': 'Виключення %(extype)s: %(exvalue)s',
'Exception %s': 'Виключення %s',
'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)',
@@ -388,6 +391,7 @@
'There are no models': 'Моделей, наразі, нема',
'There are no modules': 'Модулів поки що нема',
'There are no plugins': 'Жодної втулки, наразі, не встановлено',
'There are no private files': 'Приватних файлів поки що нема',
'There are no static files': 'Статичних файлів, наразі, нема',
'There are no translators': 'Перекладів нема',
'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу',
@@ -418,6 +422,7 @@
'Traceback': 'Стек викликів (Traceback)',
'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови',
'try something like': 'спробуйте щось схоже на',
'Try the mobile interface': 'Спробуйте мобільний інтерфейс',
'try view': 'дивитись результат',
'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]), щоб запустити їх на виконання.',
@@ -463,7 +468,7 @@
'Views': 'Відображення (Views)',
'views': 'відображення',
'WARNING:': 'ПОПЕРЕДЖЕННЯ:',
'Web Framework': 'Web Framework',
'Web Framework': 'Веб-каркас (Web Framework)',
'web2py apps to deploy': 'Готові до розгортання додатки web2py',
'web2py Debugger': 'Ладнач web2py',
'web2py downgrade': 'повернення на попередню версію web2py',
+7 -9
View File
@@ -1,7 +1,7 @@
EXPIRATION = 60 * 60 # logout after 60 minutes of inactivity
CHECK_VERSION = True
WEB2PY_URL = 'http://web2py.com'
WEB2PY_VERSION_URL = WEB2PY_URL+'/examples/default/version'
WEB2PY_VERSION_URL = WEB2PY_URL + '/examples/default/version'
###########################################################################
# Preferences for EditArea
@@ -13,15 +13,15 @@ TEXT_EDITOR = 'codemirror' or 'ace' or 'edit_area' or 'amy'
## Editor Color scheme (only for ace)
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",
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
"merbivore_soft", "monokai", "mono_industrial", "pastel_on_dark",
"solarized_dark", "solarized_light", "textmate", "tomorrow",
"tomorrow_night", "tomorrow_night_blue", "tomorrow_night_bright",
"tomorrow_night_eighties", "twilight", "vibrant_ink")[0]
## Editor Keyboard bindings (only for ace and codemirror)
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
TEXT_EDITOR_KEYBINDING = '' # 'emacs' or 'vi'
### edit_area only
# 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
MULTI_USER_MODE = False
EMAIL_SERVER = 'localhost'
EMAIL_SENDER = 'professor@example.com'
EMAIL_LOGIN = None
EMAIL_SERVER = 'localhost'
EMAIL_SENDER = 'professor@example.com'
EMAIL_LOGIN = None
# configurable twitterbox, set to None/False to suppress
TWITTER_HASH = "web2py"
@@ -78,5 +78,3 @@ PLUGINS_APP = 'http://web2py.com/plugins'
# set the language
if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage'] is None):
T.force(request.cookies['adminLanguage'].value)
-2
View File
@@ -28,5 +28,3 @@ from gluon.languages import findT, update_all_languages
from gluon.myregex import *
from gluon.restricted import *
from gluon.compileapp import compile_application, remove_compiled_application
+27 -21
View File
@@ -1,4 +1,6 @@
import base64, os, time
import base64
import os
import time
from gluon import portalocker
from gluon.admin import apath
from gluon.fileutils import read_file
@@ -24,7 +26,8 @@ elif not request.is_local and not DEMO_MODE:
try:
_config = {}
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']:
raise HTTP(200, T('admin disabled because no admin password'))
@@ -38,7 +41,8 @@ except IOError:
raise HTTP(200,
T('admin disabled because not supported on google app engine'))
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):
@@ -50,7 +54,7 @@ def verify_password(password):
elif _config['password'].startswith('pam_user:'):
session.pam_user = _config['password'][9:].strip()
import gluon.contrib.pam
return gluon.contrib.pam.authenticate(session.pam_user,password)
return gluon.contrib.pam.authenticate(session.pam_user, password)
else:
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
expiration_failed_logins = 3600
def read_hosts_deny():
import datetime
hosts = {}
@@ -75,7 +80,7 @@ def read_hosts_deny():
continue
fields = line.strip().split()
if len(fields) > 2:
hosts[fields[0].strip()] = ( # ip
hosts[fields[0].strip()] = ( # ip
int(fields[1].strip()), # n attemps
int(fields[2].strip()) # last attempts
)
@@ -83,28 +88,30 @@ def read_hosts_deny():
f.close()
return hosts
def write_hosts_deny(denied_hosts):
f = open(deny_file, 'w')
portalocker.lock(f, portalocker.LOCK_EX)
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])
f.write(line)
portalocker.unlock(f)
f.close()
def login_record(success=True):
denied_hosts = read_hosts_deny()
val = (0,0)
val = (0, 0)
if success and request.client in denied_hosts:
del denied_hosts[request.client]
elif not success and not request.is_local:
val = denied_hosts.get(request.client,(0,0))
if time.time()-val[1]<expiration_failed_logins \
val = denied_hosts.get(request.client, (0, 0))
if time.time() - val[1] < expiration_failed_logins \
and val[0] >= allowed_number_of_attempts:
return val[0] # locked out
time.sleep(2**val[0])
val = (val[0]+1,int(time.time()))
return val[0] # locked out
time.sleep(2 ** val[0])
val = (val[0] + 1, int(time.time()))
denied_hosts[request.client] = val
write_hosts_deny(denied_hosts)
return val[0]
@@ -124,9 +131,9 @@ if session.authorized:
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'
if request.controller=='default' and request.function=='index':
if request.controller == 'default' and request.function == 'index':
if not request.vars.is_mobile:
session.is_mobile = 'auto'
if not session.is_mobile:
@@ -141,14 +148,14 @@ else:
if request.controller == "webservices":
basic = request.env.http_authorization
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(':')
if not verify_password(password) or MULTI_USER_MODE:
time.sleep(10)
raise HTTP(403,"Not authorized")
raise HTTP(403, "Not authorized")
elif not session.authorized and not \
(request.controller+'/'+request.function in
('default/index','default/user','plugin_jqmobile/index','plugin_jqmobile/about')):
(request.controller + '/' + request.function in
('default/index', 'default/user', 'plugin_jqmobile/index', 'plugin_jqmobile/about')):
if request.env.query_string:
query_string = '?' + request.env.query_string
@@ -165,7 +172,6 @@ elif session.authorized and \
request.function == 'index':
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'
redirect(URL('default','sites'))
redirect(URL('default', 'sites'))
+16 -12
View File
@@ -2,37 +2,41 @@
import os
def A_button(*a,**b):
def A_button(*a, **b):
b['_data-role'] = 'button'
b['_data-inline'] = 'true'
return A(*a,**b)
return A(*a, **b)
def button(href, label):
if is_mobile:
ret = A_button(SPAN(label), _href=href)
else:
ret = A(SPAN(label),_class='button',_href=href)
ret = A(SPAN(label), _class='button', _href=href)
return ret
def button_enable(href, app):
if os.path.exists(os.path.join(apath(app,r=request),'DISABLED')):
label = SPAN(T('Enable'),_style='color:red')
if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')):
label = SPAN(T('Enable'), _style='color:red')
else:
label = SPAN(T('Disable'),_style='color:green')
id = 'enable_'+app
return A(label,_class='button',_id=id,callback=href,target=id)
label = SPAN(T('Disable'), _style='color:green')
id = 'enable_' + app
return A(label, _class='button', _id=id, callback=href, target=id)
def sp_button(href, label):
if request.user_agent().is_mobile:
ret = A_button(SPAN(label), _href=href)
else:
ret = A(SPAN(label),_class='button special',_href=href)
ret = A(SPAN(label), _class='button special', _href=href)
return ret
def helpicon():
return IMG(_src=URL('static', 'images/help.png'), _alt='help')
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))
+14 -12
View File
@@ -4,37 +4,39 @@
if MULTI_USER_MODE:
db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB
from gluon.tools import *
auth = Auth(globals(),db) # authentication/authorization
crud = Crud(globals(),db) # for CRUD helpers using auth
service = Service(globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
auth = Auth(
globals(), db) # authentication/authorization
crud = Crud(
globals(), db) # for CRUD helpers using auth
service = Service(
globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
plugins = PluginManager()
mail = auth.settings.mailer
mail.settings.server = EMAIL_SERVER
mail.settings.sender = EMAIL_SENDER
mail.settings.login = EMAIL_LOGIN
mail.settings.login = EMAIL_LOGIN
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.settings.registration_requires_verification = False
auth.settings.registration_requires_approval = 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 auth.user and not request.function=='user':
if auth.user and not request.function == 'user':
session.authorized = True
elif not request.function=='user':
redirect(URL('default','user/login'))
elif not request.function == 'user':
redirect(URL('default', 'user/login'))
def is_manager():
if not MULTI_USER_MODE:
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
else:
return False
+10 -11
View File
@@ -7,31 +7,30 @@ _c = request.controller
_f = request.function
response.title = '%s %s' % (_f, '/'.join(request.args))
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:
_t = request.vars.app or request.args[0]
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',
URL(_a,'default','about',args=_t,)))
URL(_a, 'default', 'about', args=_t,)))
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'),
_c == 'mercurial' and _f == 'commit',
URL(_a,'mercurial','commit',args=_t)))
URL(_a, 'mercurial', 'commit', args=_t)))
if not session.authorized:
response.menu = [(T('Login'), True, URL('site'))]
else:
response.menu.append((T('Logout'), False,
URL(_a,'default',f='logout')))
response.menu.append((T('Debug'), False,
URL(_a, 'debug','interact')))
URL(_a, 'default', f='logout')))
response.menu.append((T('Debug'), False,
URL(_a, 'debug', 'interact')))
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:
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(URL('static','plugin_multiselect/multi-select.css'))
response.files.append(URL('static','plugin_multiselect/start.js'))
response.files.append(
URL('static', 'plugin_multiselect/jquery.multi-select.js'))
response.files.append(URL('static', 'plugin_multiselect/multi-select.css'))
response.files.append(URL('static', 'plugin_multiselect/start.js'))
-1
View File
@@ -1,2 +1 @@
+2 -1
View File
@@ -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>
<script>window.eamy = eamy;</script>
{{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>
function isFullScreen(instance) {
return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className);
@@ -197,6 +197,7 @@ jQuery(document).ready(function(){
document.getElementById("body"),cm_opts);
var hlLine = editor.setLineClass(0, "activeline");
window.mirror = editor;
jQuery(function(){jQuery('.CodeMirror-scroll').css("height","auto").css("overflow-x","auto");});
</script>
{{elif TEXT_EDITOR == 'ace':}}
<div id="editor" style="height: 500px; width: auto; position: relative">{{=data}}</div>
@@ -9,6 +9,13 @@
body {
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 {
position: absolute;
margin-left: 320px;
@@ -35,6 +42,7 @@
</head>
<body>
<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">
<h1><a href="http://web2py.com">web2py</a> plugin</h1>
<h2>for <a href="http://jquerymobile.com/">jQuery Mobile</a></h2>
+1
View File
@@ -0,0 +1 @@
@@ -18,6 +18,3 @@ def flash():
def fade():
return dict()
+68 -52
View File
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
try:
hosts = (http_host, socket.gethostname(),
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:
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"):
raise HTTP(200, T('appadmin is disabled because insecure channel'))
if (request.application=='admin' and not session.authorized) or \
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
if (request.application == 'admin' and not session.authorized) or \
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
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
response.view = 'appadmin.html'
@@ -95,24 +95,23 @@ def get_query(request):
return None
def query_by_table_type(tablename,db,request=request):
keyed = hasattr(db[tablename],'_primarykey')
def query_by_table_type(tablename, db, request=request):
keyed = hasattr(db[tablename], '_primarykey')
if keyed:
firstkey = db[tablename][db[tablename]._primarykey[0]]
cond = '>0'
if firstkey.type in ['string', 'text']:
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:
qry = '%s.%s.id>0' % tuple(request.args[:2])
return qry
# ##########################################################
# ## list all databases and tables
# ###########################################################
def index():
return dict(databases=databases)
@@ -127,7 +126,7 @@ def insert():
form = SQLFORM(db[table], ignore_rw=ignore_rw)
if form.accepts(request.vars, session):
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():
import os
db = get_database(request)
return response.download(request,db)
return response.download(request, db)
def csv():
import gluon.contenttype
@@ -149,26 +149,27 @@ def csv():
if not query:
return None
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
% tuple(request.vars.query.split('.')[:2])
return str(db(query,ignore_common_filters=True).select())
% tuple(request.vars.query.split('.')[:2])
return str(db(query, ignore_common_filters=True).select())
def import_csv(table, file):
table.import_from_csv_file(file)
def select():
import re
db = get_database(request)
dbname = request.args[0]
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>.+)')
if request.vars.query:
match = regex.match(request.vars.query)
if match:
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
match.group('table'), match.group('field'),
match.group('value'))
match.group('table'), match.group('field'),
match.group('value'))
else:
request.vars.query = session.last_query
query = get_query(request)
@@ -192,46 +193,50 @@ def select():
session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_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',
value=False), INPUT(_style='width:400px',
_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), ''),
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):
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
match = regex.match(form.vars.query.strip())
if match:
table = match.group('table')
try:
tb = None
nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)'
% form.vars.update_fields))
% form.vars.update_fields))
response.flash = T('%s %%{row} updated', nrows)
elif form.vars.delete_check:
db(query).delete()
response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count()
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:
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:
import traceback
tb = traceback.format_exc()
(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
csv_table = table or request.vars.table
if csv_table:
formcsv = FORM(str(T('or import from csv file'))+" ",
INPUT(_type='file',_name='csvfile'),
INPUT(_type='hidden',_value=csv_table,_name='table'),
INPUT(_type='submit',_value=T('import')))
formcsv = FORM(str(T('or import from csv file')) + " ",
INPUT(_type='file', _name='csvfile'),
INPUT(_type='hidden', _value=csv_table, _name='table'),
INPUT(_type='submit', _value=T('import')))
else:
formcsv = None
if formcsv and formcsv.process().accepted:
@@ -240,7 +245,7 @@ def select():
request.vars.csvfile.file)
response.flash = T('data uploaded')
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
return dict(
@@ -251,9 +256,9 @@ def select():
nrows=nrows,
rows=rows,
query=request.vars.query,
formcsv = formcsv,
tb = tb,
)
formcsv=formcsv,
tb=tb,
)
# ##########################################################
@@ -263,14 +268,16 @@ def select():
def update():
(db, table) = get_table(request)
keyed = hasattr(db[table],'_primarykey')
keyed = hasattr(db[table], '_primarykey')
record = None
if keyed:
key = [f for f in request.vars if f in db[table]._primarykey]
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:
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:
qry = query_by_table_type(table, db)
@@ -280,20 +287,21 @@ def update():
if keyed:
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'),
ignore_rw=ignore_rw and not keyed,
linkto=URL('select',
form = SQLFORM(
db[table], record, deletable=True, delete_label=T('Check to delete'),
ignore_rw=ignore_rw and not keyed,
linkto=URL('select',
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):
session.flash = T('done!')
qry = query_by_table_type(table, db)
redirect(URL('select', args=request.args[:1],
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():
return dict()
def ccache():
form = FORM(
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
P(TAG.BUTTON(
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
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):
@@ -332,11 +344,16 @@ def ccache():
redirect(URL(r=request))
try:
from guppy import hpy; hp=hpy()
from guppy import hpy
hp = hpy()
except ImportError:
hp = False
import shelve, os, copy, time, math
import shelve
import os
import copy
import time
import math
from gluon import portalocker
ram = {
@@ -381,9 +398,10 @@ def ccache():
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
locker = open(os.path.join(request.folder,
'cache/cache.lock'), 'a')
'cache/cache.lock'), 'a')
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:
for key, value in disk_storage.items():
if isinstance(value, dict):
@@ -414,7 +432,8 @@ def ccache():
total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys']
try:
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
except (KeyError, ZeroDivisionError):
total['ratio'] = 0
@@ -440,6 +459,3 @@ def ccache():
return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False)
@@ -1,25 +1,24 @@
import time
def cache_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)))
def cache_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)))
def cache_in_ram_and_disk():
"""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)
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()
d = dict(time=t, link=A('click to reload', _href=URL(r=request)))
return response.render(d)
+19 -4
View File
@@ -9,68 +9,83 @@ response.description = T('web2py Web Framework')
session.forget()
cache_expire = not request.is_local and 300 or 0
@cache('index', time_expire=cache_expire)
def index():
return response.render()
@cache('what', time_expire=cache_expire)
def what():
import urllib;
import urllib
try:
images = XML(urllib.urlopen('http://web2py.com/poweredby/default/images').read())
images = XML(urllib.urlopen(
'http://web2py.com/poweredby/default/images').read())
except:
images = []
return response.render(images=images)
@cache('download', time_expire=cache_expire)
def download():
return response.render()
@cache('who', time_expire=cache_expire)
def who():
return response.render()
@cache('support', time_expire=cache_expire)
def support():
return response.render()
@cache('documentation', time_expire=cache_expire)
def documentation():
return response.render()
@cache('usergroups', time_expire=cache_expire)
def usergroups():
return response.render()
def contact():
redirect(URL('default','usergroups'))
redirect(URL('default', 'usergroups'))
@cache('videos', time_expire=cache_expire)
def videos():
return response.render()
def security():
redirect('http://www.web2py.com/book/default/chapter/01#security')
def api():
redirect('http://web2py.com/book/default/chapter/04#API')
@cache('license', time_expire=cache_expire)
def license():
import os
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
return response.render(dict(license=MARKMIN(read_file(filename))))
def version():
return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version
@cache('examples', time_expire=cache_expire)
def examples():
return response.render()
@cache('changelog', time_expire=cache_expire)
def changelog():
import os
filename = os.path.join(request.env.gluon_parent, 'CHANGELOG')
return response.render(dict(changelog=MARKMIN(read_file(filename))))
@@ -1,6 +1,3 @@
def form():
""" a simple entry form with various types of objects """
@@ -15,7 +12,7 @@ def form():
TR('Profile', TEXTAREA(_name='profile',
value='write something here')),
TR('', INPUT(_type='submit', _value='SUBMIT')),
))
))
if form.process().accepted:
response.flash = 'form accepted'
elif form.errors:
@@ -23,6 +20,3 @@ def form():
else:
response.flash = 'please fill the form'
return dict(form=form, vars=form.vars)
+3 -7
View File
@@ -1,4 +1,3 @@
session.forget()
response.menu = [['home', False, '/%s/default/index'
@@ -17,14 +16,14 @@ def vars():
c,
d,
value,
) = (
) = (
'Global variables',
globals(),
None,
None,
(),
None,
)
)
(title, args) = ('globals()', '')
elif len(request.args) < 3:
args = '.'.join(request.args)
@@ -76,7 +75,4 @@ def vars():
d=d,
doc=doc,
attributes=attributes,
)
)
@@ -1,6 +1,6 @@
def civilized():
response.menu = [['civilized', True, URL('civilized'
)], ['slick', False, URL('slick')],
)], ['slick', False, URL('slick')],
['basic', False, URL('basic')]]
response.flash = 'you clicked on civilized'
return dict(message='you clicked on civilized')
@@ -8,7 +8,7 @@ def civilized():
def slick():
response.menu = [['civilized', False, URL('civilized'
)], ['slick', True, URL('slick')],
)], ['slick', True, URL('slick')],
['basic', False, URL('basic')]]
response.flash = 'you clicked on slick'
return dict(message='you clicked on slick')
@@ -16,10 +16,7 @@ def slick():
def basic():
response.menu = [['civilized', False, URL('civilized'
)], ['slick', False, URL('slick')],
)], ['slick', False, URL('slick')],
['basic', True, URL('basic')]]
response.flash = 'you clicked on basic'
return dict(message='you clicked on basic')
@@ -1,6 +1,3 @@
def counter():
""" every time you reload, it increases the session.counter """
@@ -8,6 +5,3 @@ def counter():
session.counter = 0
session.counter += 1
return dict(counter=session.counter)
@@ -102,9 +102,8 @@ def rss_aggregator():
return rss2.dumps(rss)
def ajaxwiki():
default="""
default = """
# section
## subsection
@@ -129,12 +128,12 @@ Quoted text
3 | 0 | 0
---------
"""
form = FORM(TEXTAREA(_id='text',_name='text',value=default),
form = FORM(TEXTAREA(_id='text', _name='text', value=default),
INPUT(_type='button',
_value='markmin',
_onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
return dict(form=form, html=DIV(_id='html'))
def ajaxwiki_onclick():
return MARKMIN(request.vars.text).xml()
@@ -1,10 +1,11 @@
from gluon.contrib.spreadsheet import Sheet
def callback():
return cache.ram('sheet1',lambda:None,None).process(request)
return cache.ram('sheet1', lambda: None, None).process(request)
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)
return dict(sheet=sheet)
@@ -1,6 +1,3 @@
def variables():
return dict(a=10, b=20)
@@ -31,6 +28,3 @@ def xml():
def beautify():
return dict(message=BEAUTIFY(request))
+21 -26
View File
@@ -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"""
url = "http://groups.google.com/group/%s/feed/rss_v2_0_topics.xml?num=%s" %\
(group,counter)
(group, counter)
from gluon.contrib import feedparser
g = feedparser.parse(url)
if mode == 'div':
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title']+' - ' +\
entry['author'][entry['author'].rfind('('):],\
_href=entry['link'],_target='_blank'))\
for entry in g['entries'] ]),\
_class="boxInfo",\
_style="padding-bottom:5px;"))
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title'] + ' - ' +
entry['author'][
entry['author'].rfind('('):],
_href=entry['link'], _target='_blank'))
for entry in g['entries']]),
_class="boxInfo",
_style="padding-bottom:5px;"))
else:
html = XML(UL(*[LI(A(entry['title']+' - ' +\
entry['author'][entry['author'].rfind('('):],\
_href=entry['link'],_target='_blank'))\
for entry in g['entries'] ]))
html = XML(UL(*[LI(A(entry['title'] + ' - ' +
entry['author'][entry['author'].rfind('('):],
_href=entry['link'], _target='_blank'))
for entry in g['entries']]))
return html
def code_feed_reader(project,mode='div'):
def code_feed_reader(project, mode='div'):
"""parse code feeds"""
url = "http://code.google.com/feeds/p/%s/hgchanges/basic" % project
from gluon.contrib import feedparser
g = feedparser.parse(url)
if mode == 'div':
html = XML(DIV(UL(*[LI(A(entry['title'],_href=entry['link'],\
_target='_blank'))\
for entry in g['entries'][0:5]]),\
_class="boxInfo",\
html = XML(DIV(UL(*[LI(A(entry['title'], _href=entry['link'],
_target='_blank'))
for entry in g['entries'][0:5]]),
_class="boxInfo",
_style="padding-bottom:5px;"))
else:
html = XML(UL(*[LI(A(entry['title'],_href=entry['link'],\
_target='_blank'))\
for entry in g['entries'][0:5]]))
html = XML(UL(*[LI(A(entry['title'], _href=entry['link'],
_target='_blank'))
for entry in g['entries'][0:5]]))
return html
+16 -15
View File
@@ -2,18 +2,19 @@ import gluon.template
markmin_dict = dict(
code_python=lambda code: str(CODE(code)),
template=lambda \
code:gluon.template.render(code,context=globals()),
sup=lambda \
code:'<sup style="font-size:0.5em;">%s</sup>'%code,
br=lambda n:'<br>'*int(n),
groupdates=lambda group:group_feed_reader(group),
)
template=lambda
code: gluon.template.render(code, context=globals()),
sup=lambda
code: '<sup style="font-size:0.5em;">%s</sup>' % code,
br=lambda n: '<br>' * int(n),
groupdates=lambda group: group_feed_reader(group),
)
def get_content(b=None,\
c=request.controller,\
f=request.function,\
l='en',\
def get_content(b=None,
c=request.controller,
f=request.function,
l='en',
format='markmin'):
"""Gets and renders the file in
<app>/private/content/<lang>/<controller>/<function>/<block>.<format>
@@ -21,20 +22,20 @@ def get_content(b=None,\
def openfile():
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)
try:
openedfile = openfile()
except Exception, IOError:
l='en'
l = 'en'
openedfile = openfile()
if format == 'markmin':
html = MARKMIN(str(T(openedfile.read())),markmin_dict)
html = MARKMIN(str(T(openedfile.read())), markmin_dict)
else:
html = str(T(openedfile.read()))
openedfile.close()
return html
+20 -20
View File
@@ -1,28 +1,29 @@
# -*- coding: utf-8 -*-
response.menu = [
(T('Home'),False,URL('default','index')),
(T('About'),False,URL('default','what')),
(T('Download'),False,URL('default','download')),
(T('Docs & Resources'),False,URL('default','documentation')),
(T('Support'),False,URL('default','support')),
(T('Contributors'),False,URL('default','who'))]
(T('Home'), False, URL('default', 'index')),
(T('About'), False, URL('default', 'what')),
(T('Download'), False, URL('default', 'download')),
(T('Docs & Resources'), False, URL('default', 'documentation')),
(T('Support'), False, URL('default', 'support')),
(T('Contributors'), False, URL('default', 'who'))]
#########################################################################
## 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"""
positions = dict(
index='',
what='-108px -115px',
download='-211px -115px',
who='-315px -115px',
support='-418px -115px',
documentation='-520px -115px'
)
index='',
what='-108px -115px',
download='-211px -115px',
who='-315px -115px',
support='-418px -115px',
documentation='-520px -115px'
)
if request.function in positions.keys():
jscript = """
@@ -34,12 +35,11 @@ def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
});
</script>
""" % dict(cssclass=cssclass,
menuid=menuid,
function=request.function,
cssposition=positions[request.function]
)
menuid=menuid,
function=request.function,
cssposition=positions[request.function]
)
return XML(jscript)
else:
return ''
@@ -29,6 +29,7 @@
</li><li>Alvaro Justen (dynamical translations)
</li><li>Anders Roos (file locking)
</li><li>Andrew Willimott (documentation, TeraData support)
</li><li>Andriy Kornatskyy (benchmarks and profiling)
</li><li>Angelo Compagnucci (mobile devices)
</li><li>Anthony Bastardi (book, poweredby site, multiple contributions)
</li><li>Arun K. Rajeevan (plugin_wiki)
+1
View File
@@ -0,0 +1 @@
+68 -52
View File
@@ -23,7 +23,7 @@ remote_addr = request.env.remote_addr
try:
hosts = (http_host, socket.gethostname(),
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:
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"):
raise HTTP(200, T('appadmin is disabled because insecure channel'))
if (request.application=='admin' and not session.authorized) or \
(request.application!='admin' and not gluon.fileutils.check_credentials(request)):
if (request.application == 'admin' and not session.authorized) or \
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
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
response.view = 'appadmin.html'
@@ -95,24 +95,23 @@ def get_query(request):
return None
def query_by_table_type(tablename,db,request=request):
keyed = hasattr(db[tablename],'_primarykey')
def query_by_table_type(tablename, db, request=request):
keyed = hasattr(db[tablename], '_primarykey')
if keyed:
firstkey = db[tablename][db[tablename]._primarykey[0]]
cond = '>0'
if firstkey.type in ['string', 'text']:
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:
qry = '%s.%s.id>0' % tuple(request.args[:2])
return qry
# ##########################################################
# ## list all databases and tables
# ###########################################################
def index():
return dict(databases=databases)
@@ -127,7 +126,7 @@ def insert():
form = SQLFORM(db[table], ignore_rw=ignore_rw)
if form.accepts(request.vars, session):
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():
import os
db = get_database(request)
return response.download(request,db)
return response.download(request, db)
def csv():
import gluon.contenttype
@@ -149,26 +149,27 @@ def csv():
if not query:
return None
response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\
% tuple(request.vars.query.split('.')[:2])
return str(db(query,ignore_common_filters=True).select())
% tuple(request.vars.query.split('.')[:2])
return str(db(query, ignore_common_filters=True).select())
def import_csv(table, file):
table.import_from_csv_file(file)
def select():
import re
db = get_database(request)
dbname = request.args[0]
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>.+)')
if request.vars.query:
match = regex.match(request.vars.query)
if match:
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
match.group('table'), match.group('field'),
match.group('value'))
match.group('table'), match.group('field'),
match.group('value'))
else:
request.vars.query = session.last_query
query = get_query(request)
@@ -192,46 +193,50 @@ def select():
session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_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',
value=False), INPUT(_style='width:400px',
_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), ''),
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):
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
match = regex.match(form.vars.query.strip())
if match:
table = match.group('table')
try:
tb = None
nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)'
% form.vars.update_fields))
% form.vars.update_fields))
response.flash = T('%s %%{row} updated', nrows)
elif form.vars.delete_check:
db(query).delete()
response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count()
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:
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:
import traceback
tb = traceback.format_exc()
(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
csv_table = table or request.vars.table
if csv_table:
formcsv = FORM(str(T('or import from csv file'))+" ",
INPUT(_type='file',_name='csvfile'),
INPUT(_type='hidden',_value=csv_table,_name='table'),
INPUT(_type='submit',_value=T('import')))
formcsv = FORM(str(T('or import from csv file')) + " ",
INPUT(_type='file', _name='csvfile'),
INPUT(_type='hidden', _value=csv_table, _name='table'),
INPUT(_type='submit', _value=T('import')))
else:
formcsv = None
if formcsv and formcsv.process().accepted:
@@ -240,7 +245,7 @@ def select():
request.vars.csvfile.file)
response.flash = T('data uploaded')
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
return dict(
@@ -251,9 +256,9 @@ def select():
nrows=nrows,
rows=rows,
query=request.vars.query,
formcsv = formcsv,
tb = tb,
)
formcsv=formcsv,
tb=tb,
)
# ##########################################################
@@ -263,14 +268,16 @@ def select():
def update():
(db, table) = get_table(request)
keyed = hasattr(db[table],'_primarykey')
keyed = hasattr(db[table], '_primarykey')
record = None
if keyed:
key = [f for f in request.vars if f in db[table]._primarykey]
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:
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:
qry = query_by_table_type(table, db)
@@ -280,20 +287,21 @@ def update():
if keyed:
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'),
ignore_rw=ignore_rw and not keyed,
linkto=URL('select',
form = SQLFORM(
db[table], record, deletable=True, delete_label=T('Check to delete'),
ignore_rw=ignore_rw and not keyed,
linkto=URL('select',
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):
session.flash = T('done!')
qry = query_by_table_type(table, db)
redirect(URL('select', args=request.args[:1],
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():
return dict()
def ccache():
form = FORM(
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
P(TAG.BUTTON(
T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
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):
@@ -332,11 +344,16 @@ def ccache():
redirect(URL(r=request))
try:
from guppy import hpy; hp=hpy()
from guppy import hpy
hp = hpy()
except ImportError:
hp = False
import shelve, os, copy, time, math
import shelve
import os
import copy
import time
import math
from gluon import portalocker
ram = {
@@ -381,9 +398,10 @@ def ccache():
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
locker = open(os.path.join(request.folder,
'cache/cache.lock'), 'a')
'cache/cache.lock'), 'a')
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:
for key, value in disk_storage.items():
if isinstance(value, dict):
@@ -414,7 +432,8 @@ def ccache():
total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys']
try:
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses'])
total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
except (KeyError, ZeroDivisionError):
total['ratio'] = 0
@@ -440,6 +459,3 @@ def ccache():
return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False)
+3 -1
View File
@@ -9,6 +9,7 @@
## - call exposes all registered services (none by default)
#########################################################################
def index():
"""
example action using the internationalization operator T and flash
@@ -20,6 +21,7 @@ def index():
response.flash = T("Welcome to web2py!")
return dict(message=T('Hello World'))
def user():
"""
exposes:
@@ -42,7 +44,7 @@ def download():
allows downloading of uploaded files
http://..../[app]/default/download/[filename]
"""
return response.download(request,db)
return response.download(request, db)
def call():
+1
View File
@@ -89,6 +89,7 @@
'export as csv file': 'експортувати як файл csv',
'FAQ': 'ЧаПи (FAQ)',
'First name': "Ім'я",
'Forgot username?': "Забули ім'я користувача?",
'Forms and Validators': 'Форми та коректність даних',
'Free Applications': 'Вільні додатки',
'Group %(group_id)s created': 'Групу %(group_id)s створено',
+4 -4
View File
@@ -11,12 +11,12 @@
if not request.env.web2py_runtime_gae:
## if NOT running on Google App Engine use SQLite or other DB
db = DAL('sqlite://storage.sqlite')
db = DAL('sqlite://storage.sqlite')
else:
## connect to Google BigTable (optional 'google:datastore://namespace')
db = DAL('google:datastore')
## store sessions and tickets there
session.connect(request, response, db = db)
session.connect(request, response, db=db)
## or store session in Memcache, Redis, etc.
## from gluon.contrib.memdb import MEMDB
## 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)
## configure email
mail=auth.settings.mailer
mail = auth.settings.mailer
mail.settings.server = 'logging' or 'smtp.gmail.com:587'
mail.settings.sender = 'you@gmail.com'
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.
## register with janrain.com, write your domain:api_key in private/janrain.key
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
+99 -64
View File
@@ -5,7 +5,8 @@
## 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!')
## read more at http://dev.w3.org/html5/markup/meta.name.html
@@ -22,80 +23,114 @@ response.google_analytics_id = None
#########################################################################
response.menu = [
(T('Home'), False, URL('default','index'), [])
]
(T('Home'), False, URL('default', 'index'), [])
]
#########################################################################
## provide shortcuts for development. remove in production
#########################################################################
def _():
# shortcuts
app = request.application
ctr = request.controller
# useful links to internal and external resources
response.menu+=[
(SPAN('web2py',_class='highlighted'),False, 'http://web2py.com', [
(T('My Sites'),False,URL('admin','default','site')),
(T('This App'),False,URL('admin','default','design/%s' % app), [
(T('Controller'),False,
URL('admin','default','edit/%s/controllers/%s.py' % (app,ctr))),
(T('View'),False,
URL('admin','default','edit/%s/views/%s' % (app,response.view))),
(T('Layout'),False,
URL('admin','default','edit/%s/views/layout.html' % app)),
(T('Stylesheet'),False,
URL('admin','default','edit/%s/static/css/web2py.css' % app)),
(T('DB Model'),False,
URL('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)),
# useful links to internal and external resources
response.menu += [
(SPAN('web2py', _class='highlighted'), False, 'http://web2py.com', [
(T('My Sites'), False, URL('admin', 'default', 'site')),
(T('This App'), False, URL('admin', 'default', 'design/%s' % app), [
(T('Controller'), False,
URL(
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
(T('View'), False,
URL(
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
(T('Layout'), False,
URL(
'admin', 'default', 'edit/%s/views/layout.html' % app)),
(T('Stylesheet'), False,
URL(
'admin', 'default', 'edit/%s/static/css/web2py.css' % app)),
(T('DB Model'), False,
URL(
'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('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'),
]),
(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'),
(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'),
])
]
)]
_()
-1
View File
@@ -37,4 +37,3 @@ routers = {
#NOTE! To change language in your application using these rules add this line
#in one of your models files:
# if request.uri_language: T.force(request.uri_language)
+1 -6
View File
@@ -56,13 +56,8 @@ import wsgiref.handlers
path = os.path.dirname(os.path.abspath(__file__))
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
wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase)
+1 -6
View File
@@ -34,7 +34,7 @@ import os
path = os.path.dirname(os.path.abspath(__file__))
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.contrib.gateways.fcgi as fcgi
@@ -51,8 +51,3 @@ if SOFTCRON:
global_settings.web2py_crontype = 'soft'
fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run()
+9 -7
View File
@@ -33,7 +33,7 @@ import wsgiref.handlers
import datetime
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']
@@ -78,12 +78,18 @@ def wsgiapp(env, res):
"""Return the wsgiapp"""
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
# the path between requests
if global_settings.web2py_runtime == 'gae:development':
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)
@@ -91,14 +97,10 @@ def wsgiapp(env, res):
if LOG_STATS or DEBUG:
wsgiapp = log_stats(wsgiapp)
def main():
"""Run the wsgi app"""
run_wsgi_app(wsgiapp)
if __name__ == '__main__':
main()
+1 -12
View File
@@ -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 html import *
@@ -42,14 +42,3 @@ if 0:
mail = Mail()
service = Service()
plugins = PluginManager()
+31 -25
View File
@@ -23,6 +23,7 @@ from http import HTTP
if not global_settings.web2py_runtime_gae:
import site
def apath(path='', r=None):
"""
Builds a path inside an application folder
@@ -95,6 +96,7 @@ def app_pack_compiled(app, request, raise_ex=False):
raise
return None
def app_cleanup(app, request):
"""
Removes session, cache and error files
@@ -113,7 +115,7 @@ def app_cleanup(app, request):
if os.path.exists(path):
for f in os.listdir(path):
try:
if f[:1]!='.': os.unlink(os.path.join(path,f))
if f[:1] != '.': os.unlink(os.path.join(path, f))
except IOError:
r = False
@@ -122,7 +124,7 @@ def app_cleanup(app, request):
if os.path.exists(path):
for f in os.listdir(path):
try:
if f[:1]!='.': recursive_unlink(os.path.join(path,f))
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
except IOError:
r = False
@@ -131,7 +133,7 @@ def app_cleanup(app, request):
if os.path.exists(path):
for f in os.listdir(path):
try:
if f[:1]!='.': os.unlink(os.path.join(path,f))
if f[:1] != '.': os.unlink(os.path.join(path, f))
except IOError:
r = False
return r
@@ -158,7 +160,8 @@ def app_compile(app, request):
remove_compiled_application(folder)
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
@@ -186,17 +189,17 @@ def app_create(app, request,force=False,key=None,info=False):
return False
try:
w2p_unpack('welcome.w2p', path)
for subfolder in ['models','views','controllers', 'databases',
'modules','cron','errors','sessions',
'languages','static','private','uploads']:
subpath = os.path.join(path,subfolder)
for subfolder in ['models', 'views', 'controllers', 'databases',
'modules', 'cron', 'errors', 'sessions',
'languages', 'static', 'private', 'uploads']:
subpath = os.path.join(path, subfolder)
if not os.path.exists(subpath):
os.mkdir(subpath)
db = os.path.join(path, 'models', 'db.py')
if os.path.exists(db):
data = read_file(db)
data = data.replace('<your secret key>',
'sha512:'+(key or web2py_uuid()))
'sha512:' + (key or web2py_uuid()))
write_file(db, data)
if info:
return True, None
@@ -283,6 +286,7 @@ def app_uninstall(app, request):
except Exception:
return False
def plugin_pack(app, plugin_name, request):
"""
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
"""
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)
return filename
except Exception:
return False
def plugin_install(app, fobj, request, filename):
"""
Installs an application:
@@ -345,6 +351,7 @@ def plugin_install(app, fobj, request, filename):
os.unlink(upname)
return False
def check_new_version(myversion, version_URL):
"""
Compares current web2py's version with the latest stable web2py version.
@@ -375,6 +382,7 @@ def check_new_version(myversion, version_URL):
else:
return False, version
def unzip(filename, dir, subfolder=''):
"""
Unzips filename into dir (.zip only, no .gz etc)
@@ -382,7 +390,7 @@ def unzip(filename, dir, subfolder=''):
"""
filename = abspath(filename)
if not zipfile.is_zipfile(filename):
raise RuntimeError, 'Not a valid zipfile'
raise RuntimeError('Not a valid zipfile')
zf = zipfile.ZipFile(filename)
if not subfolder.endswith('/'):
subfolder = subfolder + '/'
@@ -392,7 +400,7 @@ def unzip(filename, dir, subfolder=''):
continue
#print name[n:]
if name.endswith('/'):
folder = os.path.join(dir,name[n:])
folder = os.path.join(dir, name[n:])
if not os.path.exists(folder):
os.mkdir(folder)
else:
@@ -421,7 +429,7 @@ def upgrade(request, url='http://web2py.com'):
if not gluon_parent.endswith('/'):
gluon_parent = gluon_parent + '/'
(check, version) = check_new_version(web2py_version,
url+'/examples/default/version')
url + '/examples/default/version')
if not check:
return (False, 'Already latest version')
if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
@@ -442,42 +450,40 @@ def upgrade(request, url='http://web2py.com'):
file = None
try:
write_file(filename, urllib.urlopen(full_url).read(), 'wb')
except Exception,e:
except Exception, e:
return False, e
try:
unzip(filename, destination, subfolder)
return True, None
except Exception,e:
except Exception, e:
return False, e
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:
site.addsitedir(path)
def create_missing_folders():
if not global_settings.web2py_runtime_gae:
for path in ('applications', 'deposit', 'site-packages', 'logs'):
path = abspath(path, gluon=True)
if not os.path.exists(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]
def create_missing_app_folders(request):
if not global_settings.web2py_runtime_gae:
if request.folder not in global_settings.app_folders:
for subfolder in ('models', 'views', 'controllers', 'databases',
'modules', 'cron', 'errors', 'sessions',
'languages', 'static', 'private', 'uploads'):
path = os.path.join(request.folder, subfolder)
path = os.path.join(request.folder, subfolder)
if not os.path.exists(path):
os.mkdir(path)
global_settings.app_folders.add(request.folder)
+50 -41
View File
@@ -40,19 +40,20 @@ __all__ = ['Cache', 'lazy_cache']
DEFAULT_TIME_EXPIRE = 300
class CacheAbstract(object):
"""
Abstract class for cache implementations.
Main function is now to provide referenced api documentation.
Use CacheInRam or CacheOnDisk instead which are derived from this class.
Attentions, Michele says:
There are signatures inside gdbm files that are used directly
by the python gdbm adapter that often are lagging behind in the
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.
Using gdbm directly from C would work, because there is backward
compatibility, but not from python!
@@ -73,7 +74,7 @@ class CacheAbstract(object):
raise NotImplementedError
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
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)):
del storage[key]
class CacheInRam(CacheAbstract):
"""
Ram based caching
@@ -147,8 +149,10 @@ class CacheInRam(CacheAbstract):
self.request = request
def initialize(self):
if self.initialized: return
else: self.initialized = True
if self.initialized:
return
else:
self.initialized = True
self.locker.acquire()
request = self.request
if request:
@@ -172,13 +176,14 @@ class CacheInRam(CacheAbstract):
self._clear(storage, regex)
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()
def __call__(self, key, f,
time_expire = DEFAULT_TIME_EXPIRE,
destroyer = None):
time_expire=DEFAULT_TIME_EXPIRE,
destroyer=None):
"""
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:
@@ -258,7 +263,7 @@ class CacheOnDisk(CacheAbstract):
on self.locker first. Replaces the close method of the
returned shelf instance with one that releases the lock upon
closing."""
storage = None
locker = None
locked = False
@@ -269,14 +274,15 @@ class CacheOnDisk(CacheAbstract):
try:
storage = shelve.open(self.shelve_name)
except:
logger.error('corrupted cache file %s, will try rebuild it' \
% (self.shelve_name))
logger.error('corrupted cache file %s, will try rebuild it'
% (self.shelve_name))
storage = None
if not storage and os.path.exists(self.shelve_name):
os.unlink(self.shelve_name)
storage = shelve.open(self.shelve_name)
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()
except Exception, e:
if storage:
@@ -286,7 +292,8 @@ class CacheOnDisk(CacheAbstract):
portalocker.unlock(locker)
locker.close()
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.locked = locked
self.storage = storage
@@ -296,10 +303,12 @@ class CacheOnDisk(CacheAbstract):
self.initialized = False
self.request = request
self.folder = folder
def initialize(self):
if self.initialized: return
else: self.initialized = True
if self.initialized:
return
else:
self.initialized = True
folder = self.folder
request = self.request
@@ -312,8 +321,8 @@ class CacheOnDisk(CacheAbstract):
### we need this because of a possible bug in shelve that may
### or may not lock
self.locker_name = os.path.join(folder,'cache.lock')
self.shelve_name = os.path.join(folder,'cache.shelve')
self.locker_name = os.path.join(folder, 'cache.lock')
self.shelve_name = os.path.join(folder, 'cache.shelve')
def clear(self, regex=None):
self.initialize()
@@ -328,7 +337,7 @@ class CacheOnDisk(CacheAbstract):
self._close_shelve_and_unlock()
def __call__(self, key, f,
time_expire = DEFAULT_TIME_EXPIRE):
time_expire=DEFAULT_TIME_EXPIRE):
self.initialize()
dt = time_expire
storage = self._open_shelve_and_lock()
@@ -346,7 +355,7 @@ class CacheOnDisk(CacheAbstract):
else:
value = f()
storage[key] = (now, value)
storage[CacheAbstract.cache_stats_name]['misses']+=1
storage[CacheAbstract.cache_stats_name]['misses'] += 1
storage.sync()
finally:
self._close_shelve_and_unlock()
@@ -365,8 +374,9 @@ class CacheOnDisk(CacheAbstract):
self._close_shelve_and_unlock()
return value
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.__doc__ = func.__doc__
self.func = func
@@ -374,17 +384,18 @@ class CacheAction(object):
self.time_expire = time_expire
self.cache = cache
self.cache_model = cache_model
def __call__(self,*a,**b):
def __call__(self, *a, **b):
if not self.key:
key2 = self.__name__+':'+repr(a)+':'+repr(b)
key2 = self.__name__ + ':' + repr(a) + ':' + repr(b)
else:
key2 = self.key.replace('%(name)s',self.__name__)\
.replace('%(args)s',str(a)).replace('%(vars)s',str(b))
key2 = self.key.replace('%(name)s', self.__name__)\
.replace('%(args)s', str(a)).replace('%(vars)s', str(b))
cache_model = self.cache_model
if not cache_model or isinstance(cache_model,str):
cache_model = getattr(self.cache,cache_model or 'ram')
if not cache_model or isinstance(cache_model, str):
cache_model = getattr(self.cache, cache_model or 'ram')
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)
@@ -424,9 +435,9 @@ class Cache(object):
logger.warning('no cache.disk (AttributeError)')
def __call__(self,
key = None,
time_expire = DEFAULT_TIME_EXPIRE,
cache_model = None):
key=None,
time_expire=DEFAULT_TIME_EXPIRE,
cache_model=None):
"""
Decorator function that can be used to cache any function/method.
@@ -459,8 +470,8 @@ class Cache(object):
`request.env.path_info` as key.
"""
def tmp(func,cache=self,cache_model=cache_model):
return CacheAction(func,key,time_expire,self,cache_model)
def tmp(func, cache=self, cache_model=cache_model):
return CacheAction(func, key, time_expire, self, cache_model)
return tmp
@staticmethod
@@ -468,12 +479,12 @@ class Cache(object):
"""
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
it will add prefix to all the cache keys used.
"""
"""
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix:\
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,
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)
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)
def g(*c,**d):
def g(*c, **d):
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__
return g
return decorator
-7
View File
@@ -51,10 +51,3 @@ def getcfs(key, filename, filter=None):
cfs[key] = (t, data)
cfs_lock.release()
return data
+84 -74
View File
@@ -48,7 +48,7 @@ except:
logger.warning('unable to import py_compile')
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
pjoin = os.path.join
@@ -95,6 +95,7 @@ _TEST()
CACHED_REGEXES = {}
CACHED_REGEXES_MAX_SIZE = 1000
def re_compile(regex):
try:
return CACHED_REGEXES[regex]
@@ -104,6 +105,7 @@ def re_compile(regex):
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
return compiled_regex
class mybuiltin(object):
"""
NOTE could simple use a dict and populate it,
@@ -114,14 +116,16 @@ class mybuiltin(object):
try:
return getattr(__builtin__, key)
except AttributeError:
raise KeyError, key
raise KeyError(key)
def __setitem__(self, key, value):
setattr(self, key, value)
def LOAD(c=None, f='index', args=None, vars=None,
extension=None, target=None,ajax=False,ajax_trap=False,
url=None,user_signature=False, timeout=None, times=1,
content='loading...',**attr):
extension=None, target=None, ajax=False, ajax_trap=False,
url=None, user_signature=False, timeout=None, times=1,
content='loading...', **attr):
""" LOAD a component into the action's document
Timing options:
@@ -134,13 +138,14 @@ def LOAD(c=None, f='index', args=None, vars=None,
is added on page loading without delay.
"""
from html import TAG, DIV, URL, SCRIPT, XML
if args is None: args = []
if args is None:
args = []
vars = Storage(vars or {})
target = target or 'c'+str(random.random())[2:]
attr['_id']=target
target = target or 'c' + str(random.random())[2:]
attr['_id'] = target
request = current.request
if '.' in f:
f, extension = f.rsplit('.',1)
f, extension = f.rsplit('.', 1)
if url or ajax:
url = url or URL(request.application, c, f, r=request,
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)):
raise ValueError("Timeout argument must be an integer or None")
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);" \
% (url, target, timeout, times)
% (url, target, timeout, times)
else:
statement = "web2py_component('%s','%s');" % (url, target)
script = SCRIPT(statement, _type="text/javascript")
if not content is None:
return TAG[''](script, DIV(content,**attr))
return TAG[''](script, DIV(content, **attr))
else:
return TAG[''](script)
else:
if not isinstance(args,(list,tuple)):
if not isinstance(args, (list, tuple)):
args = [args]
c = c or request.controller
other_request = Storage(request)
@@ -186,17 +192,17 @@ def LOAD(c=None, f='index', args=None, vars=None,
other_request.post_vars = Storage()
other_response = Response()
other_request.env.path_info = '/' + \
'/'.join([request.application,c,f] + \
map(str, other_request.args))
'/'.join([request.application, c, f] +
map(str, other_request.args))
other_request.env.query_string = \
vars and URL(vars=vars).split('?')[1] or ''
other_request.env.http_web2py_component_location = \
request.env.path_info
other_request.cid = 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.generic_patterns = \
@@ -218,40 +224,41 @@ def LOAD(c=None, f='index', args=None, vars=None,
js = None
if ajax_trap:
link = URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension,
user_signature=user_signature)
args=args, vars=vars, extension=extension,
user_signature=user_signature)
js = "web2py_trap_form('%s','%s');" % (link, target)
script = js and SCRIPT(js,_type="text/javascript") or ''
return TAG[''](DIV(XML(page),**attr),script)
script = js and SCRIPT(js, _type="text/javascript") or ''
return TAG[''](DIV(XML(page), **attr), script)
class LoadFactory(object):
"""
Attention: this helper is new and experimental
"""
def __init__(self,environment):
def __init__(self, environment):
self.environment = environment
def __call__(self, c=None, f='index', args=None, vars=None,
extension=None, target=None,ajax=False,ajax_trap=False,
url=None,user_signature=False, content='loading...',**attr):
if args is None: args = []
extension=None, target=None, ajax=False, ajax_trap=False,
url=None, user_signature=False, content='loading...', **attr):
if args is None:
args = []
vars = Storage(vars or {})
import globals
target = target or 'c'+str(random.random())[2:]
attr['_id']=target
target = target or 'c' + str(random.random())[2:]
attr['_id'] = target
request = self.environment['request']
if '.' in f:
f, extension = f.rsplit('.',1)
f, extension = f.rsplit('.', 1)
if url or ajax:
url = url or html.URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension,
user_signature=user_signature)
script = html.SCRIPT('web2py_component("%s","%s")' % (url, target),
_type="text/javascript")
return html.TAG[''](script, html.DIV(content,**attr))
return html.TAG[''](script, html.DIV(content, **attr))
else:
if not isinstance(args,(list,tuple)):
if not isinstance(args, (list, tuple)):
args = [args]
c = c or request.controller
@@ -266,15 +273,15 @@ class LoadFactory(object):
other_request.post_vars = Storage()
other_response = globals.Response()
other_request.env.path_info = '/' + \
'/'.join([request.application,c,f] + \
map(str, other_request.args))
'/'.join([request.application, c, f] +
map(str, other_request.args))
other_request.env.query_string = \
vars and html.URL(vars=vars).split('?')[1] or ''
other_request.env.http_web2py_component_location = \
request.env.path_info
other_request.cid = 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_response._view_environment = other_environment
other_response.generic_patterns = \
@@ -299,8 +306,8 @@ class LoadFactory(object):
args=args, vars=vars, extension=extension,
user_signature=user_signature)
js = "web2py_trap_form('%s','%s');" % (link, target)
script = js and html.SCRIPT(js,_type="text/javascript") or ''
return html.TAG[''](html.DIV(html.XML(page),**attr),script)
script = js and html.SCRIPT(js, _type="text/javascript") or ''
return html.TAG[''](html.DIV(html.XML(page), **attr), script)
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.
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)
module = __import__(name)
for item in name.split(".")[1:]:
@@ -355,12 +362,14 @@ OLD IMPLEMENTATION:
file.close()
imp.release_lock()
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
"""
_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_ = dict((k, getattr(html, k)) for k in html.__all__)
_base_environment_.update(
(k, getattr(validators, k)) for k in validators.__all__)
_base_environment_['__builtins__'] = __builtins__
_base_environment_['HTTP'] = HTTP
_base_environment_['redirect'] = redirect
@@ -371,7 +380,8 @@ _base_environment_['SQLField'] = SQLField # for backward compatibility
_base_environment_['SQLFORM'] = SQLFORM
_base_environment_['SQLTABLE'] = SQLTABLE
_base_environment_['LOAD'] = LOAD
def build_environment(request, response, session, store_current=True):
"""
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
# /[controller]/[function]/*.py)
response.models_to_run = [r'^\w+\.py$', r'^%s/\w+\.py$' % request.controller,
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
t = environment['T'] = translator(request)
c = environment['cache'] = Cache(request)
@@ -398,23 +408,24 @@ def build_environment(request, response, session, store_current=True):
current.cache = c
global __builtins__
if is_jython: # jython hack
if is_jython: # jython hack
__builtins__ = mybuiltin()
elif is_pypy: # apply the same hack to pypy too
elif is_pypy: # apply the same hack to pypy too
__builtins__ = mybuiltin()
else:
__builtins__['__import__'] = __builtin__.__import__ ### WHY?
__builtins__['__import__'] = __builtin__.__import__ # WHY?
environment['request'] = request
environment['response'] = response
environment['session'] = session
environment['local_import'] = \
lambda name, reload=False, app=request.application:\
local_import_aux(name,reload,app)
lambda name, reload=False, app=request.application:\
local_import_aux(name, reload, app)
BaseAdapter.set_folder(pjoin(request.folder, 'databases'))
response._view_environment = copy.copy(environment)
custom_import_install()
return environment
def save_pyc(filename):
"""
Bytecode compiles the file `filename`
@@ -431,7 +442,7 @@ def read_pyc(filename):
"""
data = read_file(filename, 'rb')
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:])
@@ -442,7 +453,10 @@ def compile_views(folder):
path = pjoin(folder, 'views')
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 = pjoin(folder, 'compiled', filename)
write_file(filename, data)
@@ -458,7 +472,7 @@ def compile_models(folder):
path = pjoin(folder, 'models')
for file in listdir(path, '.+\.py$'):
data = read_file(pjoin(path, file))
filename = pjoin(folder, 'compiled','models',file)
filename = pjoin(folder, 'compiled', 'models', file)
mktree(filename)
write_file(filename, data)
save_pyc(filename)
@@ -473,14 +487,14 @@ def compile_controllers(folder):
path = pjoin(folder, 'controllers')
for file in listdir(path, '.+\.py$'):
### 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)
for function in exposed:
command = data + "\nresponse._vars=response._caller(%s)\n" % \
function
filename = pjoin(folder, 'compiled', ('controllers/'
+ file[:-3]).replace('/', '_')
+ '_' + function + '.py')
+ '_' + function + '.py')
write_file(filename, command)
save_pyc(filename)
os.unlink(filename)
@@ -500,19 +514,19 @@ def run_models_in(environment):
for model in listdir(cpath, '^models_\w+\.pyc$', 0):
restricted(read_pyc(model), environment, layer=model)
path = pjoin(cpath, 'models')
models = listdir(path, '^\w+\.pyc$',0,sort=False)
compiled=True
models = listdir(path, '^\w+\.pyc$', 0, sort=False)
compiled = True
else:
path = pjoin(folder, 'models')
models = listdir(path, '^\w+\.py$',0,sort=False)
compiled=False
models = listdir(path, '^\w+\.py$', 0, sort=False)
compiled = False
n = len(path) + 1
for model in models:
regex = environment['response'].models_to_run
if isinstance(regex, list):
regex = re_compile('|'.join(regex))
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py')
if not regex.search(file) and c!= 'appadmin':
if not regex.search(file) and c != 'appadmin':
continue
elif compiled:
code = read_pyc(model)
@@ -538,7 +552,7 @@ def run_controller_in(controller, function, environment):
badf = 'invalid function (%s/%s)' % (controller, function)
if os.path.exists(path):
filename = pjoin(path, 'controllers_%s_%s.pyc'
% (controller, function))
% (controller, function))
if not os.path.exists(filename):
raise HTTP(404,
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
from settings import global_settings
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]
# TESTING END
@@ -578,18 +593,19 @@ def run_controller_in(controller, function, environment):
code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function)
if is_gae:
layer = filename + ':' + function
code = getcfs(layer, filename, lambda: compile2(code,layer))
code = getcfs(layer, filename, lambda: compile2(code, layer))
restricted(code, environment, filename)
response = environment['response']
vars=response._vars
vars = response._vars
if response.postprocessing:
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
if isinstance(vars,unicode):
if isinstance(vars, unicode):
vars = vars.encode('utf8')
elif hasattr(vars,'xml') and callable(vars.xml):
elif hasattr(vars, 'xml') and callable(vars.xml):
vars = vars.xml()
return vars
def run_view_in(environment):
"""
Executes the view for the requested action.
@@ -606,7 +622,7 @@ def run_view_in(environment):
if response.generic_patterns:
patterns = response.generic_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)
else:
allow_generic = False
@@ -626,7 +642,7 @@ def run_view_in(environment):
files.append('views_generic.pyc')
# end backward compatibility code
for f in files:
filename = pjoin(path,f)
filename = pjoin(path, f)
if os.path.exists(filename):
code = read_pyc(filename)
restricted(code, environment, layer=filename)
@@ -648,13 +664,14 @@ def run_view_in(environment):
ccode = getcfs(layer, filename,
lambda: compile2(parse_template(view,
pjoin(folder, 'views'),
context=environment),layer))
context=environment), layer))
else:
ccode = parse_template(view,
pjoin(folder, 'views'),
context=environment)
restricted(ccode, environment, layer)
def remove_compiled_application(folder):
"""
Deletes the folder `compiled` containing the compiled application.
@@ -662,7 +679,7 @@ def remove_compiled_application(folder):
try:
shutil.rmtree(pjoin(folder, 'compiled'))
path = pjoin(folder, 'controllers')
for file in listdir(path,'.*\.pyc$',drop=False):
for file in listdir(path, '.*\.pyc$', drop=False):
os.unlink(file)
except OSError:
pass
@@ -700,10 +717,3 @@ def test():
if __name__ == '__main__':
import doctest
doctest.testmod()
+5 -12
View File
@@ -700,7 +700,7 @@ CONTENT_TYPE = {
'.zabw': 'application/x-abiword',
'.zip': 'application/zip',
'.zoo': 'application/x-zoo',
}
}
def contenttype(filename, default='text/plain'):
@@ -709,18 +709,11 @@ def contenttype(filename, default='text/plain'):
"""
i = filename.rfind('.')
if i>=0:
default = CONTENT_TYPE.get(filename[i:].lower(),default)
if i >= 0:
default = CONTENT_TYPE.get(filename[i:].lower(), default)
j = filename.rfind('.', 0, i)
if j>=0:
default = CONTENT_TYPE.get(filename[j:].lower(),default)
if j >= 0:
default = CONTENT_TYPE.get(filename[j:].lower(), default)
if default.startswith('text/'):
default += '; charset=utf-8'
return default
+38 -34
View File
@@ -21,6 +21,7 @@ import urllib
_known_tuple_types = {}
class NamedTupleBase(tuple):
"""Base class for named tuples with the __new__ operator set, named tuples
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"""
# May need to unpack named field values here
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))
for kw, val in kws.iteritems():
assert kw in kws, "%r not in field list" % kw
@@ -37,6 +38,7 @@ class NamedTupleBase(tuple):
args = tuple(values)
return tuple.__new__(cls, args)
def namedtuple(typename, fieldnames):
"""
>>> import namedtuples
@@ -75,24 +77,26 @@ def namedtuple(typename, fieldnames):
# Done
return new_tuple_type
class AIM:
class AIMError(Exception):
def __init__(self, value):
self.parameter = value
def __str__(self):
return str(self.parameter)
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')
if str(transkey).strip() == '' or transkey == None:
if str(transkey).strip() == '' or transkey is None:
raise AIM.AIMError('No transaction key provided')
if testmode != True and testmode != False:
raise AIM.AIMError('Invalid value for testmode. Must be True or False. "{0}" given.'.format(testmode))
self.testmode = testmode
self.proxy = None;
self.proxy = None
self.delimiter = '|'
self.results = []
self.error = True
@@ -117,8 +121,9 @@ class AIM:
else:
url = 'https://secure.authorize.net/gateway/transact.dll'
if self.proxy == None:
self.results += str(urllib.urlopen(url, encoded_args).read()).split(self.delimiter)
if self.proxy is None:
self.results += str(urllib.urlopen(
url, encoded_args).read()).split(self.delimiter)
else:
opener = urllib.FancyURLopener(self.proxy)
opened = opener.open(url, encoded_args)
@@ -147,36 +152,37 @@ class AIM:
raise AIM.AIMError(self.response.ResponseText)
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))
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))
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))
self.setParameter('x_card_num', creditcard)
self.setParameter('x_exp_date', expiration)
self.setParameter('x_amount', total)
if cvv != None:
if cvv is not None:
self.setParameter('x_card_code', cvv)
if tax != None:
if tax is not None:
self.setParameter('x_tax', tax)
if invoice != None:
if invoice is not None:
self.setParameter('x_invoice_num', invoice)
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:
raise AIM.AIMError('Incorrect Transaction Type passed to setTransactionType(): {0}'.format(transtype))
self.setParameter('x_type', transtype.upper())
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()')
self.proxy = {'http': str(proxy).strip()}
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()
else:
raise AIM.AIMError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
@@ -194,10 +200,11 @@ class AIM:
responses = ['', 'Approved', 'Declined', 'Error']
return responses[int(self.results[0])]
def process(creditcard,expiration,total,cvv=None,tax=None,invoice=None,
login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ',testmode=True):
payment = AIM(login,transkey,testmode)
expiration = expiration.replace('/','')
def process(creditcard, expiration, total, cvv=None, tax=None, invoice=None,
login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True):
payment = AIM(login, transkey, testmode)
expiration = expiration.replace('/', '')
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
try:
payment.process()
@@ -205,6 +212,7 @@ def process(creditcard,expiration,total,cvv=None,tax=None,invoice=None,
except AIM.AIMError:
return False
def test():
import socket
import sys
@@ -215,12 +223,14 @@ def test():
total = '1.00'
cvv = '123'
tax = '0.00'
invoice = str(time())[4:10] # get a random invoice number
invoice = str(time())[4:10] # get a random invoice number
try:
payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True)
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
payment.setParameter('x_duplicate_window', 180) # three minutes duplicate windows
payment.setTransaction(
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_first_name', 'John')
payment.setParameter('x_last_name', 'Conde')
@@ -232,7 +242,8 @@ def test():
payment.setParameter('x_country', 'US')
payment.setParameter('x_phone', '800-555-1234')
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_customer', False)
payment.process()
@@ -251,16 +262,9 @@ def test():
except AIM.AIMError, e:
print "Exception thrown:", e
print 'An error occured'
print 'approved',payment.isApproved()
print 'declined',payment.isDeclined()
print 'error',payment.isError()
print 'approved', payment.isApproved()
print 'declined', payment.isDeclined()
print 'error', payment.isError()
if __name__=='__main__':
if __name__ == '__main__':
test()
+31 -33
View File
@@ -15,25 +15,27 @@ __all__ = ['DowCommerce']
from operator import itemgetter
import urllib
class DowCommerce:
class DowCommerceError(Exception):
def __init__(self, value):
self.parameter = value
def __str__(self):
return str(self.parameter)
def __init__(self, username=None, password=None, demomode=False):
if not demomode:
if str(username).strip() == '' or username == None:
if str(username).strip() == '' or username is None:
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')
else:
username = 'demo'
password = 'password'
self.proxy = None;
self.proxy = None
self.delimiter = '&'
self.results = {}
self.error = True
@@ -45,11 +47,11 @@ class DowCommerce:
self.setParameter('username', username)
self.setParameter('password', password)
def process(self):
encoded_args = urllib.urlencode(self.parameters)
if self.proxy == None:
results = str(urllib.urlopen(self.url, encoded_args).read()).split(self.delimiter)
if self.proxy is None:
results = str(urllib.urlopen(
self.url, encoded_args).read()).split(self.delimiter)
else:
opener = urllib.FancyURLopener(self.proxy)
opened = opener.open(self.url, encoded_args)
@@ -59,7 +61,7 @@ class DowCommerce:
opened.close()
for result in results:
(key,val) = result.split('=')
(key, val) = result.split('=')
self.results[key] = val
if self.results['response'] == '1':
@@ -80,17 +82,18 @@ class DowCommerce:
self.declined = False
raise DowCommerce.DowCommerceError(self.results)
def setTransaction(self, creditcard, expiration, total, cvv=None, orderid=None, orderdescription=None,
ipaddress=None, tax=None, shipping=None,
firstname=None, lastname=None, company=None, address1=None, address2=None, city=None, state=None, zipcode=None,
country=None, phone=None, fax=None, emailaddress=None, website=None,
shipping_firstname=None, shipping_lastname=None, shipping_company=None, shipping_address1=None, shipping_address2=None,
shipping_city=None, shipping_state=None, shipping_zipcode = None, shipping_country=None, shipping_emailaddress=None):
if str(creditcard).strip() == '' or creditcard == None:
def setTransaction(
self, creditcard, expiration, total, cvv=None, orderid=None, orderdescription=None,
ipaddress=None, tax=None, shipping=None,
firstname=None, lastname=None, company=None, address1=None, address2=None, city=None, state=None, zipcode=None,
country=None, phone=None, fax=None, emailaddress=None, website=None,
shipping_firstname=None, shipping_lastname=None, shipping_company=None, shipping_address1=None, shipping_address2=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))
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))
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))
self.setParameter('ccnumber', creditcard)
@@ -165,12 +168,12 @@ class DowCommerce:
self.setParameter('type', transtype.lower())
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()')
self.proxy = {'http': str(proxy).strip()}
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()
else:
raise DowCommerce.DowCommerceError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
@@ -194,6 +197,7 @@ class DowCommerce:
def getResponseText(self):
return self.results['responsetext']
def test():
import socket
import sys
@@ -212,13 +216,14 @@ def test():
total = '1.00'
cvv = '999'
tax = '0.00'
orderid = str(time())[4:10] # get a random invoice number
orderid = str(time())[4:10] # get a random invoice number
try:
payment = DowCommerce(demomode=True)
payment.setTransaction(creditcard, expiration, total, cvv=cvv, tax=tax, orderid=orderid, orderdescription='Test Transaction',
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.setTransaction(
creditcard, expiration, total, cvv=cvv, tax=tax, orderid=orderid, orderdescription='Test Transaction',
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()
if payment.isApproved():
@@ -231,16 +236,9 @@ def test():
except DowCommerce.DowCommerceError, e:
print "Exception thrown:", e
print 'An error occured'
print 'approved',payment.isApproved()
print 'declined',payment.isDeclined()
print 'error',payment.isError()
print 'approved', payment.isApproved()
print 'declined', payment.isDeclined()
print 'error', payment.isError()
if __name__=='__main__':
if __name__ == '__main__':
test()
-8
View File
@@ -1,8 +0,0 @@
-2
View File
@@ -500,5 +500,3 @@ aes_Rcon = array('B',
'c697356ad4b37dfaefc5913972e4d3bd'
'61c29f254a943366cc831d3a74e8cb'.decode('hex')
)
+29 -18
View File
@@ -42,7 +42,9 @@ revision3.com
viddler.com
"""
import re, cgi, sys
import re
import cgi
import sys
from simplejson import loads
import urllib
import uuid
@@ -75,23 +77,28 @@ EMBED_MAPS = [
'http://revision3.com/api/oembed/'),
(re.compile('http://\S+.viddler.com/\S+'),
'http://lab.viddler.com/services/oembed/'),
]
]
def image(url):
return '<img src="%s" style="max-width:100%%"/>' % url
def audio(url):
return '<audio controls="controls" style="max-width:100%%"><source src="%s" /></audio>' % url
def video(url):
return '<video controls="controls" style="max-width:100%%"><source src="%s" /></video>' % 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)
def web2py_component(url):
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 = {
'png': image,
@@ -126,33 +133,37 @@ EXTENSION_MAPS = {
'xps': googledoc_viewer,
}
class VimeoURLOpener(urllib.FancyURLopener):
"Vimeo blocks the urllib user agent for some reason"
version = "Mozilla/4.0"
urllib._urlopener = VimeoURLOpener()
def oembed(url):
for k,v in EMBED_MAPS:
for k, v in EMBED_MAPS:
if k.match(url):
oembed = v+'?format=json&url='+cgi.escape(url)
oembed = v + '?format=json&url=' + cgi.escape(url)
try:
data = urllib.urlopen(oembed).read()
print data
return loads(data) # json!
return loads(data) # json!
except:
pass
return {}
def extension(url):
return url.split('?')[0].split('.')[-1].lower()
def expand_one(url,cdict):
def expand_one(url, cdict):
# try ombed but first check in cache
if cdict and url in cdict:
r = cdict[url]
else:
r = oembed(url)
if isinstance(cdict,dict):
if isinstance(cdict, dict):
cdict[url] = r
# if oembed service
if 'html' in r:
@@ -170,21 +181,23 @@ def expand_one(url,cdict):
# else regular link
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:
raise RuntimeError, "Missing BeautifulSoup"
raise RuntimeError("Missing BeautifulSoup")
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]
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(
lambda match: expand_one(match.group(0),cdict), txt)
lambda match: expand_one(match.group(0), cdict), txt)
txt.replaceWith(BeautifulSoup(ntxt))
return str(soup)
def test():
example="""
example = """
<h3>Fringilla nisi parturient nullam</h3>
<p>http://www.youtube.com/watch?v=IWBFiI5RrA0</p>
<p>http://www.web2py.com/examples/static/images/logo_bw.png</p>
@@ -198,10 +211,8 @@ laoreet tortor.</p>
"""
return expand_html(example)
if __name__=="__main__":
if len(sys.argv)>1:
if __name__ == "__main__":
if len(sys.argv) > 1:
print expand_html(open(sys.argv[1]).read())
else:
print test()
File diff suppressed because it is too large Load Diff
+13 -12
View File
@@ -12,6 +12,7 @@ cache.ram=cache.disk=MemcacheClient(request)
import time
from google.appengine.api.memcache import Client
class MemcacheClient(object):
client = Client()
@@ -24,12 +25,12 @@ class MemcacheClient(object):
key,
f,
time_expire=300,
):
):
key = '%s/%s' % (self.request.application, key)
dt = time_expire
value = None
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]
elif f is None:
if obj:
@@ -44,24 +45,24 @@ class MemcacheClient(object):
obj = self.client.get(key)
if obj:
value = obj[1] + value
self.client.set(key, (time.time(), value))
self.client.set(key, (time.time(), value))
return value
def clear(self, key = None):
def clear(self, key=None):
if key:
key = '%s/%s' % (self.request.application, key)
self.client.delete(key)
else:
self.client.flush_all()
def delete(self,*a,**b):
return self.client.delete(*a,**b)
def delete(self, *a, **b):
return self.client.delete(*a, **b)
def get(self,*a,**b):
return self.client.delete(*a,**b)
def get(self, *a, **b):
return self.client.delete(*a, **b)
def set(self,*a,**b):
return self.client.delete(*a,**b)
def set(self, *a, **b):
return self.client.delete(*a, **b)
def flush_all(self,*a,**b):
return self.client.delete(*a,**b)
def flush_all(self, *a, **b):
return self.client.delete(*a, **b)
+8 -12
View File
@@ -51,7 +51,8 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
: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.runtime import apiproxy_errors
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)
exponent = float(exponent)
wrapped = apiproxy_stub_map.MakeSyncCall
errors = {datastore_pb.Error.TIMEOUT:'Timeout',
datastore_pb.Error.CONCURRENT_TRANSACTION:'TransactionFailedError'}
errors = {datastore_pb.Error.TIMEOUT: 'Timeout',
datastore_pb.Error.CONCURRENT_TRANSACTION: 'TransactionFailedError'}
def wrapper(*args, **kwargs):
count = 0.0
@@ -70,10 +71,12 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
return wrapped(*args, **kwargs)
except apiproxy_errors.ApplicationError, err:
errno = err.application_error
if errno not in errors: raise
if errno not in errors:
raise
sleep = (exponent ** count) * interval
count += 1.0
if count > attempts: raise
if count > attempts:
raise
msg = "Datastore %s: retry #%d in %s seconds.\n%s"
vals = ''
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)
if getattr(wrapped, '_autoretry_datastore_timeouts', True):
apiproxy_stub_map.MakeSyncCall = wrapper
+25 -23
View File
@@ -12,6 +12,7 @@ from gluon.sanitizer import sanitize
from gluon.contrib.markmin.markmin2latex import markmin2latex
from gluon.contrib.markmin.markmin2pdf import markmin2pdf
def wrapper(f):
def g(data):
try:
@@ -25,46 +26,47 @@ def wrapper(f):
raise HTTP(405, '%s error' % e)
return g
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))
def pdflatex_from_html(html):
if os.system('which pdflatex > /dev/null')==0:
markmin=TAG(html).element('body').flatten(markmin_serializer)
out,warnings,errors=markmin2pdf(markmin)
if os.system('which pdflatex > /dev/null') == 0:
markmin = TAG(html).element('body').flatten(markmin_serializer)
out, warnings, errors = markmin2pdf(markmin)
if errors:
current.response.headers['Content-Type']='text/html'
raise HTTP(405,HTML(BODY(H1('errors'),
UL(*errors),
H1('warnings'),
UL(*warnings))).xml())
current.response.headers['Content-Type'] = 'text/html'
raise HTTP(405, HTML(BODY(H1('errors'),
UL(*errors),
H1('warnings'),
UL(*warnings))).xml())
else:
return XML(out)
def pyfpdf_from_html(html):
request = current.request
def image_map(path):
if path.startswith('/%s/static/' % request.application):
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)
class MyFPDF(FPDF, HTMLMixin): pass
pdf=MyFPDF()
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)
class MyFPDF(FPDF, HTMLMixin):
pass
pdf = MyFPDF()
pdf.add_page()
html = sanitize(html, escape=False) #### should have better list of allowed tags
pdf.write_html(html,image_map=image_map)
html = sanitize(
html, escape=False) # should have better list of allowed tags
pdf.write_html(html, image_map=image_map)
return XML(pdf.output(dest='S'))
def pdf_from_html(html):
# 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)
else:
return pyfpdf_from_html(html)
+4 -10
View File
@@ -1,5 +1,6 @@
from gluon import XML
def button(merchant_id="123456789012345",
products=[dict(name="shoes",
quantity=1,
@@ -8,15 +9,8 @@ def button(merchant_id="123456789012345",
description="running shoes black")]):
t = '<input name="item_%(key)s_%(k)s" type="hidden" value="%(value)s"/>'
list_products = ''
for k,product in enumerate(products):
for key,value in product.items():
list_products += t % dict(k=k+1,key=key,value=value)
for k, product in enumerate(products):
for key, value in product.items():
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&amp;w=117&amp;h=48&amp;style=white&amp;variant=text&amp;loc=en_US" type="image"/></form>' % (merchant_id, list_products, merchant_id)
return XML(button)
+1 -8
View File
@@ -1,12 +1,5 @@
# 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
+2 -2
View File
@@ -22,6 +22,7 @@
#########################################################################
from gluon import current
class RESIZE(object):
def __init__(self, nx=160, ny=80, error_message=' image resize'):
(self.nx, self.ny, self.error_message) = (nx, ny, error_message)
@@ -43,6 +44,7 @@ class RESIZE(object):
else:
return (value, None)
def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
if image:
if not gae:
@@ -57,5 +59,3 @@ def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
return thumb
else:
return image
-3
View File
@@ -1,3 +0,0 @@
+3 -5
View File
@@ -11,9 +11,9 @@ def basic_auth(server="http://127.0.0.1"):
"""
def basic_login_aux(username,
password,
server=server):
key = base64.b64encode(username+':'+password)
password,
server=server):
key = base64.b64encode(username + ':' + password)
headers = {'Authorization': 'Basic ' + key}
request = urllib2.Request(server, None, headers)
try:
@@ -22,5 +22,3 @@ def basic_auth(server="http://127.0.0.1"):
except (urllib2.URLError, urllib2.HTTPError):
return False
return basic_login_aux
@@ -25,6 +25,7 @@ from gluon.storage import Storage
from gluon.tools import fetch
import gluon.contrib.simplejson as json
class BrowserID(object):
"""
from gluon.contrib.login_methods.browserid_account import BrowserID
@@ -34,17 +35,17 @@ class BrowserID(object):
"""
def __init__(self,
request,
audience = "",
assertion_post_url = "",
prompt = "BrowserID Login",
issuer = "browserid.org",
verify_url = "https://browserid.org/verify",
browserid_js = "https://browserid.org/include.js",
browserid_button = "https://browserid.org/i/sign_in_red.png",
crypto_js = "https://crypto-js.googlecode.com/files/2.2.0-crypto-md5.js",
on_login_failure = None,
):
request,
audience="",
assertion_post_url="",
prompt="BrowserID Login",
issuer="browserid.org",
verify_url="https://browserid.org/verify",
browserid_js="https://browserid.org/include.js",
browserid_button="https://browserid.org/i/sign_in_red.png",
crypto_js="https://crypto-js.googlecode.com/files/2.2.0-crypto-md5.js",
on_login_failure=None,
):
self.request = request
self.audience = audience
@@ -67,13 +68,13 @@ class BrowserID(object):
if request.vars.assertion:
audience = self.audience
issuer = self.issuer
assertion = XML(request.vars.assertion,sanitize=True)
verify_data = {'assertion':assertion,'audience':audience}
auth_info_json = fetch(self.verify_url,data=verify_data)
assertion = XML(request.vars.assertion, sanitize=True)
verify_data = {'assertion': assertion, 'audience': audience}
auth_info_json = fetch(self.verify_url, data=verify_data)
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:
return dict(email = j['email'])
return dict(email=j['email'])
elif self.on_login_failure:
redirect('http://google.com')
else:
@@ -83,9 +84,8 @@ class BrowserID(object):
def login_form(self):
request = self.request
onclick = "javascript:navigator.id.getVerifiedEmail(gotVerifiedEmail) ; return false"
form = DIV(SCRIPT(_src=self.browserid_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"),
SCRIPT(self.asertion_js))
form = DIV(SCRIPT(_src=self.browserid_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"),
SCRIPT(self.asertion_js))
return form
+57 -52
View File
@@ -11,7 +11,8 @@ Tinkered by Szabolcs Gyuris < szimszo n @ o regpreshaz dot eu>
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 form.
@@ -39,101 +40,105 @@ class CasAuth( object ):
user's username.
"""
def __init__(self, g=None, ### g for backward compatibility ###
urlbase = "https://web2py.com/cas/cas",
actions=['login','validate','logout'],
maps=dict(username=lambda v:v.get('username',v['user']),
email=lambda v:v.get('email',None),
user_id=lambda v:v['user']),
casversion = 1,
casusername = 'cas:user'
def __init__(self, g=None, # g for backward compatibility ###
urlbase="https://web2py.com/cas/cas",
actions=['login', 'validate', 'logout'],
maps=dict(username=lambda v: v.get('username', v['user']),
email=lambda v: v.get('email', None),
user_id=lambda v: v['user']),
casversion=1,
casusername='cas:user'
):
self.urlbase=urlbase
self.cas_login_url="%s/%s"%(self.urlbase,actions[0])
self.cas_check_url="%s/%s"%(self.urlbase,actions[1])
self.cas_logout_url="%s/%s"%(self.urlbase,actions[2])
self.maps=maps
self.urlbase = urlbase
self.cas_login_url = "%s/%s" % (self.urlbase, actions[0])
self.cas_check_url = "%s/%s" % (self.urlbase, actions[1])
self.cas_logout_url = "%s/%s" % (self.urlbase, actions[2])
self.maps = maps
self.casversion = casversion
self.casusername = casusername
http_host=current.request.env.http_x_forwarded_host
if not http_host: http_host=current.request.env.http_host
if current.request.env.wsgi_url_scheme in [ 'https', 'HTTPS' ]:
http_host = current.request.env.http_x_forwarded_host
if not http_host:
http_host = current.request.env.http_host
if current.request.env.wsgi_url_scheme in ['https', 'HTTPS']:
scheme = 'https'
else:
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 = "/" ):
current.session.token=self._CAS_login()
def login_url(self, next="/"):
current.session.token = self._CAS_login()
return next
def logout_url( self, next = "/" ):
current.session.token=None
current.session.auth=None
def logout_url(self, next="/"):
current.session.token = None
current.session.auth = None
self._CAS_logout()
return next
def get_user( self ):
user=current.session.token
def get_user(self):
user = current.session.token
if user:
d = {'source':'web2py cas'}
d = {'source': 'web2py cas'}
for key in self.maps:
d[key]=self.maps[key](user)
d[key] = self.maps[key](user)
return d
return None
def _CAS_login( self ):
def _CAS_login(self):
"""
exposed as CAS.login(request)
returns a token on success, None on failed authentication
"""
import urllib
self.ticket=current.request.vars.ticket
self.ticket = 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))
else:
url="%s?service=%s&ticket=%s" % (self.cas_check_url,
self.cas_my_url,
self.ticket )
data=urllib.urlopen( url ).read()
url = "%s?service=%s&ticket=%s" % (self.cas_check_url,
self.cas_my_url,
self.ticket)
data = urllib.urlopen(url).read()
if data.startswith('yes') or data.startswith('no'):
data = data.split('\n')
if data[0]=='yes':
if ':' in data[1]: # for Compatibility with Custom CAS
if data[0] == 'yes':
if ':' in data[1]: # for Compatibility with Custom CAS
items = data[1].split(':')
a = items[0]
b = len(items)>1 and items[1] or a
c = len(items)>2 and items[2] or b
b = len(items) > 1 and items[1] or a
c = len(items) > 2 and items[2] or b
else:
a = b = c = data[1]
return dict(user=a,email=b,username=c)
return dict(user=a, email=b, username=c)
return None
import xml.dom.minidom as dom
import xml.parsers.expat as expat
try:
dxml=dom.parseString(data)
envelop = dxml.getElementsByTagName("cas:authenticationSuccess")
if len(envelop)>0:
dxml = dom.parseString(data)
envelop = dxml.getElementsByTagName(
"cas:authenticationSuccess")
if len(envelop) > 0:
res = dict()
for x in envelop[0].childNodes:
if x.nodeName.startswith('cas:') and len(x.childNodes):
key = x.nodeName[4:].encode('utf8')
value = x.childNodes[0].nodeValue.encode('utf8')
if not key in res:
res[key]=value
res[key] = value
else:
if not isinstance(res[key],list):
res[key]=[res[key]]
if not isinstance(res[key], list):
res[key] = [res[key]]
res[key].append(value)
return res
except expat.ExpatError: pass
return None # fallback
except expat.ExpatError:
pass
return None # fallback
def _CAS_logout( self ):
def _CAS_logout(self):
"""
exposed CAS.logout()
redirects to the CAS logout page
"""
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))
+41 -38
View File
@@ -18,11 +18,13 @@ from gluon.tools import fetch
from gluon.storage import Storage
import gluon.contrib.simplejson as json
class DropboxAccount(object):
"""
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,
key="...",
secret="...",
@@ -34,47 +36,45 @@ class DropboxAccount(object):
def __init__(self,
request,
key = "",
secret = "",
key="",
secret="",
access_type="app_folder",
login_url = "",
login_url="",
on_login_failure=None,
):
self.request=request
self.key=key
self.secret=secret
self.access_type=access_type
self.request = request
self.key = key
self.secret = secret
self.access_type = access_type
self.login_url = login_url
self.on_login_failure = on_login_failure
self.sess = session.DropboxSession(
self.key,self.secret,self.access_type)
self.key, self.secret, self.access_type)
def get_user(self):
request = self.request
if not current.session.dropbox_request_token:
return None
elif not current.session.dropbox_access_token:
request_token = current.session.dropbox_request_token
self.sess.set_request_token(request_token[0],request_token[1])
request_token = current.session.dropbox_request_token
self.sess.set_request_token(request_token[0], request_token[1])
access_token = self.sess.obtain_access_token(self.sess.token)
current.session.dropbox_access_token = \
(access_token.key,access_token.secret)
(access_token.key, access_token.secret)
else:
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()
self.client = client.DropboxClient(self.sess)
data = self.client.account_info()
display_name = data.get('display_name','').split(' ',1)
user = dict(email = data.get('email',None),
first_name = display_name[0],
last_name = display_name[-1],
registration_id = data.get('uid',None))
display_name = data.get('display_name', '').split(' ', 1)
user = dict(email=data.get('email', None),
first_name=display_name[0],
last_name=display_name[-1],
registration_id=data.get('uid', None))
if not user['registration_id'] and self.on_login_failure:
redirect(self.on_login_failure)
return user
@@ -83,7 +83,7 @@ class DropboxAccount(object):
request_token = self.sess.obtain_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,
self.login_url)
redirect(dropbox_url)
@@ -93,29 +93,32 @@ class DropboxAccount(object):
_style="width:400px;height:240px;")
return form
def logout_url(self, next = "/"):
current.session.dropbox_request_token=None
current.session.auth=None
def logout_url(self, next="/"):
current.session.dropbox_request_token = None
current.session.auth = None
redirect('https://www.dropbox.com/logout')
return next
def put(self,filename,file):
return json.loads(self.client.put_file(filename,file))['bytes']
def get(self,filename,file):
def put(self, filename, file):
return json.loads(self.client.put_file(filename, file))['bytes']
def get(self, filename, file):
return self.client.get_file(filename)
def dir(self,path):
def dir(self, 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):
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
login_url = "http://%s/%s/default/user/login" % \
(host,request.application)
(host, request.application)
auth.settings.actions_disabled = \
['register','change_password','request_reset_password']
['register', 'change_password', 'request_reset_password']
auth.settings.login_form = DropboxAccount(
request,key=key,secret=secret,access_type=access_type,
login_url = login_url,**kwargs)
request, key=key, secret=secret, access_type=access_type,
login_url=login_url, **kwargs)
+4 -4
View File
@@ -1,6 +1,7 @@
import smtplib
import logging
def email_auth(server="smtp.gmail.com:587",
domain="@gmail.com",
tls_mode=None):
@@ -17,9 +18,9 @@ def email_auth(server="smtp.gmail.com:587",
domain=domain,
tls_mode=tls_mode):
if domain:
if not isinstance(domain,(list,tuple)):
domain=[str(domain)]
if not [d for d in domain if email[-len(d):]==d]:
if not isinstance(domain, (list, tuple)):
domain = [str(domain)]
if not [d for d in domain if email[-len(d):] == d]:
return False
(host, port) = server.split(':')
if tls_mode is None: # then auto detect
@@ -43,4 +44,3 @@ def email_auth(server="smtp.gmail.com:587",
pass
return False
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
class ExtendedLoginForm(object):
"""
Put extended_login_form under web2py/gluon/contrib/login_methods folder.
@@ -22,7 +23,8 @@ class ExtendedLoginForm(object):
api_key="...",
domain="...",
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
@@ -37,7 +39,7 @@ class ExtendedLoginForm(object):
auth,
alt_login_form,
signals=[],
login_arg = 'login'
login_arg='login'
):
self.auth = auth
self.alt_login_form = alt_login_form
@@ -50,7 +52,7 @@ class ExtendedLoginForm(object):
"""
if hasattr(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):
"""
@@ -91,8 +93,8 @@ class ExtendedLoginForm(object):
args = request.args
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()
self.auth.settings.login_form = self.auth
@@ -101,5 +103,3 @@ class ExtendedLoginForm(object):
form.components.append(self.alt_login_form.login_form())
return form
@@ -11,6 +11,7 @@ Thanks to Hans Donner <hans.donner@pobox.com> for GaeGoogleAccount.
from google.appengine.api import users
class GaeGoogleAccount(object):
"""
Login will be done via Google's Appengine login object, instead of web2py's
@@ -35,5 +36,3 @@ class GaeGoogleAccount(object):
if user:
return dict(nickname=user.nickname(), email=user.email(),
user_id=user.user_id(), source="google account")
+28 -15
View File
@@ -188,18 +188,23 @@ def ldap_auth(server='ldap', port=None,
str(custom_scope), str(manage_groups)))
if manage_user:
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)
else:
user_firstname_part = None
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)
else:
user_lastname_part = None
user_firstname_attrib = ldap.filter.escape_filter_chars(user_firstname_attrib)
user_lastname_attrib = ldap.filter.escape_filter_chars(user_lastname_attrib)
user_mail_attrib = ldap.filter.escape_filter_chars(user_mail_attrib)
user_firstname_attrib = ldap.filter.escape_filter_chars(
user_firstname_attrib)
user_lastname_attrib = ldap.filter.escape_filter_chars(
user_lastname_attrib)
user_mail_attrib = ldap.filter.escape_filter_chars(
user_mail_attrib)
try:
if allowed_groups:
if not is_user_in_allowed_groups(username, password):
@@ -310,7 +315,8 @@ def ldap_auth(server='ldap', port=None,
basedns = ldap_basedn
else:
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
for basedn in basedns:
try:
@@ -338,7 +344,8 @@ def ldap_auth(server='ldap', port=None,
else:
basedns = [ldap_basedn]
filter = '(&(%s=%s)(%s))' % (username_attrib,
ldap.filter.escape_filter_chars(username),
ldap.filter.escape_filter_chars(
username),
filterstr)
if custom_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))
try:
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:
store_user_firstname = result[user_firstname_attrib][0]
except KeyError, e:
store_user_firstname = None
try:
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:
store_user_lastname = result[user_lastname_attrib][0]
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
# #########################################################
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
# #############################################################
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:
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:
#
# 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,
first_name=username)
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
db_group_search = db((db.auth_membership.user_id == db_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,
description='Generated from LDAP')
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,
group_id=gid)
except:
@@ -634,4 +648,3 @@ def ldap_auth(server='ldap', port=None,
if filterstr[0] == '(' and filterstr[-1] == ')': # rfc4515 syntax
filterstr = filterstr[1:-1] # parens added again where used
return ldap_auth_aux
+11 -11
View File
@@ -14,7 +14,8 @@ from gluon.http import HTTP
try:
import linkedin
except ImportError:
raise HTTP(400,"linkedin module not found")
raise HTTP(400, "linkedin module not found")
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.api = linkedin.LinkedIn(key,secret,return_url)
self.api = linkedin.LinkedIn(key, secret, return_url)
self.token = result = self.api.requestToken()
def login_url(self, next="/"):
@@ -40,13 +41,12 @@ class LinkedInAccount(object):
return ''
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:
profile = self.api.GetProfile()
profile = self.api.GetProfile(profile).public_url = "http://www.linkedin.com/in/ozgurv"
return dict(first_name = profile.first_name,
last_name = profile.last_name,
username = profile.id)
profile = self.api.GetProfile(
profile).public_url = "http://www.linkedin.com/in/ozgurv"
return dict(first_name=profile.first_name,
last_name=profile.last_name,
username=profile.id)
+40 -38
View File
@@ -13,6 +13,7 @@ from gluon.tools import fetch
from gluon.storage import Storage
import gluon.contrib.simplejson as json
class Loginza(object):
"""
@@ -23,13 +24,13 @@ class Loginza(object):
def __init__(self,
request,
url = "",
embed = True,
auth_url = "http://loginza.ru/api/authinfo",
language = "en",
prompt = "loginza",
on_login_failure = None,
):
url="",
embed=True,
auth_url="http://loginza.ru/api/authinfo",
language="en",
prompt="loginza",
on_login_failure=None,
):
self.request = request
self.token_url = url
@@ -46,49 +47,50 @@ class Loginza(object):
# FIXME: what if email is unique=True
self.mappings["http://twitter.com/"] = lambda profile:\
dict(registration_id = profile.get("identity",""),
username = profile.get("nickname",""),
email = profile.get("email",""),
last_name = profile.get("name","").get("full_name",""),
dict(registration_id=profile.get("identity", ""),
username=profile.get("nickname", ""),
email=profile.get("email", ""),
last_name=profile.get("name", "").get("full_name", ""),
#avatar = profile.get("photo",""),
)
)
self.mappings["https://www.google.com/accounts/o8/ud"] = lambda profile:\
dict(registration_id = profile.get("identity",""),
username = profile.get("name","").get("full_name",""),
email = profile.get("email",""),
first_name = profile.get("name","").get("first_name",""),
last_name = profile.get("name","").get("last_name",""),
dict(registration_id=profile.get("identity", ""),
username=profile.get("name", "").get("full_name", ""),
email=profile.get("email", ""),
first_name=profile.get("name", "").get("first_name", ""),
last_name=profile.get("name", "").get("last_name", ""),
#avatar = profile.get("photo",""),
)
)
self.mappings["http://vkontakte.ru/"] = lambda profile:\
dict(registration_id=profile.get("identity",""),
username = profile.get("name","").get("full_name",""),
email = profile.get("email",""),
first_name = profile.get("name","").get("first_name",""),
last_name = profile.get("name","").get("last_name",""),
dict(registration_id=profile.get("identity", ""),
username=profile.get("name", "").get("full_name", ""),
email=profile.get("email", ""),
first_name=profile.get("name", "").get("first_name", ""),
last_name=profile.get("name", "").get("last_name", ""),
#avatar = profile.get("photo",""),
)
)
self.mappings.default = lambda profile:\
dict(registration_id = profile.get("identity",""),
username = profile.get("name","").get("full_name"),
email = profile.get("email",""),
first_name = profile.get("name","").get("first_name",""),
last_name = profile.get("name","").get("last_name",""),
dict(registration_id=profile.get("identity", ""),
username=profile.get("name", "").get("full_name"),
email=profile.get("email", ""),
first_name=profile.get("name", "").get("first_name", ""),
last_name=profile.get("name", "").get("last_name", ""),
#avatar = profile.get("photo",""),
)
)
def get_user(self):
request = self.request
if request.vars.token:
user = Storage()
data = urllib.urlencode(dict(token = request.vars.token))
auth_info_json = fetch(self.auth_url+'?'+data)
data = urllib.urlencode(dict(token=request.vars.token))
auth_info_json = fetch(self.auth_url + '?' + data)
#print 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
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["avatar"] = ???
return user
@@ -106,8 +108,8 @@ class Loginza(object):
_frameborder="no",
_style="width:359px;height:300px;")
else:
form = DIV(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"))
form = DIV(
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
+17 -11
View File
@@ -4,6 +4,7 @@ import time
from hashlib import md5
from gluon.dal import DAL
def motp_auth(db=DAL('sqlite://storage.sqlite'),
time_offset=60):
@@ -44,7 +45,8 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
writable=False, readable=False, default=''))
##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 = \
IS_NOT_EMPTY(error_message=auth.messages.is_empty)
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.
"""
def verify_otp(otp,pin,secret,offset=60):
def verify_otp(otp, pin, secret, offset=60):
epoch_time = int(time.time())
time_start = int(str(epoch_time - offset)[:-1])
time_end = int(str(epoch_time + offset)[:-1])
for t in range(time_start-1,time_end+1):
to_hash = str(t)+secret+pin
for t in range(time_start - 1, time_end + 1):
to_hash = str(t) + secret + pin
hash = md5(to_hash).hexdigest()[:6]
if otp == hash: return True
if otp == hash:
return True
return False
def motp_auth_aux(email,
@@ -91,15 +94,18 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
db=db,
offset=time_offset):
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['motp_secret'] and user_data['motp_pin']:
motp_secret = user_data['motp_secret']
motp_pin = user_data['motp_pin']
otp_check = verify_otp(password,motp_pin,motp_secret,offset=offset)
if otp_check: return True
else: return False
else: return False
otp_check = verify_otp(
password, motp_pin, motp_secret, offset=offset)
if otp_check:
return True
else:
return False
else:
return False
return False
return motp_auth_aux
+15 -20
View File
@@ -19,6 +19,7 @@ from urllib2 import urlopen
import urllib2
from urllib import urlencode
class OAuthAccount(object):
"""
Login will be done via OAuth Framework, instead of web2py's
@@ -51,7 +52,8 @@ class OAuthAccount(object):
TOKEN_URL="..."
ACCESS_TOKEN_URL="..."
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.
"""
r = self.request
http_host=r.env.http_x_forwarded_for
if not http_host: http_host=r.env.http_host
http_host = r.env.http_x_forwarded_for
if not http_host:
http_host = r.env.http_host
url_scheme = r.env.wsgi_url_scheme
if next:
path_info = next
else:
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:
uri += '?' + urlencode(r.get_vars)
return uri
def accessToken(self):
"""Return the access token generated by the authenticating server.
@@ -97,12 +99,11 @@ class OAuthAccount(object):
token.set_verifier(self.request.vars.oauth_verifier)
client = oauth.Client(self.consumer, token)
resp, content = client.request(self.access_token_url, "POST")
if str(resp['status']) != '200':
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)
@@ -111,7 +112,7 @@ class OAuthAccount(object):
self.session.access_token = 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.client_id = client_id
self.client_secret = client_secret
@@ -125,7 +126,6 @@ class OAuthAccount(object):
# consumer init
self.consumer = oauth.Consumer(self.client_id, self.client_secret)
def login_url(self, next="/"):
self.__oauth_login(next)
return next
@@ -142,7 +142,7 @@ class OAuthAccount(object):
is, this function must be implemented for the specific
provider.
'''
raise NotImplementedError, "Must override get_user()"
raise NotImplementedError("Must override get_user()")
def __oauth_login(self, next):
'''This method redirects the user to the authenticating form
@@ -163,10 +163,11 @@ class OAuthAccount(object):
# putting it in the body seems to work.
callback_url = self.__redirect_uri(next)
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':
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.
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.
data = urlencode(dict(oauth_token=request_token.key,
oauth_callback=callback_url))
auth_request_url = self.auth_url + '?' +data
auth_request_url = self.auth_url + '?' + data
HTTP = self.globals['HTTP']
raise HTTP(307,
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
Location=auth_request_url)
return None
+24 -25
View File
@@ -17,6 +17,7 @@ import urllib2
from urllib import urlencode
from gluon import current, redirect, HTTP
class OAuthAccount(object):
"""
Login will be done via OAuth Framework, instead of web2py's
@@ -84,7 +85,8 @@ class OAuthAccount(object):
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()
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
http_host=r.env.http_x_forwarded_for
if not http_host: http_host=r.env.http_host
http_host = r.env.http_x_forwarded_for
if not http_host:
http_host = r.env.http_host
url_scheme = r.env.wsgi_url_scheme
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)
return uri
def __build_url_opener(self, uri):
"""
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)
return opener
def accessToken(self):
"""
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.
"""
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']
# reuse token until expiration
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
raise Exception(tmp)
finally:
del current.session.code # throw it away
del current.session.code # throw it away
if open_url:
try:
data = open_url.read()
tokendata = cgi.parse_qs(data)
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
# implementations where "expires_in" becomes "expires"
if current.session.token.has_key('expires_in'):
if 'expires_in' in current.session.token:
exps = 'expires_in'
elif current.session.token.has_key('expires'):
elif 'expires' in current.session.token:
exps = 'expires'
else:
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.
"""
if not current.session.token: return None
return dict(first_name = 'Pinco',
last_name = 'Pallino',
username = 'pincopallino')
raise NotImplementedError, "Must override get_user()"
if not current.session.token:
return None
return dict(first_name='Pinco',
last_name='Pallino',
username='pincopallino')
raise NotImplementedError("Must override get_user()")
# Following code is never executed. It can be used as example
# 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
if user:
return dict(first_name = user['first_name'],
last_name = user['last_name'],
username = user['id'])
return dict(first_name=user['first_name'],
last_name=user['last_name'],
username=user['id'])
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 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,
response_type='code',
client_id=self.client_id)
response_type='code',
client_id=self.client_id)
if 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,
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
Location=auth_request_url)
@@ -273,5 +274,3 @@ server for requests. It can be used for the optional"scope" parameters for Face
self.accessToken()
return current.session.code
return None
+93 -76
View File
@@ -49,6 +49,7 @@ except ImportError, err:
DEFAULT = lambda: None
class OpenIDAuth(object):
"""
OpenIDAuth
@@ -94,7 +95,7 @@ class OpenIDAuth(object):
if not auth.settings.table_user:
raise
self.table_user = self.auth.settings.table_user
self.openid_expiration = 15 #minutes
self.openid_expiration = 15 # minutes
self.messages = self._define_messages()
@@ -116,7 +117,7 @@ class OpenIDAuth(object):
messages.flash_openid_associated = 'OpenID associated'
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. " \
+ "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_fail_authentication = 'OpenID authentication failed. (Error message: %s)'
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.
"""
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()
return self.auth()
return self._form()
@@ -172,12 +173,12 @@ class OpenIDAuth(object):
args = request.args
if args[0] == 'logout':
return True # Let logout_url got called
return True # Let logout_url got called
if current.session.w2popenid:
w2popenid = current.session.w2popenid
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):
del(current.session.w2popenid)
flash = self.messages.flash_openid_expired
@@ -196,22 +197,23 @@ class OpenIDAuth(object):
if current.session.w2popenid:
del(current.session.w2popenid)
current.session.flash = self.messages.flash_openid_associated
if request.vars.has_key(nextvar):
if nextvar in request.vars:
redirect(request.vars[nextvar])
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
# so if user login or register can go back here to associate the OpenID
redirect(URL(r=request,
args=['login'],
vars={nextvar:self.login_url}))
args=['login'],
vars={nextvar: self.login_url}))
self.login_form = self._form_with_notification()
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
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 current.session.w2popenid:
del(current.session.w2popenid)
@@ -219,16 +221,17 @@ class OpenIDAuth(object):
username = 'username'
elif 'email' in self.table_user.fields():
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'):
"""
Get the matched OpenID for given
"""
query = ((db.alt_logins.username == oid) & (db.alt_logins.type == type_))
alt_login = db(query).select().first() # Get the OpenID record
query = (
(db.alt_logins.username == oid) & (db.alt_logins.type == type_))
alt_login = db(query).select().first() # Get the OpenID record
return alt_login
def _associate_user_openid(self, user, oid):
@@ -275,7 +278,6 @@ class OpenIDAuth(object):
self.db)
return self.consumerhelper
def _form(self, style=None):
form = DIV(H3(self.messages.h_openid_login), self._login_form(style))
return form
@@ -300,7 +302,7 @@ background-color: transparent;
padding-left: 18px;
width: 400px;
"""
style = style.replace("\n","")
style = style.replace("\n", "")
request = current.request
session = current.session
@@ -308,21 +310,25 @@ width: 400px;
hidden_next_input = ""
if _next == 'profile':
profile_url = URL(r=request, f='user', args=['profile'])
hidden_next_input = INPUT(_type="hidden", _name="_next", _value=profile_url)
form = FORM(openid_field_label or self.messages.label_alt_login_username,
INPUT(_type="input", _name="oid",
requires=IS_NOT_EMPTY(error_message=messages.openid_fail_discover),
_style=style),
hidden_next_input,
INPUT(_type="submit", _value=submit_button or messages.submit_button),
" ",
A(messages.comment_openid_signin,
_href=messages.comment_openid_help_url,
_title=messages.comment_openid_help_title,
_class='openid-identifier',
_target="_blank"),
_action=self.login_url
)
hidden_next_input = INPUT(
_type="hidden", _name="_next", _value=profile_url)
form = FORM(
openid_field_label or self.messages.label_alt_login_username,
INPUT(_type="input", _name="oid",
requires=IS_NOT_EMPTY(
error_message=messages.openid_fail_discover),
_style=style),
hidden_next_input,
INPUT(_type="submit",
_value=submit_button or messages.submit_button),
" ",
A(messages.comment_openid_signin,
_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):
oid = request.vars.oid
consumerhelper = self._init_consumerhelper()
@@ -332,8 +338,9 @@ width: 400px;
warning_openid_fail(session)
redirect(url)
try:
if request.vars.has_key('_next'):
return_to_url = self.return_to_url + '?_next=' + request.vars._next
if '_next' in request.vars:
return_to_url = self.return_to_url + \
'?_next=' + request.vars._next
url = consumerhelper.begin(oid, self.realm, return_to_url)
except DiscoveryFailure:
warning_openid_fail(session)
@@ -353,7 +360,8 @@ width: 400px;
"""
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):
"""
@@ -369,7 +377,8 @@ width: 400px;
request = current.request
request_vars = request.vars
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":
w2popenid = current.session.w2popenid
user_data = self.consumerhelper.sreg()
@@ -388,7 +397,7 @@ width: 400px;
def list_user_openids(self):
messages = self.messages
request = current.request
if request.vars.has_key('delete_openid'):
if 'delete_openid' in request.vars:
self.remove_openid(request.vars.delete_openid)
query = self.db.alt_logins.user == self.auth.user.id
@@ -397,8 +406,8 @@ width: 400px;
for alt_login in alt_logins:
username = alt_login.username
delete_href = URL(r=request, f='user',
args=['profile'],
vars={'delete_openid': username})
args=['profile'],
vars={'delete_openid': username})
delete_link = A(messages.a_delete, _href=delete_href)
l.append(LI(username, " ", delete_link))
@@ -409,23 +418,23 @@ width: 400px;
_next='profile',
submit_button=messages.submit_button_add,
openid_field_label=messages.label_add_alt_login_username)
)
)
return openid_list
def remove_openid(self, openid):
query = self.db.alt_logins.username == openid
self.db(query).delete()
class ConsumerHelper(object):
"""
ConsumerHelper knows the python-openid and
"""
def __init__(self, session, db):
self.session = session
store = self._init_store(db)
self.consumer = openid.consumer.consumer.Consumer(session, store)
self.session = session
store = self._init_store(db)
self.consumer = openid.consumer.consumer.Consumer(session, store)
def _init_store(self, db):
"""
@@ -434,7 +443,7 @@ class ConsumerHelper(object):
if not hasattr(self, "store"):
store = Web2pyStore(db)
session = self.session
if not session.has_key('w2popenid'):
if 'w2popenid' not in session:
session.w2popenid = Storage()
self.store = store
return self.store
@@ -446,7 +455,7 @@ class ConsumerHelper(object):
w2popenid = self.session.w2popenid
w2popenid.oid = 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)
return url
@@ -504,19 +513,27 @@ class Web2pyStore(OpenIDStore):
if self.table_oid_associations_name not in self.database:
self.database.define_table(self.table_oid_associations_name,
Field('server_url', 'string', length=2047, required=True),
Field('handle', 'string', length=255, required=True),
Field('secret', 'blob', required=True),
Field('issued', 'integer', required=True),
Field('lifetime', 'integer', required=True),
Field('assoc_type', 'string', length=64, required=True)
)
Field('server_url',
'string', length=2047, required=True),
Field('handle',
'string', length=255, required=True),
Field('secret', 'blob', 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:
self.database.define_table(self.table_oid_nonces_name,
Field('server_url', 'string', length=2047, required=True),
Field('timestamp', 'integer', required=True),
Field('salt', 'string', length=40, required=True)
)
Field('server_url',
'string', length=2047, required=True),
Field('timestamp',
'integer', required=True),
Field('salt', 'string',
length=40, required=True)
)
def storeAssociation(self, server_url, association):
"""
@@ -525,14 +542,15 @@ class Web2pyStore(OpenIDStore):
"""
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.oid_associations.insert(server_url = server_url,
handle = association.handle,
secret = association.secret,
issued = association.issued,
lifetime = association.lifetime,
assoc_type = association.assoc_type), 'insert '*10
db.oid_associations.insert(server_url=server_url,
handle=association.handle,
secret=association.secret,
issued=association.issued,
lifetime=association.lifetime,
assoc_type=association.assoc_type), 'insert ' * 10
def getAssociation(self, server_url, handle=None):
"""
@@ -550,7 +568,8 @@ class Web2pyStore(OpenIDStore):
if len(keep_assoc) == 0:
return None
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'],
assoc['secret'],
assoc['issued'],
@@ -559,8 +578,9 @@ class Web2pyStore(OpenIDStore):
def removeAssociation(self, server_url, handle):
db = self.database
query = (db.oid_associations.server_url == server_url) & (db.oid_associations.handle == handle)
return db(query).delete() != None
query = (db.oid_associations.server_url == server_url) & (
db.oid_associations.handle == handle)
return db(query).delete() is not None
def useNonce(self, server_url, timestamp, salt):
"""
@@ -575,10 +595,10 @@ class Web2pyStore(OpenIDStore):
if db(query).count() > 0:
return False
else:
db.oid_nonces.insert(server_url = server_url,
timestamp = timestamp,
salt = salt)
return True
db.oid_nonces.insert(server_url=server_url,
timestamp=timestamp,
salt=salt)
return True
def _removeExpiredAssocations(self, rows):
"""
@@ -599,7 +619,7 @@ class Web2pyStore(OpenIDStore):
keep_assoc.append(r)
for r in remove_assoc:
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):
"""
@@ -619,7 +639,7 @@ class Web2pyStore(OpenIDStore):
db = self.database
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):
"""
@@ -628,6 +648,3 @@ class Web2pyStore(OpenIDStore):
"""
return self.cleanupNonces(), self.cleanupAssociations()
+1 -2
View File
@@ -1,5 +1,6 @@
from gluon.contrib.pam import authenticate
def pam_auth():
"""
to use pam_login:
@@ -19,5 +20,3 @@ def pam_auth():
return authenticate(username, password)
return pam_auth_aux
+47 -41
View File
@@ -19,11 +19,13 @@ from gluon.tools import fetch
from gluon.storage import Storage
import gluon.contrib.simplejson as json
class RPXAccount(object):
"""
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,
api_key="...",
domain="...",
@@ -32,18 +34,18 @@ class RPXAccount(object):
def __init__(self,
request,
api_key = "",
domain = "",
url = "",
embed = True,
auth_url = "https://rpxnow.com/api/v2/auth_info",
language= "en",
api_key="",
domain="",
url="",
embed=True,
auth_url="https://rpxnow.com/api/v2/auth_info",
language="en",
prompt='rpx',
on_login_failure = None,
on_login_failure=None,
):
self.request=request
self.api_key=api_key
self.request = request
self.api_key = api_key
self.embed = embed
self.auth_url = auth_url
self.domain = domain
@@ -54,38 +56,40 @@ class RPXAccount(object):
self.on_login_failure = on_login_failure
self.mappings = Storage()
dn = {'givenName':'','familyName':''}
dn = {'givenName': '', 'familyName': ''}
self.mappings.Facebook = lambda profile, dn=dn:\
dict(registration_id = profile.get("identifier",""),
username = profile.get("preferredUsername",""),
email = profile.get("email",""),
first_name = profile.get("name",dn).get("givenName",""),
last_name = profile.get("name",dn).get("familyName",""))
dict(registration_id=profile.get("identifier", ""),
username=profile.get("preferredUsername", ""),
email=profile.get("email", ""),
first_name=profile.get("name", dn).get("givenName", ""),
last_name=profile.get("name", dn).get("familyName", ""))
self.mappings.Google = lambda profile, dn=dn:\
dict(registration_id=profile.get("identifier",""),
username=profile.get("preferredUsername",""),
email=profile.get("email",""),
first_name=profile.get("name",dn).get("givenName",""),
last_name=profile.get("name",dn).get("familyName",""))
dict(registration_id=profile.get("identifier", ""),
username=profile.get("preferredUsername", ""),
email=profile.get("email", ""),
first_name=profile.get("name", dn).get("givenName", ""),
last_name=profile.get("name", dn).get("familyName", ""))
self.mappings.default = lambda profile:\
dict(registration_id=profile.get("identifier",""),
username=profile.get("preferredUsername",""),
email=profile.get("email",""),
first_name=profile.get("preferredUsername",""),
dict(registration_id=profile.get("identifier", ""),
username=profile.get("preferredUsername", ""),
email=profile.get("email", ""),
first_name=profile.get("preferredUsername", ""),
last_name='')
def get_user(self):
request = self.request
if request.vars.token:
user = Storage()
data = urllib.urlencode(dict(apiKey = self.api_key, token=request.vars.token))
auth_info_json = fetch(self.auth_url+'?'+data)
data = urllib.urlencode(
dict(apiKey=self.api_key, token=request.vars.token))
auth_info_json = fetch(self.auth_url + '?' + data)
auth_info = json.loads(auth_info_json)
if auth_info['stat'] == 'ok':
self.profile = auth_info['profile']
provider = re.sub('[^\w\-]','',self.profile['providerName'])
user = self.mappings.get(provider,self.mappings.default)(self.profile)
provider = re.sub('[^\w\-]', '', self.profile['providerName'])
user = self.mappings.get(
provider, self.mappings.default)(self.profile)
return user
elif self.on_login_failure:
redirect(self.on_login_failure)
@@ -95,12 +99,14 @@ class RPXAccount(object):
request = self.request
args = request.args
if self.embed:
JANRAIN_URL = \
"https://%s.rpxnow.com/openid/embed?token_url=%s&language_preference=%s"
rpxform = IFRAME(_src=JANRAIN_URL % (self.domain,self.token_url,self.language),
_scrolling="no",
_frameborder="no",
_style="width:400px;height:240px;")
JANRAIN_URL = \
"https://%s.rpxnow.com/openid/embed?token_url=%s&language_preference=%s"
rpxform = IFRAME(
_src=JANRAIN_URL % (
self.domain, self.token_url, self.language),
_scrolling="no",
_frameborder="no",
_style="width:400px;height:240px;")
else:
JANRAIN_URL = \
"https://%s.rpxnow.com/openid/v2/signin?token_url=%s"
@@ -114,15 +120,15 @@ class RPXAccount(object):
_type="text/javascript"))
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):
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
url = URL('default', 'user', args='login', scheme=True)
auth.settings.actions_disabled = \
['register','change_password','request_reset_password']
['register', 'change_password', 'request_reset_password']
auth.settings.login_form = RPXAccount(
request, api_key=key,domain=domain, url = url,**kwargs)
request, api_key=key, domain=domain, url=url, **kwargs)
+19 -26
View File
@@ -11,13 +11,12 @@ Adds support for x509 authentication.
from gluon.globals import current
from gluon.storage import Storage
from gluon.http import HTTP,redirect
from gluon.http import HTTP, redirect
#requires M2Crypto
from M2Crypto import X509
class X509Auth(object):
"""
Login using x509 cert from client.
@@ -29,8 +28,6 @@ class X509Auth(object):
"""
def __init__(self):
self.request = current.request
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:
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
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()
@@ -53,23 +51,17 @@ class X509Auth(object):
# cn = self.subject.cn
self.subject = Storage(filter(None,
map(lambda x:
(x,map(lambda y:
y.get_data().as_text(),
subject.get_entries_by_nid(subject.nid[x]))),
(x, map(lambda y:
y.get_data(
).as_text(),
subject.get_entries_by_nid(subject.nid[x]))),
subject.nid.keys())))
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="/"):
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="/"):
return next
@@ -86,10 +78,14 @@ class X509Auth(object):
p = profile = dict()
username = p['username'] = reduce(lambda a,b: '%s | %s' % (a,b), self.subject.CN or self.subject.commonName)
p['first_name'] = reduce(lambda a,b: '%s | %s' % (a,b),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)
username = p['username'] = reduce(lambda a, b: '%s | %s' % (
a, b), self.subject.CN or self.subject.commonName)
p['first_name'] = reduce(lambda a, b: '%s | %s' % (a, b),
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
p['registration_id'] = self.serial
@@ -100,6 +96,3 @@ class X509Auth(object):
p['certificate'] = self.ssl_client_raw_cert
return profile
+22 -9
View File
@@ -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_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_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]')
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$')
regex_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_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*$',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*$',re.S)
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#])")
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#])")
ttab_in = 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',"'`:*~\\[]{}@$+-.#")
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])")
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])")
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\x05',"'`:*~\\[]{}@$+-.#\n")
def markmin_escape(text):
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
@@ -686,6 +686,15 @@ def render(text,
>>> render("----\\nhello world\\n----\\n")
'<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]]')
'<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]]")
'<p><audio controls="controls"><source src="http://example.com" />Your browser doesn\\'t support &lt;audio&gt; 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 &lt;audio&gt; HTML5 tag</audio></p>'
>>> render('[[this is a **link** http://example.com]]')
'<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 ''
text = str(text or '')
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:
text = replace_at_urls(text,URL)
@@ -1254,8 +1267,8 @@ def render(text,
k = escape(k)
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
target = ' target="_blank"' if p == 'popup' else ''
t = render(t, {}, {}, 'br', URL, environment, latex, autolinks,
protolinks, class_prefix, id_prefix, pretty_print) if t else k
t = render(t, {}, {}, 'br', URL, environment, latex, None,
None, class_prefix, id_prefix, pretty_print) if t else k
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
% dict(k=k, title=title, target=target, t=t)
if t == 'NEWLINE' and not a:
+61 -69
View File
@@ -44,22 +44,21 @@ SQL_DIALECTS = {'memcache': {
'is not null': 'IS NOT NULL',
'extract': None,
'left join': None,
}}
}}
def cleanup(text):
if re.compile('[^0-9a-zA-Z_]').findall(text):
raise SyntaxError, \
'Can\'t cleanup \'%s\': only [0-9a-zA-Z_] allowed in table and field names' % text
raise SyntaxError('Can\'t cleanup \'%s\': only [0-9a-zA-Z_] allowed in table and field names' % text)
return text
def assert_filter_fields(*fields):
for field in fields:
if isinstance(field, (Field, Expression)) and field.type\
in ['text', 'blob']:
raise SyntaxError, 'AppEngine does not index by: %s'\
% field.type
in ['text', 'blob']:
raise SyntaxError('AppEngine does not index by: %s'
% field.type)
def dateobj_to_datetime(object):
@@ -78,7 +77,7 @@ def dateobj_to_datetime(object):
object.minute,
object.second,
object.microsecond,
)
)
return object
@@ -96,7 +95,7 @@ def sqlhtml_validators(field_type, length):
'time': validators.IS_TIME(),
'datetime': validators.IS_DATETIME(),
'reference': validators.IS_INT_IN_RANGE(0, 1e100),
}
}
try:
return v[field_type[:9]]
except KeyError:
@@ -114,7 +113,8 @@ class DALStorage(dict):
def __setattr__(self, key, value):
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
def __repr__(self):
@@ -151,14 +151,14 @@ class MEMDB(DALStorage):
tablename,
*fields,
**args
):
):
tablename = cleanup(tablename)
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:
self.tables.append(tablename)
else:
raise SyntaxError, 'table already defined: %s' % tablename
raise SyntaxError('table already defined: %s' % tablename)
t = self[tablename] = Table(self, tablename, *fields)
t._create()
return t
@@ -190,7 +190,7 @@ class Table(DALStorage):
db,
tablename,
*fields
):
):
self._db = db
self._tablename = tablename
self.fields = SQLCallableList()
@@ -219,24 +219,24 @@ class Table(DALStorage):
if field.type[:9] == 'reference':
referenced = field.type[10:].strip()
if not referenced:
raise SyntaxError, \
'Table %s: reference \'%s\' to nothing!' % (self._tablename, k)
raise SyntaxError('Table %s: reference \'%s\' to nothing!' % (
self._tablename, k))
if not referenced in self._db:
raise SyntaxError, \
'Table: table %s does not exist' % referenced
raise SyntaxError(
'Table: table %s does not exist' % referenced)
referee = self._db[referenced]
ftype = \
self._db._translator[field.type[:9]](
self._db[referenced]._tableobj)
if self._tablename in referee.fields: # ## THIS IS OK
raise SyntaxError, \
'Field: table \'%s\' has same name as a field ' \
'in referenced table \'%s\'' % (self._tablename, referenced)
raise SyntaxError('Field: table \'%s\' has same name as a field '
'in referenced table \'%s\'' % (
self._tablename, referenced))
self._db[referenced]._referenced_by.append((self._tablename,
field.name))
field.name))
elif not field.type in self._db._translator\
or not self._db._translator[field.type]:
raise SyntaxError, 'Field: unkown field type %s' % field.type
or not self._db._translator[field.type]:
raise SyntaxError('Field: unkown field type %s' % field.type)
self._tableobj = self._db.client
return None
@@ -269,11 +269,11 @@ class Table(DALStorage):
def update(self, id, **fields):
for field in fields:
if not field in fields and self[field].default\
!= None:
is not None:
fields[field] = self[field].default
if field in fields:
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)
def delete(self, id):
@@ -293,7 +293,7 @@ class Table(DALStorage):
if self._tableobj.set(shard_id, '0'):
id = 0
else:
raise Exception, 'cannot set memcache'
raise Exception('cannot set memcache')
return long(str(shard) + str(id))
def __str__(self):
@@ -307,7 +307,7 @@ class Expression(object):
name,
type='string',
db=None,
):
):
(self.name, self.type, self._db) = (name, type, db)
def __str__(self):
@@ -393,11 +393,11 @@ class Field(Expression):
notnull=False,
unique=False,
uploadfield=True,
):
):
self.name = cleanup(fieldname)
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):
type = 'reference ' + type._tablename
if not length:
@@ -437,9 +437,9 @@ MEMDB.Field = Field # ## required by gluon/globals.py session.connect
def obj_represent(object, fieldtype, db):
if object != None:
if object is not None:
if fieldtype == 'date' and not isinstance(object,
datetime.date):
datetime.date):
(y, m, d) = [int(x) for x in str(object).strip().split('-')]
object = datetime.date(y, m, d)
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]
object = datetime.time(h, mi, s)
elif fieldtype == 'datetime' and not isinstance(object,
datetime.datetime):
datetime.datetime):
(y, m, d) = [int(x) for x in
str(object)[:10].strip().split('-')]
time_items = [int(x) for x in
@@ -466,7 +466,7 @@ def obj_represent(object, fieldtype, db):
h,
mi,
s,
)
)
elif fieldtype == 'integer' and not isinstance(object, long):
object = long(object)
@@ -496,10 +496,10 @@ class Query(object):
left,
op=None,
right=None,
):
):
if isinstance(right, (Field, Expression)):
raise SyntaxError, \
'Query: right side of filter must be a value or entity'
raise SyntaxError(
'Query: right side of filter must be a value or entity')
if isinstance(left, Field) and left.name == 'id':
if op == '=':
self.get_one = \
@@ -507,8 +507,8 @@ class Query(object):
id=long(right))
return
else:
raise SyntaxError, 'only equality by id is supported'
raise SyntaxError, 'not supported'
raise SyntaxError('only equality by id is supported')
raise SyntaxError('not supported')
def __str__(self):
return str(self.left)
@@ -539,7 +539,7 @@ class Set(object):
self.where = where
self._tables.insert(0, where.get_all)
elif hasattr(where, 'get_one') and isinstance(where.get_one,
QueryException):
QueryException):
self.where = where.get_one
else:
@@ -553,9 +553,8 @@ class Set(object):
def __call__(self, where):
if isinstance(self.where, QueryException) or isinstance(where,
QueryException):
raise SyntaxError, \
'neither self.where nor where can be a QueryException instance'
QueryException):
raise SyntaxError('neither self.where nor where can be a QueryException instance')
if self.where:
return Set(self._db, self.where & where)
else:
@@ -564,9 +563,9 @@ class Set(object):
def _get_table_or_raise(self):
tablenames = list(set(self._tables)) # unique
if len(tablenames) < 1:
raise SyntaxError, 'Set: no tables selected'
raise SyntaxError('Set: no tables selected')
if len(tablenames) > 1:
raise SyntaxError, 'Set: no join in appengine'
raise SyntaxError('Set: no join in appengine')
return self._db[tablenames[0]]._tableobj
def _getitem_exception(self):
@@ -597,7 +596,7 @@ class Set(object):
if isinstance(self.where, QueryException):
return self._select_except()
else:
raise SyntaxError, 'select arguments not supported'
raise SyntaxError('select arguments not supported')
def count(self):
return len(self.select())
@@ -609,7 +608,7 @@ class Set(object):
return
self._db[tablename].delete(id)
else:
raise Exception, 'deletion not implemented'
raise Exception('deletion not implemented')
def update(self, **update_fields):
if isinstance(self.where, QueryException):
@@ -620,7 +619,7 @@ class Set(object):
setattr(item, key, value)
self._db[tablename].update(id, **item)
else:
raise Exception, 'update not implemented'
raise Exception('update not implemented')
def update_record(
@@ -628,7 +627,7 @@ def update_record(
s,
id,
a,
):
):
item = s.get(id)
for (key, value) in a.items():
t[key] = value
@@ -650,7 +649,7 @@ class Rows(object):
db,
response,
*colnames
):
):
self._db = db
self.colnames = colnames
self.response = response
@@ -660,9 +659,9 @@ class Rows(object):
def __getitem__(self, i):
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):
raise SyntaxError, 'Rows: internal error'
raise SyntaxError('Rows: internal error')
row = DALStorage()
for j in xrange(len(self.colnames)):
value = self.response[i][j]
@@ -684,7 +683,7 @@ class Rows(object):
referee = field.type[10:].strip()
rid = value
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)
@@ -692,13 +691,13 @@ class Rows(object):
row[tablename][fieldname] = True
else:
row[tablename][fieldname] = False
elif field.type == 'date' and value != None\
and not isinstance(value, datetime.date):
elif field.type == 'date' and value is not None\
and not isinstance(value, datetime.date):
(y, m, d) = [int(x) for x in
str(value).strip().split('-')]
row[tablename][fieldname] = datetime.date(y, m, d)
elif field.type == 'time' and value != None\
and not isinstance(value, datetime.time):
elif field.type == 'time' and value is not None\
and not isinstance(value, datetime.time):
time_items = [int(x) for x in
str(value).strip().split(':')[:3]]
if len(time_items) == 3:
@@ -706,8 +705,8 @@ class Rows(object):
else:
(h, mi, s) = time_items + [0]
row[tablename][fieldname] = datetime.time(h, mi, s)
elif field.type == 'datetime' and value != None\
and not isinstance(value, datetime.datetime):
elif field.type == 'datetime' and value is not None\
and not isinstance(value, datetime.datetime):
(y, m, d) = [int(x) for x in
str(value)[:10].strip().split('-')]
time_items = [int(x) for x in
@@ -723,19 +722,19 @@ class Rows(object):
h,
mi,
s,
)
)
else:
row[tablename][fieldname] = value
if fieldname == 'id':
id = row[tablename].id
row[tablename].update_record = lambda t = row[tablename], \
s = self._db[tablename], id = id, **a: update_record(t,
s, id, a)
s, id, a)
for (referee_table, referee_name) in \
table._referenced_by:
table._referenced_by:
s = self._db[referee_table][referee_name]
row[tablename][referee_table] = Set(self._db, s
== id)
== id)
if len(row.keys()) == 1:
return row[row.keys()[0]]
return row
@@ -905,10 +904,3 @@ SQLStorage = DALStorage
if __name__ == '__main__':
import doctest
doctest.testmod()
+33 -32
View File
@@ -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
@@ -20,7 +20,7 @@ __version__ = '0.1.4'
def remove_comments(css):
"""Remove all CSS comment blocks."""
iemac = False
preserve = False
comment_start = css.find("/*")
@@ -28,7 +28,7 @@ def remove_comments(css):
# Preserve comments that look like `/*!...*/`.
# Slicing is used to make sure we don"t get an IndexError.
preserve = css[comment_start + 2:comment_start + 3] == "!"
comment_end = css.find("*/", comment_start + 2)
if comment_end < 0:
if not preserve:
@@ -48,22 +48,22 @@ def remove_comments(css):
else:
comment_start = comment_end + 2
comment_start = css.find("/*", comment_start)
return css
def remove_unnecessary_whitespace(css):
"""Remove unnecessary whitespace characters."""
def pseudoclasscolon(css):
"""
Prevents 'p :link' from becoming 'p:link'.
Translates 'p :link' into 'p ___PSEUDOCLASSCOLON___link'; this is
translated back again later.
"""
regex = re.compile(r"(^|\})(([^\{\:])+\:)+([^\{]*\{)")
match = regex.search(css)
while match:
@@ -73,43 +73,43 @@ def remove_unnecessary_whitespace(css):
css[match.end():]])
match = regex.search(css)
return css
css = pseudoclasscolon(css)
# Remove spaces from before things.
css = re.sub(r"\s+([!{};:>+\(\)\],])", r"\1", css)
# 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"^(\s*@charset [^;]+;\s*)+", r"\1", css)
# Put the space back in for a few cases, such as `@media screen` and
# `(-webkit-min-device-pixel-ratio:0)`.
css = re.sub(r"\band\(", "and (", css)
# Put the colons back.
css = css.replace('___PSEUDOCLASSCOLON___', ':')
# Remove spaces from after things.
css = re.sub(r"([!{}:;>+\(\[,])\s+", r"\1", css)
return css
def remove_unnecessary_semicolons(css):
"""Remove unnecessary semicolons."""
return re.sub(r";+\}", "}", css)
def remove_empty_rules(css):
"""Remove empty rules."""
return re.sub(r"[^\}\{]+\{\}", "", css)
def normalize_rgb_colors_to_hex(css):
"""Convert `rgb(51,102,153)` to `#336699`."""
regex = re.compile(r"rgb\s*\(\s*([0-9,\s]+)\s*\)")
match = regex.search(css)
while match:
@@ -122,39 +122,40 @@ def normalize_rgb_colors_to_hex(css):
def condense_zero_units(css):
"""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)
def condense_multidimensional_zeros(css):
"""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;")
css = css.replace(":0 0;", ":0;")
# Revert `background-position:0;` to the valid `background-position:0 0;`.
css = css.replace("background-position:0;", "background-position:0 0;")
return css
def condense_floating_points(css):
"""Replace `0.6` with `.6` where possible."""
return re.sub(r"(:|\s)0+\.(\d+)", r"\1.\2", css)
def condense_hex_colors(css):
"""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])")
match = regex.search(css)
while match:
first = match.group(3) + match.group(5) + match.group(7)
second = match.group(4) + match.group(6) + match.group(8)
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)
else:
match = regex.search(css, match.end())
@@ -163,19 +164,19 @@ def condense_hex_colors(css):
def condense_whitespace(css):
"""Condense multiple adjacent whitespace characters into one."""
return re.sub(r"\s+", " ", css)
def condense_semicolons(css):
"""Condense multiple adjacent semicolon characters into one."""
return re.sub(r";;+", ";", css)
def wrap_css_lines(css, line_length):
"""Wrap the lines of the given CSS to an approximate length."""
lines = []
line_start = 0
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):
lines.append(css[line_start:i + 1])
line_start = i + 1
if line_start < len(css):
lines.append(css[line_start:])
return '\n'.join(lines)
@@ -212,19 +213,19 @@ def cssmin(css, wrap=None):
def main():
import optparse
import sys
p = optparse.OptionParser(
prog="cssmin", version=__version__,
usage="%prog [--wrap N]",
description="""Reads raw CSS from stdin, and writes compressed CSS to stdout.""")
p.add_option(
'-w', '--wrap', type='int', default=None, metavar='N',
help="Wrap output to approximately N chars per line.")
options, args = p.parse_args()
sys.stdout.write(cssmin(sys.stdin.read(), wrap=options.wrap))
if __name__ == '__main__':
main()
main()
+10 -8
View File
@@ -2,12 +2,14 @@
import re
def minify(response):
def _replace(match):
match = match.group()
# save whole <pre>, <textarea> tags, and opening <!-- (so it doesn't break <script>)
# otherwise, replace all whitespace with a single space character
return match if match.startswith(('<pre', '<textarea', '<!--')) else ' '
cpat = re.compile(r'\s+|<pre(.*?)</pre>|<textarea(.*?)</textarea>|<!--\s', re.DOTALL)
return cpat.sub(_replace, response)
def _replace(match):
match = match.group()
# save whole <pre>, <textarea> tags, and opening <!-- (so it doesn't break <script>)
# otherwise, replace all whitespace with a single space character
return match if match.startswith(('<pre', '<textarea', '<!--')) else ' '
cpat = re.compile(
r'\s+|<pre(.*?)</pre>|<textarea(.*?)</textarea>|<!--\s', re.DOTALL)
return cpat.sub(_replace, response)
+44 -27
View File
@@ -49,7 +49,7 @@ Both python 2 and python 3 are supported.
.. _jsmin.c by Douglas Crockford:
http://www.crockford.com/javascript/jsmin.c
Original author of Python version: Andr\xe9 Malo
Home page: http://opensource.perlig.de/rjsmin/
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:
xrange
except NameError:
xrange = range # pylint: disable = W0622
xrange = range # pylint: disable = W0622
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 ''
) for first, last in result])
return _re.sub(r'([\000-\040\047])', # for better portability
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
.replace('\\', '\\\\')
.replace('[', '\\[')
.replace(']', '\\]')
)
)
return _re.sub(r'([\000-\040\047])', # for better portability
lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result)
.replace('\\', '\\\\')
.replace('[', '\\[')
.replace(']', '\\]')
)
)
def id_literal_(what):
""" 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'|(?:(?<=%(preregex2)s)%(space)s*(%(regex)s[^\047"/\000-\040]*))'
r'|(?<=%(id_literal_close)s)'
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
r'(?=%(id_literal_open)s)'
r'%(space)s*(?:(%(newline)s)%(space)s*)+'
r'(?=%(id_literal_open)s)'
r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)'
r'|%(space)s+'
r'|(?:%(newline)s%(space)s*)+'
) % locals()).sub
def space_subber(match):
""" Substitution callback """
# pylint: disable = C0321, R0911
groups = match.groups()
if groups[0]: return groups[0]
elif groups[1]: return groups[1]
elif groups[2]: return groups[2]
elif groups[3]: return groups[3]
elif groups[4]: return '\n'
elif groups[5]: return ' '
else: return ''
if groups[0]:
return groups[0]
elif groups[1]:
return groups[1]
elif groups[2]:
return groups[2]
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"""
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'|(?:(%(newline)s)%(space)s*)+'
) % locals()).sub
def space_norm_subber(match):
""" Substitution callback """
# pylint: disable = C0321
groups = match.groups()
if groups[0]: return groups[0]
elif groups[1]: return groups[1].replace('\r', '\n') + groups[2]
elif groups[3]: return ' '
elif groups[4]: return '\n'
if groups[0]:
return groups[0]
elif groups[1]:
return groups[1].replace('\r', '\n') + groups[2]
elif groups[3]:
return ' '
elif groups[4]:
return '\n'
space_sub1 = _re.compile((
r'[\040\n]?(%(strings)s|%(pre_regex)s%(regex)s)'
r'|\040(%(not_id_literal)s)'
r'|\n(%(not_id_literal_open)s)'
) % locals()).sub
def space_subber1(match):
""" Substitution callback """
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_close)s)\n'
) % locals()).sub
def space_subber2(match):
""" Substitution callback """
groups = match.groups()
@@ -295,10 +310,11 @@ def _make_jsmin(extended=True, python_only=True):
:Rtype: ``str``
"""
return space_sub2(space_subber2,
space_sub1(space_subber1,
space_norm_sub(space_norm_subber, '\n%s\n' % script)
)
).strip()
space_sub1(space_subber1,
space_norm_sub(space_norm_subber,
'\n%s\n' % script)
)
).strip()
return jsmin
jsmin = _make_jsmin()
@@ -311,6 +327,7 @@ jsmin = _make_jsmin()
# jsmin.jsmin(script)
#
def jsmin_for_posers(script):
r"""
Minify javascript based on `jsmin.c by Douglas Crockford`_\.
+30 -28
View File
@@ -14,24 +14,27 @@ import os
import hashlib
import re
def read_binary_file(filename):
f = open(filename,'rb')
f = open(filename, 'rb')
data = f.read()
f.close()
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.close()
def fix_links(css,static_path):
def fix_links(css, static_path):
return re.sub(r'url\((["\'])\.\./', 'url(\\1' + static_path, css)
def minify(files, path_info, folder, optimize_css, optimize_js,
ignore_concat = [],
ignore_minify = ['/jquery.js', '/anytime.js']):
ignore_concat=[],
ignore_minify=['/jquery.js', '/anytime.js']):
"""
Input:
@@ -45,7 +48,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
Returns a new list of:
- filename (absolute or relative, css or js, actual or temporary) or
- ('css:inline','...css..')
- ('js:inline','...js..')
- ('js:inline','...js..')
"""
optimize_css = optimize_css 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
minify_js = 'minify' 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 = []
css = []
js = []
processed = []
for k,filename in enumerate(files):
for k, filename in enumerate(files):
if not filename.startswith('/') or \
any(filename.endswith(x) \
for x in ignore_concat):
any(filename.endswith(x)
for x in ignore_concat):
new_files.append(filename)
continue
abs_filename = os.path.join(
folder,'static', filename[len(static_path)+1:])
folder, 'static', filename[len(static_path) + 1:])
if filename.lower().endswith('.css'):
processed.append(filename)
spath_info, sfilename = \
path_info.split('/'), filename.split('/')
u = 0
for i,a in enumerate(sfilename):
for i, a in enumerate(sfilename):
try:
if a != spath_info[i]:
u = i
@@ -99,8 +102,8 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
if minify_js and \
not filename.endswith('.min.js') and \
not any(filename.endswith(x) \
for x in ignore_minify):
not any(filename.endswith(x)
for x in ignore_minify):
js.append(jsmin.jsmin(contents))
else:
js.append(contents)
@@ -110,32 +113,31 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
if css and concat_css:
css = '\n\n'.join(contents for contents in 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):
os.mkdir(temppath)
dest = "compressed_%s.css" % dest_key
tempfile = os.path.join(temppath, dest)
write_binary_file(tempfile,css)
css = path_info+'/%s' % dest
write_binary_file(tempfile, css)
css = path_info + '/%s' % dest
new_files.append(css)
else:
new_files.append(('css:inline',css))
new_files.append(('css:inline', css))
else:
new_files += css
if js and concat_js:
js = '\n'.join(contents for contents in js)
if inline_js:
js = ('js:inline',js)
js = ('js:inline', js)
else:
temppath = os.path.join(folder,'static',temp)
if not os.path.exists(temppath):
temppath = os.path.join(folder, 'static', temp)
if not os.path.exists(temppath):
os.mkdir(temppath)
dest = "compressed_%s.js" % dest_key
tempfile = os.path.join(folder,'static',temp,dest)
write_binary_file(tempfile,js)
js = path_info+'/%s' % dest
tempfile = os.path.join(folder, 'static', temp, dest)
write_binary_file(tempfile, js)
js = path_info + '/%s' % dest
new_files.append(js)
else:
new_files += js
return new_files
+20 -22
View File
@@ -24,7 +24,7 @@ CALLOC.argtypes = [c_uint, c_uint]
STRDUP = LIBC.strdup
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
PAM_PROMPT_ECHO_OFF = 1
@@ -32,56 +32,61 @@ PAM_PROMPT_ECHO_ON = 2
PAM_ERROR_MSG = 3
PAM_TEXT_INFO = 4
class PamHandle(Structure):
"""wrapper class for pam_handle_t"""
_fields_ = [
("handle", c_void_p)
]
("handle", c_void_p)
]
def __init__(self):
Structure.__init__(self)
self.handle = 0
class PamMessage(Structure):
"""wrapper class for pam_message structure"""
_fields_ = [
("msg_style", c_int),
("msg", c_char_p),
]
("msg_style", c_int),
("msg", c_char_p),
]
def __repr__(self):
return "<PamMessage %i '%s'>" % (self.msg_style, self.msg)
class PamResponse(Structure):
"""wrapper class for pam_response structure"""
_fields_ = [
("resp", c_char_p),
("resp_retcode", c_int),
]
("resp", c_char_p),
("resp_retcode", c_int),
]
def __repr__(self):
return "<PamResponse %i '%s'>" % (self.resp_retcode, self.resp)
CONV_FUNC = CFUNCTYPE(c_int,
c_int, POINTER(POINTER(PamMessage)),
POINTER(POINTER(PamResponse)), c_void_p)
c_int, POINTER(POINTER(PamMessage)),
POINTER(POINTER(PamResponse)), c_void_p)
class PamConv(Structure):
"""wrapper class for pam_conv structure"""
_fields_ = [
("conv", CONV_FUNC),
("appdata_ptr", c_void_p)
]
("conv", CONV_FUNC),
("appdata_ptr", c_void_p)
]
PAM_START = LIBPAM.pam_start
PAM_START.restype = c_int
PAM_START.argtypes = [c_char_p, c_char_p, POINTER(PamConv),
POINTER(PamHandle)]
POINTER(PamHandle)]
PAM_AUTHENTICATE = LIBPAM.pam_authenticate
PAM_AUTHENTICATE.restype = c_int
PAM_AUTHENTICATE.argtypes = [PamHandle, c_int]
def authenticate(username, password, service='login'):
"""Returns True if the given username and password authenticate for the
given service. Returns False otherwise
@@ -121,10 +126,3 @@ def authenticate(username, password, service='login'):
if __name__ == "__main__":
import getpass
print authenticate(getpass.getuser(), getpass.getpass())

Some files were not shown because too many files have changed in this diff Show More