From 891e0fd2c35c79fb2b491dce917a9a5055cad331 Mon Sep 17 00:00:00 2001 From: DonOmalVindula Date: Thu, 2 Jan 2025 16:08:13 +0530 Subject: [PATCH] Add schema attribute profile based validation to user profile --- .eslintrc.js | 2 +- .../components/user-profile.tsx | 53 ++++++++++++------- modules/core/src/models/profile.ts | 37 ++++++++++++- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c23d84a7c51..4b52da2fef6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -72,7 +72,7 @@ const getLicenseHeaderPattern = () => { const LICENSE_HEADER_DEFAULT_PATTERN = [ "*", { - pattern: " Copyright \\(c\\) \\b(2019|202[0-4])(?:-(202[0-4]))?, WSO2 LLC. \\(https://www.wso2.com\\).$", + pattern: " Copyright \\(c\\) \\b(2019|202[0-5])(?:-(202[0-5]))?, WSO2 LLC. \\(https://www.wso2.com\\).$", template: " * Copyright (c) {{year}}, WSO2 LLC. (https://www.wso2.com)." }, " *", diff --git a/features/admin.users.v1/components/user-profile.tsx b/features/admin.users.v1/components/user-profile.tsx index 4f583ad7041..cf520608937 100644 --- a/features/admin.users.v1/components/user-profile.tsx +++ b/features/admin.users.v1/components/user-profile.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023-2024, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2023-2025, WSO2 LLC. (https://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -873,8 +873,9 @@ export const UserProfile: FunctionComponent = ( if (adminUserType === AdminAccountTypes.INTERNAL) { profileSchema.forEach((schema: ProfileSchemaInterface) => { + const resolvedMutabilityValue: string = schema?.profiles?.console?.mutability ?? schema.mutability; - if (schema.mutability === ProfileConstants.READONLY_SCHEMA) { + if (resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA) { return; } @@ -1034,7 +1035,9 @@ export const UserProfile: FunctionComponent = ( } else { profileSchema.forEach((schema: ProfileSchemaInterface) => { - if (schema.mutability === ProfileConstants.READONLY_SCHEMA) { + const resolvedMutabilityValue: string = schema?.profiles?.console?.mutability ?? schema.mutability; + + if (resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA) { return; } @@ -1899,6 +1902,9 @@ export const UserProfile: FunctionComponent = ( let primaryAttributeSchema: ProfileSchemaInterface; let maxAllowedLimit: number = 0; + const resolvedMutabilityValue: string = schema?.profiles?.console?.mutability ?? schema.mutability; + const resolvedRequiredValue: boolean = schema?.profiles?.console?.required ?? schema.required; + if (schema.name === EMAIL_ADDRESSES_ATTRIBUTE) { attributeValueList = profileInfo?.get(EMAIL_ADDRESSES_ATTRIBUTE)?.split(",") ?? []; verifiedAttributeValueList = profileInfo?.get(VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE)?.split(",") ?? []; @@ -1977,11 +1983,11 @@ export const UserProfile: FunctionComponent = ( : fieldName ) } - required={ schema.required } + required={ resolvedRequiredValue } requiredErrorMessage={ fieldName + " " + "is required" } placeholder={ "Enter your" + " " + fieldName } type="text" - readOnly={ isReadOnly || schema.mutability === ProfileConstants.READONLY_SCHEMA } + readOnly={ isReadOnly || resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA } validation={ (value: string, validation: Validation) => { if (!RegExp(primaryAttributeSchema.regEx).test(value)) { setIsMultiValuedItemInvalid({ @@ -2226,12 +2232,15 @@ export const UserProfile: FunctionComponent = ( }; const resolveFormField = (schema: ProfileSchemaInterface, fieldName: string, key: number): ReactElement => { + const resolvedRequiredValue: boolean = schema?.profiles?.console?.required ?? schema.required; + const resolvedMutabilityValue: string = schema?.profiles?.console?.mutability ?? schema.mutability; + if (schema.type.toUpperCase() === "BOOLEAN") { return ( = ( value: schema.name } ] } - readOnly={ isReadOnly || schema.mutability === ProfileConstants.READONLY_SCHEMA } + readOnly={ isReadOnly || resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA } key={ key } /> ); @@ -2252,7 +2261,7 @@ export const UserProfile: FunctionComponent = ( data-testid={ `${ testId }-profile-form-${ schema.name }-input` } name={ schema.name } label={ fieldName } - required={ schema.required } + required={ resolvedRequiredValue } requiredErrorMessage={ fieldName + " " + "is required" } placeholder={ "Select your" + " " + fieldName } type="dropdown" @@ -2277,8 +2286,8 @@ export const UserProfile: FunctionComponent = ( ) } key={ key } disabled={ false } - readOnly={ isReadOnly || schema.mutability === ProfileConstants.READONLY_SCHEMA } - clearable={ !schema.required } + readOnly={ isReadOnly || resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA } + clearable={ !resolvedRequiredValue } search selection fluid @@ -2290,7 +2299,7 @@ export const UserProfile: FunctionComponent = ( data-testid={ `${ testId }-profile-form-${ schema?.name }-input` } name={ schema?.name } label={ fieldName } - required={ schema?.required } + required={ resolvedRequiredValue } requiredErrorMessage={ t("user:profile.forms.generic.inputs.validations.empty", { fieldName }) } @@ -2326,7 +2335,7 @@ export const UserProfile: FunctionComponent = ( key={ key } disabled={ false } readOnly={ isReadOnly || schema?.mutability === ProfileConstants.READONLY_SCHEMA } - clearable={ !schema?.required } + clearable={ !resolvedRequiredValue } search selection fluid @@ -2343,13 +2352,13 @@ export const UserProfile: FunctionComponent = ( data-testid={ `${ testId }-profile-form-${ schema.name }-input` } name={ schema.name } label={ fieldName } - required={ schema.required } + required={ resolvedRequiredValue } requiredErrorMessage={ fieldName + " is required" } placeholder="YYYY-MM-DD" type="text" value={ profileInfo.get(schema.name) } key={ key } - readOnly={ isReadOnly || schema.mutability === ProfileConstants.READONLY_SCHEMA } + readOnly={ isReadOnly || resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA } validation={ (value: string, validation: Validation) => { if (!RegExp(schema.regEx).test(value)) { validation.isValid = false; @@ -2376,14 +2385,14 @@ export const UserProfile: FunctionComponent = ( : fieldName ) } - required={ schema.required } + required={ resolvedRequiredValue } requiredErrorMessage={ fieldName + " is required" } placeholder={ "Enter your " + fieldName } type="text" value={ profileInfo.get(schema.name) } key={ key } disabled={ schema.name === "userName" } - readOnly={ isReadOnly || schema.mutability === ProfileConstants.READONLY_SCHEMA } + readOnly={ isReadOnly || resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA } validation={ (value: string, validation: Validation) => { if (!RegExp(schema.regEx).test(value)) { validation.isValid = false; @@ -2416,8 +2425,10 @@ export const UserProfile: FunctionComponent = ( * @returns whether the field for the input schema should be displayed. */ const isFieldDisplayable = (schema: ProfileSchemaInterface): boolean => { + const resolvedMutabilityValue: string = schema?.profiles?.console?.mutability ?? schema.mutability; + return (!isEmpty(profileInfo.get(schema.name)) || - (!isReadOnly && (schema.mutability !== ProfileConstants.READONLY_SCHEMA))); + (!isReadOnly && (resolvedMutabilityValue !== ProfileConstants.READONLY_SCHEMA))); }; /** @@ -2453,6 +2464,8 @@ export const UserProfile: FunctionComponent = ( ); const domainName: string[] = profileInfo?.get(schema.name)?.toString().split("/"); + const resolvedMutabilityValue: string = schema?.profiles?.console?.mutability ?? schema.mutability; + const resolvedRequiredValue: boolean = schema?.profiles?.console?.required ?? schema.required; return ( @@ -2472,7 +2485,7 @@ export const UserProfile: FunctionComponent = ( = ( data-testid={ `${ testId }-profile-form-${ schema.name }-input` } name={ schema.name } label={ domainName[0] + " / " } - required={ schema.required } + required={ resolvedRequiredValue } requiredErrorMessage={ fieldName + " " + "is required" } placeholder={ "Enter your" + " " + fieldName } type="text" value={ domainName[1] } key={ key } readOnly={ isReadOnly || - schema.mutability === ProfileConstants.READONLY_SCHEMA } + resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA } maxLength={ schema.maxLength ? schema.maxLength diff --git a/modules/core/src/models/profile.ts b/modules/core/src/models/profile.ts index 1eae30c2424..b8d48141ee1 100644 --- a/modules/core/src/models/profile.ts +++ b/modules/core/src/models/profile.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020-2023, WSO2 LLC. (https://www.wso2.com). + * Copyright (c) 2020-2025, WSO2 LLC. (https://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -210,6 +210,41 @@ export interface ProfileSchemaInterface { * Excluded user stores. */ excludedUserStores?: string; + /** + * Schema attribute profiles + */ + profiles?: { + /** + * Attribute profile for console user profile + */ + console?: ProfileAttributeInterface; + /** + * Attribute profile for end user profile (My Account) + */ + endUser?: ProfileAttributeInterface; + /** + * Attribute profile for self registration + */ + selfRegister?: ProfileAttributeInterface; + } +} + +/** + * Profile attribute interface. + */ +export interface ProfileAttributeInterface { + /** + * Flag to set mutability. + */ + mutability?: string; + /** + * Flag to set if the attribute is required. + */ + required?: boolean; + /** + * Flag to set if the attribute is shown. + */ + supportedByDefault?: boolean; } /**