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

IA-3955: Ignore paging param on datasource api querry used to filter groups #1975

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
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
25 changes: 23 additions & 2 deletions hat/assets/js/apps/Iaso/domains/dataSources/requests.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable no-else-return */
import React from 'react';
import { useMutation, useQueryClient } from 'react-query';
import {
getRequest,
iasoFetch,
postRequest,
putRequest,
} from 'Iaso/libs/Api.ts';
import { useSnackMutation, useSnackQuery } from 'Iaso/libs/apiHooks.ts';
import React from 'react';
import { useMutation, useQueryClient } from 'react-query';
import { openSnackBar } from '../../components/snackBars/EventDispatcher.ts';
import snackBarMessages from '../../components/snackBars/messages';
import { errorSnackBar } from '../../constants/snackBars';
Expand Down Expand Up @@ -103,6 +103,27 @@ export const useDataSourceVersions = () => {
);
};

export const useDataSourcesDropDown = () => {
return useSnackQuery(
['sourcesDropdown'],
() => getRequest('/api/datasources/dropdown/?order=name'),
undefined,
{
staleTime: 60000,
},
);
};

export const useSourceVersionDropDown = () => {
return useSnackQuery(
['sourceVersionsDropdown'],
() => getRequest('/api/sourceversions/dropdown/'),
undefined,
{
staleTime: 60000,
},
);
};
const adaptForApi = data => {
const adaptedData = { ...data };
if (data.ref_status === 'all') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import React, {
useMemo,
useCallback,
} from 'react';
import { Grid, Button } from '@mui/material';
import SearchIcon from '@mui/icons-material/Search';
import { Grid, Button } from '@mui/material';
import { useSafeIntl } from 'bluesquare-components';
import { useGetProjectsDropdownOptions } from '../../../projects/hooks/requests';
import { useDataSourceVersions } from '../../../dataSources/requests';
import { useGetDataSources } from '../../../dataSources/useGetDataSources';
import { useFilterState } from '../../../../hooks/useFilterState';
import InputComponent from '../../../../components/forms/InputComponent';
import { Project, Version } from '../../types/dataSources';
import { useFilterState } from '../../../../hooks/useFilterState';
import {
useSourceVersionDropDown,
useDataSourcesDropDown,
} from '../../../dataSources/requests';
import { useGetProjectsDropdownOptions } from '../../../projects/hooks/requests';
import { Version } from '../../types/dataSources';
import { baseUrl } from '../config';
import MESSAGES from '../messages';

Expand All @@ -33,7 +35,6 @@ type DataSource = {
label: string;
value: string;
projectIds?: string[];
projects?: Project[];
};

const Filters: FunctionComponent<Props> = ({ params }) => {
Expand All @@ -45,10 +46,9 @@ const Filters: FunctionComponent<Props> = ({ params }) => {
const { data: projects, isFetching: isFetchingProjects } =
useGetProjectsDropdownOptions();
const { data: dataSources, isLoading: areSourcesLoading } =
useGetDataSources({ ...params, ...filters });

useDataSourcesDropDown();
const { data: sourceVersions, isLoading: areSourceVersionsLoading } =
useDataSourceVersions();
useSourceVersionDropDown();

const [projectId, setProjectId] = useState<string | undefined>(
filters?.project_ids,
Expand All @@ -61,19 +61,15 @@ const Filters: FunctionComponent<Props> = ({ params }) => {
);

const dataSourceDropDown = useMemo(() => {
const allDataSources: DataSource[] = dataSources?.sources?.map(
source => {
const allProjects: Project[] = source.projects.flat();
const projectIds = allProjects.map(project =>
project?.id?.toString(),
);
return {
label: source?.name,
value: `${source?.id}`,
projectIds,
};
},
);
const allDataSources: DataSource[] = dataSources?.map(source => {
return {
label: source?.name,
value: `${source?.id}`,
projectIds: source?.projects?.map(project =>
project?.toString(),
),
};
});
if (projectId) {
return allDataSources?.filter(source =>
source?.projectIds?.includes(projectId),
Expand Down
11 changes: 5 additions & 6 deletions hat/assets/js/apps/Iaso/domains/orgUnits/groups/config.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React from 'react';
import { Chip } from '@mui/material';
import { makeStyles } from '@mui/styles';
import {
formatThousand,
IconButton,
textPlaceholder,
LinkWithLocation,
} from 'bluesquare-components';
import { Chip } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { useNavigate } from 'react-router-dom';
import GroupsDialog from './components/GroupsDialog';
import DeleteDialog from '../../../components/dialogs/DeleteDialogComponent';
import MESSAGES from './messages';
import { DateTimeCell } from '../../../components/Cells/DateTimeCell.tsx';
import DeleteDialog from '../../../components/dialogs/DeleteDialogComponent';
import { baseUrls } from '../../../constants/urls';
import { filterOrgUnitsByGroupUrl } from '../utils';
import GroupsDialog from './components/GroupsDialog';
import MESSAGES from './messages';

const useStyles = makeStyles(() => ({
groupSetChip: {
Expand Down Expand Up @@ -41,7 +41,6 @@ const TableColumns = (formatMessage, params, deleteGroup, saveGroup) => [
{
Header: formatMessage(MESSAGES.sourceVersion),
accessor: 'source_version',
sortable: false,
Cell: settings =>
settings.value !== null
? `${settings.value.data_source.name} - ${settings.value.number}`
Expand Down
18 changes: 18 additions & 0 deletions iaso/api/data_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ def has_permission(self, request, view):
return request.user and any(request.user.has_perm(perm) for perm in write_perms)


class DataSourceDropdownSerializer(serializers.ModelSerializer):
class Meta:
model = DataSource
fields = ["id", "name", "projects"]
read_only_fields = ["id", "name", "projects"]


class DataSourceViewSet(ModelViewSet):
f"""Data source API

Expand Down Expand Up @@ -276,3 +283,14 @@ def check_dhis2(self, request):
serializer.test_api()

return Response({"test": "ok"})

@action(methods=["GET"], detail=False, serializer_class=DataSourceDropdownSerializer)
def dropdown(self, request, *args):
"""To be used in dropdowns (filters)

* Read only
"""

queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
22 changes: 22 additions & 0 deletions iaso/api/source_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ def get_org_units_count(self, source_version: SourceVersion):
return source_version.orgunit_set.count()


class SourceVersionsDropdownSerializer(serializers.ModelSerializer):
data_source_name: serializers.SlugRelatedField = serializers.SlugRelatedField(
source="data_source", slug_field="name", read_only=True
)

class Meta:
model = SourceVersion
fields = ["id", "data_source", "number", "data_source_name"]
read_only_fields = ["id", "data_source", "number", "data_source_name"]


class SourceVersionViewSet(ModelViewSet):
f"""Data source API

Expand Down Expand Up @@ -163,3 +174,14 @@ def export_dhis2(self, request):
serializer.is_valid(raise_exception=True)
task = serializer.launch_export(user=request.user)
return Response({"task": TaskSerializer(instance=task).data})

@action(methods=["GET"], detail=False, serializer_class=SourceVersionsDropdownSerializer)
def dropdown(self, request, *args):
"""To be used in dropdowns (filters)

* Read only
"""

queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
9 changes: 9 additions & 0 deletions iaso/tests/api/test_data_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,12 @@ def test_datasource_filters(self):
data = self.assertJSONResponse(response, 200)
self.assertEqual(len(data["sources"]), 1)
self.assertEqual(data["sources"][0]["id"], self.data_source.pk)

def test_dropdown_datasource(self):
self.client.force_authenticate(self.joe)
response = self.client.get("/api/datasources/dropdown/?order=name")
data = self.assertJSONResponse(response, 200)
self.assertEqual(len(data), 2)
self.assertEqual(data[0]["id"], self.data_source.pk)
self.assertEqual(data[0]["name"], self.data_source.name)
self.assertEqual(data[0]["projects"], [self.project.pk])
42 changes: 42 additions & 0 deletions iaso/tests/api/test_source_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ def setUpTestData(cls):
cls.project = m.Project.objects.create(name="Project", account=cls.account, app_id="foo.bar.baz")
cls.data_source.projects.set([cls.project])

cls.account2, cls.data_source2, cls.version2, cls.project2 = cls.create_account_datasource_version_project(
source_name="GDHF source", account_name="GDHF", project_name="GDHF campaign"
)
cls.project2.account = cls.account2
cls.data_source2.account = cls.account2
cls.project2.app_id = "GDHF.campaign"
cls.project2.save()
cls.data_source2.save()
cls.user2 = cls.create_user_with_profile(username="GDHF", account=cls.account2)

def test_list_unauthorized_without_auth(self):
response = self.client.get("/api/sourceversions/")
self.assertJSONResponse(response, 401)
Expand Down Expand Up @@ -93,3 +103,35 @@ def test_list(self):
self.assertEqual(version["is_default"], False)
self.assertEqual(version["org_units_count"], 0)
self.assertEqual(version["tree_config_status_fields"], [])

def test_dropdown_sourceversions(self):
self.user.user_permissions.set([Permission.objects.get(codename=permission._SOURCES)])
self.client.force_authenticate(self.user)
response = self.client.get("/api/sourceversions/dropdown/")
data = self.assertJSONResponse(response, 200)
self.assertEqual(len(data), 1)
version = data[0]
self.assertEqual(version["id"], self.version.pk)
self.assertEqual(version["data_source"], self.data_source.pk)
self.assertEqual(version["number"], self.version.number)
self.assertEqual(version["data_source_name"], self.data_source.name)

def test_dropdown_sourceversions_without_user_authentication(self):
response = self.client.get("/api/sourceversions/dropdown/")
self.assertJSONResponse(response, 401)

def test_dropdown_sourceversions_with_user_without_permission(self):
self.client.force_authenticate(self.user)
response = self.client.get("/api/sourceversions/dropdown/")
self.assertJSONResponse(response, 403)

def test_dropdown_sourceversions_with_user_from_another_account(self):
self.user2.user_permissions.set([Permission.objects.get(codename=permission._SOURCES)])
self.client.force_authenticate(self.user2)
response = self.client.get("/api/sourceversions/dropdown/")
data = self.assertJSONResponse(response, 200)
version = data[0]
self.assertEqual(version["id"], self.version2.pk)
self.assertEqual(version["data_source"], self.data_source2.pk)
self.assertEqual(version["number"], self.version2.number)
self.assertEqual(version["data_source_name"], self.data_source2.name)
Loading