Take stuff by ref in users service profile

This commit is contained in:
dasha_uwu
2026-01-26 13:26:17 +05:00
committed by Jason Volk
parent c76a66be28
commit 73eee626df
5 changed files with 128 additions and 148 deletions

View File

@@ -43,7 +43,7 @@ pub(crate) async fn set_displayname_route(
services services
.users .users
.update_displayname(&body.user_id, body.displayname.clone(), &all_joined_rooms) .update_displayname(&body.user_id, body.displayname.as_deref(), &all_joined_rooms)
.await; .await;
// Presence update // Presence update
@@ -87,13 +87,13 @@ pub(crate) async fn get_displayname_route(
services services
.users .users
.set_displayname(&body.user_id, response.displayname.clone()); .set_displayname(&body.user_id, response.displayname.as_deref());
services services
.users .users
.set_avatar_url(&body.user_id, response.avatar_url.clone()); .set_avatar_url(&body.user_id, response.avatar_url.as_deref());
services services
.users .users
.set_blurhash(&body.user_id, response.blurhash.clone()); .set_blurhash(&body.user_id, response.blurhash.as_deref());
return Ok(get_display_name::v3::Response { displayname: response.displayname }); return Ok(get_display_name::v3::Response { displayname: response.displayname });
} }
@@ -140,8 +140,8 @@ pub(crate) async fn set_avatar_url_route(
.users .users
.update_avatar_url( .update_avatar_url(
&body.user_id, &body.user_id,
body.avatar_url.clone(), body.avatar_url.as_deref(),
body.blurhash.clone(), body.blurhash.as_deref(),
&all_joined_rooms, &all_joined_rooms,
) )
.await; .await;
@@ -188,13 +188,13 @@ pub(crate) async fn get_avatar_url_route(
services services
.users .users
.set_displayname(&body.user_id, response.displayname.clone()); .set_displayname(&body.user_id, response.displayname.as_deref());
services services
.users .users
.set_avatar_url(&body.user_id, response.avatar_url.clone()); .set_avatar_url(&body.user_id, response.avatar_url.as_deref());
services services
.users .users
.set_blurhash(&body.user_id, response.blurhash.clone()); .set_blurhash(&body.user_id, response.blurhash.as_deref());
return Ok(get_avatar_url::v3::Response { return Ok(get_avatar_url::v3::Response {
avatar_url: response.avatar_url, avatar_url: response.avatar_url,
@@ -250,22 +250,22 @@ pub(crate) async fn get_profile_route(
services services
.users .users
.set_displayname(&body.user_id, response.displayname.clone()); .set_displayname(&body.user_id, response.displayname.as_deref());
services services
.users .users
.set_avatar_url(&body.user_id, response.avatar_url.clone()); .set_avatar_url(&body.user_id, response.avatar_url.as_deref());
services services
.users .users
.set_blurhash(&body.user_id, response.blurhash.clone()); .set_blurhash(&body.user_id, response.blurhash.as_deref());
services services
.users .users
.set_timezone(&body.user_id, response.tz.clone()); .set_timezone(&body.user_id, response.tz.as_deref());
for (profile_key, profile_key_value) in &response.custom_profile_fields { for (profile_key, profile_key_value) in &response.custom_profile_fields {
services.users.set_profile_key( services.users.set_profile_key(
&body.user_id, &body.user_id,
profile_key, profile_key,
Some(profile_key_value.clone()), Some(profile_key_value),
); );
} }

View File

@@ -7,7 +7,7 @@ use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD as b64};
use futures::{FutureExt, StreamExt, TryFutureExt, future::try_join}; use futures::{FutureExt, StreamExt, TryFutureExt, future::try_join};
use reqwest::header::{CONTENT_TYPE, HeaderValue}; use reqwest::header::{CONTENT_TYPE, HeaderValue};
use ruma::{ use ruma::{
Mxc, OwnedRoomId, OwnedUserId, ServerName, UserId, Mxc, OwnedMxcUri, OwnedRoomId, OwnedUserId, ServerName, UserId,
api::client::session::{sso_callback, sso_login, sso_login_with_provider}, api::client::session::{sso_callback, sso_login, sso_login_with_provider},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -556,10 +556,10 @@ async fn set_avatar(
.collect() .collect()
.await; .await;
let mxc_uri = mxc.to_string().into(); let mxc_uri: OwnedMxcUri = mxc.to_string().into();
services services
.users .users
.update_avatar_url(user_id, Some(mxc_uri), None, &all_joined_rooms) .update_avatar_url(user_id, Some(&mxc_uri), None, &all_joined_rooms)
.await; .await;
Ok(()) Ok(())

View File

@@ -16,7 +16,7 @@ use ruma::{
}, },
presence::PresenceState, presence::PresenceState,
}; };
use tuwunel_core::{Err, Error, Result}; use tuwunel_core::{Err, Error, Result, err};
use crate::Ruma; use crate::Ruma;
@@ -99,7 +99,7 @@ pub(crate) async fn set_timezone_key_route(
services services
.users .users
.set_timezone(&body.user_id, body.tz.clone()); .set_timezone(&body.user_id, body.tz.as_deref());
// Presence update // Presence update
services services
@@ -129,42 +129,40 @@ pub(crate) async fn set_profile_field_route(
return Err!(Request(BadJson("Key names cannot be longer than 128 bytes"))); return Err!(Request(BadJson("Key names cannot be longer than 128 bytes")));
} }
if body.value.field_name() == ProfileFieldName::DisplayName { match &body.value {
let all_joined_rooms: Vec<OwnedRoomId> = services | ProfileFieldValue::DisplayName(displayname) => {
.state_cache let all_joined_rooms: Vec<OwnedRoomId> = services
.rooms_joined(&body.user_id) .state_cache
.map(Into::into) .rooms_joined(&body.user_id)
.collect() .map(Into::into)
.await; .collect()
.await;
services services
.users .users
.update_displayname( .update_displayname(&body.user_id, Some(displayname), &all_joined_rooms)
.await;
},
| ProfileFieldValue::AvatarUrl(avatar_url) => {
let all_joined_rooms: Vec<OwnedRoomId> = services
.state_cache
.rooms_joined(&body.user_id)
.map(Into::into)
.collect()
.await;
services
.users
.update_avatar_url(&body.user_id, Some(avatar_url), None, &all_joined_rooms)
.await;
},
| _ => {
services.users.set_profile_key(
&body.user_id, &body.user_id,
Some(body.value.value().to_string()), body.value.field_name().as_str(),
&all_joined_rooms, Some(&body.value.value()),
) );
.await; },
} else if body.value.field_name() == ProfileFieldName::AvatarUrl {
let mxc = ruma::OwnedMxcUri::from(body.value.value().to_string());
let all_joined_rooms: Vec<OwnedRoomId> = services
.state_cache
.rooms_joined(&body.user_id)
.map(Into::into)
.collect()
.await;
services
.users
.update_avatar_url(&body.user_id, Some(mxc), None, &all_joined_rooms)
.await;
} else {
services.users.set_profile_key(
&body.user_id,
body.value.field_name().as_str(),
Some(body.value.value().into_owned()),
);
} }
// Presence update // Presence update
@@ -191,34 +189,38 @@ pub(crate) async fn delete_profile_field_route(
return Err!(Request(Forbidden("You cannot update the profile of another user"))); return Err!(Request(Forbidden("You cannot update the profile of another user")));
} }
if body.field == ProfileFieldName::DisplayName { match body.field {
let all_joined_rooms: Vec<OwnedRoomId> = services | ProfileFieldName::DisplayName => {
.state_cache let all_joined_rooms: Vec<OwnedRoomId> = services
.rooms_joined(&body.user_id) .state_cache
.map(Into::into) .rooms_joined(&body.user_id)
.collect() .map(Into::into)
.await; .collect()
.await;
services services
.users .users
.update_displayname(&body.user_id, None, &all_joined_rooms) .update_displayname(&body.user_id, None, &all_joined_rooms)
.await; .await;
} else if body.field == ProfileFieldName::AvatarUrl { },
let all_joined_rooms: Vec<OwnedRoomId> = services | ProfileFieldName::AvatarUrl => {
.state_cache let all_joined_rooms: Vec<OwnedRoomId> = services
.rooms_joined(&body.user_id) .state_cache
.map(Into::into) .rooms_joined(&body.user_id)
.collect() .map(Into::into)
.await; .collect()
.await;
services services
.users .users
.update_avatar_url(&body.user_id, None, None, &all_joined_rooms) .update_avatar_url(&body.user_id, None, None, &all_joined_rooms)
.await; .await;
} else { },
services | _ => {
.users services
.set_profile_key(&body.user_id, body.field.as_str(), None); .users
.set_profile_key(&body.user_id, body.field.as_str(), None);
},
} }
// Presence update // Presence update
@@ -262,19 +264,19 @@ pub(crate) async fn get_timezone_key_route(
services services
.users .users
.set_displayname(&body.user_id, response.displayname.clone()); .set_displayname(&body.user_id, response.displayname.as_deref());
services services
.users .users
.set_avatar_url(&body.user_id, response.avatar_url.clone()); .set_avatar_url(&body.user_id, response.avatar_url.as_deref());
services services
.users .users
.set_blurhash(&body.user_id, response.blurhash.clone()); .set_blurhash(&body.user_id, response.blurhash.as_deref());
services services
.users .users
.set_timezone(&body.user_id, response.tz.clone()); .set_timezone(&body.user_id, response.tz.as_deref());
return Ok(get_timezone_key::unstable::Response { tz: response.tz }); return Ok(get_timezone_key::unstable::Response { tz: response.tz });
} }
@@ -323,43 +325,34 @@ pub(crate) async fn get_profile_field_route(
services services
.users .users
.set_displayname(&body.user_id, response.displayname.clone()); .set_displayname(&body.user_id, response.displayname.as_deref());
services services
.users .users
.set_avatar_url(&body.user_id, response.avatar_url.clone()); .set_avatar_url(&body.user_id, response.avatar_url.as_deref());
services services
.users .users
.set_blurhash(&body.user_id, response.blurhash.clone()); .set_blurhash(&body.user_id, response.blurhash.as_deref());
services services
.users .users
.set_timezone(&body.user_id, response.tz.clone()); .set_timezone(&body.user_id, response.tz.as_deref());
let profile_key_value: Option<ProfileFieldValue> = match response let value = response
.custom_profile_fields .custom_profile_fields
.get(body.field.as_str()) .get(body.field.as_str())
{ .ok_or_else(|| {
| Some(value) => { err!(Request(NotFound("The requested profile key does not exist.")))
services.users.set_profile_key( })?;
&body.user_id,
body.field.as_str(),
Some(value.clone()),
);
Some(ProfileFieldValue::new(body.field.as_str(), value.clone())?) services
}, .users
| _ => { .set_profile_key(&body.user_id, body.field.as_str(), Some(value));
return Err!(Request(NotFound("The requested profile key does not exist.")));
},
};
if profile_key_value.is_none() { let profile_key_value = ProfileFieldValue::new(body.field.as_str(), value.clone())?;
return Err!(Request(NotFound("The requested profile key does not exist.")));
}
return Ok(get_profile_field::v3::Response { value: profile_key_value }); return Ok(get_profile_field::v3::Response { value: Some(profile_key_value) });
} }
} }
@@ -369,20 +362,13 @@ pub(crate) async fn get_profile_field_route(
return Err!(Request(NotFound("Profile was not found."))); return Err!(Request(NotFound("Profile was not found.")));
} }
let profile_key_value: Option<ProfileFieldValue> = match services let value = services
.users .users
.profile_key(&body.user_id, body.field.as_str()) .profile_key(&body.user_id, body.field.as_str())
.await .await
{ .map_err(|_| err!(Request(NotFound("The requested profile key does not exist."))))?;
| Ok(value) => Some(ProfileFieldValue::new(body.field.as_str(), value)?),
| _ => {
return Err!(Request(NotFound("The requested profile key does not exist.")));
},
};
if profile_key_value.is_none() { let profile_key_value = ProfileFieldValue::new(body.field.as_str(), value)?;
return Err!(Request(NotFound("The requested profile key does not exist.")));
}
Ok(get_profile_field::v3::Response { value: profile_key_value }) Ok(get_profile_field::v3::Response { value: Some(profile_key_value) })
} }

View File

@@ -1,6 +1,6 @@
use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join3}; use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join3};
use ruma::{ use ruma::{
OwnedMxcUri, OwnedRoomId, UserId, MxcUri, OwnedMxcUri, OwnedRoomId, UserId,
events::room::member::{MembershipState, RoomMemberEventContent}, events::room::member::{MembershipState, RoomMemberEventContent},
}; };
use tuwunel_core::{ use tuwunel_core::{
@@ -17,7 +17,7 @@ use tuwunel_database::{Deserialized, Ignore, Interfix, Json};
pub async fn update_displayname( pub async fn update_displayname(
&self, &self,
user_id: &UserId, user_id: &UserId,
displayname: Option<String>, displayname: Option<&str>,
rooms: &[OwnedRoomId], rooms: &[OwnedRoomId],
) { ) {
let (current_avatar_url, current_blurhash, current_displayname) = join3( let (current_avatar_url, current_blurhash, current_displayname) = join3(
@@ -27,13 +27,13 @@ pub async fn update_displayname(
) )
.await; .await;
if displayname == current_displayname { if displayname == current_displayname.as_deref() {
return; return;
} }
self.services self.services
.users .users
.set_displayname(user_id, displayname.clone()); .set_displayname(user_id, displayname);
// Send a new join membership event into rooms // Send a new join membership event into rooms
let avatar_url = &current_avatar_url; let avatar_url = &current_avatar_url;
@@ -44,7 +44,7 @@ pub async fn update_displayname(
.try_stream() .try_stream()
.and_then(async |room_id: &OwnedRoomId| { .and_then(async |room_id: &OwnedRoomId| {
let pdu = PduBuilder::state(user_id.to_string(), &RoomMemberEventContent { let pdu = PduBuilder::state(user_id.to_string(), &RoomMemberEventContent {
displayname: displayname.clone(), displayname: displayname.map(ToOwned::to_owned),
membership: MembershipState::Join, membership: MembershipState::Join,
avatar_url: avatar_url.clone(), avatar_url: avatar_url.clone(),
blurhash: blurhash.clone(), blurhash: blurhash.clone(),
@@ -68,7 +68,7 @@ pub async fn update_displayname(
/// Sets a new displayname or removes it if displayname is None. You still /// Sets a new displayname or removes it if displayname is None. You still
/// need to notify all rooms of this change. /// need to notify all rooms of this change.
#[implement(super::Service)] #[implement(super::Service)]
pub fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) { pub fn set_displayname(&self, user_id: &UserId, displayname: Option<&str>) {
if let Some(displayname) = displayname { if let Some(displayname) = displayname {
self.db self.db
.userid_displayname .userid_displayname
@@ -92,8 +92,8 @@ pub async fn displayname(&self, user_id: &UserId) -> Result<String> {
pub async fn update_avatar_url( pub async fn update_avatar_url(
&self, &self,
user_id: &UserId, user_id: &UserId,
avatar_url: Option<OwnedMxcUri>, avatar_url: Option<&MxcUri>,
blurhash: Option<String>, blurhash: Option<&str>,
rooms: &[OwnedRoomId], rooms: &[OwnedRoomId],
) { ) {
let (current_avatar_url, current_blurhash, current_displayname) = join3( let (current_avatar_url, current_blurhash, current_displayname) = join3(
@@ -103,30 +103,27 @@ pub async fn update_avatar_url(
) )
.await; .await;
if current_avatar_url == avatar_url && current_blurhash == blurhash { if current_avatar_url.as_deref() == avatar_url && current_blurhash.as_deref() == blurhash {
return; return;
} }
self.services self.services
.users .users
.set_avatar_url(user_id, avatar_url.clone()); .set_avatar_url(user_id, avatar_url);
self.services self.services
.users .users
.set_blurhash(user_id, blurhash.clone()); .set_blurhash(user_id, blurhash);
// Send a new join membership event into rooms // Send a new join membership event into rooms
let avatar_url = &avatar_url;
let blurhash = &blurhash;
let displayname = &current_displayname;
let rooms: Vec<_> = rooms let rooms: Vec<_> = rooms
.iter() .iter()
.try_stream() .try_stream()
.and_then(async |room_id: &OwnedRoomId| { .and_then(async |room_id: &OwnedRoomId| {
let pdu = PduBuilder::state(user_id.to_string(), &RoomMemberEventContent { let pdu = PduBuilder::state(user_id.to_string(), &RoomMemberEventContent {
avatar_url: avatar_url.clone(), avatar_url: avatar_url.map(ToOwned::to_owned),
blurhash: blurhash.clone(), blurhash: blurhash.map(ToOwned::to_owned),
membership: MembershipState::Join, membership: MembershipState::Join,
displayname: displayname.clone(), displayname: current_displayname.clone(),
join_authorized_via_users_server: None, join_authorized_via_users_server: None,
reason: None, reason: None,
is_direct: None, is_direct: None,
@@ -146,16 +143,13 @@ pub async fn update_avatar_url(
/// Sets a new avatar_url or removes it if avatar_url is None. /// Sets a new avatar_url or removes it if avatar_url is None.
#[implement(super::Service)] #[implement(super::Service)]
pub fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<OwnedMxcUri>) { pub fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<&MxcUri>) {
match avatar_url { if let Some(avatar_url) = avatar_url {
| Some(avatar_url) => { self.db
self.db .userid_avatarurl
.userid_avatarurl .insert(user_id, avatar_url);
.insert(user_id, &avatar_url); } else {
}, self.db.userid_avatarurl.remove(user_id);
| _ => {
self.db.userid_avatarurl.remove(user_id);
},
} }
} }
@@ -171,7 +165,7 @@ pub async fn avatar_url(&self, user_id: &UserId) -> Result<OwnedMxcUri> {
/// Sets a new avatar_url or removes it if avatar_url is None. /// Sets a new avatar_url or removes it if avatar_url is None.
#[implement(super::Service)] #[implement(super::Service)]
pub fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) { pub fn set_blurhash(&self, user_id: &UserId, blurhash: Option<&str>) {
if let Some(blurhash) = blurhash { if let Some(blurhash) = blurhash {
self.db.userid_blurhash.insert(user_id, blurhash); self.db.userid_blurhash.insert(user_id, blurhash);
} else { } else {
@@ -191,14 +185,14 @@ pub async fn blurhash(&self, user_id: &UserId) -> Result<String> {
/// Sets a new timezone or removes it if timezone is None. /// Sets a new timezone or removes it if timezone is None.
#[implement(super::Service)] #[implement(super::Service)]
pub fn set_timezone(&self, user_id: &UserId, timezone: Option<String>) { pub fn set_timezone(&self, user_id: &UserId, timezone: Option<&str>) {
// TODO: insert to the stable MSC4175 key when it's stable // TODO: insert to the stable MSC4175 key when it's stable
let key = (user_id, "us.cloke.msc4175.tz"); let key = (user_id, "us.cloke.msc4175.tz");
if let Some(timezone) = timezone { if let Some(timezone) = timezone {
self.db self.db
.useridprofilekey_value .useridprofilekey_value
.put_raw(key, &timezone); .put_raw(key, timezone);
} else { } else {
self.db.useridprofilekey_value.del(key); self.db.useridprofilekey_value.del(key);
} }
@@ -243,7 +237,7 @@ pub fn set_profile_key(
&self, &self,
user_id: &UserId, user_id: &UserId,
profile_key: &str, profile_key: &str,
profile_key_value: Option<serde_json::Value>, profile_key_value: Option<&serde_json::Value>,
) { ) {
// TODO: insert to the stable MSC4175 key when it's stable // TODO: insert to the stable MSC4175 key when it's stable
let key = (user_id, profile_key); let key = (user_id, profile_key);

View File

@@ -86,7 +86,7 @@ pub async fn full_register(
self.services self.services
.users .users
.set_displayname(user_id, Some(displayname)); .set_displayname(user_id, Some(&displayname));
} }
// Initial account data // Initial account data