Skip to content
Snippets Groups Projects
plugin_dbui.py 11.88 KiB
""" plugin_dbui.py

    Controllers expose by the plugin:
    
        index
        database
        configuration

    Author: R. Le Gac

"""

import json
import os


API = """
App.csvUrl = '/%s/plugin_dbui/csv';
App.config = %s;
App.debug = %s;
App.name = '%s';
App.REMOTE_API = {
    'url': '/%s/plugin_dbui/call',
    'type': 'remoting',
    'actions': %s 
};"""


def about():
    fn = os.path.join("applications", 
                      request.application, 
                      "static", 
                      "ABOUT.html")
    return open(fn, 'rb').read()


def call():
    """Action to handle the Ext.Direct protocol.
    
    """
    return directSvc()


def csv():
    """Action returning the content of a table as a CSV file.
    Foreign keys are replaced by the parent column.
    
    """
    from gluon.contenttype import contenttype
    from plugin_dbui import (get_foreign_field, 
                             get_where_query, 
                             is_foreign_field, 
                             is_table_with_foreign_fields)

    tablename = request.vars['tableName']

    response.headers['Content-Type'] = contenttype('.csv')
    response.headers['Content-Disposition'] = 'attachment; filename=%s.csv;' % tablename
    
    table = db[tablename]
    query = table.id > 0
    
    # replace foreign key by parent fields
    # and build the query to resolve foreign keys
    if is_table_with_foreign_fields(table):
    
        fields = []
        query = ((query) & (get_where_query(table)))
        
        for field in table:
        
            if is_foreign_field(field):
                k_table, k_field, k_key = get_foreign_field(field)
                fields.append(db[k_table][k_field])
                
            else:
                fields.append(field)
    else:
        fields = [table.ALL]

    # interrogate the database    
    rows = db(query).select(*fields)
    return str(rows)
    

def dbui_conf():
    """Action returning the javascript script configuring
    the plugin dbui: application name, store definition,...
    
    """
    from gluon.contrib import simplejson as json
    from plugin_dbui import (DBUI, 
                             get_all_tables, 
                             to_jsonstore, 
                             to_model, 
                             to_treeNodes, 
                             to_viewport)

    di = {}
    
    # build the dictionary required by Ext.direct
    # containing the definition of the remote procedure
    for (k, f) in directSvc.procedures.iteritems():
        action, method = k.split('.')

        if action == DBUI:
            nargs = f.func_code.co_argcount
        else:
            nargs = f.__func__.func_code.co_argcount - 1
            
        if action not in di:
            di[action] = []
            
        di[action].append({'name': method, 'len': nargs})

    # the definition of the models
    config = {'models': {}, 
              'stores': {}, 
              'treeNodes': [],
              'viewport': None}
    
    for table in get_all_tables(db):
        config['models'][table._tablename] = to_model(table) 
      
    # the stores configuration (static, for each table,...)
    # NOTE: the interface require a store for all tables including alias.
    # The only way to extract them is to scan the attributes list of 
    # the DAL since the method db.tables() or any variant return 
    # tables but not the alias one
    config['stores'].update(plugins.dbui.static_stores)
    for table in get_all_tables(db):
        cfg = to_jsonstore(table)
        config['stores'][cfg['storeId']] = cfg 
    
    # the tree nodes configuration for the TreeStore
    config['treeNodes'] = to_treeNodes()
    
    # the viewport configuration
    config['viewport'] = to_viewport()

    # debug mode
    debug = 'false'
    if 'debug' in request.vars:
        debug = 'true'
            
    # fill the javascript template
    app = request.application
    script = API % (app, 
                    json.dumps(config),
                    debug,
                    app,
                    app, 
                    json.dumps(di))
    
    # return the response as a javascript
    response.headers['Content-Type'] = 'text/javascript'
    return script


def debug():
    """Action to run the plugin in debug mode.
    
    Load dynamically the javascript source code for all libraries.
    Active the debug mode on the server and client side.
    
    EXAMPLES
    
        http://localhost:8000/myapp/plugin_dbui/debug
        http://localhost:8000/myapp/plugin_dbui/debug?script=foo

    URL OPTIONS

        script 
            run the javascript foo in the framework defined by the plugin.
            The scripts are stored in the directory defined by the plugin
            configuration app_script_dir. 

    """
    from plugin_dbui import get_file_paths, get_script_path

    plugin = plugins.dbui

    # css files
    response.files.extend(get_file_paths(plugin.extjs_css, ext='.css'))
    response.files.extend(get_file_paths(plugin.dbui_css, ext='.css'))
    response.files.extend(get_file_paths(plugin.ace_css, ext='.css'))
    response.files.extend(get_file_paths(plugin.app_css, ext='.css'))

    # debug version of the javascript libraries
    response.files.extend(get_file_paths(plugin.ace_libmin, ext='.js'))
    
    response.files.extend(get_file_paths(plugin.mathjax_libmin, ext='.js'))
    response.files.extend(get_file_paths(plugin.extjs_debug, ext='.js'))
    response.files.extend(get_file_paths(plugin.dbui_debug, ext='.js'))
    response.files.extend(get_file_paths(plugin.app_debug, ext='.js'))

    # language files
    response.files.extend(get_file_paths(plugin.extjs_lg, ext='.js'))
    response.files.extend(get_file_paths(plugin.dbui_lg, ext='.js'))
    response.files.extend(get_file_paths(plugin.app_lg, ext='.js'))
    
    # URL for the dbui configuration activating the debug 
    # mode on the client side
    response.files.append(plugin.dbui_conf_debug)
    
    # main script which can be defined in many different ways
    pscript = get_script_path(plugin)
    response.files.append(pscript)

    # switch ON the debug mode on the server side
    session.debug = True

    # select the view    
    response.view = 'plugin_dbui/index.html'
    
    # return the plugin configuration parameter as well as the response 
    return dict(plugin=plugin)
    

def documentations():
    """Return the Ext.data.Array configuration for the documentation
    and for the source code.
    
    """
    from plugin_dbui import get_reference_paths

    # alias
    a = '<a href="%s" target="_blank">%s</a>'
    
    trDev =  T("Documentation for developers")
    trJS = T("Javascript API")
    trPy = T("Python API")
    
    # documentation of the application
    apath, lpath = get_reference_paths()

    userdoc = ""
    if os.path.exists(os.path.join(apath, 'static/docs/database.png')):
        userdoc = a % (URL('static', 'docs/database.png'), T("Data base scheme"))

    pydoc = ""
    if os.path.exists(os.path.join(apath, 'static/docs/epydoc/index.html')):
        pydoc = a % (URL('static', 'docs/epydoc/index.html'), trPy)

    jsdoc = ""
    if os.path.exists(os.path.join(apath, 'static/docs/jsduck/index.html')):
        jsdoc = a % (URL('static', 'docs/jsduck/index.html'), trJS)
        
    # configuration of the Ext.data.Array for the documentation
    cfg = dict()
    
    cfg['fields'] = [{'name': 'code', 'type': 'string'},
                     {'name': 'developer', 'type': 'string'},
                     {'name': 'python', 'type': 'string'},
                     {'name': 'javascript', 'type': 'string'}]

    r1 = (request.application, userdoc, pydoc, jsdoc)

    r2 = (a % ("https://marprod.in2p3.fr/plugin_dbui_book", "plugin_dbui"),
          a % ("https://marprod.in2p3.fr/plugin_dbui_book/default/chapter/29", trDev),
          a % (URL('static', 'plugin_dbui/docs/epydoc/index.html'), trPy),
          a % (URL('static', 'plugin_dbui/docs/jsduck/index.html'), trJS))
     
    r3 = (a % ("http://web2py.com/", "Web2py"),
          a % ("http://web2py.com/book", trDev),
          a % ("http://www.web2py.com/examples/static/epydoc/index.html", trPy),
          "")
 
    r4 = (a % ("http://www.sencha.com/products/extjs/", "Ext JS"),
          "",
          "",
          a % ("http://docs.sencha.com/extjs/4.2.1/", trJS))
 
    r5 = (a % ("http://www.mathjax.org/", "MathJax"),
          "",
          "",
          a % ("http://docs.mathjax.org/", trJS))
 
    r6 = (a % ("http://ace.c9.io/#nav=about", "Ace"),
          "",
          "",
          a % ("http://ace.c9.io/#nav=api", trJS))
 
    cfg['data'] = [r1, r2, r3, r4, r5, r6]
        
    cfg_doc = json.dumps(cfg)

    # configuration of the Ext.data.Array for the source code
    cfg = dict()
    cfg['fields'] = [{'name': 'code', 'type': 'string'},
                     {'name': 'source', 'type': 'string'}]
    
    r1 = (request.application, "<em>git clone http://marwww.in2p3.fr/~legac/wap/git/%s.git</em>" % request.application)
    r2 = ("plugin_dbui", "<em>git clone http://marwww.in2p3.fr/~legac/wap/git/web2py_plugin_dbui.git</em>")
    r3 = ("Web2py", "<em>git clone git://github.com/web2py/web2py.git</em>")
    r4 = ("Ext JS",
          "<em>Download from the Ext JS web site.</em><br>" 
          "<em>In the local directory: %s/static/plugin_extjs/src</em>" % request.application)
    r5 = ("MathJax", "<em>git clone http://github.com/mathjax/MathJax</em>")
    r6 = ("Ace", "<em>git clone git://github.com/ajaxorg/ace.git</em>")
     
    cfg['data'] = [r1, r2, r3, r4, r5, r6]
    cfg_src = json.dumps(cfg)
    
    return dict(cfg_doc=cfg_doc, cfg_src=cfg_src) 


def index():
    """Default Action to run the plugin
    Load compressed version of all libraries.
    
    EXAMPLES
        
        http://localhost:8000/myapp/plugin_dbui
        http://localhost:8000/myapp/plugin_dbui?script=foo
        
    URL OPTIONS

        script
            run the javascript foo in the framework defined by the plugin.
            The scripts are stored in the directory defined by the plugin
            configuration app_script_dir.

    """
    from plugin_dbui import get_file_paths, get_script_path

    plugin = plugins.dbui

    # css files
    response.files.extend(get_file_paths(plugin.extjs_css, ext='.css'))
    response.files.extend(get_file_paths(plugin.dbui_css, ext='.css'))
    response.files.extend(get_file_paths(plugin.ace_css, ext='.css'))
    response.files.extend(get_file_paths(plugin.app_css, ext='.css'))

    # compressed version of the javascript libraries
    response.files.extend(get_file_paths(plugin.ace_libmin, ext='.js'))

    response.files.extend(get_file_paths(plugin.mathjax_libmin, ext='.js'))
    response.files.extend(get_file_paths(plugin.extjs_libmin, ext='.js'))
    response.files.extend(get_file_paths(plugin.dbui_libmin, ext='.js'))
    response.files.extend(get_file_paths(plugin.app_libmin, ext='.js'))
    
    # language files
    response.files.extend(get_file_paths(plugin.extjs_lg, ext='.js'))
    response.files.extend(get_file_paths(plugin.dbui_lg, ext='.js'))
    response.files.extend(get_file_paths(plugin.app_lg, ext='.js'))
    
    # URL for dbui configuration script
    response.files.append(plugin.dbui_conf)
    
    # main script which can be defined in many different ways
    pscript = get_script_path(plugin)
    response.files.append(pscript)

    # switch off the debug mode on the server side
    session.debug = False

    # return the plugin configuration parameter as well as the response 
    return dict(plugin=plugin)


def status():
    return dict(request=request, response=response, session=session)


def versions():
    """Return the versions of the different part of the code.
    
    """
    from plugin_dbui import get_versions
    
    # the configuration for the Ext.data.ArrayStore
    cfg = dict()

    cfg['fields'] = [{'name': 'code', 'type': 'string'},
                     {'name': 'version', 'type': 'string'}]

    cfg['data'] = get_versions()

    
    return dict(cfg_store=json.dumps(cfg))