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 ## 2.1.0
- overall faster web2py - 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 wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
echo "remember that pymysql was tweaked" echo "remember that pymysql was tweaked"
src: src:
echo 'Version 2.1.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION echo 'Version 2.2.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
### rm -f all junk files ### rm -f all junk files
make clean make clean
### clean up baisc apps ### clean up baisc apps
@@ -130,5 +130,5 @@ pip:
# after upload clean Web2py sources with rm -R ./dist # after upload clean Web2py sources with rm -R ./dist
# http://guide.python-distribute.org/creation.html # http://guide.python-distribute.org/creation.html
python setup.py sdist python setup.py sdist
python setup.py register sudo python setup.py register
python setup.py sdist upload sudo python setup.py sdist upload
+1 -1
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 @@
+41 -22
View File
@@ -9,13 +9,18 @@ License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
This file is based, although a rewrite, on MIT-licensed code from the Bottle web framework. This file is based, although a rewrite, on MIT-licensed code from the Bottle web framework.
""" """
import os, sys, optparse, urllib import os
import sys
import optparse
import urllib
path = os.path.dirname(os.path.abspath(__file__)) path = os.path.dirname(os.path.abspath(__file__))
os.chdir(path) os.chdir(path)
sys.path = [path] + [p for p in sys.path if not p == path] sys.path = [path] + [p for p in sys.path if not p == path]
import gluon.main import gluon.main
from gluon.fileutils import read_file, write_file from gluon.fileutils import read_file, write_file
class Servers: class Servers:
@staticmethod @staticmethod
def cgi(app, address=None, **options): def cgi(app, address=None, **options):
@@ -30,8 +35,10 @@ class Servers:
@staticmethod @staticmethod
def wsgiref(app, address, **options): # pragma: no cover def wsgiref(app, address, **options): # pragma: no cover
from wsgiref.simple_server import make_server, WSGIRequestHandler from wsgiref.simple_server import make_server, WSGIRequestHandler
class QuietHandler(WSGIRequestHandler): class QuietHandler(WSGIRequestHandler):
def log_request(*args, **kw): pass def log_request(*args, **kw):
pass
options['handler_class'] = QuietHandler options['handler_class'] = QuietHandler
srv = make_server(address[0], address[1], app, **options) srv = make_server(address[0], address[1], app, **options)
srv.serve_forever() srv.serve_forever()
@@ -76,19 +83,21 @@ class Servers:
from fapws import base from fapws import base
evwsgi.start(address[0], str(address[1])) evwsgi.start(address[0], str(address[1]))
evwsgi.set_base_module(base) evwsgi.set_base_module(base)
def app(environ, start_response): def app(environ, start_response):
environ['wsgi.multiprocess'] = False environ['wsgi.multiprocess'] = False
return app(environ, start_response) return app(environ, start_response)
evwsgi.wsgi_cb(('', app)) evwsgi.wsgi_cb(('', app))
evwsgi.run() evwsgi.run()
@staticmethod @staticmethod
def gevent(app, address, **options): def gevent(app, address, **options):
from gevent import monkey; monkey.patch_all() from gevent import monkey
monkey.patch_all()
from gevent import pywsgi from gevent import pywsgi
from gevent.pool import Pool from gevent.pool import Pool
pywsgi.WSGIServer(address, app, spawn = 'workers' in options and Pool(int(options.workers)) or 'default').serve_forever() pywsgi.WSGIServer(address, app, spawn='workers' in options and Pool(
int(options.workers)) or 'default').serve_forever()
@staticmethod @staticmethod
def bjoern(app, address, **options): def bjoern(app, address, **options):
@@ -129,9 +138,11 @@ class Servers:
config = {'bind': "%s:%d" % address} config = {'bind': "%s:%d" % address}
config.update(options) config.update(options)
sys.argv = ['anyserver.py'] sys.argv = ['anyserver.py']
class GunicornApplication(Application): class GunicornApplication(Application):
def init(self, parser, opts, args): def init(self, parser, opts, args):
return config return config
def load(self): def load(self):
return app return app
g = GunicornApplication() g = GunicornApplication()
@@ -165,6 +176,7 @@ def run(servername,ip,port,softcron=True,logging=False,profiler=None):
global_settings.web2py_crontype = 'soft' global_settings.web2py_crontype = 'soft'
getattr(Servers, servername)(application, (ip, int(port))) getattr(Servers, servername)(application, (ip, int(port)))
def mongrel2_handler(application, conn, debug=False): def mongrel2_handler(application, conn, debug=False):
""" """
Based on : Based on :
@@ -190,14 +202,17 @@ def mongrel2_handler(application,conn,debug=False):
# and responses. Unless I have missed something. # and responses. Unless I have missed something.
while True: while True:
if debug: print "WAITING FOR REQUEST" if debug:
print "WAITING FOR REQUEST"
# receive a request # receive a request
req = conn.recv() req = conn.recv()
if debug: print "REQUEST BODY: %r\n" % req.body if debug:
print "REQUEST BODY: %r\n" % req.body
if req.is_disconnect(): if req.is_disconnect():
if debug: print "DISCONNECT" if debug:
print "DISCONNECT"
continue # effectively ignore the disconnect from the client continue # effectively ignore the disconnect from the client
# Set a couple of environment attributes a.k.a. header attributes # Set a couple of environment attributes a.k.a. header attributes
@@ -217,11 +232,13 @@ def mongrel2_handler(application,conn,debug=False):
environ['QUERY_STRING'] = environ['URI'].split('?')[1] environ['QUERY_STRING'] = environ['URI'].split('?')[1]
else: else:
environ['QUERY_STRING'] = '' environ['QUERY_STRING'] = ''
if environ.has_key('Content-Length'): if 'Content-Length' in environ:
environ['CONTENT_LENGTH'] = environ['Content-Length'] # necessary for POST to work with Django environ['CONTENT_LENGTH'] = environ[
'Content-Length'] # necessary for POST to work with Django
environ['wsgi.input'] = req.body environ['wsgi.input'] = req.body
if debug: print "ENVIRON: %r\n" % environ if debug:
print "ENVIRON: %r\n" % environ
# SimpleHandler needs file-like stream objects for # SimpleHandler needs file-like stream objects for
# requests, errors and responses # requests, errors and responses
@@ -230,7 +247,8 @@ def mongrel2_handler(application,conn,debug=False):
respIO = StringIO.StringIO() respIO = StringIO.StringIO()
# execute the application # execute the application
handler = SimpleHandler(reqIO, respIO, errIO, environ, multithread = False, multiprocess = False) handler = SimpleHandler(reqIO, respIO, errIO, environ,
multithread=False, multiprocess=False)
handler.run(application) handler.run(application)
# Get the response and filter out the response (=data) itself, # Get the response and filter out the response (=data) itself,
@@ -254,11 +272,15 @@ def mongrel2_handler(application,conn,debug=False):
errors = errIO.getvalue() errors = errIO.getvalue()
# return the response # return the response
if debug: print "RESPONSE: %r\n" % response if debug:
print "RESPONSE: %r\n" % response
if errors: if errors:
if debug: print "ERRORS: %r" % errors if debug:
print "ERRORS: %r" % errors
data = "%s\r\n\r\n%s" % (data, errors) data = "%s\r\n\r\n%s" % (data, errors)
conn.reply_http(req, data, code = code, status = status, headers = headers) conn.reply_http(
req, data, code=code, status=status, headers=headers)
def main(): def main():
usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P" usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P"
@@ -300,13 +322,10 @@ def main():
dest='workers', dest='workers',
help='number of workers number') help='number of workers number')
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
print 'starting %s on %s:%s...' % (options.server,options.ip,options.port) print 'starting %s on %s:%s...' % (
run(options.server,options.ip,options.port,logging=options.logging,profiler=options.profiler) options.server, options.ip, options.port)
run(options.server, options.ip, options.port,
logging=options.logging, profiler=options.profiler)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
-5
View File
@@ -2,8 +2,3 @@ def webapp_add_wsgi_middleware(app):
from google.appengine.ext.appstats import recording from google.appengine.ext.appstats import recording
app = recording.appstats_wsgi_middleware(app) app = recording.appstats_wsgi_middleware(app)
return app return app
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+36 -20
View File
@@ -102,17 +102,16 @@ def query_by_table_type(tablename,db,request=request):
cond = '>0' cond = '>0'
if firstkey.type in ['string', 'text']: if firstkey.type in ['string', 'text']:
cond = '!=""' cond = '!=""'
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond) qry = '%s.%s.%s%s' % (
request.args[0], request.args[1], firstkey.name, cond)
else: else:
qry = '%s.%s.id>0' % tuple(request.args[:2]) qry = '%s.%s.id>0' % tuple(request.args[:2])
return qry return qry
# ########################################################## # ##########################################################
# ## list all databases and tables # ## list all databases and tables
# ########################################################### # ###########################################################
def index(): def index():
return dict(databases=databases) return dict(databases=databases)
@@ -140,6 +139,7 @@ def download():
db = get_database(request) db = get_database(request)
return response.download(request, db) return response.download(request, db)
def csv(): def csv():
import gluon.contenttype import gluon.contenttype
response.headers['Content-Type'] = \ response.headers['Content-Type'] = \
@@ -156,6 +156,7 @@ def csv():
def import_csv(table, file): def import_csv(table, file):
table.import_from_csv_file(file) table.import_from_csv_file(file)
def select(): def select():
import re import re
db = get_database(request) db = get_database(request)
@@ -192,7 +193,8 @@ def select():
session.last_query = request.vars.query session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px', form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_name='query', _value=request.vars.query or '', _name='query', _value=request.vars.query or '',
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'), requires=IS_NOT_EMPTY(
error_message=T("Cannot be empty")))), TR(T('Update:'),
INPUT(_name='update_check', _type='checkbox', INPUT(_name='update_check', _type='checkbox',
value=False), INPUT(_style='width:400px', value=False), INPUT(_style='width:400px',
_name='update_fields', _value=request.vars.update_fields _name='update_fields', _value=request.vars.update_fields
@@ -200,13 +202,14 @@ def select():
_class='delete', _type='checkbox', value=False), ''), _class='delete', _type='checkbox', value=False), ''),
TR('', '', INPUT(_type='submit', _value=T('submit')))), TR('', '', INPUT(_type='submit', _value=T('submit')))),
_action=URL(r=request, args=request.args)) _action=URL(r=request, args=request.args))
tb = None
if form.accepts(request.vars, formname=None): if form.accepts(request.vars, formname=None):
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+') regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
match = regex.match(form.vars.query.strip()) match = regex.match(form.vars.query.strip())
if match: if match:
table = match.group('table') table = match.group('table')
try: try:
tb = None
nrows = db(query).count() nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields: if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)' db(query).update(**eval_in_global_env('dict(%s)'
@@ -217,9 +220,11 @@ def select():
response.flash = T('%s %%{row} deleted', nrows) response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count() nrows = db(query).count()
if orderby: if orderby:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby)) rows = db(query, ignore_common_filters=True).select(limitby=(
start, stop), orderby=eval_in_global_env(orderby))
else: else:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) rows = db(query, ignore_common_filters=True).select(
limitby=(start, stop))
except Exception, e: except Exception, e:
import traceback import traceback
tb = traceback.format_exc() tb = traceback.format_exc()
@@ -268,9 +273,11 @@ def update():
if keyed: if keyed:
key = [f for f in request.vars if f in db[table]._primarykey] key = [f for f in request.vars if f in db[table]._primarykey]
if key: if key:
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first() record = db(db[table][key[0]] == request.vars[key[
0]], ignore_common_filters=True).select().first()
else: else:
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first() record = db(db[table].id == request.args(
2), ignore_common_filters=True).select().first()
if not record: if not record:
qry = query_by_table_type(table, db) qry = query_by_table_type(table, db)
@@ -282,7 +289,8 @@ def update():
for k in db[table]._primarykey: for k in db[table]._primarykey:
db[table][k].writable = False db[table][k].writable = False
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'), form = SQLFORM(
db[table], record, deletable=True, delete_label=T('Check to delete'),
ignore_rw=ignore_rw and not keyed, ignore_rw=ignore_rw and not keyed,
linkto=URL('select', linkto=URL('select',
args=request.args[:1]), upload=URL(r=request, args=request.args[:1]), upload=URL(r=request,
@@ -304,11 +312,15 @@ def update():
def state(): def state():
return dict() return dict()
def ccache(): def ccache():
form = FORM( form = FORM(
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")), P(TAG.BUTTON(
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")), T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")), P(TAG.BUTTON(
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
P(TAG.BUTTON(
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
) )
if form.accepts(request.vars, session): if form.accepts(request.vars, session):
@@ -332,11 +344,16 @@ def ccache():
redirect(URL(r=request)) redirect(URL(r=request))
try: try:
from guppy import hpy; hp=hpy() from guppy import hpy
hp = hpy()
except ImportError: except ImportError:
hp = False hp = False
import shelve, os, copy, time, math import shelve
import os
import copy
import time
import math
from gluon import portalocker from gluon import portalocker
ram = { ram = {
@@ -383,7 +400,8 @@ def ccache():
locker = open(os.path.join(request.folder, locker = open(os.path.join(request.folder,
'cache/cache.lock'), 'a') 'cache/cache.lock'), 'a')
portalocker.lock(locker, portalocker.LOCK_EX) portalocker.lock(locker, portalocker.LOCK_EX)
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve')) disk_storage = shelve.open(
os.path.join(request.folder, 'cache/cache.shelve'))
try: try:
for key, value in disk_storage.items(): for key, value in disk_storage.items():
if isinstance(value, dict): if isinstance(value, dict):
@@ -414,7 +432,8 @@ def ccache():
total['misses'] = ram['misses'] + disk['misses'] total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys'] total['keys'] = ram['keys'] + disk['keys']
try: try:
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses']) total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
except (KeyError, ZeroDivisionError): except (KeyError, ZeroDivisionError):
total['ratio'] = 0 total['ratio'] = 0
@@ -440,6 +459,3 @@ def ccache():
return dict(form=form, total=total, return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False) ram=ram, disk=disk, object_stats=hp != False)
+11 -2
View File
@@ -5,7 +5,8 @@ import gluon.contrib.shell
import gluon.dal import gluon.dal
import gluon.html import gluon.html
import gluon.validators import gluon.validators
import code, thread import code
import thread
from gluon.debug import communicate, web_debugger, qdb_debugger from gluon.debug import communicate, web_debugger, qdb_debugger
import pydoc import pydoc
@@ -16,6 +17,7 @@ if DEMO_MODE or MULTI_USER_MODE:
FE = 10 ** 9 FE = 10 ** 9
def index(): def index():
app = request.args(0) or 'admin' app = request.args(0) or 'admin'
reset() reset()
@@ -23,6 +25,7 @@ def index():
data = communicate() data = communicate()
return dict(app=app, data=data) return dict(app=app, data=data)
def callback(): def callback():
app = request.args[0] app = request.args[0]
command = request.vars.statement command = request.vars.statement
@@ -31,6 +34,7 @@ def callback():
k = len(session['debug_commands:' + app]) - 1 k = len(session['debug_commands:' + app]) - 1
return '[%i] %s%s\n' % (k + 1, command, output) return '[%i] %s%s\n' % (k + 1, command, output)
def reset(): def reset():
app = request.args(0) or 'admin' app = request.args(0) or 'admin'
session['debug_commands:' + app] = [] session['debug_commands:' + app] = []
@@ -81,26 +85,32 @@ def interact():
f_globals=f_globals, f_locals=f_locals, f_globals=f_globals, f_locals=f_locals,
exception=web_debugger.exception_info) exception=web_debugger.exception_info)
def step(): def step():
web_debugger.do_step() web_debugger.do_step()
redirect(URL("interact")) redirect(URL("interact"))
def next(): def next():
web_debugger.do_next() web_debugger.do_next()
redirect(URL("interact")) redirect(URL("interact"))
def cont(): def cont():
web_debugger.do_continue() web_debugger.do_continue()
redirect(URL("interact")) redirect(URL("interact"))
def ret(): def ret():
web_debugger.do_return() web_debugger.do_return()
redirect(URL("interact")) redirect(URL("interact"))
def stop(): def stop():
web_debugger.do_quit() web_debugger.do_quit()
redirect(URL("interact")) redirect(URL("interact"))
def execute(): def execute():
app = request.args[0] app = request.args[0]
command = request.vars.statement command = request.vars.statement
@@ -198,4 +208,3 @@ def toggle_breakpoint():
except Exception, e: except Exception, e:
session.flash = str(e) session.flash = str(e)
return response.json({'ok': ok, 'lineno': lineno}) return response.json({'ok': ok, 'lineno': lineno})
+125 -52
View File
@@ -39,26 +39,33 @@ if FILTER_APPS and request.args(0) and not request.args(0) in FILTER_APPS:
redirect(URL('site')) redirect(URL('site'))
if not session.token: session.token = web2py_uuid() if not session.token:
session.token = web2py_uuid()
def count_lines(data): def count_lines(data):
return len([line for line in data.split('\n') if line.strip() and not line.startswith('#')]) return len([line for line in data.split('\n') if line.strip() and not line.startswith('#')])
def log_progress(app, mode='EDIT', filename=None, progress=0): def log_progress(app, mode='EDIT', filename=None, progress=0):
progress_file = os.path.join(apath(app, r=request), 'progress.log') progress_file = os.path.join(apath(app, r=request), 'progress.log')
now = str(request.now)[:19] now = str(request.now)[:19]
if not os.path.exists(progress_file): if not os.path.exists(progress_file):
safe_open(progress_file, 'w').write('[%s] START\n' % now) safe_open(progress_file, 'w').write('[%s] START\n' % now)
if filename: if filename:
safe_open(progress_file,'a').write('[%s] %s %s: %s\n' % (now,mode,filename,progress)) safe_open(progress_file, 'a').write(
'[%s] %s %s: %s\n' % (now, mode, filename, progress))
def safe_open(a, b): def safe_open(a, b):
if DEMO_MODE and ('w' in b or 'a' in b): if DEMO_MODE and ('w' in b or 'a' in b):
class tmp: class tmp:
def write(self,data): pass def write(self, data):
pass
return tmp() return tmp()
return open(a, b) return open(a, b)
def safe_read(a, b='r'): def safe_read(a, b='r'):
safe_file = safe_open(a, b) safe_file = safe_open(a, b)
try: try:
@@ -66,6 +73,7 @@ def safe_read(a, b='r'):
finally: finally:
safe_file.close() safe_file.close()
def safe_write(a, value, b='w'): def safe_write(a, value, b='w'):
safe_file = safe_open(a, b) safe_file = safe_open(a, b)
try: try:
@@ -73,14 +81,16 @@ def safe_write(a, value, b='w'):
finally: finally:
safe_file.close() safe_file.close()
def get_app(name=None): def get_app(name=None):
app = name or request.args(0) app = name or request.args(0)
if app and (not MULTI_USER_MODE or is_manager() or \ if app and (not MULTI_USER_MODE or is_manager() or
db(db.app.name == app)(db.app.owner == auth.user.id).count()): db(db.app.name == app)(db.app.owner == auth.user.id).count()):
return app return app
session.flash = T('App does not exist or your are not authorized') session.flash = T('App does not exist or your are not authorized')
redirect(URL('site')) redirect(URL('site'))
def index(): def index():
""" Index handler """ """ Index handler """
@@ -137,9 +147,10 @@ def check_version():
return SPAN('You should upgrade to version %s.%s.%s' % version_number[:3]) return SPAN('You should upgrade to version %s.%s.%s' % version_number[:3])
else: else:
return sp_button(URL('upgrade_web2py'), T('upgrade now')) \ return sp_button(URL('upgrade_web2py'), T('upgrade now')) \
+ XML(' <strong class="upgrade_version">%s.%s.%s</strong>' \ + XML(' <strong class="upgrade_version">%s.%s.%s</strong>'
% version_number[:3]) % version_number[:3])
def logout(): def logout():
""" Logout handler """ """ Logout handler """
session.authorized = None session.authorized = None
@@ -151,10 +162,12 @@ def logout():
def change_password(): def change_password():
if session.pam_user: if session.pam_user:
session.flash = T('PAM authenticated user, cannot change password here') session.flash = T(
'PAM authenticated user, cannot change password here')
redirect(URL('site')) redirect(URL('site'))
form = SQLFORM.factory(Field('current_admin_password', 'password'), form = SQLFORM.factory(Field('current_admin_password', 'password'),
Field('new_admin_password','password',requires=IS_STRONG()), Field('new_admin_password',
'password', requires=IS_STRONG()),
Field('new_admin_password_again', 'password')) Field('new_admin_password_again', 'password'))
if form.accepts(request.vars): if form.accepts(request.vars):
if not verify_password(request.vars.current_admin_password): if not verify_password(request.vars.current_admin_password):
@@ -163,7 +176,8 @@ def change_password():
form.errors.new_admin_password_again = T('no match') form.errors.new_admin_password_again = T('no match')
else: else:
path = abspath('parameters_%s.py' % request.env.server_port) path = abspath('parameters_%s.py' % request.env.server_port)
safe_write(path, 'password="%s"' % CRYPT()(request.vars.new_admin_password)[0]) safe_write(path, 'password="%s"' % CRYPT()(
request.vars.new_admin_password)[0])
session.flash = T('password changed') session.flash = T('password changed')
redirect(URL('site')) redirect(URL('site'))
return dict(form=form) return dict(form=form)
@@ -295,8 +309,10 @@ def report_progress(app):
matches = regex.findall(open(progress_file, 'r').read()) matches = regex.findall(open(progress_file, 'r').read())
events, counter = [], 0 events, counter = [], 0
for m in matches: for m in matches:
if not m: continue if not m:
days = -(request.now - datetime.datetime.strptime(m[0],'%Y-%m-%d %H:%M:%S')).days continue
days = -(request.now - datetime.datetime.strptime(m[0],
'%Y-%m-%d %H:%M:%S')).days
counter += int(m[1]) counter += int(m[1])
events.append([days, counter]) events.append([days, counter])
return events return events
@@ -324,6 +340,7 @@ def pack():
session.flash = T('internal error: %s' % e) session.flash = T('internal error: %s' % e)
redirect(URL('site')) redirect(URL('site'))
def pack_plugin(): def pack_plugin():
app = get_app() app = get_app()
if len(request.args) == 2: if len(request.args) == 2:
@@ -338,6 +355,7 @@ def pack_plugin():
session.flash = T('internal error') session.flash = T('internal error')
redirect(URL('plugin', args=request.args)) redirect(URL('plugin', args=request.args))
def upgrade_web2py(): def upgrade_web2py():
dialog = FORM.confirm(T('Upgrade'), dialog = FORM.confirm(T('Upgrade'),
{T('Cancel'): URL('site')}) {T('Cancel'): URL('site')})
@@ -350,6 +368,7 @@ def upgrade_web2py():
redirect(URL('site')) redirect(URL('site'))
return dict(dialog=dialog) return dict(dialog=dialog)
def uninstall(): def uninstall():
app = get_app() app = get_app()
@@ -407,6 +426,7 @@ def remove_compiled_app():
session.flash = T('compiled application removed') session.flash = T('compiled application removed')
redirect(URL('site')) redirect(URL('site'))
def delete(): def delete():
""" Object delete handler """ """ Object delete handler """
app = get_app() app = get_app()
@@ -432,6 +452,7 @@ def delete():
redirect(URL(sender, anchor=request.vars.id2)) redirect(URL(sender, anchor=request.vars.id2))
return dict(filename=filename, sender=sender) return dict(filename=filename, sender=sender)
def delete(): def delete():
""" Object delete handler """ """ Object delete handler """
app = get_app() app = get_app()
@@ -458,6 +479,7 @@ def delete():
redirect(URL(sender, anchor=request.vars.id2)) redirect(URL(sender, anchor=request.vars.id2))
return dict(dialog=dialog, filename=filename) return dict(dialog=dialog, filename=filename)
def enable(): def enable():
app = get_app() app = get_app()
filename = os.path.join(apath(app, r=request), 'DISABLED') filename = os.path.join(apath(app, r=request), 'DISABLED')
@@ -470,6 +492,7 @@ def enable():
safe_open(filename, 'wb').write(time.ctime()) safe_open(filename, 'wb').write(time.ctime())
return SPAN(T('Enable'), _style='color:red') return SPAN(T('Enable'), _style='color:red')
def peek(): def peek():
""" Visualize object code """ """ Visualize object code """
app = get_app(request.vars.app) app = get_app(request.vars.app)
@@ -491,6 +514,7 @@ def peek():
data=data, data=data,
extension=extension) extension=extension)
def test(): def test():
""" Execute controller tests """ """ Execute controller tests """
app = get_app() app = get_app()
@@ -499,16 +523,20 @@ def test():
else: else:
file = '.*\.py' file = '.*\.py'
controllers = listdir(apath('%s/controllers/' % app, r=request), file + '$') controllers = listdir(
apath('%s/controllers/' % app, r=request), file + '$')
return dict(app=app, controllers=controllers) return dict(app=app, controllers=controllers)
def keepalive(): def keepalive():
return '' return ''
def search(): def search():
keywords = request.vars.keywords or '' keywords = request.vars.keywords or ''
app = get_app() app = get_app()
def match(filename, keywords): def match(filename, keywords):
filename = os.path.join(apath(app, r=request), filename) filename = os.path.join(apath(app, r=request), filename)
if keywords in read_file(filename, 'rb'): if keywords in read_file(filename, 'rb'):
@@ -518,9 +546,11 @@ def search():
files1 = glob(os.path.join(path, '*/*.py')) files1 = glob(os.path.join(path, '*/*.py'))
files2 = glob(os.path.join(path, '*/*.html')) files2 = glob(os.path.join(path, '*/*.html'))
files3 = glob(os.path.join(path, '*/*/*.html')) files3 = glob(os.path.join(path, '*/*/*.html'))
files=[x[len(path)+1:].replace('\\','/') for x in files1+files2+files3 if match(x,keywords)] files = [x[len(path) + 1:].replace(
'\\', '/') for x in files1 + files2 + files3 if match(x, keywords)]
return response.json(dict(files=files, message=T.M('Searching: **%s** %%{file}', len(files)))) return response.json(dict(files=files, message=T.M('Searching: **%s** %%{file}', len(files))))
def edit(): def edit():
""" File edit handler """ """ File edit handler """
# Load json only if it is ajax edited... # Load json only if it is ajax edited...
@@ -590,7 +620,8 @@ def edit():
data = request.vars.data.replace('\r\n', '\n').strip() + '\n' data = request.vars.data.replace('\r\n', '\n').strip() + '\n'
safe_write(path, data) safe_write(path, data)
lineno_new = count_lines(data) lineno_new = count_lines(data)
log_progress(app,'EDIT',filename,progress=lineno_new-lineno_old) log_progress(
app, 'EDIT', filename, progress=lineno_new - lineno_old)
file_hash = md5_hash(data) file_hash = md5_hash(data)
saved_on = time.ctime(os.stat(path)[stat.ST_MTIME]) saved_on = time.ctime(os.stat(path)[stat.ST_MTIME])
response.flash = T('file saved on %s', saved_on) response.flash = T('file saved on %s', saved_on)
@@ -609,28 +640,33 @@ def edit():
in enumerate(request.vars.data.split("\n")) in enumerate(request.vars.data.split("\n"))
if l < e.lineno - 1]) if l < e.lineno - 1])
if e.text and e.offset: if e.text and e.offset:
offset = e.offset - (len(e.text) - len(e.text.splitlines()[-1])) offset = e.offset - (len(e.text) - len(
e.text.splitlines()[-1]))
else: else:
offset = 0 offset = 0
highlight = {'start': start, 'end': start + offset + 1, 'lineno': e.lineno} highlight = {'start': start, 'end': start +
offset + 1, 'lineno': e.lineno}
try: try:
ex_name = e.__class__.__name__ ex_name = e.__class__.__name__
except: except:
ex_name = 'unknown exception!' ex_name = 'unknown exception!'
response.flash = DIV(T('failed to compile file because:'), BR(), response.flash = DIV(T('failed to compile file because:'), BR(),
B(ex_name), ' ' + T('at line %s', e.lineno), B(ex_name), ' ' + T('at line %s', e.lineno),
offset and ' '+T('at char %s', offset) or '', offset and ' ' +
T('at char %s', offset) or '',
PRE(str(e))) PRE(str(e)))
if data_or_revert and request.args[1] == 'modules': if data_or_revert and request.args[1] == 'modules':
# Lets try to reload the modules # Lets try to reload the modules
try: try:
mopath = '.'.join(request.args[2:])[:-3] mopath = '.'.join(request.args[2:])[:-3]
exec 'import applications.%s.modules.%s' % (request.args[0], mopath) exec 'import applications.%s.modules.%s' % (
request.args[0], mopath)
reload(sys.modules['applications.%s.modules.%s' reload(sys.modules['applications.%s.modules.%s'
% (request.args[0], mopath)]) % (request.args[0], mopath)])
except Exception, e: except Exception, e:
response.flash = DIV(T('failed to reload module because:'),PRE(str(e))) response.flash = DIV(
T('failed to reload module because:'), PRE(str(e)))
edit_controller = None edit_controller = None
editviewlinks = None editviewlinks = None
@@ -660,7 +696,7 @@ def edit():
for v in viewlist: for v in viewlist:
vf = os.path.split(v)[-1] vf = os.path.split(v)[-1]
vargs = "/".join([viewpath.replace(os.sep, "/"), vf]) vargs = "/".join([viewpath.replace(os.sep, "/"), vf])
editviewlinks.append(A(vf.split(".")[0],\ editviewlinks.append(A(vf.split(".")[0],
_href=URL('edit', args=[vargs]))) _href=URL('edit', args=[vargs])))
if len(request.args) > 2 and request.args[1] == 'controllers': if len(request.args) > 2 and request.args[1] == 'controllers':
@@ -680,7 +716,7 @@ def edit():
editarea_preferences['REPLACE_TAB_BY_SPACES'] = '4' editarea_preferences['REPLACE_TAB_BY_SPACES'] = '4'
editarea_preferences['DISPLAY'] = 'onload' editarea_preferences['DISPLAY'] = 'onload'
for key in editarea_preferences: for key in editarea_preferences:
if globals().has_key(key): if key in globals():
editarea_preferences[key] = globals()[key] editarea_preferences[key] = globals()[key]
return dict(app=request.args[0], return dict(app=request.args[0],
filename=filename, filename=filename,
@@ -695,6 +731,7 @@ def edit():
editarea_preferences=editarea_preferences, editarea_preferences=editarea_preferences,
editviewlinks=editviewlinks) editviewlinks=editviewlinks)
def resolve(): def resolve():
""" """
""" """
@@ -739,7 +776,7 @@ def resolve():
return 'minus' return 'minus'
if request.vars: if request.vars:
c = '\n'.join([item[2:].rstrip() for (i, item) in enumerate(d) if item[0] \ c = '\n'.join([item[2:].rstrip() for (i, item) in enumerate(d) if item[0]
== ' ' or 'line%i' % i in request.vars]) == ' ' or 'line%i' % i in request.vars])
safe_write(path, c) safe_write(path, c)
session.flash = 'files merged' session.flash = 'files merged'
@@ -770,7 +807,8 @@ def edit_language():
form = SPAN(strings['__corrupted__'], _class='error') form = SPAN(strings['__corrupted__'], _class='error')
return dict(filename=filename, form=form) return dict(filename=filename, form=form)
keys = sorted(strings.keys(),lambda x,y: cmp(unicode(x,'utf-8').lower(), unicode(y,'utf-8').lower())) keys = sorted(strings.keys(), lambda x, y: cmp(
unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower()))
rows = [] rows = []
rows.append(H2(T('Original/Translation'))) rows.append(H2(T('Original/Translation')))
@@ -805,18 +843,21 @@ def edit_language():
strs = dict() strs = dict()
for key in keys: for key in keys:
name = md5_hash(key) name = md5_hash(key)
if form.vars[name]==chr(127): continue if form.vars[name] == chr(127):
continue
strs[key] = form.vars[name] strs[key] = form.vars[name]
write_dict(apath(filename, r=request), strs) write_dict(apath(filename, r=request), strs)
session.flash = T('file saved on %(time)s', dict(time=time.ctime())) session.flash = T('file saved on %(time)s', dict(time=time.ctime()))
redirect(URL(r=request, args=request.args)) redirect(URL(r=request, args=request.args))
return dict(app=request.args[0], filename=filename, form=form) return dict(app=request.args[0], filename=filename, form=form)
def edit_plurals(): def edit_plurals():
""" Edit plurals file """ """ Edit plurals file """
app = get_app() app = get_app()
filename = '/'.join(request.args) filename = '/'.join(request.args)
plurals = read_plural_dict(apath(filename, r=request)) # plural forms dictionary plurals = read_plural_dict(
apath(filename, r=request)) # plural forms dictionary
nplurals = int(request.vars.nplurals) - 1 # plural forms quantity nplurals = int(request.vars.nplurals) - 1 # plural forms quantity
xnplurals = xrange(nplurals) xnplurals = xrange(nplurals)
@@ -825,7 +866,8 @@ def edit_plurals():
form = SPAN(plurals['__corrupted__'], _class='error') form = SPAN(plurals['__corrupted__'], _class='error')
return dict(filename=filename, form=form) return dict(filename=filename, form=form)
keys = sorted(plurals.keys(),lambda x,y: cmp(unicode(x,'utf-8').lower(), unicode(y,'utf-8').lower())) keys = sorted(plurals.keys(), lambda x, y: cmp(
unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower()))
rows = [] rows = []
row = [T("Singular Form")] row = [T("Singular Form")]
@@ -840,8 +882,10 @@ def edit_plurals():
forms.extend(None for i in xrange(nplurals - len(forms))) forms.extend(None for i in xrange(nplurals - len(forms)))
row = [B(key)] row = [B(key)]
row.extend([INPUT(_type='text', _name=name+'_'+str(n), value=forms[n], _size=20) for n in xnplurals]) row.extend([INPUT(_type='text', _name=name + '_' + str(n),
row.append(TD(TAG.BUTTON(T('delete'), _onclick='return delkey("%s")' % name))) value=forms[n], _size=20) for n in xnplurals])
row.append(TD(
TAG.BUTTON(T('delete'), _onclick='return delkey("%s")' % name)))
rows.append(TR(row, _id=name)) rows.append(TR(row, _id=name))
if rows: if rows:
table.append(TBODY(rows)) table.append(TBODY(rows))
@@ -851,11 +895,14 @@ def edit_plurals():
new_plurals = dict() new_plurals = dict()
for key in keys: for key in keys:
name = md5_hash(key) name = md5_hash(key)
if form.vars[name+'_0']==chr(127): continue if form.vars[name + '_0'] == chr(127):
new_plurals[key] = [form.vars[name+'_'+str(n)] for n in xnplurals] continue
new_plurals[key] = [form.vars[name + '_' + str(n)]
for n in xnplurals]
write_plural_dict(apath(filename, r=request), new_plurals) write_plural_dict(apath(filename, r=request), new_plurals)
session.flash = T('file saved on %(time)s', dict(time=time.ctime())) session.flash = T('file saved on %(time)s', dict(time=time.ctime()))
redirect(URL(r=request, args=request.args, vars=dict(nplurals=request.vars.nplurals))) redirect(URL(r=request, args=request.args, vars=dict(
nplurals=request.vars.nplurals)))
return dict(app=request.args[0], filename=filename, form=form) return dict(app=request.args[0], filename=filename, form=form)
@@ -879,7 +926,7 @@ def design():
if request.vars and not request.vars.token == session.token: if request.vars and not request.vars.token == session.token:
redirect(URL('logout')) redirect(URL('logout'))
if request.vars.pluginfile!=None and not isinstance(request.vars.pluginfile,str): if request.vars.pluginfile is not None and not isinstance(request.vars.pluginfile, str):
filename = os.path.basename(request.vars.pluginfile.filename) filename = os.path.basename(request.vars.pluginfile.filename)
if plugin_install(app, request.vars.pluginfile.file, if plugin_install(app, request.vars.pluginfile.file,
request, filename): request, filename):
@@ -893,7 +940,6 @@ def design():
session.flash = T('plugin not specified') session.flash = T('plugin not specified')
redirect(URL(r=request)) redirect(URL(r=request))
# If we have only pyc files it means that # If we have only pyc files it means that
# we cannot design # we cannot design
if os.path.exists(apath('%s/compiled' % app, r=request)): if os.path.exists(apath('%s/compiled' % app, r=request)):
@@ -911,7 +957,8 @@ def design():
defines[m].sort() defines[m].sort()
# Get all controllers # Get all controllers
controllers = sorted(listdir(apath('%s/controllers/' % app, r=request), '.*\.py$')) controllers = sorted(
listdir(apath('%s/controllers/' % app, r=request), '.*\.py$'))
controllers = [x.replace('\\', '/') for x in controllers] controllers = [x.replace('\\', '/') for x in controllers]
functions = {} functions = {}
for c in controllers: for c in controllers:
@@ -920,7 +967,8 @@ def design():
functions[c] = items functions[c] = items
# Get all views # Get all views
views = sorted(listdir(apath('%s/views/' % app, r=request), '[\w/\-]+(\.\w+)+$')) views = sorted(
listdir(apath('%s/views/' % app, r=request), '[\w/\-]+(\.\w+)+$'))
views = [x.replace('\\', '/') for x in views if not x.endswith('.bak')] views = [x.replace('\\', '/') for x in views if not x.endswith('.bak')]
extend = {} extend = {}
include = {} include = {}
@@ -958,14 +1006,17 @@ def design():
#Get crontab #Get crontab
cronfolder = apath('%s/cron' % app, r=request) cronfolder = apath('%s/cron' % app, r=request)
if not os.path.exists(cronfolder): os.mkdir(cronfolder) if not os.path.exists(cronfolder):
os.mkdir(cronfolder)
crontab = apath('%s/cron/crontab' % app, r=request) crontab = apath('%s/cron/crontab' % app, r=request)
if not os.path.exists(crontab): if not os.path.exists(crontab):
safe_write(crontab, '#crontab') safe_write(crontab, '#crontab')
plugins = [] plugins = []
def filter_plugins(items, plugins): def filter_plugins(items, plugins):
plugins+=[item[7:].split('/')[0].split('.')[0] for item in items if item.startswith('plugin_')] plugins += [item[7:].split('/')[0].split(
'.')[0] for item in items if item.startswith('plugin_')]
plugins[:] = list(set(plugins)) plugins[:] = list(set(plugins))
plugins.sort() plugins.sort()
return [item for item in items if not item.startswith('plugin_')] return [item for item in items if not item.startswith('plugin_')]
@@ -985,6 +1036,7 @@ def design():
crontab=crontab, crontab=crontab,
plugins=plugins) plugins=plugins)
def delete_plugin(): def delete_plugin():
""" Object delete handler """ """ Object delete handler """
app = request.args(0) app = request.args(0)
@@ -1014,6 +1066,7 @@ def delete_plugin():
redirect(URL('design', args=request.args(0), anchor=request.vars.id2)) redirect(URL('design', args=request.args(0), anchor=request.vars.id2))
return dict(dialog=dialog, plugin=plugin) return dict(dialog=dialog, plugin=plugin)
def plugin(): def plugin():
""" Application design handler """ """ Application design handler """
app = get_app() app = get_app()
@@ -1040,7 +1093,8 @@ def plugin():
defines[m].sort() defines[m].sort()
# Get all controllers # Get all controllers
controllers = sorted(listdir(apath('%s/controllers/' % app, r=request), '.*\.py$')) controllers = sorted(
listdir(apath('%s/controllers/' % app, r=request), '.*\.py$'))
controllers = [x.replace('\\', '/') for x in controllers] controllers = [x.replace('\\', '/') for x in controllers]
functions = {} functions = {}
for c in controllers: for c in controllers:
@@ -1049,7 +1103,8 @@ def plugin():
functions[c] = items functions[c] = items
# Get all views # Get all views
views = sorted(listdir(apath('%s/views/' % app, r=request), '[\w/\-]+\.\w+$')) views = sorted(
listdir(apath('%s/views/' % app, r=request), '[\w/\-]+\.\w+$'))
views = [x.replace('\\', '/') for x in views] views = [x.replace('\\', '/') for x in views]
extend = {} extend = {}
include = {} include = {}
@@ -1195,7 +1250,8 @@ def create_file():
if len(filename) == 5: if len(filename) == 5:
raise SyntaxError raise SyntaxError
msg = T('This is the %(filename)s template', dict(filename=filename)) msg = T(
'This is the %(filename)s template', dict(filename=filename))
if extension == 'html': if extension == 'html':
text = dedent(""" text = dedent("""
{{extend 'layout.html'}} {{extend 'layout.html'}}
@@ -1245,8 +1301,10 @@ def create_file():
session.flash = T('file "%(filename)s" created', session.flash = T('file "%(filename)s" created',
dict(filename=full_filename[len(path):])) dict(filename=full_filename[len(path):]))
vars = {} vars = {}
if request.vars.id: vars['id']=request.vars.id if request.vars.id:
if request.vars.app: vars['app']=request.vars.app vars['id'] = request.vars.id
if request.vars.app:
vars['app'] = request.vars.app
redirect(URL('edit', redirect(URL('edit',
args=[os.path.join(request.vars.location, filename)], vars=vars)) args=[os.path.join(request.vars.location, filename)], vars=vars))
except Exception, e: except Exception, e:
@@ -1319,7 +1377,8 @@ def errors():
method = request.args(1) or 'new' method = request.args(1) or 'new'
db_ready = {} db_ready = {}
db_ready['status'] = get_ticket_storage(app) db_ready['status'] = get_ticket_storage(app)
db_ready['errmessage'] = T("No ticket_storage.txt found under /private folder") db_ready['errmessage'] = T(
"No ticket_storage.txt found under /private folder")
db_ready['errlink'] = "http://web2py.com/books/default/chapter/29/13#Collecting-tickets" db_ready['errlink'] = "http://web2py.com/books/default/chapter/29/13#Collecting-tickets"
if method == 'new': if method == 'new':
@@ -1334,7 +1393,8 @@ def errors():
for fn in listdir(errors_path, '^[a-fA-F0-9.\-]+$'): for fn in listdir(errors_path, '^[a-fA-F0-9.\-]+$'):
fullpath = os.path.join(errors_path, fn) fullpath = os.path.join(errors_path, fn)
if not os.path.isfile(fullpath): continue if not os.path.isfile(fullpath):
continue
try: try:
fullpath_file = open(fullpath, 'r') fullpath_file = open(fullpath, 'r')
try: try:
@@ -1367,7 +1427,6 @@ def errors():
return dict(errors=[x[1] for x in decorated], app=app, method=method, db_ready=db_ready) return dict(errors=[x[1] for x in decorated], app=app, method=method, db_ready=db_ready)
elif method == 'dbnew': elif method == 'dbnew':
errors_path = apath('%s/errors' % app, r=request) errors_path = apath('%s/errors' % app, r=request)
tk_db, tk_table = get_ticket_storage(app) tk_db, tk_table = get_ticket_storage(app)
@@ -1417,7 +1476,8 @@ def errors():
tk_db.commit() tk_db.commit()
tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id, tk_table.created_datetime, orderby=~tk_table.created_datetime) tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id, tk_table.created_datetime, orderby=~tk_table.created_datetime)
tickets = [row.ticket_id for row in tickets_] tickets = [row.ticket_id for row in tickets_]
times = dict([(row.ticket_id, row.created_datetime) for row in tickets_]) times = dict(
[(row.ticket_id, row.created_datetime) for row in tickets_])
return dict(app=app, tickets=tickets, method=method, times=times) return dict(app=app, tickets=tickets, method=method, times=times)
@@ -1425,14 +1485,16 @@ def errors():
for item in request.vars: for item in request.vars:
if item[:7] == 'delete_': if item[:7] == 'delete_':
os.unlink(apath('%s/errors/%s' % (app, item[7:]), r=request)) os.unlink(apath('%s/errors/%s' % (app, item[7:]), r=request))
func = lambda p: os.stat(apath('%s/errors/%s' % \ func = lambda p: os.stat(apath('%s/errors/%s' %
(app, p), r=request)).st_mtime (app, p), r=request)).st_mtime
tickets = sorted(listdir(apath('%s/errors/' % app, r=request), '^\w.*'), tickets = sorted(
listdir(apath('%s/errors/' % app, r=request), '^\w.*'),
key=func, key=func,
reverse=True) reverse=True)
return dict(app=app, tickets=tickets, method=method, db_ready=db_ready) return dict(app=app, tickets=tickets, method=method, db_ready=db_ready)
def get_ticket_storage(app): def get_ticket_storage(app):
private_folder = apath('%s/private' % app, r=request) private_folder = apath('%s/private' % app, r=request)
ticket_file = os.path.join(private_folder, 'ticket_storage.txt') ticket_file = os.path.join(private_folder, 'ticket_storage.txt')
@@ -1454,6 +1516,7 @@ def get_ticket_storage(app):
) )
return ticketsdb, ticketsdb.get(tablename) return ticketsdb, ticketsdb.get(tablename)
def make_link(path): def make_link(path):
""" Create a link from a path """ """ Create a link from a path """
tryFile = path.replace('\\', '/') tryFile = path.replace('\\', '/')
@@ -1536,6 +1599,7 @@ def ticket():
layer=e.layer, layer=e.layer,
myversion=myversion) myversion=myversion)
def ticketdb(): def ticketdb():
""" Ticket handler """ """ Ticket handler """
@@ -1559,10 +1623,12 @@ def ticketdb():
layer=e.layer, layer=e.layer,
myversion=myversion) myversion=myversion)
def error(): def error():
""" Generate a ticket (for testing) """ """ Generate a ticket (for testing) """
raise RuntimeError('admin ticket generator at your service') raise RuntimeError('admin ticket generator at your service')
def update_languages(): def update_languages():
""" Update available languages """ """ Update available languages """
@@ -1600,12 +1666,14 @@ def user():
else: else:
return dict(form=T("Disabled")) return dict(form=T("Disabled"))
def reload_routes(): def reload_routes():
""" Reload routes.py """ """ Reload routes.py """
import gluon.rewrite import gluon.rewrite
gluon.rewrite.load() gluon.rewrite.load()
redirect(URL('site')) redirect(URL('site'))
def manage_students(): def manage_students():
if not (MULTI_USER_MODE and is_manager()): if not (MULTI_USER_MODE and is_manager()):
session.flash = T('Not Authorized') session.flash = T('Not Authorized')
@@ -1614,6 +1682,7 @@ def manage_students():
grid = SQLFORM.grid(db.auth_user) grid = SQLFORM.grid(db.auth_user)
return locals() return locals()
def bulk_register(): def bulk_register():
if not (MULTI_USER_MODE and is_manager()): if not (MULTI_USER_MODE and is_manager()):
session.flash = T('Not Authorized') session.flash = T('Not Authorized')
@@ -1634,6 +1703,7 @@ def bulk_register():
# 2) should not prompt user at console # 2) should not prompt user at console
# 3) should give option to force commit and not reuqire manual merge # 3) should give option to force commit and not reuqire manual merge
def git_pull(): def git_pull():
""" Git Pull handler """ """ Git Pull handler """
app = get_app() app = get_app()
@@ -1660,10 +1730,12 @@ def git_pull():
session.flash = T("Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.") session.flash = T("Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.")
redirect(URL('site')) redirect(URL('site'))
except GitCommandError, status: except GitCommandError, status:
session.flash = T("Pull failed, git exited abnormally. See logs for details.") session.flash = T(
"Pull failed, git exited abnormally. See logs for details.")
redirect(URL('site')) redirect(URL('site'))
except Exception, e: except Exception, e:
session.flash = T("Pull failed, git exited abnormally. See logs for details.") session.flash = T(
"Pull failed, git exited abnormally. See logs for details.")
redirect(URL('site')) redirect(URL('site'))
elif 'cancel' in request.vars: elif 'cancel' in request.vars:
redirect(URL('site')) redirect(URL('site'))
@@ -1688,13 +1760,14 @@ def git_push():
new_commit = index.commit(form.vars.changelog) new_commit = index.commit(form.vars.changelog)
origin = repo.remotes.origin origin = repo.remotes.origin
origin.push() origin.push()
session.flash = T("Git repo updated with latest application changes.") session.flash = T(
"Git repo updated with latest application changes.")
redirect(URL('site')) redirect(URL('site'))
except UnmergedEntriesError: except UnmergedEntriesError:
session.flash = T("Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.") session.flash = T("Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.")
redirect(URL('site')) redirect(URL('site'))
except Exception, e: except Exception, e:
session.flash = T("Push failed, git exited abnormally. See logs for details.") session.flash = T(
"Push failed, git exited abnormally. See logs for details.")
redirect(URL('site')) redirect(URL('site'))
return dict(app=app, form=form) return dict(app=app, form=form)
+16 -9
View File
@@ -18,28 +18,34 @@ if MULTI_USER_MODE and not is_manager():
forever = 10 ** 8 forever = 10 ** 8
def kill(): def kill():
p = cache.ram('gae_upload', lambda: None, forever) p = cache.ram('gae_upload', lambda: None, forever)
if not p or p.poll()!=None: if not p or p.poll() is not None:
return 'oops' return 'oops'
os.kill(p.pid, signal.SIGKILL) os.kill(p.pid, signal.SIGKILL)
cache.ram('gae_upload', lambda: None, -1) cache.ram('gae_upload', lambda: None, -1)
class EXISTS(object): class EXISTS(object):
def __init__(self, error_message='file not found'): def __init__(self, error_message='file not found'):
self.error_message = error_message self.error_message = error_message
def __call__(self, value): def __call__(self, value):
if os.path.exists(value): if os.path.exists(value):
return (value, None) return (value, None)
return (value, self.error_message) return (value, self.error_message)
def deploy(): def deploy():
regex = re.compile('^\w+$') regex = re.compile('^\w+$')
apps = sorted(file for file in os.listdir(apath(r=request)) if regex.match(file)) apps = sorted(
file for file in os.listdir(apath(r=request)) if regex.match(file))
form = SQLFORM.factory( form = SQLFORM.factory(
Field('appcfg', default=GAE_APPCFG, label=T('Path to appcfg.py'), Field('appcfg', default=GAE_APPCFG, label=T('Path to appcfg.py'),
requires=EXISTS(error_message=T('file not found'))), requires=EXISTS(error_message=T('file not found'))),
Field('google_application_id',requires=IS_MATCH('[\w\-]+'),label=T('Google Application Id')), Field('google_application_id', requires=IS_MATCH(
'[\w\-]+'), label=T('Google Application Id')),
Field('applications', 'list:string', Field('applications', 'list:string',
requires=IS_IN_SET(apps, multiple=True), requires=IS_IN_SET(apps, multiple=True),
label=T('web2py apps to deploy')), label=T('web2py apps to deploy')),
@@ -51,7 +57,7 @@ def deploy():
kill() kill()
except: except:
pass pass
ignore_apps = [item for item in apps \ ignore_apps = [item for item in apps
if not item in form.vars.applications] if not item in form.vars.applications]
regex = re.compile('\(applications/\(.*') regex = re.compile('\(applications/\(.*')
yaml = apath('../app.yaml', r=request) yaml = apath('../app.yaml', r=request)
@@ -59,8 +65,10 @@ def deploy():
example = apath('../app.example.yaml', r=request) example = apath('../app.example.yaml', r=request)
shutil.copyfile(example, yaml) shutil.copyfile(example, yaml)
data = read_file(yaml) data = read_file(yaml)
data = re.sub('application:.*','application: %s' % form.vars.google_application_id,data) data = re.sub('application:.*', 'application: %s' %
data = regex.sub('(applications/(%s)/.*)|' % '|'.join(ignore_apps),data) form.vars.google_application_id, data)
data = regex.sub(
'(applications/(%s)/.*)|' % '|'.join(ignore_apps), data)
write_file(yaml, data) write_file(yaml, data)
path = request.env.applications_parent path = request.env.applications_parent
@@ -76,9 +84,10 @@ def deploy():
fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
return dict(form=form, command=cmd) return dict(form=form, command=cmd)
def callback(): def callback():
p = cache.ram('gae_upload', lambda: None, forever) p = cache.ram('gae_upload', lambda: None, forever)
if not p or p.poll()!=None: if not p or p.poll() is not None:
return '<done/>' return '<done/>'
try: try:
output = p.stdout.read() output = p.stdout.read()
@@ -89,5 +98,3 @@ def callback():
except: except:
errors = '' errors = ''
return (output + errors).replace('\n', '<br/>') return (output + errors).replace('\n', '<br/>')
+3 -2
View File
@@ -22,6 +22,7 @@ sessions/*
errors/* errors/*
""" """
def hg_repo(path): def hg_repo(path):
import os import os
uio = ui.ui() uio = ui.ui()
@@ -37,6 +38,7 @@ def hg_repo(path):
write_file(hgignore, _hgignore_content) write_file(hgignore, _hgignore_content)
return repo return repo
def commit(): def commit():
app = request.args(0) app = request.args(0)
path = apath(app, r=request) path = apath(app, r=request)
@@ -63,6 +65,7 @@ def commit():
changes = [] changes = []
return dict(form=form, files=files, changes=changes, repo=repo) return dict(form=form, files=files, changes=changes, repo=repo)
def revision(): def revision():
app = request.args(0) app = request.args(0)
path = apath(app, r=request) path = apath(app, r=request)
@@ -80,5 +83,3 @@ def revision():
desc=ctx.description(), desc=ctx.description(),
form=form form=form
) )
+11 -2
View File
@@ -1,15 +1,21 @@
import os import os
try:
from distutils import dir_util from distutils import dir_util
except ImportError:
session.flash = T('requires distutils, but not installed')
redirect(URL('default', 'site'))
try: try:
from git import * from git import *
except ImportError: except ImportError:
session.flash = T('requires python-git, but not installed') session.flash = T('requires python-git, but not installed')
redirect(URL('default', 'site')) redirect(URL('default', 'site'))
def deploy(): def deploy():
apps = sorted(file for file in os.listdir(apath(r=request))) apps = sorted(file for file in os.listdir(apath(r=request)))
form = SQLFORM.factory( form = SQLFORM.factory(
Field('osrepo',default='/tmp',label=T('Path to local openshift repo root.'), Field(
'osrepo', default='/tmp', label=T('Path to local openshift repo root.'),
requires=EXISTS(error_message=T('directory not found'))), requires=EXISTS(error_message=T('directory not found'))),
Field('osname', default='web2py', label=T('WSGI reference name')), Field('osname', default='web2py', label=T('WSGI reference name')),
Field('applications', 'list:string', Field('applications', 'list:string',
@@ -23,7 +29,8 @@ def deploy():
except: except:
pass pass
ignore_apps = [item for item in apps if not item in form.vars.applications] ignore_apps = [
item for item in apps if not item in form.vars.applications]
regex = re.compile('\(applications/\(.*') regex = re.compile('\(applications/\(.*')
w2p_origin = os.getcwd() w2p_origin = os.getcwd()
osrepo = form.vars.osrepo osrepo = form.vars.osrepo
@@ -47,9 +54,11 @@ def deploy():
#Git code ends here #Git code ends here
return dict(form=form, command=cmd) return dict(form=form, command=cmd)
class EXISTS(object): class EXISTS(object):
def __init__(self, error_message='file not found'): def __init__(self, error_message='file not found'):
self.error_message = error_message self.error_message = error_message
def __call__(self, value): def __call__(self, value):
if os.path.exists(value): if os.path.exists(value):
return (value, None) return (value, None)
@@ -1,10 +1,10 @@
response.files = response.files[:3] response.files = response.files[:3]
response.menu = [] response.menu = []
def index(): def index():
return locals() return locals()
def about(): def about():
return locals() return locals()
+7 -4
View File
@@ -1,7 +1,8 @@
import sys import sys
import cStringIO import cStringIO
import gluon.contrib.shell import gluon.contrib.shell
import code, thread import code
import thread
from gluon.shell import env from gluon.shell import env
if DEMO_MODE or MULTI_USER_MODE: if DEMO_MODE or MULTI_USER_MODE:
@@ -10,16 +11,19 @@ if DEMO_MODE or MULTI_USER_MODE:
FE = 10 ** 9 FE = 10 ** 9
def index(): def index():
app = request.args(0) or 'admin' app = request.args(0) or 'admin'
reset() reset()
return dict(app=app) return dict(app=app)
def callback(): def callback():
app = request.args[0] app = request.args[0]
command = request.vars.statement command = request.vars.statement
escape = command[:1] != '!' escape = command[:1] != '!'
history = session['history:'+app] = session.get('history:'+app,gluon.contrib.shell.History()) history = session['history:' + app] = session.get(
'history:' + app, gluon.contrib.shell.History())
if not escape: if not escape:
command = command[1:] command = command[1:]
if command == '%reset': if command == '%reset':
@@ -38,10 +42,9 @@ def callback():
#return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output)) #return TABLE(TR('In[%i]:'%k,PRE(command)),TR('Out[%i]:'%k,output))
return 'In [%i] : %s%s\n' % (k + 1, command, output) return 'In [%i] : %s%s\n' % (k + 1, command, output)
def reset(): def reset():
app = request.args(0) or 'admin' app = request.args(0) or 'admin'
session['commands:' + app] = [] session['commands:' + app] = []
session['history:' + app] = gluon.contrib.shell.History() session['history:' + app] = gluon.contrib.shell.History()
return 'done' return 'done'
+2 -2
View File
@@ -2,10 +2,12 @@ import os
from gluon.settings import global_settings, read_file from gluon.settings import global_settings, read_file
# #
def index(): def index():
app = request.args(0) app = request.args(0)
return dict(app=app) return dict(app=app)
def profiler(): def profiler():
""" """
to use the profiler start web2py with -F profiler.log to use the profiler start web2py with -F profiler.log
@@ -27,5 +29,3 @@ def profiler():
size += len(data) size += len(data)
response.cookies[KEY] = size response.cookies[KEY] = size
return data return data
@@ -82,6 +82,7 @@ def install(app_name, filename, data, overwrite=True):
return installed return installed
@service.jsonrpc @service.jsonrpc
def attach_debugger(host='localhost', port=6000, authkey='secret password'): def attach_debugger(host='localhost', port=6000, authkey='secret password'):
import gluon.contrib.qdb as qdb import gluon.contrib.qdb as qdb
@@ -124,7 +125,7 @@ def detach_debugger():
gluon.debug.qdb_debugger = None gluon.debug.qdb_debugger = None
return True return True
def call(): def call():
session.forget() session.forget()
return service() return service()
+84 -37
View File
@@ -1,9 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os, uuid, re, pickle, urllib, glob import os
import uuid
import re
import pickle
import urllib
import glob
from gluon.admin import app_create, plugin_install from gluon.admin import app_create, plugin_install
from gluon.fileutils import abspath, read_file, write_file from gluon.fileutils import abspath, read_file, write_file
def reset(session): def reset(session):
session.app = { session.app = {
'name': '', 'name': '',
@@ -30,16 +36,20 @@ def reset(session):
'page_error': '# Error: the document does not exist', 'page_error': '# Error: the document does not exist',
} }
if not session.app: reset(session) if not session.app:
reset(session)
def listify(x): def listify(x):
if not isinstance(x, (list, tuple)): if not isinstance(x, (list, tuple)):
return x and [x] or [] return x and [x] or []
return x return x
def clean(name): def clean(name):
return re.sub('\W+', '_', name.strip().lower()) return re.sub('\W+', '_', name.strip().lower())
def index(): def index():
response.view = 'wizard/step.html' response.view = 'wizard/step.html'
reset(session) reset(session)
@@ -49,11 +59,10 @@ def index():
if form.accepts(request.vars): if form.accepts(request.vars):
app = form.vars.name app = form.vars.name
session.app['name'] = app session.app['name'] = app
if MULTI_USER_MODE and db(db.app.name==app)\ if MULTI_USER_MODE and db(db.app.name == app)(db.app.owner != auth.user.id).count():
(db.app.owner!=auth.user.id).count():
session.flash = 'App belongs already to other user' session.flash = 'App belongs already to other user'
elif app in apps: elif app in apps:
meta = os.path.normpath(\ meta = os.path.normpath(
os.path.join(os.path.normpath(request.folder), os.path.join(os.path.normpath(request.folder),
'..', app, 'wizard.metadata')) '..', app, 'wizard.metadata'))
if os.path.exists(meta): if os.path.exists(meta):
@@ -96,20 +105,26 @@ def step1():
requires=IS_NOT_EMPTY()), requires=IS_NOT_EMPTY()),
Field('subtitle', default=params.get('subtitle', None)), Field('subtitle', default=params.get('subtitle', None)),
Field('author', default=params.get('author', None)), Field('author', default=params.get('author', None)),
Field('author_email',default=params.get('author_email',None)), Field(
'author_email', default=params.get('author_email', None)),
Field('keywords', default=params.get('keywords', None)), Field('keywords', default=params.get('keywords', None)),
Field('description', 'text', Field('description', 'text',
default=params.get('description', None)), default=params.get('description', None)),
Field('layout_theme', requires=IS_IN_SET(themes), Field('layout_theme', requires=IS_IN_SET(themes),
default=params.get('layout_theme', themes[0])), default=params.get('layout_theme', themes[0])),
Field('database_uri',default=params.get('database_uri',None)), Field(
Field('security_key',default=params.get('security_key',None)), 'database_uri', default=params.get('database_uri', None)),
Field('email_server',default=params.get('email_server',None)), Field(
Field('email_sender',default=params.get('email_sender',None)), '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('email_login', default=params.get('email_login', None)),
Field('login_method', requires=IS_IN_SET(('local', 'janrain')), Field('login_method', requires=IS_IN_SET(('local', 'janrain')),
default=params.get('login_method', 'local')), default=params.get('login_method', 'local')),
Field('login_config',default=params.get('login_config',None)), Field(
'login_config', default=params.get('login_config', None)),
Field('plugins', 'list:string', requires=IS_IN_SET(plugins, multiple=True))) Field('plugins', 'list:string', requires=IS_IN_SET(plugins, multiple=True)))
if form.accepts(request.vars): if form.accepts(request.vars):
@@ -118,14 +133,15 @@ def step1():
redirect(URL('step2')) redirect(URL('step2'))
return dict(step='1: Setting Parameters', form=form) return dict(step='1: Setting Parameters', form=form)
def step2(): def step2():
response.view = 'wizard/step.html' response.view = 'wizard/step.html'
form = SQLFORM.factory(Field('table_names', 'list:string', form = SQLFORM.factory(Field('table_names', 'list:string',
default=session.app['tables'])) default=session.app['tables']))
if form.accepts(request.vars): if form.accepts(request.vars):
table_names = [clean(t) for t in listify(form.vars.table_names) \ table_names = [clean(t) for t in listify(form.vars.table_names)
if t.strip()] if t.strip()]
if [t for t in table_names if t.startswith('auth_') and \ if [t for t in table_names if t.startswith('auth_') and
not t == 'auth_user']: not t == 'auth_user']:
form.error.table_names = \ form.error.table_names = \
T('invalid table names (auth_* tables already defined)') T('invalid table names (auth_* tables already defined)')
@@ -146,11 +162,13 @@ def step2():
redirect(URL('step4')) redirect(URL('step4'))
return dict(step='2: Tables', form=form) return dict(step='2: Tables', form=form)
def step3(): def step3():
response.view = 'wizard/step.html' response.view = 'wizard/step.html'
n = int(request.args(0) or 0) n = int(request.args(0) or 0)
m = len(session.app['tables']) m = len(session.app['tables'])
if n>=m: redirect(URL('step2')) if n >= m:
redirect(URL('step2'))
table = session.app['tables'][n] table = session.app['tables'][n]
form = SQLFORM.factory(Field('field_names', 'list:string', form = SQLFORM.factory(Field('field_names', 'list:string',
default=session.app.get('table_' + table, []))) default=session.app.get('table_' + table, [])))
@@ -172,9 +190,10 @@ def step3():
redirect(URL('step3', args=n + 1)) redirect(URL('step3', args=n + 1))
else: else:
redirect(URL('step4')) redirect(URL('step4'))
return dict(step='3: Fields for table "%s" (%s of %s)' \ return dict(step='3: Fields for table "%s" (%s of %s)'
% (table, n + 1, m), table=table, form=form) % (table, n + 1, m), table=table, form=form)
def step4(): def step4():
response.view = 'wizard/step.html' response.view = 'wizard/step.html'
form = SQLFORM.factory(Field('pages', 'list:string', form = SQLFORM.factory(Field('pages', 'list:string',
@@ -189,11 +208,13 @@ def step4():
redirect(URL('step6')) redirect(URL('step6'))
return dict(step='4: Pages', form=form) return dict(step='4: Pages', form=form)
def step5(): def step5():
response.view = 'wizard/step.html' response.view = 'wizard/step.html'
n = int(request.args(0) or 0) n = int(request.args(0) or 0)
m = len(session.app['pages']) m = len(session.app['pages'])
if n>=m: redirect(URL('step4')) if n >= m:
redirect(URL('step4'))
page = session.app['pages'][n] page = session.app['pages'][n]
markmin_url = 'http://web2py.com/examples/static/markmin.html' markmin_url = 'http://web2py.com/examples/static/markmin.html'
form = SQLFORM.factory(Field('content', 'text', form = SQLFORM.factory(Field('content', 'text',
@@ -209,6 +230,7 @@ def step5():
redirect(URL('step6')) redirect(URL('step6'))
return dict(step='5: View for page "%s" (%s of %s)' % (page, n + 1, m), form=form) return dict(step='5: View for page "%s" (%s of %s)' % (page, n + 1, m), form=form)
def step6(): def step6():
response.view = 'wizard/step.html' response.view = 'wizard/step.html'
params = dict(session.app['params']) params = dict(session.app['params'])
@@ -230,9 +252,11 @@ def step6():
redirect(URL('generated')) redirect(URL('generated'))
return dict(step='6: Generate app "%s"' % app, form=form) return dict(step='6: Generate app "%s"' % app, form=form)
def generated(): def generated():
return dict(app=session.app['name']) return dict(app=session.app['name'])
def sort_tables(tables): def sort_tables(tables):
import re import re
regex = re.compile('(%s)' % '|'.join(tables)) regex = re.compile('(%s)' % '|'.join(tables))
@@ -245,6 +269,7 @@ def sort_tables(tables):
tables = [] tables = []
if is_auth_user: if is_auth_user:
tables.append('auth_user') tables.append('auth_user')
def append(table, trail=[]): def append(table, trail=[]):
if table in trail: if table in trail:
raise RuntimeError raise RuntimeError
@@ -253,12 +278,15 @@ def sort_tables(tables):
append(t, trail=trail + [table]) append(t, trail=trail + [table])
if not table in tables: if not table in tables:
tables.append(table) tables.append(table)
for table in d: append(table) for table in d:
append(table)
return tables return tables
def make_table(table, fields): def make_table(table, fields):
rawtable = table rawtable = table
if table!='auth_user': table='t_'+table if table != 'auth_user':
table = 't_' + table
s = '' s = ''
s += '\n' + '#' * 40 + '\n' s += '\n' + '#' * 40 + '\n'
s += "db.define_table('%s',\n" % table s += "db.define_table('%s',\n" % table
@@ -277,11 +305,12 @@ def make_table(table,fields):
has[key] = True has[key] = True
tables = session.app['tables'] tables = session.app['tables']
refs = [t for t in tables if t in items] refs = [t for t in tables if t in items]
items = items[:1] + [x for x in items[1:] \ items = items[:1] + [x for x in items[1:]
if not x in keys and not x in tables] if not x in keys and not x in tables]
barename = name = '_'.join(items) barename = name = '_'.join(items)
if table[:2] == 't_': name = 'f_' + name if table[:2] == 't_': name = 'f_' + name
if first_field=='id': first_field=name if first_field == 'id':
first_field = name
### determine field type ### determine field type
ftype = 'string' ftype = 'string'
@@ -295,7 +324,8 @@ def make_table(table,fields):
ftype = t ftype = t
if refs: if refs:
key = refs[0] key = refs[0]
if not key=='auth_user': key='t_'+key if not key == 'auth_user':
key = 't_' + key
if 'multiple' in has: if 'multiple' in has:
ftype = 'list:reference %s' % key ftype = 'list:reference %s' % key
else: else:
@@ -352,17 +382,22 @@ def make_table(table,fields):
s += " migrate=settings.migrate)\n\n" s += " migrate=settings.migrate)\n\n"
if table == 'auth_user': if table == 'auth_user':
s += """ s += """
db.auth_user.first_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty) db.auth_user.first_name.requires = IS_NOT_EMPTY(
db.auth_user.last_name.requires = IS_NOT_EMPTY(error_message=auth.messages.is_empty) error_message=auth.messages.is_empty)
db.auth_user.password.requires = CRYPT(key=auth.settings.hmac_key, min_length=4) db.auth_user.last_name.requires = IS_NOT_EMPTY(
error_message=auth.messages.is_empty)
db.auth_user.password.requires = CRYPT(
key=auth.settings.hmac_key, min_length=4)
db.auth_user.username.requires = IS_NOT_IN_DB(db, db.auth_user.username) db.auth_user.username.requires = IS_NOT_IN_DB(db, db.auth_user.username)
db.auth_user.email.requires = (IS_EMAIL(error_message=auth.messages.invalid_email), db.auth_user.email.requires = (
IS_EMAIL(error_message=auth.messages.invalid_email),
IS_NOT_IN_DB(db, db.auth_user.email)) IS_NOT_IN_DB(db, db.auth_user.email))
""" """
else: else:
s += "db.define_table('%s_archive',db.%s,Field('current_record','reference %s',readable=False,writable=False))\n" % (table, table, table) s += "db.define_table('%s_archive',db.%s,Field('current_record','reference %s',readable=False,writable=False))\n" % (table, table, table)
return s return s
def fix_db(filename): def fix_db(filename):
params = dict(session.app['params']) params = dict(session.app['params'])
content = read_file(filename, 'rb') content = read_file(filename, 'rb')
@@ -370,7 +405,7 @@ def fix_db(filename):
auth_user = make_table('auth_user', session.app['table_auth_user']) auth_user = make_table('auth_user', session.app['table_auth_user'])
content = content.replace('sqlite://storage.sqlite', content = content.replace('sqlite://storage.sqlite',
params['database_uri']) params['database_uri'])
content = content.replace('auth.define_tables()',\ content = content.replace('auth.define_tables()',
auth_user + 'auth.define_tables(migrate = settings.migrate)') auth_user + 'auth.define_tables(migrate = settings.migrate)')
content += """ content += """
mail.settings.server = settings.email_server mail.settings.server = settings.email_server
@@ -380,7 +415,8 @@ mail.settings.login = settings.email_login
if params['login_method'] == 'janrain': if params['login_method'] == 'janrain':
content += """ content += """
from gluon.contrib.login_methods.rpx_account import RPXAccount from gluon.contrib.login_methods.rpx_account import RPXAccount
auth.settings.actions_disabled=['register','change_password','request_reset_password'] auth.settings.actions_disabled=['register','change_password',
'request_reset_password']
auth.settings.login_form = RPXAccount(request, auth.settings.login_form = RPXAccount(request,
api_key = settings.login_config.split(':')[-1], api_key = settings.login_config.split(':')[-1],
domain = settings.login_config.split(':')[0], domain = settings.login_config.split(':')[0],
@@ -388,6 +424,7 @@ auth.settings.login_form = RPXAccount(request,
""" """
write_file(filename, content, 'wb') write_file(filename, content, 'wb')
def make_menu(pages): def make_menu(pages):
s = '' s = ''
s += 'response.title = settings.title\n' s += 'response.title = settings.title\n'
@@ -408,6 +445,7 @@ def make_menu(pages):
s += ']' s += ']'
return s return s
def make_page(page, contents): def make_page(page, contents):
if 'auth_user' in session.app['tables'] and not page in ('index', 'error'): if 'auth_user' in session.app['tables'] and not page in ('index', 'error'):
s = "@auth.requires_login()\ndef %s():\n" % page s = "@auth.requires_login()\ndef %s():\n" % page
@@ -421,11 +459,13 @@ def make_page(page,contents):
s += " return dict()\n\n" s += " return dict()\n\n"
return s return s
def make_view(page, contents): def make_view(page, contents):
s = "{{extend 'layout.html'}}\n\n" s = "{{extend 'layout.html'}}\n\n"
s += str(MARKMIN(contents)) s += str(MARKMIN(contents))
return s return s
def populate(tables): def populate(tables):
s = 'from gluon.contrib.populate import populate\n' s = 'from gluon.contrib.populate import populate\n'
s += 'if db(db.auth_user).isempty():\n' s += 'if db(db.auth_user).isempty():\n'
@@ -434,6 +474,7 @@ def populate(tables):
s += " populate(db.%s,10)\n" % t s += " populate(db.%s,10)\n" % t
return s return s
def create(options): def create(options):
if DEMO_MODE: if DEMO_MODE:
session.flash = T('disabled in demo mode') session.flash = T('disabled in demo mode')
@@ -461,7 +502,8 @@ def create(options):
if options.apply_layout and params['layout_theme'] != 'Default': if options.apply_layout and params['layout_theme'] != 'Default':
try: try:
fn = 'web2py.plugin.layout_%s.w2p' % params['layout_theme'] fn = 'web2py.plugin.layout_%s.w2p' % params['layout_theme']
theme = urllib.urlopen(LAYOUTS_APP+'/static/plugin_layouts/plugins/'+fn) theme = urllib.urlopen(
LAYOUTS_APP + '/static/plugin_layouts/plugins/' + fn)
plugin_install(app, theme, request, fn) plugin_install(app, theme, request, fn)
except: except:
session.flash = T("unable to download layout") session.flash = T("unable to download layout")
@@ -502,20 +544,23 @@ def create(options):
### create newapp/models/db_wizard.py ### create newapp/models/db_wizard.py
if options.generate_model: if options.generate_model:
model = os.path.join(request.folder,'..',app,'models','db_wizard.py') model = os.path.join(
request.folder, '..', app, 'models', 'db_wizard.py')
file = open(model, 'wb') file = open(model, 'wb')
try: try:
file.write('### we prepend t_ to tablenames and f_ to fieldnames for disambiguity\n\n') file.write('### we prepend t_ to tablenames and f_ to fieldnames for disambiguity\n\n')
tables = sort_tables(session.app['tables']) tables = sort_tables(session.app['tables'])
for table in tables: for table in tables:
if table=='auth_user': continue if table == 'auth_user':
continue
file.write(make_table(table, session.app['table_' + table])) file.write(make_table(table, session.app['table_' + table]))
finally: finally:
file.close() file.close()
model = os.path.join(request.folder, '..', app, model = os.path.join(request.folder, '..', app,
'models', 'db_wizard_populate.py') 'models', 'db_wizard_populate.py')
if os.path.exists(model): os.unlink(model) if os.path.exists(model):
os.unlink(model)
if options.populate_database and session.app['tables']: if options.populate_database and session.app['tables']:
file = open(model, 'wb') file = open(model, 'wb')
try: try:
@@ -525,7 +570,8 @@ def create(options):
### create newapp/controllers/default.py ### create newapp/controllers/default.py
if options.generate_controller: if options.generate_controller:
controller = os.path.join(request.folder,'..',app,'controllers','default.py') controller = os.path.join(
request.folder, '..', app, 'controllers', 'default.py')
file = open(controller, 'wb') file = open(controller, 'wb')
try: try:
file.write("""# -*- coding: utf-8 -*- file.write("""# -*- coding: utf-8 -*-
@@ -536,17 +582,20 @@ def call(): return service()
### end requires ### end requires
""") """)
for page in session.app['pages']: for page in session.app['pages']:
file.write(make_page(page,session.app.get('page_'+page,''))) file.write(
make_page(page, session.app.get('page_' + page, '')))
finally: finally:
file.close() file.close()
### create newapp/views/default/*.html ### create newapp/views/default/*.html
if options.generate_views: if options.generate_views:
for page in session.app['pages']: for page in session.app['pages']:
view = os.path.join(request.folder,'..',app,'views','default',page+'.html') view = os.path.join(
request.folder, '..', app, 'views', 'default', page + '.html')
file = open(view, 'wb') file = open(view, 'wb')
try: try:
file.write(make_view(page,session.app.get('page_'+page,''))) file.write(
make_view(page, session.app.get('page_' + page, '')))
finally: finally:
file.close() file.close()
@@ -554,5 +603,3 @@ def call(): return service()
path = os.path.join(request.folder, '..', app, 'databases', '*') path = os.path.join(request.folder, '..', app, 'databases', '*')
for file in glob.glob(path): for file in glob.glob(path):
os.unlink(file) os.unlink(file)
@@ -19,5 +19,3 @@ for filename in os.listdir(path):
os.unlink(fullpath) os.unlink(fullpath)
except: except:
logging.exception('failure to check %s'%fullpath) logging.exception('failure to check %s'%fullpath)
+6 -1
View File
@@ -34,10 +34,12 @@
'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані', 'App does not exist or your are not authorized': 'Додаток не існує, або ви не авторизовані',
'appadmin': 'Aдм.панель', 'appadmin': 'Aдм.панель',
'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку", 'appadmin is disabled because insecure channel': "адмін.панель відключено через використання ненадійного каналу зв'язку",
'Application': 'Додаток (Application)',
'application "%s" uninstalled': 'додаток "%s" вилучено', 'application "%s" uninstalled': 'додаток "%s" вилучено',
'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s', 'application %(appname)s installed with md5sum: %(digest)s': 'додаток %(appname)s встановлено з md5sum: %(digest)s',
'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна', 'Application cannot be generated in demo mode': 'В демо-режимі генерувати додатки не можна',
'application compiled': 'додаток скомпільовано', 'application compiled': 'додаток скомпільовано',
'Application exists already': 'Додаток вже існує',
'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна', 'application is compiled and cannot be designed': 'додаток скомпільований. налаштування змінювати не можна',
'Application name:': 'Назва додатку:', 'Application name:': 'Назва додатку:',
'are not used': 'не використовуються', 'are not used': 'не використовуються',
@@ -160,6 +162,7 @@
'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)', 'Error snapshot': 'Розгорнутий знімок стану (Error snapshot)',
'Error ticket': 'Позначка (ticket) про помилку', 'Error ticket': 'Позначка (ticket) про помилку',
'Errors': 'Помилки', 'Errors': 'Помилки',
'Errors in form, please check it out.': 'Помилка у формі, будь-ласка перевірте її.',
'Exception %(extype)s: %(exvalue)s': 'Виключення %(extype)s: %(exvalue)s', 'Exception %(extype)s: %(exvalue)s': 'Виключення %(extype)s: %(exvalue)s',
'Exception %s': 'Виключення %s', 'Exception %s': 'Виключення %s',
'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)', 'Exception instance attributes': 'Атрибути примірника класу Exception (виключення)',
@@ -388,6 +391,7 @@
'There are no models': 'Моделей, наразі, нема', 'There are no models': 'Моделей, наразі, нема',
'There are no modules': 'Модулів поки що нема', 'There are no modules': 'Модулів поки що нема',
'There are no plugins': 'Жодної втулки, наразі, не встановлено', 'There are no plugins': 'Жодної втулки, наразі, не встановлено',
'There are no private files': 'Приватних файлів поки що нема',
'There are no static files': 'Статичних файлів, наразі, нема', 'There are no static files': 'Статичних файлів, наразі, нема',
'There are no translators': 'Перекладів нема', 'There are no translators': 'Перекладів нема',
'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу', 'There are no translators, only default language is supported': 'Перекладів нема, підтримується тільки мова оригіналу',
@@ -418,6 +422,7 @@
'Traceback': 'Стек викликів (Traceback)', 'Traceback': 'Стек викликів (Traceback)',
'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови', 'Translation strings for the application': 'Пари рядків <оригінал>:<переклад> для вибраної мови',
'try something like': 'спробуйте щось схоже на', 'try something like': 'спробуйте щось схоже на',
'Try the mobile interface': 'Спробуйте мобільний інтерфейс',
'try view': 'дивитись результат', 'try view': 'дивитись результат',
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.', 'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'наберіть тут будь-які команди ладнача PDB і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.', 'Type python statement in here and hit Return (Enter) to execute it.': 'Наберіть тут будь-які вирази Python і натисніть клавішу [Return] ([Enter]), щоб запустити їх на виконання.',
@@ -463,7 +468,7 @@
'Views': 'Відображення (Views)', 'Views': 'Відображення (Views)',
'views': 'відображення', 'views': 'відображення',
'WARNING:': 'ПОПЕРЕДЖЕННЯ:', 'WARNING:': 'ПОПЕРЕДЖЕННЯ:',
'Web Framework': 'Web Framework', 'Web Framework': 'Веб-каркас (Web Framework)',
'web2py apps to deploy': 'Готові до розгортання додатки web2py', 'web2py apps to deploy': 'Готові до розгортання додатки web2py',
'web2py Debugger': 'Ладнач web2py', 'web2py Debugger': 'Ладнач web2py',
'web2py downgrade': 'повернення на попередню версію web2py', 'web2py downgrade': 'повернення на попередню версію web2py',
-2
View File
@@ -78,5 +78,3 @@ PLUGINS_APP = 'http://web2py.com/plugins'
# set the language # set the language
if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage'] is None): if 'adminLanguage' in request.cookies and not (request.cookies['adminLanguage'] is None):
T.force(request.cookies['adminLanguage'].value) T.force(request.cookies['adminLanguage'].value)
-2
View File
@@ -28,5 +28,3 @@ from gluon.languages import findT, update_all_languages
from gluon.myregex import * from gluon.myregex import *
from gluon.restricted import * from gluon.restricted import *
from gluon.compileapp import compile_application, remove_compiled_application from gluon.compileapp import compile_application, remove_compiled_application
+10 -4
View File
@@ -1,4 +1,6 @@
import base64, os, time import base64
import os
import time
from gluon import portalocker from gluon import portalocker
from gluon.admin import apath from gluon.admin import apath
from gluon.fileutils import read_file from gluon.fileutils import read_file
@@ -24,7 +26,8 @@ elif not request.is_local and not DEMO_MODE:
try: try:
_config = {} _config = {}
port = int(request.env.server_port or 0) port = int(request.env.server_port or 0)
restricted(read_file(apath('../parameters_%i.py' % port, request)), _config) restricted(
read_file(apath('../parameters_%i.py' % port, request)), _config)
if not 'password' in _config or not _config['password']: if not 'password' in _config or not _config['password']:
raise HTTP(200, T('admin disabled because no admin password')) raise HTTP(200, T('admin disabled because no admin password'))
@@ -38,7 +41,8 @@ except IOError:
raise HTTP(200, raise HTTP(200,
T('admin disabled because not supported on google app engine')) T('admin disabled because not supported on google app engine'))
else: else:
raise HTTP(200, T('admin disabled because unable to access password file')) raise HTTP(
200, T('admin disabled because unable to access password file'))
def verify_password(password): def verify_password(password):
@@ -63,6 +67,7 @@ deny_file = os.path.join(request.folder, 'private', 'hosts.deny')
allowed_number_of_attempts = 5 allowed_number_of_attempts = 5
expiration_failed_logins = 3600 expiration_failed_logins = 3600
def read_hosts_deny(): def read_hosts_deny():
import datetime import datetime
hosts = {} hosts = {}
@@ -83,6 +88,7 @@ def read_hosts_deny():
f.close() f.close()
return hosts return hosts
def write_hosts_deny(denied_hosts): def write_hosts_deny(denied_hosts):
f = open(deny_file, 'w') f = open(deny_file, 'w')
portalocker.lock(f, portalocker.LOCK_EX) portalocker.lock(f, portalocker.LOCK_EX)
@@ -93,6 +99,7 @@ def write_hosts_deny(denied_hosts):
portalocker.unlock(f) portalocker.unlock(f)
f.close() f.close()
def login_record(success=True): def login_record(success=True):
denied_hosts = read_hosts_deny() denied_hosts = read_hosts_deny()
val = (0, 0) val = (0, 0)
@@ -168,4 +175,3 @@ elif session.authorized and \
if request.controller == 'appadmin' and DEMO_MODE: if request.controller == 'appadmin' and DEMO_MODE:
session.flash = 'Appadmin disabled in demo mode' session.flash = 'Appadmin disabled in demo mode'
redirect(URL('default', 'sites')) redirect(URL('default', 'sites'))
+6 -2
View File
@@ -2,11 +2,13 @@
import os import os
def A_button(*a, **b): def A_button(*a, **b):
b['_data-role'] = 'button' b['_data-role'] = 'button'
b['_data-inline'] = 'true' b['_data-inline'] = 'true'
return A(*a, **b) return A(*a, **b)
def button(href, label): def button(href, label):
if is_mobile: if is_mobile:
ret = A_button(SPAN(label), _href=href) ret = A_button(SPAN(label), _href=href)
@@ -14,6 +16,7 @@ def button(href, label):
ret = A(SPAN(label), _class='button', _href=href) ret = A(SPAN(label), _class='button', _href=href)
return ret return ret
def button_enable(href, app): def button_enable(href, app):
if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')): if os.path.exists(os.path.join(apath(app, r=request), 'DISABLED')):
label = SPAN(T('Enable'), _style='color:red') label = SPAN(T('Enable'), _style='color:red')
@@ -22,6 +25,7 @@ def button_enable(href, app):
id = 'enable_' + app id = 'enable_' + app
return A(label, _class='button', _id=id, callback=href, target=id) return A(label, _class='button', _id=id, callback=href, target=id)
def sp_button(href, label): def sp_button(href, label):
if request.user_agent().is_mobile: if request.user_agent().is_mobile:
ret = A_button(SPAN(label), _href=href) ret = A_button(SPAN(label), _href=href)
@@ -29,10 +33,10 @@ def sp_button(href, label):
ret = A(SPAN(label), _class='button special', _href=href) ret = A(SPAN(label), _class='button special', _href=href)
return ret return ret
def helpicon(): def helpicon():
return IMG(_src=URL('static', 'images/help.png'), _alt='help') return IMG(_src=URL('static', 'images/help.png'), _alt='help')
def searchbox(elementid): def searchbox(elementid):
return TAG[''](LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12)) return TAG[''](LABEL(IMG(_id="search_start", _src=URL('static', 'images/search.png'), _alt=T('filter')), _class='icon', _for=elementid), ' ', INPUT(_id=elementid, _type='text', _size=12))
+7 -5
View File
@@ -4,9 +4,12 @@
if MULTI_USER_MODE: if MULTI_USER_MODE:
db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB db = DAL('sqlite://storage.sqlite') # if not, use SQLite or other DB
from gluon.tools import * from gluon.tools import *
auth = Auth(globals(),db) # authentication/authorization auth = Auth(
crud = Crud(globals(),db) # for CRUD helpers using auth globals(), db) # authentication/authorization
service = Service(globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc crud = Crud(
globals(), db) # for CRUD helpers using auth
service = Service(
globals()) # for json, xml, jsonrpc, xmlrpc, amfrpc
plugins = PluginManager() plugins = PluginManager()
mail = auth.settings.mailer mail = auth.settings.mailer
@@ -29,6 +32,7 @@ if not session.authorized and MULTI_USER_MODE:
elif not request.function == 'user': elif not request.function == 'user':
redirect(URL('default', 'user/login')) redirect(URL('default', 'user/login'))
def is_manager(): def is_manager():
if not MULTI_USER_MODE: if not MULTI_USER_MODE:
return True return True
@@ -36,5 +40,3 @@ def is_manager():
return True return True
else: else:
return False return False
+2 -3
View File
@@ -30,8 +30,7 @@ else:
URL(_a, 'debug', 'interact'))) URL(_a, 'debug', 'interact')))
if os.path.exists('applications/examples'): if os.path.exists('applications/examples'):
response.menu.append((T('Help'), False, URL('examples','default','index'))) response.menu.append(
(T('Help'), False, URL('examples', 'default', 'index')))
else: else:
response.menu.append((T('Help'), False, 'http://web2py.com/examples')) response.menu.append((T('Help'), False, 'http://web2py.com/examples'))
@@ -1,5 +1,4 @@
response.files.append(URL('static','plugin_multiselect/jquery.multi-select.js')) response.files.append(
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/multi-select.css'))
response.files.append(URL('static', 'plugin_multiselect/start.js')) 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> <textarea style="width: auto; height:400px;direction:ltr;" rows="58" cols="100" -amy-enabled="true" id="body" name="data">{{=data}}</textarea>
<script>window.eamy = eamy;</script> <script>window.eamy = eamy;</script>
{{elif TEXT_EDITOR == 'codemirror':}} {{elif TEXT_EDITOR == 'codemirror':}}
<textarea style="width: auto; height:400px;direction:ltr;" id="body" name="data">{{=data}}</textarea> <textarea style="width: auto; height:auto; direction:ltr;" id="body" name="data">{{=data}}</textarea>
<script> <script>
function isFullScreen(instance) { function isFullScreen(instance) {
return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className); return /\bCodeMirror-fullscreen\b/.test(instance.getWrapperElement().className);
@@ -197,6 +197,7 @@ jQuery(document).ready(function(){
document.getElementById("body"),cm_opts); document.getElementById("body"),cm_opts);
var hlLine = editor.setLineClass(0, "activeline"); var hlLine = editor.setLineClass(0, "activeline");
window.mirror = editor; window.mirror = editor;
jQuery(function(){jQuery('.CodeMirror-scroll').css("height","auto").css("overflow-x","auto");});
</script> </script>
{{elif TEXT_EDITOR == 'ace':}} {{elif TEXT_EDITOR == 'ace':}}
<div id="editor" style="height: 500px; width: auto; position: relative">{{=data}}</div> <div id="editor" style="height: 500px; width: auto; position: relative">{{=data}}</div>
@@ -9,6 +9,13 @@
body { body {
background: url('{{=URL('static','plugin_jqmobile/images/iphone.jpg')}}') no-repeat white; background: url('{{=URL('static','plugin_jqmobile/images/iphone.jpg')}}') no-repeat white;
} }
#back {
z-index: 1000;
padding: 10px;
position: absolute;
top: 0;
right: 0;
}
iframe { iframe {
position: absolute; position: absolute;
margin-left: 320px; margin-left: 320px;
@@ -35,6 +42,7 @@
</head> </head>
<body> <body>
<iframe src="{{=URL('default','index',vars=dict(is_mobile='true'))}}"></iframe> <iframe src="{{=URL('default','index',vars=dict(is_mobile='true'))}}"></iframe>
<div id="back"><a href="{{=URL('default','index',vars=dict(is_mobile='false'))}}">Back</a></div>
<div id="about"> <div id="about">
<h1><a href="http://web2py.com">web2py</a> plugin</h1> <h1><a href="http://web2py.com">web2py</a> plugin</h1>
<h2>for <a href="http://jquerymobile.com/">jQuery Mobile</a></h2> <h2>for <a href="http://jquerymobile.com/">jQuery Mobile</a></h2>
+1
View File
@@ -0,0 +1 @@
@@ -18,6 +18,3 @@ def flash():
def fade(): def fade():
return dict() return dict()
+36 -20
View File
@@ -102,17 +102,16 @@ def query_by_table_type(tablename,db,request=request):
cond = '>0' cond = '>0'
if firstkey.type in ['string', 'text']: if firstkey.type in ['string', 'text']:
cond = '!=""' cond = '!=""'
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond) qry = '%s.%s.%s%s' % (
request.args[0], request.args[1], firstkey.name, cond)
else: else:
qry = '%s.%s.id>0' % tuple(request.args[:2]) qry = '%s.%s.id>0' % tuple(request.args[:2])
return qry return qry
# ########################################################## # ##########################################################
# ## list all databases and tables # ## list all databases and tables
# ########################################################### # ###########################################################
def index(): def index():
return dict(databases=databases) return dict(databases=databases)
@@ -140,6 +139,7 @@ def download():
db = get_database(request) db = get_database(request)
return response.download(request, db) return response.download(request, db)
def csv(): def csv():
import gluon.contenttype import gluon.contenttype
response.headers['Content-Type'] = \ response.headers['Content-Type'] = \
@@ -156,6 +156,7 @@ def csv():
def import_csv(table, file): def import_csv(table, file):
table.import_from_csv_file(file) table.import_from_csv_file(file)
def select(): def select():
import re import re
db = get_database(request) db = get_database(request)
@@ -192,7 +193,8 @@ def select():
session.last_query = request.vars.query session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px', form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_name='query', _value=request.vars.query or '', _name='query', _value=request.vars.query or '',
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'), requires=IS_NOT_EMPTY(
error_message=T("Cannot be empty")))), TR(T('Update:'),
INPUT(_name='update_check', _type='checkbox', INPUT(_name='update_check', _type='checkbox',
value=False), INPUT(_style='width:400px', value=False), INPUT(_style='width:400px',
_name='update_fields', _value=request.vars.update_fields _name='update_fields', _value=request.vars.update_fields
@@ -200,13 +202,14 @@ def select():
_class='delete', _type='checkbox', value=False), ''), _class='delete', _type='checkbox', value=False), ''),
TR('', '', INPUT(_type='submit', _value=T('submit')))), TR('', '', INPUT(_type='submit', _value=T('submit')))),
_action=URL(r=request, args=request.args)) _action=URL(r=request, args=request.args))
tb = None
if form.accepts(request.vars, formname=None): if form.accepts(request.vars, formname=None):
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+') regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
match = regex.match(form.vars.query.strip()) match = regex.match(form.vars.query.strip())
if match: if match:
table = match.group('table') table = match.group('table')
try: try:
tb = None
nrows = db(query).count() nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields: if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)' db(query).update(**eval_in_global_env('dict(%s)'
@@ -217,9 +220,11 @@ def select():
response.flash = T('%s %%{row} deleted', nrows) response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count() nrows = db(query).count()
if orderby: if orderby:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby)) rows = db(query, ignore_common_filters=True).select(limitby=(
start, stop), orderby=eval_in_global_env(orderby))
else: else:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) rows = db(query, ignore_common_filters=True).select(
limitby=(start, stop))
except Exception, e: except Exception, e:
import traceback import traceback
tb = traceback.format_exc() tb = traceback.format_exc()
@@ -268,9 +273,11 @@ def update():
if keyed: if keyed:
key = [f for f in request.vars if f in db[table]._primarykey] key = [f for f in request.vars if f in db[table]._primarykey]
if key: if key:
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first() record = db(db[table][key[0]] == request.vars[key[
0]], ignore_common_filters=True).select().first()
else: else:
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first() record = db(db[table].id == request.args(
2), ignore_common_filters=True).select().first()
if not record: if not record:
qry = query_by_table_type(table, db) qry = query_by_table_type(table, db)
@@ -282,7 +289,8 @@ def update():
for k in db[table]._primarykey: for k in db[table]._primarykey:
db[table][k].writable = False db[table][k].writable = False
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'), form = SQLFORM(
db[table], record, deletable=True, delete_label=T('Check to delete'),
ignore_rw=ignore_rw and not keyed, ignore_rw=ignore_rw and not keyed,
linkto=URL('select', linkto=URL('select',
args=request.args[:1]), upload=URL(r=request, args=request.args[:1]), upload=URL(r=request,
@@ -304,11 +312,15 @@ def update():
def state(): def state():
return dict() return dict()
def ccache(): def ccache():
form = FORM( form = FORM(
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")), P(TAG.BUTTON(
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")), T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")), P(TAG.BUTTON(
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
P(TAG.BUTTON(
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
) )
if form.accepts(request.vars, session): if form.accepts(request.vars, session):
@@ -332,11 +344,16 @@ def ccache():
redirect(URL(r=request)) redirect(URL(r=request))
try: try:
from guppy import hpy; hp=hpy() from guppy import hpy
hp = hpy()
except ImportError: except ImportError:
hp = False hp = False
import shelve, os, copy, time, math import shelve
import os
import copy
import time
import math
from gluon import portalocker from gluon import portalocker
ram = { ram = {
@@ -383,7 +400,8 @@ def ccache():
locker = open(os.path.join(request.folder, locker = open(os.path.join(request.folder,
'cache/cache.lock'), 'a') 'cache/cache.lock'), 'a')
portalocker.lock(locker, portalocker.LOCK_EX) portalocker.lock(locker, portalocker.LOCK_EX)
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve')) disk_storage = shelve.open(
os.path.join(request.folder, 'cache/cache.shelve'))
try: try:
for key, value in disk_storage.items(): for key, value in disk_storage.items():
if isinstance(value, dict): if isinstance(value, dict):
@@ -414,7 +432,8 @@ def ccache():
total['misses'] = ram['misses'] + disk['misses'] total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys'] total['keys'] = ram['keys'] + disk['keys']
try: try:
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses']) total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
except (KeyError, ZeroDivisionError): except (KeyError, ZeroDivisionError):
total['ratio'] = 0 total['ratio'] = 0
@@ -440,6 +459,3 @@ def ccache():
return dict(form=form, total=total, return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False) ram=ram, disk=disk, object_stats=hp != False)
@@ -1,4 +1,3 @@
import time import time
@@ -19,7 +18,7 @@ def cache_on_disk():
def cache_in_ram_and_disk(): def cache_in_ram_and_disk():
"""cache the output of the lambda function on disk and in ram""" """cache the output of the lambda function on disk and in ram"""
t = cache.ram('time', lambda : cache.disk('time', lambda : \ t = cache.ram('time', lambda: cache.disk('time', lambda:
time.ctime(), time_expire=5), time_expire=5) time.ctime(), time_expire=5), time_expire=5)
return dict(time=t, link=A('click to reload', _href=URL(r=request))) return dict(time=t, link=A('click to reload', _href=URL(r=request)))
@@ -47,5 +46,3 @@ def cache_controller_and_view():
t = time.ctime() t = time.ctime()
d = dict(time=t, link=A('click to reload', _href=URL(r=request))) d = dict(time=t, link=A('click to reload', _href=URL(r=request)))
return response.render(d) return response.render(d)
+18 -3
View File
@@ -9,68 +9,83 @@ response.description = T('web2py Web Framework')
session.forget() session.forget()
cache_expire = not request.is_local and 300 or 0 cache_expire = not request.is_local and 300 or 0
@cache('index', time_expire=cache_expire) @cache('index', time_expire=cache_expire)
def index(): def index():
return response.render() return response.render()
@cache('what', time_expire=cache_expire) @cache('what', time_expire=cache_expire)
def what(): def what():
import urllib; import urllib
try: try:
images = XML(urllib.urlopen('http://web2py.com/poweredby/default/images').read()) images = XML(urllib.urlopen(
'http://web2py.com/poweredby/default/images').read())
except: except:
images = [] images = []
return response.render(images=images) return response.render(images=images)
@cache('download', time_expire=cache_expire) @cache('download', time_expire=cache_expire)
def download(): def download():
return response.render() return response.render()
@cache('who', time_expire=cache_expire) @cache('who', time_expire=cache_expire)
def who(): def who():
return response.render() return response.render()
@cache('support', time_expire=cache_expire) @cache('support', time_expire=cache_expire)
def support(): def support():
return response.render() return response.render()
@cache('documentation', time_expire=cache_expire) @cache('documentation', time_expire=cache_expire)
def documentation(): def documentation():
return response.render() return response.render()
@cache('usergroups', time_expire=cache_expire) @cache('usergroups', time_expire=cache_expire)
def usergroups(): def usergroups():
return response.render() return response.render()
def contact(): def contact():
redirect(URL('default', 'usergroups')) redirect(URL('default', 'usergroups'))
@cache('videos', time_expire=cache_expire) @cache('videos', time_expire=cache_expire)
def videos(): def videos():
return response.render() return response.render()
def security(): def security():
redirect('http://www.web2py.com/book/default/chapter/01#security') redirect('http://www.web2py.com/book/default/chapter/01#security')
def api(): def api():
redirect('http://web2py.com/book/default/chapter/04#API') redirect('http://web2py.com/book/default/chapter/04#API')
@cache('license', time_expire=cache_expire) @cache('license', time_expire=cache_expire)
def license(): def license():
import os import os
filename = os.path.join(request.env.gluon_parent, 'LICENSE') filename = os.path.join(request.env.gluon_parent, 'LICENSE')
return response.render(dict(license=MARKMIN(read_file(filename)))) return response.render(dict(license=MARKMIN(read_file(filename))))
def version(): def version():
return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version return 'Version %s.%s.%s (%s) %s' % request.env.web2py_version
@cache('examples', time_expire=cache_expire) @cache('examples', time_expire=cache_expire)
def examples(): def examples():
return response.render() return response.render()
@cache('changelog', time_expire=cache_expire) @cache('changelog', time_expire=cache_expire)
def changelog(): def changelog():
import os import os
filename = os.path.join(request.env.gluon_parent, 'CHANGELOG') filename = os.path.join(request.env.gluon_parent, 'CHANGELOG')
return response.render(dict(changelog=MARKMIN(read_file(filename)))) return response.render(dict(changelog=MARKMIN(read_file(filename))))
@@ -1,6 +1,3 @@
def form(): def form():
""" a simple entry form with various types of objects """ """ a simple entry form with various types of objects """
@@ -23,6 +20,3 @@ def form():
else: else:
response.flash = 'please fill the form' response.flash = 'please fill the form'
return dict(form=form, vars=form.vars) return dict(form=form, vars=form.vars)
@@ -1,4 +1,3 @@
session.forget() session.forget()
response.menu = [['home', False, '/%s/default/index' response.menu = [['home', False, '/%s/default/index'
@@ -77,6 +76,3 @@ def vars():
doc=doc, doc=doc,
attributes=attributes, attributes=attributes,
) )
@@ -20,6 +20,3 @@ def basic():
['basic', True, URL('basic')]] ['basic', True, URL('basic')]]
response.flash = 'you clicked on basic' response.flash = 'you clicked on basic'
return dict(message='you clicked on basic') return dict(message='you clicked on basic')
@@ -1,6 +1,3 @@
def counter(): def counter():
""" every time you reload, it increases the session.counter """ """ every time you reload, it increases the session.counter """
@@ -8,6 +5,3 @@ def counter():
session.counter = 0 session.counter = 0
session.counter += 1 session.counter += 1
return dict(counter=session.counter) return dict(counter=session.counter)
@@ -102,7 +102,6 @@ def rss_aggregator():
return rss2.dumps(rss) return rss2.dumps(rss)
def ajaxwiki(): def ajaxwiki():
default = """ default = """
# section # section
@@ -135,6 +134,6 @@ Quoted text
_onclick="ajax('ajaxwiki_onclick',['text'],'html')")) _onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
return dict(form=form, html=DIV(_id='html')) return dict(form=form, html=DIV(_id='html'))
def ajaxwiki_onclick(): def ajaxwiki_onclick():
return MARKMIN(request.vars.text).xml() return MARKMIN(request.vars.text).xml()
@@ -1,10 +1,11 @@
from gluon.contrib.spreadsheet import Sheet from gluon.contrib.spreadsheet import Sheet
def callback(): def callback():
return cache.ram('sheet1', lambda: None, None).process(request) return cache.ram('sheet1', lambda: None, None).process(request)
def index(): def index():
sheet = cache.ram('sheet1', lambda: Sheet(10, 10, URL('callback')), 0) sheet = cache.ram('sheet1', lambda: Sheet(10, 10, URL('callback')), 0)
#sheet.cell('r0c3',value='=r0c0+r0c1+r0c2',readonly=True) #sheet.cell('r0c3',value='=r0c0+r0c1+r0c2',readonly=True)
return dict(sheet=sheet) return dict(sheet=sheet)
@@ -1,6 +1,3 @@
def variables(): def variables():
return dict(a=10, b=20) return dict(a=10, b=20)
@@ -31,6 +28,3 @@ def xml():
def beautify(): def beautify():
return dict(message=BEAUTIFY(request)) return dict(message=BEAUTIFY(request))
+15 -20
View File
@@ -1,4 +1,3 @@
def group_feed_reader(group, mode='div', counter='5'): def group_feed_reader(group, mode='div', counter='5'):
"""parse group feeds""" """parse group feeds"""
@@ -8,17 +7,18 @@ def group_feed_reader(group,mode='div',counter='5'):
g = feedparser.parse(url) g = feedparser.parse(url)
if mode == 'div': if mode == 'div':
html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title']+' - ' +\ html = XML(TAG.BLOCKQUOTE(UL(*[LI(A(entry['title'] + ' - ' +
entry['author'][entry['author'].rfind('('):],\ entry['author'][
_href=entry['link'],_target='_blank'))\ entry['author'].rfind('('):],
for entry in g['entries'] ]),\ _href=entry['link'], _target='_blank'))
_class="boxInfo",\ for entry in g['entries']]),
_class="boxInfo",
_style="padding-bottom:5px;")) _style="padding-bottom:5px;"))
else: else:
html = XML(UL(*[LI(A(entry['title']+' - ' +\ html = XML(UL(*[LI(A(entry['title'] + ' - ' +
entry['author'][entry['author'].rfind('('):],\ entry['author'][entry['author'].rfind('('):],
_href=entry['link'],_target='_blank'))\ _href=entry['link'], _target='_blank'))
for entry in g['entries']])) for entry in g['entries']]))
return html return html
@@ -31,19 +31,14 @@ def code_feed_reader(project,mode='div'):
from gluon.contrib import feedparser from gluon.contrib import feedparser
g = feedparser.parse(url) g = feedparser.parse(url)
if mode == 'div': if mode == 'div':
html = XML(DIV(UL(*[LI(A(entry['title'],_href=entry['link'],\ html = XML(DIV(UL(*[LI(A(entry['title'], _href=entry['link'],
_target='_blank'))\ _target='_blank'))
for entry in g['entries'][0:5]]),\ for entry in g['entries'][0:5]]),
_class="boxInfo",\ _class="boxInfo",
_style="padding-bottom:5px;")) _style="padding-bottom:5px;"))
else: else:
html = XML(UL(*[LI(A(entry['title'],_href=entry['link'],\ html = XML(UL(*[LI(A(entry['title'], _href=entry['link'],
_target='_blank'))\ _target='_blank'))
for entry in g['entries'][0:5]])) for entry in g['entries'][0:5]]))
return html return html
+9 -8
View File
@@ -2,18 +2,19 @@ import gluon.template
markmin_dict = dict( markmin_dict = dict(
code_python=lambda code: str(CODE(code)), code_python=lambda code: str(CODE(code)),
template=lambda \ template=lambda
code: gluon.template.render(code, context=globals()), code: gluon.template.render(code, context=globals()),
sup=lambda \ sup=lambda
code: '<sup style="font-size:0.5em;">%s</sup>' % code, code: '<sup style="font-size:0.5em;">%s</sup>' % code,
br=lambda n: '<br>' * int(n), br=lambda n: '<br>' * int(n),
groupdates=lambda group: group_feed_reader(group), groupdates=lambda group: group_feed_reader(group),
) )
def get_content(b=None,\
c=request.controller,\ def get_content(b=None,
f=request.function,\ c=request.controller,
l='en',\ f=request.function,
l='en',
format='markmin'): format='markmin'):
"""Gets and renders the file in """Gets and renders the file in
<app>/private/content/<lang>/<controller>/<function>/<block>.<format> <app>/private/content/<lang>/<controller>/<function>/<block>.<format>
@@ -21,7 +22,8 @@ def get_content(b=None,\
def openfile(): def openfile():
import os import os
path = os.path.join(request.folder,'private','content',l,c,f,b+'.'+format) path = os.path.join(
request.folder, 'private', 'content', l, c, f, b + '.' + format)
return open(path) return open(path)
try: try:
@@ -37,4 +39,3 @@ def get_content(b=None,\
openedfile.close() openedfile.close()
return html return html
+2 -2
View File
@@ -11,6 +11,8 @@ response.menu = [
######################################################################### #########################################################################
## Changes the menu active item ## Changes the menu active item
######################################################################### #########################################################################
def toggle_menuclass(cssclass='pressed', menuid='headermenu'): def toggle_menuclass(cssclass='pressed', menuid='headermenu'):
"""This function changes the menu class to put pressed appearance""" """This function changes the menu class to put pressed appearance"""
@@ -23,7 +25,6 @@ def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
documentation='-520px -115px' documentation='-520px -115px'
) )
if request.function in positions.keys(): if request.function in positions.keys():
jscript = """ jscript = """
<script> <script>
@@ -42,4 +43,3 @@ def toggle_menuclass(cssclass='pressed',menuid='headermenu'):
return XML(jscript) return XML(jscript)
else: else:
return '' return ''
@@ -29,6 +29,7 @@
</li><li>Alvaro Justen (dynamical translations) </li><li>Alvaro Justen (dynamical translations)
</li><li>Anders Roos (file locking) </li><li>Anders Roos (file locking)
</li><li>Andrew Willimott (documentation, TeraData support) </li><li>Andrew Willimott (documentation, TeraData support)
</li><li>Andriy Kornatskyy (benchmarks and profiling)
</li><li>Angelo Compagnucci (mobile devices) </li><li>Angelo Compagnucci (mobile devices)
</li><li>Anthony Bastardi (book, poweredby site, multiple contributions) </li><li>Anthony Bastardi (book, poweredby site, multiple contributions)
</li><li>Arun K. Rajeevan (plugin_wiki) </li><li>Arun K. Rajeevan (plugin_wiki)
+1
View File
@@ -0,0 +1 @@
+36 -20
View File
@@ -102,17 +102,16 @@ def query_by_table_type(tablename,db,request=request):
cond = '>0' cond = '>0'
if firstkey.type in ['string', 'text']: if firstkey.type in ['string', 'text']:
cond = '!=""' cond = '!=""'
qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond) qry = '%s.%s.%s%s' % (
request.args[0], request.args[1], firstkey.name, cond)
else: else:
qry = '%s.%s.id>0' % tuple(request.args[:2]) qry = '%s.%s.id>0' % tuple(request.args[:2])
return qry return qry
# ########################################################## # ##########################################################
# ## list all databases and tables # ## list all databases and tables
# ########################################################### # ###########################################################
def index(): def index():
return dict(databases=databases) return dict(databases=databases)
@@ -140,6 +139,7 @@ def download():
db = get_database(request) db = get_database(request)
return response.download(request, db) return response.download(request, db)
def csv(): def csv():
import gluon.contenttype import gluon.contenttype
response.headers['Content-Type'] = \ response.headers['Content-Type'] = \
@@ -156,6 +156,7 @@ def csv():
def import_csv(table, file): def import_csv(table, file):
table.import_from_csv_file(file) table.import_from_csv_file(file)
def select(): def select():
import re import re
db = get_database(request) db = get_database(request)
@@ -192,7 +193,8 @@ def select():
session.last_query = request.vars.query session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px', form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_name='query', _value=request.vars.query or '', _name='query', _value=request.vars.query or '',
requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'), requires=IS_NOT_EMPTY(
error_message=T("Cannot be empty")))), TR(T('Update:'),
INPUT(_name='update_check', _type='checkbox', INPUT(_name='update_check', _type='checkbox',
value=False), INPUT(_style='width:400px', value=False), INPUT(_style='width:400px',
_name='update_fields', _value=request.vars.update_fields _name='update_fields', _value=request.vars.update_fields
@@ -200,13 +202,14 @@ def select():
_class='delete', _type='checkbox', value=False), ''), _class='delete', _type='checkbox', value=False), ''),
TR('', '', INPUT(_type='submit', _value=T('submit')))), TR('', '', INPUT(_type='submit', _value=T('submit')))),
_action=URL(r=request, args=request.args)) _action=URL(r=request, args=request.args))
tb = None
if form.accepts(request.vars, formname=None): if form.accepts(request.vars, formname=None):
regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+') regex = re.compile(request.args[0] + '\.(?P<table>\w+)\..+')
match = regex.match(form.vars.query.strip()) match = regex.match(form.vars.query.strip())
if match: if match:
table = match.group('table') table = match.group('table')
try: try:
tb = None
nrows = db(query).count() nrows = db(query).count()
if form.vars.update_check and form.vars.update_fields: if form.vars.update_check and form.vars.update_fields:
db(query).update(**eval_in_global_env('dict(%s)' db(query).update(**eval_in_global_env('dict(%s)'
@@ -217,9 +220,11 @@ def select():
response.flash = T('%s %%{row} deleted', nrows) response.flash = T('%s %%{row} deleted', nrows)
nrows = db(query).count() nrows = db(query).count()
if orderby: if orderby:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop), orderby=eval_in_global_env(orderby)) rows = db(query, ignore_common_filters=True).select(limitby=(
start, stop), orderby=eval_in_global_env(orderby))
else: else:
rows = db(query,ignore_common_filters=True).select(limitby=(start, stop)) rows = db(query, ignore_common_filters=True).select(
limitby=(start, stop))
except Exception, e: except Exception, e:
import traceback import traceback
tb = traceback.format_exc() tb = traceback.format_exc()
@@ -268,9 +273,11 @@ def update():
if keyed: if keyed:
key = [f for f in request.vars if f in db[table]._primarykey] key = [f for f in request.vars if f in db[table]._primarykey]
if key: if key:
record = db(db[table][key[0]] == request.vars[key[0]], ignore_common_filters=True).select().first() record = db(db[table][key[0]] == request.vars[key[
0]], ignore_common_filters=True).select().first()
else: else:
record = db(db[table].id == request.args(2),ignore_common_filters=True).select().first() record = db(db[table].id == request.args(
2), ignore_common_filters=True).select().first()
if not record: if not record:
qry = query_by_table_type(table, db) qry = query_by_table_type(table, db)
@@ -282,7 +289,8 @@ def update():
for k in db[table]._primarykey: for k in db[table]._primarykey:
db[table][k].writable = False db[table][k].writable = False
form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'), form = SQLFORM(
db[table], record, deletable=True, delete_label=T('Check to delete'),
ignore_rw=ignore_rw and not keyed, ignore_rw=ignore_rw and not keyed,
linkto=URL('select', linkto=URL('select',
args=request.args[:1]), upload=URL(r=request, args=request.args[:1]), upload=URL(r=request,
@@ -304,11 +312,15 @@ def update():
def state(): def state():
return dict() return dict()
def ccache(): def ccache():
form = FORM( form = FORM(
P(TAG.BUTTON(T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")), P(TAG.BUTTON(
P(TAG.BUTTON(T("Clear RAM"), _type="submit", _name="ram", _value="ram")), T("Clear CACHE?"), _type="submit", _name="yes", _value="yes")),
P(TAG.BUTTON(T("Clear DISK"), _type="submit", _name="disk", _value="disk")), P(TAG.BUTTON(
T("Clear RAM"), _type="submit", _name="ram", _value="ram")),
P(TAG.BUTTON(
T("Clear DISK"), _type="submit", _name="disk", _value="disk")),
) )
if form.accepts(request.vars, session): if form.accepts(request.vars, session):
@@ -332,11 +344,16 @@ def ccache():
redirect(URL(r=request)) redirect(URL(r=request))
try: try:
from guppy import hpy; hp=hpy() from guppy import hpy
hp = hpy()
except ImportError: except ImportError:
hp = False hp = False
import shelve, os, copy, time, math import shelve
import os
import copy
import time
import math
from gluon import portalocker from gluon import portalocker
ram = { ram = {
@@ -383,7 +400,8 @@ def ccache():
locker = open(os.path.join(request.folder, locker = open(os.path.join(request.folder,
'cache/cache.lock'), 'a') 'cache/cache.lock'), 'a')
portalocker.lock(locker, portalocker.LOCK_EX) portalocker.lock(locker, portalocker.LOCK_EX)
disk_storage = shelve.open(os.path.join(request.folder, 'cache/cache.shelve')) disk_storage = shelve.open(
os.path.join(request.folder, 'cache/cache.shelve'))
try: try:
for key, value in disk_storage.items(): for key, value in disk_storage.items():
if isinstance(value, dict): if isinstance(value, dict):
@@ -414,7 +432,8 @@ def ccache():
total['misses'] = ram['misses'] + disk['misses'] total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys'] total['keys'] = ram['keys'] + disk['keys']
try: try:
total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses']) total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
except (KeyError, ZeroDivisionError): except (KeyError, ZeroDivisionError):
total['ratio'] = 0 total['ratio'] = 0
@@ -440,6 +459,3 @@ def ccache():
return dict(form=form, total=total, return dict(form=form, total=total,
ram=ram, disk=disk, object_stats=hp != False) ram=ram, disk=disk, object_stats=hp != False)
@@ -9,6 +9,7 @@
## - call exposes all registered services (none by default) ## - call exposes all registered services (none by default)
######################################################################### #########################################################################
def index(): def index():
""" """
example action using the internationalization operator T and flash example action using the internationalization operator T and flash
@@ -20,6 +21,7 @@ def index():
response.flash = T("Welcome to web2py!") response.flash = T("Welcome to web2py!")
return dict(message=T('Hello World')) return dict(message=T('Hello World'))
def user(): def user():
""" """
exposes: exposes:
+1
View File
@@ -89,6 +89,7 @@
'export as csv file': 'експортувати як файл csv', 'export as csv file': 'експортувати як файл csv',
'FAQ': 'ЧаПи (FAQ)', 'FAQ': 'ЧаПи (FAQ)',
'First name': "Ім'я", 'First name': "Ім'я",
'Forgot username?': "Забули ім'я користувача?",
'Forms and Validators': 'Форми та коректність даних', 'Forms and Validators': 'Форми та коректність даних',
'Free Applications': 'Вільні додатки', 'Free Applications': 'Вільні додатки',
'Group %(group_id)s created': 'Групу %(group_id)s створено', 'Group %(group_id)s created': 'Групу %(group_id)s створено',
+71 -36
View File
@@ -5,7 +5,8 @@
## Customize your APP title, subtitle and menus here ## Customize your APP title, subtitle and menus here
######################################################################### #########################################################################
response.title = ' '.join(word.capitalize() for word in request.application.split('_')) response.title = ' '.join(
word.capitalize() for word in request.application.split('_'))
response.subtitle = T('customize me!') response.subtitle = T('customize me!')
## read more at http://dev.w3.org/html5/markup/meta.name.html ## read more at http://dev.w3.org/html5/markup/meta.name.html
@@ -29,6 +30,7 @@ response.menu = [
## provide shortcuts for development. remove in production ## provide shortcuts for development. remove in production
######################################################################### #########################################################################
def _(): def _():
# shortcuts # shortcuts
app = request.application app = request.application
@@ -39,63 +41,96 @@ def _():
(T('My Sites'), False, URL('admin', 'default', 'site')), (T('My Sites'), False, URL('admin', 'default', 'site')),
(T('This App'), False, URL('admin', 'default', 'design/%s' % app), [ (T('This App'), False, URL('admin', 'default', 'design/%s' % app), [
(T('Controller'), False, (T('Controller'), False,
URL('admin','default','edit/%s/controllers/%s.py' % (app,ctr))), URL(
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
(T('View'), False, (T('View'), False,
URL('admin','default','edit/%s/views/%s' % (app,response.view))), URL(
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
(T('Layout'), False, (T('Layout'), False,
URL('admin','default','edit/%s/views/layout.html' % app)), URL(
'admin', 'default', 'edit/%s/views/layout.html' % app)),
(T('Stylesheet'), False, (T('Stylesheet'), False,
URL('admin','default','edit/%s/static/css/web2py.css' % app)), URL(
'admin', 'default', 'edit/%s/static/css/web2py.css' % app)),
(T('DB Model'), False, (T('DB Model'), False,
URL('admin','default','edit/%s/models/db.py' % app)), URL(
'admin', 'default', 'edit/%s/models/db.py' % app)),
(T('Menu Model'), False, (T('Menu Model'), False,
URL('admin','default','edit/%s/models/menu.py' % app)), URL(
'admin', 'default', 'edit/%s/models/menu.py' % app)),
(T('Database'), False, URL(app, 'appadmin', 'index')), (T('Database'), False, URL(app, 'appadmin', 'index')),
(T('Errors'),False, URL('admin','default','errors/' + app)), (T('Errors'), False, URL(
(T('About'),False, URL('admin','default','about/' + app)), 'admin', 'default', 'errors/' + app)),
(T('About'), False, URL(
'admin', 'default', 'about/' + app)),
]), ]),
('web2py.com', False, 'http://www.web2py.com', [ ('web2py.com', False, 'http://www.web2py.com', [
(T('Download'),False,'http://www.web2py.com/examples/default/download'), (T('Download'), False,
(T('Support'),False,'http://www.web2py.com/examples/default/support'), '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('Demo'), False, 'http://web2py.com/demo_admin'),
(T('Quick Examples'),False,'http://web2py.com/examples/default/examples'), (T('Quick Examples'), False,
'http://web2py.com/examples/default/examples'),
(T('FAQ'), False, 'http://web2py.com/AlterEgo'), (T('FAQ'), False, 'http://web2py.com/AlterEgo'),
(T('Videos'),False,'http://www.web2py.com/examples/default/videos/'), (T('Videos'), False,
(T('Free Applications'),False,'http://web2py.com/appliances'), 'http://www.web2py.com/examples/default/videos/'),
(T('Free Applications'),
False, 'http://web2py.com/appliances'),
(T('Plugins'), False, 'http://web2py.com/plugins'), (T('Plugins'), False, 'http://web2py.com/plugins'),
(T('Layouts'), False, 'http://web2py.com/layouts'), (T('Layouts'), False, 'http://web2py.com/layouts'),
(T('Recipes'), False, 'http://web2pyslices.com/'), (T('Recipes'), False, 'http://web2pyslices.com/'),
(T('Semantic'), False, 'http://web2py.com/semantic'), (T('Semantic'), False, 'http://web2py.com/semantic'),
]), ]),
(T('Documentation'), False, 'http://www.web2py.com/book', [ (T('Documentation'), False, 'http://www.web2py.com/book', [
(T('Preface'),False,'http://www.web2py.com/book/default/chapter/00'), (T('Preface'), False,
(T('Introduction'),False,'http://www.web2py.com/book/default/chapter/01'), 'http://www.web2py.com/book/default/chapter/00'),
(T('Python'),False,'http://www.web2py.com/book/default/chapter/02'), (T('Introduction'), False,
(T('Overview'),False,'http://www.web2py.com/book/default/chapter/03'), 'http://www.web2py.com/book/default/chapter/01'),
(T('The Core'),False,'http://www.web2py.com/book/default/chapter/04'), (T('Python'), False,
(T('The Views'),False,'http://www.web2py.com/book/default/chapter/05'), 'http://www.web2py.com/book/default/chapter/02'),
(T('Database'),False,'http://www.web2py.com/book/default/chapter/06'), (T('Overview'), False,
(T('Forms and Validators'),False,'http://www.web2py.com/book/default/chapter/07'), 'http://www.web2py.com/book/default/chapter/03'),
(T('Email and SMS'),False,'http://www.web2py.com/book/default/chapter/08'), (T('The Core'), False,
(T('Access Control'),False,'http://www.web2py.com/book/default/chapter/09'), 'http://www.web2py.com/book/default/chapter/04'),
(T('Services'),False,'http://www.web2py.com/book/default/chapter/10'), (T('The Views'), False,
(T('Ajax Recipes'),False,'http://www.web2py.com/book/default/chapter/11'), 'http://www.web2py.com/book/default/chapter/05'),
(T('Components and Plugins'),False,'http://www.web2py.com/book/default/chapter/12'), (T('Database'), False,
(T('Deployment Recipes'),False,'http://www.web2py.com/book/default/chapter/13'), 'http://www.web2py.com/book/default/chapter/06'),
(T('Other Recipes'),False,'http://www.web2py.com/book/default/chapter/14'), (T('Forms and Validators'), False,
(T('Buy this book'),False,'http://stores.lulu.com/web2py'), '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('Community'), False, None, [
(T('Groups'),False,'http://www.web2py.com/examples/default/usergroups'), (T('Groups'), False,
'http://www.web2py.com/examples/default/usergroups'),
(T('Twitter'), False, 'http://twitter.com/web2py'), (T('Twitter'), False, 'http://twitter.com/web2py'),
(T('Live Chat'),False,'http://webchat.freenode.net/?channels=web2py'), (T('Live Chat'), False,
'http://webchat.freenode.net/?channels=web2py'),
]), ]),
(T('Plugins'), False, None, [ (T('Plugins'), False, None, [
('plugin_wiki',False,'http://web2py.com/examples/default/download'), ('plugin_wiki', False,
(T('Other Plugins'),False,'http://web2py.com/plugins'), 'http://web2py.com/examples/default/download'),
(T('Layout Plugins'),False,'http://web2py.com/layouts'), (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 #NOTE! To change language in your application using these rules add this line
#in one of your models files: #in one of your models files:
# if request.uri_language: T.force(request.uri_language) # if request.uri_language: T.force(request.uri_language)
-5
View File
@@ -61,8 +61,3 @@ sys.path = [path]+[p for p in sys.path if not p==path]
import gluon.main import gluon.main
wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase) wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase)
-5
View File
@@ -51,8 +51,3 @@ if SOFTCRON:
global_settings.web2py_crontype = 'soft' global_settings.web2py_crontype = 'soft'
fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run() fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run()
+7 -5
View File
@@ -78,6 +78,12 @@ def wsgiapp(env, res):
"""Return the wsgiapp""" """Return the wsgiapp"""
env['PATH_INFO'] = env['PATH_INFO'].decode('latin1').encode('utf8') env['PATH_INFO'] = env['PATH_INFO'].decode('latin1').encode('utf8')
#when using the blobstore image uploader GAE dev SDK passes these as unicode
# they should be regular strings as they are parts of URLs
env['wsgi.url_scheme'] = str(env['wsgi.url_scheme'])
env['QUERY_STRING'] = str(env['QUERY_STRING'])
env['SERVER_NAME'] = str(env['SERVER_NAME'])
#this deals with a problem where GAE development server seems to forget #this deals with a problem where GAE development server seems to forget
# the path between requests # the path between requests
if global_settings.web2py_runtime == 'gae:development': if global_settings.web2py_runtime == 'gae:development':
@@ -91,14 +97,10 @@ def wsgiapp(env, res):
if LOG_STATS or DEBUG: if LOG_STATS or DEBUG:
wsgiapp = log_stats(wsgiapp) wsgiapp = log_stats(wsgiapp)
def main(): def main():
"""Run the wsgi app""" """Run the wsgi app"""
run_wsgi_app(wsgiapp) run_wsgi_app(wsgiapp)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
-11
View File
@@ -42,14 +42,3 @@ if 0:
mail = Mail() mail = Mail()
service = Service() service = Service()
plugins = PluginManager() plugins = PluginManager()
+17 -11
View File
@@ -23,6 +23,7 @@ from http import HTTP
if not global_settings.web2py_runtime_gae: if not global_settings.web2py_runtime_gae:
import site import site
def apath(path='', r=None): def apath(path='', r=None):
""" """
Builds a path inside an application folder Builds a path inside an application folder
@@ -95,6 +96,7 @@ def app_pack_compiled(app, request, raise_ex=False):
raise raise
return None return None
def app_cleanup(app, request): def app_cleanup(app, request):
""" """
Removes session, cache and error files Removes session, cache and error files
@@ -158,6 +160,7 @@ def app_compile(app, request):
remove_compiled_application(folder) remove_compiled_application(folder)
return tb return tb
def app_create(app, request, force=False, key=None, info=False): def app_create(app, request, force=False, key=None, info=False):
""" """
Create a copy of welcome.w2p (scaffolding) app Create a copy of welcome.w2p (scaffolding) app
@@ -283,6 +286,7 @@ def app_uninstall(app, request):
except Exception: except Exception:
return False return False
def plugin_pack(app, plugin_name, request): def plugin_pack(app, plugin_name, request):
""" """
Builds a w2p package for the application Builds a w2p package for the application
@@ -302,12 +306,14 @@ def plugin_pack(app, plugin_name, request):
filename of the w2p file or None on error filename of the w2p file or None on error
""" """
try: try:
filename = apath('../deposit/web2py.plugin.%s.w2p' % plugin_name, request) filename = apath(
'../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
w2p_pack_plugin(filename, apath(app, request), plugin_name) w2p_pack_plugin(filename, apath(app, request), plugin_name)
return filename return filename
except Exception: except Exception:
return False return False
def plugin_install(app, fobj, request, filename): def plugin_install(app, fobj, request, filename):
""" """
Installs an application: Installs an application:
@@ -345,6 +351,7 @@ def plugin_install(app, fobj, request, filename):
os.unlink(upname) os.unlink(upname)
return False return False
def check_new_version(myversion, version_URL): def check_new_version(myversion, version_URL):
""" """
Compares current web2py's version with the latest stable web2py version. Compares current web2py's version with the latest stable web2py version.
@@ -375,6 +382,7 @@ def check_new_version(myversion, version_URL):
else: else:
return False, version return False, version
def unzip(filename, dir, subfolder=''): def unzip(filename, dir, subfolder=''):
""" """
Unzips filename into dir (.zip only, no .gz etc) Unzips filename into dir (.zip only, no .gz etc)
@@ -382,7 +390,7 @@ def unzip(filename, dir, subfolder=''):
""" """
filename = abspath(filename) filename = abspath(filename)
if not zipfile.is_zipfile(filename): if not zipfile.is_zipfile(filename):
raise RuntimeError, 'Not a valid zipfile' raise RuntimeError('Not a valid zipfile')
zf = zipfile.ZipFile(filename) zf = zipfile.ZipFile(filename)
if not subfolder.endswith('/'): if not subfolder.endswith('/'):
subfolder = subfolder + '/' subfolder = subfolder + '/'
@@ -450,20 +458,25 @@ def upgrade(request, url='http://web2py.com'):
except Exception, e: except Exception, e:
return False, e return False, e
def add_path_first(path): def add_path_first(path):
sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))] sys.path = [path] + [p for p in sys.path if (
not p == path and not p == (path + '/'))]
if not global_settings.web2py_runtime_gae: if not global_settings.web2py_runtime_gae:
site.addsitedir(path) site.addsitedir(path)
def create_missing_folders(): def create_missing_folders():
if not global_settings.web2py_runtime_gae: if not global_settings.web2py_runtime_gae:
for path in ('applications', 'deposit', 'site-packages', 'logs'): for path in ('applications', 'deposit', 'site-packages', 'logs'):
path = abspath(path, gluon=True) path = abspath(path, gluon=True)
if not os.path.exists(path): if not os.path.exists(path):
os.mkdir(path) os.mkdir(path)
paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '') paths = (global_settings.gluon_parent, abspath(
'site-packages', gluon=True), abspath('gluon', gluon=True), '')
[add_path_first(path) for path in paths] [add_path_first(path) for path in paths]
def create_missing_app_folders(request): def create_missing_app_folders(request):
if not global_settings.web2py_runtime_gae: if not global_settings.web2py_runtime_gae:
if request.folder not in global_settings.app_folders: if request.folder not in global_settings.app_folders:
@@ -474,10 +487,3 @@ def create_missing_app_folders(request):
if not os.path.exists(path): if not os.path.exists(path):
os.mkdir(path) os.mkdir(path)
global_settings.app_folders.add(request.folder) global_settings.app_folders.add(request.folder)
+20 -11
View File
@@ -40,6 +40,7 @@ __all__ = ['Cache', 'lazy_cache']
DEFAULT_TIME_EXPIRE = 300 DEFAULT_TIME_EXPIRE = 300
class CacheAbstract(object): class CacheAbstract(object):
""" """
Abstract class for cache implementations. Abstract class for cache implementations.
@@ -130,6 +131,7 @@ class CacheAbstract(object):
if r.match(str(key)): if r.match(str(key)):
del storage[key] del storage[key]
class CacheInRam(CacheAbstract): class CacheInRam(CacheAbstract):
""" """
Ram based caching Ram based caching
@@ -147,8 +149,10 @@ class CacheInRam(CacheAbstract):
self.request = request self.request = request
def initialize(self): def initialize(self):
if self.initialized: return if self.initialized:
else: self.initialized = True return
else:
self.initialized = True
self.locker.acquire() self.locker.acquire()
request = self.request request = self.request
if request: if request:
@@ -172,7 +176,8 @@ class CacheInRam(CacheAbstract):
self._clear(storage, regex) self._clear(storage, regex)
if not CacheAbstract.cache_stats_name in storage.keys(): if not CacheAbstract.cache_stats_name in storage.keys():
storage[CacheAbstract.cache_stats_name] = {'hit_total': 0,'misses': 0} storage[CacheAbstract.cache_stats_name] = {
'hit_total': 0, 'misses': 0}
self.locker.release() self.locker.release()
@@ -269,14 +274,15 @@ class CacheOnDisk(CacheAbstract):
try: try:
storage = shelve.open(self.shelve_name) storage = shelve.open(self.shelve_name)
except: except:
logger.error('corrupted cache file %s, will try rebuild it' \ logger.error('corrupted cache file %s, will try rebuild it'
% (self.shelve_name)) % (self.shelve_name))
storage = None storage = None
if not storage and os.path.exists(self.shelve_name): if not storage and os.path.exists(self.shelve_name):
os.unlink(self.shelve_name) os.unlink(self.shelve_name)
storage = shelve.open(self.shelve_name) storage = shelve.open(self.shelve_name)
if not CacheAbstract.cache_stats_name in storage.keys(): if not CacheAbstract.cache_stats_name in storage.keys():
storage[CacheAbstract.cache_stats_name] = {'hit_total':0, 'misses': 0} storage[CacheAbstract.cache_stats_name] = {
'hit_total': 0, 'misses': 0}
storage.sync() storage.sync()
except Exception, e: except Exception, e:
if storage: if storage:
@@ -286,7 +292,8 @@ class CacheOnDisk(CacheAbstract):
portalocker.unlock(locker) portalocker.unlock(locker)
locker.close() locker.close()
locked = False locked = False
raise RuntimeError, 'unable to create/re-create cache file %s' % self.shelve_name raise RuntimeError(
'unable to create/re-create cache file %s' % self.shelve_name)
self.locker = locker self.locker = locker
self.locked = locked self.locked = locked
self.storage = storage self.storage = storage
@@ -298,8 +305,10 @@ class CacheOnDisk(CacheAbstract):
self.folder = folder self.folder = folder
def initialize(self): def initialize(self):
if self.initialized: return if self.initialized:
else: self.initialized = True return
else:
self.initialized = True
folder = self.folder folder = self.folder
request = self.request request = self.request
@@ -365,6 +374,7 @@ class CacheOnDisk(CacheAbstract):
self._close_shelve_and_unlock() self._close_shelve_and_unlock()
return value return value
class CacheAction(object): class CacheAction(object):
def __init__(self, func, key, time_expire, cache, cache_model): def __init__(self, func, key, time_expire, cache, cache_model):
self.__name__ = func.__name__ self.__name__ = func.__name__
@@ -374,6 +384,7 @@ class CacheAction(object):
self.time_expire = time_expire self.time_expire = time_expire
self.cache = cache self.cache = cache
self.cache_model = cache_model self.cache_model = cache_model
def __call__(self, *a, **b): def __call__(self, *a, **b):
if not self.key: if not self.key:
key2 = self.__name__ + ':' + repr(a) + ':' + repr(b) key2 = self.__name__ + ':' + repr(a) + ':' + repr(b)
@@ -483,12 +494,10 @@ def lazy_cache(key=None,time_expire=None,cache_model='ram'):
""" """
def decorator(f, key=key, time_expire=time_expire, cache_model=cache_model): def decorator(f, key=key, time_expire=time_expire, cache_model=cache_model):
key = key or repr(f) key = key or repr(f)
def g(*c, **d): def g(*c, **d):
from gluon import current from gluon import current
return current.cache(key, time_expire, cache_model)(f)(*c, **d) return current.cache(key, time_expire, cache_model)(f)(*c, **d)
g.__name__ = f.__name__ g.__name__ = f.__name__
return g return g
return decorator return decorator
-7
View File
@@ -51,10 +51,3 @@ def getcfs(key, filename, filter=None):
cfs[key] = (t, data) cfs[key] = (t, data)
cfs_lock.release() cfs_lock.release()
return data return data
+30 -20
View File
@@ -95,6 +95,7 @@ _TEST()
CACHED_REGEXES = {} CACHED_REGEXES = {}
CACHED_REGEXES_MAX_SIZE = 1000 CACHED_REGEXES_MAX_SIZE = 1000
def re_compile(regex): def re_compile(regex):
try: try:
return CACHED_REGEXES[regex] return CACHED_REGEXES[regex]
@@ -104,6 +105,7 @@ def re_compile(regex):
compiled_regex = CACHED_REGEXES[regex] = re.compile(regex) compiled_regex = CACHED_REGEXES[regex] = re.compile(regex)
return compiled_regex return compiled_regex
class mybuiltin(object): class mybuiltin(object):
""" """
NOTE could simple use a dict and populate it, NOTE could simple use a dict and populate it,
@@ -114,10 +116,12 @@ class mybuiltin(object):
try: try:
return getattr(__builtin__, key) return getattr(__builtin__, key)
except AttributeError: except AttributeError:
raise KeyError, key raise KeyError(key)
def __setitem__(self, key, value): def __setitem__(self, key, value):
setattr(self, key, value) setattr(self, key, value)
def LOAD(c=None, f='index', args=None, vars=None, def LOAD(c=None, f='index', args=None, vars=None,
extension=None, target=None, ajax=False, ajax_trap=False, extension=None, target=None, ajax=False, ajax_trap=False,
url=None, user_signature=False, timeout=None, times=1, url=None, user_signature=False, timeout=None, times=1,
@@ -134,7 +138,8 @@ def LOAD(c=None, f='index', args=None, vars=None,
is added on page loading without delay. is added on page loading without delay.
""" """
from html import TAG, DIV, URL, SCRIPT, XML from html import TAG, DIV, URL, SCRIPT, XML
if args is None: args = [] if args is None:
args = []
vars = Storage(vars or {}) vars = Storage(vars or {})
target = target or 'c' + str(random.random())[2:] target = target or 'c' + str(random.random())[2:]
attr['_id'] = target attr['_id'] = target
@@ -160,7 +165,8 @@ def LOAD(c=None, f='index', args=None, vars=None,
if not isinstance(timeout, (int, long)): if not isinstance(timeout, (int, long)):
raise ValueError("Timeout argument must be an integer or None") raise ValueError("Timeout argument must be an integer or None")
elif timeout <= 0: elif timeout <= 0:
raise ValueError("Timeout argument must be greater than zero or None") raise ValueError(
"Timeout argument must be greater than zero or None")
statement = "web2py_component('%s','%s', %s, %s);" \ statement = "web2py_component('%s','%s', %s, %s);" \
% (url, target, timeout, times) % (url, target, timeout, times)
else: else:
@@ -186,7 +192,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
other_request.post_vars = Storage() other_request.post_vars = Storage()
other_response = Response() other_response = Response()
other_request.env.path_info = '/' + \ other_request.env.path_info = '/' + \
'/'.join([request.application,c,f] + \ '/'.join([request.application, c, f] +
map(str, other_request.args)) map(str, other_request.args))
other_request.env.query_string = \ other_request.env.query_string = \
vars and URL(vars=vars).split('?')[1] or '' vars and URL(vars=vars).split('?')[1] or ''
@@ -196,7 +202,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
other_request.env.http_web2py_component_element = target other_request.env.http_web2py_component_element = target
other_response.view = '%s/%s.%s' % (c, f, other_request.extension) other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
other_environment = copy.copy(current.globalenv) ### NASTY other_environment = copy.copy(current.globalenv) # NASTY
other_response._view_environment = other_environment other_response._view_environment = other_environment
other_response.generic_patterns = \ other_response.generic_patterns = \
@@ -225,17 +231,18 @@ def LOAD(c=None, f='index', args=None, vars=None,
return TAG[''](DIV(XML(page), **attr), script) return TAG[''](DIV(XML(page), **attr), script)
class LoadFactory(object): class LoadFactory(object):
""" """
Attention: this helper is new and experimental Attention: this helper is new and experimental
""" """
def __init__(self, environment): def __init__(self, environment):
self.environment = environment self.environment = environment
def __call__(self, c=None, f='index', args=None, vars=None, def __call__(self, c=None, f='index', args=None, vars=None,
extension=None, target=None, ajax=False, ajax_trap=False, extension=None, target=None, ajax=False, ajax_trap=False,
url=None, user_signature=False, content='loading...', **attr): url=None, user_signature=False, content='loading...', **attr):
if args is None: args = [] if args is None:
args = []
vars = Storage(vars or {}) vars = Storage(vars or {})
import globals import globals
target = target or 'c' + str(random.random())[2:] target = target or 'c' + str(random.random())[2:]
@@ -266,7 +273,7 @@ class LoadFactory(object):
other_request.post_vars = Storage() other_request.post_vars = Storage()
other_response = globals.Response() other_response = globals.Response()
other_request.env.path_info = '/' + \ other_request.env.path_info = '/' + \
'/'.join([request.application,c,f] + \ '/'.join([request.application, c, f] +
map(str, other_request.args)) map(str, other_request.args))
other_request.env.query_string = \ other_request.env.query_string = \
vars and html.URL(vars=vars).split('?')[1] or '' vars and html.URL(vars=vars).split('?')[1] or ''
@@ -355,12 +362,14 @@ OLD IMPLEMENTATION:
file.close() file.close()
imp.release_lock() imp.release_lock()
if not module: if not module:
raise ImportError, "cannot find module %s in %s" % (filename, modulepath) raise ImportError, "cannot find module %s in %s" % (
filename, modulepath)
return module return module
""" """
_base_environment_ = dict((k, getattr(html, k)) for k in html.__all__) _base_environment_ = dict((k, getattr(html, k)) for k in html.__all__)
_base_environment_.update((k,getattr(validators,k)) for k in validators.__all__) _base_environment_.update(
(k, getattr(validators, k)) for k in validators.__all__)
_base_environment_['__builtins__'] = __builtins__ _base_environment_['__builtins__'] = __builtins__
_base_environment_['HTTP'] = HTTP _base_environment_['HTTP'] = HTTP
_base_environment_['redirect'] = redirect _base_environment_['redirect'] = redirect
@@ -372,6 +381,7 @@ _base_environment_['SQLFORM'] = SQLFORM
_base_environment_['SQLTABLE'] = SQLTABLE _base_environment_['SQLTABLE'] = SQLTABLE
_base_environment_['LOAD'] = LOAD _base_environment_['LOAD'] = LOAD
def build_environment(request, response, session, store_current=True): def build_environment(request, response, session, store_current=True):
""" """
Build the environment dictionary into which web2py files are executed. Build the environment dictionary into which web2py files are executed.
@@ -403,7 +413,7 @@ def build_environment(request, response, session, store_current=True):
elif is_pypy: # apply the same hack to pypy too elif is_pypy: # apply the same hack to pypy too
__builtins__ = mybuiltin() __builtins__ = mybuiltin()
else: else:
__builtins__['__import__'] = __builtin__.__import__ ### WHY? __builtins__['__import__'] = __builtin__.__import__ # WHY?
environment['request'] = request environment['request'] = request
environment['response'] = response environment['response'] = response
environment['session'] = session environment['session'] = session
@@ -415,6 +425,7 @@ def build_environment(request, response, session, store_current=True):
custom_import_install() custom_import_install()
return environment return environment
def save_pyc(filename): def save_pyc(filename):
""" """
Bytecode compiles the file `filename` Bytecode compiles the file `filename`
@@ -431,7 +442,7 @@ def read_pyc(filename):
""" """
data = read_file(filename, 'rb') data = read_file(filename, 'rb')
if not is_gae and data[:4] != imp.get_magic(): if not is_gae and data[:4] != imp.get_magic():
raise SystemError, 'compiled code is incompatible' raise SystemError('compiled code is incompatible')
return marshal.loads(data[8:]) return marshal.loads(data[8:])
@@ -442,7 +453,10 @@ def compile_views(folder):
path = pjoin(folder, 'views') path = pjoin(folder, 'views')
for file in listdir(path, '^[\w/\-]+(\.\w+)+$'): for file in listdir(path, '^[\w/\-]+(\.\w+)+$'):
try:
data = parse_template(file, path) data = parse_template(file, path)
except Exception, e:
raise Exception("%s in %s" % (e, file))
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_') filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
filename = pjoin(folder, 'compiled', filename) filename = pjoin(folder, 'compiled', filename)
write_file(filename, data) write_file(filename, data)
@@ -548,7 +562,8 @@ def run_controller_in(controller, function, environment):
# TESTING: adjust the path to include site packages # TESTING: adjust the path to include site packages
from settings import global_settings from settings import global_settings
from admin import abspath, add_path_first from admin import abspath, add_path_first
paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '') paths = (global_settings.gluon_parent, abspath(
'site-packages', gluon=True), abspath('gluon', gluon=True), '')
[add_path_first(path) for path in paths] [add_path_first(path) for path in paths]
# TESTING END # TESTING END
@@ -590,6 +605,7 @@ def run_controller_in(controller, function, environment):
vars = vars.xml() vars = vars.xml()
return vars return vars
def run_view_in(environment): def run_view_in(environment):
""" """
Executes the view for the requested action. Executes the view for the requested action.
@@ -655,6 +671,7 @@ def run_view_in(environment):
context=environment) context=environment)
restricted(ccode, environment, layer) restricted(ccode, environment, layer)
def remove_compiled_application(folder): def remove_compiled_application(folder):
""" """
Deletes the folder `compiled` containing the compiled application. Deletes the folder `compiled` containing the compiled application.
@@ -700,10 +717,3 @@ def test():
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
doctest.testmod() doctest.testmod()
-7
View File
@@ -717,10 +717,3 @@ def contenttype(filename, default='text/plain'):
if default.startswith('text/'): if default.startswith('text/'):
default += '; charset=utf-8' default += '; charset=utf-8'
return default return default
+28 -24
View File
@@ -21,6 +21,7 @@ import urllib
_known_tuple_types = {} _known_tuple_types = {}
class NamedTupleBase(tuple): class NamedTupleBase(tuple):
"""Base class for named tuples with the __new__ operator set, named tuples """Base class for named tuples with the __new__ operator set, named tuples
yielded by the namedtuple() function will subclass this and add yielded by the namedtuple() function will subclass this and add
@@ -37,6 +38,7 @@ class NamedTupleBase(tuple):
args = tuple(values) args = tuple(values)
return tuple.__new__(cls, args) return tuple.__new__(cls, args)
def namedtuple(typename, fieldnames): def namedtuple(typename, fieldnames):
""" """
>>> import namedtuples >>> import namedtuples
@@ -75,24 +77,26 @@ def namedtuple(typename, fieldnames):
# Done # Done
return new_tuple_type return new_tuple_type
class AIM: class AIM:
class AIMError(Exception): class AIMError(Exception):
def __init__(self, value): def __init__(self, value):
self.parameter = value self.parameter = value
def __str__(self): def __str__(self):
return str(self.parameter) return str(self.parameter)
def __init__(self, login, transkey, testmode=False): def __init__(self, login, transkey, testmode=False):
if str(login).strip() == '' or login == None: if str(login).strip() == '' or login is None:
raise AIM.AIMError('No login name provided') raise AIM.AIMError('No login name provided')
if str(transkey).strip() == '' or transkey == None: if str(transkey).strip() == '' or transkey is None:
raise AIM.AIMError('No transaction key provided') raise AIM.AIMError('No transaction key provided')
if testmode != True and testmode != False: if testmode != True and testmode != False:
raise AIM.AIMError('Invalid value for testmode. Must be True or False. "{0}" given.'.format(testmode)) raise AIM.AIMError('Invalid value for testmode. Must be True or False. "{0}" given.'.format(testmode))
self.testmode = testmode self.testmode = testmode
self.proxy = None; self.proxy = None
self.delimiter = '|' self.delimiter = '|'
self.results = [] self.results = []
self.error = True self.error = True
@@ -117,8 +121,9 @@ class AIM:
else: else:
url = 'https://secure.authorize.net/gateway/transact.dll' url = 'https://secure.authorize.net/gateway/transact.dll'
if self.proxy == None: if self.proxy is None:
self.results += str(urllib.urlopen(url, encoded_args).read()).split(self.delimiter) self.results += str(urllib.urlopen(
url, encoded_args).read()).split(self.delimiter)
else: else:
opener = urllib.FancyURLopener(self.proxy) opener = urllib.FancyURLopener(self.proxy)
opened = opener.open(url, encoded_args) opened = opener.open(url, encoded_args)
@@ -147,36 +152,37 @@ class AIM:
raise AIM.AIMError(self.response.ResponseText) raise AIM.AIMError(self.response.ResponseText)
def setTransaction(self, creditcard, expiration, total, cvv=None, tax=None, invoice=None): def setTransaction(self, creditcard, expiration, total, cvv=None, tax=None, invoice=None):
if str(creditcard).strip() == '' or creditcard == None: if str(creditcard).strip() == '' or creditcard is None:
raise AIM.AIMError('No credit card number passed to setTransaction(): {0}'.format(creditcard)) raise AIM.AIMError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
if str(expiration).strip() == '' or expiration == None: if str(expiration).strip() == '' or expiration is None:
raise AIM.AIMError('No expiration number to setTransaction(): {0}'.format(expiration)) raise AIM.AIMError('No expiration number to setTransaction(): {0}'.format(expiration))
if str(total).strip() == '' or total == None: if str(total).strip() == '' or total is None:
raise AIM.AIMError('No total amount passed to setTransaction(): {0}'.format(total)) raise AIM.AIMError('No total amount passed to setTransaction(): {0}'.format(total))
self.setParameter('x_card_num', creditcard) self.setParameter('x_card_num', creditcard)
self.setParameter('x_exp_date', expiration) self.setParameter('x_exp_date', expiration)
self.setParameter('x_amount', total) self.setParameter('x_amount', total)
if cvv != None: if cvv is not None:
self.setParameter('x_card_code', cvv) self.setParameter('x_card_code', cvv)
if tax != None: if tax is not None:
self.setParameter('x_tax', tax) self.setParameter('x_tax', tax)
if invoice != None: if invoice is not None:
self.setParameter('x_invoice_num', invoice) self.setParameter('x_invoice_num', invoice)
def setTransactionType(self, transtype=None): def setTransactionType(self, transtype=None):
types = ['AUTH_CAPTURE', 'AUTH_ONLY', 'PRIOR_AUTH_CAPTURE', 'CREDIT', 'CAPTURE_ONLY', 'VOID'] types = ['AUTH_CAPTURE', 'AUTH_ONLY', 'PRIOR_AUTH_CAPTURE',
'CREDIT', 'CAPTURE_ONLY', 'VOID']
if transtype.upper() not in types: if transtype.upper() not in types:
raise AIM.AIMError('Incorrect Transaction Type passed to setTransactionType(): {0}'.format(transtype)) raise AIM.AIMError('Incorrect Transaction Type passed to setTransactionType(): {0}'.format(transtype))
self.setParameter('x_type', transtype.upper()) self.setParameter('x_type', transtype.upper())
def setProxy(self, proxy=None): def setProxy(self, proxy=None):
if str(proxy).strip() == '' or proxy == None: if str(proxy).strip() == '' or proxy is None:
raise AIM.AIMError('No proxy passed to setProxy()') raise AIM.AIMError('No proxy passed to setProxy()')
self.proxy = {'http': str(proxy).strip()} self.proxy = {'http': str(proxy).strip()}
def setParameter(self, key=None, value=None): def setParameter(self, key=None, value=None):
if key != None and value != None and str(key).strip() != '' and str(value).strip() != '': if key is not None and value is not None and str(key).strip() != '' and str(value).strip() != '':
self.parameters[key] = str(value).strip() self.parameters[key] = str(value).strip()
else: else:
raise AIM.AIMError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value)) raise AIM.AIMError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
@@ -194,6 +200,7 @@ class AIM:
responses = ['', 'Approved', 'Declined', 'Error'] responses = ['', 'Approved', 'Declined', 'Error']
return responses[int(self.results[0])] return responses[int(self.results[0])]
def process(creditcard, expiration, total, cvv=None, tax=None, invoice=None, def process(creditcard, expiration, total, cvv=None, tax=None, invoice=None,
login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True): login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True):
payment = AIM(login, transkey, testmode) payment = AIM(login, transkey, testmode)
@@ -205,6 +212,7 @@ def process(creditcard,expiration,total,cvv=None,tax=None,invoice=None,
except AIM.AIMError: except AIM.AIMError:
return False return False
def test(): def test():
import socket import socket
import sys import sys
@@ -219,8 +227,10 @@ def test():
try: try:
payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True) payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True)
payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice) payment.setTransaction(
payment.setParameter('x_duplicate_window', 180) # three minutes duplicate windows creditcard, expiration, total, cvv, tax, invoice)
payment.setParameter(
'x_duplicate_window', 180) # three minutes duplicate windows
payment.setParameter('x_cust_id', '1324') # customer ID payment.setParameter('x_cust_id', '1324') # customer ID
payment.setParameter('x_first_name', 'John') payment.setParameter('x_first_name', 'John')
payment.setParameter('x_last_name', 'Conde') payment.setParameter('x_last_name', 'Conde')
@@ -232,7 +242,8 @@ def test():
payment.setParameter('x_country', 'US') payment.setParameter('x_country', 'US')
payment.setParameter('x_phone', '800-555-1234') payment.setParameter('x_phone', '800-555-1234')
payment.setParameter('x_description', 'Test Transaction') payment.setParameter('x_description', 'Test Transaction')
payment.setParameter('x_customer_ip', socket.gethostbyname(socket.gethostname())) payment.setParameter(
'x_customer_ip', socket.gethostbyname(socket.gethostname()))
payment.setParameter('x_email', 'john@example.com') payment.setParameter('x_email', 'john@example.com')
payment.setParameter('x_email_customer', False) payment.setParameter('x_email_customer', False)
payment.process() payment.process()
@@ -257,10 +268,3 @@ def test():
if __name__ == '__main__': if __name__ == '__main__':
test() test()
+18 -20
View File
@@ -15,25 +15,27 @@ __all__ = ['DowCommerce']
from operator import itemgetter from operator import itemgetter
import urllib import urllib
class DowCommerce: class DowCommerce:
class DowCommerceError(Exception): class DowCommerceError(Exception):
def __init__(self, value): def __init__(self, value):
self.parameter = value self.parameter = value
def __str__(self): def __str__(self):
return str(self.parameter) return str(self.parameter)
def __init__(self, username=None, password=None, demomode=False): def __init__(self, username=None, password=None, demomode=False):
if not demomode: if not demomode:
if str(username).strip() == '' or username == None: if str(username).strip() == '' or username is None:
raise DowCommerce.DowCommerceError('No username provided') raise DowCommerce.DowCommerceError('No username provided')
if str(password).strip() == '' or password == None: if str(password).strip() == '' or password is None:
raise DowCommerce.DowCommerceError('No password provided') raise DowCommerce.DowCommerceError('No password provided')
else: else:
username = 'demo' username = 'demo'
password = 'password' password = 'password'
self.proxy = None; self.proxy = None
self.delimiter = '&' self.delimiter = '&'
self.results = {} self.results = {}
self.error = True self.error = True
@@ -45,11 +47,11 @@ class DowCommerce:
self.setParameter('username', username) self.setParameter('username', username)
self.setParameter('password', password) self.setParameter('password', password)
def process(self): def process(self):
encoded_args = urllib.urlencode(self.parameters) encoded_args = urllib.urlencode(self.parameters)
if self.proxy == None: if self.proxy is None:
results = str(urllib.urlopen(self.url, encoded_args).read()).split(self.delimiter) results = str(urllib.urlopen(
self.url, encoded_args).read()).split(self.delimiter)
else: else:
opener = urllib.FancyURLopener(self.proxy) opener = urllib.FancyURLopener(self.proxy)
opened = opener.open(self.url, encoded_args) opened = opener.open(self.url, encoded_args)
@@ -80,17 +82,18 @@ class DowCommerce:
self.declined = False self.declined = False
raise DowCommerce.DowCommerceError(self.results) raise DowCommerce.DowCommerceError(self.results)
def setTransaction(self, creditcard, expiration, total, cvv=None, orderid=None, orderdescription=None, def setTransaction(
self, creditcard, expiration, total, cvv=None, orderid=None, orderdescription=None,
ipaddress=None, tax=None, shipping=None, ipaddress=None, tax=None, shipping=None,
firstname=None, lastname=None, company=None, address1=None, address2=None, city=None, state=None, zipcode=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, 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_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): shipping_city=None, shipping_state=None, shipping_zipcode=None, shipping_country=None, shipping_emailaddress=None):
if str(creditcard).strip() == '' or creditcard == None: if str(creditcard).strip() == '' or creditcard is None:
raise DowCommerce.DowCommerceError('No credit card number passed to setTransaction(): {0}'.format(creditcard)) raise DowCommerce.DowCommerceError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
if str(expiration).strip() == '' or expiration == None: if str(expiration).strip() == '' or expiration is None:
raise DowCommerce.DowCommerceError('No expiration number passed to setTransaction(): {0}'.format(expiration)) raise DowCommerce.DowCommerceError('No expiration number passed to setTransaction(): {0}'.format(expiration))
if str(total).strip() == '' or total == None: if str(total).strip() == '' or total is None:
raise DowCommerce.DowCommerceError('No total amount passed to setTransaction(): {0}'.format(total)) raise DowCommerce.DowCommerceError('No total amount passed to setTransaction(): {0}'.format(total))
self.setParameter('ccnumber', creditcard) self.setParameter('ccnumber', creditcard)
@@ -165,12 +168,12 @@ class DowCommerce:
self.setParameter('type', transtype.lower()) self.setParameter('type', transtype.lower())
def setProxy(self, proxy=None): def setProxy(self, proxy=None):
if str(proxy).strip() == '' or proxy == None: if str(proxy).strip() == '' or proxy is None:
raise DowCommerce.DowCommerceError('No proxy passed to setProxy()') raise DowCommerce.DowCommerceError('No proxy passed to setProxy()')
self.proxy = {'http': str(proxy).strip()} self.proxy = {'http': str(proxy).strip()}
def setParameter(self, key=None, value=None): def setParameter(self, key=None, value=None):
if key != None and value != None and str(key).strip() != '' and str(value).strip() != '': if key is not None and value is not None and str(key).strip() != '' and str(value).strip() != '':
self.parameters[key] = str(value).strip() self.parameters[key] = str(value).strip()
else: else:
raise DowCommerce.DowCommerceError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value)) raise DowCommerce.DowCommerceError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
@@ -194,6 +197,7 @@ class DowCommerce:
def getResponseText(self): def getResponseText(self):
return self.results['responsetext'] return self.results['responsetext']
def test(): def test():
import socket import socket
import sys import sys
@@ -216,7 +220,8 @@ def test():
try: try:
payment = DowCommerce(demomode=True) payment = DowCommerce(demomode=True)
payment.setTransaction(creditcard, expiration, total, cvv=cvv, tax=tax, orderid=orderid, orderdescription='Test Transaction', payment.setTransaction(
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', 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') zipcode='12345', country='US', phone='888-555-1212', emailaddress='john@noemail.local', ipaddress='192.168.1.1')
@@ -237,10 +242,3 @@ def test():
if __name__ == '__main__': if __name__ == '__main__':
test() test()
-8
View File
@@ -1,8 +0,0 @@
-2
View File
@@ -500,5 +500,3 @@ aes_Rcon = array('B',
'c697356ad4b37dfaefc5913972e4d3bd' 'c697356ad4b37dfaefc5913972e4d3bd'
'61c29f254a943366cc831d3a74e8cb'.decode('hex') '61c29f254a943366cc831d3a74e8cb'.decode('hex')
) )
+15 -4
View File
@@ -42,7 +42,9 @@ revision3.com
viddler.com viddler.com
""" """
import re, cgi, sys import re
import cgi
import sys
from simplejson import loads from simplejson import loads
import urllib import urllib
import uuid import uuid
@@ -77,18 +79,23 @@ EMBED_MAPS = [
'http://lab.viddler.com/services/oembed/'), 'http://lab.viddler.com/services/oembed/'),
] ]
def image(url): def image(url):
return '<img src="%s" style="max-width:100%%"/>' % url return '<img src="%s" style="max-width:100%%"/>' % url
def audio(url): def audio(url):
return '<audio controls="controls" style="max-width:100%%"><source src="%s" /></audio>' % url return '<audio controls="controls" style="max-width:100%%"><source src="%s" /></audio>' % url
def video(url): def video(url):
return '<video controls="controls" style="max-width:100%%"><source src="%s" /></video>' % url return '<video controls="controls" style="max-width:100%%"><source src="%s" /></video>' % url
def googledoc_viewer(url): def googledoc_viewer(url):
return '<iframe src="http://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url) return '<iframe src="http://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
def web2py_component(url): def web2py_component(url):
code = str(uuid.uuid4()) code = str(uuid.uuid4())
return '<div id="%s"></div><script>\nweb2py_component("%s","%s");\n</script>' % (code, url, code) return '<div id="%s"></div><script>\nweb2py_component("%s","%s");\n</script>' % (code, url, code)
@@ -126,11 +133,13 @@ EXTENSION_MAPS = {
'xps': googledoc_viewer, 'xps': googledoc_viewer,
} }
class VimeoURLOpener(urllib.FancyURLopener): class VimeoURLOpener(urllib.FancyURLopener):
"Vimeo blocks the urllib user agent for some reason" "Vimeo blocks the urllib user agent for some reason"
version = "Mozilla/4.0" version = "Mozilla/4.0"
urllib._urlopener = VimeoURLOpener() urllib._urlopener = VimeoURLOpener()
def oembed(url): def oembed(url):
for k, v in EMBED_MAPS: for k, v in EMBED_MAPS:
if k.match(url): if k.match(url):
@@ -143,9 +152,11 @@ def oembed(url):
pass pass
return {} return {}
def extension(url): def extension(url):
return url.split('?')[0].split('.')[-1].lower() return url.split('?')[0].split('.')[-1].lower()
def expand_one(url, cdict): def expand_one(url, cdict):
# try ombed but first check in cache # try ombed but first check in cache
if cdict and url in cdict: if cdict and url in cdict:
@@ -170,9 +181,10 @@ def expand_one(url,cdict):
# else regular link # else regular link
return '<a href="%(u)s">%(u)s</a>' % dict(u=url) return '<a href="%(u)s">%(u)s</a>' % dict(u=url)
def expand_html(html, cdict=None): def expand_html(html, cdict=None):
if not have_soup: if not have_soup:
raise RuntimeError, "Missing BeautifulSoup" raise RuntimeError("Missing BeautifulSoup")
soup = BeautifulSoup(html) soup = BeautifulSoup(html)
comments = soup.findAll(text=lambda text: isinstance(text, Comment)) comments = soup.findAll(text=lambda text: isinstance(text, Comment))
[comment.extract() for comment in comments] [comment.extract() for comment in comments]
@@ -183,6 +195,7 @@ def expand_html(html,cdict=None):
txt.replaceWith(BeautifulSoup(ntxt)) txt.replaceWith(BeautifulSoup(ntxt))
return str(soup) return str(soup)
def test(): def test():
example = """ example = """
<h3>Fringilla nisi parturient nullam</h3> <h3>Fringilla nisi parturient nullam</h3>
@@ -203,5 +216,3 @@ if __name__=="__main__":
print expand_html(open(sys.argv[1]).read()) print expand_html(open(sys.argv[1]).read())
else: else:
print test() print test()
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -12,6 +12,7 @@ cache.ram=cache.disk=MemcacheClient(request)
import time import time
from google.appengine.api.memcache import Client from google.appengine.api.memcache import Client
class MemcacheClient(object): class MemcacheClient(object):
client = Client() client = Client()
@@ -29,7 +30,7 @@ class MemcacheClient(object):
dt = time_expire dt = time_expire
value = None value = None
obj = self.client.get(key) obj = self.client.get(key)
if obj and (dt == None or obj[0] > time.time() - dt): if obj and (dt is None or obj[0] > time.time() - dt):
value = obj[1] value = obj[1]
elif f is None: elif f is None:
if obj: if obj:
+6 -10
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. :param exponent: rate of exponential back-off.
""" """
import time, logging import time
import logging
from google.appengine.api import apiproxy_stub_map from google.appengine.api import apiproxy_stub_map
from google.appengine.runtime import apiproxy_errors from google.appengine.runtime import apiproxy_errors
from google.appengine.datastore import datastore_pb from google.appengine.datastore import datastore_pb
@@ -70,10 +71,12 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
return wrapped(*args, **kwargs) return wrapped(*args, **kwargs)
except apiproxy_errors.ApplicationError, err: except apiproxy_errors.ApplicationError, err:
errno = err.application_error errno = err.application_error
if errno not in errors: raise if errno not in errors:
raise
sleep = (exponent ** count) * interval sleep = (exponent ** count) * interval
count += 1.0 count += 1.0
if count > attempts: raise if count > attempts:
raise
msg = "Datastore %s: retry #%d in %s seconds.\n%s" msg = "Datastore %s: retry #%d in %s seconds.\n%s"
vals = '' vals = ''
if count == 1.0: if count == 1.0:
@@ -84,10 +87,3 @@ def autoretry_datastore_timeouts(attempts=5.0, interval=0.1, exponent=2.0):
setattr(wrapper, '_autoretry_datastore_timeouts', False) setattr(wrapper, '_autoretry_datastore_timeouts', False)
if getattr(wrapped, '_autoretry_datastore_timeouts', True): if getattr(wrapped, '_autoretry_datastore_timeouts', True):
apiproxy_stub_map.MakeSyncCall = wrapper apiproxy_stub_map.MakeSyncCall = wrapper
+11 -9
View File
@@ -12,6 +12,7 @@ from gluon.sanitizer import sanitize
from gluon.contrib.markmin.markmin2latex import markmin2latex from gluon.contrib.markmin.markmin2latex import markmin2latex
from gluon.contrib.markmin.markmin2pdf import markmin2pdf from gluon.contrib.markmin.markmin2pdf import markmin2pdf
def wrapper(f): def wrapper(f):
def g(data): def g(data):
try: try:
@@ -25,10 +26,12 @@ def wrapper(f):
raise HTTP(405, '%s error' % e) raise HTTP(405, '%s error' % e)
return g return g
def latex_from_html(html): def latex_from_html(html):
markmin = TAG(html).element('body').flatten(markmin_serializer) markmin = TAG(html).element('body').flatten(markmin_serializer)
return XML(markmin2latex(markmin)) return XML(markmin2latex(markmin))
def pdflatex_from_html(html): def pdflatex_from_html(html):
if os.system('which pdflatex > /dev/null') == 0: if os.system('which pdflatex > /dev/null') == 0:
markmin = TAG(html).element('body').flatten(markmin_serializer) markmin = TAG(html).element('body').flatten(markmin_serializer)
@@ -42,29 +45,28 @@ def pdflatex_from_html(html):
else: else:
return XML(out) return XML(out)
def pyfpdf_from_html(html): def pyfpdf_from_html(html):
request = current.request request = current.request
def image_map(path): def image_map(path):
if path.startswith('/%s/static/' % request.application): if path.startswith('/%s/static/' % request.application):
return os.path.join(request.folder, path.split('/', 2)[2]) return os.path.join(request.folder, path.split('/', 2)[2])
return 'http%s://%s%s' % (request.is_https and 's' or '', request.env.http_host, path) return 'http%s://%s%s' % (request.is_https and 's' or '', request.env.http_host, path)
class MyFPDF(FPDF, HTMLMixin): pass
class MyFPDF(FPDF, HTMLMixin):
pass
pdf = MyFPDF() pdf = MyFPDF()
pdf.add_page() pdf.add_page()
html = sanitize(html, escape=False) #### should have better list of allowed tags html = sanitize(
html, escape=False) # should have better list of allowed tags
pdf.write_html(html, image_map=image_map) pdf.write_html(html, image_map=image_map)
return XML(pdf.output(dest='S')) return XML(pdf.output(dest='S'))
def pdf_from_html(html): def pdf_from_html(html):
# try use latex and pdflatex # try use latex and pdflatex
if os.system('which pdflatex > /dev/null') == 0: if os.system('which pdflatex > /dev/null') == 0:
return pdflatex_from_html(html) return pdflatex_from_html(html)
else: else:
return pyfpdf_from_html(html) return pyfpdf_from_html(html)
+1 -7
View File
@@ -1,5 +1,6 @@
from gluon import XML from gluon import XML
def button(merchant_id="123456789012345", def button(merchant_id="123456789012345",
products=[dict(name="shoes", products=[dict(name="shoes",
quantity=1, quantity=1,
@@ -13,10 +14,3 @@ def button(merchant_id="123456789012345",
list_products += t % dict(k=k + 1, key=key, value=value) list_products += t % dict(k=k + 1, key=key, value=value)
button = '<form action="https://checkout.google.com/api/checkout/v2/checkoutForm/Merchant/%s" id="BB_BuyButtonForm" method="post" name="BB_BuyButtonForm" target="_top">%s<input name="_charset_" type="hidden" value="utf-8"/><input alt="" src="https://checkout.google.com/buttons/buy.gif?merchant_id=%s&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) 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) return XML(button)
-7
View File
@@ -3,10 +3,3 @@
__all__ = ['DAL', 'Field', 'drivers', 'gae'] __all__ = ['DAL', 'Field', 'drivers', 'gae']
from gluon.dal import DAL, Field, Table, Query, Set, Expression, Row, Rows, drivers, BaseAdapter, SQLField, SQLTable, SQLXorable, SQLQuery, SQLSet, SQLRows, SQLStorage, SQLDB, GQLDB, SQLALL, SQLCustomType, gae from gluon.dal import DAL, Field, Table, Query, Set, Expression, Row, Rows, drivers, BaseAdapter, SQLField, SQLTable, SQLXorable, SQLQuery, SQLSet, SQLRows, SQLStorage, SQLDB, GQLDB, SQLALL, SQLCustomType, gae
+2 -2
View File
@@ -22,6 +22,7 @@
######################################################################### #########################################################################
from gluon import current from gluon import current
class RESIZE(object): class RESIZE(object):
def __init__(self, nx=160, ny=80, error_message=' image resize'): def __init__(self, nx=160, ny=80, error_message=' image resize'):
(self.nx, self.ny, self.error_message) = (nx, ny, error_message) (self.nx, self.ny, self.error_message) = (nx, ny, error_message)
@@ -43,6 +44,7 @@ class RESIZE(object):
else: else:
return (value, None) return (value, None)
def THUMB(image, nx=120, ny=120, gae=False, name='thumb'): def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
if image: if image:
if not gae: if not gae:
@@ -57,5 +59,3 @@ def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
return thumb return thumb
else: else:
return image return image
-3
View File
@@ -1,3 +0,0 @@
@@ -22,5 +22,3 @@ def basic_auth(server="http://127.0.0.1"):
except (urllib2.URLError, urllib2.HTTPError): except (urllib2.URLError, urllib2.HTTPError):
return False return False
return basic_login_aux return basic_login_aux
@@ -25,6 +25,7 @@ from gluon.storage import Storage
from gluon.tools import fetch from gluon.tools import fetch
import gluon.contrib.simplejson as json import gluon.contrib.simplejson as json
class BrowserID(object): class BrowserID(object):
""" """
from gluon.contrib.login_methods.browserid_account import BrowserID from gluon.contrib.login_methods.browserid_account import BrowserID
@@ -88,4 +89,3 @@ class BrowserID(object):
A(IMG(_src=self.browserid_button, _alt=self.prompt), _href="#", _onclick=onclick, _class="browserid", _title="Login With BrowserID"), A(IMG(_src=self.browserid_button, _alt=self.prompt), _href="#", _onclick=onclick, _class="browserid", _title="Login With BrowserID"),
SCRIPT(self.asertion_js)) SCRIPT(self.asertion_js))
return form return form
+13 -8
View File
@@ -11,6 +11,7 @@ Tinkered by Szabolcs Gyuris < szimszo n @ o regpreshaz dot eu>
from gluon import current, redirect from gluon import current, redirect
class CasAuth(object): class CasAuth(object):
""" """
Login will be done via Web2py's CAS application, instead of web2py's Login will be done via Web2py's CAS application, instead of web2py's
@@ -39,7 +40,7 @@ class CasAuth( object ):
user's username. user's username.
""" """
def __init__(self, g=None, ### g for backward compatibility ### def __init__(self, g=None, # g for backward compatibility ###
urlbase="https://web2py.com/cas/cas", urlbase="https://web2py.com/cas/cas",
actions=['login', 'validate', 'logout'], actions=['login', 'validate', 'logout'],
maps=dict(username=lambda v: v.get('username', v['user']), maps=dict(username=lambda v: v.get('username', v['user']),
@@ -56,21 +57,25 @@ class CasAuth( object ):
self.casversion = casversion self.casversion = casversion
self.casusername = casusername self.casusername = casusername
http_host = current.request.env.http_x_forwarded_host http_host = current.request.env.http_x_forwarded_host
if not http_host: http_host=current.request.env.http_host if not http_host:
http_host = current.request.env.http_host
if current.request.env.wsgi_url_scheme in ['https', 'HTTPS']: if current.request.env.wsgi_url_scheme in ['https', 'HTTPS']:
scheme = 'https' scheme = 'https'
else: else:
scheme = 'http' scheme = 'http'
self.cas_my_url='%s://%s%s'%( scheme, http_host, current.request.env.path_info ) self.cas_my_url = '%s://%s%s' % (
scheme, http_host, current.request.env.path_info)
def login_url(self, next="/"): def login_url(self, next="/"):
current.session.token = self._CAS_login() current.session.token = self._CAS_login()
return next return next
def logout_url(self, next="/"): def logout_url(self, next="/"):
current.session.token = None current.session.token = None
current.session.auth = None current.session.auth = None
self._CAS_logout() self._CAS_logout()
return next return next
def get_user(self): def get_user(self):
user = current.session.token user = current.session.token
if user: if user:
@@ -79,6 +84,7 @@ class CasAuth( object ):
d[key] = self.maps[key](user) d[key] = self.maps[key](user)
return d return d
return None return None
def _CAS_login(self): def _CAS_login(self):
""" """
exposed as CAS.login(request) exposed as CAS.login(request)
@@ -110,7 +116,8 @@ class CasAuth( object ):
import xml.parsers.expat as expat import xml.parsers.expat as expat
try: try:
dxml = dom.parseString(data) dxml = dom.parseString(data)
envelop = dxml.getElementsByTagName("cas:authenticationSuccess") envelop = dxml.getElementsByTagName(
"cas:authenticationSuccess")
if len(envelop) > 0: if len(envelop) > 0:
res = dict() res = dict()
for x in envelop[0].childNodes: for x in envelop[0].childNodes:
@@ -124,10 +131,10 @@ class CasAuth( object ):
res[key] = [res[key]] res[key] = [res[key]]
res[key].append(value) res[key].append(value)
return res return res
except expat.ExpatError: pass except expat.ExpatError:
pass
return None # fallback return None # fallback
def _CAS_logout(self): def _CAS_logout(self):
""" """
exposed CAS.logout() exposed CAS.logout()
@@ -135,5 +142,3 @@ class CasAuth( object ):
""" """
import urllib import urllib
redirect("%s?service=%s" % (self.cas_logout_url, self.cas_my_url)) redirect("%s?service=%s" % (self.cas_logout_url, self.cas_my_url))
@@ -18,11 +18,13 @@ from gluon.tools import fetch
from gluon.storage import Storage from gluon.storage import Storage
import gluon.contrib.simplejson as json import gluon.contrib.simplejson as json
class DropboxAccount(object): class DropboxAccount(object):
""" """
from gluon.contrib.login_methods.dropbox_account import DropboxAccount from gluon.contrib.login_methods.dropbox_account import DropboxAccount
auth.settings.actions_disabled=['register','change_password','request_reset_password'] auth.settings.actions_disabled=['register','change_password',
'request_reset_password']
auth.settings.login_form = DropboxAccount(request, auth.settings.login_form = DropboxAccount(request,
key="...", key="...",
secret="...", secret="...",
@@ -50,7 +52,6 @@ class DropboxAccount(object):
self.sess = session.DropboxSession( self.sess = session.DropboxSession(
self.key, self.secret, self.access_type) self.key, self.secret, self.access_type)
def get_user(self): def get_user(self):
request = self.request request = self.request
if not current.session.dropbox_request_token: if not current.session.dropbox_request_token:
@@ -66,7 +67,6 @@ class DropboxAccount(object):
access_token = current.session.dropbox_access_token access_token = current.session.dropbox_access_token
self.sess.set_token(access_token[0], access_token[1]) self.sess.set_token(access_token[0], access_token[1])
user = Storage() user = Storage()
self.client = client.DropboxClient(self.sess) self.client = client.DropboxClient(self.sess)
data = self.client.account_info() data = self.client.account_info()
@@ -98,13 +98,17 @@ class DropboxAccount(object):
current.session.auth = None current.session.auth = None
redirect('https://www.dropbox.com/logout') redirect('https://www.dropbox.com/logout')
return next return next
def put(self, filename, file): def put(self, filename, file):
return json.loads(self.client.put_file(filename, file))['bytes'] return json.loads(self.client.put_file(filename, file))['bytes']
def get(self, filename, file): def get(self, filename, file):
return self.client.get_file(filename) return self.client.get_file(filename)
def dir(self, path): def dir(self, path):
return json.loads(self.client.metadata(path)) return json.loads(self.client.metadata(path))
def use_dropbox(auth, filename='private/dropbox.key', **kwargs): def use_dropbox(auth, filename='private/dropbox.key', **kwargs):
path = os.path.join(current.request.folder, filename) path = os.path.join(current.request.folder, filename)
if os.path.exists(path): if os.path.exists(path):
@@ -118,4 +122,3 @@ def use_dropbox(auth,filename='private/dropbox.key',**kwargs):
auth.settings.login_form = DropboxAccount( auth.settings.login_form = DropboxAccount(
request, key=key, secret=secret, access_type=access_type, request, key=key, secret=secret, access_type=access_type,
login_url=login_url, **kwargs) login_url=login_url, **kwargs)
+1 -1
View File
@@ -1,6 +1,7 @@
import smtplib import smtplib
import logging import logging
def email_auth(server="smtp.gmail.com:587", def email_auth(server="smtp.gmail.com:587",
domain="@gmail.com", domain="@gmail.com",
tls_mode=None): tls_mode=None):
@@ -43,4 +44,3 @@ def email_auth(server="smtp.gmail.com:587",
pass pass
return False return False
return email_auth_aux return email_auth_aux
@@ -8,6 +8,7 @@ So user can choose the built-in login or extended login methods.
from gluon import current, DIV from gluon import current, DIV
class ExtendedLoginForm(object): class ExtendedLoginForm(object):
""" """
Put extended_login_form under web2py/gluon/contrib/login_methods folder. Put extended_login_form under web2py/gluon/contrib/login_methods folder.
@@ -22,7 +23,8 @@ class ExtendedLoginForm(object):
api_key="...", api_key="...",
domain="...", domain="...",
url = "http://localhost:8000/%s/default/user/login" % request.application) url = "http://localhost:8000/%s/default/user/login" % request.application)
extended_login_form = ExtendedLoginForm(auth, alt_login_form, signals=['token']) extended_login_form = ExtendedLoginForm(
auth, alt_login_form, signals=['token'])
auth.settings.login_form = extended_login_form auth.settings.login_form = extended_login_form
@@ -91,7 +93,7 @@ class ExtendedLoginForm(object):
args = request.args args = request.args
if (self.signals and if (self.signals and
any([True for signal in self.signals if request.vars.has_key(signal)]) any([True for signal in self.signals if signal in request.vars])
): ):
return self.alt_login_form.login_form() return self.alt_login_form.login_form()
@@ -101,5 +103,3 @@ class ExtendedLoginForm(object):
form.components.append(self.alt_login_form.login_form()) form.components.append(self.alt_login_form.login_form())
return form return form
@@ -11,6 +11,7 @@ Thanks to Hans Donner <hans.donner@pobox.com> for GaeGoogleAccount.
from google.appengine.api import users from google.appengine.api import users
class GaeGoogleAccount(object): class GaeGoogleAccount(object):
""" """
Login will be done via Google's Appengine login object, instead of web2py's Login will be done via Google's Appengine login object, instead of web2py's
@@ -35,5 +36,3 @@ class GaeGoogleAccount(object):
if user: if user:
return dict(nickname=user.nickname(), email=user.email(), return dict(nickname=user.nickname(), email=user.email(),
user_id=user.user_id(), source="google account") user_id=user.user_id(), source="google account")
+28 -15
View File
@@ -188,18 +188,23 @@ def ldap_auth(server='ldap', port=None,
str(custom_scope), str(manage_groups))) str(custom_scope), str(manage_groups)))
if manage_user: if manage_user:
if user_firstname_attrib.count(':') > 0: if user_firstname_attrib.count(':') > 0:
(user_firstname_attrib, user_firstname_part) = user_firstname_attrib.split(':', 1) (user_firstname_attrib,
user_firstname_part) = user_firstname_attrib.split(':', 1)
user_firstname_part = (int(user_firstname_part) - 1) user_firstname_part = (int(user_firstname_part) - 1)
else: else:
user_firstname_part = None user_firstname_part = None
if user_lastname_attrib.count(':') > 0: if user_lastname_attrib.count(':') > 0:
(user_lastname_attrib, user_lastname_part) = user_lastname_attrib.split(':', 1) (user_lastname_attrib,
user_lastname_part) = user_lastname_attrib.split(':', 1)
user_lastname_part = (int(user_lastname_part) - 1) user_lastname_part = (int(user_lastname_part) - 1)
else: else:
user_lastname_part = None user_lastname_part = None
user_firstname_attrib = ldap.filter.escape_filter_chars(user_firstname_attrib) user_firstname_attrib = ldap.filter.escape_filter_chars(
user_lastname_attrib = ldap.filter.escape_filter_chars(user_lastname_attrib) user_firstname_attrib)
user_mail_attrib = ldap.filter.escape_filter_chars(user_mail_attrib) user_lastname_attrib = ldap.filter.escape_filter_chars(
user_lastname_attrib)
user_mail_attrib = ldap.filter.escape_filter_chars(
user_mail_attrib)
try: try:
if allowed_groups: if allowed_groups:
if not is_user_in_allowed_groups(username, password): if not is_user_in_allowed_groups(username, password):
@@ -310,7 +315,8 @@ def ldap_auth(server='ldap', port=None,
basedns = ldap_basedn basedns = ldap_basedn
else: else:
basedns = [ldap_basedn] basedns = [ldap_basedn]
filter = '(&(uid=%s)(%s))' % (ldap.filter.escape_filter_chars(username), filterstr) filter = '(&(uid=%s)(%s))' % (
ldap.filter.escape_filter_chars(username), filterstr)
found = False found = False
for basedn in basedns: for basedn in basedns:
try: try:
@@ -338,7 +344,8 @@ def ldap_auth(server='ldap', port=None,
else: else:
basedns = [ldap_basedn] basedns = [ldap_basedn]
filter = '(&(%s=%s)(%s))' % (username_attrib, filter = '(&(%s=%s)(%s))' % (username_attrib,
ldap.filter.escape_filter_chars(username), ldap.filter.escape_filter_chars(
username),
filterstr) filterstr)
if custom_scope == 'subtree': if custom_scope == 'subtree':
ldap_scope = ldap.SCOPE_SUBTREE ldap_scope = ldap.SCOPE_SUBTREE
@@ -368,14 +375,16 @@ def ldap_auth(server='ldap', port=None,
logger.info('[%s] Manage user data' % str(username)) logger.info('[%s] Manage user data' % str(username))
try: try:
if user_firstname_part is not None: if user_firstname_part is not None:
store_user_firstname = result[user_firstname_attrib][0].split(' ', 1)[user_firstname_part] store_user_firstname = result[user_firstname_attrib][
0].split(' ', 1)[user_firstname_part]
else: else:
store_user_firstname = result[user_firstname_attrib][0] store_user_firstname = result[user_firstname_attrib][0]
except KeyError, e: except KeyError, e:
store_user_firstname = None store_user_firstname = None
try: try:
if user_lastname_part is not None: if user_lastname_part is not None:
store_user_lastname = result[user_lastname_attrib][0].split(' ', 1)[user_lastname_part] store_user_lastname = result[user_lastname_attrib][
0].split(' ', 1)[user_lastname_part]
else: else:
store_user_lastname = result[user_lastname_attrib][0] store_user_lastname = result[user_lastname_attrib][0]
except KeyError, e: except KeyError, e:
@@ -464,16 +473,19 @@ def ldap_auth(server='ldap', port=None,
# #
# Get all group name where the user is in actually in ldap # Get all group name where the user is in actually in ldap
# ######################################################### # #########################################################
ldap_groups_of_the_user = get_user_groups_from_ldap(username, password) ldap_groups_of_the_user = get_user_groups_from_ldap(
username, password)
# #
# Get all group name where the user is in actually in local db # Get all group name where the user is in actually in local db
# ############################################################# # #############################################################
try: try:
db_user_id = db(db.auth_user.username == username).select(db.auth_user.id).first().id db_user_id = db(db.auth_user.username == username).select(
db.auth_user.id).first().id
except: except:
try: try:
db_user_id = db(db.auth_user.email == username).select(db.auth_user.id).first().id db_user_id = db(db.auth_user.email == username).select(
db.auth_user.id).first().id
except AttributeError, e: except AttributeError, e:
# #
# There is no user in local db # There is no user in local db
@@ -486,7 +498,8 @@ def ldap_auth(server='ldap', port=None,
db_user_id = db.auth_user.insert(email=username, db_user_id = db.auth_user.insert(email=username,
first_name=username) first_name=username)
if not db_user_id: if not db_user_id:
logging.error('There is no username or email for %s!' % username) logging.error(
'There is no username or email for %s!' % username)
raise raise
db_group_search = db((db.auth_membership.user_id == db_user_id) & db_group_search = db((db.auth_membership.user_id == db_user_id) &
(db.auth_user.id == db.auth_membership.user_id) & (db.auth_user.id == db.auth_membership.user_id) &
@@ -520,7 +533,8 @@ def ldap_auth(server='ldap', port=None,
gid = db.auth_group.insert(role=group_to_add, gid = db.auth_group.insert(role=group_to_add,
description='Generated from LDAP') description='Generated from LDAP')
else: else:
gid = db(db.auth_group.role == group_to_add).select(db.auth_group.id).first().id gid = db(db.auth_group.role == group_to_add).select(
db.auth_group.id).first().id
db.auth_membership.insert(user_id=db_user_id, db.auth_membership.insert(user_id=db_user_id,
group_id=gid) group_id=gid)
except: except:
@@ -634,4 +648,3 @@ def ldap_auth(server='ldap', port=None,
if filterstr[0] == '(' and filterstr[-1] == ')': # rfc4515 syntax if filterstr[0] == '(' and filterstr[-1] == ')': # rfc4515 syntax
filterstr = filterstr[1:-1] # parens added again where used filterstr = filterstr[1:-1] # parens added again where used
return ldap_auth_aux return ldap_auth_aux
@@ -16,6 +16,7 @@ try:
except ImportError: except ImportError:
raise HTTP(400, "linkedin module not found") raise HTTP(400, "linkedin module not found")
class LinkedInAccount(object): class LinkedInAccount(object):
""" """
Login will be done via Google's Appengine login object, instead of web2py's Login will be done via Google's Appengine login object, instead of web2py's
@@ -40,13 +41,12 @@ class LinkedInAccount(object):
return '' return ''
def get_user(self): def get_user(self):
result = self.request.vars.verifier and self.api.accessToken(verifier = self.request.vars.verifier ) result = self.request.vars.verifier and self.api.accessToken(
verifier=self.request.vars.verifier)
if result: if result:
profile = self.api.GetProfile() profile = self.api.GetProfile()
profile = self.api.GetProfile(profile).public_url = "http://www.linkedin.com/in/ozgurv" profile = self.api.GetProfile(
profile).public_url = "http://www.linkedin.com/in/ozgurv"
return dict(first_name=profile.first_name, return dict(first_name=profile.first_name,
last_name=profile.last_name, last_name=profile.last_name,
username=profile.id) username=profile.id)
+7 -5
View File
@@ -13,6 +13,7 @@ from gluon.tools import fetch
from gluon.storage import Storage from gluon.storage import Storage
import gluon.contrib.simplejson as json import gluon.contrib.simplejson as json
class Loginza(object): class Loginza(object):
""" """
@@ -85,10 +86,11 @@ class Loginza(object):
auth_info_json = fetch(self.auth_url + '?' + data) auth_info_json = fetch(self.auth_url + '?' + data)
#print auth_info_json #print auth_info_json
auth_info = json.loads(auth_info_json) auth_info = json.loads(auth_info_json)
if auth_info["identity"] != None: if auth_info["identity"] is not None:
self.profile = auth_info self.profile = auth_info
provider = self.profile["provider"] provider = self.profile["provider"]
user = self.mappings.get(provider, self.mappings.default)(self.profile) user = self.mappings.get(
provider, self.mappings.default)(self.profile)
#user["password"] = ??? #user["password"] = ???
#user["avatar"] = ??? #user["avatar"] = ???
return user return user
@@ -106,8 +108,8 @@ class Loginza(object):
_frameborder="no", _frameborder="no",
_style="width:359px;height:300px;") _style="width:359px;height:300px;")
else: else:
form = DIV(A(self.prompt, _href=LOGINZA_URL % (self.language, self.token_url), _class="loginza"), form = DIV(
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")) SCRIPT(_src="https://s3-eu-west-1.amazonaws.com/s1.loginza.ru/js/widget.js", _type="text/javascript"))
return form return form
+13 -7
View File
@@ -4,6 +4,7 @@ import time
from hashlib import md5 from hashlib import md5
from gluon.dal import DAL from gluon.dal import DAL
def motp_auth(db=DAL('sqlite://storage.sqlite'), def motp_auth(db=DAL('sqlite://storage.sqlite'),
time_offset=60): time_offset=60):
@@ -44,7 +45,8 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
writable=False, readable=False, default='')) writable=False, readable=False, default=''))
##validators ##validators
custom_auth_table = db[auth.settings.table_user_name] # get the custom_auth_table custom_auth_table = db[auth.settings.table_user_name]
# get the custom_auth_table
custom_auth_table.first_name.requires = \ custom_auth_table.first_name.requires = \
IS_NOT_EMPTY(error_message=auth.messages.is_empty) IS_NOT_EMPTY(error_message=auth.messages.is_empty)
custom_auth_table.last_name.requires = \ custom_auth_table.last_name.requires = \
@@ -83,7 +85,8 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
for t in range(time_start - 1, time_end + 1): for t in range(time_start - 1, time_end + 1):
to_hash = str(t) + secret + pin to_hash = str(t) + secret + pin
hash = md5(to_hash).hexdigest()[:6] hash = md5(to_hash).hexdigest()[:6]
if otp == hash: return True if otp == hash:
return True
return False return False
def motp_auth_aux(email, def motp_auth_aux(email,
@@ -96,10 +99,13 @@ def motp_auth(db=DAL('sqlite://storage.sqlite'),
if user_data['motp_secret'] and user_data['motp_pin']: if user_data['motp_secret'] and user_data['motp_pin']:
motp_secret = user_data['motp_secret'] motp_secret = user_data['motp_secret']
motp_pin = user_data['motp_pin'] motp_pin = user_data['motp_pin']
otp_check = verify_otp(password,motp_pin,motp_secret,offset=offset) otp_check = verify_otp(
if otp_check: return True password, motp_pin, motp_secret, offset=offset)
else: return False if otp_check:
else: return False return True
else:
return False
else:
return False
return False return False
return motp_auth_aux return motp_auth_aux
+10 -15
View File
@@ -19,6 +19,7 @@ from urllib2 import urlopen
import urllib2 import urllib2
from urllib import urlencode from urllib import urlencode
class OAuthAccount(object): class OAuthAccount(object):
""" """
Login will be done via OAuth Framework, instead of web2py's Login will be done via OAuth Framework, instead of web2py's
@@ -51,7 +52,8 @@ class OAuthAccount(object):
TOKEN_URL="..." TOKEN_URL="..."
ACCESS_TOKEN_URL="..." ACCESS_TOKEN_URL="..."
from gluon.contrib.login_methods.oauth10a_account import OAuthAccount from gluon.contrib.login_methods.oauth10a_account import OAuthAccount
auth.settings.login_form=OAuthAccount(globals(),CLIENT_ID,CLIENT_SECRET, AUTH_URL, TOKEN_URL, ACCESS_TOKEN_URL) auth.settings.login_form=OAuthAccount(globals(
),CLIENT_ID,CLIENT_SECRET, AUTH_URL, TOKEN_URL, ACCESS_TOKEN_URL)
""" """
@@ -62,7 +64,8 @@ class OAuthAccount(object):
""" """
r = self.request r = self.request
http_host = r.env.http_x_forwarded_for http_host = r.env.http_x_forwarded_for
if not http_host: http_host=r.env.http_host if not http_host:
http_host = r.env.http_host
url_scheme = r.env.wsgi_url_scheme url_scheme = r.env.wsgi_url_scheme
if next: if next:
@@ -74,7 +77,6 @@ class OAuthAccount(object):
uri += '?' + urlencode(r.get_vars) uri += '?' + urlencode(r.get_vars)
return uri return uri
def accessToken(self): def accessToken(self):
"""Return the access token generated by the authenticating server. """Return the access token generated by the authenticating server.
@@ -97,12 +99,11 @@ class OAuthAccount(object):
token.set_verifier(self.request.vars.oauth_verifier) token.set_verifier(self.request.vars.oauth_verifier)
client = oauth.Client(self.consumer, token) client = oauth.Client(self.consumer, token)
resp, content = client.request(self.access_token_url, "POST") resp, content = client.request(self.access_token_url, "POST")
if str(resp['status']) != '200': if str(resp['status']) != '200':
self.session.request_token = None self.session.request_token = None
self.globals['redirect'](self.globals['URL'](f='user',args='logout')) self.globals['redirect'](self.globals[
'URL'](f='user', args='logout'))
self.session.access_token = oauth.Token.from_string(content) self.session.access_token = oauth.Token.from_string(content)
@@ -125,7 +126,6 @@ class OAuthAccount(object):
# consumer init # consumer init
self.consumer = oauth.Consumer(self.client_id, self.client_secret) self.consumer = oauth.Consumer(self.client_id, self.client_secret)
def login_url(self, next="/"): def login_url(self, next="/"):
self.__oauth_login(next) self.__oauth_login(next)
return next return next
@@ -142,7 +142,7 @@ class OAuthAccount(object):
is, this function must be implemented for the specific is, this function must be implemented for the specific
provider. provider.
''' '''
raise NotImplementedError, "Must override get_user()" raise NotImplementedError("Must override get_user()")
def __oauth_login(self, next): def __oauth_login(self, next):
'''This method redirects the user to the authenticating form '''This method redirects the user to the authenticating form
@@ -166,7 +166,8 @@ class OAuthAccount(object):
resp, content = client.request(self.token_url, "POST", body=data) resp, content = client.request(self.token_url, "POST", body=data)
if resp['status'] != '200': if resp['status'] != '200':
self.session.request_token = None self.session.request_token = None
self.globals['redirect'](self.globals['URL'](f='user',args='logout')) self.globals['redirect'](self.globals[
'URL'](f='user', args='logout'))
# Store the request token in session. # Store the request token in session.
request_token = self.session.request_token = oauth.Token.from_string(content) request_token = self.session.request_token = oauth.Token.from_string(content)
@@ -176,16 +177,10 @@ class OAuthAccount(object):
oauth_callback=callback_url)) oauth_callback=callback_url))
auth_request_url = self.auth_url + '?' + data auth_request_url = self.auth_url + '?' + data
HTTP = self.globals['HTTP'] HTTP = self.globals['HTTP']
raise HTTP(307, raise HTTP(307,
"You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>", "You are not authenticated: you are being redirected to the <a href='" + auth_request_url + "'> authentication server</a>",
Location=auth_request_url) Location=auth_request_url)
return None return None
+11 -12
View File
@@ -17,6 +17,7 @@ import urllib2
from urllib import urlencode from urllib import urlencode
from gluon import current, redirect, HTTP from gluon import current, redirect, HTTP
class OAuthAccount(object): class OAuthAccount(object):
""" """
Login will be done via OAuth Framework, instead of web2py's Login will be done via OAuth Framework, instead of web2py's
@@ -84,7 +85,8 @@ class OAuthAccount(object):
username = user['id']) username = user['id'])
auth.settings.actions_disabled=['register','change_password','request_reset_password','profile'] auth.settings.actions_disabled=['register',
'change_password','request_reset_password','profile']
auth.settings.login_form=FaceBookAccount() auth.settings.login_form=FaceBookAccount()
Any optional arg in the constructor will be passed asis to remote Any optional arg in the constructor will be passed asis to remote
@@ -100,7 +102,8 @@ server for requests. It can be used for the optional"scope" parameters for Face
r = current.request r = current.request
http_host = r.env.http_x_forwarded_for http_host = r.env.http_x_forwarded_for
if not http_host: http_host=r.env.http_host if not http_host:
http_host = r.env.http_host
url_scheme = r.env.wsgi_url_scheme url_scheme = r.env.wsgi_url_scheme
if next: if next:
@@ -112,7 +115,6 @@ server for requests. It can be used for the optional"scope" parameters for Face
uri += '?' + urlencode(r.get_vars) uri += '?' + urlencode(r.get_vars)
return uri return uri
def __build_url_opener(self, uri): def __build_url_opener(self, uri):
""" """
Build the url opener for managing HTTP Basic Athentication Build the url opener for managing HTTP Basic Athentication
@@ -128,7 +130,6 @@ server for requests. It can be used for the optional"scope" parameters for Face
opener = urllib2.build_opener(auth_handler) opener = urllib2.build_opener(auth_handler)
return opener return opener
def accessToken(self): def accessToken(self):
""" """
Return the access token generated by the authenticating server. Return the access token generated by the authenticating server.
@@ -137,7 +138,7 @@ server for requests. It can be used for the optional"scope" parameters for Face
Otherwise the token is fetched from the auth server. Otherwise the token is fetched from the auth server.
""" """
if current.session.token and current.session.token.has_key('expires'): if current.session.token and 'expires' in current.session.token:
expires = current.session.token['expires'] expires = current.session.token['expires']
# reuse token until expiration # reuse token until expiration
if expires == 0 or expires > time.time(): if expires == 0 or expires > time.time():
@@ -169,9 +170,9 @@ server for requests. It can be used for the optional"scope" parameters for Face
dict([(k, v[-1]) for k, v in tokendata.items()]) dict([(k, v[-1]) for k, v in tokendata.items()])
# set expiration absolute time try to avoid broken # set expiration absolute time try to avoid broken
# implementations where "expires_in" becomes "expires" # implementations where "expires_in" becomes "expires"
if current.session.token.has_key('expires_in'): if 'expires_in' in current.session.token:
exps = 'expires_in' exps = 'expires_in'
elif current.session.token.has_key('expires'): elif 'expires' in current.session.token:
exps = 'expires' exps = 'expires'
else: else:
exps = None exps = None
@@ -217,11 +218,12 @@ server for requests. It can be used for the optional"scope" parameters for Face
Override this method by sublcassing the class. Override this method by sublcassing the class.
""" """
if not current.session.token: return None if not current.session.token:
return None
return dict(first_name='Pinco', return dict(first_name='Pinco',
last_name='Pallino', last_name='Pallino',
username='pincopallino') username='pincopallino')
raise NotImplementedError, "Must override get_user()" raise NotImplementedError("Must override get_user()")
# Following code is never executed. It can be used as example # Following code is never executed. It can be used as example
# for overriding in subclasses. # for overriding in subclasses.
@@ -243,7 +245,6 @@ server for requests. It can be used for the optional"scope" parameters for Face
last_name=user['last_name'], last_name=user['last_name'],
username=user['id']) username=user['id'])
def __oauth_login(self, next): def __oauth_login(self, next):
""" """
This method redirects the user to the authenticating form This method redirects the user to the authenticating form
@@ -273,5 +274,3 @@ server for requests. It can be used for the optional"scope" parameters for Face
self.accessToken() self.accessToken()
return current.session.code return current.session.code
return None return None
+49 -32
View File
@@ -49,6 +49,7 @@ except ImportError, err:
DEFAULT = lambda: None DEFAULT = lambda: None
class OpenIDAuth(object): class OpenIDAuth(object):
""" """
OpenIDAuth OpenIDAuth
@@ -158,7 +159,7 @@ class OpenIDAuth(object):
and not processed yet. Else return the OpenID form for login. and not processed yet. Else return the OpenID form for login.
""" """
request = current.request request = current.request
if request.vars.has_key('janrain_nonce') and not self._processed(): if 'janrain_nonce' in request.vars and not self._processed():
self._process_response() self._process_response()
return self.auth() return self.auth()
return self._form() return self._form()
@@ -196,11 +197,11 @@ class OpenIDAuth(object):
if current.session.w2popenid: if current.session.w2popenid:
del(current.session.w2popenid) del(current.session.w2popenid)
current.session.flash = self.messages.flash_openid_associated current.session.flash = self.messages.flash_openid_associated
if request.vars.has_key(nextvar): if nextvar in request.vars:
redirect(request.vars[nextvar]) redirect(request.vars[nextvar])
redirect(self.auth.settings.login_next) redirect(self.auth.settings.login_next)
if not request.vars.has_key(nextvar): if nextvar not in request.vars:
# no next var, add it and do login again # no next var, add it and do login again
# so if user login or register can go back here to associate the OpenID # so if user login or register can go back here to associate the OpenID
redirect(URL(r=request, redirect(URL(r=request,
@@ -211,7 +212,8 @@ class OpenIDAuth(object):
return None # need to login or register to associate this openid return None # need to login or register to associate this openid
# Get existed OpenID user # Get existed OpenID user
user = db(self.table_user.id==alt_login.user).select().first() user = db(
self.table_user.id == alt_login.user).select().first()
if user: if user:
if current.session.w2popenid: if current.session.w2popenid:
del(current.session.w2popenid) del(current.session.w2popenid)
@@ -227,7 +229,8 @@ class OpenIDAuth(object):
""" """
Get the matched OpenID for given Get the matched OpenID for given
""" """
query = ((db.alt_logins.username == oid) & (db.alt_logins.type == type_)) query = (
(db.alt_logins.username == oid) & (db.alt_logins.type == type_))
alt_login = db(query).select().first() # Get the OpenID record alt_login = db(query).select().first() # Get the OpenID record
return alt_login return alt_login
@@ -275,7 +278,6 @@ class OpenIDAuth(object):
self.db) self.db)
return self.consumerhelper return self.consumerhelper
def _form(self, style=None): def _form(self, style=None):
form = DIV(H3(self.messages.h_openid_login), self._login_form(style)) form = DIV(H3(self.messages.h_openid_login), self._login_form(style))
return form return form
@@ -308,13 +310,17 @@ width: 400px;
hidden_next_input = "" hidden_next_input = ""
if _next == 'profile': if _next == 'profile':
profile_url = URL(r=request, f='user', args=['profile']) profile_url = URL(r=request, f='user', args=['profile'])
hidden_next_input = INPUT(_type="hidden", _name="_next", _value=profile_url) hidden_next_input = INPUT(
form = FORM(openid_field_label or self.messages.label_alt_login_username, _type="hidden", _name="_next", _value=profile_url)
form = FORM(
openid_field_label or self.messages.label_alt_login_username,
INPUT(_type="input", _name="oid", INPUT(_type="input", _name="oid",
requires=IS_NOT_EMPTY(error_message=messages.openid_fail_discover), requires=IS_NOT_EMPTY(
error_message=messages.openid_fail_discover),
_style=style), _style=style),
hidden_next_input, hidden_next_input,
INPUT(_type="submit", _value=submit_button or messages.submit_button), INPUT(_type="submit",
_value=submit_button or messages.submit_button),
" ", " ",
A(messages.comment_openid_signin, A(messages.comment_openid_signin,
_href=messages.comment_openid_help_url, _href=messages.comment_openid_help_url,
@@ -332,8 +338,9 @@ width: 400px;
warning_openid_fail(session) warning_openid_fail(session)
redirect(url) redirect(url)
try: try:
if request.vars.has_key('_next'): if '_next' in request.vars:
return_to_url = self.return_to_url + '?_next=' + request.vars._next return_to_url = self.return_to_url + \
'?_next=' + request.vars._next
url = consumerhelper.begin(oid, self.realm, return_to_url) url = consumerhelper.begin(oid, self.realm, return_to_url)
except DiscoveryFailure: except DiscoveryFailure:
warning_openid_fail(session) warning_openid_fail(session)
@@ -353,7 +360,8 @@ width: 400px;
""" """
Set expiration for OpenID authentication. Set expiration for OpenID authentication.
""" """
w2popenid.expiration = datetime.now() + timedelta(minutes=self.openid_expiration) w2popenid.expiration = datetime.now(
) + timedelta(minutes=self.openid_expiration)
def _w2popenid_expired(self, w2popenid): def _w2popenid_expired(self, w2popenid):
""" """
@@ -369,7 +377,8 @@ width: 400px;
request = current.request request = current.request
request_vars = request.vars request_vars = request.vars
consumerhelper = self._init_consumerhelper() consumerhelper = self._init_consumerhelper()
process_status = consumerhelper.process_response(request_vars, self.return_to_url) process_status = consumerhelper.process_response(
request_vars, self.return_to_url)
if process_status == "success": if process_status == "success":
w2popenid = current.session.w2popenid w2popenid = current.session.w2popenid
user_data = self.consumerhelper.sreg() user_data = self.consumerhelper.sreg()
@@ -388,7 +397,7 @@ width: 400px;
def list_user_openids(self): def list_user_openids(self):
messages = self.messages messages = self.messages
request = current.request request = current.request
if request.vars.has_key('delete_openid'): if 'delete_openid' in request.vars:
self.remove_openid(request.vars.delete_openid) self.remove_openid(request.vars.delete_openid)
query = self.db.alt_logins.user == self.auth.user.id query = self.db.alt_logins.user == self.auth.user.id
@@ -412,11 +421,11 @@ width: 400px;
) )
return openid_list return openid_list
def remove_openid(self, openid): def remove_openid(self, openid):
query = self.db.alt_logins.username == openid query = self.db.alt_logins.username == openid
self.db(query).delete() self.db(query).delete()
class ConsumerHelper(object): class ConsumerHelper(object):
""" """
ConsumerHelper knows the python-openid and ConsumerHelper knows the python-openid and
@@ -434,7 +443,7 @@ class ConsumerHelper(object):
if not hasattr(self, "store"): if not hasattr(self, "store"):
store = Web2pyStore(db) store = Web2pyStore(db)
session = self.session session = self.session
if not session.has_key('w2popenid'): if 'w2popenid' not in session:
session.w2popenid = Storage() session.w2popenid = Storage()
self.store = store self.store = store
return self.store return self.store
@@ -504,18 +513,26 @@ class Web2pyStore(OpenIDStore):
if self.table_oid_associations_name not in self.database: if self.table_oid_associations_name not in self.database:
self.database.define_table(self.table_oid_associations_name, self.database.define_table(self.table_oid_associations_name,
Field('server_url', 'string', length=2047, required=True), Field('server_url',
Field('handle', 'string', length=255, required=True), 'string', length=2047, required=True),
Field('handle',
'string', length=255, required=True),
Field('secret', 'blob', required=True), Field('secret', 'blob', required=True),
Field('issued', 'integer', required=True), Field('issued',
Field('lifetime', 'integer', required=True), 'integer', required=True),
Field('assoc_type', 'string', length=64, required=True) Field('lifetime',
'integer', required=True),
Field('assoc_type',
'string', length=64, required=True)
) )
if self.table_oid_nonces_name not in self.database: if self.table_oid_nonces_name not in self.database:
self.database.define_table(self.table_oid_nonces_name, self.database.define_table(self.table_oid_nonces_name,
Field('server_url', 'string', length=2047, required=True), Field('server_url',
Field('timestamp', 'integer', required=True), 'string', length=2047, required=True),
Field('salt', 'string', length=40, required=True) Field('timestamp',
'integer', required=True),
Field('salt', 'string',
length=40, required=True)
) )
def storeAssociation(self, server_url, association): def storeAssociation(self, server_url, association):
@@ -525,7 +542,8 @@ class Web2pyStore(OpenIDStore):
""" """
db = self.database db = self.database
query = (db.oid_associations.server_url == server_url) & (db.oid_associations.handle == association.handle) query = (db.oid_associations.server_url == server_url) & (
db.oid_associations.handle == association.handle)
db(query).delete() db(query).delete()
db.oid_associations.insert(server_url=server_url, db.oid_associations.insert(server_url=server_url,
handle=association.handle, handle=association.handle,
@@ -550,7 +568,8 @@ class Web2pyStore(OpenIDStore):
if len(keep_assoc) == 0: if len(keep_assoc) == 0:
return None return None
else: else:
assoc = keep_assoc.pop() # pop the last one as it should be the latest one assoc = keep_assoc.pop(
) # pop the last one as it should be the latest one
return Association(assoc['handle'], return Association(assoc['handle'],
assoc['secret'], assoc['secret'],
assoc['issued'], assoc['issued'],
@@ -559,8 +578,9 @@ class Web2pyStore(OpenIDStore):
def removeAssociation(self, server_url, handle): def removeAssociation(self, server_url, handle):
db = self.database db = self.database
query = (db.oid_associations.server_url == server_url) & (db.oid_associations.handle == handle) query = (db.oid_associations.server_url == server_url) & (
return db(query).delete() != None db.oid_associations.handle == handle)
return db(query).delete() is not None
def useNonce(self, server_url, timestamp, salt): def useNonce(self, server_url, timestamp, salt):
""" """
@@ -628,6 +648,3 @@ class Web2pyStore(OpenIDStore):
""" """
return self.cleanupNonces(), self.cleanupAssociations() return self.cleanupNonces(), self.cleanupAssociations()
+1 -2
View File
@@ -1,5 +1,6 @@
from gluon.contrib.pam import authenticate from gluon.contrib.pam import authenticate
def pam_auth(): def pam_auth():
""" """
to use pam_login: to use pam_login:
@@ -19,5 +20,3 @@ def pam_auth():
return authenticate(username, password) return authenticate(username, password)
return pam_auth_aux return pam_auth_aux
+11 -5
View File
@@ -19,11 +19,13 @@ from gluon.tools import fetch
from gluon.storage import Storage from gluon.storage import Storage
import gluon.contrib.simplejson as json import gluon.contrib.simplejson as json
class RPXAccount(object): class RPXAccount(object):
""" """
from gluon.contrib.login_methods.rpx_account import RPXAccount from gluon.contrib.login_methods.rpx_account import RPXAccount
auth.settings.actions_disabled=['register','change_password','request_reset_password'] auth.settings.actions_disabled=['register','change_password',
'request_reset_password']
auth.settings.login_form = RPXAccount(request, auth.settings.login_form = RPXAccount(request,
api_key="...", api_key="...",
domain="...", domain="...",
@@ -78,14 +80,16 @@ class RPXAccount(object):
request = self.request request = self.request
if request.vars.token: if request.vars.token:
user = Storage() user = Storage()
data = urllib.urlencode(dict(apiKey = self.api_key, token=request.vars.token)) data = urllib.urlencode(
dict(apiKey=self.api_key, token=request.vars.token))
auth_info_json = fetch(self.auth_url + '?' + data) auth_info_json = fetch(self.auth_url + '?' + data)
auth_info = json.loads(auth_info_json) auth_info = json.loads(auth_info_json)
if auth_info['stat'] == 'ok': if auth_info['stat'] == 'ok':
self.profile = auth_info['profile'] self.profile = auth_info['profile']
provider = re.sub('[^\w\-]', '', self.profile['providerName']) provider = re.sub('[^\w\-]', '', self.profile['providerName'])
user = self.mappings.get(provider,self.mappings.default)(self.profile) user = self.mappings.get(
provider, self.mappings.default)(self.profile)
return user return user
elif self.on_login_failure: elif self.on_login_failure:
redirect(self.on_login_failure) redirect(self.on_login_failure)
@@ -97,7 +101,9 @@ class RPXAccount(object):
if self.embed: if self.embed:
JANRAIN_URL = \ JANRAIN_URL = \
"https://%s.rpxnow.com/openid/embed?token_url=%s&language_preference=%s" "https://%s.rpxnow.com/openid/embed?token_url=%s&language_preference=%s"
rpxform = IFRAME(_src=JANRAIN_URL % (self.domain,self.token_url,self.language), rpxform = IFRAME(
_src=JANRAIN_URL % (
self.domain, self.token_url, self.language),
_scrolling="no", _scrolling="no",
_frameborder="no", _frameborder="no",
_style="width:400px;height:240px;") _style="width:400px;height:240px;")
@@ -114,6 +120,7 @@ class RPXAccount(object):
_type="text/javascript")) _type="text/javascript"))
return rpxform return rpxform
def use_janrain(auth, filename='private/janrain.key', **kwargs): def use_janrain(auth, filename='private/janrain.key', **kwargs):
path = os.path.join(current.request.folder, filename) path = os.path.join(current.request.folder, filename)
if os.path.exists(path): if os.path.exists(path):
@@ -125,4 +132,3 @@ def use_janrain(auth,filename='private/janrain.key',**kwargs):
['register', 'change_password', 'request_reset_password'] ['register', 'change_password', 'request_reset_password']
auth.settings.login_form = RPXAccount( auth.settings.login_form = RPXAccount(
request, api_key=key, domain=domain, url=url, **kwargs) request, api_key=key, domain=domain, url=url, **kwargs)
+14 -21
View File
@@ -17,7 +17,6 @@ from gluon.http import HTTP,redirect
from M2Crypto import X509 from M2Crypto import X509
class X509Auth(object): class X509Auth(object):
""" """
Login using x509 cert from client. Login using x509 cert from client.
@@ -29,8 +28,6 @@ class X509Auth(object):
""" """
def __init__(self): def __init__(self):
self.request = current.request self.request = current.request
self.ssl_client_raw_cert = self.request.env.ssl_client_raw_cert self.ssl_client_raw_cert = self.request.env.ssl_client_raw_cert
@@ -41,10 +38,11 @@ class X509Auth(object):
if self.ssl_client_raw_cert: if self.ssl_client_raw_cert:
x509=X509.load_cert_string(self.ssl_client_raw_cert, X509.FORMAT_PEM) x509 = X509.load_cert_string(
self.ssl_client_raw_cert, X509.FORMAT_PEM)
# extract it from the cert # extract it from the cert
self.serial = self.request.env.ssl_client_serial or ('%x' % x509.get_serial_number()).upper() self.serial = self.request.env.ssl_client_serial or (
'%x' % x509.get_serial_number()).upper()
subject = x509.get_subject() subject = x509.get_subject()
@@ -54,23 +52,17 @@ class X509Auth(object):
self.subject = Storage(filter(None, self.subject = Storage(filter(None,
map(lambda x: map(lambda x:
(x, map(lambda y: (x, map(lambda y:
y.get_data().as_text(), y.get_data(
).as_text(),
subject.get_entries_by_nid(subject.nid[x]))), subject.get_entries_by_nid(subject.nid[x]))),
subject.nid.keys()))) subject.nid.keys())))
def login_form(self, **args): def login_form(self, **args):
raise HTTP(403, 'Login not allowed. No valid x509 crentials') raise HTTP(403, 'Login not allowed. No valid x509 crentials')
def login_url(self, next="/"): def login_url(self, next="/"):
raise HTTP(403, 'Login not allowed. No valid x509 crentials') raise HTTP(403, 'Login not allowed. No valid x509 crentials')
def logout_url(self, next="/"): def logout_url(self, next="/"):
return next return next
@@ -86,10 +78,14 @@ class X509Auth(object):
p = profile = dict() p = profile = dict()
username = p['username'] = reduce(lambda a,b: '%s | %s' % (a,b), self.subject.CN or self.subject.commonName) username = p['username'] = reduce(lambda a, b: '%s | %s' % (
p['first_name'] = reduce(lambda a,b: '%s | %s' % (a,b),self.subject.givenName or username) a, b), self.subject.CN or self.subject.commonName)
p['last_name'] = reduce(lambda a,b: '%s | %s' % (a,b),self.subject.surname) p['first_name'] = reduce(lambda a, b: '%s | %s' % (a, b),
p['email'] = reduce(lambda a,b: '%s | %s' % (a,b),self.subject.Email or self.subject.emailAddress) self.subject.givenName or username)
p['last_name'] = reduce(
lambda a, b: '%s | %s' % (a, b), self.subject.surname)
p['email'] = reduce(lambda a, b: '%s | %s' % (
a, b), self.subject.Email or self.subject.emailAddress)
# IMPORTANT WE USE THE CERT SERIAL AS UNIQUE KEY FOR THE USER # IMPORTANT WE USE THE CERT SERIAL AS UNIQUE KEY FOR THE USER
p['registration_id'] = self.serial p['registration_id'] = self.serial
@@ -100,6 +96,3 @@ class X509Auth(object):
p['certificate'] = self.ssl_client_raw_cert p['certificate'] = self.ssl_client_raw_cert
return profile return profile
+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_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M) regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M) regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]') regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]',re.S)
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$') regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$',re.S)
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$') regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$',re.S)
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#])") regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])")
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#])") regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])")
ttab_in = maketrans("'`:*~\\[]{}@$+-.#", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b') ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05')
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b',"'`:*~\\[]{}@$+-.#") ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05',"'`:*~\\[]{}@$+-.#\n")
def markmin_escape(text): def markmin_escape(text):
""" insert \\ before markmin control characters: '`:*~[]{}@$ """ """ insert \\ before markmin control characters: '`:*~[]{}@$ """
@@ -686,6 +686,15 @@ def render(text,
>>> render("----\\nhello world\\n----\\n") >>> render("----\\nhello world\\n----\\n")
'<blockquote>hello world</blockquote>' '<blockquote>hello world</blockquote>'
>>> render('[[http://example.com]]')
'<p><span class="anchor" id="markmin_http://example.com"></span></p>'
>>> render('[[ http://example.com]]')
'<p><a href="http://example.com">http://example.com</a></p>'
>>> render('[[bookmark [http://example.com] ]]')
'<p><span class="anchor" id="markmin_bookmark"><a href="http://example.com">http://example.com</a></span></p>'
>>> render('[[this is a link http://example.com]]') >>> render('[[this is a link http://example.com]]')
'<p><a href="http://example.com">this is a link</a></p>' '<p><a href="http://example.com">this is a link</a></p>'
@@ -701,6 +710,9 @@ def render(text,
>>> render("[[Your browser doesn't support <audio> HTML5 tag http://example.com audio]]") >>> render("[[Your browser doesn't support <audio> HTML5 tag http://example.com audio]]")
'<p><audio controls="controls"><source src="http://example.com" />Your browser doesn\\'t support &lt;audio&gt; HTML5 tag</audio></p>' '<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]]') >>> render('[[this is a **link** http://example.com]]')
'<p><a href="http://example.com">this is a <strong>link</strong></a></p>' '<p><a href="http://example.com">this is a <strong>link</strong></a></p>'
@@ -850,6 +862,7 @@ def render(text,
pp='\n' if pretty_print else '' pp='\n' if pretty_print else ''
text = str(text or '') text = str(text or '')
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text) text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
text = text.replace('\x05','') # concatenate strings separeted by \\n
if URL is not None: if URL is not None:
text = replace_at_urls(text,URL) text = replace_at_urls(text,URL)
@@ -1254,8 +1267,8 @@ def render(text,
k = escape(k) k = escape(k)
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else '' title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
target = ' target="_blank"' if p == 'popup' else '' target = ' target="_blank"' if p == 'popup' else ''
t = render(t, {}, {}, 'br', URL, environment, latex, autolinks, t = render(t, {}, {}, 'br', URL, environment, latex, None,
protolinks, class_prefix, id_prefix, pretty_print) if t else k None, class_prefix, id_prefix, pretty_print) if t else k
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \ return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
% dict(k=k, title=title, target=target, t=t) % dict(k=k, title=title, target=target, t=t)
if t == 'NEWLINE' and not a: if t == 'NEWLINE' and not a:
+35 -43
View File
@@ -49,8 +49,7 @@ SQL_DIALECTS = {'memcache': {
def cleanup(text): def cleanup(text):
if re.compile('[^0-9a-zA-Z_]').findall(text): if re.compile('[^0-9a-zA-Z_]').findall(text):
raise SyntaxError, \ raise SyntaxError('Can\'t cleanup \'%s\': only [0-9a-zA-Z_] allowed in table and field names' % text)
'Can\'t cleanup \'%s\': only [0-9a-zA-Z_] allowed in table and field names' % text
return text return text
@@ -58,8 +57,8 @@ def assert_filter_fields(*fields):
for field in fields: for field in fields:
if isinstance(field, (Field, Expression)) and field.type\ if isinstance(field, (Field, Expression)) and field.type\
in ['text', 'blob']: in ['text', 'blob']:
raise SyntaxError, 'AppEngine does not index by: %s'\ raise SyntaxError('AppEngine does not index by: %s'
% field.type % field.type)
def dateobj_to_datetime(object): def dateobj_to_datetime(object):
@@ -114,7 +113,8 @@ class DALStorage(dict):
def __setattr__(self, key, value): def __setattr__(self, key, value):
if key in self: if key in self:
raise SyntaxError, 'Object \'%s\'exists and cannot be redefined' % key raise SyntaxError(
'Object \'%s\'exists and cannot be redefined' % key)
self[key] = value self[key] = value
def __repr__(self): def __repr__(self):
@@ -154,11 +154,11 @@ class MEMDB(DALStorage):
): ):
tablename = cleanup(tablename) tablename = cleanup(tablename)
if tablename in dir(self) or tablename[0] == '_': if tablename in dir(self) or tablename[0] == '_':
raise SyntaxError, 'invalid table name: %s' % tablename raise SyntaxError('invalid table name: %s' % tablename)
if not tablename in self.tables: if not tablename in self.tables:
self.tables.append(tablename) self.tables.append(tablename)
else: else:
raise SyntaxError, 'table already defined: %s' % tablename raise SyntaxError('table already defined: %s' % tablename)
t = self[tablename] = Table(self, tablename, *fields) t = self[tablename] = Table(self, tablename, *fields)
t._create() t._create()
return t return t
@@ -219,24 +219,24 @@ class Table(DALStorage):
if field.type[:9] == 'reference': if field.type[:9] == 'reference':
referenced = field.type[10:].strip() referenced = field.type[10:].strip()
if not referenced: if not referenced:
raise SyntaxError, \ raise SyntaxError('Table %s: reference \'%s\' to nothing!' % (
'Table %s: reference \'%s\' to nothing!' % (self._tablename, k) self._tablename, k))
if not referenced in self._db: if not referenced in self._db:
raise SyntaxError, \ raise SyntaxError(
'Table: table %s does not exist' % referenced 'Table: table %s does not exist' % referenced)
referee = self._db[referenced] referee = self._db[referenced]
ftype = \ ftype = \
self._db._translator[field.type[:9]]( self._db._translator[field.type[:9]](
self._db[referenced]._tableobj) self._db[referenced]._tableobj)
if self._tablename in referee.fields: # ## THIS IS OK if self._tablename in referee.fields: # ## THIS IS OK
raise SyntaxError, \ raise SyntaxError('Field: table \'%s\' has same name as a field '
'Field: table \'%s\' has same name as a field ' \ 'in referenced table \'%s\'' % (
'in referenced table \'%s\'' % (self._tablename, referenced) self._tablename, referenced))
self._db[referenced]._referenced_by.append((self._tablename, self._db[referenced]._referenced_by.append((self._tablename,
field.name)) field.name))
elif not field.type in self._db._translator\ elif not field.type in self._db._translator\
or not self._db._translator[field.type]: or not self._db._translator[field.type]:
raise SyntaxError, 'Field: unkown field type %s' % field.type raise SyntaxError('Field: unkown field type %s' % field.type)
self._tableobj = self._db.client self._tableobj = self._db.client
return None return None
@@ -269,7 +269,7 @@ class Table(DALStorage):
def update(self, id, **fields): def update(self, id, **fields):
for field in fields: for field in fields:
if not field in fields and self[field].default\ if not field in fields and self[field].default\
!= None: is not None:
fields[field] = self[field].default fields[field] = self[field].default
if field in fields: if field in fields:
fields[field] = obj_represent(fields[field], fields[field] = obj_represent(fields[field],
@@ -293,7 +293,7 @@ class Table(DALStorage):
if self._tableobj.set(shard_id, '0'): if self._tableobj.set(shard_id, '0'):
id = 0 id = 0
else: else:
raise Exception, 'cannot set memcache' raise Exception('cannot set memcache')
return long(str(shard) + str(id)) return long(str(shard) + str(id))
def __str__(self): def __str__(self):
@@ -397,7 +397,7 @@ class Field(Expression):
self.name = cleanup(fieldname) self.name = cleanup(fieldname)
if fieldname in dir(Table) or fieldname[0] == '_': if fieldname in dir(Table) or fieldname[0] == '_':
raise SyntaxError, 'Field: invalid field name: %s' % fieldname raise SyntaxError('Field: invalid field name: %s' % fieldname)
if isinstance(type, Table): if isinstance(type, Table):
type = 'reference ' + type._tablename type = 'reference ' + type._tablename
if not length: if not length:
@@ -437,7 +437,7 @@ MEMDB.Field = Field # ## required by gluon/globals.py session.connect
def obj_represent(object, fieldtype, db): def obj_represent(object, fieldtype, db):
if object != None: if object is not None:
if fieldtype == 'date' and not isinstance(object, if fieldtype == 'date' and not isinstance(object,
datetime.date): datetime.date):
(y, m, d) = [int(x) for x in str(object).strip().split('-')] (y, m, d) = [int(x) for x in str(object).strip().split('-')]
@@ -498,8 +498,8 @@ class Query(object):
right=None, right=None,
): ):
if isinstance(right, (Field, Expression)): if isinstance(right, (Field, Expression)):
raise SyntaxError, \ raise SyntaxError(
'Query: right side of filter must be a value or entity' 'Query: right side of filter must be a value or entity')
if isinstance(left, Field) and left.name == 'id': if isinstance(left, Field) and left.name == 'id':
if op == '=': if op == '=':
self.get_one = \ self.get_one = \
@@ -507,8 +507,8 @@ class Query(object):
id=long(right)) id=long(right))
return return
else: else:
raise SyntaxError, 'only equality by id is supported' raise SyntaxError('only equality by id is supported')
raise SyntaxError, 'not supported' raise SyntaxError('not supported')
def __str__(self): def __str__(self):
return str(self.left) return str(self.left)
@@ -554,8 +554,7 @@ class Set(object):
def __call__(self, where): def __call__(self, where):
if isinstance(self.where, QueryException) or isinstance(where, if isinstance(self.where, QueryException) or isinstance(where,
QueryException): QueryException):
raise SyntaxError, \ raise SyntaxError('neither self.where nor where can be a QueryException instance')
'neither self.where nor where can be a QueryException instance'
if self.where: if self.where:
return Set(self._db, self.where & where) return Set(self._db, self.where & where)
else: else:
@@ -564,9 +563,9 @@ class Set(object):
def _get_table_or_raise(self): def _get_table_or_raise(self):
tablenames = list(set(self._tables)) # unique tablenames = list(set(self._tables)) # unique
if len(tablenames) < 1: if len(tablenames) < 1:
raise SyntaxError, 'Set: no tables selected' raise SyntaxError('Set: no tables selected')
if len(tablenames) > 1: if len(tablenames) > 1:
raise SyntaxError, 'Set: no join in appengine' raise SyntaxError('Set: no join in appengine')
return self._db[tablenames[0]]._tableobj return self._db[tablenames[0]]._tableobj
def _getitem_exception(self): def _getitem_exception(self):
@@ -597,7 +596,7 @@ class Set(object):
if isinstance(self.where, QueryException): if isinstance(self.where, QueryException):
return self._select_except() return self._select_except()
else: else:
raise SyntaxError, 'select arguments not supported' raise SyntaxError('select arguments not supported')
def count(self): def count(self):
return len(self.select()) return len(self.select())
@@ -609,7 +608,7 @@ class Set(object):
return return
self._db[tablename].delete(id) self._db[tablename].delete(id)
else: else:
raise Exception, 'deletion not implemented' raise Exception('deletion not implemented')
def update(self, **update_fields): def update(self, **update_fields):
if isinstance(self.where, QueryException): if isinstance(self.where, QueryException):
@@ -620,7 +619,7 @@ class Set(object):
setattr(item, key, value) setattr(item, key, value)
self._db[tablename].update(id, **item) self._db[tablename].update(id, **item)
else: else:
raise Exception, 'update not implemented' raise Exception('update not implemented')
def update_record( def update_record(
@@ -660,9 +659,9 @@ class Rows(object):
def __getitem__(self, i): def __getitem__(self, i):
if i >= len(self.response) or i < 0: if i >= len(self.response) or i < 0:
raise SyntaxError, 'Rows: no such row: %i' % i raise SyntaxError('Rows: no such row: %i' % i)
if len(self.response[0]) != len(self.colnames): if len(self.response[0]) != len(self.colnames):
raise SyntaxError, 'Rows: internal error' raise SyntaxError('Rows: internal error')
row = DALStorage() row = DALStorage()
for j in xrange(len(self.colnames)): for j in xrange(len(self.colnames)):
value = self.response[i][j] value = self.response[i][j]
@@ -684,7 +683,7 @@ class Rows(object):
referee = field.type[10:].strip() referee = field.type[10:].strip()
rid = value rid = value
row[tablename][fieldname] = rid row[tablename][fieldname] = rid
elif field.type == 'boolean' and value != None: elif field.type == 'boolean' and value is not None:
# row[tablename][fieldname]=Set(self._db[referee].id==rid) # row[tablename][fieldname]=Set(self._db[referee].id==rid)
@@ -692,12 +691,12 @@ class Rows(object):
row[tablename][fieldname] = True row[tablename][fieldname] = True
else: else:
row[tablename][fieldname] = False row[tablename][fieldname] = False
elif field.type == 'date' and value != None\ elif field.type == 'date' and value is not None\
and not isinstance(value, datetime.date): and not isinstance(value, datetime.date):
(y, m, d) = [int(x) for x in (y, m, d) = [int(x) for x in
str(value).strip().split('-')] str(value).strip().split('-')]
row[tablename][fieldname] = datetime.date(y, m, d) row[tablename][fieldname] = datetime.date(y, m, d)
elif field.type == 'time' and value != None\ elif field.type == 'time' and value is not None\
and not isinstance(value, datetime.time): and not isinstance(value, datetime.time):
time_items = [int(x) for x in time_items = [int(x) for x in
str(value).strip().split(':')[:3]] str(value).strip().split(':')[:3]]
@@ -706,7 +705,7 @@ class Rows(object):
else: else:
(h, mi, s) = time_items + [0] (h, mi, s) = time_items + [0]
row[tablename][fieldname] = datetime.time(h, mi, s) row[tablename][fieldname] = datetime.time(h, mi, s)
elif field.type == 'datetime' and value != None\ elif field.type == 'datetime' and value is not None\
and not isinstance(value, datetime.datetime): and not isinstance(value, datetime.datetime):
(y, m, d) = [int(x) for x in (y, m, d) = [int(x) for x in
str(value)[:10].strip().split('-')] str(value)[:10].strip().split('-')]
@@ -905,10 +904,3 @@ SQLStorage = DALStorage
if __name__ == '__main__': if __name__ == '__main__':
import doctest import doctest
doctest.testmod() doctest.testmod()
+2 -1
View File
@@ -154,7 +154,8 @@ def condense_hex_colors(css):
first = match.group(3) + match.group(5) + match.group(7) first = match.group(3) + match.group(5) + match.group(7)
second = match.group(4) + match.group(6) + match.group(8) second = match.group(4) + match.group(6) + match.group(8)
if first.lower() == second.lower(): if first.lower() == second.lower():
css = css.replace(match.group(), match.group(1) + match.group(2) + '#' + first) css = css.replace(
match.group(), match.group(1) + match.group(2) + '#' + first)
match = regex.search(css, match.end() - 3) match = regex.search(css, match.end() - 3)
else: else:
match = regex.search(css, match.end()) match = regex.search(css, match.end())
+3 -1
View File
@@ -2,6 +2,7 @@
import re import re
def minify(response): def minify(response):
def _replace(match): def _replace(match):
match = match.group() match = match.group()
@@ -9,5 +10,6 @@ def minify(response):
# otherwise, replace all whitespace with a single space character # otherwise, replace all whitespace with a single space character
return match if match.startswith(('<pre', '<textarea', '<!--')) else ' ' return match if match.startswith(('<pre', '<textarea', '<!--')) else ' '
cpat = re.compile(r'\s+|<pre(.*?)</pre>|<textarea(.*?)</textarea>|<!--\s', re.DOTALL) cpat = re.compile(
r'\s+|<pre(.*?)</pre>|<textarea(.*?)</textarea>|<!--\s', re.DOTALL)
return cpat.sub(_replace, response) return cpat.sub(_replace, response)
+29 -12
View File
@@ -196,17 +196,25 @@ def _make_jsmin(extended=True, python_only=True):
r'|%(space)s+' r'|%(space)s+'
r'|(?:%(newline)s%(space)s*)+' r'|(?:%(newline)s%(space)s*)+'
) % locals()).sub ) % locals()).sub
def space_subber(match): def space_subber(match):
""" Substitution callback """ """ Substitution callback """
# pylint: disable = C0321, R0911 # pylint: disable = C0321, R0911
groups = match.groups() groups = match.groups()
if groups[0]: return groups[0] if groups[0]:
elif groups[1]: return groups[1] return groups[0]
elif groups[2]: return groups[2] elif groups[1]:
elif groups[3]: return groups[3] return groups[1]
elif groups[4]: return '\n' elif groups[2]:
elif groups[5]: return ' ' return groups[2]
else: return '' elif groups[3]:
return groups[3]
elif groups[4]:
return '\n'
elif groups[5]:
return ' '
else:
return ''
def jsmin(script): # pylint: disable = W0621 def jsmin(script): # pylint: disable = W0621
r""" r"""
@@ -239,20 +247,26 @@ def _make_jsmin(extended=True, python_only=True):
r'|(%(space)s)+' r'|(%(space)s)+'
r'|(?:(%(newline)s)%(space)s*)+' r'|(?:(%(newline)s)%(space)s*)+'
) % locals()).sub ) % locals()).sub
def space_norm_subber(match): def space_norm_subber(match):
""" Substitution callback """ """ Substitution callback """
# pylint: disable = C0321 # pylint: disable = C0321
groups = match.groups() groups = match.groups()
if groups[0]: return groups[0] if groups[0]:
elif groups[1]: return groups[1].replace('\r', '\n') + groups[2] return groups[0]
elif groups[3]: return ' ' elif groups[1]:
elif groups[4]: return '\n' return groups[1].replace('\r', '\n') + groups[2]
elif groups[3]:
return ' '
elif groups[4]:
return '\n'
space_sub1 = _re.compile(( space_sub1 = _re.compile((
r'[\040\n]?(%(strings)s|%(pre_regex)s%(regex)s)' r'[\040\n]?(%(strings)s|%(pre_regex)s%(regex)s)'
r'|\040(%(not_id_literal)s)' r'|\040(%(not_id_literal)s)'
r'|\n(%(not_id_literal_open)s)' r'|\n(%(not_id_literal_open)s)'
) % locals()).sub ) % locals()).sub
def space_subber1(match): def space_subber1(match):
""" Substitution callback """ """ Substitution callback """
groups = match.groups() groups = match.groups()
@@ -264,6 +278,7 @@ def _make_jsmin(extended=True, python_only=True):
r'|(%(not_id_literal)s)\040' r'|(%(not_id_literal)s)\040'
r'|(%(not_id_literal_close)s)\n' r'|(%(not_id_literal_close)s)\n'
) % locals()).sub ) % locals()).sub
def space_subber2(match): def space_subber2(match):
""" Substitution callback """ """ Substitution callback """
groups = match.groups() groups = match.groups()
@@ -296,7 +311,8 @@ def _make_jsmin(extended=True, python_only=True):
""" """
return space_sub2(space_subber2, return space_sub2(space_subber2,
space_sub1(space_subber1, space_sub1(space_subber1,
space_norm_sub(space_norm_subber, '\n%s\n' % script) space_norm_sub(space_norm_subber,
'\n%s\n' % script)
) )
).strip() ).strip()
return jsmin return jsmin
@@ -311,6 +327,7 @@ jsmin = _make_jsmin()
# jsmin.jsmin(script) # jsmin.jsmin(script)
# #
def jsmin_for_posers(script): def jsmin_for_posers(script):
r""" r"""
Minify javascript based on `jsmin.c by Douglas Crockford`_\. Minify javascript based on `jsmin.c by Douglas Crockford`_\.
+5 -3
View File
@@ -14,17 +14,20 @@ import os
import hashlib import hashlib
import re import re
def read_binary_file(filename): def read_binary_file(filename):
f = open(filename, 'rb') f = open(filename, 'rb')
data = f.read() data = f.read()
f.close() f.close()
return data return data
def write_binary_file(filename, data): def write_binary_file(filename, data):
f = open(filename, 'wb') f = open(filename, 'wb')
f.write(data) f.write(data)
f.close() f.close()
def fix_links(css, static_path): def fix_links(css, static_path):
return re.sub(r'url\((["\'])\.\./', 'url(\\1' + static_path, css) return re.sub(r'url\((["\'])\.\./', 'url(\\1' + static_path, css)
@@ -62,7 +65,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
processed = [] processed = []
for k, filename in enumerate(files): for k, filename in enumerate(files):
if not filename.startswith('/') or \ if not filename.startswith('/') or \
any(filename.endswith(x) \ any(filename.endswith(x)
for x in ignore_concat): for x in ignore_concat):
new_files.append(filename) new_files.append(filename)
continue continue
@@ -99,7 +102,7 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
if minify_js and \ if minify_js and \
not filename.endswith('.min.js') and \ not filename.endswith('.min.js') and \
not any(filename.endswith(x) \ not any(filename.endswith(x)
for x in ignore_minify): for x in ignore_minify):
js.append(jsmin.jsmin(contents)) js.append(jsmin.jsmin(contents))
else: else:
@@ -138,4 +141,3 @@ def minify(files, path_info, folder, optimize_css, optimize_js,
else: else:
new_files += js new_files += js
return new_files return new_files
+5 -7
View File
@@ -32,6 +32,7 @@ PAM_PROMPT_ECHO_ON = 2
PAM_ERROR_MSG = 3 PAM_ERROR_MSG = 3
PAM_TEXT_INFO = 4 PAM_TEXT_INFO = 4
class PamHandle(Structure): class PamHandle(Structure):
"""wrapper class for pam_handle_t""" """wrapper class for pam_handle_t"""
_fields_ = [ _fields_ = [
@@ -42,6 +43,7 @@ class PamHandle(Structure):
Structure.__init__(self) Structure.__init__(self)
self.handle = 0 self.handle = 0
class PamMessage(Structure): class PamMessage(Structure):
"""wrapper class for pam_message structure""" """wrapper class for pam_message structure"""
_fields_ = [ _fields_ = [
@@ -52,6 +54,7 @@ class PamMessage(Structure):
def __repr__(self): def __repr__(self):
return "<PamMessage %i '%s'>" % (self.msg_style, self.msg) return "<PamMessage %i '%s'>" % (self.msg_style, self.msg)
class PamResponse(Structure): class PamResponse(Structure):
"""wrapper class for pam_response structure""" """wrapper class for pam_response structure"""
_fields_ = [ _fields_ = [
@@ -66,6 +69,7 @@ CONV_FUNC = CFUNCTYPE(c_int,
c_int, POINTER(POINTER(PamMessage)), c_int, POINTER(POINTER(PamMessage)),
POINTER(POINTER(PamResponse)), c_void_p) POINTER(POINTER(PamResponse)), c_void_p)
class PamConv(Structure): class PamConv(Structure):
"""wrapper class for pam_conv structure""" """wrapper class for pam_conv structure"""
_fields_ = [ _fields_ = [
@@ -82,6 +86,7 @@ PAM_AUTHENTICATE = LIBPAM.pam_authenticate
PAM_AUTHENTICATE.restype = c_int PAM_AUTHENTICATE.restype = c_int
PAM_AUTHENTICATE.argtypes = [PamHandle, c_int] PAM_AUTHENTICATE.argtypes = [PamHandle, c_int]
def authenticate(username, password, service='login'): def authenticate(username, password, service='login'):
"""Returns True if the given username and password authenticate for the """Returns True if the given username and password authenticate for the
given service. Returns False otherwise given service. Returns False otherwise
@@ -121,10 +126,3 @@ def authenticate(username, password, service='login'):
if __name__ == "__main__": if __name__ == "__main__":
import getpass import getpass
print authenticate(getpass.getuser(), getpass.getpass()) print authenticate(getpass.getuser(), getpass.getpass())
-2
View File
@@ -128,5 +128,3 @@ def test():
if __name__ == '__main__': if __name__ == '__main__':
test() test()

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