Resolved few intialization issue with Node model data, moved the
privileges functionality out of the backform.pgadmin.js to make it more modular. Now - privileges will expect the privileges data in following format: <name_of_the_property> : [{ "privileges": [{ "privilege_type": <privilege_type>, "privilege": true, "with_grant": false }, ... ], "grantee": <grantee>, "grantor": <grantor> }, ... ] Example: acl": [{ "privileges": [{ "privilege_type": "CONNECT", "privilege": true, "with_grant": false }], "grantee": '', "grantor": 'ashesh' },{ "privileges": [{ "privilege_type": "CREATE", "privilege": true, "with_grant": false },{ "privilege": true, "privilege_type": "TEMPORARY", "with_grant": false }], "grantee": test, "grantor": ashesh }]pull/3/head
parent
bf5170bc89
commit
c51ecc69e4
|
@ -8,7 +8,8 @@
|
|||
##########################################################################
|
||||
import json
|
||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||
from flask import render_template, request, make_response, jsonify, current_app
|
||||
from flask import render_template, request, make_response, jsonify, \
|
||||
current_app, url_for
|
||||
from flask.ext.security import login_required, current_user
|
||||
from pgadmin.settings.settings_model import db, Server, ServerGroup, User
|
||||
from pgadmin.utils.menu import MenuItem
|
||||
|
@ -84,6 +85,25 @@ class ServerModule(sg.ServerGroupPluginModule):
|
|||
|
||||
return snippets
|
||||
|
||||
def get_own_javascripts(self):
|
||||
scripts = []
|
||||
|
||||
scripts.extend([{
|
||||
'name': 'pgadmin.node.server',
|
||||
'path': url_for('browser.index') + '%s/module' % self.node_type,
|
||||
'when': self.script_load
|
||||
},
|
||||
{
|
||||
'name': 'pgadmin.browser.server.privilege',
|
||||
'path': url_for('browser.index') + 'server/static/js/privilege',
|
||||
'when': self.node_type
|
||||
}])
|
||||
|
||||
for module in self.submodules:
|
||||
scripts.extend(module.get_own_javascripts())
|
||||
|
||||
return scripts
|
||||
|
||||
|
||||
class ServerMenuItem(MenuItem):
|
||||
def __init__(self, **kwargs):
|
||||
|
@ -606,7 +626,8 @@ class ServerNode(PGChildNodeView):
|
|||
),
|
||||
'connected': True,
|
||||
'type': manager.server_type,
|
||||
'version': manager.version
|
||||
'version': manager.version,
|
||||
'db': manager.db
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
(function(root, factory) {
|
||||
// Set up Backform appropriately for the environment. Start with AMD.
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify', 'pgadmin.browser.node'],
|
||||
function(_, $, Backbone, Backform, Backgrid, Alertify, pgNode) {
|
||||
// Export global even in AMD case in case this script is loaded with
|
||||
// others that may still expect a global Backform.
|
||||
return factory(root, _, $, Backbone, Backform, Alertify, pgNode);
|
||||
});
|
||||
|
||||
// Next for Node.js or CommonJS. jQuery may not be needed as a module.
|
||||
} else if (typeof exports !== 'undefined') {
|
||||
var _ = require('underscore') || root._,
|
||||
$ = root.jQuery || root.$ || root.Zepto || root.ender,
|
||||
Backbone = require('backbone') || root.Backbone,
|
||||
Backform = require('backform') || root.Backform;
|
||||
Alertify = require('alertify') || root.Alertify;
|
||||
pgAdmin = require('pgadmin.browser.node') || root.pgAdmin.Browser.Node;
|
||||
factory(root, _, $, Backbone, Backform, Alertify, pgNode);
|
||||
|
||||
// Finally, as a browser global.
|
||||
} else {
|
||||
factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.pgAdmin.Browser.Node);
|
||||
}
|
||||
} (this, function(root, _, $, Backbone, Backform, Alertify, pgNode) {
|
||||
|
||||
/**
|
||||
* Each Privilege, supporeted by an database object, will be represented
|
||||
* using this Model.
|
||||
*
|
||||
* Defaults:
|
||||
* privilege_type -> Name of the permission
|
||||
* i.e. CREATE, TEMPORARY, CONNECT, etc.
|
||||
* privilege -> Has privilege? (true/false)
|
||||
* with_grant -> Has privilege with grant option (true/false)
|
||||
**/
|
||||
var PrivilegeModel = pgNode.Model.extend({
|
||||
idAttribute: 'privilege_type',
|
||||
defaults: {
|
||||
privilege_type: undefined,
|
||||
privilege: false,
|
||||
with_grant: false
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A database object has privileges item list (aclitem[]).
|
||||
*
|
||||
* This model represents the individual privilege item (aclitem).
|
||||
* It has basically three properties:
|
||||
* + grantee - Role to which that privilege applies to.
|
||||
* Empty value represents to PUBLIC.
|
||||
* + grantor - Granter who has given this permission.
|
||||
* + privileges - Privileges for that role.
|
||||
**/
|
||||
var PrivilegeRoleModel = pgNode.PrivilegeRoleModel = pgNode.Model.extend({
|
||||
defaults: {
|
||||
grantee: undefined,
|
||||
grantor: undefined,
|
||||
privileges: undefined
|
||||
},
|
||||
/*
|
||||
* Each of the database object needs to extend this model, which should
|
||||
* provide the type of privileges (it supports).
|
||||
*/
|
||||
privileges:[],
|
||||
|
||||
schema: [{
|
||||
id: 'grantee', label:'Grantee', type:'text', group: null, cell: 'string',
|
||||
disabled: true, cellHeaderClasses: 'width_percent_40'
|
||||
}, {
|
||||
id: 'privileges', label:'Privileges',
|
||||
type: 'collection', model: PrivilegeModel, group: null,
|
||||
disabled: false, cell: 'privilege', control: 'text',
|
||||
cellHeaderClasses: 'width_percent_40'
|
||||
},{
|
||||
id: 'grantor', label: 'Granter', type: 'text', disabled: true
|
||||
}],
|
||||
|
||||
/*
|
||||
* Initialize the model, which will transform the privileges string to
|
||||
* collection of Privilege Model.
|
||||
*/
|
||||
initialize: function(attrs, opts) {
|
||||
|
||||
pgNode.Model.prototype.initialize.apply(this, arguments);
|
||||
|
||||
/*
|
||||
* Define the collection of the privilege supported by this model
|
||||
*/
|
||||
var privileges = this.get('privileges') || {};
|
||||
if (_.isArray(privileges)) {
|
||||
privileges = new (pgNode.Collection)(
|
||||
models, {
|
||||
model: PrivilegeModel,
|
||||
handler: this.handler || this,
|
||||
silent: true,
|
||||
parse: false
|
||||
});
|
||||
this.set('privileges', privileges, {silent: true});
|
||||
}
|
||||
|
||||
var privs = {};
|
||||
_.each(this.privileges, function(p) {
|
||||
privs[p] = {
|
||||
'privilige_type': p, 'privilege': false, 'with_grant': false
|
||||
}
|
||||
});
|
||||
|
||||
privileges.each(function(m) {
|
||||
delete privs[m.get('privilege_type')];
|
||||
});
|
||||
|
||||
_.each(privs, function(p) {
|
||||
privileges.add(p, {silent: true});
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
toJSON: function(session) {
|
||||
if (session) {
|
||||
return pgNode.Model.prototype.apply(this, [true, false]);
|
||||
}
|
||||
|
||||
var privileges = [];
|
||||
|
||||
this.attributes['privileges'].each(
|
||||
function(p) {
|
||||
if (p.get('privilege')) {
|
||||
privileges.push(p.toJSON());
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
'grantee': this.get('grantee'),
|
||||
'grantor': this.get('grantor'),
|
||||
'privileges': privileges
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Custom cell editor for editing privileges.
|
||||
*/
|
||||
var PrivilegeCellEditor = Backgrid.Extension.PrivilegeCellEditor =
|
||||
Backgrid.CellEditor.extend({
|
||||
tagName: "div",
|
||||
|
||||
// All available privileges in the PostgreSQL database server for
|
||||
// generating the label for the specific Control
|
||||
Labels: {
|
||||
"C": "CREATE",
|
||||
"T": "TEMP",
|
||||
"c": "CONNECT",
|
||||
"a": "INSERT",
|
||||
"r": "SELECT",
|
||||
"w": "UPDATE",
|
||||
"d": "DELETE",
|
||||
"D": "TRUNCATE",
|
||||
"x": "REFERENCES",
|
||||
"t": "TRIGGER",
|
||||
"U": "USAGE",
|
||||
"X": "EXECUTE"
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<tr class="<%= header ? "header" : "" %>">',
|
||||
' <td class="renderable">',
|
||||
' <label>',
|
||||
' <input type="checkbox" name="privilege" privilege="<%- privilege_type %>" target="<%- target %>" <%= privilege ? \'checked\' : "" %>></input>',
|
||||
' <%- privilege_type %>',
|
||||
' </label>',
|
||||
' </td>',
|
||||
' <td class="renderable">',
|
||||
' <label>',
|
||||
' <input type="checkbox" name="with_grant" privilege="<%- privilege_type %>" target="<%- target %>" <%= with_grant ? \'checked\' : "" %> <%= privilege ? "" : \'disabled\'%>></input>',
|
||||
' WITH GRANT OPTION',
|
||||
' </label>',
|
||||
' </td>',
|
||||
'</tr>'].join(" "), null, {variable: null}),
|
||||
|
||||
events: {
|
||||
'change': 'privilegeChanged',
|
||||
'blur': 'lostFocus'
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this.$el.attr('tabindex', '1');
|
||||
this.$el.attr('target', this.elId);
|
||||
|
||||
var collection = this.model.get(this.column.get("name")),
|
||||
tbl = $("<table></table>").appendTo(this.$el),
|
||||
self = this,
|
||||
privilege = true, with_grant = true;
|
||||
|
||||
// For each privilege generate html template.
|
||||
// List down all the Privilege model.
|
||||
collection.each(function(m) {
|
||||
var d = m.toJSON();
|
||||
|
||||
_.extend(
|
||||
d, {
|
||||
'target': self.cid,
|
||||
'header': false
|
||||
});
|
||||
privilege = (privilege && d.privilege);
|
||||
with_grant = (with_grant && privilege && d.with_grant);
|
||||
tbl.append(self.template(d));
|
||||
});
|
||||
|
||||
// Preprend the ALL controls on that table
|
||||
tbl.prepend(
|
||||
self.template({
|
||||
'target': self.cid,
|
||||
'name': 'ALL',
|
||||
'privilege_type': 'ALL',
|
||||
'privilege': privilege,
|
||||
'with_grant': with_grant,
|
||||
'header': true
|
||||
}));
|
||||
|
||||
self.$el.find('input[type=checkbox]').first().focus();
|
||||
self.delegateEvents();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/*
|
||||
* Listen to the checkbox value change and update the model accordingly.
|
||||
*/
|
||||
privilegeChanged: function(ev) {
|
||||
if (ev && ev.target) {
|
||||
/*
|
||||
* We're looking for checkboxes only.
|
||||
*/
|
||||
var $el = $(ev.target),
|
||||
privilege_type = $el.attr('privilege'),
|
||||
type = $el.attr('name'),
|
||||
checked = $el.prop('checked'),
|
||||
$tr = $el.closest('tr'),
|
||||
$tbl = $tr.closest('table'),
|
||||
collection = this.model.get('privileges');;
|
||||
|
||||
/*
|
||||
* If the checkbox selected/deselected is for 'ALL', we will select all
|
||||
* the checkbox for each privilege.
|
||||
*/
|
||||
if (privilege_type == 'ALL') {
|
||||
var $elGrant = $tr.find('input[name=with_grant]'),
|
||||
$allPrivileges = $tbl.find(
|
||||
'input[name=privilege][privilege!=\'ALL\']'
|
||||
),
|
||||
$allGrants = $tbl.find(
|
||||
'input[name=with_grant][privilege!=\'ALL\']'
|
||||
),
|
||||
allPrivilege, allWithGrant;
|
||||
|
||||
if (type == 'privilege') {
|
||||
/*
|
||||
* We clicked the privilege checkbox, and not checkbox for with
|
||||
* grant options.
|
||||
*/
|
||||
allPrivilege = checked;
|
||||
allWithGrant = false;
|
||||
|
||||
if (checked) {
|
||||
$allPrivileges.prop('checked', true);
|
||||
/*
|
||||
* We have clicked the ALL checkbox, we should be able to select
|
||||
* the grant options too.
|
||||
*/
|
||||
$allGrants.prop('disabled', false);
|
||||
$elGrant.prop('disabled', false);
|
||||
} else {
|
||||
/*
|
||||
* ALL checkbox has been deselected, hence - we need to make
|
||||
* sure.
|
||||
* 1. Deselect all the privileges checkboxes
|
||||
* 2. Deselect and disable all with grant privilege checkboxes.
|
||||
* 3. Deselect and disable the checkbox for ALL with grant privilege.
|
||||
*/
|
||||
$allPrivileges.prop('checked', false);
|
||||
$elGrant.prop('checked', false),
|
||||
$allGrants.prop('checked', false);
|
||||
$elGrant.prop('disabled', true);
|
||||
$allGrants.prop('disabled', true);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We were able to click the ALL with grant privilege checkbox,
|
||||
* that means, privilege for Privileges are true.
|
||||
*
|
||||
* We need to select/deselect all the with grant options
|
||||
* checkboxes, based on the current value of the ALL with grant
|
||||
* privilege checkbox.
|
||||
*/
|
||||
allPrivilege = true;
|
||||
allWithGrant = checked;
|
||||
$allGrants.prop('checked', checked);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the values for each Privilege Model.
|
||||
*/
|
||||
collection.each(function(m) {
|
||||
m.set({'privilege': allPrivilege, 'with_grant': allWithGrant});
|
||||
});
|
||||
} else {
|
||||
/*
|
||||
* Particular privilege has been selected/deselected, which can be
|
||||
* identified using the privilege="X" attribute.
|
||||
*/
|
||||
var attrs = {},
|
||||
$tbl = $tr.closest('table'),
|
||||
$allPrivilege = $tbl.find(
|
||||
'input[name=privilege][privilege=\'ALL\']'
|
||||
),
|
||||
$allGrant = $tbl.find(
|
||||
'input[name=with_grant][privilege=\'ALL\']'
|
||||
);
|
||||
|
||||
attrs[type] = checked;
|
||||
|
||||
if (type == 'privilege') {
|
||||
var $elGrant = ($el.closest('tr')).find('input[name=with_grant]');
|
||||
if (!checked) {
|
||||
attrs['with_grant'] = false;
|
||||
|
||||
$elGrant.prop('checked', false).prop('disabled', true);
|
||||
$allPrivilege.prop('checked', false);
|
||||
$allGrant.prop('disabled', true);
|
||||
$allGrant.prop('checked', false);
|
||||
} else {
|
||||
$elGrant.prop('disabled', false);
|
||||
}
|
||||
} else if (!checked) {
|
||||
$allGrant.prop('checked', false);
|
||||
}
|
||||
collection.get(privilege_type).set(attrs);
|
||||
|
||||
if (checked) {
|
||||
var $allPrivileges = $tbl.find(
|
||||
'input[name=privilege][privilege!=\'ALL\']:checked'
|
||||
);
|
||||
|
||||
if ($allPrivileges.length == collection.models.length) {
|
||||
|
||||
$allPrivilege.prop('checked', true);
|
||||
|
||||
if (type == 'with_grant') {
|
||||
var $allGrants = $tbl.find(
|
||||
'input[name=with_grant][privilege!=\'ALL\']:checked'
|
||||
);
|
||||
if ($allGrants.length == collection.models.length) {
|
||||
$allGrant.prop('disabled', false);
|
||||
$allGrant.prop('checked', true);
|
||||
}
|
||||
} else {
|
||||
$allGrant.prop('disabled', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
lostFocus: function(ev) {
|
||||
/*
|
||||
* We lost the focuse, it's time for us to exit the editor.
|
||||
*/
|
||||
var m = this.model;
|
||||
m.trigger('backgrid:edited', m, this.column, new Backgrid.Command(ev));
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* This will help us transform the privilieges value in proper format to be
|
||||
* displayed in the cell.
|
||||
*/
|
||||
var PrivilegeCellFormatter = Backgrid.Extension.PrivilegeCellFormatter =
|
||||
function () {};
|
||||
_.extend(PrivilegeCellFormatter.prototype, {
|
||||
notation: {
|
||||
"CREATE" : "C",
|
||||
"TEMPORARY" : "T",
|
||||
"CONNECT" : "c",
|
||||
"INSERT" : "a",
|
||||
"SELECT" : "r",
|
||||
"UPDATE" : "w",
|
||||
"DELETE" : "d",
|
||||
"TRUNCATE" : "D",
|
||||
"REFERENCES" : "x",
|
||||
"TRIGGER" : "t",
|
||||
"USAGE" : "U",
|
||||
"EXECUTE" : "X"
|
||||
},
|
||||
/**
|
||||
* Takes a raw value from a model and returns an optionally formatted
|
||||
* string for display.
|
||||
*/
|
||||
fromRaw: function (rawData, model) {
|
||||
var res = '',
|
||||
self = this;
|
||||
|
||||
if (rawData instanceof Backbone.Collection) {
|
||||
rawData.each(function(m) {
|
||||
if (m.get('privilege')) {
|
||||
res += self.notation[m.get('privilege_type')];
|
||||
if (m.get('with_grant')) {
|
||||
res += '*';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* PrivilegeCell for rendering and taking input for the privileges.
|
||||
*/
|
||||
var PrivilegeCell = Backgrid.Extension.PrivilegeCell = Backgrid.Cell.extend({
|
||||
className: "edit-cell",
|
||||
formatter: PrivilegeCellFormatter,
|
||||
editor: PrivilegeCellEditor
|
||||
});
|
||||
|
||||
return PrivilegeRoleModel;
|
||||
}));
|
|
@ -443,25 +443,44 @@ OWNER TO helpdesk;\n';
|
|||
if (d) {
|
||||
/* Loading all the scripts registered to be loaded on this node */
|
||||
if (obj.scripts && obj.scripts[d._type]) {
|
||||
_.each(obj.scripts[d._type], function(s) {
|
||||
if (!s.loaded) {
|
||||
require([s.name], function(m) {
|
||||
s.loaded = true;
|
||||
// Call the initialize (if present)
|
||||
if (m && m.init && typeof m.init == 'function') {
|
||||
try {
|
||||
m.init();
|
||||
} catch (err) {
|
||||
obj.report_error(
|
||||
'{{ _('Error Initializing script - ') }}' + s.path, err);
|
||||
var scripts = _.extend({}, obj.scripts[d._type]);
|
||||
|
||||
/*
|
||||
* We can remove it from the Browser.scripts object as
|
||||
* these're about to be loaded.
|
||||
*
|
||||
* This will make sure that - we do check for the script for
|
||||
* loading only once.
|
||||
*
|
||||
*/
|
||||
delete obj.scripts[d._type];
|
||||
|
||||
setTimeout(function() {
|
||||
_.each(scripts, function(s) {
|
||||
if (!s.loaded) {
|
||||
require([s.name], function(m) {
|
||||
s.loaded = true;
|
||||
// Call the initialize (if present)
|
||||
if (m && m.init && typeof m.init == 'function') {
|
||||
try {
|
||||
m.init();
|
||||
} catch (err) {
|
||||
console.log("Error running module Init script for '" + s.path + "'");
|
||||
console.log(err);
|
||||
|
||||
obj.report_error(
|
||||
'{{ _('Error Initializing script - ') }}' + s.path, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, function() {
|
||||
obj.report_error(
|
||||
'{{ _('Error loading script - ') }}' + s.path);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, function() {
|
||||
console.log("Error loading script - " + s.path);
|
||||
console.log(arguments);
|
||||
obj.report_error(
|
||||
'{{ _('Error loading script - ') }}' + s.path);
|
||||
}).bind(s);
|
||||
}
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1005,7 +1005,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
Model: Backbone.Model.extend({
|
||||
parse: function(res) {
|
||||
var self = this;
|
||||
if ('node' in res && res['node']) {
|
||||
if (res && _.isObject(res) && 'node' in res && res['node']) {
|
||||
self.tnode = _.extend({}, res.node);
|
||||
delete res.node;
|
||||
}
|
||||
|
@ -1042,24 +1042,25 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
case 'model':
|
||||
obj = self.get(s.id);
|
||||
val = res[s.id];
|
||||
if (_.isArray(val) || _.isObject(val)) {
|
||||
if (!_.isObject(obj)) {
|
||||
if (!_.isUndefined(val) && !_.isNull(val)) {
|
||||
if (!obj || !(obj instanceof Backbone.Model)) {
|
||||
if (_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes[s.model]) {
|
||||
obj = new (pgBrowser.Nodes[s.model].Model)(
|
||||
null, {handler: self.handler || self}
|
||||
obj, {silent: true, handler: self.handler || self}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(null, {handler: self.handler || self});
|
||||
obj = new (s.model)(obj, {
|
||||
silent: true, handler: self.handler || self
|
||||
});
|
||||
}
|
||||
}
|
||||
obj.set(self.get(s.id), {parse: true, silent: true});
|
||||
obj.set(val, {parse: true, silent: true});
|
||||
} else {
|
||||
if (obj)
|
||||
delete obj;
|
||||
obj = null;
|
||||
}
|
||||
self.set(s.id, obj, {silent: true});
|
||||
res[s.id] = obj;
|
||||
break;
|
||||
default:
|
||||
|
@ -1072,6 +1073,8 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
initialize: function(attributes, options) {
|
||||
var self = this;
|
||||
|
||||
Backbone.Model.prototype.initialize.apply(self, arguments);
|
||||
|
||||
if (_.isUndefined(options) || _.isNull(options)) {
|
||||
options = attributes || {};
|
||||
attributes = null;
|
||||
|
@ -1088,31 +1091,35 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
|
||||
if (self.schema && _.isArray(self.schema)) {
|
||||
_.each(self.schema, function(s) {
|
||||
var obj = null;
|
||||
var obj = self.get(s.id);
|
||||
switch(s.type) {
|
||||
case 'collection':
|
||||
if (_.isString(s.model) &&
|
||||
if (!obj || !(obj instanceof pgBrowser.Node.Collection)) {
|
||||
if (_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes) {
|
||||
var node = pgBrowser.Nodes[s.model];
|
||||
obj = new (node.Collection)(null, {
|
||||
model: node.model,
|
||||
handler: self.handler || self
|
||||
});
|
||||
} else {
|
||||
obj = new (pgBrowser.Node.Collection)(null, {
|
||||
model: s.model,
|
||||
handler: self.handler || self
|
||||
});
|
||||
var node = pgBrowser.Nodes[s.model];
|
||||
obj = new (node.Collection)(obj, {
|
||||
model: node.model,
|
||||
handler: self.handler || self
|
||||
});
|
||||
} else {
|
||||
obj = new (pgBrowser.Node.Collection)(obj, {
|
||||
model: s.model,
|
||||
handler: self.handler || self
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'model':
|
||||
if (_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes[s.model]) {
|
||||
obj = new (pgBrowser.Nodes[s.model].Model)(
|
||||
null, {handler: self.handler || self}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(null, {handler: self.handler || self});
|
||||
if (!obj || !(obj instanceof Backbone.Model)) {
|
||||
if (_.isString(s.model) &&
|
||||
s.model in pgBrowser.Nodes[s.model]) {
|
||||
obj = new (pgBrowser.Nodes[s.model].Model)(
|
||||
obj, {handler: self.handler || self}
|
||||
);
|
||||
} else {
|
||||
obj = new (s.model)(obj, {handler: self.handler || self});
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1148,8 +1155,12 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
var self = this;
|
||||
|
||||
return (_.size(self.sessAttrs) > 0 ||
|
||||
_.some(self.objects, function(o) {
|
||||
return self.get(o).sessChanged();
|
||||
_.some(self.objects, function(k) {
|
||||
var obj = self.get(k);
|
||||
if (!(_.isNull(obj) || _.isUndefined(obj))) {
|
||||
return obj.sessChanged();
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
sessValid: function() {
|
||||
|
@ -1208,11 +1219,10 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
res = _.extend(res, self.sessAttrs);
|
||||
}
|
||||
|
||||
_.each(self.objects, function(o) {
|
||||
var obj = self.get(o);
|
||||
if (session || obj)
|
||||
res[o] = (obj && obj.toJSON(session));
|
||||
});
|
||||
_.each(self.objects, function(k) {
|
||||
var obj = self.get(k);
|
||||
res[k] = (obj && obj.toJSON(session));
|
||||
});
|
||||
return res;
|
||||
},
|
||||
startNewSession: function() {
|
||||
|
@ -1229,6 +1239,10 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) {
|
|||
_.each(self.objects, function(o) {
|
||||
var obj = self.get(o);
|
||||
|
||||
if (_.isUndefined(obj) || _.isNull(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete self.origSessAttrs[o];
|
||||
|
||||
if (obj && 'startNewSession' in obj && _.isFunction(obj.startNewSession)) {
|
||||
|
|
|
@ -57,6 +57,7 @@ class PGChildModule:
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.min_ver = 1000000000
|
||||
self.max_ver = 0
|
||||
self.server_type = None
|
||||
self.attributes = {}
|
||||
|
||||
super(PGChildModule, self).__init__(*args, **kwargs)
|
||||
|
|
|
@ -492,7 +492,11 @@ fieldset[disabled] .form-control {
|
|||
}
|
||||
|
||||
.backgrid td.renderable:not(.editable):not(.delete-cell) {
|
||||
background-color: #eee;
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
.backgrid tr.header td.renderable:not(.editable):not(.delete-cell) {
|
||||
background-color: #AAA;
|
||||
}
|
||||
|
||||
.subnode-header {
|
||||
|
@ -583,3 +587,11 @@ table.backgrid tr.new {
|
|||
.switch-cell {
|
||||
height: 0px; width: 0px;
|
||||
}
|
||||
|
||||
.width_percent_40 {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.width_percent_60 {
|
||||
width: 60%;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
var pgAdmin = (window.pgAdmin = window.pgAdmin || {});
|
||||
|
||||
pgAdmin.editableCell = function() {
|
||||
if (this.attributes && this.attributes.disabled) {
|
||||
if (this.attributes && !_.isUndefined(this.attributes.disabled) &&
|
||||
!_.isNull(this.attributes.disabled)) {
|
||||
if(_.isFunction(this.attributes.disabled)) {
|
||||
return !(this.attributes.disabled.apply(this, arguments));
|
||||
}
|
||||
|
@ -503,14 +504,19 @@
|
|||
initialize: function() {
|
||||
Backform.Control.prototype.initialize.apply(this, arguments);
|
||||
|
||||
var uniqueCol = this.field.get('uniqueCol') || [];
|
||||
var uniqueCol = this.field.get('uniqueCol') || [],
|
||||
m = this.field.get('model'),
|
||||
schema = m.prototype.schema || m.__super__.schema,
|
||||
columns = [];
|
||||
|
||||
_.each(schema, function(s) {
|
||||
columns.push(s.id);
|
||||
});
|
||||
|
||||
var columns = this.field.get('columns')
|
||||
// Check if unique columns provided are also in model attributes.
|
||||
if (uniqueCol.length > _.intersection(columns, uniqueCol).length){
|
||||
errorMsg = "Developer: Unique column/s [ "+_.difference(uniqueCol, columns)+" ] not found in collection model [ " + columns +" ]."
|
||||
alert (errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
var collection = this.model.get(this.field.get('name')),
|
||||
|
@ -747,7 +753,8 @@
|
|||
var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype,
|
||||
gridSchema = Backform.generateGridColumnsFromModel(
|
||||
data.node_info, subnode, this.field.get('mode'), data.columns
|
||||
);
|
||||
), self = this,
|
||||
pgBrowser = window.pgAdmin.Browser;
|
||||
|
||||
// Set visibility of Add button
|
||||
if (data.disabled || data.canAdd == false) {
|
||||
|
@ -775,7 +782,17 @@
|
|||
});
|
||||
}
|
||||
|
||||
var collection = this.model.get(data.name);
|
||||
var collection = self.model.get(data.name);
|
||||
|
||||
if (!collection) {
|
||||
collection = new (pgBrowser.Node.Collection)(null, {
|
||||
handler: self.model.handler || self,
|
||||
model: data.model,
|
||||
silent: true
|
||||
});
|
||||
self.model.set(data.name, collection, {silent: true});
|
||||
}
|
||||
|
||||
// Initialize a new Grid instance
|
||||
var grid = new Backgrid.Grid({
|
||||
columns: gridSchema.columns,
|
||||
|
|
|
@ -119,254 +119,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
Custom cell formatter for privileges.
|
||||
*/
|
||||
var PrivilegeCellFormatter = Backgrid.Extension.PrivilegeCellFormatter = function () {};
|
||||
_.extend(PrivilegeCellFormatter.prototype, {
|
||||
|
||||
fromRaw: function (rawData, model) {
|
||||
return rawData;
|
||||
},
|
||||
|
||||
|
||||
/* Convert string privileges to object privileges for manipulation.
|
||||
|
||||
E.g C*Tc ===> {"C":{"privilege":true,
|
||||
"withGrantPrivilege":true},
|
||||
"T":{"privilege":true,
|
||||
"withGrantPrivilege":false},
|
||||
"c":{"privilege":true,
|
||||
"withGrantPrivilege":false}
|
||||
}
|
||||
*/
|
||||
|
||||
fromRawToObject: function (rawData, model) {
|
||||
var objData = {};
|
||||
var currentChar = "";
|
||||
for (var i = 0, len = rawData.length; i < len; i++) {
|
||||
if (rawData[i] == "*" && currentChar != ""){
|
||||
if ( _.has(objData,currentChar)){
|
||||
objData[currentChar]["withGrantPrivilege"] = true;
|
||||
}
|
||||
}else{
|
||||
currentChar = rawData[i]
|
||||
objData[currentChar] = {"privilege":true,
|
||||
"withGrantPrivilege":false};
|
||||
}
|
||||
}
|
||||
return objData;
|
||||
},
|
||||
|
||||
toRaw: function (formattedData, model) {
|
||||
return formattedData;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
Custom cell editor for editing privileges.
|
||||
*/
|
||||
|
||||
var PrivilegeCellEditor = Backgrid.Extension.PrivilegeCellEditor = Backgrid.CellEditor.extend({
|
||||
tagName: "div",
|
||||
template: _.template(['<tr>',
|
||||
'<td class="renderable"><label><input type="checkbox" name="<%- value %>" <%= privilege ? \'checked\' : "" %>><%- name %></label></td>',
|
||||
'<td class="renderable"><label><input type="checkbox" name="<%- value %>_grant" <%= withGrantPrivilege ? \'checked\' : "" %>>WITH GRANT OPTION</label></td>',
|
||||
'</tr>'].join(" "), null, {variable: null}),
|
||||
|
||||
initialize: function() {
|
||||
Backgrid.CellEditor.prototype.initialize.apply(this, arguments);
|
||||
this.elId = _.uniqueId('pgPriv_');
|
||||
},
|
||||
setPrivilegeOptions: function (privilegeOptions){
|
||||
this.privilegeOptions = privilegeOptions;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this.$el.attr('tabindex', '1');
|
||||
this.$el.attr('id', this.elId);
|
||||
this.$el.attr('privilegeseditor', '1');
|
||||
|
||||
var privilegeOptions = _.result(this, "privilegeOptions");
|
||||
var model = this.model;
|
||||
var selectedValues = this.formatter.fromRawToObject(model.get(this.column.get("name")), model),
|
||||
tbl = $("<table></table>").appendTo(this.$el);
|
||||
|
||||
if (!_.isArray(privilegeOptions)) throw new TypeError("privilegeOptions must be an array");
|
||||
self = this;
|
||||
// For each privilege generate html template.
|
||||
_.each(privilegeOptions, function (privilegeOption){
|
||||
var templateData = {name: privilegeOption['name'],
|
||||
value: privilegeOption['value'],
|
||||
privilege : false,
|
||||
withGrantPrivilege : false
|
||||
};
|
||||
|
||||
if ( _.has(selectedValues,privilegeOption['value'])){
|
||||
_.extend(templateData,{ privilege:selectedValues[privilegeOption['value']]["privilege"],
|
||||
withGrantPrivilege:selectedValues[privilegeOption['value']]["withGrantPrivilege"]
|
||||
});
|
||||
}
|
||||
|
||||
var editorHtml = self.template(templateData);
|
||||
tbl.append(editorHtml);
|
||||
|
||||
var $prvilegeGrantCheckbox = self.$el.find("[name='" + privilegeOption['value'] + "_grant']");
|
||||
|
||||
// Add event listeners on each privilege checkbox. And set initial state.
|
||||
// Update model if user changes value.
|
||||
$prvilegeGrantCheckbox.click(function(e) {
|
||||
var addRemoveflag = $(this).is(':checked');
|
||||
privilege = this.name;
|
||||
self.updateModel(privilege, addRemoveflag);
|
||||
});
|
||||
|
||||
var $prvilegeCheckbox = self.$el.find("[name='" + privilegeOption['value'] + "']");
|
||||
|
||||
if (!$prvilegeCheckbox.is(':checked')) {
|
||||
$prvilegeGrantCheckbox.attr("disabled", true);
|
||||
$prvilegeGrantCheckbox.attr("checked", false);
|
||||
}
|
||||
|
||||
$prvilegeCheckbox.click(function(e) {
|
||||
var addRemoveflag = $(this).is(':checked');
|
||||
privilege = this.name;
|
||||
if (addRemoveflag) {
|
||||
$prvilegeGrantCheckbox.removeAttr("disabled");
|
||||
} else {
|
||||
$prvilegeGrantCheckbox.attr("disabled", true);
|
||||
$prvilegeGrantCheckbox.attr("checked", false);
|
||||
}
|
||||
self.updateModel(privilege, addRemoveflag);
|
||||
});
|
||||
});
|
||||
|
||||
self.$el.find('input[type=checkbox]').blur(self.focusLost.bind(this)).first().focus();
|
||||
self.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
updateModel: function(privilege, addRemoveflag){
|
||||
// Update model with new privilege string. e.g. 'C*Tc'.
|
||||
var self = this,
|
||||
model = self.model,
|
||||
column = self.column,
|
||||
newVal = "",
|
||||
withGrant = false,
|
||||
privilegeConst = privilege[0];
|
||||
|
||||
if (privilege.length > 1){
|
||||
withGrant = true;
|
||||
}
|
||||
|
||||
oldValObj = self.formatter.fromRawToObject(model.get(self.column.get("name")), model);
|
||||
|
||||
if (addRemoveflag){
|
||||
if (!withGrant){
|
||||
oldValObj[privilegeConst] = {"privilege": true,
|
||||
"withGrantPrivilege":false};
|
||||
}else{
|
||||
oldValObj[privilegeConst] = {"privilege": true,
|
||||
"withGrantPrivilege":true}
|
||||
}
|
||||
}else{
|
||||
if (!withGrant){
|
||||
oldValObj[privilegeConst] = {"privilege": false,
|
||||
"withGrantPrivilege":false};
|
||||
}else{
|
||||
oldValObj[privilegeConst] = {"privilege": true,
|
||||
"withGrantPrivilege":false};
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0, len = model.privileges.length; i < len; i++) {
|
||||
if ( _.has(oldValObj, model.privileges[i])){
|
||||
if(oldValObj[model.privileges[i]]["privilege"]){
|
||||
newVal = newVal + model.privileges[i]
|
||||
}
|
||||
if(oldValObj[model.privileges[i]]["withGrantPrivilege"]){
|
||||
newVal = newVal + "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
model.set(column.get("name"), newVal);
|
||||
},
|
||||
focusLost :function(e) {
|
||||
setTimeout(
|
||||
function() {
|
||||
var lostFocus = true;
|
||||
if (document.activeElement) {
|
||||
lostFocus = !(
|
||||
$(document.activeElement).closest(
|
||||
'div[privilegeseditor=1]'
|
||||
).first().attr('id') == this.$el.attr('id')
|
||||
);
|
||||
}
|
||||
if (lostFocus) {
|
||||
this.model.trigger("backgrid:edited", this.model, this.column, new Backgrid.Command(e));
|
||||
}
|
||||
}.bind(this), 200);
|
||||
}
|
||||
});
|
||||
|
||||
var PrivilegeCell = Backgrid.Extension.PrivilegeCell = Backgrid.Cell.extend({
|
||||
className: "edit-cell",
|
||||
// All available privileges.
|
||||
privilegeLabels: { "C": "CREATE",
|
||||
"T": "TEMP",
|
||||
"c": "CONNECT",
|
||||
"a": "INSERT",
|
||||
"r": "SELECT",
|
||||
"w": "UPDATE",
|
||||
"d": "DELETE",
|
||||
"D": "TRUNCATE",
|
||||
"x": "REFERENCES",
|
||||
"t": "TRIGGER",
|
||||
"U": "USAGE",
|
||||
"X": "EXECUTE"
|
||||
},
|
||||
|
||||
formatter: PrivilegeCellFormatter,
|
||||
|
||||
editor: PrivilegeCellEditor,
|
||||
|
||||
initialize: function(options) {
|
||||
Backgrid.Cell.prototype.initialize.apply(this, arguments);
|
||||
|
||||
var privilegeOptions = [];
|
||||
var privileges = this.model.privileges || [];
|
||||
self = this;
|
||||
// Generate array of privileges to be shown in editor.
|
||||
_.each(privileges, function(privilege){
|
||||
privilegeOptions.push({name:self.privilegeLabels[privilege],
|
||||
value:privilege})
|
||||
})
|
||||
|
||||
this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
|
||||
if (column.get("name") == this.column.get("name"))
|
||||
// Set available privilege options in editor.
|
||||
editor.setPrivilegeOptions(privilegeOptions);
|
||||
});
|
||||
},
|
||||
|
||||
render: function(){
|
||||
this.$el.empty();
|
||||
var model = this.model;
|
||||
this.$el.text(this.formatter.fromRaw(model.get(this.column.get("name")), model));
|
||||
this.delegateEvents();
|
||||
if (this.grabFocus)
|
||||
this.$el.focus();
|
||||
return this;
|
||||
},
|
||||
|
||||
exitEditMode: function() {
|
||||
Backgrid.Cell.prototype.exitEditMode.apply(this, arguments);
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
|
||||
var ObjectCell = Backgrid.Extension.ObjectCell = Backgrid.Cell.extend({
|
||||
editorOptionDefaults: {
|
||||
schema: []
|
||||
|
|
Loading…
Reference in New Issue