# -*- coding: utf-8 -*- # ########################################################## # ## make sure administrator is on localhost # ########################################################### import os import socket import datetime import copy import gluon.contenttype import gluon.fileutils # ## critical --- make a copy of the environment global_env = copy.copy(globals()) global_env['datetime'] = datetime http_host = request.env.http_host.split(':')[0] remote_addr = request.env.remote_addr try: hosts = (http_host, socket.gethostname(), socket.gethostbyname(http_host), '::1','127.0.0.1','::ffff:127.0.0.1') except: hosts = (http_host, ) if request.env.http_x_forwarded_for or request.env.wsgi_url_scheme\ in ['https', 'HTTPS']: session.secure() elif (remote_addr not in hosts) and (remote_addr != "127.0.0.1"): raise HTTP(200, T('appadmin is disabled because insecure channel')) if not gluon.fileutils.check_credentials(request): redirect(URL(a='admin', c='default', f='index')) ignore_rw = True response.view = 'appadmin.html' response.menu = [[T('design'), False, URL('admin', 'default', 'design', args=[request.application])], [T('db'), False, URL(r=request, f='index')], [T('state'), False, URL(r=request, f='state')], [T('cache'), False, URL(r=request, f='ccache')]] # ########################################################## # ## auxiliary functions # ########################################################### def get_databases(request): dbs = {} for (key, value) in global_env.items(): cond = False try: cond = isinstance(value, GQLDB) except: cond = isinstance(value, SQLDB) if cond: dbs[key] = value return dbs databases = get_databases(None) def eval_in_global_env(text): exec ('_ret=%s' % text, {}, global_env) return global_env['_ret'] def get_database(request): if request.args and request.args[0] in databases: return eval_in_global_env(request.args[0]) else: session.flash = T('invalid request') redirect(URL(r=request, f='index')) def get_table(request): db = get_database(request) if len(request.args) > 1 and request.args[1] in db.tables: return (db, request.args[1]) else: session.flash = T('invalid request') redirect(URL(r=request, f='index')) def get_query(request): try: return eval_in_global_env(request.vars.query) except Exception: return None def query_by_table_type(tablename,db,request=request): keyed = hasattr(db[tablename],'_primarykey') if keyed: firstkey = db[tablename][db[tablename]._primarykey[0]] cond = '>0' if firstkey.type in ['string', 'text']: cond = '!=""' qry = '%s.%s.%s%s' % (request.args[0], request.args[1], firstkey.name, cond) else: qry = '%s.%s.id>0' % tuple(request.args[:2]) return qry # ########################################################## # ## list all databases and tables # ########################################################### def index(): return dict(databases=databases) # ########################################################## # ## insert a new record # ########################################################### def insert(): (db, table) = get_table(request) form = SQLFORM(db[table], ignore_rw=ignore_rw) if form.accepts(request.vars, session): response.flash = T('new record inserted') return dict(form=form,table=db[table]) # ########################################################## # ## list all records in table and insert new record # ########################################################### def download(): import os db = get_database(request) return response.download(request,db) def csv(): import gluon.contenttype response.headers['Content-Type'] = \ gluon.contenttype.contenttype('.csv') db = get_database(request) query = get_query(request) if not query: return None response.headers['Content-disposition'] = 'attachment; filename=%s_%s.csv'\ % tuple(request.vars.query.split('.')[:2]) return str(db(query).select()) def import_csv(table, file): table.import_from_csv_file(file) def select(): import re db = get_database(request) dbname = request.args[0] regex = re.compile('(?P\w+)\.(?P\w+)=(?P\d+)') if len(request.args)>1 and hasattr(db[request.args[1]],'_primarykey'): regex = re.compile('(?P
\w+)\.(?P\w+)=(?P.+)') if request.vars.query: match = regex.match(request.vars.query) if match: request.vars.query = '%s.%s.%s==%s' % (request.args[0], match.group('table'), match.group('field'), match.group('value')) else: request.vars.query = session.last_query query = get_query(request) if request.vars.start: start = int(request.vars.start) else: start = 0 nrows = 0 stop = start + 100 table = None rows = [] orderby = request.vars.orderby if orderby: orderby = dbname + '.' + orderby if orderby == session.last_orderby: if orderby[0] == '~': orderby = orderby[1:] else: orderby = '~' + orderby session.last_orderby = orderby session.last_query = request.vars.query form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px', _name='query', _value=request.vars.query or '', requires=IS_NOT_EMPTY(error_message=T("Cannot be empty")))), TR(T('Update:'), INPUT(_name='update_check', _type='checkbox', value=False), INPUT(_style='width:400px', _name='update_fields', _value=request.vars.update_fields or '')), TR(T('Delete:'), INPUT(_name='delete_check', _class='delete', _type='checkbox', value=False), ''), TR('', '', INPUT(_type='submit', _value='submit'))), _action=URL(r=request,args=request.args)) if request.vars.csvfile != None: try: import_csv(db[request.vars.table], request.vars.csvfile.file) response.flash = T('data uploaded') except Exception, e: response.flash = DIV(T('unable to parse csv file'),PRE(str(e))) if form.accepts(request.vars, formname=None): # regex = re.compile(request.args[0] + '\.(?P
\w+)\.id\>0') regex = re.compile(request.args[0] + '\.(?P
\w+)\..+') match = regex.match(form.vars.query.strip()) if match: table = match.group('table') try: nrows = db(query).count() if form.vars.update_check and form.vars.update_fields: db(query).update(**eval_in_global_env('dict(%s)' % form.vars.update_fields)) response.flash = T('%s rows updated', nrows) elif form.vars.delete_check: db(query).delete() response.flash = T('%s rows deleted', nrows) nrows = db(query).count() if orderby: rows = db(query).select(limitby=(start, stop), orderby=eval_in_global_env(orderby)) else: rows = db(query).select(limitby=(start, stop)) except Exception, e: (rows, nrows) = ([], 0) response.flash = DIV(T('Invalid Query'),PRE(str(e))) return dict( form=form, table=table, start=start, stop=stop, nrows=nrows, rows=rows, query=request.vars.query, ) # ########################################################## # ## edit delete one record # ########################################################### def update(): (db, table) = get_table(request) keyed = hasattr(db[table],'_primarykey') record = None if keyed: key = [f for f in request.vars if f in db[table]._primarykey] if key: record = db(db[table][key[0]] == request.vars[key[0]]).select().first() else: record = db(db[table].id == request.args(2)).select().first() if not record: qry = query_by_table_type(table, db) session.flash = T('record does not exist') redirect(URL(r=request, f='select', args=request.args[:1], vars=dict(query=qry))) if keyed: for k in db[table]._primarykey: db[table][k].writable=False form = SQLFORM(db[table], record, deletable=True, delete_label=T('Check to delete'), ignore_rw=ignore_rw and not keyed, linkto=URL(r=request, f='select', args=request.args[:1]), upload=URL(r=request, f='download', args=request.args[:1])) if form.accepts(request.vars, session): session.flash = T('done!') qry = query_by_table_type(table, db) redirect(URL(r=request, f='select', args=request.args[:1], vars=dict(query=qry))) return dict(form=form,table=db[table]) # ########################################################## # ## get global variables # ########################################################### def state(): return dict() def ccache(): form = FORM( P(TAG.BUTTON("Clear CACHE?", _type="submit", _name="yes", _value="yes")), P(TAG.BUTTON("Clear RAM", _type="submit", _name="ram", _value="ram")), P(TAG.BUTTON("Clear DISK", _type="submit", _name="disk", _value="disk")), ) if form.accepts(request.vars, session): clear_ram = False clear_disk = False session.flash = "" if request.vars.yes: clear_ram = clear_disk = True if request.vars.ram: clear_ram = True if request.vars.disk: clear_disk = True if clear_ram: cache.ram.clear() session.flash += "Ram Cleared " if clear_disk: cache.disk.clear() session.flash += "Disk Cleared" redirect(URL(r=request)) try: from guppy import hpy; hp=hpy() except ImportError: hp = False import shelve, os, copy, time, math from gluon import portalocker ram = { 'bytes': 0, 'objects': 0, 'hits': 0, 'misses': 0, 'ratio': 0, 'oldest': time.time() } disk = copy.copy(ram) total = copy.copy(ram) for key, value in cache.ram.storage.items(): if isinstance(value, dict): ram['hits'] = value['hit_total'] - value['misses'] ram['misses'] = value['misses'] try: ram['ratio'] = ram['hits'] * 100 / value['hit_total'] except (KeyError, ZeroDivisionError): ram['ratio'] = 0 else: if hp: ram['bytes'] += hp.iso(value[1]).size ram['objects'] += hp.iso(value[1]).count if value[0] < ram['oldest']: ram['oldest'] = value[0] locker = open(os.path.join(request.folder, 'cache/cache.lock'), 'a') portalocker.lock(locker, portalocker.LOCK_EX) disk_storage = shelve.open( os.path.join(request.folder, 'cache/cache.shelve')) for key, value in disk_storage.items(): if isinstance(value, dict): disk['hits'] = value['hit_total'] - value['misses'] disk['misses'] = value['misses'] try: disk['ratio'] = disk['hits'] * 100 / value['hit_total'] except (KeyError, ZeroDivisionError): disk['ratio'] = 0 else: if hp: disk['bytes'] += hp.iso(value[1]).size disk['objects'] += hp.iso(value[1]).count if value[0] < disk['oldest']: disk['oldest'] = value[0] portalocker.unlock(locker) locker.close() disk_storage.close() total['bytes'] = ram['bytes'] + disk['bytes'] total['objects'] = ram['objects'] + disk['objects'] total['hits'] = ram['hits'] + disk['hits'] total['misses'] = ram['misses'] + disk['misses'] try: total['ratio'] = total['hits'] * 100 / (total['hits'] + total['misses']) except (KeyError, ZeroDivisionError): total['ratio'] = 0 if disk['oldest'] < ram['oldest']: total['oldest'] = disk['oldest'] else: total['oldest'] = ram['oldest'] def GetInHMS(seconds): hours = math.floor(seconds / 3600) seconds -= hours * 3600 minutes = math.floor(seconds / 60) seconds -= minutes * 60 seconds = math.floor(seconds) return (hours, minutes, seconds) ram['oldest'] = GetInHMS(time.time() - ram['oldest']) disk['oldest'] = GetInHMS(time.time() - disk['oldest']) total['oldest'] = GetInHMS(time.time() - total['oldest']) return dict(form=form, total=total, ram=ram, disk=disk)