diff --git a/src/components/Tables/Base/Action/index.jsx b/src/components/Tables/Base/Action/index.jsx index d7b7ada1..7d9c3d22 100644 --- a/src/components/Tables/Base/Action/index.jsx +++ b/src/components/Tables/Base/Action/index.jsx @@ -12,17 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -import checkItemPolicy from 'resources/policy'; +import checkItemPolicy, { systemRoleIsReader } from 'resources/policy'; -export async function checkAllowed( +export async function checkAllowed({ item, policy, allowed, containerProps, actionName, - extra -) { - const policyResult = checkItemPolicy(policy, item, actionName, extra); + extra, + isAdminPage, + action, +}) { + const { enableSystemReader } = action || {}; + const policyResult = checkItemPolicy({ + policy, + item, + actionName, + isAdminPage, + enableSystemReader, + }); if (!policyResult) { return false; } @@ -36,32 +45,38 @@ export async function checkAllowed( return result; } -export async function getAllowedResults( +export async function getAllowedResults({ actions, data, key, containerProps, - extra -) { + extra, + isAdminPage, +}) { const allowedPromises = actions.map(async (it) => { - const result = checkAllowed( - data, - key ? it[key].policy : it.policy, - key ? it[key].allowed : it.allowed, + const result = checkAllowed({ + item: data, + policy: key ? it[key].policy : it.policy, + allowed: key ? it[key].allowed : it.allowed, containerProps, - key ? it[key].title : it.title, - extra - ); + actionName: key ? it[key].title : it.title, + extra, + isAdminPage, + action: it.action, + }); return result; }); const results = await Promise.all(allowedPromises); return results; } -export function getPolicyResults(actions, extra) { +export function getPolicyResults({ actions, extra, isAdminPage }) { return actions.map((it) => { - const { policy, title } = it; - const result = checkItemPolicy(policy, null, title, extra); + const { policy, title, enableSystemReader } = it; + if (isAdminPage && !enableSystemReader && systemRoleIsReader()) { + return false; + } + const result = checkItemPolicy({ policy, actionName: title, extra }); return result; }); } @@ -76,10 +91,10 @@ export function getAction(action, item, containerProps) { return action; } -export function getActionsByPolicy(actions, containerProps) { +export function getActionsByPolicy({ actions, containerProps, isAdminPage }) { const actionList = actions.map((action) => getAction(action, null, containerProps) ); - const policyResults = getPolicyResults(actionList); + const policyResults = getPolicyResults({ actions: actionList, isAdminPage }); return actionList.filter((it, index) => policyResults[index]); } diff --git a/src/components/Tables/Base/BatchActionButtons/index.jsx b/src/components/Tables/Base/BatchActionButtons/index.jsx index fb14bafb..e13515f7 100644 --- a/src/components/Tables/Base/BatchActionButtons/index.jsx +++ b/src/components/Tables/Base/BatchActionButtons/index.jsx @@ -96,12 +96,17 @@ export default function TableBatchButtons(props) { onClickAction, onCancelAction, resourceName, + isAdminPage, } = props; let moreButton = null; let batchButtons = null; let showedActions = []; let restActions = []; - const actionList = getActionsByPolicy(batchActions, containerProps); + const actionList = getActionsByPolicy({ + actions: batchActions, + containerProps, + isAdminPage, + }); if (visibleButtonNumber < actionList.length) { if (visibleButtonNumber < 0) { restActions = actionList; diff --git a/src/components/Tables/Base/ItemActionButtons/index.jsx b/src/components/Tables/Base/ItemActionButtons/index.jsx index 4ca96cad..a46fb112 100644 --- a/src/components/Tables/Base/ItemActionButtons/index.jsx +++ b/src/components/Tables/Base/ItemActionButtons/index.jsx @@ -288,7 +288,7 @@ export default class ItemActionButtons extends Component { } async updateResult(item, containerProps) { - const { actions } = this.props; + const { actions, isAdminPage } = this.props; const { actionList, firstAction, moreActions } = getActionList( actions, item, @@ -297,12 +297,13 @@ export default class ItemActionButtons extends Component { this.actionList = actionList; this.firstAction = firstAction; this.moreActions = moreActions; - const results = await getAllowedResults( - this.actionList, - item, - 'action', - containerProps - ); + const results = await getAllowedResults({ + actions: this.actionList, + data: item, + key: 'action', + containerProps, + isAdminPage, + }); this.setState({ results, }); diff --git a/src/components/Tables/Base/PrimaryActionButtons/index.jsx b/src/components/Tables/Base/PrimaryActionButtons/index.jsx index 20e8da26..b0aac32f 100644 --- a/src/components/Tables/Base/PrimaryActionButtons/index.jsx +++ b/src/components/Tables/Base/PrimaryActionButtons/index.jsx @@ -62,15 +62,16 @@ export default class TablePrimaryButtons extends Component { } async getActionsAllowed() { - const { containerProps, primaryActionsExtra } = this.props; + const { containerProps, primaryActionsExtra, isAdminPage } = this.props; const { detail = null } = containerProps; - const results = await getAllowedResults( - this.actionList, - detail, - null, + const results = await getAllowedResults({ + actions: this.actionList, + data: detail, containerProps, - primaryActionsExtra - ); + key: null, + extra: primaryActionsExtra, + isAdminPage, + }); this.setState({ primaryAllowedResults: results, }); diff --git a/src/components/Tables/Base/index.jsx b/src/components/Tables/Base/index.jsx index 814e80b0..098d064c 100644 --- a/src/components/Tables/Base/index.jsx +++ b/src/components/Tables/Base/index.jsx @@ -110,6 +110,7 @@ export default class BaseTable extends React.Component { hideTotal: false, hideDownload: false, primaryActionsExtra: null, + isAdminPage: false, }; constructor(props) { @@ -472,6 +473,7 @@ export default class BaseTable extends React.Component { onClickAction, onFinishAction, onCancelAction, + isAdminPage, } = this.props; const { hideRow } = this.state; const currentColumns = columns @@ -489,6 +491,7 @@ export default class BaseTable extends React.Component { width: 150, render: (text, record, index) => ( selectedRowKeys.indexOf(it[rowKey]) >= 0 @@ -540,6 +544,7 @@ export default class BaseTable extends React.Component { if (batchActions) { return ( ); diff --git a/src/containers/TabDetail/index.jsx b/src/containers/TabDetail/index.jsx index d7fd7439..922ba60e 100644 --- a/src/containers/TabDetail/index.jsx +++ b/src/containers/TabDetail/index.jsx @@ -218,7 +218,7 @@ export default class DetailBase extends React.Component { getRouteProps = () => ({}); fetchDataWithPolicy = (silent, params) => { - if (!checkItemPolicy(this.policy, null, this.name)) { + if (!checkItemPolicy({ policy: this.policy, actionName: this.name })) { const error = { message: t("You don't have access to get {name}.", { name: this.name.toLowerCase(), @@ -396,6 +396,7 @@ export default class DetailBase extends React.Component { onFinishAction={this.onFinishAction} item={this.getActionData()} containerProps={{ isAdminPage: this.isAdminPage }} + isAdminPage={this.isAdminPage} // firstActionClassName={styles['attach-btn']} /> ); diff --git a/src/layouts/Base/index.jsx b/src/layouts/Base/index.jsx index e7a19526..89fe771d 100644 --- a/src/layouts/Base/index.jsx +++ b/src/layouts/Base/index.jsx @@ -97,7 +97,7 @@ class BaseLayout extends Component { if (licenseKey && !this.checkLicenseKey(licenseKey)) { return null; } - if (policy && !checkItemPolicy(policy)) { + if (policy && !checkItemPolicy({ policy })) { return null; } if (children.length === 0) { diff --git a/src/pages/configuration/containers/Setting/actions/View.jsx b/src/pages/configuration/containers/Setting/actions/View.jsx index 92aeac74..48641511 100644 --- a/src/pages/configuration/containers/Setting/actions/View.jsx +++ b/src/pages/configuration/containers/Setting/actions/View.jsx @@ -31,6 +31,8 @@ export default class View extends ModalAction { static readOnly = true; + static enableSystemReader = true; + get name() { return t('View'); } diff --git a/src/resources/policy.js b/src/resources/policy.js index 0f789ca5..af5f2ee6 100644 --- a/src/resources/policy.js +++ b/src/resources/policy.js @@ -36,11 +36,32 @@ const checkPolicyRules = (rules, every, actionName) => { return rules.some((rule) => checkPolicyRule(rule, actionName)); }; -const checkItemPolicy = (policy, item, actionName) => { +export const systemRoleIsReader = () => { + const { user: { roles = [] } = {} } = globals || {}; + const readerRole = 'system_reader'; + const adminRoles = ['system_admin', 'admin']; + const hasReaderRole = roles.some((it) => it.name === readerRole); + if (!hasReaderRole) { + return false; + } + const hasAdminRole = roles.some((it) => adminRoles.includes(it.name)); + return hasReaderRole && !hasAdminRole; +}; + +const checkItemPolicy = ({ + policy, + item, + actionName, + isAdminPage, + enableSystemReader, +}) => { if (globals.policies.length === 0) { // TODO: change to false return true; } + if (isAdminPage && !enableSystemReader && systemRoleIsReader()) { + return false; + } if (!policy) { // eslint-disable-next-line no-console console.log('has no policy', policy, item, actionName); diff --git a/src/stores/root.js b/src/stores/root.js index a12b3e56..fdd29cd8 100644 --- a/src/stores/root.js +++ b/src/stores/root.js @@ -121,7 +121,7 @@ class RootStore { this.roles = roles; this.baseRoles = base_roles; this.baseDomains = base_domains; - // const adminRole = roles.find(it => it.name === 'admin'); + // TODO: fix system/project admin/member/reader for W this.hasAdminRole = checkPolicy(onlyAdminCanReadPolicy); globals.user.hasAdminRole = this.hasAdminRole; }