diff --git a/src/config/v2/api.rs b/src/config/v2/api.rs index ebd943ea..551e1b40 100644 --- a/src/config/v2/api.rs +++ b/src/config/v2/api.rs @@ -45,6 +45,6 @@ impl Api { } fn default_max_user_profile_page_size() -> u8 { - 30 + 100 } } diff --git a/src/databases/database.rs b/src/databases/database.rs index 7d41758d..83408db0 100644 --- a/src/databases/database.rs +++ b/src/databases/database.rs @@ -143,8 +143,13 @@ pub trait Database: Sync + Send { /// Get `UserProfile` from `username`. async fn get_user_profile_from_username(&self, username: &str) -> Result; - /// Get all user profiles in a paginated form as `UserProfilesResponse`. - async fn get_user_profiles_paginated(&self, offset: u64, page_size: u8) -> Result; + /// Get all user profiles in a paginated and sorted form as `UserProfilesResponse` from `search`,`offset` and `page_size`. + async fn get_user_profiles_search_paginated( + &self, + search: &Option, + offset: u64, + page_size: u8, + ) -> Result; /// Get `UserCompact` from `user_id`. async fn get_user_compact_from_id(&self, user_id: i64) -> Result; diff --git a/src/databases/mysql.rs b/src/databases/mysql.rs index 99eaacbe..a4b93210 100644 --- a/src/databases/mysql.rs +++ b/src/databases/mysql.rs @@ -155,12 +155,23 @@ impl Database for Mysql { .map_err(|_| database::Error::UserNotFound) } - async fn get_user_profiles_paginated(&self, offset: u64, limit: u8) -> Result { - let mut query_string = "SELECT * FROM torrust_user_profiles".to_string(); + async fn get_user_profiles_search_paginated( + &self, + search: &Option, + offset: u64, + limit: u8, + ) -> Result { + let user_name = match search { + None => "%".to_string(), + Some(v) => format!("%{v}%"), + }; + + let mut query_string = "SELECT * FROM torrust_user_profiles WHERE username LIKE ?".to_string(); let count_query = format!("SELECT COUNT(*) as count FROM ({query_string}) AS count_table"); let count_result: Result = query_as(&count_query) + .bind(user_name.clone()) .fetch_one(&self.pool) .await .map(|(v,)| v) @@ -171,6 +182,7 @@ impl Database for Mysql { query_string = format!("{query_string} LIMIT ?, ?"); let res: Vec = sqlx::query_as::<_, UserProfile>(&query_string) + .bind(user_name.clone()) .bind(i64::saturating_add_unsigned(0, offset)) .bind(limit) .fetch_all(&self.pool) diff --git a/src/databases/sqlite.rs b/src/databases/sqlite.rs index 337a5858..a3e77774 100644 --- a/src/databases/sqlite.rs +++ b/src/databases/sqlite.rs @@ -156,12 +156,23 @@ impl Database for Sqlite { .map_err(|_| database::Error::UserNotFound) } - async fn get_user_profiles_paginated(&self, offset: u64, limit: u8) -> Result { - let mut query_string = "SELECT * FROM torrust_user_profiles".to_string(); + async fn get_user_profiles_search_paginated( + &self, + search: &Option, + offset: u64, + limit: u8, + ) -> Result { + let user_name = match search { + None => "%".to_string(), + Some(v) => format!("%{v}%"), + }; + + let mut query_string = "SELECT * FROM torrust_user_profiles WHERE username LIKE ?".to_string(); let count_query = format!("SELECT COUNT(*) as count FROM ({query_string}) AS count_table"); let count_result: Result = query_as(&count_query) + .bind(user_name.clone()) .fetch_one(&self.pool) .await .map(|(v,)| v) @@ -172,6 +183,7 @@ impl Database for Sqlite { query_string = format!("{query_string} LIMIT ?, ?"); let res: Vec = sqlx::query_as::<_, UserProfile>(&query_string) + .bind(user_name.clone()) .bind(i64::saturating_add_unsigned(0, offset)) .bind(limit) .fetch_all(&self.pool) diff --git a/src/services/user.rs b/src/services/user.rs index 083a0e2c..c55443b1 100644 --- a/src/services/user.rs +++ b/src/services/user.rs @@ -36,6 +36,7 @@ fn no_email() -> String { pub struct ListingRequest { pub page_size: Option, pub page: Option, + pub search: Option, } /// Internal specification for user profiles listings. @@ -43,6 +44,7 @@ pub struct ListingRequest { pub struct ListingSpecification { pub offset: u64, pub page_size: u8, + pub search: Option, } pub struct RegistrationService { @@ -401,7 +403,11 @@ impl ListingService { let offset = u64::from(page * u32::from(page_size)); - ListingSpecification { offset, page_size } + ListingSpecification { + search: request.search.clone(), + offset, + page_size, + } } } @@ -504,7 +510,7 @@ impl DbUserProfileRepository { /// It returns an error if there is a database error. pub async fn generate_listing(&self, specification: &ListingSpecification) -> Result { self.database - .get_user_profiles_paginated(specification.offset, specification.page_size) + .get_user_profiles_search_paginated(&specification.search, specification.offset, specification.page_size) .await } }