Skip to content

Commit

Permalink
Merge pull request #170 from bento-platform/fix/max-query-params
Browse files Browse the repository at this point in the history
fix: authorized beacon queries
  • Loading branch information
v-rocheleau authored Jul 16, 2024
2 parents 6e0d977 + 5615708 commit e8b13f8
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 21 deletions.
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;
}

0 comments on commit e8b13f8

Please sign in to comment.