18123: Disable controls related to group for built in groups.
authorStephen Smith <stephen@curii.com>
Wed, 1 Dec 2021 20:13:37 +0000 (15:13 -0500)
committerStephen Smith <stephen@curii.com>
Wed, 1 Dec 2021 20:13:37 +0000 (15:13 -0500)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/models/group.ts
src/views-components/data-explorer/renderers.tsx
src/views/group-details-panel/group-details-panel.tsx

index 7d144a5812f6cb45d5e39b0ebf64408436b2d0f7..a0c22212b794e72c6c2ce02e17c06f1c59ebacb9 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { ResourceKind, TrashableResource } from "./resource";
+import { ResourceKind, TrashableResource, ResourceObjectType, RESOURCE_UUID_REGEX } from "./resource";
 
 export interface GroupResource extends TrashableResource {
     kind: ResourceKind.GROUP;
@@ -19,3 +19,15 @@ export enum GroupClass {
     FILTER  = 'filter',
     ROLE  = 'role',
 }
+
+export const BUILTIN_GROUP_IDS = [
+    'fffffffffffffff',
+    'anonymouspublic',
+    '000000000000000',
+]
+
+export const isBuiltinGroup = (uuid: string) => {
+    const match = RESOURCE_UUID_REGEX.exec(uuid);
+    const parts = match ? match[0].split('-') : [];
+    return parts.length === 3 && parts[1] === ResourceObjectType.GROUP && BUILTIN_GROUP_IDS.includes(parts[2]);
+};
index a13269e5b544d50023e7ccab3b638f5f0d9e2bcd..5040746ad53266795642a873306ea791ef48eff5 100644 (file)
@@ -28,7 +28,7 @@ import { withResourceData } from 'views-components/data-explorer/with-resources'
 import { CollectionResource } from 'models/collection';
 import { IllegalNamingWarning } from 'components/warning/warning';
 import { loadResource } from 'store/resources/resources-actions';
-import { GroupClass, GroupResource } from 'models/group';
+import { GroupClass, GroupResource, isBuiltinGroup } from 'models/group';
 import { openRemoveGroupMemberDialog } from 'store/group-details-panel/group-details-panel-actions';
 import { setMemberIsHidden } from 'store/group-details-panel/group-details-panel-actions';
 import { formatPermissionLevel } from 'views-components/sharing-dialog/permission-select';
@@ -215,12 +215,19 @@ export const ResourceLinkTailIsActive = connect(
     }, { toggleIsActive }
 )(renderIsActive);
 
-const renderIsHidden = (props: { memberLinkUuid: string, permissionLinkUuid: string, hidden: boolean, setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void }) => {
+const renderIsHidden = (props: {
+                            memberLinkUuid: string,
+                            permissionLinkUuid: string,
+                            hidden: boolean,
+                            canManage: boolean,
+                            setMemberIsHidden: (memberLinkUuid: string, permissionLinkUuid: string, hide: boolean) => void 
+                        }) => {
     if (props.memberLinkUuid) {
         return <Checkbox
                 data-cy="user-hidden-checkbox"
                 color="primary"
                 checked={props.hidden}
+                disabled={!props.canManage}
                 onClick={() => props.setMemberIsHidden(props.memberLinkUuid, props.permissionLinkUuid, !props.hidden)} />;
     } else {
         return <Typography />;
@@ -241,10 +248,12 @@ export const ResourceLinkTailIsHidden = connect(
 
         const permissionLinkUuid = permissions.length > 0 ? permissions[0].uuid : '';
         const isVisible = link && group && permissions.length > 0;
+        // Consider whether the current user canManage this resurce in addition when it's possible
+        const isBuiltin = isBuiltinGroup(link?.headUuid || '');
 
         return member?.kind === ResourceKind.USER
-            ? { memberLinkUuid: link?.uuid, permissionLinkUuid, hidden: !isVisible }
-            : { memberLinkUuid: '', permissionLinkUuid: '', hidden: false};
+            ? { memberLinkUuid: link?.uuid, permissionLinkUuid, hidden: !isVisible, canManage: !isBuiltin }
+            : { memberLinkUuid: '', permissionLinkUuid: '', hidden: false, canManage: false };
     }, { setMemberIsHidden }
 )(renderIsHidden);
 
@@ -425,9 +434,11 @@ const renderLinkDelete = (dispatch: Dispatch, item: LinkResource, canManage: boo
 export const ResourceLinkDelete = connect(
     (state: RootState, props: { uuid: string }) => {
         const link = getResource<LinkResource>(props.uuid)(state.resources);
+        const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
+
         return {
             item: link || { uuid: '', kind: ResourceKind.NONE },
-            canManage: link && getResourceLinkCanManage(state, link),
+            canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
         };
     })((props: { item: LinkResource, canManage: boolean } & DispatchProp<any>) =>
       renderLinkDelete(props.dispatch, props.item, props.canManage));
@@ -463,10 +474,11 @@ const renderPermissionLevel = (dispatch: Dispatch, link: LinkResource, canManage
 export const ResourceLinkHeadPermissionLevel = connect(
     (state: RootState, props: { uuid: string }) => {
         const link = getResource<LinkResource>(props.uuid)(state.resources);
+        const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
 
         return {
             link: link || { uuid: '', name: '', kind: ResourceKind.NONE },
-            canManage: link && getResourceLinkCanManage(state, link),
+            canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
         };
     })((props: { link: LinkResource, canManage: boolean } & DispatchProp<any>) =>
         renderPermissionLevel(props.dispatch, props.link, props.canManage));
@@ -474,10 +486,11 @@ export const ResourceLinkHeadPermissionLevel = connect(
 export const ResourceLinkTailPermissionLevel = connect(
     (state: RootState, props: { uuid: string }) => {
         const link = getResource<LinkResource>(props.uuid)(state.resources);
+        const isBuiltin = isBuiltinGroup(link?.headUuid || '') || isBuiltinGroup(link?.tailUuid || '');
 
         return {
             link: link || { uuid: '', name: '', kind: ResourceKind.NONE },
-            canManage: link && getResourceLinkCanManage(state, link),
+            canManage: link && getResourceLinkCanManage(state, link) && !isBuiltin,
         };
     })((props: { link: LinkResource, canManage: boolean } & DispatchProp<any>) =>
         renderPermissionLevel(props.dispatch, props.link, props.canManage));
index 932005a7bf3efcd7bcb3b7b07b772c202a518674..ae64b62890f2f31bf1ce9ac8f0e3bcaa2f850e17 100644 (file)
@@ -17,7 +17,7 @@ import { ResourcesState, getResource } from 'store/resources/resources';
 import { Grid, Button, Tabs, Tab, Paper } from '@material-ui/core';
 import { AddIcon } from 'components/icon/icon';
 import { getUserUuid } from 'common/getuser';
-import { GroupResource } from 'models/group';
+import { GroupResource, isBuiltinGroup } from 'models/group';
 
 export enum GroupDetailsPanelMembersColumnNames {
     FULL_NAME = "Name",
@@ -134,7 +134,9 @@ const mapStateToProps = (state: RootState) => {
 
     return {
         resources: state.resources,
-        groupCanManage: userUuid ? group?.writableBy?.includes(userUuid) : false,
+        groupCanManage: userUuid && !isBuiltinGroup(group?.uuid || '')
+                            ? group?.writableBy?.includes(userUuid)
+                            : false,
     };
 };