summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormrw1593 <botahamec@outlook.com>2023-05-13 13:49:56 -0400
committermrw1593 <botahamec@outlook.com>2023-05-29 10:45:56 -0400
commitfdbc7ed756ce455c956dd7a5885db6b6eabfd578 (patch)
tree3fc2678ed128f74beeb2127b0e21e298d25a6ef2 /src
parentdc08e1486c919dc8f168543adeb86cfe1f3b645e (diff)
Add the ability to search users
Diffstat (limited to 'src')
-rw-r--r--src/api/users.rs36
-rw-r--r--src/services/db.rs48
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,