diff options
| author | mrw1593 <botahamec@outlook.com> | 2023-05-13 13:49:56 -0400 |
|---|---|---|
| committer | mrw1593 <botahamec@outlook.com> | 2023-05-29 10:45:56 -0400 |
| commit | fdbc7ed756ce455c956dd7a5885db6b6eabfd578 (patch) | |
| tree | 3fc2678ed128f74beeb2127b0e21e298d25a6ef2 /src | |
| parent | dc08e1486c919dc8f168543adeb86cfe1f3b645e (diff) | |
Add the ability to search users
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/users.rs | 36 | ||||
| -rw-r--r-- | src/services/db.rs | 48 |
2 files changed, 84 insertions, 0 deletions
diff --git a/src/api/users.rs b/src/api/users.rs index 6e00336..b2dd1c7 100644 --- a/src/api/users.rs +++ b/src/api/users.rs @@ -23,6 +23,41 @@ impl From<User> for UserResponse { } } +#[get("/")] +async fn search_users( + web::Query(username): web::Query<Option<Box<str>>>, + web::Query(limit): web::Query<Option<u32>>, + web::Query(offset): web::Query<Option<u32>>, + conn: web::Data<MySqlPool>, +) -> HttpResponse { + let conn = conn.get_ref(); + + let username = username.unwrap_or_default(); + let offset = offset.unwrap_or_default(); + + let results: Box<[UserResponse]> = if let Some(limit) = limit { + db::search_users_limit(conn, &username, offset, limit) + .await + .unwrap() + .iter() + .cloned() + .map(|u| u.into()) + .collect() + } else { + db::search_users(conn, &username) + .await + .unwrap() + .into_iter() + .skip(offset as usize) + .cloned() + .map(|u| u.into()) + .collect() + }; + + let response = HttpResponse::Ok().json(results); + response +} + #[derive(Debug, Clone, Error)] #[error("No user with the given ID exists")] struct UserNotFoundError { @@ -224,6 +259,7 @@ async fn update_password( pub fn service() -> Scope { web::scope("/users") + .service(search_users) .service(get_user) .service(get_username) .service(create_user) diff --git a/src/services/db.rs b/src/services/db.rs index b24c640..d717594 100644 --- a/src/services/db.rs +++ b/src/services/db.rs @@ -101,6 +101,54 @@ pub async fn get_user_by_username<'c>( Ok(Some(record.try_into()?)) } +pub async fn search_users<'c>( + conn: impl Executor<'c, Database = MySql>, + username: &str, +) -> Result<Box<[User]>, RawUnexpected> { + let username = format!("%{username}%"); + let records = query_as!( + UserRow, + r"SELECT user_id, username, password_hash, password_salt, password_version + FROM users + WHERE LOCATE(?, username) != 0", + username, + ) + .fetch_all(conn) + .await?; + + Ok(records + .into_iter() + .map(|u| u.try_into()) + .collect::<Result<Box<[User]>, RawUnexpected>>()?) +} + +pub async fn search_users_limit<'c>( + conn: impl Executor<'c, Database = MySql>, + username: &str, + offset: u32, + limit: u32, +) -> Result<Box<[User]>, RawUnexpected> { + let username = format!("%{username}%"); + let records = query_as!( + UserRow, + r"SELECT user_id, username, password_hash, password_salt, password_version + FROM users + WHERE LOCATE(?, username) != 0 + LIMIT ? + OFFSET ?", + username, + offset, + limit + ) + .fetch_all(conn) + .await?; + + Ok(records + .into_iter() + .map(|u| u.try_into()) + .collect::<Result<Box<[User]>, RawUnexpected>>()?) +} + pub async fn get_username<'c>( conn: impl Executor<'c, Database = MySql>, user_id: Uuid, |
