matrix_sdk/room/
privacy_settings.rs1use matrix_sdk_base::Room as BaseRoom;
2use ruma::{
3 OwnedRoomAliasId, RoomAliasId,
4 api::client::{
5 directory::{get_room_visibility, set_room_visibility},
6 room::Visibility,
7 state::send_state_event,
8 },
9 assign,
10 events::{
11 EmptyStateKey,
12 room::{
13 canonical_alias::RoomCanonicalAliasEventContent,
14 history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
15 join_rules::{JoinRule, RoomJoinRulesEventContent},
16 },
17 },
18};
19
20use crate::{Client, Result};
21
22#[derive(Debug)]
25pub struct RoomPrivacySettings<'a> {
26 room: &'a BaseRoom,
27 client: &'a Client,
28}
29
30impl<'a> RoomPrivacySettings<'a> {
31 pub(crate) fn new(room: &'a BaseRoom, client: &'a Client) -> Self {
32 Self { room, client }
33 }
34
35 pub async fn publish_room_alias_in_room_directory(
42 &'a self,
43 alias: &RoomAliasId,
44 ) -> Result<bool> {
45 if self.client.is_room_alias_available(alias).await? {
46 self.client.create_room_alias(alias, self.room.room_id()).await?;
47 return Ok(true);
48 }
49
50 Ok(false)
51 }
52
53 pub async fn remove_room_alias_from_room_directory(
60 &'a self,
61 alias: &RoomAliasId,
62 ) -> Result<bool> {
63 if self.client.resolve_room_alias(alias).await.is_ok() {
64 self.client.remove_room_alias(alias).await?;
65 return Ok(true);
66 }
67
68 Ok(false)
69 }
70
71 pub async fn update_canonical_alias(
84 &'a self,
85 alias: Option<OwnedRoomAliasId>,
86 alt_aliases: Vec<OwnedRoomAliasId>,
87 ) -> Result<()> {
88 let content = assign!(
90 RoomCanonicalAliasEventContent::new(),
91 { alias, alt_aliases }
92 );
93
94 let request = send_state_event::v3::Request::new(
96 self.room.room_id().to_owned(),
97 &EmptyStateKey,
98 &content,
99 )?;
100 self.client.send(request).await?;
101
102 Ok(())
103 }
104
105 pub async fn update_room_history_visibility(
112 &'a self,
113 new_value: HistoryVisibility,
114 ) -> Result<()> {
115 let request = send_state_event::v3::Request::new(
116 self.room.room_id().to_owned(),
117 &EmptyStateKey,
118 &RoomHistoryVisibilityEventContent::new(new_value),
119 )?;
120 self.client.send(request).await?;
121 Ok(())
122 }
123
124 pub async fn update_join_rule(&'a self, new_rule: JoinRule) -> Result<()> {
131 let request = send_state_event::v3::Request::new(
132 self.room.room_id().to_owned(),
133 &EmptyStateKey,
134 &RoomJoinRulesEventContent::new(new_rule),
135 )?;
136 self.client.send(request).await?;
137 Ok(())
138 }
139
140 pub async fn get_room_visibility(&'a self) -> Result<Visibility> {
145 let request = get_room_visibility::v3::Request::new(self.room.room_id().to_owned());
146 let response = self.client.send(request).await?;
147 Ok(response.visibility)
148 }
149
150 pub async fn update_room_visibility(&'a self, visibility: Visibility) -> Result<()> {
155 let request =
156 set_room_visibility::v3::Request::new(self.room.room_id().to_owned(), visibility);
157
158 self.client.send(request).await?;
159
160 Ok(())
161 }
162}
163
164#[cfg(all(test, not(target_family = "wasm")))]
165mod tests {
166 use std::ops::Not;
167
168 use matrix_sdk_test::{JoinedRoomBuilder, async_test, event_factory::EventFactory};
169 use ruma::{
170 api::client::room::Visibility,
171 event_id,
172 events::{
173 StateEventType,
174 room::{history_visibility::HistoryVisibility, join_rules::JoinRule},
175 },
176 owned_room_alias_id, room_id, user_id,
177 };
178
179 use crate::test_utils::mocks::MatrixMockServer;
180
181 #[async_test]
182 async fn test_publish_room_alias_to_room_directory() {
183 let server = MatrixMockServer::new().await;
184 let client = server.client_builder().build().await;
185
186 let room_id = room_id!("!a:b.c");
187 let room = server.sync_joined_room(&client, room_id).await;
188
189 let room_alias = owned_room_alias_id!("#a:b.c");
190
191 server
193 .mock_room_directory_resolve_alias()
194 .for_alias(room_alias.to_string())
195 .not_found()
196 .mock_once()
197 .mount()
198 .await;
199
200 server.mock_room_directory_create_room_alias().ok().mock_once().mount().await;
202
203 let published = room
204 .privacy_settings()
205 .publish_room_alias_in_room_directory(&room_alias)
206 .await
207 .expect("we should get a result value, not an error");
208 assert!(published);
209 }
210
211 #[async_test]
212 async fn test_publish_room_alias_to_room_directory_when_alias_exists() {
213 let server = MatrixMockServer::new().await;
214 let client = server.client_builder().build().await;
215
216 let room_id = room_id!("!a:b.c");
217 let room = server.sync_joined_room(&client, room_id).await;
218
219 let room_alias = owned_room_alias_id!("#a:b.c");
220
221 server
223 .mock_room_directory_resolve_alias()
224 .for_alias(room_alias.to_string())
225 .ok(room_id.as_ref(), Vec::new())
226 .mock_once()
227 .mount()
228 .await;
229
230 server.mock_room_directory_create_room_alias().ok().never().mount().await;
232
233 let published = room
234 .privacy_settings()
235 .publish_room_alias_in_room_directory(&room_alias)
236 .await
237 .expect("we should get a result value, not an error");
238 assert!(published.not());
239 }
240
241 #[async_test]
242 async fn test_remove_room_alias() {
243 let server = MatrixMockServer::new().await;
244 let client = server.client_builder().build().await;
245
246 let room_id = room_id!("!a:b.c");
247 let f = EventFactory::new().sender(user_id!("@example:localhost"));
248 let joined_room_builder = JoinedRoomBuilder::new(room_id).add_state_event(
249 f.canonical_alias(Some(owned_room_alias_id!("#tutorial:localhost")), vec![]),
250 );
251 let room = server.sync_room(&client, joined_room_builder).await;
252
253 let room_alias = owned_room_alias_id!("#a:b.c");
254
255 server
257 .mock_room_directory_resolve_alias()
258 .for_alias(room_alias.to_string())
259 .ok(room_id.as_ref(), Vec::new())
260 .mock_once()
261 .mount()
262 .await;
263
264 server.mock_room_directory_remove_room_alias().ok().mock_once().mount().await;
266
267 let removed = room
268 .privacy_settings()
269 .remove_room_alias_from_room_directory(&room_alias)
270 .await
271 .expect("we should get a result value, not an error");
272 assert!(removed);
273 }
274
275 #[async_test]
276 async fn test_remove_room_alias_if_it_does_not_exist() {
277 let server = MatrixMockServer::new().await;
278 let client = server.client_builder().build().await;
279
280 let room_id = room_id!("!a:b.c");
281 let f = EventFactory::new().sender(user_id!("@example:localhost"));
282 let joined_room_builder = JoinedRoomBuilder::new(room_id).add_state_event(
283 f.canonical_alias(Some(owned_room_alias_id!("#tutorial:localhost")), vec![]),
284 );
285 let room = server.sync_room(&client, joined_room_builder).await;
286
287 let room_alias = owned_room_alias_id!("#a:b.c");
288
289 server
291 .mock_room_directory_resolve_alias()
292 .for_alias(room_alias.to_string())
293 .not_found()
294 .mock_once()
295 .mount()
296 .await;
297
298 server.mock_room_directory_remove_room_alias().ok().never().mount().await;
300
301 let removed = room
302 .privacy_settings()
303 .remove_room_alias_from_room_directory(&room_alias)
304 .await
305 .expect("we should get a result value, not an error");
306 assert!(removed.not());
307 }
308
309 #[async_test]
310 async fn test_update_canonical_alias_with_some_value() {
311 let server = MatrixMockServer::new().await;
312 let client = server.client_builder().build().await;
313
314 let room_id = room_id!("!a:b.c");
315 let room = server.sync_joined_room(&client, room_id).await;
316
317 server
318 .mock_room_send_state()
319 .for_type(StateEventType::RoomCanonicalAlias)
320 .ok(event_id!("$a:b.c"))
321 .mock_once()
322 .mount()
323 .await;
324
325 let room_alias = owned_room_alias_id!("#a:b.c");
326 let ret = room
327 .privacy_settings()
328 .update_canonical_alias(Some(room_alias.clone()), Vec::new())
329 .await;
330 assert!(ret.is_ok());
331 }
332
333 #[async_test]
334 async fn test_update_canonical_alias_with_no_value() {
335 let server = MatrixMockServer::new().await;
336 let client = server.client_builder().build().await;
337
338 let room_id = room_id!("!a:b.c");
339 let room = server.sync_joined_room(&client, room_id).await;
340
341 server
342 .mock_room_send_state()
343 .for_type(StateEventType::RoomCanonicalAlias)
344 .ok(event_id!("$a:b.c"))
345 .mock_once()
346 .mount()
347 .await;
348
349 let ret = room.privacy_settings().update_canonical_alias(None, Vec::new()).await;
350 assert!(ret.is_ok());
351 }
352
353 #[async_test]
354 async fn test_update_room_history_visibility() {
355 let server = MatrixMockServer::new().await;
356 let client = server.client_builder().build().await;
357
358 let room_id = room_id!("!a:b.c");
359 let room = server.sync_joined_room(&client, room_id).await;
360
361 server
362 .mock_room_send_state()
363 .for_type(StateEventType::RoomHistoryVisibility)
364 .ok(event_id!("$a:b.c"))
365 .mock_once()
366 .mount()
367 .await;
368
369 let ret =
370 room.privacy_settings().update_room_history_visibility(HistoryVisibility::Joined).await;
371 assert!(ret.is_ok());
372 }
373
374 #[async_test]
375 async fn test_update_join_rule() {
376 let server = MatrixMockServer::new().await;
377 let client = server.client_builder().build().await;
378
379 let room_id = room_id!("!a:b.c");
380 let room = server.sync_joined_room(&client, room_id).await;
381
382 server
383 .mock_room_send_state()
384 .for_type(StateEventType::RoomJoinRules)
385 .ok(event_id!("$a:b.c"))
386 .mock_once()
387 .mount()
388 .await;
389
390 let ret = room.privacy_settings().update_join_rule(JoinRule::Public).await;
391 assert!(ret.is_ok());
392 }
393
394 #[async_test]
395 async fn test_get_room_visibility() {
396 let server = MatrixMockServer::new().await;
397 let client = server.client_builder().build().await;
398
399 let room_id = room_id!("!a:b.c");
400 let room = server.sync_joined_room(&client, room_id).await;
401
402 server
403 .mock_room_send_state()
404 .for_type(StateEventType::RoomJoinRules)
405 .ok(event_id!("$a:b.c"))
406 .mock_once()
407 .mount()
408 .await;
409
410 let ret = room.privacy_settings().update_join_rule(JoinRule::Public).await;
411 assert!(ret.is_ok());
412 }
413
414 #[async_test]
415 async fn test_update_room_visibility() {
416 let server = MatrixMockServer::new().await;
417 let client = server.client_builder().build().await;
418
419 let room_id = room_id!("!a:b.c");
420 let room = server.sync_joined_room(&client, room_id).await;
421
422 server.mock_room_directory_set_room_visibility().ok().mock_once().mount().await;
423
424 let ret = room.privacy_settings().update_room_visibility(Visibility::Private).await;
425 assert!(ret.is_ok());
426 }
427}