Skip to content

Commit

Permalink
Merge branch 'main' into 17-retries
Browse files Browse the repository at this point in the history
  • Loading branch information
kennsippell authored Feb 20, 2024
2 parents 64a724e + e536fc0 commit 9ff7868
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 19 deletions.
81 changes: 79 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cht-user-management",
"version": "1.0.11",
"version": "1.0.13",
"main": "dist/index.js",
"dependencies": {
"@fastify/autoload": "^5.8.0",
Expand All @@ -21,6 +21,7 @@
"fastify": "^4.23.2",
"fastify-sse-v2": "^3.1.2",
"jsonwebtoken": "^9.0.2",
"jszip": "^3.10.1",
"libphonenumber-js": "^1.10.48",
"liquidjs": "^10.9.2",
"lodash": "^4.17.21",
Expand Down
2 changes: 1 addition & 1 deletion src/public/app/nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<span class="material-symbols-outlined">group_add</span> Upload
</a>

<a class="navbar-item" href="/files/credentials" download="{{ session.authInfo.domain }}.users.csv">
<a class="navbar-item" href="/files/credentials">
<span class="material-symbols-outlined">save_as</span> Save Credentials
</a>

Expand Down
45 changes: 35 additions & 10 deletions src/routes/files.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import _ from 'lodash';
import { FastifyInstance } from 'fastify';
import { transform, stringify } from 'csv/sync';
import { Config } from '../config';
import { stringify } from 'csv/sync';
import { Config, ContactType } from '../config';
import SessionCache from '../services/session-cache';
import Place from '../services/place';
import JSZip from 'jszip';

export default async function files(fastify: FastifyInstance) {
fastify.get('/files/template/:placeType', async (req) => {
Expand All @@ -20,19 +20,44 @@ export default async function files(fastify: FastifyInstance) {
return stringify([columns]);
});

fastify.get('/files/credentials', async (req) => {
fastify.get('/files/credentials', async (req, reply) => {
const sessionCache: SessionCache = req.sessionCache;
const results = new Map<ContactType, String[][]>();
const places = sessionCache.getPlaces();
const refinedRecords = transform(places, (place: Place) => {
return [
place.type.friendly,
places.forEach(place => {
const parent = Config.getParentProperty(place.type);
const record = [
place.hierarchyProperties[parent.property_name],
place.name,
place.contact.properties.name,
place.contact.properties.phone,
place.creationDetails.username,
place.creationDetails.password,
place.creationDetails.disabledUsers,
];
const result = results.get(place.type) || [];
result.push(record);
results.set(place.type, result);
});

return stringify(refinedRecords);
const zip = new JSZip();
results.forEach((places, contactType) => {
const parent = Config.getParentProperty(contactType);
const columns = [
parent.friendly_name,
contactType.friendly,
'name',
'phone',
'username',
'password'
];
zip.file(
`${contactType.name}.csv`,
stringify(places, {
columns: columns,
header: true,
})
);
});
reply.header('Content-Disposition', `attachment; filename="${Date.now()}_${req.chtSession.authInfo.friendly}_users.zip"`);
return zip.generateNodeStream();
});
}
18 changes: 14 additions & 4 deletions src/services/place.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,28 @@ export default class Place {
}, {});
};

const contactAttributes = (contactType: string) => {
const RESERVED_CONTACT_TYPES = ['district_hospital', 'health_center', 'clinic', 'person'];

if (RESERVED_CONTACT_TYPES.includes(contactType)) {
return { type: contactType };
}

return {
type: 'contact',
contact_type: contactType,
};
};
return {
...filteredProperties(this.properties),
...contactAttributes(this.type.name),
_id: this.isReplacement ? this.resolvedHierarchy[0]?.id : this.id,
type: 'contact',
contact_type: this.type.name,
parent: this.resolvedHierarchy[1]?.id,
user_attribution,
contact: {
...filteredProperties(this.contact.properties),
...contactAttributes(this.contact.type.contact_type),
name: this.contact.name,
type: 'contact',
contact_type: this.contact.type.contact_type,
user_attribution,
}
};
Expand Down
28 changes: 27 additions & 1 deletion test/services/place.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from 'chai';

import Place from '../../src/services/place';
import { mockSimpleContactType } from '../mocks';
import { mockSimpleContactType, mockValidContactType } from '../mocks';
import RemotePlaceResolver from '../../src/lib/remote-place-resolver';

describe('service place.ts', () => {
Expand Down Expand Up @@ -109,4 +109,30 @@ describe('service place.ts', () => {
const actual = place.generateUsername();
expect(actual).to.eq('migwani_itoloni');
});

it('asChtPayload uses contact_type by default', () => {
const contactType = mockValidContactType('string', undefined);
Object.freeze(contactType);

const place = new Place(contactType);
const actual = place.asChtPayload('usr');
expect(actual.type).to.eq('contact');
expect(actual.contact.type).to.eq('contact');
expect(actual.contact_type).to.eq(contactType.name);
});

it('#46 - asChtPayload should use type:health_center instead of contact_type:health_center', () => {
const contactType = mockValidContactType('string', undefined);
contactType.name = 'health_center';
contactType.contact_type = 'person';
Object.freeze(contactType);

const place = new Place(contactType);
const actual = place.asChtPayload('usr');
expect(actual.type).to.eq(contactType.name);
expect(actual.contact_type).to.be.undefined;

expect(actual.contact.type).to.eq(contactType.contact_type);
expect(actual.contact.contact_type).to.be.undefined;
});
});

0 comments on commit 9ff7868

Please sign in to comment.