2021-09-20 13:02:41 +05:30
/////////////////////////////////////////////////////////////
//
// 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 _ from 'lodash' ;
import url_for from 'sources/url_for' ;
import React from 'react' ;
import { Box } from '@material-ui/core' ;
import { makeStyles } from '@material-ui/core/styles' ;
2021-09-23 14:40:38 +05:30
import Wizard from '../helpers/wizard/Wizard' ;
import WizardStep from '../helpers/wizard/WizardStep' ;
import PgTable from 'sources/components/PgTable' ;
import { getNodePrivilegeRoleSchema } from '../../../browser/server_groups/servers/static/js/privilege.ui.js' ;
import { InputSQL , InputText , FormFooterMessage , MESSAGE_TYPE } from './FormComponents' ;
import getApiInstance from '../api_instance' ;
import SchemaView from '../SchemaView' ;
2021-09-20 13:02:41 +05:30
import clsx from 'clsx' ;
import Loader from 'sources/components/Loader' ;
import Alertify from 'pgadmin.alertifyjs' ;
import PropTypes from 'prop-types' ;
2021-09-23 14:40:38 +05:30
import PrivilegeSchema from '../../../tools/grant_wizard/static/js/privilege_schema.ui' ;
2021-09-20 13:02:41 +05:30
const useStyles = makeStyles (() =>
({
grantWizardStep : {
height : '100%'
},
grantWizardTitle : {
top : '0 !important' ,
opacity : '1 !important' ,
borderRadius : '6px 6px 0px 0px !important' ,
margin : '0 !important' ,
width : '100%' ,
height : '6%'
},
grantWizardContent : {
height : '94% !important'
},
stepPanelCss : {
height : 500 ,
overflow : 'hidden'
},
objectSelection : {
display : 'flex' ,
flexDirection : 'column' ,
height : '100%' ,
overflow : 'hidden' ,
marginBottom : '1em'
},
searchBox : {
marginBottom : '1em' ,
display : 'flex' ,
},
searchPadding : {
flex : 2.5
},
searchInput : {
flex : 1 ,
marginTop : 2 ,
borderLeft : 'none' ,
paddingLeft : 5
},
grantWizardPanelContent : {
paddingTop : '0.9em !important' ,
overflow : 'hidden'
},
grantWizardSql : {
height : '90% !important' ,
width : '100%'
},
privilegeStep : {
height : '100%' ,
}
}),
);
export default function GrantWizard ({ sid , did , nodeInfo , nodeData }) {
const classes = useStyles ();
var columns = [
{
Header : 'Object Type' ,
accessor : 'object_type' ,
sortble : true ,
resizable : false ,
disableGlobalFilter : true
},
{
Header : 'Schema' ,
accessor : 'nspname' ,
sortble : true ,
resizable : false ,
disableGlobalFilter : true
},
{
Header : 'Name' ,
2021-09-30 10:56:51 +05:30
accessor : 'name_with_args' ,
2021-09-20 13:02:41 +05:30
sortble : true ,
resizable : true ,
disableGlobalFilter : false ,
minWidth : 280
2021-09-30 10:56:51 +05:30
},
{
Header : 'parameters' ,
accessor : 'proargs' ,
sortble : false ,
resizable : false ,
disableGlobalFilter : false ,
minWidth : 280 ,
isVisible : false
},
{
Header : 'Name' ,
accessor : 'name' ,
sortble : false ,
resizable : false ,
disableGlobalFilter : false ,
minWidth : 280 ,
isVisible : false
},
{
Header : 'ID' ,
accessor : 'oid' ,
sortble : false ,
resizable : false ,
disableGlobalFilter : false ,
minWidth : 280 ,
isVisible : false
2021-09-20 13:02:41 +05:30
}
];
var steps = [ 'Object Selection' , 'Privilege Selection' , 'Review Selection' ];
const [ selectedObject , setSelectedObject ] = React . useState ([]);
const [ selectedAcl , setSelectedAcl ] = React . useState ({});
const [ msqlData , setSQL ] = React . useState ( '' );
const [ stepType , setStepType ] = React . useState ( '' );
const [ searchVal , setSearchVal ] = React . useState ( '' );
const [ loaderText , setLoaderText ] = React . useState ( '' );
const [ tablebData , setTableData ] = React . useState ([]);
const [ privOptions , setPrivOptions ] = React . useState ({});
const [ privileges , setPrivileges ] = React . useState ([]);
const [ privSchemaInstance , setPrivSchemaInstance ] = React . useState ();
const [ errMsg , setErrMsg ] = React . useState ( '' );
const api = getApiInstance ();
const validatePrivilege = () => {
var isValid = true ;
selectedAcl . privilege . forEach (( priv ) => {
if (( _ . isUndefined ( priv . grantee ) || _ . isUndefined ( priv . privileges ) || priv . privileges . length === 0 ) && isValid ) {
isValid = false ;
}
});
return ! isValid ;
};
React . useEffect (() => {
privSchemaInstance ? . privilegeRoleSchema . updateSupportedPrivs ( privileges );
}, [ privileges ]);
React . useEffect (() => {
const privSchema = new PrivilegeSchema (( privileges ) => getNodePrivilegeRoleSchema ( '' , nodeInfo , nodeData , privileges ));
setPrivSchemaInstance ( privSchema );
setLoaderText ( 'Loading...' );
api . get ( url_for (
'grant_wizard.acl' , {
'sid' : encodeURI ( sid ),
'did' : encodeURI ( did ),
}
)). then ( res => {
setPrivOptions ( res . data );
});
var node_type = nodeData . _type . replace ( 'coll-' , '' ). replace (
'materialized_' , ''
);
var _url = url_for (
'grant_wizard.objects' , {
'sid' : encodeURI ( sid ),
'did' : encodeURI ( did ),
'node_id' : encodeURI ( nodeData . _id ),
'node_type' : encodeURI ( node_type ),
});
api . get ( _url )
. then ( res => {
var data = res . data . result ;
data . forEach ( element => {
if ( element . icon )
element [ 'icon' ] = {
'object_type' : element . icon
};
2021-09-30 10:56:51 +05:30
if ( element . object_type === 'Function' ) {
element . name_with_args = element . name + '(' + ( typeof ( element . proargs ) != 'undefined' ? element . proargs : '' ) + ')' ;
} else {
element . name_with_args = element . name ;
}
2021-09-20 13:02:41 +05:30
});
setTableData ( data );
setLoaderText ( '' );
})
. catch (() => {
Alertify . error ( gettext ( 'Error while fetching grant wizard data.' ));
setLoaderText ( '' );
});
}, [ nodeData ]);
const wizardStepChange = ( data ) => {
switch ( data . currentStep ) {
case 0 :
setStepType ( 'object_type' );
break ;
case 1 :
setStepType ( 'privileges' );
break ;
case 2 :
setLoaderText ( 'Loading SQL ...' );
var msql_url = url_for (
'grant_wizard.modified_sql' , {
'sid' : encodeURI ( sid ),
'did' : encodeURI ( did ),
});
var post_data = {
acl : selectedAcl . privilege ,
objects : selectedObject
};
api . post ( msql_url , post_data )
. then ( res => {
setSQL ( res . data . data );
setLoaderText ( '' );
})
. catch (() => {
Alertify . error ( gettext ( 'Error while fetching SQL.' ));
});
break ;
default :
setStepType ( '' );
}
};
const onSave = () => {
setLoaderText ( 'Saving...' );
var _url = url_for (
'grant_wizard.apply' , {
'sid' : encodeURI ( sid ),
'did' : encodeURI ( did ),
});
const post_data = {
acl : selectedAcl . privilege ,
objects : selectedObject
};
api . post ( _url , post_data )
. then (() => {
setLoaderText ( '' );
Alertify . wizardDialog (). close ();
})
2021-09-23 14:40:38 +05:30
. catch (( error ) => {
2021-09-20 13:02:41 +05:30
setLoaderText ( '' );
2021-09-23 14:40:38 +05:30
Alertify . error ( gettext ( `Error while saving grant wizard data: ${ error . response . data . errormsg } ` ));
2021-09-20 13:02:41 +05:30
});
};
const disableNextCheck = () => {
return selectedObject . length > 0 && stepType === 'object_type' ?
false : selectedAcl ? . privilege ? . length > 0 && stepType === 'privileges' ? validatePrivilege () : true ;
};
const onDialogHelp = () => {
window . open ( url_for ( 'help.static' , { 'filename' : 'grant_wizard.html' }), 'pgadmin_help' );
};
const getTableSelectedRows = ( selRows ) => {
var selObj = [];
var objectTypes = new Set ();
if ( selRows . length > 0 ) {
selRows . forEach (( row ) => {
var object_type = '' ;
switch ( row . values . object_type ) {
case 'Function' :
object_type = 'function' ;
break ;
case 'Trigger Function' :
object_type = 'function' ;
break ;
case 'Procedure' :
object_type = 'procedure' ;
break ;
case 'Table' :
object_type = 'table' ;
break ;
case 'Sequence' :
object_type = 'sequence' ;
break ;
case 'View' :
object_type = 'table' ;
break ;
case 'Materialized View' :
object_type = 'table' ;
break ;
case 'Foreign Table' :
object_type = 'foreign_table' ;
break ;
case 'Package' :
object_type = 'package' ;
break ;
default :
break ;
}
objectTypes . add ( object_type );
selObj . push ( row . values );
});
}
var privileges = new Set ();
objectTypes . forEach (( objType ) => {
privOptions [ objType ] ? . acl . forEach (( priv ) => {
privileges . add ( priv );
});
});
setPrivileges ( Array . from ( privileges ));
setSelectedObject ( selObj );
setErrMsg ( selObj . length === 0 ? gettext ( 'Please select any database object.' ) : '' );
};
const onErrClose = React . useCallback (()=>{
setErrMsg ( '' );
});
return (
<>
< Box className = { clsx ( 'wizard-header' , classes . grantWizardTitle )}>{ gettext ( 'Grant Wizard' )}</ Box >
< Loader message = { loaderText } />
< Wizard
stepList = { steps }
rootClass = { clsx ( classes . grantWizardContent )}
stepPanelCss = { classes . grantWizardPanelContent }
disableNextStep = { disableNextCheck }
onStepChange = { wizardStepChange }
onSave = { onSave }
onHelp = { onDialogHelp }
>
< WizardStep
stepId = { 0 }
className = { clsx ( classes . objectSelection , classes . grantWizardStep , classes . stepPanelCss )} >
< Box className = { classes . searchBox }>
< Box className = { classes . searchPadding }></ Box >
< InputText
placeholder = { 'Search' }
className = { classes . searchInput }
value = { searchVal }
onChange = {( val ) => {
setSearchVal ( val );}
}>
</ InputText >
</ Box >
< PgTable
className = { classes . table }
height = { window . innerHeight - 450 }
columns = { columns }
data = { tablebData }
isSelectRow = { true }
searchText = { searchVal }
getSelectedRows = { getTableSelectedRows }>
</ PgTable >
< FormFooterMessage type = { MESSAGE_TYPE . ERROR } message = { errMsg } onClose = { onErrClose } />
</ WizardStep >
< WizardStep
stepId = { 1 }
className = { clsx ( classes . grantWizardStep , classes . privilegeStep )}>
{ privSchemaInstance &&
< SchemaView
formType = { 'dialog' }
getInitData = {() => { }}
viewHelperProps = {{ mode : 'create' }}
schema = { privSchemaInstance }
showFooter = { false }
isTabView = { false }
onDataChange = {( isChanged , changedData ) => {
setSelectedAcl ( changedData );
}}
/>
}
</ WizardStep >
< WizardStep
stepId = { 2 }
className = { classes . grantWizardStep }>
< Box >{ gettext ( 'The SQL below will be executed on the database server to grant the selected privileges. Please click on Finish to complete the process.' )}</ Box >
< InputSQL
onLable = { true }
className = { classes . grantWizardSql }
readonly = { true }
value = { msqlData . toString ()} />
</ WizardStep >
</ Wizard >
</>
);
}
GrantWizard . propTypes = {
sid : PropTypes . string ,
did : PropTypes . number ,
nodeInfo : PropTypes . object ,
nodeData : PropTypes . object ,
};