Introduced a class - NodeView to achieve REST API required by the

PostgreSQL node(s).

Browser Tree Node (PostgreSQL object) requires more than just CRUD.
i.e.
   - CRUD (Create, Read, Update & Delete)
    - Reversed Engineered SQL for the object
    - Modified Query in edit mode
      i.e. ALTER TABLE ...
    - Statistics
    - List of dependents
    - List of dependencies
    - Children node list

This class can be inherited to achieve the different routes for each of
the object types/collections.

    OPERATION      |              URL       | Method
    ---------------+------------------------+--------
    List           | /obj/[Parent URL]/     | GET
    Properties     | /obj/[Parent URL]/id   | GET
    Create         | /obj/[Parent URL]/     | POST
    Delete         | /obj/[Parent URL]/id   | DELETE
    Update         | /obj/[Parent URL]/id   | PUT

    SQL (Reversed  | /sql/[Parent URL]/id   | GET
    Engineering)   |
    SQL (Modified  | /sql/[Parent URL]/id   | POST
    Properties)    |

    Statistics     | /stats/[Parent URL]/id | GET
    Dependencies   | /deps/[Parent URL]/id  | GET
    Dependents     | /deps/[Parent URL]/id  | POST

    Children Nodes | /nodes/[Parent URL]/id | GET

    NOTE:
    Parent URL can be seen as the path to identify the particular node.

    i.e.
     In order to identify the TABLE object, we requires information
     about the server -> database -> schema objects.

     Hence, the Parent URL for the TABLE object will be something like
     this as below:
     <int:sid>/<str:database>/<str:schema>

Inherited a new classes ServerGroupView and ServerView, which are
inherited from the NodeView for the implementation of above operations.
This commit is contained in:
Ashesh Vashi
2015-06-29 13:41:56 +05:30
parent b626eec0fd
commit 35d01bea3e
12 changed files with 603 additions and 260 deletions

View File

@@ -18,10 +18,10 @@ from pgadmin.utils.ajax import make_json_response
from pgadmin.browser import BrowserPluginModule
from pgadmin.utils.menu import MenuItem
from pgadmin.settings.settings_model import db, ServerGroup
from pgadmin.browser.utils import generate_browser_node
import config
class ServerGroupModule(BrowserPluginModule):
NODE_TYPE = "server-group"
@@ -65,18 +65,20 @@ class ServerGroupModule(BrowserPluginModule):
# TODO: Move this JSON generation to a Server method
# this code is duplicated somewhere else
for group in groups:
yield {
"id": "%s/%d" % (self.node_type, group.id),
"label": group.name,
"icon": "icon-%s" % self.node_type,
"inode": True,
"_type": self.node_type
}
yield generate_browser_node(
"%d" % (group.id),
group.name,
"icon-%s" % self.node_type,
True,
self.node_type)
@property
def node_type(self):
return self.NODE_TYPE
@property
def node_path(self):
return '/browser/' + self.node_type
class ServerGroupMenuItem(MenuItem):
@@ -99,109 +101,142 @@ class ServerGroupPluginModule(BrowserPluginModule):
pass
# Initialise the module
@property
def node_path(self):
return '/browser/' + self.node_type
blueprint = ServerGroupModule( __name__, static_url_path='')
@blueprint.route("/<server_group>")
@login_required
def get_nodes(server_group):
"""Build a list of treeview nodes from the child nodes."""
nodes = []
for module in current_blueprint.submodules:
nodes.extend(module.get_nodes(server_group=server_group))
return make_json_response(data=nodes)
# Initialise the module
from pgadmin.browser.utils import NodeView
@blueprint.route('/add/', methods=['POST'])
@login_required
def add():
"""Add a server group node to the settings database"""
success = 1
errormsg = ''
data = { }
class ServerGroupView(NodeView):
if request.form['name'] != '':
servergroup = ServerGroup(user_id=current_user.id, name=request.form['name'])
node_type = ServerGroupModule.NODE_TYPE
parent_ids = []
ids = [{'type':'int', 'id':'gid'}]
try:
db.session.add(servergroup)
db.session.commit()
except Exception as e:
success = 0
errormsg = e.message
else:
success = 0
errormsg = gettext('No server group name was specified')
def list(self):
res = []
for g in blueprint.get_nodes():
res.append(g)
return make_json_response(result=res)
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,
data=data)
def delete(self, gid):
"""Delete a server group node in the settings database"""
@blueprint.route('/delete/', methods=['POST'])
@login_required
def delete():
"""Delete a server group node in the settings database"""
success = 1
errormsg = ''
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()
servergroup = ServerGroup.query.filter_by(
user_id=current_user.id,
id=gid)
if servergroup is None:
success = 0
errormsg = gettext('The specified server group could not be found.')
return make_json_response(
success=0,
errormsg=gettext('The specified server group could not be found.'))
else:
try:
db.session.delete(servergroup)
db.session.commit()
except Exception as e:
success = 0
errormsg = e.message
return make_json_response(success=0, errormsg=e.message)
else:
success = 0
errormsg = gettext('No server group was specified.')
return make_json_response(result=request.form)
return make_json_response(success=success,
errormsg=errormsg,
info=traceback.format_exc(),
result=request.form)
@blueprint.route('/rename/', methods=['POST'])
@login_required
def rename():
"""Rename a server group node in the settings database"""
success = 1
errormsg = ''
def update(self, gid):
"""Update the server-group properties"""
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()
servergroup = ServerGroup.query.filter_by(
user_id=current_user.id,
id=gid).first()
if servergroup is None:
success = 0
errormsg = gettext('The specified server group could not be found.')
return make_json_response(
success=0,
errormsg=gettext('The specified server group could not be found.'))
else:
try:
servergroup.name = request.form['name']
if 'name' in request.form:
servergroup.name = request.form['name']
db.session.commit()
except Exception as e:
success = 0
errormsg = e.message
return make_json_response(success=0, errormsg=e.message)
else:
success = 0
errormsg = gettext('No server group was specified.')
return make_json_response(result=request.form)
return make_json_response(success=success,
errormsg=errormsg,
info=traceback.format_exc(),
result=request.form)
def properties(self, gid):
"""Update the server-group properties"""
# There can be only one record at most
sg = ServerGroup.query.filter_by(
user_id=current_user.id,
id=gid).first()
data = {}
if sg is None:
return make_json_response(
success=0,
errormsg=gettext('The specified server group could not be found.'))
else:
return make_json_response(data={'id': sg.id, 'name': sg.name})
def create(self):
data = []
if request.form['name'] != '':
servergroup = ServerGroup(
user_id=current_user.id,
name=request.form['name'])
try:
db.session.add(servergroup)
db.session.commit()
data['id'] = servergroup.id
data['name'] = servergroup.name
except Exception as e:
return make_json_response(success=0, errormsg=e.message)
else:
return make_json_response(
success=0,
errormsg=gettext('No server group name was specified'))
return make_json_response(data=data)
def nodes(self, gid):
"""Build a list of treeview nodes from the child nodes."""
nodes = []
for module in blueprint.submodules:
nodes.extend(module.get_nodes(server_group=gid))
return make_json_response(data=nodes)
def sql(self, gid):
return make_json_response(data='')
def modified_sql(self, gid):
return make_json_response(data='')
def statistics(self, gid):
return make_json_response(data='')
def dependencies(self, gid):
return make_json_response(data='')
def dependents(self, gid):
return make_json_response(data='')
ServerGroupView.register_node_view(blueprint)

View File

@@ -9,9 +9,10 @@
from flask import render_template, request
from pgadmin.browser.server_groups import ServerGroupPluginModule
from flask.ext.security import login_required, current_user
from pgadmin.settings.settings_model import db, Server
from pgadmin.settings.settings_model import db, Server, ServerGroup
from pgadmin.utils.menu import MenuItem
from pgadmin.utils.ajax import make_json_response
from pgadmin.browser.utils import generate_browser_node, NodeView
import traceback
from flask.ext.babel import gettext
@@ -30,13 +31,13 @@ class ServerModule(ServerGroupPluginModule):
# TODO: Move this JSON generation to a Server method
for server in servers:
yield {
"id": "%s/%d" % (NODE_TYPE, server.id),
"label": server.name,
"icon": "icon-%s" % NODE_TYPE,
"inode": True,
"_type": NODE_TYPE
}
yield generate_browser_node(
"%d" % server.id,
server.name,
"icon-%s" % self.NODE_TYPE,
True,
self.NODE_TYPE
)
def get_own_menuitems(self):
return {
@@ -49,13 +50,13 @@ class ServerModule(ServerGroupPluginModule):
name="create_server",
label=gettext('Server...'),
priority=50,
function='create_server')
function='create_server(item)')
],
'context_items': [
ServerMenuItem(name='delete_server',
label=gettext('Delete server'),
priority=50,
onclick='drop_server'),
onclick='drop_server(item)'),
ServerMenuItem(name='rename_server',
label=gettext('Rename server...'),
priority=60,
@@ -75,98 +76,224 @@ class ServerMenuItem(MenuItem):
kwargs.setdefault("type", ServerModule.NODE_TYPE)
super(ServerMenuItem, self).__init__(**kwargs)
blueprint = ServerModule(__name__)
@blueprint.route('/add/', methods=['POST'])
@login_required
def add():
"""Add a server node to the settings database"""
success = 1
errormsg = ''
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:
errormsg = e.message
else:
errormsg = gettext('No server name was specified')
class ServerNode(NodeView):
if success:
data['id'] = server.id
data['name'] = server.name
node_type = ServerModule.NODE_TYPE
parent_ids = [{'type':'int', 'id':'gid'}]
ids = [{'type':'int', 'id':'sid'}]
return make_json_response(success=success,
errormsg=errormsg,
info=traceback.format_exc(),
result=request.form,
data=data)
@blueprint.route('/delete/', methods=['POST'])
@login_required
def delete():
"""Delete a server node in the settings database"""
success = 1
errormsg = ''
def list(self, gid):
res = []
"""Return a JSON document listing the server groups for the user"""
servers = Server.query.filter_by(user_id=current_user.id,
servergroup_id=gid)
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()
for server in servers:
res.append(
generate_browser_node(
"%d/%d" % (gid, server.id),
server.name,
"icon-%s" % NODE_TYPE,
True,
NODE_TYPE
)
)
return make_json_response(result=res)
def delete(self, gid, sid):
"""Delete a server node in the settings database"""
server = Server.query.filter_by(user_id=current_user.id, id=sid)
# TODO:: A server, which is connected, can not be deleted
if server is None:
success = 0
errormsg = gettext('The specified server could not be found.')
return make_json_response(
success=0,
errormsg=gettext(
'The specified server could not be found.\n'
'Does the user have permission to access the '
'server?'
)
)
else:
try:
db.session.delete(server)
db.session.commit()
except Exception as e:
success = 0
errormsg = e.message
return make_json_response(
success=0,
errormsg=e.message)
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'])
@login_required
def rename():
"""Rename a server node in the settings database"""
success = 1
errormsg = ''
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()
def update(self, gid, sid):
"""Update the server settings"""
server = Server.query.filter_by(user_id=current_user.id, id=sid).first()
if server is None:
success = 0
errormsg = gettext('The specified server could not be found.')
else:
try:
server.name = request.form['name']
db.session.commit()
except Exception as e:
success = 0
errormsg = e.message
return make_json_response(
success=0,
errormsg=gettext("Couldn't find the given server.")
)
else:
success = 0
errormsg = gettext('No server was specified.')
# TODO::
# Not all parameters can be modified, while the server is connected
possible_args = {
'name': 'name',
'host': 'host',
'port': 'port',
'db': 'maintenance_db',
'username': 'username',
'sslmode': 'sslmode',
'gid': 'servergroup_id'
}
return make_json_response(success=success,
errormsg=errormsg,
info=traceback.format_exc(),
result=request.form)
idx = 0
for arg in possible_args:
if arg in request.form:
server[possible_args[arg]] = request.form[arg]
idx += 1
if idx == 0:
return make_json_response(
success=0,
errormsg=gettext('No parameters were chagned!')
)
try:
db.session.commit()
except Exception as e:
return make_json_response(
success=0,
errormsg=e.message
)
return make_json_response(
success=1,
data={
'id': server.id,
'gid': server.servergroup_id
}
)
def properties(self, gid, sid):
"""Return list of attributes of a server"""
server = Server.query.filter_by(
user_id=current_user.id,
id=sid).first()
if server is None:
return make_json_response(
success=0,
errormsg=gettext("Couldn't find the given server")
)
sg = ServerGroup.query.filter_by(
user_id=current_user.id,
id=server.servergroup_id
).first()
return make_json_response(
success=1,
data={
'id':server.id,
'name':server.name,
'host':server.host,
'port':server.port,
'db':server.maintenance_db,
'username':server.username,
'gid':server.servergroup_id,
'group-name':sg.name
}
)
def create(self, gid):
"""Add a server node to the settings database"""
required_args = [
'name',
'host',
'port',
'db',
'username',
'sslmode'
]
for arg in required_args:
if arg not in request.form:
return make_json_response(
success=0,
errormsg=gettext(
"Couldn't find the required parameter (%s)." % arg
)
)
server = Server(
user_id=current_user.id,
servergroup_id=gid,
name=request.form['name'],
host=request.form['host'],
port=request.form['port'],
maintenance_db=request.form['db'],
username=request.form['username'],
sslmode=request.form['username']
)
try:
db.session.add(server)
db.session.commit()
except Exception as e:
return make_json_response(
success=0,
errormsg=e.message
)
return make_json_response(success=1,
data={
'id': server.id,
'name': server.name,
'gid': gid
})
def nodes(self, gid, sid):
"""Build a list of treeview nodes from the child nodes."""
nodes = []
# TODO::
# We can have nodes for the server object, only when
# the server is connected at the moment.
for module in blueprint.submodules:
nodes.extend(module.get_nodes(server=sid))
return make_json_response(data=nodes)
def sql(self, gid, sid):
return make_json_response(data='')
def modified_sql(self, gid, sid):
return make_json_response(data='')
def statistics(self, gid, sid):
return make_json_response(data='')
def dependencies(self, gid, sid):
return make_json_response(data='')
def dependents(self, gid, sid):
return make_json_response(data='')
ServerNode.register_node_view(blueprint)

View File

@@ -1,11 +1,18 @@
// Add a server
function create_server() {
function create_server(item) {
var alert = alertify.prompt(
'{{ _('Create a server') }}',
'{{ _('Enter a name for the new server') }}',
'',
function(evt, value) {
$.post("{{ url_for('NODE-server.add') }}", { name: value })
var d = tree.itemData(item);
if (d._type != 'server-group') {
d = tree.itemData(tree.parent(item));
}
$.post(
"{{ url_for('browser.index') }}server/obj/" + d.refid + '/',
{ name: value }
)
.done(function(data) {
if (data.success == 0) {
report_error(data.errormsg, data.info);
@@ -38,8 +45,10 @@ function drop_server(item) {
'{{ _('Are you sure you wish to drop the server "{0}"?') }}'.replace('{0}', tree.getLabel(item)),
function() {
var id = tree.getId(item).split('/').pop()
$.post("{{ url_for('NODE-server.delete') }}", { id: id })
.done(function(data) {
$.ajax({
url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
type:'DELETE',
success: function(data) {
if (data.success == 0) {
report_error(data.errormsg, data.info);
} else {
@@ -53,7 +62,7 @@ function drop_server(item) {
}
}
}
)
})
},
null
)
@@ -66,17 +75,20 @@ function rename_server(item) {
'{{ _('Enter a new name for the server') }}',
tree.getLabel(item),
function(evt, value) {
var id = tree.getId(item).split('/').pop()
$.post("{{ url_for('NODE-server.rename') }}", { id: id, name: value })
.done(function(data) {
var d = tree.itemData(item);
$.ajax({
url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
type:'PUT',
params: {name: value},
success: function(data) {
if (data.success == 0) {
report_error(data.errormsg, data.info);
} else {
tree.setLabel(item, { label: value });
}
}
)
})
},
null
)
}
}

View File

@@ -5,7 +5,7 @@ function create_server_group() {
'{{ _('Enter a name for the new server group') }}',
'',
function(evt, value) {
$.post("{{ url_for('NODE-server-group.add') }}", { name: value })
$.post("{{ url_for('browser.index') }}server-group/obj/", { name: value })
.done(function(data) {
if (data.success == 0) {
report_error(data.errormsg, data.info);
@@ -37,9 +37,11 @@ function drop_server_group(item) {
'{{ _('Delete server group?') }}',
'{{ _('Are you sure you wish to delete the server group "{0}"?') }}'.replace('{0}', tree.getLabel(item)),
function() {
var id = tree.getId(item).split('/').pop()
$.post("{{ url_for('NODE-server-group.delete') }}", { id: id })
.done(function(data) {
var d = tree.itemData(item);
$.ajax({
url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
type:'DELETE',
success: function(data) {
if (data.success == 0) {
report_error(data.errormsg, data.info);
} else {
@@ -53,7 +55,7 @@ function drop_server_group(item) {
}
}
}
)
})
},
null
)
@@ -66,16 +68,19 @@ function rename_server_group(item) {
'{{ _('Enter a new name for the server group') }}',
tree.getLabel(item),
function(evt, value) {
var id = tree.getId(item).split('/').pop()
$.post("{{ url_for('NODE-server-group.rename') }}", { id: id, name: value })
.done(function(data) {
var d = tree.itemData(item);
$.ajax({
url:"{{ url_for('browser.index') }}" + d._type + "/obj/" + d.refid,
type:'PUT',
params: { name: value },
success: function(data) {
if (data.success == 0) {
report_error(data.errormsg, data.info);
} else {
tree.setLabel(item, { label: value });
}
}
)
})
},
null
)