Skip to content

Commit

Permalink
Adding backwards compatibility for name identity (#4791)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Sachs <[email protected]>
  • Loading branch information
galvana and adamsachs committed Apr 12, 2024
1 parent 9a100ef commit 08bc968
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The types of changes are:
- Fixed issue when loading the privacy request detail page [#4775](https://github.com/ethyca/fides/pull/4775)
- Fixed connection test for Aircall [#4756](https://github.com/ethyca/fides/pull/4756/pull)
- Fixed issues connecting to Redshift due to character encoding and SSL requirements [#4790](https://github.com/ethyca/fides/pull/4790)
- Fixed the way the name identity is handled in the Privacy Center [#4791](https://github.com/ethyca/fides/pull/4791)

### Developer Experience
- Build a `fides-types.d.ts` type declaration file to include alongside our FidesJS developer docs [#4772](https://github.com/ethyca/fides/pull/4772)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ModalViews } from "~/components/modals/types";
import { FormErrorMessage } from "~/components/FormErrorMessage";
import {
emailValidation,
nameValidation,
phoneValidation,
} from "~/components/modals/validation";
import { useConfig } from "~/features/common/config.slice";
Expand Down Expand Up @@ -64,7 +65,15 @@ const usePrivacyRequestForm = ({
const formik = useFormik<FormValues>({
initialValues: {
...Object.fromEntries(
Object.entries(identityInputs).map(([key]) => [key, ""])
Object.entries(identityInputs)
.filter(
([key, value]) =>
key === "name" ||
key === "phone" ||
key === "email" ||
(typeof value === "object" && value.label)
)
.map(([key]) => [key, ""])
),
...Object.fromEntries(
Object.entries(customPrivacyRequestFields)
Expand All @@ -80,13 +89,21 @@ const usePrivacyRequestForm = ({

// extract identity input values
const identityInputValues = Object.fromEntries(
Object.entries(action.identity_inputs ?? {}).map(([key, field]) => {
const value = fallbackNull(values[key]);
if (typeof field === "string") {
return [key, value];
}
return [key, { label: field.label, value }];
})
Object.entries(action.identity_inputs ?? {})
// we have to support name as an identity_input for legacy purposes
// but we ignore it since it's not unique enough to be treated as an identity
.filter(([key]) => key !== "name")
.map(([key, field]) => {
const value = fallbackNull(values[key]);
if (typeof field === "string") {
if (key === "phone") {
// eslint-disable-next-line no-param-reassign
key = "phone_number";
}
return [key, value];
}
return [key, { label: field.label, value }];
})
);

// extract custom privacy request field values
Expand Down Expand Up @@ -183,6 +200,7 @@ const usePrivacyRequestForm = ({
}
},
validationSchema: Yup.object().shape({
name: nameValidation(identityInputs?.name),
email: emailValidation(identityInputs?.email).test(
"one of email or phone entered",
"You must enter either email or phone",
Expand Down Expand Up @@ -211,7 +229,13 @@ const usePrivacyRequestForm = ({
),
...Object.fromEntries(
Object.entries(identityInputs)
.filter(([key]) => key !== "email" && key !== "phone")
.filter(
([key, value]) =>
key !== "email" &&
key !== "phone" &&
key !== "name" &&
typeof value !== "string"
)
.map(([key, value]) => {
const customIdentity = value as CustomIdentity;
return [
Expand Down Expand Up @@ -306,29 +330,82 @@ const PrivacyRequestForm: React.FC<PrivacyRequestFormProps> = ({
</Text>
))}
<Stack>
{Object.entries(identityInputs).map(([key, item]) => (
{identityInputs.name ? (
<FormControl
key={key}
id={key}
isInvalid={touched[key] && Boolean(errors[key])}
isRequired
id="name"
isInvalid={touched.name && Boolean(errors.name)}
isRequired={identityInputs.name === "required"}
>
<FormLabel fontSize="sm">
{typeof item === "string"
? key[0].toUpperCase() + key.slice(1)
: item.label}
</FormLabel>
{key === "phone" ? (
<PhoneInput
id={key}
name={key}
onChange={(value) => {
setFieldValue(key, value, true);
}}
onBlur={handleBlur}
value={values[key]}
/>
) : (
<FormLabel fontSize="sm">Name</FormLabel>
<Input
id="name"
name="name"
focusBorderColor="primary.500"
placeholder="Michael Brown"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
<FormErrorMessage>{errors.name}</FormErrorMessage>
</FormControl>
) : null}
{identityInputs.email ? (
<FormControl
id="email"
isInvalid={touched.email && Boolean(errors.email)}
isRequired={identityInputs.email === "required"}
>
<FormLabel fontSize="sm">Email</FormLabel>
<Input
id="email"
name="email"
type="email"
focusBorderColor="primary.500"
placeholder="[email protected]"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
<FormErrorMessage>{errors.email}</FormErrorMessage>
</FormControl>
) : null}
{identityInputs.phone ? (
<FormControl
id="phone"
isInvalid={touched.phone && Boolean(errors.phone)}
isRequired={identityInputs.phone === "required"}
>
<FormLabel fontSize="sm">Phone</FormLabel>
<PhoneInput
id="phone"
name="phone"
onChange={(value) => {
setFieldValue("phone", value, true);
}}
onBlur={handleBlur}
value={values.phone}
/>
<FormErrorMessage>{errors.phone}</FormErrorMessage>
</FormControl>
) : null}
{Object.entries(identityInputs)
.filter(
([key, item]) =>
key !== "email" &&
key !== "phone" &&
key !== "name" &&
typeof item !== "string"
)
.map(([key, item]) => (
<FormControl
key={key}
id={key}
isInvalid={touched[key] && Boolean(errors[key])}
isRequired
>
<FormLabel fontSize="sm">
{(item as CustomIdentity).label}
</FormLabel>
<Input
id={key}
name={key}
Expand All @@ -337,10 +414,9 @@ const PrivacyRequestForm: React.FC<PrivacyRequestFormProps> = ({
onBlur={handleBlur}
value={values[key]}
/>
)}
<FormErrorMessage>{errors[key]}</FormErrorMessage>
</FormControl>
))}
<FormErrorMessage>{errors[key]}</FormErrorMessage>
</FormControl>
))}
{Object.entries(customPrivacyRequestFields)
.filter(([, field]) => !field.hidden)
.map(([key, item]) => (
Expand Down
1 change: 1 addition & 0 deletions clients/privacy-center/types/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ConsentValue } from "fides-js";

type DefaultIdentities = {
name?: string; // here for legacy purposes, we don't treat it as an identity or pass it along in the privacy request
email?: string;
phone?: string;
};
Expand Down
9 changes: 3 additions & 6 deletions tests/ctl/api/test_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,8 @@ async def test_load_samples(
assert len(systems) == 5
assert len(datasets) == 4
assert len(policies) == 1
assert len(connections) == 3
assert len(dataset_configs) == 3
assert len(connections) == 2
assert len(dataset_configs) == 2

assert sorted([e.fides_key for e in systems]) == [
"cookie_house",
Expand All @@ -513,13 +513,11 @@ async def test_load_samples(
# expected to exist; the others defined in the sample_connections.yml
# will be ignored since they are missing secrets!
assert sorted([e.key for e in connections]) == [
"cookie_house_loyalty_database",
"cookie_house_postgresql_database",
"stripe_connector",
]
assert sorted([e.fides_key for e in dataset_configs]) == [
"postgres_example_test_dataset",
"postgres_example_test_extended_dataset",
"stripe_connector",
]

Expand Down Expand Up @@ -588,9 +586,8 @@ async def test_load_sample_connections(self):
assert False, error_message

# Assert that only the connections with all their secrets are returned
assert len(connections) == 3
assert len(connections) == 2
assert sorted([e.key for e in connections]) == [
"cookie_house_loyalty_database",
"cookie_house_postgresql_database",
"stripe_connector",
]
Expand Down

0 comments on commit 08bc968

Please sign in to comment.