Skip to content

Commit

Permalink
Add schema attribute profile based validation to user profile
Browse files Browse the repository at this point in the history
  • Loading branch information
DonOmalVindula committed Jan 2, 2025
1 parent 2236b69 commit 891e0fd
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)."
},
" *",
Expand Down
53 changes: 33 additions & 20 deletions features/admin.users.v1/components/user-profile.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -873,8 +873,9 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (

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;
}

Expand Down Expand Up @@ -1034,7 +1035,9 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (

} 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;
}

Expand Down Expand Up @@ -1899,6 +1902,9 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
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(",") ?? [];
Expand Down Expand Up @@ -1977,11 +1983,11 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
: 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({
Expand Down Expand Up @@ -2226,12 +2232,15 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
};

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 (
<Field
data-testid={ `${ testId }-profile-form-${ schema.name }-input` }
name={ schema.name }
required={ schema.required }
required={ resolvedRequiredValue }
requiredErrorMessage={ fieldName + " " + "is required" }
type="checkbox"
value={ profileInfo.get(schema.name) ? [ schema.name ] : [] }
Expand All @@ -2241,7 +2250,7 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
value: schema.name
}
] }
readOnly={ isReadOnly || schema.mutability === ProfileConstants.READONLY_SCHEMA }
readOnly={ isReadOnly || resolvedMutabilityValue === ProfileConstants.READONLY_SCHEMA }
key={ key }
/>
);
Expand All @@ -2252,7 +2261,7 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
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"
Expand All @@ -2277,8 +2286,8 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
) }
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
Expand All @@ -2290,7 +2299,7 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
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 })
}
Expand Down Expand Up @@ -2326,7 +2335,7 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
key={ key }
disabled={ false }
readOnly={ isReadOnly || schema?.mutability === ProfileConstants.READONLY_SCHEMA }
clearable={ !schema?.required }
clearable={ !resolvedRequiredValue }
search
selection
fluid
Expand All @@ -2343,13 +2352,13 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
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;
Expand All @@ -2376,14 +2385,14 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
: 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;
Expand Down Expand Up @@ -2416,8 +2425,10 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
* @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)));
};

/**
Expand Down Expand Up @@ -2453,6 +2464,8 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
);

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 (
<Grid.Row columns={ 1 } key={ key }>
Expand All @@ -2472,7 +2485,7 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
<Input
data-testid={ `${ testId }-profile-form-${ schema.name }-input` }
name={ schema.name }
required={ schema.required }
required={ resolvedRequiredValue }
requiredErrorMessage={ fieldName + " " + "is required" }
placeholder={ "Enter your" + " " + fieldName }
type="text"
Expand All @@ -2498,14 +2511,14 @@ export const UserProfile: FunctionComponent<UserProfilePropsInterface> = (
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
Expand Down
37 changes: 36 additions & 1 deletion modules/core/src/models/profile.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
}

/**
Expand Down

0 comments on commit 891e0fd

Please sign in to comment.