matrix_sdk/room/
privacy_settings.rs1use matrix_sdk_base::Room as BaseRoom;
2use ruma::{
3 api::client::{
4 directory::{get_room_visibility, set_room_visibility},
5 room::Visibility,
6 state::send_state_event,
7 },
8 assign,
9 events::{
10 room::{
11 canonical_alias::RoomCanonicalAliasEventContent,
12 history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
13 join_rules::{JoinRule, RoomJoinRulesEventContent},
14 },
15 EmptyStateKey,
16 },
17 OwnedRoomAliasId, RoomAliasId,
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_arch = "wasm32")))]
165mod tests {
166 use std::ops::Not;
167
168 use matrix_sdk_test::{async_test, JoinedRoomBuilder, StateTestEvent};
169 use ruma::{
170 api::client::room::Visibility,
171 event_id,
172 events::{
173 room::{history_visibility::HistoryVisibility, join_rules::JoinRule},
174 StateEventType,
175 },
176 owned_room_alias_id, room_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 joined_room_builder =
248 JoinedRoomBuilder::new(room_id).add_state_event(StateTestEvent::Alias);
249 let room = server.sync_room(&client, joined_room_builder).await;
250
251 let room_alias = owned_room_alias_id!("#a:b.c");
252
253 server
255 .mock_room_directory_resolve_alias()
256 .for_alias(room_alias.to_string())
257 .ok(room_id.as_ref(), Vec::new())
258 .mock_once()
259 .mount()
260 .await;
261
262 server.mock_room_directory_remove_room_alias().ok().mock_once().mount().await;
264
265 let removed = room
266 .privacy_settings()
267 .remove_room_alias_from_room_directory(&room_alias)
268 .await
269 .expect("we should get a result value, not an error");
270 assert!(removed);
271 }
272
273 #[async_test]
274 async fn test_remove_room_alias_if_it_does_not_exist() {
275 let server = MatrixMockServer::new().await;
276 let client = server.client_builder().build().await;
277
278 let room_id = room_id!("!a:b.c");
279 let joined_room_builder =
280 JoinedRoomBuilder::new(room_id).add_state_event(StateTestEvent::Alias);
281 let room = server.sync_room(&client, joined_room_builder).await;
282
283 let room_alias = owned_room_alias_id!("#a:b.c");
284
285 server
287 .mock_room_directory_resolve_alias()
288 .for_alias(room_alias.to_string())
289 .not_found()
290 .mock_once()
291 .mount()
292 .await;
293
294 server.mock_room_directory_remove_room_alias().ok().never().mount().await;
296
297 let removed = room
298 .privacy_settings()
299 .remove_room_alias_from_room_directory(&room_alias)
300 .await
301 .expect("we should get a result value, not an error");
302 assert!(removed.not());
303 }
304
305 #[async_test]
306 async fn test_update_canonical_alias_with_some_value() {
307 let server = MatrixMockServer::new().await;
308 let client = server.client_builder().build().await;
309
310 let room_id = room_id!("!a:b.c");
311 let room = server.sync_joined_room(&client, room_id).await;
312
313 server
314 .mock_room_send_state()
315 .for_type(StateEventType::RoomCanonicalAlias)
316 .ok(event_id!("$a:b.c"))
317 .mock_once()
318 .mount()
319 .await;
320
321 let room_alias = owned_room_alias_id!("#a:b.c");
322 let ret = room
323 .privacy_settings()
324 .update_canonical_alias(Some(room_alias.clone()), Vec::new())
325 .await;
326 assert!(ret.is_ok());
327 }
328
329 #[async_test]
330 async fn test_update_canonical_alias_with_no_value() {
331 let server = MatrixMockServer::new().await;
332 let client = server.client_builder().build().await;
333
334 let room_id = room_id!("!a:b.c");
335 let room = server.sync_joined_room(&client, room_id).await;
336
337 server
338 .mock_room_send_state()
339 .for_type(StateEventType::RoomCanonicalAlias)
340 .ok(event_id!("$a:b.c"))
341 .mock_once()
342 .mount()
343 .await;
344
345 let ret = room.privacy_settings().update_canonical_alias(None, Vec::new()).await;
346 assert!(ret.is_ok());
347 }
348
349 #[async_test]
350 async fn test_update_room_history_visibility() {
351 let server = MatrixMockServer::new().await;
352 let client = server.client_builder().build().await;
353
354 let room_id = room_id!("!a:b.c");
355 let room = server.sync_joined_room(&client, room_id).await;
356
357 server
358 .mock_room_send_state()
359 .for_type(StateEventType::RoomHistoryVisibility)
360 .ok(event_id!("$a:b.c"))
361 .mock_once()
362 .mount()
363 .await;
364
365 let ret =
366 room.privacy_settings().update_room_history_visibility(HistoryVisibility::Joined).await;
367 assert!(ret.is_ok());
368 }
369
370 #[async_test]
371 async fn test_update_join_rule() {
372 let server = MatrixMockServer::new().await;
373 let client = server.client_builder().build().await;
374
375 let room_id = room_id!("!a:b.c");
376 let room = server.sync_joined_room(&client, room_id).await;
377
378 server
379 .mock_room_send_state()
380 .for_type(StateEventType::RoomJoinRules)
381 .ok(event_id!("$a:b.c"))
382 .mock_once()
383 .mount()
384 .await;
385
386 let ret = room.privacy_settings().update_join_rule(JoinRule::Public).await;
387 assert!(ret.is_ok());
388 }
389
390 #[async_test]
391 async fn test_get_room_visibility() {
392 let server = MatrixMockServer::new().await;
393 let client = server.client_builder().build().await;
394
395 let room_id = room_id!("!a:b.c");
396 let room = server.sync_joined_room(&client, room_id).await;
397
398 server
399 .mock_room_send_state()
400 .for_type(StateEventType::RoomJoinRules)
401 .ok(event_id!("$a:b.c"))
402 .mock_once()
403 .mount()
404 .await;
405
406 let ret = room.privacy_settings().update_join_rule(JoinRule::Public).await;
407 assert!(ret.is_ok());
408 }
409
410 #[async_test]
411 async fn test_update_room_visibility() {
412 let server = MatrixMockServer::new().await;
413 let client = server.client_builder().build().await;
414
415 let room_id = room_id!("!a:b.c");
416 let room = server.sync_joined_room(&client, room_id).await;
417
418 server.mock_room_directory_set_room_visibility().ok().mock_once().mount().await;
419
420 let ret = room.privacy_settings().update_room_visibility(Visibility::Private).await;
421 assert!(ret.is_ok());
422 }
423}