# coding: utf8
from gluon.admin import *
from gluon.fileutils import abspath, read_file, write_file
from glob import glob
import shutil
import platform
if DEMO_MODE and request.function in ['change_password','pack','pack_plugin','upgrade_web2py','uninstall','cleanup','compile_app','remove_compiled_app','delete','delete_plugin','create_file','upload_file','update_languages','reload_routes']:
session.flash = T('disabled in demo mode')
redirect(URL('site'))
if not is_manager() and request.function in ['change_password','upgrade_web2py']:
session.flash = T('disabled in multi user mode')
redirect(URL('site'))
if FILTER_APPS and request.args(0) and not request.args(0) in FILTER_APPS:
session.flash = T('disabled in demo mode')
redirect(URL('site'))
def safe_open(a,b):
if DEMO_MODE and 'w' in b:
class tmp:
def write(self,data): pass
return tmp()
return open(a,b)
def safe_read(a, b='r'):
safe_file = safe_open(a, b)
try:
return safe_file.read()
finally:
safe_file.close()
def safe_write(a, value, b='w'):
safe_file = safe_open(a, b)
try:
safe_file.write(value)
finally:
safe_file.close()
def get_app(name=None):
app = name or request.args(0)
if app and (not MULTI_USER_MODE or db(db.app.name==app)(db.app.owner==auth.user.id).count()):
return app
session.flash = 'App does not exist or your are not authorized'
redirect(URL('site'))
def index():
""" Index handler """
send = request.vars.send
if DEMO_MODE:
session.authorized = True
session.last_time = t0
if not send:
send = URL('site')
if session.authorized:
redirect(send)
elif request.vars.password:
if verify_password(request.vars.password):
session.authorized = True
login_record(True)
if CHECK_VERSION:
session.check_version = True
else:
session.check_version = False
session.last_time = t0
if isinstance(send, list): # ## why does this happen?
send = str(send[0])
redirect(send)
else:
times_denied = login_record(False)
if times_denied >= allowed_number_of_attempts:
response.flash = \
T('admin disabled because too many invalid login attempts')
elif times_denied == allowed_number_of_attempts - 1:
response.flash = \
T('You have one more login attempt before you are locked out')
else:
response.flash = T('invalid password.')
return dict(send=send)
def check_version():
""" Checks if web2py is up to date """
session.forget()
session._unlock(response)
new_version, version_number = check_new_version(request.env.web2py_version,
WEB2PY_VERSION_URL)
if new_version == -1:
return A(T('Unable to check for upgrades'), _href=WEB2PY_URL)
elif new_version != True:
return A(T('web2py is up to date'), _href=WEB2PY_URL)
elif platform.system().lower() in ('windows','win32','win64') and os.path.exists("web2py.exe"):
return SPAN('You should upgrade to version %s' % version_number)
else:
return sp_button(URL('upgrade_web2py'), T('upgrade now')) \
+ XML(' <strong class="upgrade_version">%s</strong>' % version_number)
def logout():
""" Logout handler """
session.authorized = None
if MULTI_USER_MODE:
redirect(URL('user/logout'))
redirect(URL('index'))
def change_password():
if session.pam_user:
session.flash = T('PAM authenticated user, cannot change password here')
redirect(URL('site'))
form=SQLFORM.factory(Field('current_admin_password','password'),
Field('new_admin_password','password',requires=IS_STRONG()),
Field('new_admin_password_again','password'))
if form.accepts(request.vars):
if not verify_password(request.vars.current_admin_password):
form.errors.current_admin_password = T('invalid password')
elif form.vars.new_admin_password != form.vars.new_admin_password_again:
form.errors.new_admin_password_again = T('no match')
else:
path = abspath('parameters_%s.py' % request.env.server_port)
safe_write(path, 'password="%s"' % CRYPT()(request.vars.new_admin_password)[0])
session.flash = T('password changed')
redirect(URL('site'))
return dict(form=form)
def site():
""" Site handler """
myversion = request.env.web2py_version
# Shortcut to make the elif statements more legible
file_or_appurl = 'file' in request.vars or 'appurl' in request.vars
if DEMO_MODE:
pass
elif request.vars.filename and not 'file' in request.vars:
# create a new application
appname = cleanpath(request.vars.filename).replace('.', '_')
if app_create(appname, request):
if MULTI_USER_MODE:
db.app.insert(name=appname,owner=auth.user.id)
session.flash = T('new application "%s" created', appname)
redirect(URL('design',args=appname))
else:
session.flash = \
T('unable to create application "%s" (it may exist already)', request.vars.filename)
redirect(URL(r=request))
elif file_or_appurl and not request.vars.filename:
# can't do anything without an app name
msg = 'you must specify a name for the uploaded application'
response.flash = T(msg)
elif file_or_appurl and request.vars.filename:
# fetch an application via URL or file upload
f = None
if request.vars.appurl is not '':
try:
f = urllib.urlopen(request.vars.appurl)
except Exception, e:
session.flash = DIV(T('Unable to download app because:'),PRE(str(e)))
redirect(URL(r=request))
fname = request.vars.appurl
elif request.vars.file is not '':
f = request.vars.file.file
fname = request.vars.file.filename
if f:
appname = cleanpath(request.vars.filename).replace('.', '_')
installed = app_install(appname, f, request, fname,
overwrite=request.vars.overwrite_check)
if f and installed:
msg = 'application %(appname)s installed with md5sum: %(digest)s'
session.flash = T(msg, dict(appname=appname,
digest=md5_hash(installed)))
elif f and request.vars.overwrite_check:
msg = 'unable to install application "%(appname)s"'
session.flash = T(msg, dict(appname=request.vars.filename))
else:
msg = 'unable to install application "%(appname)s"'
session.flash = T(msg, dict(appname=request.vars.filename))
redirect(URL(r=request))
regex = re.compile('^\w+$')
if is_manager():
apps = [f for f in os.listdir(apath(r=request)) if regex.match(f)]
else:
apps = [f.name for f in db(db.app.owner==auth.user_id).select()]
if FILTER_APPS:
apps = [f for f in apps if f in FILTER_APPS]
apps = sorted(apps,lambda a,b:cmp(a.upper(),b.upper()))
return dict(app=None, apps=apps, myversion=myversion)
def pack():
app = get_app()
if len(request.args) == 1:
fname = 'web2py.app.%s.w2p' % app
filename = app_pack(app, request)
else:
fname = 'web2py.app.%s.compiled.w2p' % app
filename = app_pack_compiled(app, request)
if filename:
response.headers['Content-Type'] = 'application/w2p'
disposition = 'attachment; filename=%s' % fname
response.headers['Content-Disposition'] = disposition
return safe_read(filename, 'rb')
else:
session.flash = T('internal error')
redirect(URL('site'))
def pack_plugin():
app = get_app()
if len(request.args) == 2:
fname = 'web2py.plugin.%s.w2p' % request.args[1]
filename = plugin_pack(app, request.args[1], request)
if filename:
response.headers['Content-Type'] = 'application/w2p'
disposition = 'attachment; filename=%s' % fname
response.headers['Content-Disposition'] = disposition
return safe_read(filename, 'rb')
else:
session.flash = T('internal error')
redirect(URL('plugin',args=request.args))
def upgrade_web2py():
if 'upgrade' in request.vars:
(success, error) = upgrade(request)
if success:
session.flash = T('web2py upgraded; please restart it')
else:
session.flash = T('unable to upgrade because "%s"', error)
redirect(URL('site'))
elif 'noupgrade' in request.vars:
redirect(URL('site'))
return dict()
def uninstall():
app = get_app()
if 'delete' in request.vars:
if MULTI_USER_MODE:
if is_manager() and db(db.app.name==app).delete():
pass
elif db(db.app.name==app)(db.app.owner==auth.user.id).delete():
pass
else:
session.flash = T('no permission to uninstall "%s"', app)
redirect(URL('site'))
if app_uninstall(app, request):
session.flash = T('application "%s" uninstalled', app)
else:
session.flash = T('unable to uninstall "%s"', app)
redirect(URL('site'))
elif 'nodelete' in request.vars:
redirect(URL('site'))
return dict(app=app)
def cleanup():
app = get_app()
clean = app_cleanup(app, request)
if not clean:
session.flash = T("some files could not be removed")
else:
session.flash = T('cache, errors and sessions cleaned')
redirect(URL('site'))
def compile_app():
app = get_app()
c = app_compile(app, request)
if not c:
session.flash = T('application compiled')
else:
session.flash = DIV(T('Cannot compile: there are errors in your app:'),
CODE(c))
redirect(URL('site'))
def remove_compiled_app():
""" Remove the compiled application """
app = get_app()
remove_compiled_application(apath(app, r=request))
session.flash = T('compiled application removed')
redirect(URL('site'))
def delete():
""" Object delete handler """
app = get_app()
filename = '/'.join(request.args)
sender = request.vars.sender
if isinstance(sender, list): # ## fix a problem with Vista
sender = sender[0]
if 'nodelete' in request.vars:
redirect(URL(sender))
elif 'delete' in request.vars:
try:
os.unlink(apath(filename, r=request))
session.flash = T('file "%(filename)s" deleted',
dict(filename=filename))
except Exception:
session.flash = T('unable to delete file "%(filename)s"',
dict(filename=filename))
redirect(URL(sender))
return dict(filename=filename, sender=sender)
def peek():
""" Visualize object code """
app = get_app()
filename = '/'.join(request.args)
try:
data = safe_read(apath(filename, r=request)).replace('\r','')
except IOError:
session.flash = T('file does not exist')
redirect(URL('site'))
extension = filename[filename.rfind('.') + 1:].lower()
return dict(app=request.args[0],
filename=filename,
data=data,
extension=extension)
def test():
""" Execute controller tests """
app = get_app()
if len(request.args) > 1:
file = request.args[1]
else:
file = '.*\.py'
controllers = listdir(apath('%s/controllers/' % app, r=request), file + '$')
return dict(app=app, controllers=controllers)
def keepalive():
return ''
def search():
keywords=request.vars.keywords or ''
app = get_app()
def match(filename,keywords):
filename=os.path.join(apath(app, r=request),filename)
if keywords in read_file(filename,'rb'):
return True
return False
path = apath(request.args[0], r=request)
files1 = glob(os.path.join(path,'*/*.py'))
files2 = 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)]
return response.json({'files':files})
def edit():
""" File edit handler """
# Load json only if it is ajax edited...
app = get_app()
filename = '/'.join(request.args)
# Try to discover the file type
if filename[-3:] == '.py':
filetype = 'python'
elif filename[-5:] == '.html':
filetype = 'html'
elif filename[-5:] == '.load':
filetype = 'html'
elif filename[-4:] == '.css':
filetype = 'css'
elif filename[-3:] == '.js':
filetype = 'js'
else:
filetype = 'html'
# ## check if file is not there
path = apath(filename, r=request)
if request.vars.revert and os.path.exists(path + '.bak'):
try:
data = safe_read(path + '.bak')
data1 = safe_read(path)
except IOError:
session.flash = T('Invalid action')
if 'from_ajax' in request.vars:
return response.json({'error': str(T('Invalid action'))})
else:
redirect(URL('site'))
safe_write(path, data)
file_hash = md5_hash(data)
saved_on = time.ctime(os.stat(path)[stat.ST_MTIME])
safe_write(path + '.bak', data1)
response.flash = T('file "%s" of %s restored', (filename, saved_on))
else:
try:
data = safe_read(path)
except IOError:
session.flash = T('Invalid action')
if 'from_ajax' in request.vars:
return response.json({'error': str(T('Invalid action'))})
else:
redirect(URL('site'))
file_hash = md5_hash(data)
saved_on = time.ctime(os.stat(path)[stat.ST_MTIME])
if request.vars.file_hash and request.vars.file_hash != file_hash:
session.flash = T('file changed on disk')
data = request.vars.data.replace('\r\n', '\n').strip() + '\n'
safe_write(path + '.1', data)
if 'from_ajax' in request.vars:
return response.json({'error': str(T('file changed on disk')),
'redirect': URL('resolve',
args=request.args)})
else:
redirect(URL('resolve', args=request.args))
elif request.vars.data:
safe_write(path + '.bak', data)
data = request.vars.data.replace('\r\n', '\n').strip() + '\n'
safe_write(path, data)
file_hash = md5_hash(data)
saved_on = time.ctime(os.stat(path)[stat.ST_MTIME])
response.flash = T('file saved on %s', saved_on)
data_or_revert = (request.vars.data or request.vars.revert)
# Check compile errors
highlight = None
if filetype == 'python' and request.vars.data:
import _ast
try:
code = request.vars.data.rstrip().replace('\r\n','\n')+'\n'
compile(code, path, "exec", _ast.PyCF_ONLY_AST)
except Exception, e:
start = sum([len(line)+1 for l, line
in enumerate(request.vars.data.split("\n"))
if l < e.lineno-1])
if e.text and e.offset:
offset = e.offset - (len(e.text) - len(e.text.splitlines()[-1]))
else:
offset = 0
highlight = {'start': start, 'end': start + offset + 1}
try:
ex_name = e.__class__.__name__
except:
ex_name = 'unknown exception!'
response.flash = DIV(T('failed to compile file because:'), BR(),
B(ex_name), T(' at line %s') % e.lineno,
offset and T(' at char %s') % offset or '',
PRE(str(e)))
if data_or_revert and request.args[1] == 'modules':
# Lets try to reload the modules
try:
mopath = '.'.join(request.args[2:])[:-3]
exec 'import applications.%s.modules.%s' % (request.args[0], mopath)
reload(sys.modules['applications.%s.modules.%s'
% (request.args[0], mopath)])
except Exception, e:
response.flash = DIV(T('failed to reload module because:'),PRE(str(e)))
edit_controller = None
editviewlinks = None
view_link = None
if filetype == 'html' and len(request.args) >= 3:
cfilename = os.path.join(request.args[0], 'controllers',
request.args[2] + '.py')
if os.path.exists(apath(cfilename, r=request)):
edit_controller = URL('edit', args=[cfilename])
view = request.args[3].replace('.html','')
view_link = URL(request.args[0],request.args[2],view)
elif filetype == 'python' and request.args[1] == 'controllers':
## it's a controller file.
## Create links to all of the associated view files.
app = get_app()
viewname = os.path.splitext(request.args[2])[0]
viewpath = os.path.join(app,'views',viewname)
aviewpath = apath(viewpath, r=request)
viewlist = []
if os.path.exists(aviewpath):
if os.path.isdir(aviewpath):
viewlist = glob(os.path.join(aviewpath,'*.html'))
elif os.path.exists(aviewpath+'.html'):
viewlist.append(aviewpath+'.html')
if len(viewlist):
editviewlinks = []
for v in viewlist:
vf = os.path.split(v)[-1]
vargs = "/".join([viewpath.replace(os.sep,"/"),vf])
editviewlinks.append(A(T(vf.split(".")[0]),\
_href=URL('edit',args=[vargs])))
if len(request.args) > 2 and request.args[1] == 'controllers':
controller = (request.args[2])[:-3]
functions = regex_expose.findall(data)
else:
(controller, functions) = (None, None)
if 'from_ajax' in request.vars:
return response.json({'file_hash': file_hash, 'saved_on': saved_on, 'functions':functions, 'controller': controller, 'application': request.args[0], 'highlight': highlight })
else:
editarea_preferences = {}
editarea_preferences['FONT_SIZE'] = '10'
editarea_preferences['FULL_SCREEN'] = 'false'
editarea_preferences['ALLOW_TOGGLE'] = 'true'
editarea_preferences['REPLACE_TAB_BY_SPACES'] = '4'
editarea_preferences['DISPLAY'] = 'onload'
for key in editarea_preferences:
if globals().has_key(key):
editarea_preferences[key]=globals()[key]
return dict(app=request.args[0],
filename=filename,
filetype=filetype,
data=data,
edit_controller=edit_controller,
file_hash=file_hash,
saved_on=saved_on,
controller=controller,
functions=functions,
view_link=view_link,
editarea_preferences=editarea_preferences,
editviewlinks=editviewlinks)
def resolve():
"""
"""
filename = '/'.join(request.args)
# ## check if file is not there
path = apath(filename, r=request)
a = safe_read(path).split('\n')
try:
b = safe_read(path + '.1').split('\n')
except IOError:
session.flash = 'Other file, no longer there'
redirect(URL('edit', args=request.args))
d = difflib.ndiff(a, b)
def leading(line):
""" """
# TODO: we really need to comment this
z = ''
for (k, c) in enumerate(line):
if c == ' ':
z += ' '
elif c == ' \t':
z += ' '
elif k == 0 and c == '?':
pass
else:
break
return XML(z)
def getclass(item):
""" Determine item class """
if item[0] == ' ':
return 'normal'
if item[0] == '+':
return 'plus'
if item[0] == '-':
return 'minus'
if request.vars:
c = '\n'.join([item[2:].rstrip() for (i, item) in enumerate(d) if item[0] \
== ' ' or 'line%i' % i in request.vars])
safe_write(path, c)
session.flash = 'files merged'
redirect(URL('edit', args=request.args))
else:
# Making the short circuit compatible with <= python2.4
gen_data = lambda index,item: not item[:1] in ['+','-'] and "" \
or INPUT(_type='checkbox',
_name='line%i' % index,
value=item[0] == '+')
diff = TABLE(*[TR(TD(gen_data(i,item)),
TD(item[0]),
TD(leading(item[2:]),
TT(item[2:].rstrip())), _class=getclass(item))
for (i, item) in enumerate(d) if item[0] != '?'])
return dict(diff=diff, filename=filename)
def edit_language():
""" Edit language file """
app = get_app()
filename = '/'.join(request.args)
from gluon.languages import read_dict, write_dict
strings = read_dict(apath(filename, r=request))
keys = sorted(strings.keys(),lambda x,y: cmp(x.lower(), y.lower()))
rows = []
rows.append(H2(T('Original/Translation')))
for key in keys:
name = md5_hash(key)
if key==strings[key]:
_class='untranslated'
else:
_class='translated'
if len(key) <= 40:
elem = INPUT(_type='text', _name=name,value=strings[key],
_size=70,_class=_class)
else:
elem = TEXTAREA(_name=name, value=strings[key], _cols=70,
_rows=5, _class=_class)
# Making the short circuit compatible with <= python2.4
k = (strings[key] != key) and key or B(key)
rows.append(P(k, BR(), elem, TAG.BUTTON(T('delete'),
_onclick='return delkey("%s")' % name), _id=name))
rows.append(INPUT(_type='submit', _value=T('update')))
form = FORM(*rows)
if form.accepts(request.vars, keepvalues=True):
strs = dict()
for key in keys:
name = md5_hash(key)
if form.vars[name]==chr(127): continue
strs[key] = form.vars[name]
write_dict(apath(filename, r=request), strs)
session.flash = T('file saved on %(time)s', dict(time=time.ctime()))
redirect(URL(r=request,args=request.args))
return dict(app=request.args[0], filename=filename, form=form)
def about():
""" Read about info """
app = get_app()
# ## check if file is not there
about = safe_read(apath('%s/ABOUT' % app, r=request))
license = safe_read(apath('%s/LICENSE' % app, r=request))
return dict(app=app, about=MARKMIN(about), license=MARKMIN(license))
def design():
""" Application design handler """
app = get_app()
if not response.flash and app == request.application:
msg = T('ATTENTION: you cannot edit the running application!')
response.flash = msg
if request.vars.pluginfile!=None and not isinstance(request.vars.pluginfile,str):
filename=os.path.basename(request.vars.pluginfile.filename)
if plugin_install(app, request.vars.pluginfile.file,
request, filename):
session.flash = T('new plugin installed')
redirect(URL('design',args=app))
else:
session.flash = \
T('unable to create application "%s"', request.vars.filename)
redirect(URL(r=request))
elif isinstance(request.vars.pluginfile,str):
session.flash = T('plugin not specified')
redirect(URL(r=request))
# If we have only pyc files it means that
# we cannot design
if os.path.exists(apath('%s/compiled' % app, r=request)):
session.flash = \
T('application is compiled and cannot be designed')
redirect(URL('site'))
# Get all models
models = listdir(apath('%s/models/' % app, r=request), '.*\.py$')
models=[x.replace('\\','/') for x in models]
defines = {}
for m in models:
data = safe_read(apath('%s/models/%s' % (app, m), r=request))
defines[m] = regex_tables.findall(data)
defines[m].sort()
# Get all controllers
controllers = sorted(listdir(apath('%s/controllers/' % app, r=request), '.*\.py$'))
controllers = [x.replace('\\','/') for x in controllers]
functions = {}
for c in controllers:
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
items = regex_expose.findall(data)
functions[c] = items
# Get all views
views = sorted(listdir(apath('%s/views/' % app, r=request), '[\w/\-]+(\.\w+)+$'))
views = [x.replace('\\','/') for x in views if not x.endswith('.bak')]
extend = {}
include = {}
for c in views:
data = safe_read(apath('%s/views/%s' % (app, c), r=request))
items = regex_extend.findall(data)
if items:
extend[c] = items[0][1]
items = regex_include.findall(data)
include[c] = [i[1] for i in items]
# Get all modules
modules = listdir(apath('%s/modules/' % app, r=request), '.*\.py$')
modules = modules=[x.replace('\\','/') for x in modules]
modules.sort()
# Get all static files
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*')
statics = [x.replace('\\','/') for x in statics]
statics.sort()
# Get all languages
languages = listdir(apath('%s/languages/' % app, r=request), '[\w-]*\.py')
#Get crontab
cronfolder = apath('%s/cron' % app, r=request)
if not os.path.exists(cronfolder): os.mkdir(cronfolder)
crontab = apath('%s/cron/crontab' % app, r=request)
if not os.path.exists(crontab):
safe_write(crontab, '#crontab')
plugins=[]
def filter_plugins(items,plugins):
plugins+=[item[7:].split('/')[0].split('.')[0] for item in items if item.startswith('plugin_')]
plugins[:]=list(set(plugins))
plugins.sort()
return [item for item in items if not item.startswith('plugin_')]
return dict(app=app,
models=filter_plugins(models,plugins),
defines=defines,
controllers=filter_plugins(controllers,plugins),
functions=functions,
views=filter_plugins(views,plugins),
modules=filter_plugins(modules,plugins),
extend=extend,
include=include,
statics=filter_plugins(statics,plugins),
languages=languages,
crontab=crontab,
plugins=plugins)
def delete_plugin():
""" Object delete handler """
app=request.args(0)
plugin = request.args(1)
plugin_name='plugin_'+plugin
if 'nodelete' in request.vars:
redirect(URL('design',args=app))
elif 'delete' in request.vars:
try:
for folder in ['models','views','controllers','static','modules']:
path=os.path.join(apath(app,r=request),folder)
for item in os.listdir(path):
if item.startswith(plugin_name):
filename=os.path.join(path,item)
if os.path.isdir(filename):
shutil.rmtree(filename)
else:
os.unlink(filename)
session.flash = T('plugin "%(plugin)s" deleted',
dict(plugin=plugin))
except Exception:
session.flash = T('unable to delete file plugin "%(plugin)s"',
dict(plugin=plugin))
redirect(URL('design',args=request.args(0)))
return dict(plugin=plugin)
def plugin():
""" Application design handler """
app = get_app()
plugin = request.args(1)
if not response.flash and app == request.application:
msg = T('ATTENTION: you cannot edit the running application!')
response.flash = msg
# If we have only pyc files it means that
# we cannot design
if os.path.exists(apath('%s/compiled' % app, r=request)):
session.flash = \
T('application is compiled and cannot be designed')
redirect(URL('site'))
# Get all models
models = listdir(apath('%s/models/' % app, r=request), '.*\.py$')
models=[x.replace('\\','/') for x in models]
defines = {}
for m in models:
data = safe_read(apath('%s/models/%s' % (app, m), r=request))
defines[m] = regex_tables.findall(data)
defines[m].sort()
# Get all controllers
controllers = sorted(listdir(apath('%s/controllers/' % app, r=request), '.*\.py$'))
controllers = [x.replace('\\','/') for x in controllers]
functions = {}
for c in controllers:
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
items = regex_expose.findall(data)
functions[c] = items
# Get all views
views = sorted(listdir(apath('%s/views/' % app, r=request), '[\w/\-]+\.\w+$'))
views = [x.replace('\\','/') for x in views]
extend = {}
include = {}
for c in views:
data = safe_read(apath('%s/views/%s' % (app, c), r=request))
items = regex_extend.findall(data)
if items:
extend[c] = items[0][1]
items = regex_include.findall(data)
include[c] = [i[1] for i in items]
# Get all modules
modules = listdir(apath('%s/modules/' % app, r=request), '.*\.py$')
modules = modules=[x.replace('\\','/') for x in modules]
modules.sort()
# Get all static files
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*')
statics = [x.replace('\\','/') for x in statics]
statics.sort()
# Get all languages
languages = listdir(apath('%s/languages/' % app, r=request), '[\w-]*\.py')
#Get crontab
crontab = apath('%s/cron/crontab' % app, r=request)
if not os.path.exists(crontab):
safe_write(crontab, '#crontab')
def filter_plugins(items):
regex=re.compile('^plugin_'+plugin+'(/.*|\..*)?$')
return [item for item in items if regex.match(item)]
return dict(app=app,
models=filter_plugins(models),
defines=defines,
controllers=filter_plugins(controllers),
functions=functions,
views=filter_plugins(views),
modules=filter_plugins(modules),
extend=extend,
include=include,
statics=filter_plugins(statics),
languages=languages,
crontab=crontab)
def create_file():
""" Create files handler """
try:
app = get_app(name=request.vars.location.split('/')[0])
path = apath(request.vars.location, r=request)
filename = re.sub('[^\w./-]+', '_', request.vars.filename)
if path[-11:] == '/languages/':
# Handle language files
if len(filename) == 0:
raise SyntaxError
if not filename[-3:] == '.py':
filename += '.py'
app = path.split('/')[-3]
path=os.path.join(apath(app, r=request),'languages',filename)
if not os.path.exists(path):
safe_write(path, '')
findT(apath(app, r=request), filename[:-3])
session.flash = T('language file "%(filename)s" created/updated',
dict(filename=filename))
redirect(request.vars.sender)
elif path[-8:] == '/models/':
# Handle python models
if not filename[-3:] == '.py':
filename += '.py'
if len(filename) == 3:
raise SyntaxError
text = '# coding: utf8\n'
elif path[-13:] == '/controllers/':
# Handle python controllers
if not filename[-3:] == '.py':
filename += '.py'
if len(filename) == 3:
raise SyntaxError
text = '# coding: utf8\n# %s\ndef index(): return dict(message="hello from %s")'
text = text % (T('try something like'), filename)
elif path[-7:] == '/views/':
if request.vars.plugin and not filename.startswith('plugin_%s/' % request.vars.plugin):
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
# Handle template (html) views
if filename.find('.')<0:
filename += '.html'
extension = filename.split('.')[-1].lower()
if len(filename) == 5:
raise SyntaxError
msg = T('This is the %(filename)s template',
dict(filename=filename))
if extension == 'html':
text = dedent("""
{{extend 'layout.html'}}
<h1>%s</h1>
{{=BEAUTIFY(response._vars)}}""" % msg)
else:
generic = os.path.join(path,'generic.'+extension)
if os.path.exists(generic):
text = read_file(generic)
else:
text = ''
elif path[-9:] == '/modules/':
if request.vars.plugin and not filename.startswith('plugin_%s/' % request.vars.plugin):
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
# Handle python module files
if not filename[-3:] == '.py':
filename += '.py'
if len(filename) == 3:
raise SyntaxError
text = dedent("""
#!/usr/bin/env python
# coding: utf8
from gluon import *\n""")
elif path[-8:] == '/static/':
if request.vars.plugin and not filename.startswith('plugin_%s/' % request.vars.plugin):
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
text = ''
else:
redirect(request.vars.sender)
full_filename = os.path.join(path, filename)
dirpath = os.path.dirname(full_filename)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
if os.path.exists(full_filename):
raise SyntaxError
safe_write(full_filename, text)
session.flash = T('file "%(filename)s" created',
dict(filename=full_filename[len(path):]))
redirect(URL('edit',
args=[os.path.join(request.vars.location, filename)]))
except Exception, e:
if not isinstance(e,HTTP):
session.flash = T('cannot create file')
redirect(request.vars.sender)
def upload_file():
""" File uploading handler """
try:
filename = None
app = get_app(name=request.vars.location.split('/')[0])
path = apath(request.vars.location, r=request)
if request.vars.filename:
filename = re.sub('[^\w\./]+', '_', request.vars.filename)
else:
filename = os.path.split(request.vars.file.filename)[-1]
if path[-8:] == '/models/' and not filename[-3:] == '.py':
filename += '.py'
if path[-9:] == '/modules/' and not filename[-3:] == '.py':
filename += '.py'
if path[-13:] == '/controllers/' and not filename[-3:] == '.py':
filename += '.py'
if path[-7:] == '/views/' and not filename[-5:] == '.html':
filename += '.html'
if path[-11:] == '/languages/' and not filename[-3:] == '.py':
filename += '.py'
filename = os.path.join(path, filename)
dirpath = os.path.dirname(filename)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
safe_write(filename, request.vars.file.file.read(), 'wb')
session.flash = T('file "%(filename)s" uploaded',
dict(filename=filename[len(path):]))
except Exception:
if filename:
d = dict(filename = filename[len(path):])
else:
d = dict(filename = 'unkown')
session.flash = T('cannot upload file "%(filename)s"', d)
redirect(request.vars.sender)
def errors():
""" Error handler """
import operator
import os
import pickle
import hashlib
app = get_app()
method = request.args(1) or 'new'
if method == 'new':
errors_path = apath('%s/errors' % app, r=request)
delete_hashes = []
for item in request.vars:
if item[:7] == 'delete_':
delete_hashes.append(item[7:])
hash2error = dict()
for fn in listdir(errors_path, '^\w.*'):
fullpath = os.path.join(errors_path, fn)
if not os.path.isfile(fullpath): continue
try:
fullpath_file = open(fullpath, 'r')
try:
error = pickle.load(fullpath_file)
finally:
fullpath_file.close()
except IOError:
continue
hash = hashlib.md5(error['traceback']).hexdigest()
if hash in delete_hashes:
os.unlink(fullpath)
else:
try:
hash2error[hash]['count'] += 1
except KeyError:
error_lines = error['traceback'].split("\n")
last_line = error_lines[-2]
error_causer = os.path.split(error['layer'])[1]
hash2error[hash] = dict(count=1, pickel=error,
causer=error_causer,
last_line=last_line,
hash=hash,ticket=fn)
decorated = [(x['count'], x) for x in hash2error.values()]
decorated.sort(key=operator.itemgetter(0), reverse=True)
return dict(errors = [x[1] for x in decorated], app=app, method=method)
else:
for item in request.vars:
if item[:7] == 'delete_':
os.unlink(apath('%s/errors/%s' % (app, item[7:]), r=request))
func = lambda p: os.stat(apath('%s/errors/%s' % \
(app, p), r=request)).st_mtime
tickets = sorted(listdir(apath('%s/errors/' % app, r=request), '^\w.*'),
key=func,
reverse=True)
return dict(app=app, tickets=tickets, method=method)
def make_link(path):
""" Create a link from a path """
tryFile = path.replace('\\', '/')
if os.path.isabs(tryFile) and os.path.isfile(tryFile):
(folder, filename) = os.path.split(tryFile)
(base, ext) = os.path.splitext(filename)
app = get_app()
editable = {'controllers': '.py', 'models': '.py', 'views': '.html'}
for key in editable.keys():
check_extension = folder.endswith("%s/%s" % (app,key))
if ext.lower() == editable[key] and check_extension:
return A('"' + tryFile + '"',
_href=URL(r=request,
f='edit/%s/%s/%s' % (app, key, filename))).xml()
return ''
def make_links(traceback):
""" Make links using the given traceback """
lwords = traceback.split('"')
# Making the short circuit compatible with <= python2.4
result = (len(lwords) != 0) and lwords[0] or ''
i = 1
while i < len(lwords):
link = make_link(lwords[i])
if link == '':
result += '"' + lwords[i]
else:
result += link
if i + 1 < len(lwords):
result += lwords[i + 1]
i = i + 1
i = i + 1
return result
class TRACEBACK(object):
""" Generate the traceback """
def __init__(self, text):
""" TRACEBACK constructor """
self.s = make_links(CODE(text).xml())
def xml(self):
""" Returns the xml """
return self.s
def ticket():
""" Ticket handler """
if len(request.args) != 2:
session.flash = T('invalid ticket')
redirect(URL('site'))
app = get_app()
myversion = request.env.web2py_version
ticket = request.args[1]
e = RestrictedError()
e.load(request, app, ticket)
return dict(app=app,
ticket=ticket,
output=e.output,
traceback=(e.traceback and TRACEBACK(e.traceback)),
snapshot=e.snapshot,
code=e.code,
layer=e.layer,
myversion=myversion)
def error():
""" Generate a ticket (for testing) """
raise RuntimeError('admin ticket generator at your service')
def update_languages():
""" Update available languages """
app = get_app()
update_all_languages(apath(app, r=request))
session.flash = T('Language files (static strings) updated')
redirect(URL('design',args=app,anchor='languages'))
def twitter():
session.forget()
session._unlock(response)
import gluon.tools
import gluon.contrib.simplejson as sj
try:
if TWITTER_HASH:
page = gluon.tools.fetch('http://twitter.com/%s?format=json'%TWITTER_HASH)
return sj.loads(page)['#timeline']
else:
return 'disabled'
except Exception, e:
return DIV(T('Unable to download because:'),BR(),str(e))
def user():
if MULTI_USER_MODE:
if not db(db.auth_user).count():
auth.settings.registration_requires_approval = False
return dict(form=auth())
else:
return dict(form=T("Disabled"))
def reload_routes():
""" Reload routes.py """
import gluon.rewrite
gluon.rewrite.load()
redirect(URL('site'))