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-12-16 18:29:44 +05:30
import Wizard from '../../../../static/js/helpers/wizard/Wizard' ;
import WizardStep from '../../../../static/js/helpers/wizard/WizardStep' ;
2021-09-23 14:40:38 +05:30
import PgTable from 'sources/components/PgTable' ;
2021-12-16 18:29:44 +05:30
import { getNodePrivilegeRoleSchema } from '../../../../../pgadmin/browser/server_groups/servers/static/js/privilege.ui.js' ;
import { InputSQL , InputText , FormFooterMessage , MESSAGE _TYPE } from '../../../../static/js/components/FormComponents' ;
import getApiInstance from '../../../../static/js/api_instance' ;
import SchemaView from '../../../../static/js/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-12-16 18:29:44 +05:30
import PrivilegeSchema from './privilege_schema.ui' ;
import Notify from '../../../../static/js/helpers/Notifier' ;
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
}
] ;
2021-12-21 18:00:07 +05:30
var steps = [ 'Object Selection' , 'Privilege Selection' , 'Review' ] ;
2021-09-20 13:02:41 +05:30
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 ( ( ) => {
2021-12-02 16:05:52 +05:30
Notify . error ( gettext ( 'Error while fetching grant wizard data.' ) ) ;
2021-09-20 13:02:41 +05:30
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 ( ( ) => {
2021-12-02 16:05:52 +05:30
Notify . error ( gettext ( 'Error while fetching SQL.' ) ) ;
2021-09-20 13:02:41 +05:30
} ) ;
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-12-02 16:05:52 +05:30
Notify . 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 ,
} ;