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

data whitelisting #732

Merged
merged 14 commits into from
Jul 19, 2023
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
6 changes: 4 additions & 2 deletions __tests__/gui/data_whitelist.feature
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Feature: Data Whitelist
And I click on "Demographics" in Data Mapper
And I click on "Language" in Data Mapper
And I click on "Language most spoken at home" in Data Mapper
And I confirm that available subindicators are "20-24,30-35" in Data Mapper
And I click on "30-35" in Data Mapper
And I expand the filter dialog
Then I confirm that the choropleth is filtered by "gender:Female" at index 0
Expand All @@ -20,7 +21,7 @@ Feature: Data Whitelist

# Rich data panel default filter
When I expand Rich Data Panel
Then I confirm that "gender:Female" is applied to "Language most spoken at home" as a site-wide filter
Then I confirm that "gender:Female" is applied to "Language most spoken at home"

Scenario: Restricting filter values and setting profile-wide filters on a view
Given I am on the Wazimap Homepage Test View
Expand All @@ -31,6 +32,7 @@ Feature: Data Whitelist
And I click on "Demographics" in Data Mapper
And I click on "Language" in Data Mapper
And I click on "Language most spoken at home" in Data Mapper
And I confirm that available subindicators are "15-19,20-24,30-35" in Data Mapper
And I click on "30-35" in Data Mapper
And I expand the filter dialog
Then I confirm that the choropleth is filtered by "gender:Male" at index 0
Expand All @@ -42,4 +44,4 @@ Feature: Data Whitelist

# Rich data panel default filter
When I expand Rich Data Panel
Then I confirm that "gender:Male" is applied to "Language most spoken at home" as a site-wide filter
Then I confirm that "gender:Male" is applied to "Language most spoken at home"
21 changes: 16 additions & 5 deletions __tests__/gui/data_whitelist/data_whitelist.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {Given, Then, When} from "cypress-cucumber-preprocessor/steps";
import {
collapseMyViewPanel, confirmChartIsFiltered,
confirmChoroplethIsFiltered, confirmDropdownOptions,
confirmChartIsFiltered,
confirmChoroplethIsFiltered,
confirmDropdownOptions,
expandChoroplethFilterDialog,
expandDataMapper, expandRichDataPanel,
gotoHomepage, selectChoroplethDropdownOption,
expandDataMapper,
expandRichDataPanel,
gotoHomepage,
selectChoroplethDropdownOption,
setupInterceptions,
waitUntilGeographyIsLoaded
} from "../common_cy_functions/general";
Expand Down Expand Up @@ -57,7 +60,7 @@ When('I expand Rich Data Panel', () => {
expandRichDataPanel();
})

Then(/^I confirm that "([^"]*)" is applied to "([^"]*)" as a site\-wide filter$/, function (filter, chartTitle) {
Then(/^I confirm that "([^"]*)" is applied to "([^"]*)"$/, function (filter, chartTitle) {
const filters = filter.split(':');
confirmChartIsFiltered(filters[0], filters[1], chartTitle);
});
Expand All @@ -66,3 +69,11 @@ Given('I am on the Wazimap Homepage Test View', () => {
setupInterceptions(profiles, all_details, profile, themes, {}, [], profile_indicator_summary, profile_indicator_data);
cy.visit("/?view=test");
})

When(/^I confirm that available subindicators are "([^"]*)" in Data Mapper$/, function (options) {
let optionsArr = options.split(',');
cy.get('.data-mapper').find('.subIndicator-item').should('have.length', optionsArr.length)
cy.get('.subIndicator-item').each(($div, index) => {
expect($div.text()).equal(optionsArr[index]);
})
});
9 changes: 9 additions & 0 deletions __tests__/gui/data_whitelist/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
"English",
"Afrikaans",
"This is ignored"
],
"age": [
"20-24",
"30-35"
]
},
"views": {
Expand All @@ -52,6 +56,11 @@
"English",
"Sepedi",
"isiXhosa"
],
"age": [
"15-19",
"20-24",
"30-35"
]
}
}
Expand Down
3 changes: 3 additions & 0 deletions __tests__/gui/data_whitelist/profile_indicator_summary.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"subcategories": {
"Language": {
"order": 242,
"id": 1,
"name": "Language",
"indicators": {
"Language most spoken at home": {
Expand Down Expand Up @@ -108,6 +109,7 @@
},
"Migration": {
"order": 243,
"id": 2,
"name": "Migration",
"indicators": {
"Region of birth": {
Expand Down Expand Up @@ -211,6 +213,7 @@
},
"South African Citizenship": {
"order": 246,
"id": 3,
"name": "South African Citizenship",
"indicators": {
"Citizenship": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"age": [
"15-35 (ZA)",
"15-24 (Intl)",
"30-35"
"30-35",
"15-19",
],
"race": [
"Coloured",
Expand Down
99 changes: 99 additions & 0 deletions src/js/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ export class API extends Observable {
this.busyLoggingIn = false;
this.failedLogins = 0;
this.abortController = null;
this._restrictValues = {};
}

set restrictValues(value) {
this._restrictValues = value;
}

get restrictValues() {
return this._restrictValues;
}

getToken() {
Expand All @@ -33,6 +42,44 @@ export class API extends Observable {
return this.loadUrl(url, this.abortController);
}

getProfileWrapper(profileId, areaCode, version) {
const self = this;

return self.getProfile(profileId, areaCode, version).then(data => {
Object.keys(data.profile.profile_data).forEach(categoryName => {
const subcategories = data.profile.profile_data[categoryName].subcategories;
Object.keys(subcategories).forEach(subcategoryName => {
const indicators = subcategories[subcategoryName].indicators;
if (indicators != null) {
Object.keys(indicators).forEach((indicator) => {
let indicatorData = indicators[indicator];

Object.keys(self.restrictValues).forEach(restrictKey => {
// does not contain the key
// or
// key value is one of the restrictValue
indicatorData.data = indicatorData.data.filter(x => Object.keys(x).indexOf(restrictKey) < 0 ||
self.restrictValues[restrictKey].indexOf(x[restrictKey]) >= 0);

// filter metadata
indicatorData.metadata.groups = indicatorData.metadata.groups.map(group => {
if (group.name === restrictKey) {
group.subindicators = group.subindicators.filter(element => self.restrictValues[restrictKey].includes(element));
}

return group;
})

})
});
}
})
})

return data;
});
}

getProfileWithoutVersion(profileId, areaCode) {
const url = `${this.baseUrl}/all_details/profile/${profileId}/geography/${areaCode}/?skip-children=true&format=json`;
return this.loadUrl(url, this.abortController);
Expand All @@ -53,6 +100,24 @@ export class API extends Observable {
return this.loadUrl(url, this.abortController);
}

getIndicatorChildDataWrapper(profileId, areaCode, indicatorId) {
const self = this;

return self.getIndicatorChildData(profileId, areaCode, indicatorId).then(data => {
Object.keys(data).forEach((geo) => {
Object.keys(self.restrictValues).forEach(restrictKey => {
// does not contain the key
// or
// key value is one of the restrictValue
data[geo] = data[geo].filter(x => Object.keys(x).indexOf(restrictKey) < 0
|| self.restrictValues[restrictKey].indexOf(x[restrictKey]) >= 0);
})
});

return data;
});
}

loadThemes(profileId) {
const url = `${this.baseUrl}/profile/${profileId}/points/themes/?format=json`;
return this.loadUrl(url);
Expand Down Expand Up @@ -193,6 +258,40 @@ export class API extends Observable {
return this.loadUrl(url, this.abortController);
}

async getIndicatorSummaryWrapper(profileId, areaCode, version) {
const self = this;

return self.getIndicatorSummary(profileId, areaCode, version).then(data => {
Object.keys(data).forEach((category) => {
let categoryData = data[category];
let subCategories = categoryData.subcategories;

Object.keys(subCategories).forEach((subCategory) => {
let subCategoryData = subCategories[subCategory];
let indicators = subCategoryData.indicators;

if (indicators != null) {
Object.keys(indicators).forEach((indicator) => {
let indicatorData = indicators[indicator];

Object.keys(self.restrictValues).forEach(restrictKey => {
indicatorData.metadata.groups = indicatorData.metadata.groups.map(group => {
if (group.name === restrictKey) {
group.subindicators = group.subindicators.filter(element => self.restrictValues[restrictKey].includes(element));
}

return group;
})
})
});
}
});
});

return data;
});
}

cancelAndInitAbortController() {
if (this.abortController !== null) {
//on first request this.abortController is null
Expand Down
Loading
Loading