From dae2a6c14db87b002938795be4c7487da231d06f Mon Sep 17 00:00:00 2001
From: JoshuaVulcan <38018017+JoshuaVulcan@users.noreply.github.com>
Date: Mon, 22 Jul 2024 10:50:18 -0700
Subject: [PATCH] feat:wiring up new back-end permissions for data export
functionality
---
src/GlobalMenuDrawer/index.js | 91 +++++++++++++--------
src/GlobalMenuDrawer/index.test.js | 127 +++++++++++++++++++++--------
src/constants/index.js | 2 +
3 files changed, 153 insertions(+), 67 deletions(-)
diff --git a/src/GlobalMenuDrawer/index.js b/src/GlobalMenuDrawer/index.js
index 7b828f791..6bfa9c68e 100644
--- a/src/GlobalMenuDrawer/index.js
+++ b/src/GlobalMenuDrawer/index.js
@@ -67,6 +67,8 @@ const GlobalMenuDrawer = () => {
const { t } = useTranslation('menu-drawer', { keyPrefix: 'globalMenuDrawer' });
const hasPatrolViewPermissions = usePermissions(PERMISSION_KEYS.PATROLS, PERMISSIONS.READ);
+ const hasObservationExportPermissions = usePermissions(PERMISSION_KEYS.OBSERVATIONS_EXPORT, PERMISSIONS.READ);
+ const hasEventExportPermissions = usePermissions(PERMISSION_KEYS.EVENTS_EXPORT, PERMISSIONS.READ);
const isMediumLayoutOrLarger = useMatchMedia(BREAKPOINTS.screenIsMediumLayoutOrLarger);
@@ -79,37 +81,62 @@ const GlobalMenuDrawer = () => {
const token = useSelector((state) => state.data.token);
const user = useSelector((state) => state.data.user);
- const modals = useMemo(() => [
- ...(dailyReportEnabled ? [{
- title: t('dailyReportModal.title'),
- content: DailyReportModal,
- modalProps: { className: 'daily-report-modal' },
- }] : []),
- {
- title: t('fieldReportsModal.title'),
- content: DataExportModal,
- url: 'activity/events/export',
- paramString: calcEventFilterForRequest(),
- children:
{t('fieldReportsModal.content')}
- },
- ...(kmlExportEnabled ? [{
- title: t('masterKMLModal.title'),
- content: KMLExportModal,
- url: 'subjects/kml/root',
- modalProps: { className: 'kml-export-modal' },
- }] : []),
- {
- title: t('subjectInformationModal.title'),
- content: DataExportModal,
- url: 'trackingmetadata/export',
- },
- {
- title: t('subjectReportsModal.title'),
- content: DataExportModal,
- url: 'trackingdata/export',
- },
- // eslint-disable-next-line react-hooks/exhaustive-deps
- ], [dailyReportEnabled, eventFilter, eventTypes, kmlExportEnabled, t]);
+ const modals = useMemo(() => {
+ const modals = [
+ ];
+
+ if (dailyReportEnabled) {
+ modals.push(
+ {
+ title: t('dailyReportModal.title'),
+ content: DailyReportModal,
+ modalProps: { className: 'daily-report-modal' },
+ }
+ );
+ }
+
+ if (kmlExportEnabled) {
+ modals.push(
+ {
+ title: t('masterKMLModal.title'),
+ content: KMLExportModal,
+ url: 'subjects/kml/root',
+ modalProps: { className: 'kml-export-modal' },
+ }
+ );
+ }
+
+ if (hasObservationExportPermissions) {
+ modals.push(...[
+ {
+ title: t('subjectInformationModal.title'),
+ content: DataExportModal,
+ url: 'trackingmetadata/export',
+ },
+ {
+ title: t('subjectReportsModal.title'),
+ content: DataExportModal,
+ url: 'trackingdata/export',
+ }
+ ]);
+ }
+
+ if (hasEventExportPermissions) {
+ modals.push(
+ {
+ title: t('fieldReportsModal.title'),
+ content: DataExportModal,
+ url: 'activity/events/export',
+ paramString: calcEventFilterForRequest(),
+ children: {t('fieldReportsModal.content')}
+ }
+ );
+ }
+
+ return modals;
+ /* eslint-disable-next-line react-hooks/exhaustive-deps */
+ }, [eventFilter, hasEventExportPermissions, hasObservationExportPermissions, dailyReportEnabled, kmlExportEnabled, t]);
+
const showPatrols = !!patrolFlagEnabled && !!hasPatrolViewPermissions;
const onModalClick = useCallback((modal, analyticsTitle = REPORT_EXPORT_CATEGORY) => {
@@ -140,7 +167,7 @@ const GlobalMenuDrawer = () => {
if (siteInput) {
siteInput.value = window.location.hostname;
}
- const username = (selectedUserProfile?.id ? selectedUserProfile: user)?.username;
+ const username = (selectedUserProfile?.id ? selectedUserProfile : user)?.username;
const userInput = selectSupportFormFieldByLabelText('ER Requestor Name');
if (userInput) {
diff --git a/src/GlobalMenuDrawer/index.test.js b/src/GlobalMenuDrawer/index.test.js
index 9a7069cae..80d9f12eb 100644
--- a/src/GlobalMenuDrawer/index.test.js
+++ b/src/GlobalMenuDrawer/index.test.js
@@ -36,11 +36,11 @@ jest.mock('../hooks/useNavigate', () => jest.fn());
describe('GlobalMenuDrawer', () => {
let addModalMock, fetchTableauDashboardMock, hideDrawerMock, navigate, store, useMatchMediaMock, useNavigateMock;
beforeEach(() => {
- addModalMock = jest.fn(() => () => {});
+ addModalMock = jest.fn(() => () => { });
addModal.mockImplementation(addModalMock);
fetchTableauDashboardMock = jest.fn(() => () => Promise.resolve({ display_url: 'tableau url ' }));
fetchTableauDashboard.mockImplementation(fetchTableauDashboardMock);
- hideDrawerMock = jest.fn(() => () => {});
+ hideDrawerMock = jest.fn(() => () => { });
hideDrawer.mockImplementation(hideDrawerMock);
useMatchMediaMock = jest.fn(() => true);
useMatchMedia.mockImplementation(useMatchMediaMock);
@@ -59,6 +59,8 @@ describe('GlobalMenuDrawer', () => {
user: {
permissions: {
[PERMISSION_KEYS.PATROLS]: [PERMISSIONS.READ],
+ [PERMISSION_KEYS.EVENTS_EXPORT]: [PERMISSIONS.READ],
+ [PERMISSION_KEYS.OBSERVATIONS_EXPORT]: [PERMISSIONS.READ],
}
},
},
@@ -320,22 +322,41 @@ describe('GlobalMenuDrawer', () => {
expect(addModal.mock.calls[0][0].title).toBe('Daily Report');
});
- test('opens the field reports modal when clicking the Field Reports button', async () => {
- render(
-
-
-
- );
+ describe('exporting field reports', () => {
+ const getFieldEventsButton = () => screen.queryByText('Field Events');
- expect(addModal).toHaveBeenCalledTimes(0);
+ test('does not show the Field Reports button if a user doesn\'t have export event data permissions', () => {
+ delete store.data.user.permissions[PERMISSION_KEYS.EVENTS_EXPORT];
- const fieldReportsButton = await screen.findByText('Field Events');
- userEvent.click(fieldReportsButton);
+ render(
+
+
+
+ );
- expect(addModal).toHaveBeenCalledTimes(1);
- expect(addModal.mock.calls[0][0].title).toBe('Field Events');
+ const fieldEventsButton = getFieldEventsButton();
+
+ expect(fieldEventsButton).toBeNull();
+ });
+
+ test('opens the field reports modal when clicking the Field Reports button', () => {
+ render(
+
+
+
+ );
+
+ expect(addModal).toHaveBeenCalledTimes(0);
+
+ const fieldEventsButton = getFieldEventsButton();
+ userEvent.click(fieldEventsButton);
+
+ expect(addModal).toHaveBeenCalledTimes(1);
+ expect(addModal.mock.calls[0][0].title).toBe('Field Events');
+ });
});
+
test('opens the kml export modal when clicking the Master KML button', async () => {
render(
@@ -352,38 +373,74 @@ describe('GlobalMenuDrawer', () => {
expect(addModal.mock.calls[0][0].title).toBe('Subject KML');
});
- test('opens the subject information modal when clicking the Subject Information button', async () => {
- render(
-
-
-
- );
- expect(addModal).toHaveBeenCalledTimes(0);
+ describe('exporting subject information', () => {
+ const getSubjectInfoButton = () => screen.queryByText('Subject Summary');
- const subjectInformationButton = await screen.findByText('Subject Summary');
- userEvent.click(subjectInformationButton);
+ test('does not show the subject information link if a user doesn\'t have export observation data permissions', () => {
+ delete store.data.user.permissions[PERMISSION_KEYS.OBSERVATIONS_EXPORT];
- expect(addModal).toHaveBeenCalledTimes(1);
- expect(addModal.mock.calls[0][0].title).toBe('Subject Summary');
+ render(
+
+
+
+ );
+
+ const subjectInfoButton = getSubjectInfoButton();
+ expect(subjectInfoButton).toBeNull();
+ });
+
+ test('opens the subject information modal when clicking the Subject Information button', () => {
+ render(
+
+
+
+ );
+
+ expect(addModal).toHaveBeenCalledTimes(0);
+
+ const subjectInfoButton = getSubjectInfoButton();
+ userEvent.click(subjectInfoButton);
+
+ expect(addModal).toHaveBeenCalledTimes(1);
+ expect(addModal.mock.calls[0][0].title).toBe('Subject Summary');
+ });
});
- test('opens the subject reports modal when clicking the Subject Reports button', async () => {
- render(
-
-
-
- );
+ describe('exporting subject reports', () => {
+ const getSubjectReportsButton = () => screen.queryByText('Observations');
- expect(addModal).toHaveBeenCalledTimes(0);
+ test('does not show the subject reports link if a user doesn\'t have export observation data permissions', () => {
+ delete store.data.user.permissions[PERMISSION_KEYS.OBSERVATIONS_EXPORT];
- const subjectReportsButton = await screen.findByText('Observations');
- userEvent.click(subjectReportsButton);
+ render(
+
+
+
+ );
- expect(addModal).toHaveBeenCalledTimes(1);
- expect(addModal.mock.calls[0][0].title).toBe('Observations');
+ const subjectReportsButton = getSubjectReportsButton();
+ expect(subjectReportsButton).toBeNull();
+ });
+
+ test('opens the subject reports modal when clicking the Subject Reports button', () => {
+ render(
+
+
+
+ );
+
+ expect(addModal).toHaveBeenCalledTimes(0);
+
+ const subjectReportsButton = getSubjectReportsButton();
+ userEvent.click(subjectReportsButton);
+
+ expect(addModal).toHaveBeenCalledTimes(1);
+ expect(addModal.mock.calls[0][0].title).toBe('Observations');
+ });
});
+
test('lists links to various privacy and data policies', async () => {
render(
diff --git a/src/constants/index.js b/src/constants/index.js
index 2c5657082..bbc36dcbf 100644
--- a/src/constants/index.js
+++ b/src/constants/index.js
@@ -297,6 +297,8 @@ export const PERMISSION_KEYS = {
PATROLS: 'patrol',
PATROL_TYPES: 'patroltype',
MESSAGING: 'message',
+ OBSERVATIONS_EXPORT: 'export_observation_data',
+ EVENTS_EXPORT: 'export_event_data',
};