Port Role node to react. Fixes #6651

This commit is contained in:
Nikhil Mohite 2021-08-10 12:43:51 +05:30 committed by Akshay Joshi
parent 0ddd053e88
commit f742c5eb8a
6 changed files with 530 additions and 100 deletions

View File

@ -108,21 +108,6 @@ export default class MViewSchema extends BaseUISchema {
type: 'nested-tab', group: gettext('Parameter'), mode: ['create', 'edit'],
schema: this.getVacuumSettingsSchema(),
},
/*{
type: 'nested', control: 'tab', id: 'materialization',
label: gettext('Parameter'), mode: ['edit', 'create'],
group: gettext('Parameter'),
schema: Backform.VacuumSettingsSchema,
},
{
// Add Privilege Control
id: 'datacl', label: gettext('Privileges'), type: 'collection',
model: pgBrowser.Node.PrivilegeRoleModel.extend({
privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't'],
}), uniqueCol : ['grantee'], editable: false,
group: 'security', canAdd: true, canDelete: true,
mode: ['edit', 'create'], control: 'unique-col-collection',
},*/
{
id: 'datacl', label: gettext('Privileges'), type: 'collection',
schema: this.getPrivilegeRoleSchema(['U']),

View File

@ -6,6 +6,10 @@
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import RoleSchema from './role.ui';
import { getNodeVariableSchema } from '../../../static/js/variable.ui';
import { getNodeListByName } from '../../../../../static/js/node_ajax';
import { getMembershipSchema } from '../../../static/js/membership.ui';
define('pgadmin.node.role', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
@ -833,13 +837,22 @@ define('pgadmin.node.role', [
gettext('Reassign/Drop Owned - \'%s\'', _d.label)
).resizeTo(pgAdmin.Browser.stdW.md, pgAdmin.Browser.stdH.lg);
},
getSchema: function(treeNodeInfo, itemNodeData) {
return new RoleSchema(
()=>getNodeVariableSchema(this, treeNodeInfo, itemNodeData, true, false),
()=>getMembershipSchema(this, treeNodeInfo, itemNodeData),
{
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData),
nodeInfo: treeNodeInfo
},
);
},
model: pgAdmin.Browser.Node.Model.extend({
idAttribute: 'oid',
defaults: {
oid: null,
rolname: undefined,
rolcanlogin: false,
rolpassword: null,
rolconnlimit: -1,
rolsuper: false,
rolcreaterole: false,
@ -847,11 +860,7 @@ define('pgadmin.node.role', [
rolinherit: true,
rolcatupdate: false,
rolreplication: false,
rolmembership: [],
rolmembers: [],
rolvaliduntil: null,
seclabels: [],
variables: [],
},
schema: [{
id: 'rolname', label: gettext('Name'), type: 'text',
@ -859,19 +868,6 @@ define('pgadmin.node.role', [
},{
id: 'oid', label: gettext('OID'), cell: 'string', mode: ['properties'],
editable: false, type: 'text', visible: true,
},{
id: 'rolpassword', label: gettext('Password'), type: 'password',
group: gettext('Definition'), mode: ['edit', 'create'],
control: 'input', deps: ['rolcanlogin'], retype: true,
cell: 'string', disabled: function(m) {
if (!m.isNew()) {
var user = this.node_info.server.user;
return (!(user.is_superuser || user.can_create_role) &&
user.id != m.get('oid'));
}
return false;
},
},{
id: 'rolvaliduntil', readonly: 'readonly', type: 'text',
group: gettext('Definition'), label: gettext('Account expires'),
@ -955,73 +951,6 @@ define('pgadmin.node.role', [
controlsClassName: 'pgadmin-controls pg-el-sm-8 pg-el-12',
min_version: 90100,
readonly: 'readonly',
},
{
id: 'rolmembership', label: gettext('Member of'),
group: gettext('Membership'), type: 'collection',
cell: 'string', mode: ['properties', 'edit', 'create'],
readonly: 'readonly',
control: RoleMembersControl, model: pgBrowser.Node.Model.extend({
keys: ['role'],
idAttribute: 'role',
defaults: {
role: undefined,
admin: false,
},
validate: function() {
return null;
},
}),
filter: function(d) {
return this.model.isNew() || (this.model.get('rolname') != d.label);
},
helpMessage: function(m) {
if (m.has('read_only') && m.get('read_only') == false) {
return gettext('Select the checkbox for roles to include WITH ADMIN OPTION.');
} else {
return gettext('Roles shown with a check mark have the WITH ADMIN OPTION set.');
}
},
},
{
id: 'rolmembers', label: gettext('Members'), type: 'collection', group: gettext('Membership'),
mode: ['properties', 'edit', 'create'], cell: 'string',
readonly: 'readonly',
control: RoleMembersControl, model: pgBrowser.Node.Model.extend({
keys: ['role'],
idAttribute: 'role',
defaults: {
role: undefined,
admin: false,
},
validate: function() {
return null;
},
}),
filter: function(d) {
return this.model.isNew() || (this.model.get('rolname') != d.label);
},
helpMessage: function(m) {
if (m.has('read_only') && m.get('read_only') == false) {
return gettext('Select the checkbox for roles to include WITH ADMIN OPTION.');
} else {
return gettext('Roles shown with a check mark have the WITH ADMIN OPTION set.');
}
},
},
{
id: 'variables', label: '', type: 'collection',
group: gettext('Parameters'), hasDatabase: true, url: 'variables',
model: pgBrowser.Node.VariableModel.extend({keys:['name', 'database']}),
control: 'variable-collection',
mode: [ 'edit', 'create'], canAdd: true, canDelete: true,
readonly: 'readonly',
},{
id: 'seclabels', label: gettext('Security labels'),
model: SecurityModel, editable: false, type: 'collection',
group: gettext('Security'), mode: ['edit', 'create'],
min_version: 90200, readonly: 'readonly', canAdd: true,
canEdit: false, canDelete: true, control: 'unique-col-collection',
}],
readonly: function(m) {
if (!m.has('read_only')) {

View File

@ -0,0 +1,231 @@
/////////////////////////////////////////////////////////////
//
// 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';
import SecLabelSchema from '../../../static/js/sec_label.ui';
export default class RoleSchema extends BaseUISchema {
constructor(getVariableSchema, getMembershipSchema,fieldOptions={}) {
super({
oid: null,
rolname: null,
rolcanlogin: false,
rolpassword: null,
rolconnlimit: -1,
rolsuper: false,
rolcreaterole: false,
rolcreatedb: false,
rolinherit: true,
rolcatupdate: false,
rolreplication: false,
rolmembership: [],
rolmembers: [],
rolvaliduntil: null,
seclabels: [],
variables: [],
});
this.getVariableSchema = getVariableSchema;
this.getMembershipSchema = getMembershipSchema;
this.fieldOptions = {
role: [],
...fieldOptions,
};
this.isReadOnly = null;
this.nodeInfo = this.fieldOptions.nodeInfo;
this.user = this.nodeInfo.server.user;
}
get idAttribute() {
return 'oid';
}
readOnly(state) {
var user = this.nodeInfo.server.user;
this.oid = state.oid;
this.isReadOnly = !(user.is_superuser || user.can_create_role);
return (!(user.is_superuser || user.can_create_role) && user.id != state.oid);
}
memberDataFormatter(rawData) {
var members = '';
if(_.isObject(rawData)) {
var withAdmin = '';
rawData.forEach(member => {
if(member.admin) { withAdmin = ' [WITH ADMIN]';}
if (members.length > 0) { members += ', '; }
members = members + (member.role + withAdmin);
});
}
return members;
}
get baseFields() {
let obj = this;
return [
{
id: 'rolname', label: gettext('Name'), type: 'text', noEmpty: true,
disabled: obj.readOnly,
},{
id: 'oid', label: gettext('OID'), cell: 'string', mode: ['properties'],
editable: false, type: 'text', visible: true,
},
{
id: 'is_sys_obj', label: gettext('System role?'),
cell:'boolean', type: 'switch', mode: ['properties'],
},
{
id: 'description', label: gettext('Comments'), type: 'multiline',
mode: ['properties', 'edit', 'create'],
disabled: obj.readOnly,
},
{
id: 'rolpassword', label: gettext('Password'), type: 'password',
group: gettext('Definition'), mode: ['edit', 'create'],
control: 'input', deps: ['rolcanlogin'], retype: true,
cell: 'text', disabled: obj.readOnly,
},
{
id: 'rolvaliduntil', type: 'datetimepicker',
group: gettext('Definition'), label: gettext('Account expires'),
mode: ['properties', 'edit', 'create'],
deps: ['rolcanlogin'],
helpMessage: gettext('Please note that if you leave this field blank, then password will never expire.'),
controlProps: { format: 'YYYY-MM-DD HH:mm:ss Z', ampm: false,
placeholder: gettext('No Expiry'), autoOk: true,
},
disabled: obj.readOnly,
},
{
id: 'rolconnlimit', type: 'int', group: gettext('Definition'),
label: gettext('Connection limit'), cell: 'integer', min : -1,
mode: ['properties', 'edit', 'create'],
disabled: obj.readOnly,
},
{
id: 'rolcanlogin', label: gettext('Can login?'),
type: 'switch',
controlLabelClassName: 'control-label pg-el-sm-4 pg-el-12',
controlsClassName: 'pgadmin-controls pg-el-sm-8 pg-el-12',
group: gettext('Privileges'),
disabled: obj.readOnly,
},
{
id: 'rolsuper', label: gettext('Superuser?'),
type: 'switch',
group: gettext('Privileges'),
depChange: (state) => {
state.rolcatupdate = state.rolcreaterole = state.rolcreatedb = state.rolsuper;
},
disabled: obj.readOnly,
},
{
id: 'rolcreaterole', label: gettext('Create roles?'),
group: gettext('Privileges'),
type: 'switch',
controlLabelClassName: 'control-label pg-el-sm-4 pg-el-12',
controlsClassName: 'pgadmin-controls pg-el-sm-8 pg-el-12',
disabled: obj.readOnly,
},
{
id: 'rolcreatedb', label: gettext('Create databases?'),
group: gettext('Privileges'),
type: 'switch',
disabled: obj.readOnly,
},
{
id: 'rolcatupdate', label: gettext('Update catalog?'),
max_version: 90400,
group: gettext('Privileges'),
type: 'switch',
disabled: (state) => {
return !state.rolsuper;
},
readonly: () => {
return !(obj.user.is_superuser || obj.user.can_create_role);
}
},
{
id: 'rolinherit', group: gettext('Privileges'),
label: gettext('Inherit rights from the parent roles?'),
type: 'switch',
controlLabelClassName: 'control-label pg-el-sm-4 pg-el-12',
controlsClassName: 'pgadmin-controls pg-el-sm-8 pg-el-12',
disabled: obj.readOnly,
},
{
id: 'rolreplication', group: gettext('Privileges'),
label: gettext('Can initiate streaming replication and backups?'),
type: 'switch',
controlLabelClassName: 'control-label pg-el-sm-4 pg-el-12',
controlsClassName: 'pgadmin-controls pg-el-sm-8 pg-el-12',
min_version: 90100,
disabled: obj.readOnly,
},
{
id: 'rolmembership', label: gettext('Member of'), group: gettext('Membership'),
disabled: obj.readOnly,
mode: ['edit', 'create'], cell: 'text',
type: 'collection',
schema: new obj.getMembershipSchema(),
helpMessage: obj.isReadOnly ? gettext('Select the checkbox for roles to include WITH ADMIN OPTION.') : gettext('Roles shown with a check mark have the WITH ADMIN OPTION set.'),
},
{
id: 'rolmembership', label: gettext('Member of'), group: gettext('Membership'),
disabled: obj.readOnly,
mode: ['properties'], cell: 'text',
type: 'text',
controlProps: {
formatter: {
fromRaw: obj.memberDataFormatter,
},
}
},
{
id: 'rolmembers', label: gettext('Members'), group: gettext('Membership'),
mode: ['edit', 'create'], cell: 'text',
type: 'collection',
schema: new obj.getMembershipSchema(),
disabled: obj.readOnly,
helpMessage: obj.isReadOnly ? gettext('Select the checkbox for roles to include WITH ADMIN OPTION.') : gettext('Roles shown with a check mark have the WITH ADMIN OPTION set.') ,
},
{
id: 'rolmembers', label: gettext('Members'), group: gettext('Membership'),
disabled: obj.readOnly,
mode: ['properties'], cell: 'text',
type: 'text',
controlProps: {
formatter: {
fromRaw: obj.memberDataFormatter,
},
}
},
{
id: 'variables', label: '', type: 'collection',
group: gettext('Parameters'),
schema: this.getVariableSchema(),
mode: [ 'edit', 'create'], canAdd: true, canDelete: true,
disabled: obj.readOnly,
},
{
id: 'seclabels', label: gettext('Security labels'), type: 'collection',
schema: new SecLabelSchema(),
editable: false, group: gettext('Security'),
mode: ['edit', 'create'],
canAdd: true, canEdit: false, canDelete: true,
uniqueCol : ['provider'],
min_version: 90200,
disabled: obj.readOnly,
}
];
}
}

View File

@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////
//
// 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';
import { getNodeListByName } from '../../../../static/js/node_ajax';
export function getMembershipSchema(nodeObj, treeNodeInfo, itemNodeData) {
return new MembershipSchema(
()=>getNodeListByName('role', treeNodeInfo, itemNodeData, {}, ()=>true),
);
}
export default class MembershipSchema extends BaseUISchema {
constructor(roleMembersOptions) {
super({
role: undefined,
admin: undefined
});
this.roleMembersOptions = roleMembersOptions;
}
get baseFields() {
return [{
id: 'role', label: gettext('User/Role'), type:'text',
editable: true,
cell: ()=>({
cell: 'select', options: this.roleMembersOptions,
controlProps: {
allowClear: false,
}
}),
noEmpty: true,
minWidth: 300
},
{
id: 'admin', label: gettext('WITH ADMIN'),
cell: 'checkbox', type: 'checkbox',
minWidth: 300,
deps: ['role'],
depChange: (state) => {
if(_.isUndefined(state.admin)) {
state.admin = false;
}
}
},
];
}
}

View File

@ -0,0 +1,119 @@
/////////////////////////////////////////////////////////////
//
// 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 MembershipSchema, {getMembershipSchema} from '../../../pgadmin/browser/server_groups/servers/static/js/membership.ui';
import * as nodeAjax from '../../../pgadmin/browser/static/js/node_ajax';
describe('PrivilegeSchema', ()=>{
let mount;
let schemaObj = new MembershipSchema(
()=>[]);
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 || {};
pgAdmin.Browser.utils.support_ssh_tunnel = true;
});
it('create', ()=>{
mount(<SchemaView
formType='dialog'
schema={schemaObj}
viewHelperProps={{
mode: 'create',
}}
onSave={()=>{}}
onClose={()=>{}}
onHelp={()=>{}}
onEdit={()=>{}}
onDataChange={()=>{}}
confirmOnCloseReset={false}
hasSQL={false}
disableSqlHelp={false}
disableDialogHelp={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}
disableDialogHelp={false}
/>);
});
it('properties', ()=>{
mount(<SchemaView
formType='tab'
schema={schemaObj}
getInitData={getInitData}
viewHelperProps={{
mode: 'properties',
}}
onHelp={()=>{}}
onEdit={()=>{}}
/>);
});
it('MembershipMemberSchema', ()=>{
spyOn(nodeAjax, 'getNodeListByName').and.returnValue([]);
let memberObj = new getMembershipSchema({}, {server: {user: {name: 'postgres'}}}, {});
let ctrl = mount(<SchemaView
formType='dialog'
schema={memberObj}
viewHelperProps={{
mode: 'create',
}}
onSave={()=>{}}
onClose={()=>{}}
onHelp={()=>{}}
onEdit={()=>{}}
onDataChange={()=>{}}
confirmOnCloseReset={false}
hasSQL={false}
disableSqlHelp={false}
disableDialogHelp={false}
/>);
/* Make sure you hit every corner */
ctrl.find('DataGridView').at(0).find('PgIconButton[data-test="add-row"]').find('button').simulate('click');
});
});

View File

@ -0,0 +1,107 @@
/////////////////////////////////////////////////////////////
//
// 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 RoleSchema from '../../../pgadmin/browser/server_groups/servers/roles/static/js/role.ui';
class MockSchema extends BaseUISchema {
get baseFields() {
return [];
}
}
describe('RoleSchema', ()=>{
let mount;
let schemaObj = new RoleSchema(
()=>new MockSchema(),
()=>new MockSchema(),
{
role: ()=>[],
nodeInfo: {server: {user: {name:'postgres', id:0}}}
},
);
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={()=>{}}
/>);
});
});