@@ -173,6 +173,103 @@ public bool Validate(JsonDocument? value, IStringLocalizer<Program> localizer,
173173 return true ;
174174 }
175175 }
176+
177+ extension ( UserInfo user )
178+ {
179+ /// <summary>
180+ /// Update user metadata by user input
181+ /// </summary>
182+ /// <param name="metadata">The new metadata from user</param>
183+ /// <param name="localizer">String localizer for error messages</param>
184+ /// <param name="fieldDefs">Field definitions</param>
185+ /// <param name="errorResponse">Error response if validation fails</param>
186+ /// <returns>>True if update is successful, false otherwise</returns>
187+ internal bool UpdateUserMetadataByUser ( MetadataStore metadata ,
188+ IStringLocalizer < Program > localizer ,
189+ Dictionary < string , UserMetadataField > fieldDefs ,
190+ [ MaybeNullWhen ( true ) ] out string errorResponse )
191+ {
192+ var newMetadata = new MetadataStore ( ) ;
193+
194+ foreach ( ( var key , JsonDocument ? value ) in metadata )
195+ {
196+ // Skip fields that are locked or not defined
197+ if ( ! fieldDefs . TryGetValue ( key , out var field ) || field . Locked )
198+ continue ;
199+
200+ // Validate field value
201+ if ( ! field . Validate ( value , localizer , out var error ) )
202+ {
203+ errorResponse = localizer [ nameof ( Resources . Program . Model_FieldValidationFailed ) ,
204+ field . DisplayName , error ] ;
205+ return false ;
206+ }
207+
208+ newMetadata [ key ] = value ;
209+ }
210+
211+ if ( user . Metadata is not null )
212+ {
213+ foreach ( ( var key , JsonDocument ? value ) in user . Metadata )
214+ {
215+ // Preserve locked fields
216+ if ( fieldDefs . TryGetValue ( key , out var field ) && field . Locked )
217+ newMetadata [ key ] = value ;
218+ }
219+ }
220+
221+ user . Metadata = newMetadata ;
222+ errorResponse = null ;
223+ return true ;
224+ }
225+
226+ /// <summary>
227+ /// Update user metadata by admin input
228+ /// </summary>
229+ /// <param name="metadata">The new metadata from user</param>
230+ /// <param name="localizer">String localizer for error messages</param>
231+ /// <param name="fieldDefs">Field definitions</param>
232+ /// <param name="errorResponse">Error response if validation fails</param>
233+ /// <returns>>True if update is successful, false otherwise</returns>
234+ internal bool UpdateUserMetadataByAdmin ( MetadataStore metadata ,
235+ IStringLocalizer < Program > localizer ,
236+ Dictionary < string , UserMetadataField > fieldDefs ,
237+ [ MaybeNullWhen ( true ) ] out string errorResponse )
238+ {
239+ var newMetadata = new MetadataStore ( ) ;
240+
241+ foreach ( ( var key , JsonDocument ? value ) in metadata )
242+ {
243+ // Skip fields that are locked or not defined
244+ if ( ! fieldDefs . TryGetValue ( key , out var field ) )
245+ continue ;
246+
247+ // Validate field value
248+ if ( ! field . Validate ( value , localizer , out var error ) )
249+ {
250+ errorResponse = localizer [ nameof ( Resources . Program . Model_FieldValidationFailed ) ,
251+ field . DisplayName , error ] ;
252+ return false ;
253+ }
254+
255+ newMetadata [ key ] = value ;
256+ }
257+
258+ if ( user . Metadata is not null )
259+ {
260+ foreach ( ( var key , JsonDocument ? value ) in user . Metadata )
261+ {
262+ // Preserve old fields that are not being updated
263+ if ( ! newMetadata . ContainsKey ( key ) && fieldDefs . ContainsKey ( key ) )
264+ newMetadata [ key ] = value ;
265+ }
266+ }
267+
268+ user . Metadata = newMetadata ;
269+ errorResponse = null ;
270+ return true ;
271+ }
272+ }
176273}
177274
178275public sealed record UserMetadataFieldValue ( UserMetadataFieldValueType Type , JsonDocument ? Value ) : IDisposable
0 commit comments