Skip to content

Commit

Permalink
refactor fn to get region code, move permissions to its own file, imp…
Browse files Browse the repository at this point in the history
…rove functions names
  • Loading branch information
eperedo committed Jan 6, 2025
1 parent 61c7841 commit 1f048b7
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 85 deletions.
21 changes: 8 additions & 13 deletions src/data/repositories/ConfigD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Region } from "$/domain/entities/Region";
import { Future, FutureData } from "$/domain/entities/generic/Future";
import { ConfigRepository } from "$/domain/repositories/ConfigRepository";
import { D2Api } from "$/types/d2-api";
import { extractFirstTwoLetters, extractPrefix } from "$/utils/string";

export class ConfigD2Repository implements ConfigRepository {
constructor(private api: D2Api) {}
Expand Down Expand Up @@ -43,7 +44,8 @@ export class ConfigD2Repository implements ConfigRepository {
return d2Response.objects.map(region => ({
id: region.id,
name: region.name,
code: this.extractRegionCode(region.code),
// org. unit code includes the region code in the first two letters before the underscore
code: extractFirstTwoLetters(region.code),
}));
});
}
Expand All @@ -55,19 +57,12 @@ export class ConfigD2Repository implements ConfigRepository {
paging: false,
})
).map(d2Response => {
return d2Response.objects.map(region => ({
id: region.id,
name: region.name,
code: this.extractCode(region.name),
return d2Response.objects.map(d2UserGroup => ({
id: d2UserGroup.id,
name: d2UserGroup.name,
// user group name includes the region code in the first two letters
code: extractPrefix(d2UserGroup.name),
}));
});
}

private extractRegionCode(code: string): string {
return (code.slice(0, 2) || "").toUpperCase();
}

private extractCode(code: string): string {
return (code.split("_")[0] || "").toUpperCase();
}
}
3 changes: 1 addition & 2 deletions src/data/repositories/DataSetD2Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import {
DataSet,
DataSetList,
OrgUnit,
Permissions,
} from "$/domain/entities/DataSet";
import { Paginated } from "$/domain/entities/Paginated";
import { GetDataSetOptions } from "$/domain/repositories/DataSetRepository";
import { Future, FutureData } from "$/domain/entities/generic/Future";
import { Maybe } from "$/utils/ts-utils";
import { Id } from "$/domain/entities/Ref";
import { Permission } from "$/domain/entities/Permission";
import { Permission, Permissions } from "$/domain/entities/Permission";
import _ from "$/domain/entities/generic/Collection";
import { Project } from "$/domain/entities/Project";
import { D2ApiCategoryOption } from "$/data/repositories/D2ApiCategoryOption";
Expand Down
31 changes: 6 additions & 25 deletions src/data/repositories/DataSetD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { D2AttributeValue, MetadataPick } from "@eyeseetea/d2-api/2.36";
import { D2Api, MetadataResponse } from "$/types/d2-api";

import { apiToFuture } from "$/data/api-futures";
import { AccessData, DataSet, DataSetList } from "$/domain/entities/DataSet";
import { DataSet, DataSetList } from "$/domain/entities/DataSet";
import { Paginated } from "$/domain/entities/Paginated";
import {
DataSetName,
Expand All @@ -12,11 +12,7 @@ import {
import { Future, FutureData } from "$/domain/entities/generic/Future";
import { getUid } from "$/utils/uid";
import _ from "$/domain/entities/generic/Collection";
import {
DataSetD2Api,
OctalNotationPermission,
dataSetFieldsWithOrgUnits,
} from "$/data/repositories/DataSetD2Api";
import { DataSetD2Api, dataSetFieldsWithOrgUnits } from "$/data/repositories/DataSetD2Api";
import { Maybe } from "$/utils/ts-utils";
import { chunkRequest, runMetadata } from "$/data/utils";
import { D2Config } from "$/data/repositories/D2ApiMetadata";
Expand Down Expand Up @@ -314,11 +310,11 @@ export class DataSetD2Repository implements DataSetRepository {
}),
userGroupAccesses: _(dataSet.access)
.filter(access => access.type === "groups")
.map(access => {
.map(groupAccess => {
return {
access: this.d2DataSetApi.generateFullPermission(access.permissions),
id: access.id,
displayName: access.name,
access: this.d2DataSetApi.generateFullPermission(groupAccess.permissions),
id: groupAccess.id,
displayName: groupAccess.name,
};
})
.value(),
Expand All @@ -330,20 +326,6 @@ export class DataSetD2Repository implements DataSetRepository {
};
}

private convertSharingGroupsToAccessData(d2UserGroups: Maybe<SharingUserGroup>): AccessData[] {
if (!d2UserGroups || Object.keys(d2UserGroups).length === 0) return [];

return Object.values(d2UserGroups).map(({ id, access }) => ({
id,
permissions: {
data: this.d2DataSetApi.buildPermission(access, "data"),
metadata: this.d2DataSetApi.buildPermission(access, "metadata"),
},
name: "",
type: "groups",
}));
}

private buildDataSetElements(dataSet: DataSetToSave) {
const relatedDataElements = dataSet.indicators
.filter(indicator => indicator.type === "outcomes")
Expand Down Expand Up @@ -416,7 +398,6 @@ type D2DataSetSection = {
indicators: Ref[];
};

type SharingUserGroup = Record<Id, { id: Id; access: OctalNotationPermission }>;
const indicatorTypeLabel: Record<IndicatorAttrs["type"], string> = {
outcomes: "Outcomes",
outputs: "Outputs",
Expand Down
12 changes: 0 additions & 12 deletions src/data/repositories/RegionD2Repository.ts

This file was deleted.

23 changes: 14 additions & 9 deletions src/domain/entities/DataSet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Permission } from "$/domain/entities/Permission";
import { Permission, Permissions } from "$/domain/entities/Permission";
import { Project } from "$/domain/entities/Project";
import { Id, ISODateString, Ref } from "$/domain/entities/Ref";
import { Struct } from "$/domain/entities/generic/Struct";
Expand All @@ -10,6 +10,7 @@ import { validateOrgUnits, validateRequired } from "$/domain/entities/generic/Va
import { Indicator } from "$/domain/entities/Indicator";
import { Config, UserGroup } from "$/domain/entities/Config";
import { DataSetToSave } from "$/domain/entities/DataSetToSave";
import { extractFirstTwoLetters, extractPrefix } from "$/utils/string";

export type DataSetAttrs = {
created: ISODateString;
Expand All @@ -29,7 +30,6 @@ export type DataSetAttrs = {
};

export type OrgUnit = { id: Id; code: string; name: string; path: Id[] };
export type Permissions = { data: Permission; metadata: Permission };
export type AccessData = { id: Id; permissions: Permissions; name: string; type: AccessType };
export type AccessType = "users" | "groups";

Expand Down Expand Up @@ -57,11 +57,16 @@ export class DataSet extends Struct<DataSetAttrs>() {

updateProject(project: Maybe<Project>, config: Config): DataSet {
const name = project ? `${project.name} DataSet` : "";
const orgUnits = project ? project.orgsUnits : this.orgUnits;
const orgsUnits = project ? project.orgsUnits : this.orgUnits;

const accessGroupsFromProject = this.getAccessFromProject(project, config);

return this._update({ access: accessGroupsFromProject, project, name, orgUnits });
return this._update({
access: accessGroupsFromProject,
project,
name,
orgUnits: orgsUnits,
});
}

updateAccess(config: Config): DataSet {
Expand Down Expand Up @@ -109,7 +114,7 @@ export class DataSet extends Struct<DataSetAttrs>() {
: [];
}

validateSharingStep(): ValidationError<DataSet>[] {
validateRegionCodes(): ValidationError<DataSet>[] {
if (this.project) return [];

const regionCodesFromOrgUnits = this.getRegionCodesFromAccess();
Expand All @@ -128,7 +133,7 @@ export class DataSet extends Struct<DataSetAttrs>() {
getRegionCodesFromAccess(): string[] {
return _(this.access)
.filter(access => access.type === "groups")
.compactMap(access => access.name.split("_")[0])
.compactMap(access => extractPrefix(access.name))
.uniq()
.value();
}
Expand All @@ -146,7 +151,7 @@ export class DataSet extends Struct<DataSetAttrs>() {
private getValidationErrors(): ValidationError<DataSet>[] {
const setupErrors = this.buildSetupErrors();
const indicatorsErrors = this.validateIndicatorsStep();
const sharingErrors = this.validateSharingStep();
const sharingErrors = this.validateRegionCodes();

return [...setupErrors, ...indicatorsErrors, ...sharingErrors];
}
Expand Down Expand Up @@ -179,7 +184,7 @@ export class DataSet extends Struct<DataSetAttrs>() {
}

private getAccessFromOrgUnits(orgUnits: OrgUnit[], config: Config): AccessData[] {
const orgsUnitsCodes = orgUnits.map(orgUnit => orgUnit.code.slice(0, 2));
const orgsUnitsCodes = orgUnits.map(orgUnit => extractFirstTwoLetters(orgUnit.code));

const regions = config.regions.filter(region => orgsUnitsCodes.includes(region.code));
const regionsCodes = regions.map(region => region.code);
Expand All @@ -193,7 +198,7 @@ export class DataSet extends Struct<DataSetAttrs>() {

private getAccessFromProject(project: Maybe<Project>, config: Config): AccessData[] {
if (!project || !project.code) return [];
const regionCode = (project.code?.slice(0, 2) || "").toUpperCase();
const regionCode = extractFirstTwoLetters(project.code);

const region = config.regions.find(region => region.code === regionCode);
const userGroups = config.userGroups.filter(userGroup => userGroup.code === region?.code);
Expand Down
9 changes: 5 additions & 4 deletions src/domain/entities/Permission.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Permissions } from "$/domain/entities/DataSet";
import { Struct } from "$/domain/entities/generic/Struct";

export type PermissionAttrs = { read: boolean; write: boolean };
Expand All @@ -13,12 +12,14 @@ export class Permission extends Struct<PermissionAttrs>() {
}

static setDefaultPermissionsForGroups(isAdmin: boolean): Permissions {
const adminDataPermission = Permission.create({ read: true, write: true });
const readWritePermission = Permission.create({ read: true, write: true });
return {
data: adminDataPermission,
data: readWritePermission,
metadata: isAdmin
? adminDataPermission
? readWritePermission
: Permission.create({ read: true, write: false }),
};
}
}

export type Permissions = { data: Permission; metadata: Permission };
6 changes: 3 additions & 3 deletions src/domain/entities/__tests__/DataSet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe("DataSet", () => {
configTest
);

const errors = dataSetToSave.validateSharingStep();
const errors = dataSetToSave.validateRegionCodes();
const errorMessage = getErrorMessageFromErrors(errors);
expect(errors.length).toBeGreaterThan(0);
expect(errorMessage).toMatch("Select at least one country");
Expand All @@ -49,7 +49,7 @@ describe("DataSet", () => {
],
}).updateAccess(configTest);

const result = dataSetToSave.validateSharingStep();
const result = dataSetToSave.validateRegionCodes();
expect(result).toHaveLength(0);

expectUserGroups(dataSetToSave);
Expand All @@ -62,7 +62,7 @@ describe("DataSet", () => {
project: undefined,
}).updateProject(projectTest, configTest);

const result = dataSetToSave.validateSharingStep();
const result = dataSetToSave.validateRegionCodes();
expect(result).toHaveLength(0);

expectUserGroups(dataSetToSave);
Expand Down
6 changes: 0 additions & 6 deletions src/domain/repositories/RegionRepository.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/utils/permission.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Maybe } from "$/utils/ts-utils";
import { Permission } from "$/domain/entities/Permission";
import { Permissions } from "$/domain/entities/DataSet";
import { Permission, Permissions } from "$/domain/entities/Permission";

export const NO_ACCESS_NOTATION = "--------";

Expand Down
26 changes: 26 additions & 0 deletions src/utils/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Extracts the first two characters of a string and convert it to uppercase.
* If the input string is empty, returns an empty string.
*
* Example:
* Input: "us123"
* Output: "US"
*
*/

export function extractFirstTwoLetters(value: string): string {
return (value.slice(0, 2) || "").toUpperCase();
}

/**
* Extracts the portion of a code string before the first underscore ("_")
* and converts it to uppercase.
*
* Example:
* Input: "us_region"
* Output: "US"
*
*/
export function extractPrefix(value: string): string {
return (value.split("_")[0] || "").toUpperCase();
}
2 changes: 1 addition & 1 deletion src/webapp/components/dataset-wizard/DataSetWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export function useValidateDataSetWizard(props: {
const validationMap: ValidationStepType = {
setup: () => dataSet.validateSetup(),
indicators: () => dataSet.validateIndicatorsStep(),
share: () => dataSet.validateSharingStep(),
share: () => dataSet.validateRegionCodes(),
};

const validate = validationMap[currentStep.key];
Expand Down
9 changes: 1 addition & 8 deletions src/webapp/components/dataset-wizard/SummaryDataSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,7 @@ export const SummaryList = React.memo((props: { dataSet: DataSet; orgUnits: OrgU
.map(indicator => indicator.coreCompetency?.name || "")
.join(", ");

const regionsCodes = _(dataSet.access)
.filter(access => access.type === "groups")
.compactMap(access => {
return access.name.split("_")[0];
})
.uniq()
.value();

const regionsCodes = dataSet.getRegionCodesFromAccess();
const selectedRegions = config.regions.filter(region => regionsCodes.includes(region.code));

return (
Expand Down

0 comments on commit 1f048b7

Please sign in to comment.