mirror of
https://github.com/mattermost/mattermost.git
synced 2026-05-28 04:35:04 -04:00
* Phase 1: CPA display_name + CEL-safe name validation (server) - Add typed DisplayName field to CPAAttrs + display_name attr key constant. - Add ValidateCPAFieldName helper enforcing CEL IDENTIFIER + reserved-word blacklist. - Wire validation into App.CreateCPAField (always) and App.PatchCPAField (lenient grandfather: skip when Name unchanged). - Trim + 255-rune cap DisplayName in CPAField.SanitizeAndValidate. - Developer-facing godoc note documenting rule, sources of truth, and Option C scoping. - Asserting test for documented Option C plugin-API bypass (closed by PR #36173). Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md Plan: .planning/phase-1/PLAN.md Made-with: Cursor * Phase 1 (review): address Reza's Major + Minor findings - Rename misleading subtest "empty DisplayName is omitted from attrs" to "empty DisplayName round-trips as empty string" (Major #1). - Add TestCPAAttrs_JSONOmitEmpty pinning the omitempty wire-format contract that PR #36173's typed-attrs strategy relies on (Major #1). - Extend TestValidateCPAFieldName: case-sensitivity (IN/In ok), single-character names (a/_/A ok), missing "as" reserved word (Minor #2). Add whitespace-only DisplayName case (Minor #2). - Document PropertyFieldNameMaxRunes reuse in SanitizeAndValidate to prevent drift (Minor #3). - Replace broken PLAN-server.md reference in bypass-test docstring with in-tree CPAAttrs godoc reference (Minor #4). - Document omitempty semantics on CPAAttrs.DisplayName field to prevent the same misreading caught in review (Minor #5). - Document grouping intent above CPAFieldNameReservedWords (Minor #8). Review: .planning/phase-1/REVIEW.md Made-with: Cursor * Phase 2: in-app backfill migration for CPA display_name - Add cpaDisplayNameBackfillKey + cpaDisplayNameBackfillVersion constants. - Implement (*Server).doSetupCPADisplayNameBackfill: idempotent, cursor-paged scan over CPA group fields; backfill attrs.display_name = name when empty. - Register in m1 migration slice in doAppMigrations (mlog.Fatal on error, matching existing convention). - Three migration tests: NoExistingFields, BackfillsMissing, Idempotent. System-key idempotency + per-field DisplayName-empty check together provide HA-safe behavior on rolling deploys (last-write-wins on the System key; data-level idempotency from the per-field check). Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md Plan: .planning/phase-2/PLAN.md Made-with: Cursor * Phase 2 (review): document race + harden idempotency test - Document SearchPropertyFields→UpdatePropertyFields rolling-deploy race: stale snapshot can revert concurrent admin CPA rename. Pre- existing systemic shape (no UpdateAt optimistic-lock); narrow window; bounded blast radius (admin re-rename, ABAC ID-keyed). Accepted limitation per spec Out of Scope (Major #1, Option C). - Tighten TestCPADisplayNameBackfill_Idempotent: snapshot UpdateAt before second run; assert no DB write on the System key or the field row (Major #2). - Extract clearCPABackfillMarker helper with explanatory godoc to centralize the 3x-repeated test precondition (Minor #1). - Comment fieldA seed as the "key-present-as-empty-string" idempotency boundary case (Minor #6). - Add godoc to doSetupCPADisplayNameBackfill (Minor #10). Review: .planning/phase-2/REVIEW.md Made-with: Cursor * Linting * Removing unnecessary comments * Clean up tests * Linting * Fix tests * Updated API doc * Fix tests * PR Feedback * Move migration to PropertyService * Linting * Linting * Removed pagination --------- Co-authored-by: Mattermost Build <build@mattermost.com>
471 lines
16 KiB
YAML
471 lines
16 KiB
YAML
"/api/v4/custom_profile_attributes/fields":
|
|
get:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: List all the Custom Profile Attributes fields
|
|
description: |
|
|
List all the Custom Profile Attributes fields.
|
|
|
|
__Minimum server version__: 10.5
|
|
|
|
##### Permissions
|
|
Must be authenticated.
|
|
operationId: ListAllCPAFields
|
|
responses:
|
|
"200":
|
|
description: Custom Profile Attributes fetch successful. Result may be empty.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/PropertyField"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
|
|
post:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: Create a Custom Profile Attribute field
|
|
description: |
|
|
Create a new Custom Profile Attribute field on the system.
|
|
|
|
__Minimum server version__: 10.5
|
|
|
|
##### Permissions
|
|
Must have `manage_system` permission.
|
|
operationId: CreateCPAField
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required:
|
|
- name
|
|
- type
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: >
|
|
The internal identifier for this attribute. Must match
|
|
`^[A-Za-z_][A-Za-z0-9_]*$` and must not be a CEL reserved
|
|
word (true, false, null, in, as, break, const, continue, else,
|
|
for, function, if, import, let, loop, package, namespace,
|
|
return, var, void, while). This name is used in ABAC policy
|
|
expressions as `user.attributes.<name>`.
|
|
type:
|
|
type: string
|
|
attrs:
|
|
type: object
|
|
properties:
|
|
visibility:
|
|
type: string
|
|
description: "Visibility of the attribute"
|
|
enum: ["hidden", "when_set", "always"]
|
|
default: "when_set"
|
|
sort_order:
|
|
type: number
|
|
description: "Sort order for displaying this attribute"
|
|
options:
|
|
type: array
|
|
description: "Options for select/multiselect fields"
|
|
items:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
value_type:
|
|
type: string
|
|
description: "Type of text value"
|
|
enum: ["email", "url", "phone"]
|
|
ldap:
|
|
type: string
|
|
description: "LDAP attribute for syncing"
|
|
saml:
|
|
type: string
|
|
description: "SAML attribute for syncing"
|
|
protected:
|
|
type: boolean
|
|
description: "If true, the field is read-only and cannot be modified."
|
|
source_plugin_id:
|
|
type: string
|
|
description: "The ID of the plugin that created this field. This attribute cannot be changed."
|
|
access_mode:
|
|
type: string
|
|
description: "Access mode of the field"
|
|
enum: ["", "source_only", "shared_only"]
|
|
default: ""
|
|
display_name:
|
|
type: string
|
|
description: >
|
|
Human-readable label shown in the UI. Defaults to the field
|
|
`name` when omitted or empty. Maximum 255 characters.
|
|
responses:
|
|
"201":
|
|
description: Custom Profile Attribute field creation successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PropertyField"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"403":
|
|
$ref: "#/components/responses/Forbidden"
|
|
"422":
|
|
description: >
|
|
Validation error. Returned when `name` does not match the
|
|
required identifier pattern, is a CEL reserved word, or when
|
|
`attrs.display_name` exceeds 255 characters.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AppError"
|
|
|
|
"/api/v4/custom_profile_attributes/fields/{field_id}":
|
|
patch:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: Patch a Custom Profile Attribute field
|
|
description: |
|
|
Partially update a Custom Profile Attribute field by providing
|
|
only the fields you want to update. Omitted fields will not be
|
|
updated. The fields that can be updated are defined in the
|
|
request body, all other provided fields will be ignored.
|
|
|
|
**Note:** Fields with `attrs.protected = true` cannot be
|
|
modified and will return an error.
|
|
|
|
__Minimum server version__: 10.5
|
|
|
|
##### Permissions
|
|
Must have `manage_system` permission.
|
|
operationId: PatchCPAField
|
|
parameters:
|
|
- name: field_id
|
|
in: path
|
|
description: Custom Profile Attribute field GUID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
requestBody:
|
|
description: Custom Profile Attribute field that is to be updated
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: >
|
|
New name for the attribute. When changed, must match
|
|
`^[A-Za-z_][A-Za-z0-9_]*$` and must not be a CEL reserved
|
|
word. Pre-existing fields with non-conforming names remain
|
|
patchable on all other attributes; the validation only fires
|
|
when `name` actually changes.
|
|
type:
|
|
type: string
|
|
attrs:
|
|
type: object
|
|
properties:
|
|
visibility:
|
|
type: string
|
|
description: "Visibility of the attribute"
|
|
enum: ["hidden", "when_set", "always"]
|
|
default: "when_set"
|
|
sort_order:
|
|
type: number
|
|
description: "Sort order for displaying this attribute"
|
|
options:
|
|
type: array
|
|
description: "Options for select/multiselect fields"
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
value_type:
|
|
type: string
|
|
description: "Type of text value"
|
|
enum: ["email", "url", "phone"]
|
|
ldap:
|
|
type: string
|
|
description: "LDAP attribute for syncing"
|
|
saml:
|
|
type: string
|
|
description: "SAML attribute for syncing"
|
|
protected:
|
|
type: boolean
|
|
description: "If true, the field is read-only and cannot be modified."
|
|
source_plugin_id:
|
|
type: string
|
|
description: "The ID of the plugin that created this field. This attribute cannot be changed."
|
|
access_mode:
|
|
type: string
|
|
description: "Access mode of the field"
|
|
enum: ["", "source_only", "shared_only"]
|
|
default: ""
|
|
display_name:
|
|
type: string
|
|
description: >
|
|
Human-readable label shown in the UI. Maximum 255 characters.
|
|
responses:
|
|
"200":
|
|
description: Custom Profile Attribute field patch successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/PropertyField"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"403":
|
|
$ref: "#/components/responses/Forbidden"
|
|
"422":
|
|
description: >
|
|
Validation error. Returned when a `name` change does not match
|
|
the required identifier pattern, is a CEL reserved word, or
|
|
when `attrs.display_name` exceeds 255 characters.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/AppError"
|
|
|
|
delete:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: Delete a Custom Profile Attribute field
|
|
description: |
|
|
Marks a Custom Profile Attribute field and all its values as
|
|
deleted.
|
|
|
|
__Minimum server version__: 10.5
|
|
|
|
##### Permissions
|
|
Must have `manage_system` permission.
|
|
operationId: DeleteCPAField
|
|
parameters:
|
|
- name: field_id
|
|
in: path
|
|
description: Custom Profile Attribute field GUID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: Custom Profile Attribute field deletion successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/StatusOK"
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"403":
|
|
$ref: "#/components/responses/Forbidden"
|
|
|
|
"/api/v4/custom_profile_attributes/values":
|
|
patch:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: Patch Custom Profile Attribute values
|
|
description: |
|
|
Partially update a set of values on the requester's Custom
|
|
Profile Attribute fields by providing only the information you
|
|
want to update. Omitted fields will not be updated. The fields
|
|
that can be updated are defined in the request body, all other
|
|
provided fields will be ignored.
|
|
|
|
**Note:** Values for fields with `attrs.protected = true` cannot be
|
|
updated and will return an error.
|
|
|
|
__Minimum server version__: 10.5
|
|
|
|
##### Permissions
|
|
Must be authenticated.
|
|
operationId: PatchCPAValues
|
|
requestBody:
|
|
description: Custom Profile Attribute values that are to be updated
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
value:
|
|
oneOf:
|
|
- type: string
|
|
- type: array
|
|
items:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: Custom Profile Attribute values patch successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
value:
|
|
oneOf:
|
|
- type: string
|
|
- type: array
|
|
items:
|
|
type: string
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"403":
|
|
$ref: "#/components/responses/Forbidden"
|
|
"/api/v4/custom_profile_attributes/group":
|
|
get:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: Get Custom Profile Attribute property group data
|
|
description: |
|
|
Get the property group used for Custom Profile Attributes.
|
|
|
|
__Minimum server version__: 10.8
|
|
|
|
##### Permissions
|
|
Must be authenticated.
|
|
operationId: GetCPAGroup
|
|
responses:
|
|
"200":
|
|
description: Group fetch successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
description: The ID of the custom profile attributes group
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"403":
|
|
$ref: "#/components/responses/Forbidden"
|
|
|
|
"/api/v4/users/{user_id}/custom_profile_attributes":
|
|
get:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: List Custom Profile Attribute values
|
|
description: |
|
|
List all the Custom Profile Attributes values for specified user.
|
|
|
|
__Minimum server version__: 10.5
|
|
|
|
##### Permissions
|
|
Must have `view members` permission.
|
|
operationId: ListCPAValues
|
|
parameters:
|
|
- name: user_id
|
|
in: path
|
|
description: User GUID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: Custom Profile Attribute values fetch successful. Result may be empty.
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
field_id:
|
|
type: string
|
|
value:
|
|
type: string
|
|
"400":
|
|
$ref: "#/components/responses/BadRequest"
|
|
"401":
|
|
$ref: "#/components/responses/Unauthorized"
|
|
"403":
|
|
$ref: "#/components/responses/Forbidden"
|
|
patch:
|
|
tags:
|
|
- custom profile attributes
|
|
summary: Update custom profile attribute values for a user
|
|
description: |
|
|
Update Custom Profile Attribute field values for a specific user.
|
|
|
|
**Note:** Values for fields with `attrs.protected = true` cannot be
|
|
updated and will return an error.
|
|
|
|
__Minimum server version__: 11
|
|
|
|
##### Permissions
|
|
Must have permission to edit the user. Users can only edit their own CPA values unless they are system administrators.
|
|
parameters:
|
|
- name: user_id
|
|
in: path
|
|
description: User GUID
|
|
required: true
|
|
schema:
|
|
type: string
|
|
operationId: PatchCPAValuesForUser
|
|
requestBody:
|
|
description: Custom Profile Attribute values that are to be updated
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
value:
|
|
oneOf:
|
|
- type: string
|
|
- type: array
|
|
items:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Custom profile attribute values updated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
value:
|
|
oneOf:
|
|
- type: string
|
|
- type: array
|
|
items:
|
|
type: string
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|