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

add sharing step #472

Merged
merged 9 commits into from
Jan 13, 2025
68 changes: 68 additions & 0 deletions src/data/repositories/ConfigD2Repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { apiToFuture } from "$/data/api-futures";
import { metadataCodes } from "$/data/repositories/D2ApiMetadata";
import { Config, UserGroup } from "$/domain/entities/Config";
import { Project } from "$/domain/entities/Project";
import { Region, extractRegionCode } from "$/domain/entities/Region";
import { Future, FutureData } from "$/domain/entities/generic/Future";
import { ConfigRepository } from "$/domain/repositories/ConfigRepository";
import { D2Api } from "$/types/d2-api";

export class ConfigD2Repository implements ConfigRepository {
constructor(private api: D2Api) {}

get(): FutureData<Config> {
return this.getOrgUnitLevelGroup().flatMap(orgUnitLevel => {
return Future.joinObj({
regions: this.getRegions(orgUnitLevel),
userGroups: this.getUserGroups(),
});
});
}

private getOrgUnitLevelGroup(): FutureData<number> {
return apiToFuture(
this.api.models.organisationUnitLevels.get({
fields: { id: true, level: true },
filter: { name: { eq: metadataCodes.orgUnitLevels.country } },
})
).flatMap(d2Response => {
const orgUnitLevel = d2Response.objects[0];
return orgUnitLevel
? Future.success(orgUnitLevel.level)
: Future.error(new Error("Country level not found"));
});
}

private getRegions(level: number): FutureData<Region[]> {
return apiToFuture(
this.api.models.organisationUnits.get({
fields: { id: true, code: true, name: true },
filter: { level: { eq: String(level) }, children: { gt: "0" } },
paging: false,
})
).map(d2Response => {
return d2Response.objects.map(region => ({
id: region.id,
name: region.name,
// org. unit code includes the region code in the first two letters before the underscore
code: Project.extractCode(region.code),
}));
});
}

private getUserGroups(): FutureData<UserGroup[]> {
return apiToFuture(
this.api.models.userGroups.get({
fields: { id: true, name: true },
paging: false,
})
).map(d2Response => {
return d2Response.objects.map(d2UserGroup => ({
id: d2UserGroup.id,
name: d2UserGroup.name,
// user group name includes the region code in the first two letters
code: extractRegionCode(d2UserGroup.name),
}));
});
}
}
15 changes: 12 additions & 3 deletions src/data/repositories/D2ApiCategoryOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,27 @@ export class D2ApiCategoryOption {
return apiToFuture(
this.api.models.categoryOptions.get({
filter: { id: { in: categoryOptionsIds } },
fields: { id: true, displayName: true, lastUpdated: true },
fields: { id: true, code: true, displayName: true, lastUpdated: true },
paging: false,
})
).map(response => response.objects);
});
}
}

export type D2CategoryOptionType = { id: string; displayName: string; lastUpdated: ISODateString };
export type D2CategoryOptionType = {
code: string;
id: string;
displayName: string;
lastUpdated: ISODateString;
};
export type D2CategoryOptionDates = {
startDate: Maybe<ISODateString>;
endDate: Maybe<ISODateString>;
};

export type D2CategoryOptionWithDates = D2CategoryOptionType & D2CategoryOptionDates;
export type D2CategoryOptionWithDates = D2CategoryOptionType &
D2CategoryOptionDates & {
code: string;
organisationUnits: { id: string; code: string; displayName: string; path: string }[];
};
1 change: 1 addition & 0 deletions src/data/repositories/D2ApiMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const metadataCodes = {
localIndicator: "Local Indicators",
},
indicatorGroupSets: { theme: "Theme", status: "Status" },
orgUnitLevels: { country: "Country" },
};

const metadataFields = {
Expand Down
12 changes: 7 additions & 5 deletions src/data/repositories/DataSetD2Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ 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";
import { D2ApiConfig, D2Config } from "$/data/repositories/D2ApiMetadata";
import { Pager } from "@eyeseetea/d2-api/api";
import { D2OrgUnit } from "$/data/repositories/OrgUnitD2Repository";

export class DataSetD2Api {
private d2ApiCategoryOption: D2ApiCategoryOption;
Expand Down Expand Up @@ -149,6 +149,8 @@ export class DataSetD2Api {
name: categoryOption.displayName,
lastUpdated: categoryOption.lastUpdated,
isOpen: false,
orgsUnits: [],
code: categoryOption.code,
});
});
});
Expand Down Expand Up @@ -207,6 +209,7 @@ export class DataSetD2Api {
orgUnits: d2DataSet.organisationUnits
? d2DataSet.organisationUnits.map((ou): OrgUnit => {
return {
code: ou.code,
id: ou.id,
name: ou.displayName,
path: ou.path.split("/").slice(1),
Expand Down Expand Up @@ -261,7 +264,7 @@ export class DataSetD2Api {
return ccCodeParts.join("_");
}

private buildPermission(permissions: string, permissionType: "data" | "metadata"): Permission {
buildPermission(permissions: string, permissionType: "data" | "metadata"): Permission {
if (permissionType === "metadata") {
const { canRead, canWrite } = this.buildPermissionByType(permissions, permissionType);
return Permission.create({ read: canRead, write: canWrite });
Expand Down Expand Up @@ -314,13 +317,12 @@ export const dataSetFields = {

export const dataSetFieldsWithOrgUnits = {
...dataSetFields,
organisationUnits: { id: true, displayName: true, path: true },
organisationUnits: { id: true, code: true, displayName: true, path: true },
};

type D2DataSetFields = MetadataPick<{
dataSets: { fields: typeof dataSetFields };
}>["dataSets"][number];

type D2DataSet = { organisationUnits?: D2OrgUnit[] } & D2DataSetFields;
type D2OrgUnit = { id: Id; path: string; displayName: string };
export type OctalNotationPermission = string;
10 changes: 5 additions & 5 deletions src/data/repositories/DataSetD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,12 @@ export class DataSetD2Repository implements DataSetRepository {
};
}),
userGroupAccesses: _(dataSet.access)
.compactMap(access => {
if (access.type !== "groups") return undefined;
.filter(access => access.type === "groups")
.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 Down
4 changes: 2 additions & 2 deletions src/data/repositories/DataSetTestRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ export class DataSetTestRepository implements DataSetRepository {
throw new Error("Method not implemented.");
}
getByIds(): FutureData<DataSet[]> {
throw new Error("Method not implemented.");
return Future.success([]);
}
save(): FutureData<void> {
throw new Error("Method not implemented.");
return Future.void();
}
delete(): FutureData<void> {
throw new Error("Method not implemented.");
Expand Down
5 changes: 3 additions & 2 deletions src/data/repositories/OrgUnitD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class OrgUnitD2Repository implements OrgUnitRepository {
const d2OrgsUnits$ = chunkRequest<D2OrgUnit>(ids, idsToFetch => {
return apiToFuture(
this.api.models.organisationUnits.get({
fields: { id: true, displayName: true, path: true },
fields: { id: true, code: true, displayName: true, path: true },
filter: { id: { in: idsToFetch } },
paging: false,
})
Expand All @@ -23,6 +23,7 @@ export class OrgUnitD2Repository implements OrgUnitRepository {
return d2OrgsUnits$.map(d2OrgUnits => {
return d2OrgUnits.map(d2OrgUnit => {
return {
code: d2OrgUnit.code,
id: d2OrgUnit.id,
name: d2OrgUnit.displayName,
path: d2OrgUnit.path.split("/").slice(1),
Expand All @@ -32,4 +33,4 @@ export class OrgUnitD2Repository implements OrgUnitRepository {
}
}

type D2OrgUnit = { id: string; displayName: string; path: string };
export type D2OrgUnit = { id: string; code: string; displayName: string; path: string };
30 changes: 28 additions & 2 deletions src/data/repositories/ProjectD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ export class ProjectD2Repository implements ProjectRepository {
return apiToFuture(
this.api.models.categoryOptions.get({
fields: {
code: true,
id: true,
displayName: true,
startDate: true,
endDate: true,
lastUpdated: true,
organisationUnits: { id: true, code: true, displayName: true, path: true },
},
filter: { "categories.code": { eq: code } },
order: "displayName:asc",
Expand All @@ -58,10 +60,17 @@ export class ProjectD2Repository implements ProjectRepository {
return categoryOptions.map(d2CategoryOption => {
return Project.build({
dataSets: [],
code: d2CategoryOption.code,
id: d2CategoryOption.id,
name: d2CategoryOption.displayName,
lastUpdated: d2CategoryOption.lastUpdated,
isOpen: this.isProjectOpen(d2CategoryOption.startDate, d2CategoryOption.endDate),
orgsUnits: d2CategoryOption.organisationUnits.map(orgUnit => ({
id: orgUnit.id,
code: orgUnit.code,
name: orgUnit.displayName,
path: orgUnit.path.split("/").slice(1),
})),
});
});
}
Expand Down Expand Up @@ -109,7 +118,13 @@ export class ProjectD2Repository implements ProjectRepository {
},
page: options.paging.page,
pageSize: options.paging.pageSize,
fields: { id: true, displayName: true, lastUpdated: true },
fields: {
id: true,
code: true,
displayName: true,
lastUpdated: true,
organisationUnits: { id: true, code: true, path: true, displayName: true },
},
order: this.buildOrderParam(options),
})
).flatMap(d2Response => {
Expand Down Expand Up @@ -153,13 +168,22 @@ export class ProjectD2Repository implements ProjectRepository {
});
}

private buildProject(d2CategoryOption: D2CategoryOptionType): Project {
private buildProject(
d2CategoryOption: D2CategoryOptionType & { organisationUnits: D2OrgUnit[] }
): Project {
return Project.build({
code: d2CategoryOption.code,
id: d2CategoryOption.id,
name: d2CategoryOption.displayName,
lastUpdated: d2CategoryOption.lastUpdated,
dataSets: [],
isOpen: false,
orgsUnits: d2CategoryOption.organisationUnits.map(orgUnit => ({
code: orgUnit.code,
id: orgUnit.id,
name: orgUnit.displayName,
path: orgUnit.path.split("/").slice(1),
})),
});
}

Expand All @@ -168,3 +192,5 @@ export class ProjectD2Repository implements ProjectRepository {
return `${options.sorting.field}:${options.sorting.order}`;
}
}

type D2OrgUnit = { id: Id; code: string; displayName: string; path: string };
6 changes: 6 additions & 0 deletions src/domain/entities/Config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { NamedCodeRef } from "$/domain/entities/Ref";
import { Region } from "$/domain/entities/Region";

export type UserGroup = NamedCodeRef;

export type Config = { regions: Region[]; userGroups: UserGroup[] };
Loading
Loading