in src/app/functions/server/updateDataBrokerScanProfile.ts [20:141]
async function updateDataBrokerScanProfile(
onerepProfileId: number,
profileDataToUpdate: UpdateableProfileDetails,
) {
logger.info(
`Attempt to update data broker scan profile: [${onerepProfileId}]`,
);
// NOTE: The type `UpdateableProfileDetails` only makes sure we don’t pass
// the expected profile details during compile time. We are checking the
// allow listed fields as an additional safeguard to make sure we don’t make
// any unexpected changes.
for (const profileDataKey in profileDataToUpdate) {
if (
!CONST_DATA_BROKER_PROFILE_DETAIL_ALLOW_LIST.includes(
profileDataKey as keyof typeof profileDataToUpdate,
)
) {
throw new Error(`Passed invalid profile detail: [${profileDataKey}]`);
}
}
const currentProfileData = await getProfileDetails(onerepProfileId);
if (currentProfileData?.onerep_profile_id === null) {
throw new Error(`No profile found for: [${onerepProfileId}]`);
}
const updatedProfileData = {
...currentProfileData,
...profileDataToUpdate,
};
for (const detailKey in CONST_DATA_BROKER_PROFILE_DETAIL_LIMITS) {
const profileDetailKey =
detailKey as keyof typeof CONST_DATA_BROKER_PROFILE_DETAIL_LIMITS;
const profileDataItem = updatedProfileData[profileDetailKey];
if (
profileDataItem &&
profileDataItem.length >
CONST_DATA_BROKER_PROFILE_DETAIL_LIMITS[profileDetailKey]
) {
throw new Error(
`Profile detail [${profileDetailKey}] is exceeding limit: [${profileDataItem.length}]`,
);
}
}
const updatedProfileDataSanitized = {
first_name: updatedProfileData.first_name.trim(),
middle_name: updatedProfileData.middle_name?.trim(),
last_name: updatedProfileData.last_name.trim(),
first_names: updatedProfileData.first_names
.map((first_name) => first_name.trim())
.filter((value) => value),
middle_names: updatedProfileData.middle_names
.map((middle_name) => middle_name.trim())
.filter((value) => value),
last_names: updatedProfileData.last_names
.map((last_name) => last_name.trim())
.filter((value) => value),
phone_numbers: updatedProfileData.phone_numbers
.map((phone_number) => phone_number.match(/\d/g)?.join("") ?? "")
.filter((value) => value),
addresses: updatedProfileData.addresses.filter(
(value) => value.city.trim() && value.state.trim(),
),
};
const {
first_name,
last_name,
first_names,
last_names,
middle_names,
phone_numbers,
addresses,
middle_name,
} = updatedProfileDataSanitized;
// Update the remote profile details.
const remoteProfileData = {
...(middle_name && { middle_name }),
first_name,
last_name,
first_names: first_names.map((first_name) => ({
first_name,
})),
last_names: last_names.map((last_name) => ({
last_name,
})),
middle_names: middle_names.map((middle_name) => ({
middle_name,
})),
phone_numbers: phone_numbers.map((number) => ({
number,
})),
addresses,
birth_date: currentProfileData.date_of_birth.toISOString().split("T")[0],
};
await updateProfile(onerepProfileId, remoteProfileData);
// Apply the updates to the `onerep_profiles` table.
await updateProfileDetails(onerepProfileId, {
first_name,
middle_name,
last_name,
first_names,
last_names,
middle_names,
phone_numbers,
addresses,
});
// Updating profile details filters out irrelevant scan results that have
// not already been `removed`: These scan results get the event type
// `scan_result.filtered` assigned.
await refreshStoredScanResults(onerepProfileId);
logger.info(
`Data broker scan profile updated successfully: [${onerepProfileId}]`,
);
}