Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSCFC4EMSCR-491 Implement MSCR copy in UI continues #186

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mscr-ui/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"finish-editing": "Finish editing",
"invalidate-crosswalk": "Invalidate crosswalk",
"invalidate-schema": "Invalidate schema",
"mscr-copy": "Make MSCR copy",
"publish-crosswalk": "Publish crosswalk",
"publish-schema": "Publish schema",
"revision": "Add new revision"
Expand Down
1 change: 1 addition & 0 deletions mscr-ui/public/locales/fi/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"finish-editing": "",
"invalidate-crosswalk": "",
"invalidate-schema": "",
"mscr-copy": "",
"publish-crosswalk": "",
"publish-schema": "",
"revision": ""
Expand Down
1 change: 1 addition & 0 deletions mscr-ui/public/locales/sv/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"finish-editing": "",
"invalidate-crosswalk": "",
"invalidate-schema": "",
"mscr-copy": "",
"publish-crosswalk": "",
"publish-schema": "",
"revision": ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { CrosswalkWithVersionInfo } from '@app/common/interfaces/crosswalk.inter
import { SchemaWithVersionInfo } from '@app/common/interfaces/schema.interface';
import { ActionMenuWrapper } from '@app/common/components/schema-and-crosswalk-actionmenu/schema-and-crosswalk-actionmenu.styles';
import FormModal, { ModalType } from '@app/modules/form';
import { Format } from '@app/common/interfaces/format.interface';
import { Format, formatsAvailableForMscrCopy } from '@app/common/interfaces/format.interface';

interface SchemaAndCrosswalkActionmenuProps {
type: ActionMenuTypes;
Expand Down Expand Up @@ -55,6 +55,7 @@ export default function SchemaAndCrosswalkActionMenu({
const [isDeleteConfirmModalOpen, setDeleteConfirmModalOpen] = useState(false);
const [isRemoveConfirmModalOpen, setRemoveConfirmModalOpen] = useState(false);
const [isRevisionModalOpen, setRevisionModalOpen] = useState(false);
const [isMscrCopyModalOpen, setMscrCopyModalOpen] = useState(false);
const [isCrosswalkPublished, setCrosswalkPublished] =
React.useState<boolean>(false);
const [isLatestVersion, setIsLatestVersion] = useState(false);
Expand Down Expand Up @@ -202,6 +203,10 @@ export default function SchemaAndCrosswalkActionMenu({
}
}, [metadata.revisions, metadata.pid]);

if (type == ActionMenuTypes.NoEditPermission) {
return renderStubMenu();
}

return (
<>
<ActionMenuWrapper>
Expand Down Expand Up @@ -293,6 +298,18 @@ export default function SchemaAndCrosswalkActionMenu({
>
{t('actionmenu.revision')}
</ActionMenuItem>
<ActionMenuItem
className={
formatsAvailableForMscrCopy.includes(metadata.format) &&
(type === ActionMenuTypes.Schema ||
type === ActionMenuTypes.SchemaMetadata)
? ''
: 'd-none'
}
onClick={() => setMscrCopyModalOpen(true)}
>
{t('actionmenu.mscr-copy')}
</ActionMenuItem>
</ActionMenu>
</ActionMenuWrapper>
<ConfirmModal
Expand Down Expand Up @@ -406,6 +423,34 @@ export default function SchemaAndCrosswalkActionMenu({
setVisible={setRevisionModalOpen}
initialData={metadata}
/>
<FormModal
modalType={ModalType.McsrCopy}
contentType={Type.Schema}
visible={isMscrCopyModalOpen}
setVisible={setMscrCopyModalOpen}
initialData={metadata}
/>
</>
);

function renderStubMenu() {
return (
<>
<ActionMenuWrapper>
<ActionMenu buttonText={t('action.actions')}>
<ActionMenuItem onClick={() => setMscrCopyModalOpen(true)}>
{t('actionmenu.mscr-copy')}
</ActionMenuItem>
</ActionMenu>
</ActionMenuWrapper>
<FormModal
modalType={ModalType.McsrCopy}
contentType={Type.Schema}
visible={isMscrCopyModalOpen}
setVisible={setMscrCopyModalOpen}
initialData={metadata}
/>
</>
);
}
}
11 changes: 11 additions & 0 deletions mscr-ui/src/common/components/schema/schema.slice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ export const schemaApi = createApi({
},
})
}),
putSchemaMscrCopy: builder.mutation<Schema, { pid: string; data: Partial<Metadata> }>({
query: ({pid, data }) => ({
url: `/schema?action=mscrCopyOf&target=${pid}`,
method: 'PUT',
data: data,
headers: {
'content-Type': 'application/json;',
},
}),
}),
patchSchema: builder.mutation<
Metadata,
{
Expand Down Expand Up @@ -141,6 +151,7 @@ export const {
useGetSchemasQuery,
usePutSchemaFullMutation,
usePutSchemaRevisionMutation,
usePutSchemaMscrCopyMutation,
usePatchSchemaMutation,
util: { getRunningQueriesThunk },
} = schemaApi;
Expand Down
8 changes: 8 additions & 0 deletions mscr-ui/src/common/interfaces/format.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ export const formatsAvailableForSchemaRegistration: Format[] = [
Format.Shacl
];

export const formatsAvailableForMscrCopy: Format[] = [
Format.Csv,
Format.Jsonschema,
Format.Mscr,
Format.Shacl,
Format.Xsd
];

export const fileExtensionsAvailableForCrosswalkRegistrationAttachments: FileExtensions[] =
[FileExtensions.Csv, FileExtensions.Xslt, FileExtensions.Pdf];

Expand Down
1 change: 1 addition & 0 deletions mscr-ui/src/common/interfaces/search.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export enum ActionMenuTypes {
CrosswalkVersionInfo = 'CROSSWALK_VERSIONINFO',
Schema = 'SCHEMA',
SchemaMetadata = 'SCHEMA_METADATA',
NoEditPermission = 'NO_EDIT_PERMISSION',
}

export interface ResultInfo {
Expand Down
145 changes: 45 additions & 100 deletions mscr-ui/src/common/utils/has-permission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,36 @@ import {
import { User } from 'yti-common-ui/interfaces/user.interface';
import { Roles } from '../interfaces/format.interface';

// Need to specify the acctions permitted for each type of user
// Need to specify the actions permitted for each type of user
const actions = [
'CREATE_SCHEMA',
'EDIT_SCHEMA',
'EDIT_SCHEMA_METADATA',
'EDIT_SCHEMA_FILES',
'DELETE_SCHEMA',
'CREATE_CROSSWALK',
'EDIT_CROSSWALK_MAPPINGS',
'EDIT_CROSSWALK_METADATA',
'EDIT_CROSSWALK_FILES',
'DELETE_CROSSWALK',
// 'CREATE_SCHEMA',
// 'EDIT_SCHEMA',
// 'EDIT_SCHEMA_METADATA',
// 'EDIT_SCHEMA_FILES',
// 'DELETE_SCHEMA',
// 'CREATE_CROSSWALK',
// 'EDIT_CROSSWALK_MAPPINGS',
// 'EDIT_CROSSWALK_METADATA',
// 'EDIT_CROSSWALK_FILES',
// 'DELETE_CROSSWALK',
'EDIT_CONTENT',
'MAKE_MSCR_COPY',
] as const;

export type Actions = typeof actions[number];
export type Action = typeof actions[number];

export interface hasPermissionProps {
actions: Actions | Actions[];
targetOrganization?: string;
action: Action;
owner?: string[];
}

export interface checkPermissionProps {
user: User;
actions: Actions[];
targetOrganizations?: string[];
action: Action;
owner?: string[];
}

export default function HasPermission({
actions,
targetOrganization,
owner,
}: hasPermissionProps) {
export default function HasPermission({ action, owner }: hasPermissionProps) {
const { data: authenticatedUser } = useGetAuthenticatedUserQuery();
const dispatch = useStoreDispatch();
const user = useSelector(selectLogin());
Expand All @@ -66,99 +62,48 @@ export default function HasPermission({
return false;
}

//No Target Organization
if (!targetOrganization) {
if (owner && owner.length) {
//Editing Step as already has owner
return checkEditPermission({
user,
actions: Array.isArray(actions) ? actions : [actions],
owner,
});
}
if (!owner || owner.length == 0) {
return checkPermission({
user,
actions: Array.isArray(actions) ? actions : [actions],
action,
});
}

//If there is target organization
if (owner && owner.length) {
//Editing Step as already has owner
return checkEditPermission({
user,
actions: Array.isArray(actions) ? actions : [actions],
targetOrganizations: [targetOrganization],
owner,
});
}
return checkPermission({
//Content Creation
user,
actions: Array.isArray(actions) ? actions : [actions],
targetOrganizations: [targetOrganization],
action,
owner,
});
}

export function checkPermission({
user,
actions,
targetOrganizations,
}: checkPermissionProps) {

const rolesInOrganizations = Object.keys(user.organizationsInRole);

const rolesInTargetOrganizations =
targetOrganizations &&
targetOrganizations
?.flatMap((org) => user.rolesInOrganizations[org])
.filter((t) => t);

// Return true if user is superuser
if (user.superuser) {
return true;
}

// Return true if target organization is undefined and user has admin role
if (rolesInOrganizations.includes(Roles.admin) && !targetOrganizations) {
return true;
}

// console.log(rolesInTargetOrganizations);
// Return true if user has data model editor role in target organization
if (
rolesInTargetOrganizations?.includes(Roles.dataModelEditor)||rolesInTargetOrganizations?.includes(Roles.admin)
) {
export function checkPermission({ user, action, owner }: checkPermissionProps) {
if (action == 'MAKE_MSCR_COPY') {
return true;
}


return false;
}

export function checkEditPermission({
user,
owner
}: checkPermissionProps) {
if (owner?.includes(user.id)) {
//user is the owner, Check for personal Contents
return true;
} else {
//Gruop Content

if (owner && user.organizationsInRole[Roles.admin]&& user.organizationsInRole[Roles.admin].includes(owner[0])) {
// User has admin right for this group
return true;
}

if (
owner &&user.organizationsInRole[Roles.dataModelEditor]&&
user.organizationsInRole[Roles.dataModelEditor].includes(owner[0])
) {
} else if (action == 'EDIT_CONTENT') {
if (owner?.includes(user.id)) {
//user is the owner, Check for personal Contents
return true;
} else {
//Group Content
if (
owner &&
user.organizationsInRole[Roles.admin] &&
user.organizationsInRole[Roles.admin].includes(owner[0])
) {
// User has admin right for this group
return true;
}

if (
owner &&
user.organizationsInRole[Roles.dataModelEditor] &&
user.organizationsInRole[Roles.dataModelEditor].includes(owner[0])
) {
// User has data model editor right for this group
return true;
}
}
}


return false;
}
20 changes: 12 additions & 8 deletions mscr-ui/src/modules/crosswalk-editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export default function CrosswalkEditor({
} = useGetCrosswalkWithRevisionsQuery(crosswalkId);

const hasEditRights = HasPermission({
actions: ['EDIT_CROSSWALK_MAPPINGS'],
action: 'EDIT_CONTENT',
owner: getCrosswalkData?.owner,
});

Expand Down Expand Up @@ -723,13 +723,17 @@ export default function CrosswalkEditor({
</Grid>
<Grid item xs={6} className="d-flex justify-content-end">
<div className="mt-3 me-2">
<SchemaAndCrosswalkActionMenu
buttonCallbackFunction={performCallbackFromActionMenu}
metadata={getCrosswalkData}
isMappingsEditModeActive={isEditModeActive}
refetchMetadata={refetchCrosswalkData}
type={ActionMenuTypes.CrosswalkVersionInfo}
></SchemaAndCrosswalkActionMenu>
{hasEditRights && (
<SchemaAndCrosswalkActionMenu
buttonCallbackFunction={
performCallbackFromActionMenu
}
metadata={getCrosswalkData}
isMappingsEditModeActive={isEditModeActive}
refetchMetadata={refetchCrosswalkData}
type={ActionMenuTypes.CrosswalkVersionInfo}
/>
)}
</div>
</Grid>
<Grid item xs={12}>
Expand Down
Loading
Loading