1use std::borrow::Cow;
2
3use futures::StreamExt;
4use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId};
5use tuwunel_core::{Err, Result, err, utils::BoolExt};
6use tuwunel_service::Services;
7
8const UNFEDERATABLE_CAVEAT: &str = ", but this room's `m.room.create` event sets `m.federate` \
9 to false, so remote users still cannot join it or be \
10 invited to it. That property is fixed when the room is \
11 created and no command can change it.";
12
13pub(crate) async fn get_room_info(
14 services: &Services,
15 room_id: &RoomId,
16) -> (OwnedRoomId, u64, String) {
17 let join_count = services
18 .state_cache
19 .room_joined_count(room_id)
20 .await
21 .unwrap_or(0);
22
23 let name = match services.state_accessor.get_name(room_id).await {
24 | Ok(name) => name,
25 | Err(_) if join_count == 2 => services
26 .state_cache
27 .room_members(room_id)
28 .map(ToString::to_string)
29 .collect::<Vec<_>>()
30 .await
31 .join(", "),
32 | Err(_) => room_id.to_string(),
33 };
34
35 (room_id.into(), join_count, name)
36}
37
38pub(crate) async fn room_enabled_reply(
46 services: &Services,
47 room_id: &RoomId,
48 confirmation: &'static str,
49 prefix: &'static str,
50) -> Cow<'static, str> {
51 services
52 .state_accessor
53 .is_federating(room_id)
54 .await
55 .map_or_else(|| format!("{prefix}{UNFEDERATABLE_CAVEAT}").into(), || confirmation.into())
56}
57
58pub(crate) async fn parse_active_local_user_id(
63 services: &Services,
64 user_id: &str,
65) -> Result<OwnedUserId> {
66 let user_id = parse_existing_local_user_id(services, user_id).await?;
67
68 if services.users.is_deactivated(&user_id).await? {
69 return Err!("User {user_id:?} is deactivated.");
70 }
71
72 Ok(user_id)
73}
74
75pub(crate) async fn parse_existing_local_user_id(
80 services: &Services,
81 user_id: &str,
82) -> Result<OwnedUserId> {
83 let user_id = parse_user_id(services, user_id)?;
84
85 check_existing_local_user(services, &user_id).await?;
86
87 Ok(user_id)
88}
89
90pub(crate) fn parse_local_user_id(services: &Services, user_id: &str) -> Result<OwnedUserId> {
95 let user_id = parse_user_id(services, user_id)?;
96
97 if !services.globals.user_is_local(&user_id) {
98 return Err!("User {user_id:?} does not belong to our server.");
99 }
100
101 Ok(user_id)
102}
103
104pub(crate) fn parse_user_id(services: &Services, user_id: &str) -> Result<OwnedUserId> {
109 UserId::parse_with_server_name(user_id.to_lowercase(), services.globals.server_name())
110 .map_err(|e| err!("The supplied username is not a valid username: {e}"))
111}
112
113pub(crate) async fn check_existing_local_user(services: &Services, user_id: &UserId) -> Result {
117 if !services.globals.user_is_local(user_id) {
118 return Err!("User {user_id:?} does not belong to our server.");
119 }
120
121 if !services.users.exists(user_id).await {
122 return Err!("User {user_id:?} does not exist on this server.");
123 }
124
125 Ok(())
126}
127
128pub(crate) async fn check_known_remote_user(services: &Services, user_id: &UserId) -> Result {
129 if services.globals.user_is_local(user_id) {
130 return Err!("User {user_id:?} belongs to our server.");
131 }
132
133 if !services.users.exists(user_id).await {
134 return Err!("User {user_id:?} is not known to this server.");
135 }
136
137 Ok(())
138}