diff --git a/crates/delta/src/routes/servers/member_experimental_query.rs b/crates/delta/src/routes/servers/member_experimental_query.rs new file mode 100644 index 00000000..44040ebe --- /dev/null +++ b/crates/delta/src/routes/servers/member_experimental_query.rs @@ -0,0 +1,82 @@ +use revolt_quark::{ + models::{Member, User}, + perms, Db, Error, Ref, Result, +}; + +use rocket::serde::json::Json; +use serde::{Deserialize, Serialize}; + +/// # Query Parameters +#[derive(Deserialize, JsonSchema, FromForm)] +pub struct OptionsQueryMembers { + /// String to search for + query: String, + + /// Discourage use of this API + experimental_api: bool, +} + +/// # Query members by name +#[derive(Serialize, JsonSchema)] +pub struct MemberQueryResponse { + /// List of members + members: Vec, + /// List of users + users: Vec, +} + +/// # Query members by name +/// +/// Query members by a given name, this API is not stable and will be removed in the future. +#[openapi(tag = "Server Members")] +#[get("//members_experimental_query?")] +pub async fn member_experimental_query( + db: &Db, + user: User, + target: Ref, + options: OptionsQueryMembers, +) -> Result> { + if !options.experimental_api { + return Err(Error::InternalError); + } + + let server = target.as_server(db).await?; + perms(&user).server(&server).calc(db).await?; + + let mut members = db.fetch_all_members(&server.id).await?; + + let mut user_ids = vec![]; + for member in &members { + user_ids.push(member.id.user.clone()); + } + + let mut users = User::fetch_foreign_users(db, &user_ids).await?; + + // Ensure the lists match up exactly + members.sort_by(|a, b| a.id.user.cmp(&b.id.user)); + users.sort_by(|a, b| a.id.cmp(&b.id)); + + // Filter all matches + let mut zipped_vec: Vec<(Member, User)> = members + .into_iter() + .zip(users) + .filter(|(member, user)| { + if let Some(nickname) = &member.nickname { + nickname.contains(&options.query) + } else { + user.username.contains(&options.query) + } + }) + .collect(); + + // Sort remaining matches by length + zipped_vec.sort_by(|(member_a, user_a), (member_b, user_b)| { + let left = member_a.nickname.as_ref().unwrap_or(&user_a.username); + let right = member_b.nickname.as_ref().unwrap_or(&user_b.username); + left.len().cmp(&right.len()) + }); + + // Take the first five and return them + let (members, users) = zipped_vec.into_iter().take(10).unzip(); + Ok(Json(MemberQueryResponse { members, users })) +} diff --git a/crates/delta/src/routes/servers/mod.rs b/crates/delta/src/routes/servers/mod.rs index 15cdd735..a3ebeb75 100644 --- a/crates/delta/src/routes/servers/mod.rs +++ b/crates/delta/src/routes/servers/mod.rs @@ -8,6 +8,7 @@ mod channel_create; mod emoji_list; mod invites_fetch; mod member_edit; +mod member_experimental_query; mod member_fetch; mod member_fetch_all; mod member_remove; @@ -34,6 +35,7 @@ pub fn routes() -> (Vec, OpenApi) { member_remove::req, member_fetch::req, member_edit::req, + member_experimental_query::member_experimental_query, ban_create::req, ban_remove::req, ban_list::req,