From 85814e96e3ffab49a4d30328a0abeabb970b323b Mon Sep 17 00:00:00 2001
From: strawberry <strawberry@puppygock.gay>
Date: Sun, 7 Apr 2024 15:45:48 -0400
Subject: [PATCH] implement unstable MSC2666 support for querying mutual rooms

https://github.com/matrix-org/matrix-spec-proposals/pull/2666

Signed-off-by: strawberry <strawberry@puppygock.gay>
---
 Cargo.toml                           |  5 ++--
 src/api/client_server/mod.rs         |  2 ++
 src/api/client_server/unstable.rs    | 45 ++++++++++++++++++++++++++++
 src/api/client_server/unversioned.rs |  3 +-
 src/routes.rs                        |  1 +
 5 files changed, 53 insertions(+), 3 deletions(-)
 create mode 100644 src/api/client_server/unstable.rs

diff --git a/Cargo.toml b/Cargo.toml
index 29fa46c3..8cadc6ae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -252,15 +252,16 @@ features = [
     "federation-api",
     "push-gateway-api-c",
     "state-res",
-    "unstable-msc2448",
-    "unstable-msc3575",
     "unstable-exhaustive-types",
     "ring-compat",
     "unstable-unspecified",
+    "unstable-msc2448",
+    "unstable-msc2666",
     "unstable-msc2867",
     "unstable-msc2870",
     "unstable-msc3026",
     "unstable-msc3061",
+    "unstable-msc3575",
     "unstable-msc4121",
     "unstable-extensible-events",
 ]
diff --git a/src/api/client_server/mod.rs b/src/api/client_server/mod.rs
index 84eb641c..1aac4aaa 100644
--- a/src/api/client_server/mod.rs
+++ b/src/api/client_server/mod.rs
@@ -29,6 +29,7 @@ mod thirdparty;
 mod threads;
 mod to_device;
 mod typing;
+mod unstable;
 mod unversioned;
 mod user_directory;
 mod voip;
@@ -64,6 +65,7 @@ pub use thirdparty::*;
 pub use threads::*;
 pub use to_device::*;
 pub use typing::*;
+pub use unstable::*;
 pub use unversioned::*;
 pub use user_directory::*;
 pub use voip::*;
diff --git a/src/api/client_server/unstable.rs b/src/api/client_server/unstable.rs
new file mode 100644
index 00000000..eb9fa0af
--- /dev/null
+++ b/src/api/client_server/unstable.rs
@@ -0,0 +1,45 @@
+use ruma::{
+	api::client::{error::ErrorKind, membership::mutual_rooms},
+	OwnedRoomId,
+};
+
+use crate::{services, Error, Result, Ruma};
+
+/// # `GET /_matrix/client/unstable/uk.half-shot.msc2666/user/mutual_rooms`
+///
+/// Gets all the rooms the sender shares with the specified user.
+///
+/// TODO: Implement pagination, currently this just returns everything
+///
+/// An implementation of [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666)
+pub async fn get_mutual_rooms_route(
+	body: Ruma<mutual_rooms::unstable::Request>,
+) -> Result<mutual_rooms::unstable::Response> {
+	let sender_user = body.sender_user.as_ref().expect("user is authenticated");
+
+	if sender_user == &body.user_id {
+		return Err(Error::BadRequest(
+			ErrorKind::Unknown,
+			"You cannot request rooms in common with yourself.",
+		));
+	}
+
+	if !services().users.exists(&body.user_id)? {
+		return Ok(mutual_rooms::unstable::Response {
+			joined: vec![],
+			next_batch_token: None,
+		});
+	}
+
+	let mutual_rooms: Vec<OwnedRoomId> = services()
+		.rooms
+		.user
+		.get_shared_rooms(vec![sender_user.clone(), body.user_id.clone()])?
+		.filter_map(Result::ok)
+		.collect();
+
+	Ok(mutual_rooms::unstable::Response {
+		joined: mutual_rooms,
+		next_batch_token: None,
+	})
+}
diff --git a/src/api/client_server/unversioned.rs b/src/api/client_server/unversioned.rs
index be2bd75c..a4a978ec 100644
--- a/src/api/client_server/unversioned.rs
+++ b/src/api/client_server/unversioned.rs
@@ -45,10 +45,11 @@ pub async fn get_supported_versions_route(
 		unstable_features: BTreeMap::from_iter([
 			("org.matrix.e2e_cross_signing".to_owned(), true),
 			("org.matrix.msc2285.stable".to_owned(), true),
+			("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true),
 			("org.matrix.msc2836".to_owned(), true),
 			("org.matrix.msc2946".to_owned(), true),
-			("org.matrix.msc3827".to_owned(), true),
 			("org.matrix.msc3026.busy_presence".to_owned(), true),
+			("org.matrix.msc3827".to_owned(), true),
 		]),
 	};
 
diff --git a/src/routes.rs b/src/routes.rs
index 2ae1072f..caeeba69 100644
--- a/src/routes.rs
+++ b/src/routes.rs
@@ -206,6 +206,7 @@ pub fn routes() -> Router {
 		.ruma_route(server_server::get_keys_route)
 		.ruma_route(server_server::claim_keys_route)
         .ruma_route(server_server::get_hierarchy_route)
+        .ruma_route(client_server::get_mutual_rooms_route)
         .ruma_route(client_server::well_known_support)
         .route("/_conduwuit/server_version", get(client_server::conduwuit_server_version))
 		.route("/_matrix/client/r0/rooms/:room_id/initialSync", get(initial_sync))