diff --git a/console/cypress/integration/data/permissions/utils.js b/console/cypress/integration/data/permissions/utils.js index 58163f04dd3b7..5050a9856bcc4 100644 --- a/console/cypress/integration/data/permissions/utils.js +++ b/console/cypress/integration/data/permissions/utils.js @@ -91,7 +91,7 @@ export const permRemove = (tableName, query) => { // click on the query type to edit permission cy.get(getElementFromAlias(`role0-${query}`)).click(); // Remove permission - cy.get(getElementFromAlias('Remove-all-access-button')).click(); + cy.get(getElementFromAlias('Remove-button')).click(); cy.wait(2500); // Check for notif // cy.get('.notification-success').click(); diff --git a/console/src/components/Common/Common.scss b/console/src/components/Common/Common.scss index 0581d5dce837b..b2b6d1363fc7d 100644 --- a/console/src/components/Common/Common.scss +++ b/console/src/components/Common/Common.scss @@ -480,7 +480,7 @@ input { } .add_mar_small { - margin-right: 10px; + margin-right: 10px !important; } .code_space { diff --git a/console/src/components/Services/Data/DataState.js b/console/src/components/Services/Data/DataState.js index fef4350c4960d..2959951623a81 100644 --- a/console/src/components/Services/Data/DataState.js +++ b/console/src/components/Services/Data/DataState.js @@ -28,6 +28,8 @@ const defaultPermissionsState = { custom_checked: false, newRole: '', limitEnabled: true, + bulkSelect: [], + applySamePermissions: [], }; const defaultQueryPermissions = { diff --git a/console/src/components/Services/Data/TableCommon/TableReducer.js b/console/src/components/Services/Data/TableCommon/TableReducer.js index 7d4e9f3f92ec6..40aca0dade161 100644 --- a/console/src/components/Services/Data/TableCommon/TableReducer.js +++ b/console/src/components/Services/Data/TableCommon/TableReducer.js @@ -43,7 +43,6 @@ import { PERM_TOGGLE_COLUMN, PERM_TOGGLE_ALL_COLUMNS, PERM_ALLOW_ALL, - PERM_TOGGLE_ENABLE_LIMIT, PERM_TOGGLE_MODIFY_LIMIT, PERM_TOGGLE_ALLOW_UPSERT, PERM_CUSTOM_CHECKED, @@ -51,12 +50,20 @@ import { PERM_SAVE_PERMISSIONS, PERM_CLOSE_EDIT, PERM_SET_ROLE_NAME, + PERM_SELECT_BULK, + PERM_DESELECT_BULK, + PERM_RESET_BULK_SELECT, + PERM_RESET_BULK_SAME_SELECT, + PERM_SAME_APPLY_BULK, + PERM_DESELECT_SAME_APPLY_BULK, toggleColumn, toggleAllColumns, getFilterKey, getBasePermissionsState, updatePermissionsState, deleteFromPermissionsState, + updateBulkSelect, + updateBulkSameSelect, } from '../TablePermissions/Actions'; const modifyReducer = (tableName, schemas, modifyStateOrig, action) => { @@ -306,15 +313,6 @@ const modifyReducer = (tableName, schemas, modifyStateOrig, action) => { }, }; - case PERM_TOGGLE_ENABLE_LIMIT: - return { - ...modifyState, - permissionsState: { - ...modifyState.permissionsState, - limitEnabled: action.data, - }, - }; - case PERM_TOGGLE_MODIFY_LIMIT: return { ...modifyState, @@ -406,6 +404,73 @@ const modifyReducer = (tableName, schemas, modifyStateOrig, action) => { ...modifyState, }; + case PERM_SELECT_BULK: + return { + ...modifyState, + permissionsState: { + ...modifyState.permissionsState, + bulkSelect: updateBulkSelect( + modifyState.permissionsState, + action.data, + true + ), + }, + }; + case PERM_DESELECT_BULK: + return { + ...modifyState, + permissionsState: { + ...modifyState.permissionsState, + bulkSelect: updateBulkSelect( + modifyState.permissionsState, + action.data, + false + ), + }, + }; + case PERM_SAME_APPLY_BULK: + return { + ...modifyState, + permissionsState: { + ...modifyState.permissionsState, + applySamePermissions: updateBulkSameSelect( + modifyState.permissionsState, + action.data, + true + ), + }, + }; + case PERM_DESELECT_SAME_APPLY_BULK: + return { + ...modifyState, + permissionsState: { + ...modifyState.permissionsState, + applySamePermissions: updateBulkSameSelect( + modifyState.permissionsState, + action.data, + false + ), + }, + }; + + case PERM_RESET_BULK_SELECT: + return { + ...modifyState, + permissionsState: { + ...modifyState.permissionsState, + bulkSelect: [], + }, + }; + + case PERM_RESET_BULK_SAME_SELECT: + return { + ...modifyState, + permissionsState: { + ...modifyState.permissionsState, + applySamePermissions: [], + }, + }; + case TOGGLE_ACTIVE_COLUMN: const newCol = modifyState.activeEdit.column === action.column ? '' : action.column; diff --git a/console/src/components/Services/Data/TableModify/Modify.scss b/console/src/components/Services/Data/TableModify/Modify.scss index 9d99e07706fc2..b62cf1eee0266 100644 --- a/console/src/components/Services/Data/TableModify/Modify.scss +++ b/console/src/components/Services/Data/TableModify/Modify.scss @@ -41,7 +41,7 @@ .newRoleInput { margin-left: 20px; - width: 80%; + width: calc(100% - 40px); height: 30px; } @@ -173,7 +173,18 @@ hr td:first-child, th:first-child { border-right: 4px double #ddd; font-weight: bold; - width: 20%; + width: 10%; + } + td:nth-child(2) { + overflow: auto; + max-width: 250px; + width: 250px; + } + .newRoleTd { + padding-top: 13px; + } + .permissionDelete { + cursor: pointer; } .editPermissionLink { @@ -181,6 +192,11 @@ hr position: absolute; right: 10px; color: #337ab7; + cursor: pointer; + } + + .bulkSelect { + margin-right: 10px !important; } .clickableCell { @@ -209,17 +225,34 @@ hr } } +.applyBulkPermissions { + display: inline-block; +} + +.samePermissionRole { + display: inline-block; + width: auto; + height: auto; +} + +.bulkApplyBtn { + display: block; + margin-top: 10px; + clear: both; +} .activeEdit { .editPermissionsHeading { font-weight: bold; font-size: 16px; margin-bottom: 5px; + word-wrap: break-word; } .editPermissionsSection { margin: 5px; padding: 10px; + word-wrap: break-word; .columnListElement { float: left; diff --git a/console/src/components/Services/Data/TablePermissions/Actions.js b/console/src/components/Services/Data/TablePermissions/Actions.js index 06905fb09a924..3a763ee6542d2 100644 --- a/console/src/components/Services/Data/TablePermissions/Actions.js +++ b/console/src/components/Services/Data/TablePermissions/Actions.js @@ -17,6 +17,14 @@ export const PERM_REMOVE_ACCESS = 'ModifyTable/PERM_REMOVE_ACCESS'; export const PERM_SAVE_PERMISSIONS = 'ModifyTable/PERM_SAVE_PERMISSIONS'; export const PERM_CLOSE_EDIT = 'ModifyTable/PERM_CLOSE_EDIT'; export const PERM_SET_ROLE_NAME = 'ModifyTable/PERM_SET_ROLE_NAME'; +export const PERM_SELECT_BULK = 'ModifyTable/PERM_SELECT_BULK'; +export const PERM_DESELECT_BULK = 'ModifyTable/PERM_DESELECT_BULK'; +export const PERM_RESET_BULK_SELECT = 'ModifyTable/PERM_RESET_BULK_SELECT'; +export const PERM_RESET_BULK_SAME_SELECT = + 'ModifyTable/PERM_RESET_BULK_SAME_SELECT'; +export const PERM_SAME_APPLY_BULK = 'ModifyTable/PERM_SAME_APPLY_BULK'; +export const PERM_DESELECT_SAME_APPLY_BULK = + 'ModifyTable/PERM_DESELECT_SAME_APPLY_BULK'; const queriesWithPermColumns = ['select', 'update']; const permChangeTypes = { @@ -52,14 +60,28 @@ const permToggleAllowUpsert = checked => ({ type: PERM_TOGGLE_ALLOW_UPSERT, data: checked, }); -const permToggleEnableLimit = checked => ({ - type: PERM_TOGGLE_ENABLE_LIMIT, - data: checked, -}); const permToggleModifyLimit = limit => ({ type: PERM_TOGGLE_MODIFY_LIMIT, data: limit, }); +const permSetBulkSelect = (isChecked, selectedRole) => { + return dispatch => { + if (isChecked) { + dispatch({ type: PERM_SELECT_BULK, data: selectedRole }); + } else { + dispatch({ type: PERM_DESELECT_BULK, data: selectedRole }); + } + }; +}; +const permSetSameSelect = (isChecked, selectedRole) => { + return dispatch => { + if (isChecked) { + dispatch({ type: PERM_SAME_APPLY_BULK, data: selectedRole }); + } else { + dispatch({ type: PERM_DESELECT_SAME_APPLY_BULK, data: selectedRole }); + } + }; +}; const permCustomChecked = () => ({ type: PERM_CUSTOM_CHECKED }); const getFilterKey = query => { @@ -100,6 +122,26 @@ const updatePermissionsState = (permissions, key, value) => { return _permissions; }; +const updateBulkSelect = (permissionsState, selectedRole, isAdd) => { + let bulkRes = permissionsState.bulkSelect; + if (isAdd) { + bulkRes.push(selectedRole); + } else { + bulkRes = bulkRes.filter(e => e !== selectedRole); + } + return bulkRes; +}; + +const updateBulkSameSelect = (permissionsState, selectedRole, isAdd) => { + let bulkRes = permissionsState.applySamePermissions; + if (isAdd) { + bulkRes.push(selectedRole); + } else { + bulkRes = bulkRes.filter(e => e !== selectedRole); + } + return bulkRes; +}; + const deleteFromPermissionsState = permissions => { const _permissions = JSON.parse(JSON.stringify(permissions)); @@ -132,6 +174,237 @@ const toggleColumn = (permissions, column) => { return _newColumns; }; +const permRemoveRole = (tableSchema, roleName) => { + return (dispatch, getState) => { + const currentSchema = getState().tables.currentSchema; + + const table = tableSchema.table_name; + const role = roleName; + + const currRolePermissions = tableSchema.permissions.find( + p => p.role_name === role + ); + + const permissionsUpQueries = []; + const permissionsDownQueries = []; + + if (currRolePermissions && currRolePermissions.permissions) { + Object.keys(currRolePermissions.permissions).forEach(type => { + const deleteQuery = { + type: 'drop_' + type + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + }, + }; + const createQuery = { + type: 'create_' + type + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + permission: currRolePermissions.permissions[type], + }, + }; + permissionsUpQueries.push(deleteQuery); + permissionsDownQueries.push(createQuery); + }); + } + + // Apply migration + const migrationName = + 'remove_permission_' + role + '_' + currentSchema + '_table_' + table; + + const requestMsg = 'Removing permissions...'; + const successMsg = 'Permission removed'; + const errorMsg = 'Removing permissions failed'; + + const customOnSuccess = () => { + dispatch(_permRemoveAccess()); + // reset new role name + dispatch(permSetRoleName('')); + // close edit box + dispatch(permCloseEdit()); + }; + const customOnError = () => {}; + + makeMigrationCall( + dispatch, + getState, + permissionsUpQueries, + permissionsDownQueries, + migrationName, + customOnSuccess, + customOnError, + requestMsg, + successMsg, + errorMsg + ); + }; +}; + +const permRemoveMultipleRoles = tableSchema => { + return (dispatch, getState) => { + const currentSchema = getState().tables.currentSchema; + const permissionsState = getState().tables.modify.permissionsState; + + const table = tableSchema.table_name; + const roles = permissionsState.bulkSelect; + + const permissionsUpQueries = []; + const permissionsDownQueries = []; + const currentPermissions = tableSchema.permissions; + + roles.map(role => { + const currentRolePermission = currentPermissions.filter(el => { + return el.role_name === role; + }); + Object.keys(currentRolePermission[0].permissions).forEach(type => { + const deleteQuery = { + type: 'drop_' + type + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + }, + }; + const createQuery = { + type: 'create_' + type + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + permission: currentRolePermission[0].permissions[type], + }, + }; + permissionsUpQueries.push(deleteQuery); + permissionsDownQueries.push(createQuery); + }); + }); + + // Apply migration + const migrationName = 'remove_roles_' + currentSchema + '_table_' + table; + + const requestMsg = 'Removing roles...'; + const successMsg = 'Roles removed'; + const errorMsg = 'Removing roles failed'; + + const customOnSuccess = () => { + // reset new role name + dispatch(permSetRoleName('')); + // close edit box + dispatch(permCloseEdit()); + // reset checkbox selections + dispatch({ type: PERM_RESET_BULK_SELECT }); + }; + const customOnError = () => {}; + + makeMigrationCall( + dispatch, + getState, + permissionsUpQueries, + permissionsDownQueries, + migrationName, + customOnSuccess, + customOnError, + requestMsg, + successMsg, + errorMsg + ); + }; +}; + +const applySamePermissionsBulk = tableSchema => { + return (dispatch, getState) => { + const currentSchema = getState().tables.currentSchema; + const permissionsState = getState().tables.modify.permissionsState; + + const table = tableSchema.table_name; + const currentQueryType = permissionsState.query; + const toBeAppliedPermission = permissionsState[currentQueryType]; + const selectedRoles = permissionsState.applySamePermissions; + + const permissionsUpQueries = []; + const permissionsDownQueries = []; + const currentPermissions = tableSchema.permissions; + + selectedRoles.map(role => { + // find out if selected role has an existing permission of the same query type. + // if so add a drop permission and then create the new permission. + + const currentRolePermission = currentPermissions.filter(el => { + return el.role_name === role; + }); + if (currentRolePermission[0].permissions[currentQueryType]) { + // existing permission is there. so drop and recreate. + const deleteQuery = { + type: 'drop_' + currentQueryType + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + }, + }; + const createQuery = { + type: 'create_' + currentQueryType + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + permission: currentRolePermission[0].permissions[currentQueryType], + }, + }; + permissionsUpQueries.push(deleteQuery); + permissionsDownQueries.push(createQuery); + } + // now add normal create and drop permissions + const createQuery = { + type: 'create_' + currentQueryType + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + permission: toBeAppliedPermission, + }, + }; + const deleteQuery = { + type: 'drop_' + currentQueryType + '_permission', + args: { + table: { name: table, schema: currentSchema }, + role: role, + }, + }; + permissionsUpQueries.push(createQuery); + permissionsDownQueries.push(deleteQuery); + }); + + // Apply migration + const migrationName = + 'apply_same_permissions_' + currentSchema + '_table_' + table; + + const requestMsg = 'Applying Same Permissions'; + const successMsg = 'Permission Changes Applied'; + const errorMsg = 'Permisison Changes Failed'; + + const customOnSuccess = () => { + // reset new role name + dispatch(permSetRoleName('')); + // close edit box + dispatch(permCloseEdit()); + // reset checkbox selections + dispatch({ type: PERM_RESET_BULK_SAME_SELECT }); + }; + const customOnError = () => {}; + + makeMigrationCall( + dispatch, + getState, + permissionsUpQueries, + permissionsDownQueries, + migrationName, + customOnSuccess, + customOnError, + requestMsg, + successMsg, + errorMsg + ); + }; +}; + const permChangePermissions = changeType => { return (dispatch, getState) => { const allSchemas = getState().tables.allSchemas; @@ -249,9 +522,10 @@ export { permChangePermissions, permAllowAll, permToggleAllowUpsert, - permToggleEnableLimit, permToggleModifyLimit, permCustomChecked, + permRemoveRole, + permSetBulkSelect, toggleColumn, toggleAllColumns, queriesWithPermColumns, @@ -259,4 +533,9 @@ export { getBasePermissionsState, updatePermissionsState, deleteFromPermissionsState, + updateBulkSelect, + updateBulkSameSelect, + permRemoveMultipleRoles, + permSetSameSelect, + applySamePermissionsBulk, }; diff --git a/console/src/components/Services/Data/TablePermissions/Permissions.js b/console/src/components/Services/Data/TablePermissions/Permissions.js index 6f0d0c0670caf..c1162c72ecdb1 100644 --- a/console/src/components/Services/Data/TablePermissions/Permissions.js +++ b/console/src/components/Services/Data/TablePermissions/Permissions.js @@ -20,9 +20,13 @@ import { permSetRoleName, permChangePermissions, permToggleAllowUpsert, - permToggleEnableLimit, permToggleModifyLimit, permCustomChecked, + permRemoveRole, + permSetBulkSelect, + permRemoveMultipleRoles, + permSetSameSelect, + applySamePermissionsBulk, } from './Actions'; import PermissionBuilder from './PermissionBuilder/PermissionBuilder'; import TableHeader from '../TableCommon/TableHeader'; @@ -181,12 +185,61 @@ class Permissions extends Component { const dispatchRoleNameChange = e => { dispatch(permSetRoleName(e.target.value)); }; + const dispatchBulkSelect = e => { + const isChecked = e.target.checked; + const selectedRole = e.target.getAttribute('data-role'); + dispatch(permSetBulkSelect(isChecked, selectedRole)); + }; + const dispatchDeletePermission = () => { + const isConfirm = window.confirm( + 'Are you sure you want to delete the permission for role ' + + role + + '?' + ); + if (isConfirm) { + dispatch(permRemoveRole(tableSchema, role)); + } + }; const _permissionsRowHtml = []; + if (role === 'admin' || role === '') { + _permissionsRowHtml.push(