diff --git a/src/domain/application/applicationView/ApplicationView.tsx b/src/domain/application/applicationView/ApplicationView.tsx
index 542c89730..817c21c5d 100644
--- a/src/domain/application/applicationView/ApplicationView.tsx
+++ b/src/domain/application/applicationView/ApplicationView.tsx
@@ -38,7 +38,7 @@ import { ApplicationCancel } from '../components/ApplicationCancel';
import AttachmentSummary from '../components/AttachmentSummary';
import useAttachments from '../hooks/useAttachments';
import FeatureFlags from '../../../common/components/featureFlags/FeatureFlags';
-import UserRightsCheck from '../../hanke/hankeUsers/UserRightsCheck';
+import { CheckRightsByHanke } from '../../hanke/hankeUsers/UserRightsCheck';
type Props = {
application: Application;
@@ -120,7 +120,7 @@ function ApplicationView({ application, hanke, onEditApplication }: Props) {
{isPending ? (
-
+
}
@@ -128,17 +128,17 @@ function ApplicationView({ application, hanke, onEditApplication }: Props) {
>
{t('hakemus:buttons:editApplication')}
-
+
) : null}
{hanke ? (
-
+
}
/>
-
+
) : null}
diff --git a/src/domain/hanke/accessRights/AccessRightsViewContainer.tsx b/src/domain/hanke/accessRights/AccessRightsViewContainer.tsx
index cf5c08827..7e21afbab 100644
--- a/src/domain/hanke/accessRights/AccessRightsViewContainer.tsx
+++ b/src/domain/hanke/accessRights/AccessRightsViewContainer.tsx
@@ -7,7 +7,7 @@ import ErrorLoadingText from '../../../common/components/errorLoadingText/ErrorL
import { useHankeUsers } from '../hankeUsers/hooks/useHankeUsers';
import useHanke from '../hooks/useHanke';
import AccessRightsView from './AccessRightsView';
-import useUserRightsForHanke from '../hankeUsers/hooks/useUserRightsForHanke';
+import { usePermissionsForHanke } from '../hankeUsers/hooks/useUserRightsForHanke';
type Props = {
hankeTunnus: string;
@@ -17,7 +17,7 @@ function AccessRightsViewContainer({ hankeTunnus }: Props) {
const { t } = useTranslation();
const { data: hankeUsers, isLoading, isError, error } = useHankeUsers(hankeTunnus);
const { data: hankeData } = useHanke(hankeTunnus);
- const { data: signedInUser } = useUserRightsForHanke(hankeTunnus);
+ const { data: signedInUser } = usePermissionsForHanke(hankeTunnus);
if (isLoading) {
return (
diff --git a/src/domain/hanke/hankeUsers/UserRightsCheck.test.tsx b/src/domain/hanke/hankeUsers/UserRightsCheck.test.tsx
index 06be23cfb..3be64c2f6 100644
--- a/src/domain/hanke/hankeUsers/UserRightsCheck.test.tsx
+++ b/src/domain/hanke/hankeUsers/UserRightsCheck.test.tsx
@@ -2,60 +2,108 @@ import React from 'react';
import { rest } from 'msw';
import { render, screen, waitFor } from '../../../testUtils/render';
import { server } from '../../mocks/test-server';
-import { SignedInUser } from './hankeUser';
-import UserRightsCheck from './UserRightsCheck';
-
-test('Should render children if user has required right', async () => {
- render(
-
- Children
- ,
- );
-
- await waitFor(() => {
- expect(screen.getByText('Children')).toBeInTheDocument();
+import { AccessRightLevel, SignedInUser } from './hankeUser';
+import { CheckRightsByHanke, CheckRightsByUser } from './UserRightsCheck';
+import { signedInUser } from '../../mocks/signedInUser';
+
+describe('CheckRightsByHanke', () => {
+ test('Should render children if user has required right', async () => {
+ render(
+
+ Children
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText('Children')).toBeInTheDocument();
+ });
});
-});
-test('Should not render children if user does not have required right', async () => {
- server.use(
- rest.get('/api/hankkeet/:hankeTunnus/whoami', async (req, res, ctx) => {
- return res(
- ctx.status(200),
- ctx.json({
- hankeKayttajaId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
- kayttooikeustaso: 'KATSELUOIKEUS',
- kayttooikeudet: ['VIEW'],
- }),
- );
- }),
- );
-
- render(
-
- Children
- ,
- );
-
- await waitFor(() => {
- expect(screen.queryByText('Children')).not.toBeInTheDocument();
+ test('Should not render children if user does not have required right', async () => {
+ server.use(
+ rest.get('/api/hankkeet/:hankeTunnus/whoami', async (_, res, ctx) => {
+ return res(
+ ctx.status(200),
+ ctx.json({
+ hankeKayttajaId: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
+ kayttooikeustaso: 'KATSELUOIKEUS',
+ kayttooikeudet: ['VIEW'],
+ }),
+ );
+ }),
+ );
+
+ render(
+
+ Children
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.queryByText('Children')).not.toBeInTheDocument();
+ });
+ });
+
+ test('Should render children when access right feature is not enabled', async () => {
+ const OLD_ENV = { ...window._env_ };
+ window._env_ = { ...OLD_ENV, REACT_APP_FEATURE_ACCESS_RIGHTS: 0 };
+
+ render(
+
+ Children
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText('Children')).toBeInTheDocument();
+ });
+ jest.resetModules();
+ window._env_ = OLD_ENV;
});
});
-test('Should render children when access right feature is not enabled', async () => {
- const OLD_ENV = window._env_;
- window._env_.REACT_APP_FEATURE_ACCESS_RIGHTS = 0;
+describe('CheckRightsByUser', () => {
+ const ALL_RIGHTS_USER = signedInUser(AccessRightLevel.KAIKKI_OIKEUDET);
+ const VIEW_RIGHT_USER = signedInUser(AccessRightLevel.KATSELUOIKEUS);
+
+ test('Should render children on required right', async () => {
+ render(
+
+ Children
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText('Children')).toBeInTheDocument();
+ });
+ });
- render(
-
- Children
- ,
- );
+ test('Should not render children if not enough rights', async () => {
+ render(
+
+ Children
+ ,
+ );
- await waitFor(() => {
- expect(screen.getByText('Children')).toBeInTheDocument();
+ await waitFor(() => {
+ expect(screen.queryByText('Children')).not.toBeInTheDocument();
+ });
});
- jest.resetModules();
- window._env_ = OLD_ENV;
+ test('Should render children if feature not enabled regardless of permission', async () => {
+ const OLD_ENV = { ...window._env_ };
+ window._env_ = { ...OLD_ENV, REACT_APP_FEATURE_ACCESS_RIGHTS: 0 };
+
+ render(
+
+ Children
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByText('Children')).toBeInTheDocument();
+ });
+ jest.resetModules();
+ window._env_ = OLD_ENV;
+ });
});
diff --git a/src/domain/hanke/hankeUsers/UserRightsCheck.tsx b/src/domain/hanke/hankeUsers/UserRightsCheck.tsx
index a6189086f..0189ab925 100644
--- a/src/domain/hanke/hankeUsers/UserRightsCheck.tsx
+++ b/src/domain/hanke/hankeUsers/UserRightsCheck.tsx
@@ -1,13 +1,13 @@
import React from 'react';
-import useUserRightsForHanke from './hooks/useUserRightsForHanke';
-import { Rights } from './hankeUser';
+import { Rights, SignedInUser } from './hankeUser';
import { useFeatureFlags } from '../../../common/components/featureFlags/FeatureFlagsContext';
+import { usePermissionsForHanke } from './hooks/useUserRightsForHanke';
/**
* Check that user has required rights.
* If they have, render children.
*/
-function UserRightsCheck({
+export function CheckRightsByHanke({
requiredRight,
hankeTunnus,
children,
@@ -18,7 +18,7 @@ function UserRightsCheck({
hankeTunnus?: string;
children: React.ReactElement | null;
}) {
- const { data: signedInUser } = useUserRightsForHanke(hankeTunnus);
+ const { data: signedInUser } = usePermissionsForHanke(hankeTunnus);
const features = useFeatureFlags();
if (!features.accessRights) {
@@ -32,4 +32,20 @@ function UserRightsCheck({
return null;
}
-export default UserRightsCheck;
+export function CheckRightsByUser({
+ requiredRight,
+ signedInUser: userPermission,
+ children,
+}: {
+ requiredRight: keyof typeof Rights;
+ signedInUser: SignedInUser;
+ children: React.ReactElement | null;
+}) {
+ const features = useFeatureFlags();
+
+ if (!features.accessRights) {
+ return children;
+ }
+
+ return userPermission?.kayttooikeudet?.includes(requiredRight) ? children : null;
+}
diff --git a/src/domain/hanke/hankeUsers/hankeUser.ts b/src/domain/hanke/hankeUsers/hankeUser.ts
index fd18b105f..b831cffdd 100644
--- a/src/domain/hanke/hankeUsers/hankeUser.ts
+++ b/src/domain/hanke/hankeUsers/hankeUser.ts
@@ -34,6 +34,10 @@ export type SignedInUser = {
kayttooikeudet: UserRights;
};
+export type SignedInUserByHanke = {
+ [hankeTunnus: string]: SignedInUser;
+};
+
export type IdentificationResponse = {
kayttajaId: string;
hankeTunnus: string;
diff --git a/src/domain/hanke/hankeUsers/hankeUsersApi.ts b/src/domain/hanke/hankeUsers/hankeUsersApi.ts
index 5ae8bd20c..6d176e769 100644
--- a/src/domain/hanke/hankeUsers/hankeUsersApi.ts
+++ b/src/domain/hanke/hankeUsers/hankeUsersApi.ts
@@ -1,5 +1,5 @@
import api from '../../api/api';
-import { HankeUser, IdentificationResponse, SignedInUser } from './hankeUser';
+import { HankeUser, IdentificationResponse, SignedInUser, SignedInUserByHanke } from './hankeUser';
export async function getHankeUsers(hankeTunnus: string) {
const { data } = await api.get<{ kayttajat: HankeUser[] }>(`hankkeet/${hankeTunnus}/kayttajat`);
@@ -23,6 +23,11 @@ export async function getSignedInUserForHanke(hankeTunnus?: string): Promise {
+ const { data } = await api.get('hankkeet/my-permissions');
+ return data;
+}
+
export async function identifyUser(id: string) {
const { data } = await api.post('kayttajat', { tunniste: id });
return data;
diff --git a/src/domain/hanke/hankeUsers/hooks/useUserRightsForHanke.ts b/src/domain/hanke/hankeUsers/hooks/useUserRightsForHanke.ts
index a883f8407..4f5e82331 100644
--- a/src/domain/hanke/hankeUsers/hooks/useUserRightsForHanke.ts
+++ b/src/domain/hanke/hankeUsers/hooks/useUserRightsForHanke.ts
@@ -1,9 +1,9 @@
import { useQuery } from 'react-query';
-import { SignedInUser } from '../hankeUser';
-import { getSignedInUserForHanke } from '../hankeUsersApi';
+import { SignedInUser, SignedInUserByHanke } from '../hankeUser';
+import { getSignedInUserForHanke, getSignedInUserByHanke } from '../hankeUsersApi';
import { useFeatureFlags } from '../../../../common/components/featureFlags/FeatureFlagsContext';
-export default function useSignedInUserRightsForHanke(hankeTunnus?: string) {
+export function usePermissionsForHanke(hankeTunnus?: string) {
const features = useFeatureFlags();
return useQuery(
@@ -14,3 +14,11 @@ export default function useSignedInUserRightsForHanke(hankeTunnus?: string) {
},
);
}
+
+export function usePermissionsByHanke() {
+ const features = useFeatureFlags();
+
+ return useQuery(['signedInUserByHanke'], () => getSignedInUserByHanke(), {
+ enabled: features.accessRights,
+ });
+}
diff --git a/src/domain/hanke/hankeView/HankeView.tsx b/src/domain/hanke/hankeView/HankeView.tsx
index 044a992f7..54c5ba347 100644
--- a/src/domain/hanke/hankeView/HankeView.tsx
+++ b/src/domain/hanke/hankeView/HankeView.tsx
@@ -52,7 +52,7 @@ import {
import FeatureFlags from '../../../common/components/featureFlags/FeatureFlags';
import { useFeatureFlags } from '../../../common/components/featureFlags/FeatureFlagsContext';
import { SignedInUser } from '../hankeUsers/hankeUser';
-import UserRightsCheck from '../hankeUsers/UserRightsCheck';
+import { CheckRightsByHanke } from '../hankeUsers/UserRightsCheck';
type AreaProps = {
area: HankeAlue;
@@ -217,7 +217,7 @@ const HankeView: React.FC = ({
-
+
-
-
+
+
{isHankePublic ? (
) : null}
-
+
-
+
} theme="black">
{t('hankeList:buttons:endHanke')}
-
+
{!isLoading && isCancelPossible && (
-
+
-
+
)}
diff --git a/src/domain/hanke/hankeView/HankeViewContainer.tsx b/src/domain/hanke/hankeView/HankeViewContainer.tsx
index 1f1346ec5..19c6a97d8 100644
--- a/src/domain/hanke/hankeView/HankeViewContainer.tsx
+++ b/src/domain/hanke/hankeView/HankeViewContainer.tsx
@@ -5,7 +5,7 @@ import { ROUTES } from '../../../common/types/route';
import HankeDelete from '../edit/components/HankeDelete';
import useHanke from '../hooks/useHanke';
import HankeView from './HankeView';
-import useUserRightsForHanke from '../hankeUsers/hooks/useUserRightsForHanke';
+import { usePermissionsForHanke } from '../hankeUsers/hooks/useUserRightsForHanke';
type Props = {
hankeTunnus?: string;
@@ -13,7 +13,7 @@ type Props = {
const HankeViewContainer: React.FC = ({ hankeTunnus }) => {
const { data: hankeData } = useHanke(hankeTunnus);
- const { data: signedInUser } = useUserRightsForHanke(hankeTunnus);
+ const { data: signedInUser } = usePermissionsForHanke(hankeTunnus);
const getEditHankePath = useLinkPath(ROUTES.EDIT_HANKE);
const getEditRightsPath = useLinkPath(ROUTES.ACCESS_RIGHTS);
const navigate = useNavigate();
diff --git a/src/domain/hanke/portfolio/HankePortfolio.test.tsx b/src/domain/hanke/portfolio/HankePortfolio.test.tsx
index 9afaab508..2ff1c798a 100644
--- a/src/domain/hanke/portfolio/HankePortfolio.test.tsx
+++ b/src/domain/hanke/portfolio/HankePortfolio.test.tsx
@@ -6,6 +6,8 @@ import HankePortfolioComponent from './HankePortfolioComponent';
import { render, screen, waitFor } from '../../../testUtils/render';
import hankeList from '../../mocks/hankeList';
import { changeFilterDate } from '../../../testUtils/helperFunctions';
+import { USER_VIEW, signedInUserByHanke } from '../../mocks/signedInUser';
+import { SignedInUserByHanke } from '../hankeUsers/hankeUser';
const startDateLabel = 'Ajanjakson alku';
const endDateLabel = 'Ajanjakson loppu';
@@ -16,7 +18,9 @@ jest.setTimeout(30000);
describe.only('HankePortfolio', () => {
test('Changing search text filters correct number of projects', async () => {
- const { user } = render();
+ const { user } = render(
+ ,
+ );
await user.type(screen.getByLabelText('Haku'), 'Mannerheimintie autottomaksi');
await waitFor(() => {
@@ -41,7 +45,9 @@ describe.only('HankePortfolio', () => {
});
test('Changing filter startDates filters correct number of projects', async () => {
- const renderedComponent = render();
+ const renderedComponent = render(
+ ,
+ );
expect(renderedComponent.getByTestId('numberOfFilteredRows')).toHaveTextContent('2');
changeFilterDate(startDateLabel, renderedComponent, '02.10.2022');
expect(renderedComponent.getByTestId('numberOfFilteredRows')).toHaveTextContent('2');
@@ -56,7 +62,9 @@ describe.only('HankePortfolio', () => {
});
test('Changing filter endDates filters correct number of projects', async () => {
- const renderedComponent = render();
+ const renderedComponent = render(
+ ,
+ );
expect(renderedComponent.getByTestId('numberOfFilteredRows')).toHaveTextContent('2');
changeFilterDate(endDateLabel, renderedComponent, '01.10.2022');
expect(renderedComponent.getByTestId('numberOfFilteredRows')).toHaveTextContent('0');
@@ -72,7 +80,9 @@ describe.only('HankePortfolio', () => {
});
test('Changing Hanke type filters correct number of projects', async () => {
- const renderedComponent = render();
+ const renderedComponent = render(
+ ,
+ );
expect(renderedComponent.getByTestId('numberOfFilteredRows')).toHaveTextContent('2');
await renderedComponent.user.click(
renderedComponent.getByRole('button', { name: 'Tyƶn tyyppi' }),
@@ -98,13 +108,19 @@ describe.only('HankePortfolio', () => {
});
test('Having no projects renders correct text', () => {
- render();
+ render();
expect(screen.queryByText('Hankesalkussasi ei ole hankkeita')).toBeInTheDocument();
});
test('Should render edit hanke links for hankkeet that user has edit rights', async () => {
- render();
+ const hankeTunnusList = hankeList.map((hanke) => hanke.hankeTunnus);
+ const signedUserData: SignedInUserByHanke = {
+ ...signedInUserByHanke(hankeTunnusList),
+ [hankeTunnusList[0]]: USER_VIEW,
+ };
+
+ render();
await waitFor(() => {
expect(screen.queryAllByTestId('hankeEditLink')).toHaveLength(1);
@@ -112,7 +128,7 @@ describe.only('HankePortfolio', () => {
});
test('Should show draft state notification for hankkeet that are in draft state', async () => {
- render();
+ render();
expect(
screen.getAllByText(
diff --git a/src/domain/hanke/portfolio/HankePortfolioComponent.tsx b/src/domain/hanke/portfolio/HankePortfolioComponent.tsx
index c16c344d7..61c99679f 100644
--- a/src/domain/hanke/portfolio/HankePortfolioComponent.tsx
+++ b/src/domain/hanke/portfolio/HankePortfolioComponent.tsx
@@ -39,13 +39,18 @@ import { SKIP_TO_ELEMENT_ID } from '../../../common/constants/constants';
import useHankeViewPath from '../hooks/useHankeViewPath';
import { useNavigateToApplicationList } from '../hooks/useNavigateToApplicationList';
import FeatureFlags from '../../../common/components/featureFlags/FeatureFlags';
-import UserRightsCheck from '../hankeUsers/UserRightsCheck';
+import { CheckRightsByUser } from '../hankeUsers/UserRightsCheck';
+import { SignedInUser, SignedInUserByHanke } from '../hankeUsers/hankeUser';
type CustomAccordionProps = {
hanke: HankeData;
+ permission: SignedInUser;
};
-const CustomAccordion: React.FC> = ({ hanke }) => {
+const CustomAccordion: React.FC> = ({
+ hanke,
+ permission,
+}) => {
const getEditHankePath = useLinkPath(ROUTES.EDIT_HANKE);
const hankeViewPath = useHankeViewPath(hanke?.hankeTunnus);
const navigateToApplications = useNavigateToApplicationList(hanke?.hankeTunnus);
@@ -115,7 +120,7 @@ const CustomAccordion: React.FC> =
-
+
> =
>
-
+