Hello. I'm trying to dive into the PGAdmin 4 codebase, and one low hanging fruit that I saw was the handling of JSON data.
The first patch is really trivial, and allows PgAdmin4 to run on system with case sensitive filesystems. JSON data should be returned to the client using an application/json MIME- TYPE. Flask already provides an easy way to generate JSON response, with its jsonify function. This patch does not change anything architecturally, it just ensure that the get_nodes method of each hook returns JSONizable objects, instead of building them manually. Moreover, there was a function already in place to return JSON document according to a certain layout (everything under "data", with metadata attached along the way), which was not used by the ACi tree. This patch also changes this format to ensure the json responses returned by the application are consistent. On a side note, I have a few questions about the architecture of the application. - the "hooks" function should really implement a common class, instead of relying on testing the presence of attributes to find a function. Essentially, hooks modules are classes in disguise right now. I think it may be cleaner to define our own Blueprint subclass to add those methods. - regarding the jsonification, I feel like the NODE_TYPE should be a part of the model itself, via a class attribute. A common method should be implemented for all nodes, such as to eliminate duplicated code like the one which can be found in the servers/hooks et server_groups/hooks get_nodes implementation What are your thought on this ? Sorry for the noise in the patch, but my vim configuration automatically removes extraneous white spaces. If you'd prefer a separate patch for that, I can try to generate one. As for the Javascript, did you consider using a rich application framework ? For such a massive application as PgAdmin, I feel like developing each component from a jquery plugin and some glue might not scale well with the size of the app, and could lead to unmaintainable code. By Rich Application Framework, I'm thinking about something like Dojo or ExtJS. -- Ronan Dunklau http://dalibo.com - http://dalibo.org
diff --git a/web/pgadmin/browser/views.py b/web/pgadmin/browser/views.py
index 07637be..799deef 100644
--- a/web/pgadmin/browser/views.py
+++ b/web/pgadmin/browser/views.py
@@ -60,32 +60,32 @@ def index():
stylesheets.append(url_for('static', filename='css/wcDocker/wcDockerSkeleton.min.css'))
stylesheets.append(url_for('static', filename='css/wcDocker/theme.css'))
- stylesheets.append(url_for('static', filename='css/jQuery-contextMenu/jQuery.contextMenu.css'))
+ stylesheets.append(url_for('static', filename='css/jQuery-contextMenu/jquery.contextMenu.css'))
stylesheets.append(url_for('browser.static', filename='css/browser.css'))
stylesheets.append(url_for('browser.static', filename='css/aciTree/css/aciTree.css'))
stylesheets.append(url_for('browser.browser_css'))
-
+
# Add browser scripts
scripts.append(url_for('static', filename='js/codemirror/codemirror.js'))
scripts.append(url_for('static', filename='js/codemirror/mode/sql.js'))
-
+
if config.DEBUG:
scripts.append(url_for('static', filename='js/wcDocker/wcDocker.js'))
else:
scripts.append(url_for('static', filename='js/wcDocker/wcDocker.min.js'))
scripts.append(url_for('static', filename='js/jQuery-contextMenu/jquery.ui.position.js'))
- scripts.append(url_for('static', filename='js/jQuery-contextMenu/jQuery.contextMenu.js'))
+ scripts.append(url_for('static', filename='js/jQuery-contextMenu/jquery.contextMenu.js'))
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciPlugin.min.js'))
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.dom.js'))
scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.min.js'))
scripts.append(url_for('browser.browser_js'))
-
+
for module in modules_and_nodes:
# Get the edit menu items
if 'hooks' in dir(module) and 'get_file_menu_items' in dir(module.hooks):
file_items.extend(module.hooks.get_file_menu_items())
-
+
# Get the edit menu items
if 'hooks' in dir(module) and 'get_edit_menu_items' in dir(module.hooks):
edit_items.extend(module.hooks.get_edit_menu_items())
diff --git a/web/pgadmin/browser/server_groups/hooks.py b/web/pgadmin/browser/server_groups/hooks.py
index 248b733..413e093 100644
--- a/web/pgadmin/browser/server_groups/hooks.py
+++ b/web/pgadmin/browser/server_groups/hooks.py
@@ -22,21 +22,23 @@ from . import NODE_TYPE, sub_nodes
def register_submodules(app):
"""Register any child node blueprints"""
register_modules(app, __file__, all_nodes, sub_nodes, 'pgadmin.browser.server_groups')
-
+
def get_nodes():
"""Return a JSON document listing the server groups for the user"""
groups = ServerGroup.query.filter_by(user_id=current_user.id)
-
- value = ''
+ # TODO: Move this JSON generation to a Server method
+ # this code is duplicated somewhere else
for group in groups:
- value += '{"id":"%s/%d","label":"%s","icon":"icon-%s","inode":true,"_type":"%s"},' % (NODE_TYPE, group.id, group.name, NODE_TYPE, NODE_TYPE)
- value = value[:-1]
-
- return value
+ yield {
+ "id": "%s/%d" % (NODE_TYPE, group.id),
+ "label": group.name,
+ "icon": "icon-%s" % NODE_TYPE,
+ "inode": True,
+ "_type": NODE_TYPE
+ }
-
def get_standard_menu_items():
- """Return a (set) of dicts of standard menu items (create/drop/rename), with
+ """Return a (set) of dicts of standard menu items (create/drop/rename), with
object type, action and the function name (no parens) to call on click."""
return [
{'type': 'server-group', 'action': 'drop', 'priority': 10, 'function': 'drop_server_group'},
@@ -45,22 +47,22 @@ def get_standard_menu_items():
def get_create_menu_items():
- """Return a (set) of dicts of create menu items, with a Javascript array of
- object types on which the option should appear, name, label and the function
+ """Return a (set) of dicts of create menu items, with a Javascript array of
+ object types on which the option should appear, name, label and the function
name (no parens) to call on click."""
return [
{'type': "['server-group']", 'name': 'create_server_group', 'label': gettext('Server Group...'), 'priority': 10, 'function': 'create_server_group'}
]
-
-
+
+
def get_context_menu_items():
"""Return a (set) of dicts of content menu items with name, node type, label, priority and JS"""
return [
{'name': 'delete_server_group', 'type': NODE_TYPE, 'label': gettext('Delete server group'), 'priority': 10, 'onclick': 'drop_server_group(item);'},
{'name': 'rename_server_group', 'type': NODE_TYPE, 'label': gettext('Rename server group...'), 'priority': 20, 'onclick': 'rename_server_group(item);'}
]
-
-
+
+
def get_script_snippets():
"""Return the script snippets needed to handle treeview node operations."""
return render_template('server_groups/server_groups.js')
@@ -72,5 +74,5 @@ def get_css_snippets():
css += " background: url('%s') 0 0 no-repeat !important;\n" % \
url_for('NODE-%s.static' % NODE_TYPE, filename='img/server-group.png')
css += "}\n"
-
+
return css
diff --git a/web/pgadmin/browser/server_groups/servers/hooks.py b/web/pgadmin/browser/server_groups/servers/hooks.py
index 6178b9b..30a7c5f 100644
--- a/web/pgadmin/browser/server_groups/servers/hooks.py
+++ b/web/pgadmin/browser/server_groups/servers/hooks.py
@@ -19,27 +19,30 @@ from . import NODE_TYPE
def get_nodes(server_group):
"""Return a JSON document listing the server groups for the user"""
servers = Server.query.filter_by(user_id=current_user.id, servergroup_id=server_group)
-
- value = ''
+
+ # TODO: Move this JSON generation to a Server method
for server in servers:
- value += '{"id":"%s/%d","label":"%s","icon":"icon-%s","inode":true,"_type":"%s"},' % (NODE_TYPE, server.id, server.name, NODE_TYPE, NODE_TYPE)
- value = value[:-1]
-
- return value
+ yield {
+ "id": "%s/%d" % (NODE_TYPE, server.id),
+ "label": server.name,
+ "icon": "icon-%s" % NODE_TYPE,
+ "inode": True,
+ "_type": NODE_TYPE
+ }
+
-
def get_standard_menu_items():
- """Return a (set) of dicts of standard menu items (create/drop/rename), with
+ """Return a (set) of dicts of standard menu items (create/drop/rename), with
object type, action, priority and the function to call on click."""
return [
{'type': 'server', 'action': 'drop', 'priority': 50, 'function': 'drop_server'},
{'type': 'server', 'action': 'rename', 'priority': 60, 'function': 'rename_server'}
]
-
+
def get_create_menu_items():
- """Return a (set) of dicts of create menu items, with a Javascript array of
- object types on which the option should appear, name, label, priority and
+ """Return a (set) of dicts of create menu items, with a Javascript array of
+ object types on which the option should appear, name, label, priority and
the function name (no parens) to call on click."""
return [
{'type': "['server-group', 'server']", 'name': 'create_server', 'label': gettext('Server...'), 'priority': 50, 'function': 'create_server'}
@@ -52,8 +55,8 @@ def get_context_menu_items():
{'name': 'delete_server', 'type': NODE_TYPE, 'label': gettext('Delete server'), 'priority': 50, 'onclick': 'drop_server(item);'},
{'name': 'rename_server', 'type': NODE_TYPE, 'label': gettext('Rename server...'), 'priority': 60, 'onclick': 'rename_server(item);'}
]
-
-
+
+
def get_script_snippets():
"""Return the script snippets needed to handle treeview node operations."""
return render_template('servers/servers.js')
@@ -65,5 +68,5 @@ def get_css_snippets():
css += " background: url('%s') 0 0 no-repeat !important;\n" % \
url_for('NODE-%s.static' % NODE_TYPE, filename='img/server.png')
css += "}\n"
-
+
return css
diff --git a/web/pgadmin/browser/server_groups/servers/views.py b/web/pgadmin/browser/server_groups/servers/views.py
index 318b365..fb38dcd 100644
--- a/web/pgadmin/browser/server_groups/servers/views.py
+++ b/web/pgadmin/browser/server_groups/servers/views.py
@@ -9,17 +9,22 @@
"""Defines views for management of servers"""
-from flask import Blueprint, Response, current_app, request
+from flask import Blueprint, request
from flask.ext.babel import gettext
from flask.ext.security import current_user, login_required
from . import NODE_TYPE, NODE_PATH
from pgadmin.utils.ajax import make_json_response
-from pgadmin.settings.settings_model import db, ServerGroup
-import config
+from pgadmin.settings.settings_model import db, Server
+import traceback
# Initialise the module
-blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static', static_url_path='', template_folder='templates', url_prefix=NODE_PATH)
+blueprint = Blueprint("NODE-" + NODE_TYPE, __name__,
+ static_folder='static',
+ static_url_path='',
+ template_folder='templates',
+ url_prefix=NODE_PATH)
+
@blueprint.route('/add/', methods=['POST'])
@login_required
@@ -27,30 +32,29 @@ def add():
"""Add a server node to the settings database"""
success = 1
errormsg = ''
- data = { }
-
+ data = {}
+
+ success = False
+ errormsg = ''
if request.form['name'] != '':
server = Server(user_id=current_user.id, name=request.form['name'])
-
try:
db.session.add(server)
db.session.commit()
+ success = True
except Exception as e:
- success = 0
errormsg = e.message
-
else:
- success = 0
errormsg = gettext('No server name was specified')
-
- if success == 1:
+
+ if success:
data['id'] = server.id
data['name'] = server.name
-
- return make_json_response(success=success,
- errormsg=errormsg,
- info=traceback.format_exc(),
- result=request.form,
+
+ return make_json_response(success=success,
+ errormsg=errormsg,
+ info=traceback.format_exc(),
+ result=request.form,
data�ta)
@blueprint.route('/delete/', methods=['POST'])
@@ -63,7 +67,7 @@ def delete():
if request.form['id'] != '':
# There can be only one record at most
servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-
+
if server is None:
success = 0
errormsg = gettext('The specified server could not be found.')
@@ -78,10 +82,10 @@ def delete():
else:
success = 0
errormsg = gettext('No server was specified.')
-
- return make_json_response(success=success,
- errormsg=errormsg,
- info=traceback.format_exc(),
+
+ return make_json_response(success=success,
+ errormsg=errormsg,
+ info=traceback.format_exc(),
result=request.form)
@blueprint.route('/rename/', methods=['POST'])
@@ -94,7 +98,7 @@ def rename():
if request.form['id'] != '':
# There can be only one record at most
servergroup = Server.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-
+
if server is None:
success = 0
errormsg = gettext('The specified server could not be found.')
@@ -109,9 +113,9 @@ def rename():
else:
success = 0
errormsg = gettext('No server was specified.')
-
- return make_json_response(success=success,
- errormsg=errormsg,
- info=traceback.format_exc(),
+
+ return make_json_response(success=success,
+ errormsg=errormsg,
+ info=traceback.format_exc(),
result=request.form)
-
\ No newline at end of file
+
diff --git a/web/pgadmin/browser/server_groups/views.py b/web/pgadmin/browser/server_groups/views.py
index b0f5551..5348819 100644
--- a/web/pgadmin/browser/server_groups/views.py
+++ b/web/pgadmin/browser/server_groups/views.py
@@ -26,24 +26,13 @@ blueprint = Blueprint("NODE-" + NODE_TYPE, __name__, static_folder='static', st
@login_required
def get_nodes(server_group):
"""Build a list of treeview nodes from the child nodes."""
- value = '['
-
+ nodes = []
for node in sub_nodes:
- if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks):
- value += node.hooks.get_nodes(server_group) + ','
-
- if value[-1:] == ',':
- value = value[:-1]
-
- value += ']'
-
- resp = Response(response=value,
- status 0,
- mimetype="text/json")
-
- return resp
-
-
+ if hasattr(node, 'hooks') and hasattr(node.hooks, 'get_nodes'):
+ nodes.extend(node.hooks.get_nodes(server_group))
+ return make_json_response(data=nodes)
+
+
@blueprint.route('/add/', methods=['POST'])
@login_required
def add():
@@ -51,7 +40,7 @@ def add():
success = 1
errormsg = ''
data = { }
-
+
if request.form['name'] != '':
servergroup = ServerGroup(user_id=current_user.id, name=request.form['name'])
@@ -65,15 +54,15 @@ def add():
else:
success = 0
errormsg = gettext('No server group name was specified')
-
+
if success == 1:
data['id'] = servergroup.id
data['name'] = servergroup.name
-
- return make_json_response(success=success,
- errormsg=errormsg,
- info=traceback.format_exc(),
- result=request.form,
+
+ return make_json_response(success=success,
+ errormsg=errormsg,
+ info=traceback.format_exc(),
+ result=request.form,
data�ta)
@blueprint.route('/delete/', methods=['POST'])
@@ -86,7 +75,7 @@ def delete():
if request.form['id'] != '':
# There can be only one record at most
servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-
+
if servergroup is None:
success = 0
errormsg = gettext('The specified server group could not be found.')
@@ -101,10 +90,10 @@ def delete():
else:
success = 0
errormsg = gettext('No server group was specified.')
-
- return make_json_response(success=success,
- errormsg=errormsg,
- info=traceback.format_exc(),
+
+ return make_json_response(success=success,
+ errormsg=errormsg,
+ info=traceback.format_exc(),
result=request.form)
@blueprint.route('/rename/', methods=['POST'])
@@ -117,7 +106,7 @@ def rename():
if request.form['id'] != '':
# There can be only one record at most
servergroup = ServerGroup.query.filter_by(user_id=current_user.id, id=int(request.form['id'])).first()
-
+
if servergroup is None:
success = 0
errormsg = gettext('The specified server group could not be found.')
@@ -132,9 +121,9 @@ def rename():
else:
success = 0
errormsg = gettext('No server group was specified.')
-
- return make_json_response(success=success,
- errormsg=errormsg,
- info=traceback.format_exc(),
+
+ return make_json_response(success=success,
+ errormsg=errormsg,
+ info=traceback.format_exc(),
result=request.form)
-
\ No newline at end of file
+
diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js
index 16025f1..a5c324d 100644
--- a/web/pgadmin/browser/templates/browser/js/browser.js
+++ b/web/pgadmin/browser/templates/browser/js/browser.js
@@ -292,7 +292,12 @@ ALTER TABLE tickets_detail \n\
// Initialise the treeview
$('#tree').aciTree({
ajax: {
- url: '{{ url_for('browser.get_nodes') }}'
+ url: '{{ url_for('browser.get_nodes') }}',
+ converters: {
+ 'text json': function(payload) {
+ return $.parseJSON(payload).data;
+ }
+ }
},
});
tree = $('#tree').aciTree('api');
diff --git a/web/pgadmin/browser/views.py b/web/pgadmin/browser/views.py
index 799deef..8ae6e80 100644
--- a/web/pgadmin/browser/views.py
+++ b/web/pgadmin/browser/views.py
@@ -20,6 +20,7 @@ from . import sub_nodes
from pgadmin.browser import all_nodes
from pgadmin import modules
from pgadmin.settings import get_setting
+from pgadmin.utils.ajax import make_json_response
import config
@@ -50,7 +51,7 @@ def index():
scripts = [ ]
modules_and_nodes = modules + all_nodes
-
+
# Add browser stylesheets
stylesheets.append(url_for('static', filename='css/codemirror/codemirror.css'))
@@ -97,30 +98,30 @@ def index():
# Get the management menu items
if 'hooks' in dir(module) and 'get_management_menu_items' in dir(module.hooks):
management_items.extend(module.hooks.get_management_menu_items())
-
+
# Get the help menu items
if 'hooks' in dir(module) and 'get_help_menu_items' in dir(module.hooks):
help_items.extend(module.hooks.get_help_menu_items())
-
+
# Get any stylesheets
if 'hooks' in dir(module) and 'get_stylesheets' in dir(module.hooks):
stylesheets += module.hooks.get_stylesheets()
-
+
# Get any scripts
if 'hooks' in dir(module) and 'get_scripts' in dir(module.hooks):
scripts += module.hooks.get_scripts()
-
+
file_items = sorted(file_items, key=lambda k: k['priority'])
edit_items = sorted(edit_items, key=lambda k: k['priority'])
tools_items = sorted(tools_items, key=lambda k: k['priority'])
management_items = sorted(management_items, key=lambda k: k['priority'])
help_items = sorted(help_items, key=lambda k: k['priority'])
- return render_template(MODULE_NAME + '/index.html',
- username=current_user.email,
- file_items=file_items,
- edit_items�it_items,
- tools_items=tools_items,
+ return render_template(MODULE_NAME + '/index.html',
+ username=current_user.email,
+ file_items=file_items,
+ edit_items�it_items,
+ tools_items=tools_items,
management_items=management_items,
help_items=help_items,
stylesheets = stylesheets,
@@ -132,15 +133,15 @@ def browser_js():
"""Render and return JS snippets from the nodes and modules."""
snippets = ''
modules_and_nodes = modules + all_nodes
-
+
# Load the core browser code first
-
+
# Get the context menu items
standard_items = [ ]
create_items = [ ]
context_items = [ ]
panel_items = [ ]
-
+
for module in modules_and_nodes:
# Get any standard menu items
if 'hooks' in dir(module) and 'get_standard_menu_items' in dir(module.hooks):
@@ -149,11 +150,11 @@ def browser_js():
# Get any create menu items
if 'hooks' in dir(module) and 'get_create_menu_items' in dir(module.hooks):
create_items.extend(module.hooks.get_create_menu_items())
-
+
# Get any context menu items
if 'hooks' in dir(module) and 'get_context_menu_items' in dir(module.hooks):
context_items.extend(module.hooks.get_context_menu_items())
-
+
# Get any panels
if 'hooks' in dir(module) and 'get_panels' in dir(module.hooks):
panel_items += module.hooks.get_panels()
@@ -162,25 +163,25 @@ def browser_js():
create_items = sorted(create_items, key=lambda k: k['priority'])
context_items = sorted(context_items, key=lambda k: k['priority'])
panel_items = sorted(panel_items, key=lambda k: k['priority'])
-
+
layout = get_setting('Browser/Layout', default='')
-
- snippets += render_template('browser/js/browser.js',
+
+ snippets += render_template('browser/js/browser.js',
layout = layout,
standard_items = standard_items,
create_items = create_items,
context_items = context_items,
panel_items = panel_items)
-
+
# Add module and node specific code
for module in modules_and_nodes:
if 'hooks' in dir(module) and 'get_script_snippets' in dir(module.hooks):
snippets += module.hooks.get_script_snippets()
-
+
resp = Response(response=snippets,
status 0,
mimetype="application/javascript")
-
+
return resp
@blueprint.route("/browser.css")
@@ -189,15 +190,15 @@ def browser_css():
"""Render and return CSS snippets from the nodes and modules."""
snippets = ''
modules_and_nodes = modules + all_nodes
-
+
for module in modules_and_nodes:
if 'hooks' in dir(module) and 'get_css_snippets' in dir(module.hooks):
snippets += module.hooks.get_css_snippets()
-
+
resp = Response(response=snippets,
status 0,
mimetype="text/css")
-
+
return resp
@@ -206,21 +207,8 @@ def browser_css():
def get_nodes():
"""Build a list of treeview nodes from the child nodes."""
value = '['
-
+ nodes = []
for node in sub_nodes:
- if 'hooks' in dir(node) and 'get_nodes' in dir(node.hooks):
- value += node.hooks.get_nodes() + ','
-
- if value[-1:] == ',':
- value = value[:-1]
-
- value += ']'
-
- resp = Response(response=value,
- status 0,
- mimetype="text/json")
-
- return resp
-
-
-
\ No newline at end of file
+ if hasattr(node, 'hooks') and hasattr(node.hooks, 'get_nodes'):
+ nodes.extend(node.hooks.get_nodes())
+ return make_json_response(data=nodes)
diff --git a/web/pgadmin/settings/settings_model.py b/web/pgadmin/settings/settings_model.py
index 731137b..3dc82c1 100644
--- a/web/pgadmin/settings/settings_model.py
+++ b/web/pgadmin/settings/settings_model.py
@@ -9,7 +9,7 @@
"""Defines the models for the configuration database.
-If any of the models are updated, you (yes, you, the developer) MUST do two
+If any of the models are updated, you (yes, you, the developer) MUST do two
things:
1) Increment SETTINGS_SCHEMA_VERSION in config.py
@@ -28,12 +28,13 @@ roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
+
class Version(db.Model):
"""Version numbers for reference/upgrade purposes"""
__tablename__ = 'version'
name = db.Column(db.String(32), primary_key=True)
value = db.Column(db.Integer(), nullable�lse)
-
+
class Role(db.Model, RoleMixin):
"""Define a security role"""
__tablename__ = 'role'
@@ -51,7 +52,7 @@ class User(db.Model, UserMixin):
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref�.backref('users', lazy='dynamic'))
-
+
class Setting(db.Model):
"""Define a setting object"""
__tablename__ = 'setting'
@@ -66,7 +67,7 @@ class ServerGroup(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable�lse)
name = db.Column(db.String(128), nullable�lse)
__table_args__ = (db.UniqueConstraint('user_id', 'name'),)
-
+
class Server(db.Model):
"""Define a registered Postgres server"""
@@ -80,5 +81,3 @@ class Server(db.Model):
maintenance_db = db.Column(db.String(64), nullable�lse)
username = db.Column(db.String(64), nullable�lse)
ssl_mode = db.Column(db.String(16), nullable�lse)
-
-
diff --git a/web/pgadmin/utils/ajax.py b/web/pgadmin/utils/ajax.py
index 367c356..db77b97 100644
--- a/web/pgadmin/utils/ajax.py
+++ b/web/pgadmin/utils/ajax.py
@@ -9,20 +9,13 @@
"""Utility functions for dealing with AJAX."""
-from flask import Response
+from flask import jsonify
import json
-def make_json_response(success=1, errormsg='', info='', result={}, data={}):
+def make_json_response(success=True, **kwargs):
"""Create a HTML response document describing the results of a request and
containing the data."""
- doc = { }
- doc['success'] = success
- doc['errormsg'] = errormsg
- doc['info'] = info
- doc['result'] = result
- doc['data'] = data
-
- response = Response(response=json.dumps(doc),
- status 0,
- mimetype="text/json")
- return response
\ No newline at end of file
+ response = kwargs.copy()
+ response.setdefault('result', {})
+ response.setdefault('data', {})
+ return jsonify(response)
signature.asc
Description: This is a digitally signed message part.
