Skip to content

Commit

Permalink
error if user tries to create a place with an in-use name
Browse files Browse the repository at this point in the history
  • Loading branch information
freddieptf committed Nov 5, 2024
1 parent 496066f commit c718599
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Property | Type | Description
`contact_types.contact_properties` | Array<ConfigProperty> | Defines the attributes which are collected and set on the user's primary contact doc. See [ConfigProperty](#ConfigProperty).
`contact_types.deactivate_users_on_replace` | boolean | Controls what should happen to the defunct contact and user documents when a user is replaced. When `false`, the contact and user account will be deleted. When `true`, the contact will be unaltered and the user account will be assigned the role `deactivated`. This allows for account restoration.
`contact_types.hint` | string | Provide a brief hint or description to clarify the expected input for the property.
`contact_types.dedup_property` | string | The place's `property_name` used to prevent creation of duplicates under a certain parent.
`logoBase64` | Image in base64 | Logo image for your project

#### ConfigProperty
Expand Down
1 change: 1 addition & 0 deletions src/config/chis-ke/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@
"user_role": ["community_health_assistant"],
"username_from_place": true,
"deactivate_users_on_replace": false,
"dedup_property": "code",
"hierarchy": [
{
"friendly_name": "Sub County",
Expand Down
1 change: 1 addition & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export type ContactType = {
contact_properties: ContactProperty[];
deactivate_users_on_replace: boolean;
hint?: string;
dedup_property?: string;
};

export type HierarchyConstraint = {
Expand Down
15 changes: 15 additions & 0 deletions src/lib/cht-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,21 @@ export class ChtApi {
return { parent, sibling };
};

contactByType = async (placeType: string, property: string, value: string): Promise<{ name: String; parent: String }[]> => {
const url = `medic/_design/medic-client/_view/contacts_by_type_freetext`;
const params = {
include_docs: true,
key: JSON.stringify([placeType, property + ':' + value.toLowerCase()])
};
const resp = await this.axiosInstance.get(url, { params });
return resp.data.rows.map((row: any) => {
return {
name: row.doc.name,
parent: row.doc.parent?._id
};
});
};

getPlacesWithType = async (placeType: string)
: Promise<RemotePlace[]> => {
const url = `medic/_design/medic-client/_view/contacts_by_type_freetext`;
Expand Down
6 changes: 6 additions & 0 deletions src/services/upload.new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export class UploadNewPlace implements Uploader {
};

handlePlacePayload = async (place: Place, payload: PlacePayload): Promise<string> => {
if (place.type.dedup_property) {
const contacts = await this.chtApi.contactByType(payload.contact_type, place.type.dedup_property, payload[place.type.dedup_property]);
if (contacts.some(c => c.parent === payload.parent)) {
throw new Error(place.type.friendly + ` with ${place.type.dedup_property} "${payload[place.type.dedup_property]}" already exists`);
}
}
return await this.chtApi.createPlace(payload);
};

Expand Down
12 changes: 12 additions & 0 deletions test/services/upload-manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ describe('services/upload-manager.ts', () => {
expect(chtApi.createUser.callCount).to.eq(placeCount);
expect(places.find(p => !p.isCreated)).to.be.undefined;
});

it('err when creating place with duplicate name in parent place', async () => {
const { fakeFormData, contactType, sessionCache, chtApi } = await createMocks();
contactType.dedup_property = 'name';
const place = await PlaceFactory.createOne(fakeFormData, contactType, sessionCache, chtApi);
chtApi.contactByType.resolves([{ name: '', parent: place.asChtPayload('test').parent }]);
const uploadManager = new UploadManager();
await uploadManager.doUpload([place], chtApi);
expect(chtApi.contactByType.calledOnce).to.be.true;
expect(place.isCreated).to.be.false;
});

it('required attributes can be inherited during replacement', async () => {
const { remotePlace, sessionCache, contactType, fakeFormData, chtApi } = await createMocks();
Expand Down Expand Up @@ -392,6 +403,7 @@ async function createMocks() {
updateContactParent: sinon.stub().resolves('created-contact-id'),
createUser: sinon.stub().resolves(),

contactByType: sinon.stub().resolves([]),
getParentAndSibling: sinon.stub().resolves({ parent: {}, sibling: {} }),
createContact: sinon.stub().resolves('replacement-contact-id'),
updatePlace: sinon.stub().resolves({
Expand Down

0 comments on commit c718599

Please sign in to comment.