Membership refactor

Introduce deactivate, membership services

Move membership and user deactivation functions from api crate into those services
This commit is contained in:
dasha_uwu
2025-08-25 19:12:27 +05:00
parent 6810604629
commit 8e9c6661b2
28 changed files with 2318 additions and 2091 deletions

View File

@@ -1,7 +1,6 @@
use clap::Subcommand;
use futures::{FutureExt, StreamExt};
use ruma::{OwnedRoomId, OwnedRoomOrAliasId, RoomAliasId, RoomId, RoomOrAliasId};
use tuwunel_api::client::leave_room;
use tuwunel_core::{
Err, Result, debug,
utils::{IterStream, ReadyExt},
@@ -152,13 +151,20 @@ async fn ban_room(&self, room: OwnedRoomOrAliasId) -> Result {
evicting admins too)",
);
if let Err(e) = leave_room(self.services, user_id, &room_id, None)
let state_lock = self.services.state.mutex.lock(&room_id).await;
if let Err(e) = self
.services
.membership
.leave(user_id, &room_id, None, &state_lock)
.boxed()
.await
{
warn!("Failed to leave room: {e}");
}
drop(state_lock);
self.services
.state_cache
.forget(&room_id, user_id);
@@ -320,13 +326,20 @@ async fn ban_list_of_rooms(&self) -> Result {
evicting admins too)",
);
if let Err(e) = leave_room(self.services, user_id, &room_id, None)
let state_lock = self.services.state.mutex.lock(&room_id).await;
if let Err(e) = self
.services
.membership
.leave(user_id, &room_id, None, &state_lock)
.boxed()
.await
{
warn!("Failed to leave room: {e}");
}
drop(state_lock);
self.services
.state_cache
.forget(&room_id, user_id);

View File

@@ -12,16 +12,13 @@ use ruma::{
tag::{TagEvent, TagEventContent, TagInfo},
},
};
use tuwunel_api::client::{
full_user_deactivate, join_room_by_id_helper, leave_all_rooms, leave_room, update_avatar_url,
update_displayname,
};
use tuwunel_core::{
Err, Result, debug, debug_warn, error, info, is_equal_to,
matrix::{Event, pdu::PduBuilder},
utils::{self, ReadyExt},
warn,
};
use tuwunel_service::Services;
use crate::{
admin_command, get_room_info,
@@ -142,20 +139,24 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
continue;
}
let state_lock = self.services.state.mutex.lock(&room_id).await;
if let Some(room_server_name) = room.server_name() {
match join_room_by_id_helper(
self.services,
&user_id,
&room_id,
Some("Automatically joining this room upon registration".to_owned()),
&[
self.services.globals.server_name().to_owned(),
room_server_name.to_owned(),
],
None,
&None,
)
.await
match self
.services
.membership
.join(
&user_id,
&room_id,
Some("Automatically joining this room upon registration".to_owned()),
&[
self.services.globals.server_name().to_owned(),
room_server_name.to_owned(),
],
&None,
&state_lock,
)
.await
{
| Ok(_response) => {
info!("Automatically joined room {room} for user {user_id}");
@@ -174,6 +175,8 @@ pub(super) async fn create_user(&self, username: String, password: Option<String
.await;
},
}
drop(state_lock);
}
}
}
@@ -215,33 +218,7 @@ pub(super) async fn deactivate(&self, no_leave_rooms: bool, user_id: String) ->
return Err!("Not allowed to deactivate the server service account.",);
}
self.services
.users
.deactivate_account(&user_id)
.await?;
if !no_leave_rooms {
self.services
.admin
.send_text(&format!("Making {user_id} leave all rooms after deactivation..."))
.await;
let all_joined_rooms: Vec<OwnedRoomId> = self
.services
.state_cache
.rooms_joined(&user_id)
.map(Into::into)
.collect()
.await;
full_user_deactivate(self.services, &user_id, &all_joined_rooms)
.boxed()
.await?;
update_displayname(self.services, &user_id, None, &all_joined_rooms).await;
update_avatar_url(self.services, &user_id, None, None, &all_joined_rooms).await;
leave_all_rooms(self.services, &user_id).await;
}
deactivate_user(self.services, &user_id, no_leave_rooms).await?;
self.write_str(&format!("User {user_id} has been deactivated"))
.await
@@ -334,40 +311,16 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
let mut deactivation_count: usize = 0;
for user_id in user_ids {
match self
.services
.users
.deactivate_account(&user_id)
.await
{
match deactivate_user(self.services, &user_id, no_leave_rooms).await {
| Ok(()) => {
deactivation_count = deactivation_count.saturating_add(1);
},
| Err(e) => {
self.services
.admin
.send_text(&format!("Failed deactivating user: {e}"))
.await;
},
| Ok(()) => {
deactivation_count = deactivation_count.saturating_add(1);
if !no_leave_rooms {
info!("Forcing user {user_id} to leave all rooms apart of deactivate-all");
let all_joined_rooms: Vec<OwnedRoomId> = self
.services
.state_cache
.rooms_joined(&user_id)
.map(Into::into)
.collect()
.await;
full_user_deactivate(self.services, &user_id, &all_joined_rooms)
.boxed()
.await?;
update_displayname(self.services, &user_id, None, &all_joined_rooms).await;
update_avatar_url(self.services, &user_id, None, None, &all_joined_rooms)
.await;
leave_all_rooms(self.services, &user_id).await;
}
},
}
}
@@ -384,6 +337,20 @@ pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) ->
.await
}
async fn deactivate_user(services: &Services, user_id: &UserId, no_leave_rooms: bool) -> Result {
if !no_leave_rooms {
services
.deactivate
.full_deactivate(user_id)
.boxed()
.await?;
} else {
services.users.deactivate_account(user_id).await?;
}
Ok(())
}
#[admin_command]
pub(super) async fn list_joined_rooms(&self, user_id: String) -> Result {
// Validate user id
@@ -510,17 +477,21 @@ pub(super) async fn force_join_list_of_local_users(
let mut failed_joins: usize = 0;
let mut successful_joins: usize = 0;
let state_lock = self.services.state.mutex.lock(&room_id).await;
for user_id in user_ids {
match join_room_by_id_helper(
self.services,
&user_id,
&room_id,
Some(String::from(BULK_JOIN_REASON)),
&servers,
None,
&None,
)
.await
match self
.services
.membership
.join(
&user_id,
&room_id,
Some(String::from(BULK_JOIN_REASON)),
&servers,
&None,
&state_lock,
)
.await
{
| Ok(_res) => {
successful_joins = successful_joins.saturating_add(1);
@@ -532,6 +503,8 @@ pub(super) async fn force_join_list_of_local_users(
}
}
drop(state_lock);
self.write_str(&format!(
"{successful_joins} local users have been joined to {room_id}. {failed_joins} joins \
failed.",
@@ -592,6 +565,8 @@ pub(super) async fn force_join_all_local_users(
let mut failed_joins: usize = 0;
let mut successful_joins: usize = 0;
let state_lock = self.services.state.mutex.lock(&room_id).await;
for user_id in &self
.services
.users
@@ -600,16 +575,18 @@ pub(super) async fn force_join_all_local_users(
.collect::<Vec<_>>()
.await
{
match join_room_by_id_helper(
self.services,
user_id,
&room_id,
Some(String::from(BULK_JOIN_REASON)),
&servers,
None,
&None,
)
.await
match self
.services
.membership
.join(
user_id,
&room_id,
Some(String::from(BULK_JOIN_REASON)),
&servers,
&None,
&state_lock,
)
.await
{
| Ok(_res) => {
successful_joins = successful_joins.saturating_add(1);
@@ -621,6 +598,8 @@ pub(super) async fn force_join_all_local_users(
}
}
drop(state_lock);
self.write_str(&format!(
"{successful_joins} local users have been joined to {room_id}. {failed_joins} joins \
failed.",
@@ -645,9 +624,16 @@ pub(super) async fn force_join_room(
self.services.globals.user_is_local(&user_id),
"Parsed user_id must be a local user"
);
join_room_by_id_helper(self.services, &user_id, &room_id, None, &servers, None, &None)
let state_lock = self.services.state.mutex.lock(&room_id).await;
self.services
.membership
.join(&user_id, &room_id, None, &servers, &None, &state_lock)
.await?;
drop(state_lock);
self.write_str(&format!("{user_id} has been joined to {room_id}.",))
.await
}
@@ -675,10 +661,16 @@ pub(super) async fn force_leave_room(
return Err!("{user_id} is not joined in the room");
}
leave_room(self.services, &user_id, &room_id, None)
let state_lock = self.services.state.mutex.lock(&room_id).await;
self.services
.membership
.leave(&user_id, &room_id, None, &state_lock)
.boxed()
.await?;
drop(state_lock);
self.write_str(&format!("{user_id} has left {room_id}.",))
.await
}