[MM-62695] Extend property types for CPA (#30201)

* test: Add unit tests for custom profile attributes select options

* feat: Add custom profile attributes model with validation and constants

* refactor: Trim spaces from name and color in custom profile attribute select option constructor

* gofmt

* refactor: Fix typo in custom profile attributes select option function name

* feat: Add IsValid method to validate CustomProfileAttributesSelectOptions

* refactor: Replace map[string]bool with map[string]struct{} for key existence check

* refactor: Rename NewCustomProfileAttributeSelectOption to NewCustomProfileAttributesSelectOption

* feat: Add validation to prevent empty custom profile attribute options

* refactor: Add validation and creation methods for custom profile attributes

* feat: Add index number to validation error messages in custom profile attributes

* fix tests

* add default visibility

* feat: Add comprehensive test cases for custom profile attributes field validation

* fix: Update custom profile attributes map keys to use capitalized names

* feat: Add support for lowercase and title case keys in custom profile attributes map

* test: Add comprehensive test for NewCustomProfileAttributesSelectOptionFromMap

* feat: Add validation for custom profile attributes fields

* refactor: Update CustomProfileAttributesSelectOption constructor to prioritize ID parameter

* test: Add test cases for preserving IDs in custom profile attributes

* feat: Enhance ID validation and trimming in custom profile attributes

* don't do validation in constructor

* test: Add test case for preserving option IDs when patching select field

* improve test

* i18n

* refactor: Modify CustomProfileAttributesSelectOption to use lowercase JSON keys

* fix casing in custom profilte attributes test

* refactor: Use consistent "ValidateCPAField" in error messages for custom profile attributes

* use custom types rather than string

* lint

* fix api test

* refactor: Make color field optional in custom profile attributes

* style

* generic options

* removed unused i18n

* test: Add tests for NewCPAFieldFromPropertyField and CPAFieldToPropertyField

* test: Add test case for property field with empty attributes

* refactor: Cleanup whitespace and remove empty Attrs in custom profile attributes test

* test: Add test case for CPA field with empty attributes

* refactor: Improve custom profile attributes field handling and validation

* refactor: Move validateCustomProfileAttributesField to Validate method on CPAField struct

* use CPAField

* code style

* add validation and tests

* tests

* i18n

* err->appErr

* fix TestDeleteCPAField test

* i18n

* Add SAML and LDAP attr

* rename CustomProfileAttributes in method to CPA

* rename CPASortOrder method

* rearrange consts

* use Len test method

* sanitize and validate

* manage error the same way property field and value do

* fix: Update test error ID for custom profile attributes validation

* test: Update error ID expectations in custom profile attributes tests

* refactor: Convert CPAAttrs.SortOrder from string to int

* json uses float64

* feat: Add length validation for custom profile attribute option name and color

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Julien Tant
2025-03-20 11:47:40 -07:00
коммит произвёл GitHub
родитель 7770c03919
Коммит cb89e5646e
8 изменённых файлов: 1137 добавлений и 170 удалений

Просмотреть файл

@@ -4,7 +4,9 @@
package model
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
@@ -178,3 +180,55 @@ type PropertyFieldSearchOpts struct {
func (pf *PropertyField) GetAttr(key string) any {
return pf.Attrs[key]
}
const PropertyFieldAttributeOptions = "options"
type PropertyOption interface {
GetID() string
GetName() string
SetID(id string)
IsValid() error
}
type PropertyOptions[T PropertyOption] []T
func NewPropertyOptionsFromFieldAttrs[T PropertyOption](optionsArr any) (PropertyOptions[T], error) {
options := PropertyOptions[T]{}
b, err := json.Marshal(optionsArr)
if err != nil {
return nil, fmt.Errorf("failed to marshal options: %w", err)
}
err = json.Unmarshal(b, &options)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal options: %w", err)
}
for i := range options {
if options[i].GetID() == "" {
options[i].SetID(NewId())
}
}
return options, nil
}
func (p PropertyOptions[T]) IsValid() error {
if len(p) == 0 {
return errors.New("options list cannot be empty")
}
seenNames := make(map[string]struct{})
for i, option := range p {
if err := option.IsValid(); err != nil {
return fmt.Errorf("invalid option at index %d: %w", i, err)
}
if _, exists := seenNames[option.GetName()]; exists {
return fmt.Errorf("duplicate option name found at index %d: %s", i, option.GetName())
}
seenNames[option.GetName()] = struct{}{}
}
return nil
}