diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index afdee6c9..54839640 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -32,15 +32,15 @@ from gluon.languages import (read_possible_languages, read_dict, write_dict, if DEMO_MODE and request.function in ['change_password', 'pack', -'pack_custom','pack_plugin', 'upgrade_web2py', 'uninstall', -'cleanup', 'compile_app', 'remove_compiled_app', 'delete', -'delete_plugin', 'create_file', 'upload_file', 'update_languages', -'reload_routes', 'git_push', 'git_pull', 'install_plugin']: + 'pack_custom', 'pack_plugin', 'upgrade_web2py', 'uninstall', + 'cleanup', 'compile_app', 'remove_compiled_app', 'delete', + 'delete_plugin', 'create_file', 'upload_file', 'update_languages', + 'reload_routes', 'git_push', 'git_pull', 'install_plugin']: session.flash = T('disabled in demo mode') redirect(URL('site')) if is_gae and request.function in ('edit', 'edit_language', -'edit_plurals', 'update_languages', 'create_file', 'install_plugin'): + 'edit_plurals', 'update_languages', 'create_file', 'install_plugin'): session.flash = T('disabled in GAE mode') redirect(URL('site')) @@ -74,8 +74,10 @@ def log_progress(app, mode='EDIT', filename=None, progress=0): def safe_open(a, b): if (DEMO_MODE or is_gae) and ('w' in b or 'a' in b): class tmp: + def write(self, data): pass + def close(self): pass return tmp() @@ -208,6 +210,7 @@ def site(): file_or_appurl = 'file' in request.vars or 'appurl' in request.vars class IS_VALID_APPNAME(object): + def __call__(self, value): if not re.compile('^\w+$').match(value): return (value, T('Invalid application name')) @@ -325,7 +328,7 @@ def report_progress(app): if not m: continue days = -(request.now - datetime.datetime.strptime(m[0], - '%Y-%m-%d %H:%M:%S')).days + '%Y-%m-%d %H:%M:%S')).days counter += int(m[1]) events.append([days, counter]) return events @@ -353,6 +356,7 @@ def pack(): session.flash = T('internal error: %s', e) redirect(URL('site')) + def pack_plugin(): app = get_app() if len(request.args) == 2: @@ -368,7 +372,6 @@ def pack_plugin(): redirect(URL('plugin', args=request.args)) - def pack_exe(app, base, filenames=None): import urllib import zipfile @@ -397,10 +400,20 @@ def pack_exe(app, base, filenames=None): def pack_custom(): app = get_app() base = apath(app, r=request) + + def ignore(fs): + return [f for f in fs if not ( + f[:1] in '#' or f.endswith('~') or f.endswith('.bak'))] + files = {} + for (r, d, f) in os.walk(base): + files[r] = {'folders': ignore(d), 'files': ignore(f)} + if request.post_vars.file: - + valid_set = set(os.path.relpath(os.path.join(r, f), base) for r in files for f in files[r]['files']) files = request.post_vars.file - files = [files] if not isinstance(files,list) else files + files = [files] if not isinstance(files, list) else files + files = [file for file in files if file in valid_set] + if request.post_vars.doexe is None: fname = 'web2py.app.%s.w2p' % app try: @@ -417,12 +430,7 @@ def pack_custom(): redirect(URL(args=request.args)) else: return pack_exe(app, base, files) - def ignore(fs): - return [f for f in fs if not ( - f[:1] in '#' or f.endswith('~') or f.endswith('.bak'))] - files = {} - for (r,d,f) in os.walk(base): - files[r] = {'folders':ignore(d),'files':ignore(f)} + return locals() @@ -485,14 +493,14 @@ def cleanup(): def compile_app(): app = get_app() c = app_compile(app, request, - skip_failed_views = (request.args(1) == 'skip_failed_views')) + skip_failed_views=(request.args(1) == 'skip_failed_views')) if not c: session.flash = T('application compiled') elif isinstance(c, list): session.flash = DIV(*[T('application compiled'), BR(), BR(), T('WARNING: The following views could not be compiled:'), BR()] + - [CAT(BR(), view) for view in c] + - [BR(), BR(), T('DO NOT use the "Pack compiled" feature.')]) + [CAT(BR(), view) for view in c] + + [BR(), BR(), T('DO NOT use the "Pack compiled" feature.')]) else: session.flash = DIV(T('Cannot compile: there are errors in your app:'), CODE(c)) @@ -546,6 +554,7 @@ def enable(): safe_open(filename, 'wb').write('disabled: True\ntime-disabled: %s' % request.now) return SPAN(T('Enable'), _style='color:red') + def peek(): """ Visualize object code """ app = get_app(request.vars.app) @@ -609,7 +618,7 @@ def edit(): # Load json only if it is ajax edited... app = get_app(request.vars.app) app_path = apath(app, r=request) - preferences={'theme':'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth':'4', 'indentwithtabs':'false', 'linenumbers':'true', 'highlightline':'true'} + preferences = {'theme': 'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth': '4', 'indentwithtabs': 'false', 'linenumbers': 'true', 'highlightline': 'true'} config = Config(os.path.join(request.folder, 'settings.cfg'), section='editor', default_values={}) preferences.update(config.read()) @@ -617,14 +626,14 @@ def edit(): if not(request.ajax) and not(is_mobile): # return the scaffolding, the rest will be through ajax requests response.title = T('Editing %s') % app - return response.render ('default/edit.html', dict(app=app, editor_settings=preferences)) + return response.render('default/edit.html', dict(app=app, editor_settings=preferences)) # show settings tab and save prefernces if 'settings' in request.vars: - if request.post_vars: #save new preferences + if request.post_vars: # save new preferences post_vars = request.post_vars.items() # Since unchecked checkbox are not serialized, we must set them as false by hand to store the correct preference in the settings - post_vars+= [(opt, 'false') for opt in preferences if opt not in request.post_vars ] + post_vars += [(opt, 'false') for opt in preferences if opt not in request.post_vars] if config.save(post_vars): response.headers["web2py-component-flash"] = T('Preferences saved correctly') else: @@ -632,8 +641,8 @@ def edit(): response.headers["web2py-component-command"] = "update_editor(%s);$('a[href=#editor_settings] button.close').click();" % response.json(config.read()) return else: - details = {'realfilename':'settings', 'filename':'settings', 'id':'editor_settings', 'force': False} - details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings':preferences}) + details = {'realfilename': 'settings', 'filename': 'settings', 'id': 'editor_settings', 'force': False} + details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings': preferences}) return response.json(details) """ File edit handler """ @@ -764,8 +773,8 @@ def edit(): 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. + # 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) @@ -796,22 +805,22 @@ def edit(): return response.json({'file_hash': file_hash, 'saved_on': saved_on, 'functions': functions, 'controller': controller, 'application': request.args[0], 'highlight': highlight}) else: file_details = dict(app=request.args[0], - lineno=request.vars.lineno or 1, - editor_settings=preferences, - filename=filename, - realfilename=realfilename, - filetype=filetype, - data=data, - edit_controller=edit_controller, - file_hash=file_hash, - saved_on=saved_on, - controller=controller, - functions=functions, - view_link=view_link, - editviewlinks=editviewlinks, - id=IS_SLUG()(filename)[0], - force= True if (request.vars.restore or - request.vars.revert) else False) + lineno=request.vars.lineno or 1, + editor_settings=preferences, + filename=filename, + realfilename=realfilename, + filetype=filetype, + data=data, + edit_controller=edit_controller, + file_hash=file_hash, + saved_on=saved_on, + controller=controller, + functions=functions, + view_link=view_link, + editviewlinks=editviewlinks, + id=IS_SLUG()(filename)[0], + force=True if (request.vars.restore or + request.vars.revert) else False) plain_html = response.render('default/edit_js.html', file_details) file_details['plain_html'] = plain_html if is_mobile: @@ -820,14 +829,16 @@ def edit(): else: return response.json(file_details) + def todolist(): """ Returns all TODO of the requested app """ app = request.vars.app or '' - app_path = apath('%(app)s' % {'app':app}, r=request) - dirs=['models', 'controllers', 'modules', 'private' ] + app_path = apath('%(app)s' % {'app': app}, r=request) + dirs = ['models', 'controllers', 'modules', 'private'] + def listfiles(app, dir, regexp='.*\.py$'): - files = sorted( listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp)) + files = sorted(listdir(apath('%(app)s/%(dir)s/' % {'app': app, 'dir': dir}, r=request), regexp)) files = [x.replace(os.path.sep, '/') for x in files if not x.endswith('.bak')] return files @@ -838,17 +849,18 @@ def todolist(): for d in dirs: for f in listfiles(app, d): matches = [] - filename= apath(os.path.join(app, d, f), r=request) + filename = apath(os.path.join(app, d, f), r=request) with open(filename, 'r') as f_s: src = f_s.read() for m in regex.finditer(src): start = m.start() lineno = src.count('\n', 0, start) + 1 - matches.append({'text':m.group(0), 'lineno':lineno}) + matches.append({'text': m.group(0), 'lineno': lineno}) if len(matches) != 0: - output.append({'filename':f,'matches':matches, 'dir':d}) + output.append({'filename': f, 'matches': matches, 'dir': d}) + + return {'todo': output, 'app': app} - return {'todo':output, 'app': app} def editor_sessions(): config = Config(os.path.join(request.folder, 'settings.cfg'), @@ -858,13 +870,14 @@ def editor_sessions(): if request.vars.session_name and request.vars.files: session_name = request.vars.session_name files = request.vars.files - preferences.update({session_name:','.join(files)}) + preferences.update({session_name: ','.join(files)}) if config.save(preferences.items()): response.headers["web2py-component-flash"] = T('Session saved correctly') else: response.headers["web2py-component-flash"] = T('Session saved on session only') - return response.render('default/editor_sessions.html', {'editor_sessions':preferences}) + return response.render('default/editor_sessions.html', {'editor_sessions': preferences}) + def resolve(): """ @@ -901,8 +914,8 @@ def resolve(): def getclass(item): """ Determine item class """ - operators = {' ':'normal', '+':'plus', '-':'minus'} - + operators = {' ': 'normal', '+': 'plus', '-': 'minus'} + return operators[item[0]] if request.vars: @@ -921,7 +934,7 @@ def resolve(): diff = TABLE(*[TR(TD(gen_data(i, item)), TD(item[0]), TD(leading(item[2:]), - TT(item[2:].rstrip())), + TT(item[2:].rstrip())), _class=getclass(item)) for (i, item) in enumerate(d) if item[0] != '?']) @@ -968,11 +981,11 @@ def edit_language(): new_row = DIV(LABEL(prefix, k, _style="font-weight:normal;"), CAT(elem, '\n', TAG.BUTTON( - T('delete'), - _onclick='return delkey("%s")' % name, - _class='btn')), _id=name, _class='span6 well well-small') + T('delete'), + _onclick='return delkey("%s")' % name, + _class='btn')), _id=name, _class='span6 well well-small') - rows.append(DIV(new_row,_class="row-fluid")) + rows.append(DIV(new_row, _class="row-fluid")) rows.append(DIV(INPUT(_type='submit', _value=T('update'), _class="btn btn-primary"), _class='controls')) form = FORM(*rows) if form.accepts(request.vars, keepvalues=True): @@ -1128,18 +1141,18 @@ def design(): # Get all static files statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*', - maxnum = MAXNFILES) + maxnum=MAXNFILES) statics = [x.replace(os.path.sep, '/') for x in statics] statics.sort() # Get all languages - langpath = os.path.join(apath(app, r=request),'languages') + langpath = os.path.join(apath(app, r=request), 'languages') languages = dict([(lang, info) for lang, info in read_possible_languages(langpath).iteritems() if info[2] != 0]) # info[2] is langfile_mtime: - # get only existed files + # get only existed files - #Get crontab + # Get crontab cronfolder = apath('%s/cron' % app, r=request) crontab = apath('%s/cron/crontab' % app, r=request) if not is_gae: @@ -1265,7 +1278,7 @@ def plugin(): # Get all static files statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*', - maxnum = MAXNFILES) + maxnum=MAXNFILES) statics = [x.replace(os.path.sep, '/') for x in statics] statics.sort() @@ -1273,9 +1286,9 @@ def plugin(): languages = sorted([lang + '.py' for lang, info in T.get_possible_languages_info().iteritems() if info[2] != 0]) # info[2] is langfile_mtime: - # get only existed files + # get only existed files - #Get crontab + # Get crontab crontab = apath('%s/cron/crontab' % app, r=request) if not os.path.exists(crontab): safe_write(crontab, '#crontab') @@ -1298,6 +1311,7 @@ def plugin(): languages=languages, crontab=crontab) + def create_file(): """ Create files handler """ if request.vars and not request.vars.token == session.token: @@ -1309,7 +1323,7 @@ def create_file(): path = abspath(request.vars.location) else: if request.vars.dir: - request.vars.location += request.vars.dir + '/' + request.vars.location += request.vars.dir + '/' app = get_app(name=request.vars.location.split('/')[0]) path = apath(request.vars.location, r=request) filename = re.sub('[^\w./-]+', '_', request.vars.filename) @@ -1419,7 +1433,7 @@ def create_file(): elif (path[-8:] == '/static/') or (path[-9:] == '/private/'): if (request.vars.plugin and - not filename.startswith('plugin_%s/' % request.vars.plugin)): + not filename.startswith('plugin_%s/' % request.vars.plugin)): filename = 'plugin_%s/%s' % (request.vars.plugin, filename) text = '' @@ -1439,17 +1453,17 @@ def create_file(): log_progress(app, 'CREATE', filename) if request.vars.dir: result = T('file "%(filename)s" created', - dict(filename=full_filename[len(path):])) + dict(filename=full_filename[len(path):])) else: session.flash = T('file "%(filename)s" created', - dict(filename=full_filename[len(path):])) + dict(filename=full_filename[len(path):])) vars = {} if request.vars.id: vars['id'] = request.vars.id if request.vars.app: vars['app'] = request.vars.app 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: if not isinstance(e, HTTP): @@ -1460,7 +1474,7 @@ def create_file(): response.headers['web2py-component-content'] = 'append' response.headers['web2py-component-command'] = "%s %s %s" % ( "$.web2py.invalidate('#files_menu');", - "load_file('%s');" % URL('edit', args=[app,request.vars.dir,filename]), + "load_file('%s');" % URL('edit', args=[app, request.vars.dir, filename]), "$.web2py.enableElement($('#form form').find($.web2py.formInputClickSelector));") return '' else: @@ -1468,32 +1482,35 @@ def create_file(): def listfiles(app, dir, regexp='.*\.py$'): - files = sorted( - listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp)) - files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')] - return files + files = sorted( + listdir(apath('%(app)s/%(dir)s/' % {'app': app, 'dir': dir}, r=request), regexp)) + files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')] + return files + + +def editfile(path, file, vars={}, app=None): + args = (path, file) if 'app' in vars else (app, path, file) + url = URL('edit', args=args, vars=vars) + return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;') -def editfile(path,file,vars={}, app = None): - args=(path,file) if 'app' in vars else (app,path,file) - url = URL('edit', args=args, vars=vars) - return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;') def files_menu(): - app = request.vars.app or 'welcome' - dirs=[{'name':'models', 'reg':'.*\.py$'}, - {'name':'controllers', 'reg':'.*\.py$'}, - {'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'}, - {'name':'modules', 'reg':'.*\.py$'}, - {'name':'static', 'reg': '[^\.#].*'}, - {'name':'private', 'reg':'.*\.py$'}] - result_files = [] - for dir in dirs: - result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"), - LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.','__')), app), _style="overflow:hidden", _id=dir['name']+"__"+f.replace('.','__')) - for f in listfiles(app, dir['name'], regexp=dir['reg'])], - _class="nav nav-list small-font"), - _id=dir['name'] + '_files', _style="display: none;"))) - return dict(result_files = result_files) + app = request.vars.app or 'welcome' + dirs = [{'name': 'models', 'reg': '.*\.py$'}, + {'name': 'controllers', 'reg': '.*\.py$'}, + {'name': 'views', 'reg': '[\w/\-]+(\.\w+)+$'}, + {'name': 'modules', 'reg': '.*\.py$'}, + {'name': 'static', 'reg': '[^\.#].*'}, + {'name': 'private', 'reg': '.*\.py$'}] + result_files = [] + for dir in dirs: + result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"), + LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.', '__')), app), _style="overflow:hidden", _id=dir['name'] + "__" + f.replace('.', '__')) + for f in listfiles(app, dir['name'], regexp=dir['reg'])], + _class="nav nav-list small-font"), + _id=dir['name'] + '_files', _style="display: none;"))) + return dict(result_files=result_files) + def upload_file(): """ File uploading handler """ @@ -1556,7 +1573,7 @@ def errors(): app = get_app() if is_gae: method = 'dbold' if ('old' in - (request.args(1) or '')) else 'dbnew' + (request.args(1) or '')) else 'dbnew' else: method = request.args(1) or 'new' db_ready = {} @@ -1599,7 +1616,7 @@ def errors(): hash2error[hash]['count'] += 1 except KeyError: error_lines = error['traceback'].split("\n") - last_line = error_lines[-2] if len(error_lines)>1 else 'unknown' + last_line = error_lines[-2] if len(error_lines) > 1 else 'unknown' error_causer = os.path.split(error['layer'])[1] hash2error[hash] = dict(count=1, pickel=error, causer=error_causer, @@ -1638,9 +1655,9 @@ def errors(): 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.ticket_id) + pickel=error, causer=error_causer, + last_line=last_line, hash=hash, + ticket=fn.ticket_id) except AttributeError, e: tk_db(tk_table.id == fn.id).delete() tk_db.commit() @@ -1657,11 +1674,11 @@ def errors(): tk_db(tk_table.ticket_id == item[7:]).delete() tk_db.commit() tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id, - tk_table.created_datetime, - orderby=~tk_table.created_datetime) + tk_table.created_datetime, + orderby=~tk_table.created_datetime) tickets = [row.ticket_id for row in tickets_] times = dict([(row.ticket_id, row.created_datetime) for - row in tickets_]) + row in tickets_]) return dict(app=app, tickets=tickets, method=method, times=times, db_ready=db_ready) @@ -1721,7 +1738,7 @@ def make_link(path): if ext.lower() == editable[key] and check_extension: return A('"' + tryFile + '"', _href=URL(r=request, - f='edit/%s/%s/%s' % (app, key, filename))).xml() + f='edit/%s/%s/%s' % (app, key, filename))).xml() return '' @@ -1867,7 +1884,7 @@ def bulk_register(): redirect(URL('site')) return locals() -### Begin experimental stuff need fixes: +# Begin experimental stuff need fixes: # 1) should run in its own process - cannot os.chdir # 2) should not prompt user at console # 3) should give option to force commit and not reuqire manual merge @@ -1934,6 +1951,7 @@ def git_push(): redirect(URL('site')) return dict(app=app, form=form) + def plugins(): app = request.args(0) from serializers import loads_json @@ -1948,6 +1966,7 @@ def plugins(): session.plugins = [] return dict(plugins=session.plugins["results"], app=request.args(0)) + def install_plugin(): app = request.args(0) source = request.vars.source @@ -1969,5 +1988,5 @@ def install_plugin(): else: session.flash = \ T('unable to install plugin "%s"', filename) - redirect(URL(f="plugins", args=[app,])) + redirect(URL(f="plugins", args=[app, ])) return dict(form=form, app=app, plugin=plugin, source=source)