mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-28 04:13:22 -04:00
Format Terms and Conditions accepted timestamp (#49031)
Closes #44591 Signed-off-by: Palash Thakur <palash@LAPTOP-8OJ5UPT8.localdomain> Co-authored-by: Palash Thakur <palash@LAPTOP-8OJ5UPT8.localdomain>
This commit is contained in:
parent
dddf24e3ed
commit
07d30b650a
2 changed files with 109 additions and 1 deletions
|
|
@ -47,6 +47,8 @@ import { useNavigate } from "react-router-dom";
|
|||
import { CopyToClipboardButton } from "../components/copy-to-clipboard-button/CopyToClipboardButton";
|
||||
import { GroupResourceContext } from "../context/group-resource/GroupResourceContext";
|
||||
|
||||
const TERMS_AND_CONDITIONS_ATTRIBUTE = "terms_and_conditions";
|
||||
|
||||
export type BruteForced = {
|
||||
isBruteForceProtected?: boolean;
|
||||
isLocked?: boolean;
|
||||
|
|
@ -86,6 +88,10 @@ export const UserForm = ({
|
|||
const canViewFederationLink = hasAccess("view-realm");
|
||||
const { whoAmI } = useWhoAmI();
|
||||
|
||||
const termsAndConditionsAcceptedDate = toTermsAndConditionsAcceptedDate(
|
||||
user?.attributes?.[TERMS_AND_CONDITIONS_ATTRIBUTE],
|
||||
);
|
||||
|
||||
const { handleSubmit, setValue, control, reset, formState } = form;
|
||||
const { errors } = formState;
|
||||
|
||||
|
|
@ -270,6 +276,19 @@ export const UserForm = ({
|
|||
label={t("emailVerified")}
|
||||
labelIcon={t("emailVerifiedHelp")}
|
||||
/>
|
||||
{termsAndConditionsAcceptedDate && (
|
||||
<FormGroup
|
||||
label={t("termsAndConditionsUserAttribute")}
|
||||
fieldId={TERMS_AND_CONDITIONS_ATTRIBUTE}
|
||||
>
|
||||
<span
|
||||
id={TERMS_AND_CONDITIONS_ATTRIBUTE}
|
||||
data-testid={TERMS_AND_CONDITIONS_ATTRIBUTE}
|
||||
>
|
||||
{formatDate(termsAndConditionsAcceptedDate)}
|
||||
</span>
|
||||
</FormGroup>
|
||||
)}
|
||||
{user?.attributes?.["kc.email.pending"] && (
|
||||
<Alert
|
||||
variant={AlertVariant.warning}
|
||||
|
|
@ -298,7 +317,11 @@ export const UserForm = ({
|
|||
...userProfileMetadata,
|
||||
attributes: userProfileMetadata.attributes?.filter(
|
||||
(attribute: UserProfileAttributeMetadata) => {
|
||||
return attribute.name !== "kc.email.pending";
|
||||
return (
|
||||
attribute.name !== "kc.email.pending" &&
|
||||
(attribute.name !== TERMS_AND_CONDITIONS_ATTRIBUTE ||
|
||||
!termsAndConditionsAcceptedDate)
|
||||
);
|
||||
},
|
||||
),
|
||||
}}
|
||||
|
|
@ -430,3 +453,15 @@ export const UserForm = ({
|
|||
</FormAccess>
|
||||
);
|
||||
};
|
||||
|
||||
function toTermsAndConditionsAcceptedDate(value: unknown): Date | undefined {
|
||||
const timestamp = Number(Array.isArray(value) ? value[0] : value);
|
||||
|
||||
if (!Number.isFinite(timestamp) || timestamp <= 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const date = new Date(timestamp * 1000);
|
||||
|
||||
return Number.isNaN(date.getTime()) ? undefined : date;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,79 @@ test.describe("Existing users", () => {
|
|||
await assertNotificationMessage(page, "The user has been saved");
|
||||
});
|
||||
|
||||
test("formats Terms and Conditions accepted timestamp", async ({ page }) => {
|
||||
const termsAcceptedTimestamp = "1700000000";
|
||||
const email = "existing-user@example.com";
|
||||
const firstName = "Existing";
|
||||
const lastName = "User";
|
||||
|
||||
await using testBed = await createTestBed({
|
||||
attributes: {
|
||||
userProfileEnabled: "true",
|
||||
},
|
||||
requiredActions: [
|
||||
{
|
||||
alias: "TERMS_AND_CONDITIONS",
|
||||
name: "Terms and Conditions",
|
||||
providerId: "TERMS_AND_CONDITIONS",
|
||||
enabled: true,
|
||||
defaultAction: false,
|
||||
priority: 20,
|
||||
config: {},
|
||||
},
|
||||
],
|
||||
users: [
|
||||
{
|
||||
username: existingUserName,
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
attributes: {
|
||||
terms_and_conditions: [termsAcceptedTimestamp],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const user = await adminClient.findUserByUsername(
|
||||
testBed.realm,
|
||||
existingUserName,
|
||||
);
|
||||
|
||||
await login(page, {
|
||||
to: toUser({ realm: testBed.realm, id: user.id!, tab: "settings" }),
|
||||
});
|
||||
|
||||
const termsAcceptedField = page.getByTestId("terms_and_conditions");
|
||||
await expect(termsAcceptedField).toBeVisible();
|
||||
await expect(termsAcceptedField).not.toHaveText(termsAcceptedTimestamp);
|
||||
await expect(
|
||||
page.getByText(termsAcceptedTimestamp, { exact: true }),
|
||||
).toHaveCount(0);
|
||||
await expect(
|
||||
page.locator(`input[value="${termsAcceptedTimestamp}"]`),
|
||||
).toHaveCount(0);
|
||||
|
||||
const displayedTimestamp = await termsAcceptedField.innerText();
|
||||
expect(displayedTimestamp).toContain("2023");
|
||||
expect(displayedTimestamp).toMatch(/\D/);
|
||||
expect(displayedTimestamp).toMatch(/\d{1,2}:\d{2}/);
|
||||
|
||||
await expect(page.getByTestId("email")).toHaveValue(email);
|
||||
await expect(page.getByTestId("firstName")).toHaveValue(firstName);
|
||||
await expect(page.getByTestId("lastName")).toHaveValue(lastName);
|
||||
|
||||
await clickSaveButton(page);
|
||||
await assertNotificationMessage(page, "The user has been saved");
|
||||
|
||||
const updatedUser = await adminClient.findUserByUsername(
|
||||
testBed.realm,
|
||||
existingUserName,
|
||||
);
|
||||
expect(updatedUser.attributes?.terms_and_conditions).toEqual([
|
||||
termsAcceptedTimestamp,
|
||||
]);
|
||||
});
|
||||
|
||||
test("shows validation error for empty required attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue