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

chore: address feedback around admin reindex endpoints #657

Draft
wants to merge 63 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
7e0a00f
refactor: move contacts and cases types to HrmTypes module
GPaoloni May 3, 2024
0c62562
chore: license header
GPaoloni May 3, 2024
03d3a21
chore: moved hrm types to own package hrm-types
GPaoloni May 6, 2024
02e996f
chore: pull hrm-types from correct package
GPaoloni May 6, 2024
9e44933
chore: added dependencies to search-index-consumer
GPaoloni May 6, 2024
b3a140c
chore: move types around to ease lambda implementation
GPaoloni May 7, 2024
e3d37ca
chore: implement search-index-consumer indexing
GPaoloni May 7, 2024
bd80def
Merge remote-tracking branch 'origin/master' into gian_CHI-2717-2
GPaoloni May 7, 2024
d5ec170
chore: fix TS complaints
GPaoloni May 7, 2024
43456e2
fix: add emtpy parent if missing in contact document
GPaoloni May 8, 2024
83c1777
fix: wrong import
GPaoloni May 8, 2024
9417567
chore: added logic to update documents via elasticsearch client
GPaoloni May 10, 2024
2bc2d8e
chore: update hrm-search-config package to generate case update scrip…
GPaoloni May 10, 2024
340bdd2
chore: search-index-consumer rework
GPaoloni May 10, 2024
7cf998c
fix: small TS errors
GPaoloni May 10, 2024
f5b3bef
debug
GPaoloni May 10, 2024
c0cabb1
fix: contemplate case where case index payloads is undefined
GPaoloni May 10, 2024
8097a42
chore: fix unit tests
GPaoloni May 13, 2024
a10662d
debug logs
GPaoloni May 13, 2024
08e28c9
debug
GPaoloni May 13, 2024
c59db2a
chore: factor out convertToScriptUpdate logic
GPaoloni May 14, 2024
4101c0c
chore: refactor search-index-consumer to improve redability
GPaoloni May 14, 2024
7df50bd
chore: lint
GPaoloni May 14, 2024
06f0254
chore: removed comments
GPaoloni May 14, 2024
b208991
chore: moved channelTypes constants to hrm-types module
GPaoloni May 16, 2024
acb1245
chore fetch transcripts from S3
GPaoloni May 16, 2024
0982e55
debug
GPaoloni May 16, 2024
9ef239b
chore: add packages/s3-client to tsconfig.build
GPaoloni May 16, 2024
c0a62d1
chore: remove debug logs
GPaoloni May 17, 2024
8387804
chore: add support for parameterized ES config
GPaoloni May 21, 2024
d6e187b
chore: provide ssm parameter name from env vars to ES config
GPaoloni May 21, 2024
9a2703f
Merge remote-tracking branch 'origin/gian_CHI-2717-2' into gian_CHI-2…
GPaoloni May 21, 2024
7c51980
chore: rename env var for ES config
GPaoloni May 21, 2024
2178928
chore: added hrm-search-config package to hrm-core
GPaoloni May 22, 2024
0b8307e
chore: added wrapper to publish index-search messages to correspondin…
GPaoloni May 22, 2024
7913bbf
Merge remote-tracking branch 'origin/master' into gian_CHI-2723
GPaoloni May 22, 2024
21e0087
feat: added reindexContacts service and admin endpoint
mythilytm May 30, 2024
055fb3c
chore: factored out autoPagination & maxPermissins for reuse
GPaoloni May 30, 2024
8712186
chore: introduce processInBatch, reusing logic from autoPaginate
GPaoloni May 30, 2024
63bb44c
chore: fix lint
GPaoloni May 30, 2024
8016445
Merge remote-tracking branch 'origin' into CHI-2702-reindex-contacts
mythilytm May 31, 2024
0045119
feat: wire admin endpoint for reindexing
mythilytm May 31, 2024
b89e8d3
fix admin route to use account id from req url
mythilytm Jun 3, 2024
f5f0f95
feat: build script for reindexing contacts and cases
mythilytm Jun 3, 2024
971d2d9
change options for indexing
mythilytm Jun 4, 2024
7da3080
sqs debug
mythilytm Jun 4, 2024
27d1239
chore: publish pending index-search jobs on write/update ops for cont…
GPaoloni Jun 5, 2024
c2da2b5
revert logs
mythilytm Jun 5, 2024
a9952e1
Merge branch 'gian_CHI-2723' into CHI-2702-reindex-contacts
mythilytm Jun 5, 2024
26d5dee
Merge remote-tracking branch 'origin/master' into CHI-2702-reindex-co…
GPaoloni Jun 6, 2024
ded5bf6
Merge remote-tracking branch 'origin/CHI-2702-reindex-contacts' into …
GPaoloni Jun 6, 2024
4dda995
chore: added admin cases routes, implemented reindex case endpoint
GPaoloni Jun 6, 2024
1d6e226
chore: simpify path for reindex endpoints
GPaoloni Jun 6, 2024
ee189e0
CHI-2760 Build script for reindexing contacts and cases (#652)
mythilytm Jun 7, 2024
062e34c
Merge remote-tracking branch 'origin/CHI-2702-reindex-contacts' into …
GPaoloni Jun 7, 2024
936c768
chore: moved auto paginate logic into batch-processing module
GPaoloni Jun 7, 2024
a26bc2a
chore: add dependency and import from appropriate place
GPaoloni Jun 7, 2024
5b71d57
chore: added missing tsconfig files
GPaoloni Jun 7, 2024
1955b11
chore: use correct src dir
GPaoloni Jun 7, 2024
bb6673b
chore: tidy package.json
GPaoloni Jun 7, 2024
7c1a91a
chore: fixed build issues (I think)
GPaoloni Jun 7, 2024
8094150
chore: removed unnecessary dependency
GPaoloni Jun 7, 2024
f0a29d5
chore: resolved deps (hopefully)
GPaoloni Jun 8, 2024
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
46 changes: 46 additions & 0 deletions hrm-domain/hrm-core/case/adminCaseRoutesV0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import type { Request, Response, NextFunction } from 'express';
import { isErr, mapHTTPError } from '@tech-matters/types';
import { SafeRouter, publicEndpoint } from '../permissions';
import { reindexCases } from './caseReindexService';

const adminContactsRouter = SafeRouter();

// admin POST endpoint to reindex contacts. req body has accountSid, dateFrom, dateTo
adminContactsRouter.post(
'/reindex',
publicEndpoint,
async (req: Request, res: Response, next: NextFunction) => {
const { hrmAccountId } = req;
const { dateFrom, dateTo } = req.body;

const result = await reindexCases(hrmAccountId, dateFrom, dateTo);

if (isErr(result)) {
return next(
mapHTTPError(result, {
InvalidParameterError: 400,
}),
);
}

res.json(result.data);
},
);

export default adminContactsRouter.expressRouter;
74 changes: 74 additions & 0 deletions hrm-domain/hrm-core/case/caseReindexService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import { HrmAccountId, newErr, newOkFromData } from '@tech-matters/types';
import { CaseService, searchCases } from './caseService';
import { publishCaseToSearchIndex } from '../jobs/search/publishToSearchIndex';
import { maxPermissions } from '../permissions';
import {
AsyncProcessor,
SearchFunction,
processInBatch,
} from '@tech-matters/batch-processing';
import formatISO from 'date-fns/formatISO';

export const reindexCases = async (
accountSid: HrmAccountId,
dateFrom: string,
dateTo: string,
) => {
try {
const filters = {
updatedAt: {
from: formatISO(new Date(dateFrom)),
to: formatISO(new Date(dateTo)),
},
};

const searchFunction: SearchFunction<CaseService> = async limitAndOffset => {
const res = await searchCases(
accountSid,
{
limit: limitAndOffset.limit.toString(),
offset: limitAndOffset.offset.toString(),
},
{},
{ filters },
maxPermissions,
);
return { records: res.cases as CaseService[], count: res.count };
};

const asyncProcessor: AsyncProcessor<CaseService, void> = async casesResult => {
const promises = casesResult.records.map(caseObj => {
return publishCaseToSearchIndex({
accountSid,
case: caseObj,
operation: 'index',
});
});

await Promise.all(promises);
};

await processInBatch(searchFunction, asyncProcessor);

return newOkFromData('Successfully indexed contacts');
} catch (error) {
console.error('Error reindexing contacts', error);
return newErr({ error, message: 'Error reindexing contacts' });
}
};
46 changes: 46 additions & 0 deletions hrm-domain/hrm-core/contact/adminContactRoutesV0.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import type { Request, Response, NextFunction } from 'express';
import { isErr, mapHTTPError } from '@tech-matters/types';
import { SafeRouter, publicEndpoint } from '../permissions';
import { reindexContacts } from './contactsReindexService';

const adminContactsRouter = SafeRouter();

// admin POST endpoint to reindex contacts. req body has accountSid, dateFrom, dateTo
adminContactsRouter.post(
'/reindex',
publicEndpoint,
async (req: Request, res: Response, next: NextFunction) => {
const { hrmAccountId } = req;
const { dateFrom, dateTo } = req.body;

const result = await reindexContacts(hrmAccountId, dateFrom, dateTo);

if (isErr(result)) {
return next(
mapHTTPError(result, {
InvalidParameterError: 400,
}),
);
}

res.json(result.data);
},
);

export default adminContactsRouter.expressRouter;
67 changes: 67 additions & 0 deletions hrm-domain/hrm-core/contact/contactsReindexService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import { HrmAccountId, newErr, newOkFromData } from '@tech-matters/types';
import { Contact, searchContacts } from './contactService';
import { publishContactToSearchIndex } from '../jobs/search/publishToSearchIndex';
import { maxPermissions } from '../permissions';
import {
AsyncProcessor,
SearchFunction,
processInBatch,
} from '@tech-matters/batch-processing';

export const reindexContacts = async (
accountSid: HrmAccountId,
dateFrom: string,
dateTo: string,
) => {
try {
const searchParameters = {
dateFrom,
dateTo,
};

const searchFunction: SearchFunction<Contact> = async limitAndOffset => {
const res = await searchContacts(
accountSid,
searchParameters,
limitAndOffset,
maxPermissions,
);
return { records: res.contacts, count: res.count };
};

const asyncProcessor: AsyncProcessor<Contact, void> = async contactsResult => {
const promises = contactsResult.records.map(contact => {
return publishContactToSearchIndex({
accountSid,
contact,
operation: 'index',
});
});

await Promise.all(promises);
};

await processInBatch(searchFunction, asyncProcessor);

return newOkFromData('Successfully indexed contacts');
} catch (error) {
console.error('Error reindexing contacts', error);
return newErr({ error, message: 'Error reindexing contacts' });
}
};
1 change: 0 additions & 1 deletion hrm-domain/hrm-core/jobs/search/publishToSearchIndex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const publishToSearchIndex = async ({
JSON.stringify(message),
);
const queueUrl = await getSsmParameter(PENDING_INDEX_QUEUE_SSM_PATH);

return await sendSqsMessage({
queueUrl,
message: JSON.stringify(message),
Expand Down
1 change: 1 addition & 0 deletions hrm-domain/hrm-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"dependencies": {
"@tech-matters/hrm-search-config": "^1.0.0",
"@tech-matters/hrm-types": "^1.0.0",
"@tech-matters/batch-processing": "^1.0.0",
"@tech-matters/http": "^1.0.0",
"@tech-matters/resources-service": "^1.0.0",
"@tech-matters/s3-client": "^1.0.0",
Expand Down
31 changes: 23 additions & 8 deletions hrm-domain/hrm-core/permissions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@
*/

import { SafeRouterRequest } from './safe-router';
import { rulesMap } from './rulesMap';
import { type InitializedCan, initializeCanForRules } from './initializeCanForRules';
import { type RulesFile } from './rulesMap';
import type { Request, Response, NextFunction } from 'express';
import type { TwilioUser } from '@tech-matters/twilio-worker-auth';
import type { AccountSID } from '@tech-matters/types';

export { SafeRouter, publicEndpoint } from './safe-router';
export { rulesMap } from './rulesMap';
export { Actions, actionsMaps } from './actions';

import { InitializedCan, initializeCanForRules } from './initializeCanForRules';
import { RulesFile } from './rulesMap';
import type { Request, Response, NextFunction } from 'express';
import { TwilioUser } from '@tech-matters/twilio-worker-auth';
import { AccountSID } from '@tech-matters/types';
export { type Actions, actionsMaps } from './actions';
export { rulesMap };

declare global {
namespace Express {
Expand Down Expand Up @@ -72,3 +72,18 @@ export const setupPermissions =
export type RequestWithPermissions = SafeRouterRequest & {
can: InitializedCan;
};

export const maxPermissions: {
user: TwilioUser;
can: () => boolean;
permissions: (typeof rulesMap)[keyof typeof rulesMap];
} = {
can: () => true,
user: {
accountSid: 'ACxxx',
workerSid: 'WKxxx',
roles: ['supervisor'],
isSupervisor: true,
},
permissions: rulesMap.open,
};
8 changes: 7 additions & 1 deletion hrm-domain/hrm-core/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import referrals from './referral/referral-routes-v0';
import permissions from './permissions/permissions-routes-v0';
import profiles from './profile/profileRoutesV0';
import adminProfiles from './profile/adminProfileRoutesV0';
import adminContacts from './contact/adminContactRoutesV0';
import adminCases from './case/adminCaseRoutesV0';
import { Permissions } from './permissions';

export const HRM_ROUTES: {
Expand All @@ -49,7 +51,11 @@ export const apiV0 = (rules: Permissions) => {
export const ADMIN_ROUTES: {
path: string;
routerFactory: () => Router;
}[] = [{ path: '/profiles', routerFactory: () => adminProfiles }];
}[] = [
{ path: '/profiles', routerFactory: () => adminProfiles },
{ path: '/contacts', routerFactory: () => adminContacts },
{ path: '/cases', routerFactory: () => adminCases },
];

export const adminApiV0 = () => {
const router: IRouter = Router();
Expand Down
2 changes: 2 additions & 0 deletions hrm-domain/hrm-service/scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ admin-cli
| ├── create: # Create a new profile flag
| ├── edit: # Edit an existing profile flag
| ├── delete: # Delete an existing profile flag
├── reindex
| ├── hrm: # Reindex contacts and cases based on date range
```

### Usage
Expand Down
25 changes: 25 additions & 0 deletions hrm-domain/hrm-service/scripts/admin-commands/reindex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

export const command = 'reindex <command>';
export const desc = 'admin endpoints for reindexing contacts and cases';

export const builder = function (yargs) {
return yargs.commandDir('reindex', {
exclude: /^(index|_)/,
extensions: ['ts'],
});
};
Loading
Loading