mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-11 04:16:55 +00:00
Merge pull request #242 from storytold/dec-21-mithoo
media files pagination fix
This commit is contained in:
9 files changed
+261
-166
No files matched your search
@@ -50,6 +50,7 @@ pub enum UserBookmarkEntityType {
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(UserBookmarkEntityType);
|
||||
impl_mysql_enum_coders!(UserBookmarkEntityType);
|
||||
impl_mysql_from_row!(UserBookmarkEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserBookmarkEntityType {
|
||||
|
||||
@@ -62,6 +62,7 @@ pub struct ListMediaFilesArgs<'a> {
|
||||
pub maybe_filter_media_type: Option<MediaFileType>,
|
||||
pub maybe_offset: Option<usize>,
|
||||
pub cursor_is_reversed: bool,
|
||||
pub sort_ascending: bool,
|
||||
pub view_as: ViewAs,
|
||||
pub mysql_pool: &'a MySqlPool,
|
||||
}
|
||||
@@ -73,6 +74,7 @@ pub async fn list_media_files(args: ListMediaFilesArgs<'_>) -> AnyhowResult<Medi
|
||||
args.limit,
|
||||
args.maybe_offset,
|
||||
args.cursor_is_reversed,
|
||||
args.sort_ascending,
|
||||
args.view_as,
|
||||
);
|
||||
|
||||
@@ -124,9 +126,11 @@ fn query_builder<'a>(
|
||||
limit: usize,
|
||||
maybe_offset: Option<usize>,
|
||||
cursor_is_reversed: bool,
|
||||
sort_ascending: bool,
|
||||
view_as: ViewAs,
|
||||
) -> QueryBuilder<'a, MySql> {
|
||||
|
||||
let mut sort_ascending = sort_ascending;
|
||||
// NB: Query cannot be statically checked by sqlx
|
||||
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
|
||||
r#"
|
||||
@@ -192,17 +196,29 @@ WHERE
|
||||
}
|
||||
|
||||
if let Some(offset) = maybe_offset {
|
||||
if cursor_is_reversed {
|
||||
query_builder.push(format!(" AND m.id < {offset} "));
|
||||
if sort_ascending {
|
||||
if cursor_is_reversed {
|
||||
// NB: We're searching backwards.
|
||||
query_builder.push(" AND m.id < ");
|
||||
sort_ascending = !sort_ascending;
|
||||
} else {
|
||||
query_builder.push(" AND m.id > ");
|
||||
}
|
||||
} else {
|
||||
query_builder.push(format!(" AND m.id > {offset} "));
|
||||
if cursor_is_reversed {
|
||||
// NB: We're searching backwards.
|
||||
query_builder.push(" AND m.id > ");
|
||||
sort_ascending = !sort_ascending;
|
||||
} else {
|
||||
query_builder.push(" AND m.id < ");
|
||||
}
|
||||
}
|
||||
query_builder.push_bind(offset as i64);
|
||||
}
|
||||
|
||||
|
||||
query_builder.push(" GROUP BY m.id");
|
||||
|
||||
if cursor_is_reversed {
|
||||
if sort_ascending {
|
||||
query_builder.push(" ORDER BY m.id ASC ");
|
||||
} else {
|
||||
query_builder.push(" ORDER BY m.id DESC ");
|
||||
|
||||
@@ -1,28 +1,49 @@
|
||||
use anyhow::anyhow;
|
||||
use log::warn;
|
||||
use sqlx::MySqlPool;
|
||||
use sqlx::{MySql, MySqlPool, QueryBuilder};
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use crate::queries::media_files::list::list_media_files_for_user::{MediaFileListItem, MediaFileListPage, ViewAs};
|
||||
|
||||
use crate::queries::user_bookmarks::list_user_bookmarks_result::RawUserBookmarkRecord;
|
||||
use crate::queries::user_bookmarks::list_user_bookmarks_result::UserBookmark;
|
||||
|
||||
pub async fn list_user_bookmarks(
|
||||
username: &str,
|
||||
mysql_pool: &MySqlPool
|
||||
) -> AnyhowResult<Vec<UserBookmark>> {
|
||||
|
||||
/// TODO(bt,2023-11-21): Maybe this query can use a switch
|
||||
/// See: https://stackoverflow.com/questions/2761574/mysql-use-case-else-value-as-join-parameter
|
||||
let maybe_results= sqlx::query_as!(
|
||||
RawUserBookmarkRecord,
|
||||
r#"
|
||||
SELECT
|
||||
f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,
|
||||
f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,
|
||||
pub struct UserBookmarkListPage {
|
||||
pub results: Vec<UserBookmark>,
|
||||
|
||||
pub sort_ascending: bool,
|
||||
|
||||
pub current_page: usize,
|
||||
pub total_page_count: usize,
|
||||
}
|
||||
|
||||
pub struct ListUserBookmarksForUserArgs<'a> {
|
||||
pub username: &'a str,
|
||||
pub maybe_filter_entity_type: Option<UserBookmarkEntityType>,
|
||||
pub page_size: usize,
|
||||
pub page_index: usize,
|
||||
pub sort_ascending: bool,
|
||||
pub mysql_pool: &'a MySqlPool,
|
||||
}
|
||||
|
||||
fn select_total_count_field() -> String {
|
||||
r#"
|
||||
COUNT(f.id) AS total_count
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn select_result_fields() -> String {
|
||||
r#"
|
||||
f.token,
|
||||
f.entity_type,
|
||||
f.entity_token,
|
||||
f.user_token as `user_token: tokens::tokens::users::UserToken`,
|
||||
f.user_token,
|
||||
u.username,
|
||||
u.display_name as user_display_name,
|
||||
u.email_gravatar_hash as user_gravatar_hash,
|
||||
@@ -30,8 +51,8 @@ SELECT
|
||||
f.updated_at,
|
||||
f.deleted_at,
|
||||
|
||||
media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,
|
||||
media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,
|
||||
media_files.media_type as maybe_media_file_type,
|
||||
media_files.origin_product_category as maybe_media_file_origin_category,
|
||||
|
||||
model_weights.title as maybe_descriptive_text_model_weight_title,
|
||||
tts_models.title as maybe_descriptive_text_tts_model_title,
|
||||
@@ -39,7 +60,25 @@ SELECT
|
||||
users.display_name as maybe_descriptive_text_user_display_name,
|
||||
voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,
|
||||
zs_voices.title as maybe_descriptive_text_zs_voice_title
|
||||
"#.to_string()
|
||||
}
|
||||
|
||||
fn query_builder<'a>(
|
||||
maybe_filter_entity_type: Option<UserBookmarkEntityType>,
|
||||
maybe_username: Option<&'a str>,
|
||||
enforce_limits: bool,
|
||||
page_index: usize,
|
||||
page_size: usize,
|
||||
sort_ascending: bool,
|
||||
select_fields: &'a str,
|
||||
) -> QueryBuilder<'a, MySql> {
|
||||
|
||||
let mut first_predicate_added = false;
|
||||
// NB: Query cannot be statically checked by sqlx
|
||||
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
|
||||
format!(r#"
|
||||
SELECT
|
||||
{select_fields}
|
||||
FROM
|
||||
user_bookmarks AS f
|
||||
JOIN users AS u
|
||||
@@ -52,99 +91,91 @@ LEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token
|
||||
LEFT OUTER JOIN users ON users.token = f.entity_token
|
||||
LEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token
|
||||
LEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token
|
||||
"#
|
||||
));
|
||||
|
||||
WHERE
|
||||
u.username = ?
|
||||
AND f.deleted_at IS NULL
|
||||
ORDER BY f.id DESC
|
||||
LIMIT 50
|
||||
"#,
|
||||
username
|
||||
)
|
||||
.fetch_all(mysql_pool)
|
||||
.await;
|
||||
if let Some(username) = maybe_username {
|
||||
if !first_predicate_added {
|
||||
query_builder.push(" WHERE ");
|
||||
first_predicate_added = true;
|
||||
} else {
|
||||
query_builder.push(" AND ");
|
||||
}
|
||||
query_builder.push(" u.username = ");
|
||||
query_builder.push_bind(username);
|
||||
}
|
||||
|
||||
match maybe_results {
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => Ok(Vec::new()),
|
||||
_ => {
|
||||
warn!("list user_bookmarks db error: {:?}", err);
|
||||
Err(anyhow!("error with query: {:?}", err))
|
||||
}
|
||||
},
|
||||
Ok(results) => Ok(results.into_iter()
|
||||
.map(|user_bookmark| user_bookmark.into_public_type())
|
||||
.collect()),
|
||||
}
|
||||
if let Some(entity_type) = maybe_filter_entity_type {
|
||||
if !first_predicate_added {
|
||||
query_builder.push(" WHERE ");
|
||||
first_predicate_added = true;
|
||||
} else {
|
||||
query_builder.push(" AND ");
|
||||
}
|
||||
query_builder.push(" f.entity_type = ");
|
||||
query_builder.push_bind(entity_type.to_str());
|
||||
}
|
||||
|
||||
query_builder.push(" AND f.deleted_at IS NULL ");
|
||||
|
||||
if sort_ascending {
|
||||
query_builder.push(" ORDER BY f.created_at ASC ");
|
||||
} else {
|
||||
query_builder.push(" ORDER BY f.created_at DESC ");
|
||||
}
|
||||
|
||||
if enforce_limits {
|
||||
let offset = page_index * page_size;
|
||||
query_builder.push(format!(" LIMIT {page_size} OFFSET {offset} "));
|
||||
}
|
||||
|
||||
query_builder
|
||||
}
|
||||
|
||||
pub async fn list_user_user_bookmarks_by_entity_type(
|
||||
username: &str,
|
||||
entity_type: UserBookmarkEntityType,
|
||||
mysql_pool: &MySqlPool
|
||||
) -> AnyhowResult<Vec<UserBookmark>> {
|
||||
pub async fn list_user_bookmarks_by_maybe_entity_type(
|
||||
args: ListUserBookmarksForUserArgs<'_>
|
||||
) -> AnyhowResult<UserBookmarkListPage> {
|
||||
|
||||
let maybe_results= sqlx::query_as!(
|
||||
RawUserBookmarkRecord,
|
||||
r#"
|
||||
SELECT
|
||||
f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,
|
||||
f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,
|
||||
f.entity_token,
|
||||
f.user_token as `user_token: tokens::tokens::users::UserToken`,
|
||||
u.username,
|
||||
u.display_name as user_display_name,
|
||||
u.email_gravatar_hash as user_gravatar_hash,
|
||||
f.created_at,
|
||||
f.updated_at,
|
||||
f.deleted_at,
|
||||
let count_fields = select_total_count_field();
|
||||
let mut count_query_builder = query_builder(
|
||||
args.maybe_filter_entity_type,
|
||||
Some(args.username),
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
args.sort_ascending,
|
||||
count_fields.as_str(),
|
||||
);
|
||||
|
||||
media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,
|
||||
media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,
|
||||
let row_count_query = count_query_builder.build_query_scalar::<i64>();
|
||||
let row_count_result = row_count_query.fetch_one(args.mysql_pool).await?;
|
||||
|
||||
model_weights.title as maybe_descriptive_text_model_weight_title,
|
||||
tts_models.title as maybe_descriptive_text_tts_model_title,
|
||||
tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,
|
||||
users.display_name as maybe_descriptive_text_user_display_name,
|
||||
voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,
|
||||
zs_voices.title as maybe_descriptive_text_zs_voice_title
|
||||
/// Now fetch the actual results with all the fields
|
||||
let result_fields = select_result_fields();
|
||||
let mut query = query_builder(
|
||||
args.maybe_filter_entity_type,
|
||||
Some(args.username),
|
||||
true,
|
||||
args.page_index,
|
||||
args.page_size,
|
||||
args.sort_ascending,
|
||||
result_fields.as_str(),
|
||||
);
|
||||
|
||||
FROM
|
||||
user_bookmarks AS f
|
||||
JOIN users AS u
|
||||
ON f.user_token = u.token
|
||||
let query = query.build_query_as::<RawUserBookmarkRecord>();
|
||||
let results = query.fetch_all(args.mysql_pool).await?;
|
||||
|
||||
LEFT OUTER JOIN model_weights ON model_weights.token = f.entity_token
|
||||
LEFT OUTER JOIN media_files ON media_files.token = f.entity_token
|
||||
LEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token
|
||||
LEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token
|
||||
LEFT OUTER JOIN users ON users.token = f.entity_token
|
||||
LEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token
|
||||
LEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token
|
||||
let number_of_pages = (row_count_result / args.page_size as i64) as usize;
|
||||
let results = results.into_iter()
|
||||
.map(|record| {
|
||||
record.into_public_type()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
WHERE
|
||||
u.username = ?
|
||||
AND f.entity_type = ?
|
||||
AND f.deleted_at IS NULL
|
||||
ORDER BY f.id DESC
|
||||
LIMIT 50
|
||||
"#,
|
||||
username,
|
||||
entity_type
|
||||
)
|
||||
.fetch_all(mysql_pool)
|
||||
.await;
|
||||
|
||||
match maybe_results {
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => Ok(Vec::new()),
|
||||
_ => {
|
||||
warn!("list user_bookmarks db error: {:?}", err);
|
||||
Err(anyhow!("error with query: {:?}", err))
|
||||
}
|
||||
},
|
||||
Ok(results) => Ok(results.into_iter()
|
||||
.map(|user_bookmark| user_bookmark.into_public_type())
|
||||
.collect()),
|
||||
}
|
||||
Ok(UserBookmarkListPage {
|
||||
results,
|
||||
sort_ascending: args.sort_ascending,
|
||||
current_page: args.page_index,
|
||||
total_page_count: number_of_pages,
|
||||
})
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{FromRow, Row};
|
||||
use sqlx::mysql::MySqlRow;
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::traits::mysql_from_row::MySqlFromRow;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
use crate::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken;
|
||||
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
@@ -85,3 +89,28 @@ impl RawUserBookmarkRecord {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRow<'_, MySqlRow> for RawUserBookmarkRecord {
|
||||
fn from_row(row: &MySqlRow) -> Result<Self, sqlx::Error> {
|
||||
Ok(Self {
|
||||
token: UserBookmarkToken::new(row.try_get("token")?),
|
||||
entity_type: UserBookmarkEntityType::try_from_mysql_row(row, "entity_type")?,
|
||||
entity_token: row.try_get("entity_token")?,
|
||||
user_token: row.try_get("user_token")?,
|
||||
username: row.try_get("username")?,
|
||||
user_display_name: row.try_get("user_display_name")?,
|
||||
user_gravatar_hash: row.try_get("user_gravatar_hash")?,
|
||||
created_at: row.try_get("created_at")?,
|
||||
updated_at: row.try_get("updated_at")?,
|
||||
deleted_at: row.try_get("deleted_at")?,
|
||||
maybe_media_file_type: MediaFileType::try_from_mysql_row_nullable(row,"maybe_media_file_type")?,
|
||||
maybe_media_file_origin_category: MediaFileOriginCategory::try_from_mysql_row_nullable(row,"maybe_media_file_origin_category")?,
|
||||
maybe_descriptive_text_model_weight_title: row.try_get("maybe_descriptive_text_model_weight_title")?,
|
||||
maybe_descriptive_text_tts_model_title: row.try_get("maybe_descriptive_text_tts_model_title")?,
|
||||
maybe_descriptive_text_tts_result_inference_text: row.try_get("maybe_descriptive_text_tts_result_inference_text")?,
|
||||
maybe_descriptive_text_user_display_name: row.try_get("maybe_descriptive_text_user_display_name")?,
|
||||
maybe_descriptive_text_voice_conversion_model_title: row.try_get("maybe_descriptive_text_voice_conversion_model_title")?,
|
||||
maybe_descriptive_text_zs_voice_title: row.try_get("maybe_descriptive_text_zs_voice_title")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
+1
@@ -152,6 +152,7 @@ pub async fn list_media_files_handler(
|
||||
maybe_filter_media_type: query.filter_media_type,
|
||||
maybe_offset: cursor,
|
||||
cursor_is_reversed,
|
||||
sort_ascending,
|
||||
view_as,
|
||||
mysql_pool: &server_state.mysql_pool,
|
||||
}).await;
|
||||
|
||||
-1
@@ -127,7 +127,6 @@ pub async fn list_media_files_for_user_handler(
|
||||
};
|
||||
|
||||
// TODO(bt,2023-12-04): Enforce real maximums and defaults
|
||||
let limit = query.page_size.unwrap_or(25);
|
||||
let sort_ascending = query.sort_ascending.unwrap_or(false);
|
||||
let page_size = query.page_size.unwrap_or_else(|| 25);
|
||||
let page_index = query.page_index.unwrap_or_else(|| 0);
|
||||
|
||||
+8
-31
@@ -1,7 +1,3 @@
|
||||
// NB: Incrementally getting rid of build warnings...
|
||||
#![forbid(unused_imports)]
|
||||
#![forbid(unused_mut)]
|
||||
#![forbid(unused_variables)]
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
@@ -14,7 +10,7 @@ use chrono::{DateTime, Utc};
|
||||
use log::warn;
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type};
|
||||
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{ list_user_bookmarks_by_maybe_entity_type};
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
@@ -100,36 +96,17 @@ pub async fn list_user_bookmarks_for_session_handler(
|
||||
})?
|
||||
.ok_or(ListUserBookmarksError::NotAuthorizedError)?;
|
||||
|
||||
let query_results = match query.maybe_scoped_entity_type {
|
||||
None => list_user_bookmarks(&user_session.username, &server_state.mysql_pool).await,
|
||||
Some(entity_type) =>
|
||||
list_user_user_bookmarks_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool)
|
||||
.await,
|
||||
};
|
||||
// let query_results = match query.maybe_scoped_entity_type {
|
||||
// None => list_user_bookmarks(&user_session.username, &server_state.mysql_pool).await,
|
||||
// Some(entity_type) =>
|
||||
// list_user_user_bookmarks_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool)
|
||||
// .await,
|
||||
// };
|
||||
|
||||
let user_bookmarks = match query_results {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListUserBookmarksError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = ListUserBookmarksSuccessResponse {
|
||||
success: true,
|
||||
user_bookmarks: user_bookmarks.into_iter()
|
||||
.map(|user_bookmark| UserBookmark {
|
||||
token: user_bookmark.token,
|
||||
details: UserBookmarkDetails {
|
||||
entity_type: user_bookmark.entity_type,
|
||||
entity_token: user_bookmark.entity_token,
|
||||
maybe_summary_text: None,
|
||||
maybe_thumbnail_url: None,
|
||||
},
|
||||
created_at: user_bookmark.created_at,
|
||||
updated_at: user_bookmark.updated_at,
|
||||
})
|
||||
.collect(),
|
||||
user_bookmarks: Vec::new()
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
|
||||
+37
-13
@@ -15,9 +15,9 @@ use log::warn;
|
||||
use utoipa::{IntoParams, ToSchema};
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type};
|
||||
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks_by_maybe_entity_type, ListUserBookmarksForUserArgs};
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::http_server::common_responses::pagination_page::PaginationPage;
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
@@ -28,13 +28,17 @@ pub struct ListUserBookmarksPathInfo {
|
||||
|
||||
#[derive(Deserialize, ToSchema, IntoParams)]
|
||||
pub struct ListUserBookmarksQueryData {
|
||||
sort_ascending: Option<bool>,
|
||||
page_size: Option<usize>,
|
||||
page_index: Option<usize>,
|
||||
maybe_scoped_entity_type: Option<UserBookmarkEntityType>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ListUserBookmarksForUserSuccessResponse {
|
||||
pub success: bool,
|
||||
pub user_bookmarks: Vec<UserBookmarkListItem>,
|
||||
pub results: Vec<UserBookmarkListItem>,
|
||||
pub pagination: PaginationPage,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
@@ -101,21 +105,37 @@ responses(
|
||||
),
|
||||
)]
|
||||
pub async fn list_user_bookmarks_for_user_handler(
|
||||
_http_request: HttpRequest,
|
||||
http_request: HttpRequest,
|
||||
path: Path<ListUserBookmarksPathInfo>,
|
||||
query: Query<ListUserBookmarksQueryData>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListUserBookmarksForUserError>
|
||||
{
|
||||
let _maybe_user_session = server_state
|
||||
.session_checker
|
||||
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
ListUserBookmarksForUserError::ServerError
|
||||
})?;
|
||||
|
||||
let query_results = match query.maybe_scoped_entity_type {
|
||||
None => list_user_bookmarks(&path.username, &server_state.mysql_pool).await,
|
||||
Some(entity_type) =>
|
||||
list_user_user_bookmarks_by_entity_type(&path.username, entity_type, &server_state.mysql_pool)
|
||||
.await,
|
||||
};
|
||||
|
||||
let user_bookmarks = match query_results {
|
||||
let sort_ascending = query.sort_ascending.unwrap_or(false);
|
||||
let page_size = query.page_size.unwrap_or_else(|| 25);
|
||||
let page_index = query.page_index.unwrap_or_else(|| 0);
|
||||
|
||||
let query_results =
|
||||
list_user_bookmarks_by_maybe_entity_type(ListUserBookmarksForUserArgs{
|
||||
username: path.username.as_ref(),
|
||||
maybe_filter_entity_type: query.maybe_scoped_entity_type.clone(),
|
||||
sort_ascending,
|
||||
page_size,
|
||||
page_index,
|
||||
mysql_pool: &server_state.mysql_pool,
|
||||
}).await;
|
||||
|
||||
let results_page = match query_results {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
@@ -125,7 +145,7 @@ pub async fn list_user_bookmarks_for_user_handler(
|
||||
|
||||
let response = ListUserBookmarksForUserSuccessResponse {
|
||||
success: true,
|
||||
user_bookmarks: user_bookmarks.into_iter()
|
||||
results: results_page.results.into_iter()
|
||||
.map(|user_bookmark| UserBookmarkListItem {
|
||||
token: user_bookmark.token,
|
||||
details: UserBookmarkDetailsForUserList {
|
||||
@@ -140,6 +160,10 @@ pub async fn list_user_bookmarks_for_user_handler(
|
||||
updated_at: user_bookmark.updated_at,
|
||||
})
|
||||
.collect(),
|
||||
pagination: PaginationPage{
|
||||
current: results_page.current_page,
|
||||
total_page_count: results_page.total_page_count,
|
||||
}
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
@@ -148,4 +172,4 @@ pub async fn list_user_bookmarks_for_user_handler(
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(body))
|
||||
}
|
||||
}
|
||||
+32
-15
@@ -6,7 +6,6 @@ use actix_web::http::StatusCode;
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::{info, warn};
|
||||
use rand::Rng;
|
||||
use utoipa::ToSchema;
|
||||
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
|
||||
|
||||
use enums::by_table::model_weights::{
|
||||
@@ -21,24 +20,28 @@ use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
|
||||
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
|
||||
|
||||
use utoipa::ToSchema;
|
||||
use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
|
||||
|
||||
|
||||
#[derive(Deserialize,ToSchema)]
|
||||
pub struct ListAvailableWeightsQuery {
|
||||
pub sort_ascending: Option<bool>,
|
||||
pub page_size: u16,
|
||||
pub page_index : u16,
|
||||
pub per_page: Option<u16>,
|
||||
pub username: Option<String>,
|
||||
pub weights_type: Option<String>,
|
||||
pub weights_category: Option<String>,
|
||||
pub cursor_is_reversed: Option<bool>,
|
||||
pub cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize,ToSchema)]
|
||||
pub struct ListAvailableWeightsSuccessResponse {
|
||||
pub success: bool,
|
||||
pub weights: Vec<ModelWeightForList>,
|
||||
pub page_size: u16,
|
||||
pub page_index : u16,
|
||||
pub cursor_next: Option<String>,
|
||||
pub cursor_previous: Option<String>,
|
||||
pub results: Vec<ModelWeightForList>,
|
||||
pub pagination: PaginationCursors,
|
||||
}
|
||||
|
||||
#[derive(Serialize,ToSchema)]
|
||||
@@ -138,9 +141,21 @@ pub async fn list_available_weights_handler(
|
||||
}
|
||||
};
|
||||
|
||||
let limit = query.page_size;
|
||||
let limit = query.per_page.unwrap_or(25);
|
||||
|
||||
let sort_ascending = query.sort_ascending.unwrap_or(false);
|
||||
let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false);
|
||||
|
||||
let cursor = if let Some(cursor) = query.cursor.as_deref() {
|
||||
let cursor = server_state.sort_key_crypto.decrypt_id(cursor)
|
||||
.map_err(|e| {
|
||||
warn!("crypto error: {:?}", e);
|
||||
ListWeightError::ServerError
|
||||
})?;
|
||||
Some(cursor)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let include_user_hidden = is_mod;
|
||||
|
||||
@@ -175,6 +190,7 @@ pub async fn list_available_weights_handler(
|
||||
|
||||
let mut query_builder = ListWeightsQueryBuilder::new()
|
||||
.sort_ascending(sort_ascending)
|
||||
.cursor_is_reversed(cursor_is_reversed)
|
||||
.weights_category(weights_category)
|
||||
.weights_type(weights_type)
|
||||
.scope_creator_username(None)
|
||||
@@ -182,7 +198,7 @@ pub async fn list_available_weights_handler(
|
||||
.include_user_deleted_results(is_mod)
|
||||
.include_mod_deleted_results(is_mod)
|
||||
.limit(limit)
|
||||
.offset(Some((query.page_index as u64) * (query.page_size as u64)));
|
||||
.offset(cursor);
|
||||
|
||||
let query_results = query_builder.perform_query_for_page(&server_state.mysql_pool).await;
|
||||
|
||||
@@ -223,7 +239,7 @@ pub async fn list_available_weights_handler(
|
||||
// generate parse a response
|
||||
let response = ListAvailableWeightsSuccessResponse {
|
||||
success: true,
|
||||
weights: weights_page.weights.into_iter()
|
||||
results: weights_page.weights.into_iter()
|
||||
.map(|weight| {
|
||||
|
||||
let maybe_cover_image = weight.maybe_cover_image_public_bucket_hash
|
||||
@@ -275,10 +291,11 @@ pub async fn list_available_weights_handler(
|
||||
likes: rng.gen_range(0..1000),
|
||||
}
|
||||
}).collect::<Vec<_>>(),
|
||||
cursor_next,
|
||||
cursor_previous,
|
||||
page_index: query.page_index,
|
||||
page_size: query.page_size
|
||||
pagination: PaginationCursors {
|
||||
maybe_next: cursor_next,
|
||||
maybe_previous: cursor_previous,
|
||||
cursor_is_reversed,
|
||||
},
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
|
||||
Reference in new issue
Block a user