Skip to content

Commit 54c147d

Browse files
m-salaudeenchris-elliott-nhsd
authored andcommitted
CCM-10429: Fix PR comments
1 parent c76441d commit 54c147d

File tree

7 files changed

+591
-80
lines changed

7 files changed

+591
-80
lines changed

data-migration/user-transfer/src/user-transfer.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ function getParameters(): Parameters {
2424
type: 'string',
2525
demandOption: true,
2626
},
27+
component: {
28+
type: 'string',
29+
demandOption: true,
30+
},
2731
})
2832
.parseSync();
2933
}
@@ -33,13 +37,13 @@ async function updateItems(
3337
parameters: Parameters
3438
): Promise<void> {
3539
for (const item of items) {
36-
console.log(item.owner.S);
40+
console.log(item.id.S, item.owner.S);
3741

3842
// Get owner id of this item
3943
const { owner, id, templateType, clientId } = item;
4044

4145
//check if owner doesn't have CLIENT#
42-
if (owner.S && !owner.S?.includes('CLIENT#')) {
46+
if (owner.S && !owner.S?.startsWith('CLIENT#')) {
4347
// check the user in cognito, if it exist then pull the client id
4448
const cognitoUser = await findCognitoUser(owner.S);
4549

@@ -65,10 +69,14 @@ async function updateItems(
6569
// if it matches make the required swaps (clientId, createdby and updatedby)
6670
// if item doesn't have a client id then create one and do the above
6771
// update the item and delete the previous one
68-
await Promise.all([
69-
updateItem(item, parameters, newClientId),
70-
deleteItem(item, parameters),
71-
]);
72+
73+
// migrate and update item
74+
await updateItem(item, parameters, newClientId);
75+
76+
// check if migration was successful
77+
78+
// delete migrated item
79+
await deleteItem(item, parameters);
7280
}
7381

7482
//
@@ -78,13 +86,10 @@ async function updateItems(
7886

7987
//migrate to a new s3 location
8088
for (const itemObject of itemObjects) {
81-
const versionId = itemObject['Key'].split('/').reverse();
8289
await Promise.all([
8390
copyObjects(
8491
owner.S as string,
8592
itemObject['Key'],
86-
id.S as string,
87-
versionId[0],
8893
clientId.S as string
8994
),
9095
// delete previous objects
Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/* eslint-disable security/detect-non-literal-fs-filename */
2-
import fs from 'node:fs';
31
import { AttributeValue } from '@aws-sdk/client-dynamodb';
42
import { Parameters } from '@/src/utils/constants';
53
import { getAccountId } from '@/src/utils/sts-utils';
@@ -23,27 +21,3 @@ export async function backupData(
2321
await writeJsonToFile(filePath, JSON.stringify(items), bucketName);
2422
console.log(`Backed up data to s3://${bucketName}/${filePath}`);
2523
}
26-
27-
export async function backupDataLocal(
28-
items: Record<string, AttributeValue>[]
29-
): Promise<void> {
30-
console.log(`Found ${items.length} results`);
31-
if (items.length <= 0) {
32-
return;
33-
}
34-
35-
const timestamp = new Date().toISOString().replaceAll(/[.:T-]/g, '_');
36-
37-
fs.writeFile(
38-
`new-data-${timestamp}-templates.json`,
39-
JSON.stringify(items),
40-
(err) => {
41-
if (err) {
42-
console.log('Error writing file:', err);
43-
} else {
44-
console.log('Successfully wrote file');
45-
}
46-
}
47-
);
48-
console.log(`Data downloaded`);
49-
}

data-migration/user-transfer/src/utils/cognito-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ async function getUserClientId(
6868
): Promise<string | undefined> {
6969
if (userGroups && userGroups.length > 0) {
7070
const clientIdGroup = userGroups?.filter((group) =>
71-
group.GroupName?.includes('client')
71+
group.GroupName?.startsWith('client:')
7272
);
7373

74-
return clientIdGroup[0].GroupName?.split(':')[0];
74+
return clientIdGroup[0].GroupName?.split(':')[1];
7575
}
7676

7777
return undefined;

data-migration/user-transfer/src/utils/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export type Parameters = {
22
sourceOwner?: string;
33
destinationOwner?: string;
44
environment: string;
5+
component: string;
56
};

data-migration/user-transfer/src/utils/ddb-utils.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import {
77
QueryCommandInput,
88
ScanCommand,
99
ScanCommandInput,
10-
TransactWriteItemsCommand,
1110
} from '@aws-sdk/client-dynamodb';
1211
import { Parameters } from '@/src/utils/constants';
1312

1413
const client = new DynamoDBClient({ region: 'eu-west-2' });
1514

1615
// change 'sandbox' back to 'app' when testing on prod environment
17-
function getTableName(environment: string) {
18-
return `nhs-notify-${environment}-sandbox-api-templates`;
16+
function getTableName(parameters: Parameters) {
17+
const { environment, component } = parameters;
18+
return `nhs-notify-${environment}-${component}-api-templates`;
1919
}
2020

2121
export async function retrieveAllTemplates(
@@ -25,9 +25,9 @@ export async function retrieveAllTemplates(
2525
let lastEvaluatedKey = undefined;
2626
do {
2727
const query: ScanCommandInput = {
28-
TableName: getTableName(parameters.environment),
28+
TableName: getTableName(parameters),
2929
FilterExpression:
30-
'attribute_exists(#owner) AND NOT contains(#owner, :subString)',
30+
'attribute_exists(#owner) AND NOT begins_with(#owner, :subString)',
3131
ExpressionAttributeNames: { '#owner': 'owner' },
3232
ExpressionAttributeValues: { ':subString': { S: 'CLIENT#' } },
3333
};
@@ -46,14 +46,11 @@ export async function retrieveTemplates(
4646
let lastEvaluatedKey = undefined;
4747
do {
4848
const query: QueryCommandInput = {
49-
TableName: getTableName(parameters.environment),
49+
TableName: getTableName(parameters),
5050
KeyConditionExpression: '#owner = :owner',
5151
ExpressionAttributeNames: {
5252
'#owner': 'owner',
5353
},
54-
ExpressionAttributeValues: {
55-
':owner': { S: parameters.sourceOwner as string },
56-
},
5754
ExclusiveStartKey: lastEvaluatedKey,
5855
};
5956

@@ -69,7 +66,7 @@ export async function updateItem(
6966
parameters: Parameters,
7067
newClientId: string
7168
): Promise<void> {
72-
const tableName = getTableName(parameters.environment);
69+
const tableName = getTableName(parameters);
7370
console.log({ item, parameters, newClientId, tableName });
7471
await client.send(
7572
new PutItemCommand({
@@ -89,10 +86,11 @@ export async function deleteItem(
8986
item: Record<string, AttributeValue>,
9087
parameters: Parameters
9188
) {
92-
const tableName = getTableName(parameters.environment);
89+
const tableName = getTableName(parameters);
9390
await client.send(
9491
new DeleteItemCommand({
9592
Key: {
93+
id: item.id,
9694
owner: item.owner,
9795
},
9896
TableName: tableName,

data-migration/user-transfer/src/utils/s3-utils.ts

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
PutObjectCommandOutput,
66
S3Client,
77
NotFound,
8-
ListObjectsV2Command,
8+
paginateListObjectsV2,
9+
HeadObjectCommand,
910
} from '@aws-sdk/client-s3';
1011
import { Parameters } from '@/src/utils/constants';
1112
import { getAccountId } from './sts-utils';
@@ -34,20 +35,33 @@ export async function writeJsonToFile(
3435
);
3536
}
3637

38+
async function listItemObjectsWithPaginator(bucket: string) {
39+
const itemObjects = [];
40+
const paginatedItemObjects = paginateListObjectsV2(
41+
{
42+
client: s3Client,
43+
pageSize: 1000,
44+
},
45+
{ Bucket: bucket }
46+
);
47+
48+
for await (const page of paginatedItemObjects) {
49+
if (page.Contents) {
50+
itemObjects.push(...page.Contents.map((item) => item.Key));
51+
}
52+
}
53+
54+
return itemObjects.length > 0 ? itemObjects : [];
55+
}
56+
3757
export async function getItemObjects(
3858
templateId: string
3959
): Promise<unknown | void> {
4060
try {
41-
const items = await s3Client.send(
42-
new ListObjectsV2Command({
43-
Bucket: sourceBucket,
44-
})
45-
);
61+
const items = await listItemObjectsWithPaginator(sourceBucket as string);
4662

47-
if (items.Contents && items.Contents.length > 0) {
48-
const itemObjects = items.Contents?.filter((item) =>
49-
item['Key']?.includes(templateId)
50-
);
63+
if (items.length > 0) {
64+
const itemObjects = items.filter((item) => item.includes(templateId));
5165
return itemObjects;
5266
} else {
5367
throw Error;
@@ -64,25 +78,35 @@ export async function getItemObjects(
6478
export async function copyObjects(
6579
owner: string,
6680
sourceKey: string,
67-
templateId: string,
68-
versionId: string,
6981
clientId: string
7082
) {
7183
const destinationKey = sourceKey.replace(owner, clientId);
72-
console.log({ sourceKey, destinationKey });
84+
85+
// Get existing metadata
86+
const head = await s3Client.send(
87+
new HeadObjectCommand({
88+
Bucket: sourceBucket,
89+
Key: sourceKey,
90+
})
91+
);
92+
93+
const existingMetadata = head.Metadata || {};
94+
95+
// 2. Update just the one key necessary
96+
const { ['owner']: _, ...rest } = existingMetadata;
97+
const updatedMetadata = {
98+
...rest,
99+
['client-id']: clientId,
100+
};
73101
return await s3Client.send(
74102
new CopyObjectCommand({
75103
CopySource: `${sourceBucket}/${sourceKey}`,
76104
Bucket: sourceBucket,
77105
Key: destinationKey,
78-
Metadata: {
79-
'client-id': clientId,
80-
'file-type': 'pdf-template',
81-
'template-id': templateId,
82-
'version-id': versionId,
83-
},
106+
Metadata: updatedMetadata,
84107
MetadataDirective: 'REPLACE',
85108
TaggingDirective: 'COPY',
109+
ContentType: head.ContentType,
86110
})
87111
);
88112
}
@@ -102,24 +126,16 @@ export async function backupObject(parameters: Parameters) {
102126
const bucketName = `nhs-notify-${accountId}-eu-west-2-main-acct-migration-backup`;
103127
const key = `ownership-transfer/templates/s3-objects/${environment}/`;
104128

105-
const items = await s3Client.send(
106-
new ListObjectsV2Command({
107-
Bucket: sourceBucket,
108-
})
109-
);
110-
111-
if (items['Contents'] && items['Contents'].length <= 0) {
112-
return;
113-
}
129+
const items = await listItemObjectsWithPaginator(sourceBucket as string);
114130

115-
console.log(`Found ${items['Contents']?.length} objects in S3`);
131+
console.log(`Found ${items.length} objects in S3`);
116132

117-
for (const item of items['Contents']) {
133+
for (const item of items) {
118134
await s3Client.send(
119135
new CopyObjectCommand({
120136
Bucket: bucketName,
121-
Key: key + item.Key,
122-
CopySource: `${sourceBucket}/${item.Key}`,
137+
Key: key + item,
138+
CopySource: `${sourceBucket}/${item}`,
123139
MetadataDirective: 'COPY',
124140
})
125141
);

0 commit comments

Comments
 (0)