Port RLS node to react. Fixes #6660

This commit is contained in:
Nikhil Mohite 2021-08-05 11:14:49 +05:30 committed by Akshay Joshi
parent 977d148c40
commit 40879a5784
3 changed files with 251 additions and 87 deletions

View File

@ -6,6 +6,9 @@
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import RowSecurityPolicySchema from './row_security_policy.ui';
import { getNodeListByName } from '../../../../../../../../static/js/node_ajax';
define('pgadmin.node.row_security_policy', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
@ -74,17 +77,21 @@ define('pgadmin.node.row_security_policy', [
},
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
getSchema: function(treeNodeInfo, itemNodeData) {
return new RowSecurityPolicySchema(
{
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData, {}, ()=>true, (res)=>{
res.unshift({label: 'PUBLIC', value: 'public'});
return res;
}),
nodeInfo: treeNodeInfo
}
);
},
model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: {
name: undefined,
policyowner: 'public',
event: 'ALL',
using: undefined,
using_orig: undefined,
withcheck: undefined,
withcheck_orig: undefined,
type:'PERMISSIVE',
},
schema: [{
id: 'name', label: gettext('Name'), cell: 'string',
@ -92,86 +99,7 @@ define('pgadmin.node.row_security_policy', [
},{
id: 'oid', label: gettext('OID'), cell: 'string',
editable: false, type: 'text', mode: ['properties'],
},
{
id: 'event', label: gettext('Event'), control: 'select2', deps:['event'],
group: gettext('Commands'), type: 'text',readonly: function(m) {
return !m.isNew();},
select2: {
width: '100%',
allowClear: false,
},
options:[
{label: 'ALL', value: 'ALL'},
{label: 'SELECT', value: 'SELECT'},
{label: 'INSERT', value: 'INSERT'},
{label: 'UPDATE', value: 'UPDATE'},
{label: 'DELETE', value: 'DELETE'},
],
},
{
id: 'using', label: gettext('Using'), deps: ['using', 'event'],
type: 'text', disabled: 'disableUsing',
mode: ['create', 'edit', 'properties'],
control: 'sql-field', visible: true, group: gettext('Commands'),
},
{
id: 'withcheck', label: gettext('With check'), deps: ['withcheck', 'event'],
type: 'text', mode: ['create', 'edit', 'properties'],
control: 'sql-field', visible: true, group: gettext('Commands'),
disabled: 'disableWithCheck',
},
{
id: 'rls_expression_key_note', label: gettext('RLS policy expression'),
type: 'note', group: gettext('Commands'), mode: ['create', 'edit'],
text: [
'<ul><li>',
'<strong>', gettext('Using: '), '</strong>',
gettext('This expression will be added to queries that refer to the table if row level security is enabled. Rows for which the expression returns true will be visible. Any rows for which the expression returns false or null will not be visible to the user (in a SELECT), and will not be available for modification (in an UPDATE or DELETE). Such rows are silently suppressed; no error is reported.'),
'</li><li>',
'<strong>', gettext('With check: '), '</strong>',
gettext('This expression will be used in INSERT and UPDATE queries against the table if row level security is enabled. Only rows for which the expression evaluates to true will be allowed. An error will be thrown if the expression evaluates to false or null for any of the records inserted or any of the records that result from the update.'),
'</li></ul>',
].join(''),
},
{
id: 'policyowner', label: gettext('Role'), cell: 'string',
control: 'node-list-by-name',
node: 'role', select2: { allowClear: false },
mode: ['properties', 'edit','create'],
transform: function() {
var res =
Backform.NodeListByNameControl.prototype.defaults.transform.apply(
this, arguments
);
res.unshift({
label: 'public', value: 'public',
});
return res;
},
},
{
id: 'type', label: gettext('Type'), control: 'select2', deps:['type'],
type: 'text',readonly: function(m) {
return !m.isNew();},
select2: {
width: '100%',
allowClear: false,
},
options:[
{label: 'PERMISSIVE', value: 'PERMISSIVE'},
{label: 'RESTRICTIVE', value: 'RESTRICTIVE'},
],
visible: function(m) {
if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
&& !_.isUndefined(m.node_info.server.version) &&
m.node_info.server.version >= 100000)
return true;
return false;
},
},
],
}],
validate: function(keys) {
var msg;
this.errorModel.clear();

View File

@ -0,0 +1,137 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import gettext from 'sources/gettext';
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
export default class RowSecurityPolicySchema extends BaseUISchema {
constructor(fieldOptions={}, initValues) {
super({
name: undefined,
policyowner: 'public',
event: 'ALL',
using: undefined,
using_orig: undefined,
withcheck: undefined,
withcheck_orig: undefined,
type:'PERMISSIVE',
...initValues
});
this.fieldOptions = {
role: [],
function_names: [],
...fieldOptions,
};
this.nodeInfo = this.fieldOptions.nodeInfo;
}
get idAttribute() {
return 'oid';
}
disableUsingField(state){
if (state.event == 'INSERT'){
return true;
}
return false;
}
disableWithCheckField(state){
var event = state.event;
if ((event == 'SELECT') || (event == 'DELETE')){
state.withcheck = '';
return true;
}
return false;
}
get baseFields() {
let obj = this;
return [
{
id: 'name', label: gettext('Name'), cell: 'text',
editable: true, type: 'text', readonly: false,
noEmpty: true
},{
id: 'oid', label: gettext('OID'), cell: 'string',
editable: false, type: 'text', mode: ['properties'],
},
{
id: 'event', label: gettext('Event'), type: 'select',
group: gettext('Commands'),disabled: () => {
if(obj.isNew()) {
return false;
}
return true;
},
controlProps: { allowClear: false },
options:[
{label: 'ALL', value: 'ALL'},
{label: 'SELECT', value: 'SELECT'},
{label: 'INSERT', value: 'INSERT'},
{label: 'UPDATE', value: 'UPDATE'},
{label: 'DELETE', value: 'DELETE'},
],
},
{
id: 'using', label: gettext('Using'), deps: ['using', 'event'],
type: 'text', disabled: obj.disableUsingField,
mode: ['create', 'edit', 'properties'],
control: 'sql', visible: true, group: gettext('Commands'),
},
{
id: 'withcheck', label: gettext('With check'), deps: ['withcheck', 'event'],
type: 'text', mode: ['create', 'edit', 'properties'],
control: 'sql', visible: true, group: gettext('Commands'),
disabled: obj.disableWithCheckField,
},
{
id: 'rls_expression_key_note', label: gettext('RLS policy expression'),
type: 'note', group: gettext('Commands'), mode: ['create', 'edit'],
text: [
'<ul><li>',
'<strong>', gettext('Using: '), '</strong>',
gettext('This expression will be added to queries that refer to the table if row level security is enabled. Rows for which the expression returns true will be visible. Any rows for which the expression returns false or null will not be visible to the user (in a SELECT), and will not be available for modification (in an UPDATE or DELETE). Such rows are silently suppressed; no error is reported.'),
'</li><li>',
'<strong>', gettext('With check: '), '</strong>',
gettext('This expression will be used in INSERT and UPDATE queries against the table if row level security is enabled. Only rows for which the expression evaluates to true will be allowed. An error will be thrown if the expression evaluates to false or null for any of the records inserted or any of the records that result from the update.'),
'</li></ul>',
].join(''),
},
{
id: 'policyowner', label: gettext('Role'), cell: 'text',
type: 'select',
options: obj.fieldOptions.role,
controlProps: { allowClear: false }
},
{
id: 'type', label: gettext('Type'), type: 'select', deps:['type'],
disabled: () => {return !obj.isNew();},
controlProps: {
width: '100%',
allowClear: false,
},
options:[
{label: 'PERMISSIVE', value: 'PERMISSIVE'},
{label: 'RESTRICTIVE', value: 'RESTRICTIVE'},
],
visible: () => {
if(obj.nodeInfo.server.version >= 100000)
return true;
return false;
},
},
];
}
}

View File

@ -0,0 +1,99 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import jasmineEnzyme from 'jasmine-enzyme';
import React from 'react';
import '../helper/enzyme.helper';
import { createMount } from '@material-ui/core/test-utils';
import pgAdmin from 'sources/pgadmin';
import {messages} from '../fake_messages';
import SchemaView from '../../../pgadmin/static/js/SchemaView';
//import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import RowSecurityPolicySchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/tables/row_security_policies/static/js/row_security_policy.ui';
describe('RowSecurityPolicySchema', ()=>{
let mount;
let schemaObj = new RowSecurityPolicySchema(
{
role: ()=>[],
nodeInfo: {server: {version: 90400}},
}
);
let getInitData = ()=>Promise.resolve({});
/* Use createMount so that material ui components gets the required context */
/* https://material-ui.com/guides/testing/#api */
beforeAll(()=>{
mount = createMount();
});
afterAll(() => {
mount.cleanUp();
});
beforeEach(()=>{
jasmineEnzyme();
/* messages used by validators */
pgAdmin.Browser = pgAdmin.Browser || {};
pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
});
it('create', ()=>{
mount(<SchemaView
formType='dialog'
schema={schemaObj}
viewHelperProps={{
mode: 'create',
}}
onSave={()=>{}}
onClose={()=>{}}
onHelp={()=>{}}
onEdit={()=>{}}
onDataChange={()=>{}}
confirmOnCloseReset={false}
hasSQL={false}
disableSqlHelp={false}
/>);
});
it('edit', ()=>{
mount(<SchemaView
formType='dialog'
schema={schemaObj}
getInitData={getInitData}
viewHelperProps={{
mode: 'edit',
}}
onSave={()=>{}}
onClose={()=>{}}
onHelp={()=>{}}
onEdit={()=>{}}
onDataChange={()=>{}}
confirmOnCloseReset={false}
hasSQL={false}
disableSqlHelp={false}
/>);
});
it('properties', ()=>{
mount(<SchemaView
formType='tab'
schema={schemaObj}
getInitData={getInitData}
viewHelperProps={{
mode: 'properties',
}}
onHelp={()=>{}}
onEdit={()=>{}}
/>);
});
});