# coding: utf8 from gluon.admin import * from gluon.fileutils import abspath 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 get_app(name=None): app = name or request.args(0) if 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 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: 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(' %s' % 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_open(path,'w').write('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_open(filename, 'rb').read() 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_open(filename, 'rb').read() 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_open(apath(filename, r=request), 'r').read().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 open(filename,'rb').read(): 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_open(path + '.bak', 'r').read() data1 = safe_open(path, 'r').read() 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_open(path, 'w').write(data) file_hash = md5_hash(data) saved_on = time.ctime(os.stat(path)[stat.ST_MTIME]) safe_open(path + '.bak', 'w').write(data1) response.flash = T('file "%s" of %s restored', (filename, saved_on)) else: try: data = safe_open(path, 'r').read() 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_open(path + '.1', 'w').write(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_open(path + '.bak', 'w').write(data) data = request.vars.data.replace('\r\n', '\n').strip() + '\n' safe_open(path, 'w').write(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_open(path, 'r').readlines() try: b = safe_open(path + '.1', 'r').readlines() 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 = ''.join([item[2:] for (i, item) in enumerate(d) if item[0] \ == ' ' or 'line%i' % i in request.vars]) safe_open(path, 'w').write(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_open(apath('%s/ABOUT' % app, r=request), 'r').read() license = safe_open(apath('%s/LICENSE' % app, r=request), 'r').read() 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: 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)) # 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_open(apath('%s/models/%s' % (app, m), r=request), 'r').read() 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_open(apath('%s/controllers/%s' % (app, c), r=request), 'r').read() 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_open(apath('%s/views/%s' % (app, c), r=request), 'r').read() 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_open(crontab,'w').write('#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_open(apath('%s/models/%s' % (app, m), r=request), 'r').read() 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_open(apath('%s/controllers/%s' % (app, c), r=request), 'r').read() 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_open(apath('%s/views/%s' % (app, c), r=request), 'r').read() 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_open(crontab,'w').write('#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_open(path,'w').write('') 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' if len(filename) == 5: raise SyntaxError msg = T('This is the %(filename)s template', dict(filename=filename)) text = dedent(""" {{extend 'layout.html'}}

%s

{{=BEAUTIFY(response._vars)}}""" % msg) 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.html import * from gluon.http import * from gluon.validators import * from gluon.sqlhtml import * # request, response, session, cache, T, db(s) # must be passed and cannot be imported!""") 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_open(full_filename, 'w').write(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: 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_open(filename, 'wb').write(request.vars.file.file.read()) session.flash = T('file "%(filename)s" uploaded', dict(filename=filename[len(path):])) except Exception: session.flash = T('cannot upload file "%(filename)s"', dict(filename[len(path):])) 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: error = pickle.load(open(fullpath, 'r')) 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)) def twitter(): session.forget() session._unlock(response) import gluon.tools import gluon.contrib.simplejson as sj try: page = gluon.tools.fetch('http://twitter.com/web2py?format=json') return sj.loads(page)['#timeline'] 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 """ gluon.rewrite.load() redirect(URL('site'))