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

fix: authorized beacon queries #170

Merged
merged 2 commits into from
Jul 16, 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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bento_public",
"version": "0.19.0",
"version": "0.19.1",
"description": "A publicly accessible portal for clinical datasets, where users are able to see high-level statistics of the data available through predefined variables of interest and search the data using limited variables at a time. This portal allows users to gain a generic understanding of the data available (secure and firewalled) without the need to access it directly. Initially, this portal facilitates the search in English language only, but the French language will be added at a later time.",
"main": "index.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions src/js/components/Beacon/BeaconQueryUi.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState, ReactNode } from 'react';
import { useAppSelector, useAppDispatch, useTranslationDefault, useBeaconWithAuthIfAllowed } from '@/hooks';
import { useAppSelector, useAppDispatch, useTranslationDefault, useQueryWithAuthIfAllowed } from '@/hooks';
import { Button, Card, Col, Form, Row, Space, Tooltip, Typography } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons';
import { useIsAuthenticated } from 'bento-auth-js';
Expand Down Expand Up @@ -91,7 +91,7 @@ const BeaconQueryUi = () => {
}, [isFetchingBeaconConfig, isAuthenticated]);

// Disables max query param if user is authenticated and authorized
useBeaconWithAuthIfAllowed();
useQueryWithAuthIfAllowed();

// beacon request handling

Expand Down
5 changes: 5 additions & 0 deletions src/js/components/Search/MakeQueryOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ const MakeQueryOption = ({ queryField }: MakeQueryOptionProps) => {
dispatch(makeGetKatsuPublic());
};

// TODO: allow disabling max query parameters for authenticated and authorized users when Katsu has AuthZ
// useQueryWithAuthIfAllowed()
// const maxQueryParametersRequired = useAppSelector((state) => state.config.maxQueryParametersRequired);
// const hasMaxFilters = maxQueryParametersRequired && queryParamCount >= maxQueryParameters;
// const disabled = isChecked ? false : hasMaxFilters;
const disabled = isChecked ? false : queryParamCount >= maxQueryParameters;

return (
Expand Down
5 changes: 5 additions & 0 deletions src/js/components/Search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ const RoutedSearch: React.FC = () => {
attemptedFetch,
} = useAppSelector((state) => state.query);

// TODO: allow disabling max query parameters for authenticated and authorized users when Katsu has AuthZ
// const maxQueryParametersRequired = useAppSelector((state) => state.config.maxQueryParametersRequired);
// const allowedQueryParamsCount = maxQueryParametersRequired ? maxQueryParameters : queryParamCount;

const searchFields = useMemo(
() => searchSections.flatMap(({ fields }) => fields.map((field) => ({ id: field.id, options: field.options }))),
[searchSections]
Expand All @@ -45,6 +49,7 @@ const RoutedSearch: React.FC = () => {

const queryParamArray = Array.from(query.entries()).map(([key, value]) => ({ key, value }));

// TODO: to disable max query parameters, slice with allowedQueryParamsCount instead
const validQueryParamArray = queryParamArray
.filter(({ key, value }) => validateQueryParam(key, value))
.slice(0, maxQueryParameters);
Expand Down
1 change: 1 addition & 0 deletions src/js/constants/configConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PORTAL_URL } from '@/config';
export const MAX_CHARTS = 3;

export const katsuPublicOverviewUrl = `${PORTAL_URL}/api/metadata/api/public_overview`;
export const katsuPublicRulesUrl = `${PORTAL_URL}/api/metadata/api/public_rules`;
export const searchFieldsUrl = `${PORTAL_URL}/api/metadata/api/public_search_fields`;
export const katsuUrl = `${PORTAL_URL}/api/metadata/api/public`;
export const provenanceUrl = `${PORTAL_URL}/api/metadata/api/public_dataset`;
Expand Down
20 changes: 9 additions & 11 deletions src/js/features/config/config.store.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import axios from 'axios';
import { katsuPublicOverviewUrl } from '@/constants/configConstants';
import { katsuPublicRulesUrl } from '@/constants/configConstants';
import { printAPIError } from '@/utils/error.util';
import { ServiceInfoStore, ServicesResponse } from '@/types/services';
import { RootState } from '@/store';
import { PUBLIC_URL } from '@/config';
import { KatsuPublicOverviewResponse } from '@/types/configResponse';
import { DiscoveryRules } from '@/types/configResponse';

export const makeGetConfigRequest = createAsyncThunk<KatsuPublicOverviewResponse, void, { rejectValue: string }>(
export const makeGetConfigRequest = createAsyncThunk<DiscoveryRules, void, { rejectValue: string }>(
'config/getConfigData',
(_, { rejectWithValue }) =>
// TODO: should be project/dataset scoped with url params
axios
.get(katsuPublicOverviewUrl)
.get(katsuPublicRulesUrl)
.then((res) => res.data)
.catch(printAPIError(rejectWithValue))
);
Expand Down Expand Up @@ -57,13 +58,10 @@ const configStore = createSlice({
builder.addCase(makeGetConfigRequest.pending, (state) => {
state.isFetchingConfig = true;
});
builder.addCase(
makeGetConfigRequest.fulfilled,
(state, { payload }: PayloadAction<KatsuPublicOverviewResponse>) => {
state.maxQueryParameters = payload.max_query_parameters;
state.isFetchingConfig = false;
}
);
builder.addCase(makeGetConfigRequest.fulfilled, (state, { payload }: PayloadAction<DiscoveryRules>) => {
state.maxQueryParameters = payload.max_query_parameters;
state.isFetchingConfig = false;
});
builder.addCase(makeGetConfigRequest.rejected, (state) => {
state.isFetchingConfig = false;
});
Expand Down
4 changes: 2 additions & 2 deletions src/js/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ export const useHasResourcePermissionWrapper = (resource: Resource, permission:
};
};

export const useBeaconWithAuthIfAllowed = () => {
export const useQueryWithAuthIfAllowed = () => {
const dispatch = useAppDispatch();
const { hasPermission } = useHasResourcePermissionWrapper(RESOURCE_EVERYTHING, queryData);
useEffect(() => {
if (hasPermission) {
console.log('Beacon: user authorized for no max query parameters.');
console.log('Beacon | Search: user authorized for no max query parameters.');
dispatch(setMaxQueryParametersRequired(false));
}
}, [dispatch, hasPermission]);
Expand Down
4 changes: 2 additions & 2 deletions src/js/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
BentoAuthContextProvider,
nop,
} from 'bento-auth-js';
import { useBeaconWithAuthIfAllowed } from '@/hooks';
import { useQueryWithAuthIfAllowed } from '@/hooks';

// Store and configuration imports
import { store } from './store';
Expand Down Expand Up @@ -97,7 +97,7 @@ const App = () => {

useSessionWorkerTokenRefresh(sessionWorker, createSessionWorker, nop);

useBeaconWithAuthIfAllowed();
useQueryWithAuthIfAllowed();

return (
<ConfigProvider theme={{ components: { Menu: { iconSize: 20 } } }}>
Expand Down
5 changes: 4 additions & 1 deletion src/js/types/configResponse.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export interface KatsuPublicOverviewResponse {
count_threshold: number;
counts: object;
fields: object;
layout: [];
}

export interface DiscoveryRules {
max_query_parameters: number;
count_threshold: number;
}