Fix custom profile field values being double-serialized with escapes.

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk
2026-02-17 07:54:08 +00:00
parent d7b0fad6b8
commit fc23cc1568
4 changed files with 38 additions and 12 deletions

View File

@@ -292,7 +292,7 @@ pub(crate) async fn get_profile_route(
return Err!(Request(NotFound("Profile was not found."))); return Err!(Request(NotFound("Profile was not found.")));
} }
let mut custom_profile_fields: BTreeMap<String, serde_json::Value> = services let mut custom_profile_fields: BTreeMap<String, _> = services
.users .users
.all_profile_keys(&body.user_id) .all_profile_keys(&body.user_id)
.collect() .collect()
@@ -317,11 +317,24 @@ pub(crate) async fn get_profile_route(
("m.tz", tz), ("m.tz", tz),
]; ];
let response = canonical_fields Ok(canonical_fields
.into_iter() .into_iter()
.filter_map(|(key, val)| val.map(|val| (key, val))) .map(|(key, val)| (key.to_owned(), val))
.map(|(key, val)| (key.to_owned(), val.into())) .filter_map(|(key, val)| {
.chain(custom_profile_fields.into_iter()); val.map(serde_json::to_value)
.transpose()
Ok(response.collect::<get_profile::v3::Response>()) .ok()
.flatten()
.map(|val| (key, val))
})
.chain(
custom_profile_fields
.into_iter()
.filter_map(|(key, val)| {
serde_json::to_value(val.json())
.map(|val| (key, val))
.ok()
}),
)
.collect())
} }

View File

@@ -366,6 +366,7 @@ pub(crate) async fn get_profile_field_route(
.users .users
.profile_key(&body.user_id, body.field.as_str()) .profile_key(&body.user_id, body.field.as_str())
.await .await
.and_then(|val| serde_json::to_value(val.json()).map_err(Into::into))
.map_err(|_| err!(Request(NotFound("The requested profile key does not exist."))))?; .map_err(|_| err!(Request(NotFound("The requested profile key does not exist."))))?;
let profile_key_value = ProfileFieldValue::new(body.field.as_str(), value)?; let profile_key_value = ProfileFieldValue::new(body.field.as_str(), value)?;

View File

@@ -98,7 +98,11 @@ pub(crate) async fn get_profile_information_route(
.await .await
{ {
Ok(Response { Ok(Response {
custom_profile_fields: [(custom_field.to_string(), value)].into(), custom_profile_fields: [(
custom_field.to_string(),
serde_json::to_value(value.json())?,
)]
.into(),
..Response::default() ..Response::default()
}) })
} else { } else {
@@ -117,11 +121,17 @@ pub(crate) async fn get_profile_information_route(
let custom_profile_fields = services let custom_profile_fields = services
.users .users
.all_profile_keys(&body.user_id) .all_profile_keys(&body.user_id)
.collect(); .collect::<Vec<_>>();
let (avatar_url, blurhash, custom_profile_fields, displayname, tz) = let (avatar_url, blurhash, custom_profile_fields, displayname, tz) =
join5(avatar_url, blurhash, custom_profile_fields, displayname, tz).await; join5(avatar_url, blurhash, custom_profile_fields, displayname, tz).await;
let custom_profile_fields = custom_profile_fields
.into_iter()
.map(|(k, v)| (k, serde_json::to_value(v)))
.filter_map(|(k, v)| v.ok().map(|v| (k, v)))
.collect();
Ok(Response { Ok(Response {
avatar_url, avatar_url,
blurhash, blurhash,

View File

@@ -1,7 +1,9 @@
use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join3}; use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join3};
use ruma::{ use ruma::{
MxcUri, OwnedMxcUri, OwnedRoomId, UserId, MxcUri, OwnedMxcUri, OwnedRoomId, UserId,
api::client::profile::ProfileFieldValue,
events::room::member::{MembershipState, RoomMemberEventContent}, events::room::member::{MembershipState, RoomMemberEventContent},
serde::Raw,
}; };
use tuwunel_core::{ use tuwunel_core::{
Result, implement, Result, implement,
@@ -216,8 +218,8 @@ pub async fn timezone(&self, user_id: &UserId) -> Result<String> {
pub fn all_profile_keys<'a>( pub fn all_profile_keys<'a>(
&'a self, &'a self,
user_id: &'a UserId, user_id: &'a UserId,
) -> impl Stream<Item = (String, serde_json::Value)> + 'a + Send { ) -> impl Stream<Item = (String, Raw<ProfileFieldValue>)> + 'a + Send {
type KeyVal = ((Ignore, String), serde_json::Value); type KeyVal = ((Ignore, String), Raw<ProfileFieldValue>);
let prefix = (user_id, Interfix); let prefix = (user_id, Interfix);
self.db self.db
@@ -253,7 +255,7 @@ pub async fn profile_key(
&self, &self,
user_id: &UserId, user_id: &UserId,
profile_key: &str, profile_key: &str,
) -> Result<serde_json::Value> { ) -> Result<Raw<ProfileFieldValue>> {
let key = (user_id, profile_key); let key = (user_id, profile_key);
self.db self.db
.useridprofilekey_value .useridprofilekey_value