diff --git a/crates/lib/database_queries/src/queries/vocoder/list_vocoder_models.rs b/crates/lib/database_queries/src/queries/vocoder/list_vocoder_models.rs new file mode 100644 index 0000000000..63bbc00537 --- /dev/null +++ b/crates/lib/database_queries/src/queries/vocoder/list_vocoder_models.rs @@ -0,0 +1,269 @@ +use anyhow::anyhow; +use chrono::{DateTime, Utc}; +use container_common::anyhow_result::AnyhowResult; +use crate::helpers::boolean_converters::i8_to_bool; +use log::{warn, info}; +use sqlx::MySqlPool; + +// FIXME: This is the old style of query scoping and shouldn't be copied. +// But I'm in a hurry... + +// NB: Do not publicly expose this type. +pub struct VocoderModelListItem { + pub vocoder_token: String, + pub vocoder_type: String, + + pub title: String, + pub is_staff_recommended: bool, + + pub creator_user_token: String, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, + + pub created_at: DateTime, + pub updated_at: DateTime, + + // Moderator fields + pub moderator_fields: VocoderModelListItemModFields, +} + +// NB: Do not publicly expose this type. +pub struct VocoderModelListItemModFields { + pub is_mod_disabled_from_public_use: bool, + pub is_mod_disabled_from_author_use: bool, + pub is_mod_author_editing_locked: bool, + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +// FIXME: This is the old style of query scoping and shouldn't be copied. +// But I'm in a hurry... + +pub async fn list_vocoder_models( + mysql_pool: &MySqlPool, + scope_creator_username: Option<&str>, + can_see_deleted_and_hidden: bool, +) -> AnyhowResult> { + + let maybe_models = match scope_creator_username { + Some(username) => { + list_vocoder_models_creator_scoped(mysql_pool, username, can_see_deleted_and_hidden) + .await + }, + None => { + list_vocoder_models_for_all_creators(mysql_pool, can_see_deleted_and_hidden) + .await + }, + }; + + let models : Vec = match maybe_models { + Ok(models) => models, + Err(err) => { + match err { + RowNotFound => { + return Ok(Vec::new()); + }, + _ => { + warn!("vocoder model list query error: {:?}", err); + return Err(anyhow!("vocoder model list query error")); + } + } + } + }; + + Ok(models.into_iter() + .map(|model| { + VocoderModelListItem { + vocoder_token: model.model_token, + vocoder_type: model.vocoder_type, + title: model.title, + is_staff_recommended: i8_to_bool(model.is_staff_recommended), + creator_user_token: model.creator_user_token, + creator_username: model.creator_username, + creator_display_name: model.creator_display_name, + creator_gravatar_hash: model.creator_gravatar_hash, + created_at: model.created_at, + updated_at: model.updated_at, + moderator_fields: VocoderModelListItemModFields { + is_mod_disabled_from_public_use: i8_to_bool(model.is_mod_disabled_from_public_use), + is_mod_disabled_from_author_use: i8_to_bool(model.is_mod_disabled_from_author_use), + is_mod_author_editing_locked: i8_to_bool(model.is_mod_author_editing_locked), + user_deleted_at: model.user_deleted_at, + mod_deleted_at: model.mod_deleted_at, + } + } + }) + .collect::>()) +} + +async fn list_vocoder_models_for_all_creators( + mysql_pool: &MySqlPool, + can_see_deleted_and_hidden: bool +) -> AnyhowResult> { + // NB: Sqlx doesn't like non-string literal queries, so we have to branch. + // Repeating the query is ugly, but that's the best we can do without a + // full-on query builder pattern. + let maybe_models = if !can_see_deleted_and_hidden { + info!("listing vocoder models for everyone; publicly visible only"); + sqlx::query_as!( + InternalVocoderModelListItemRaw, + r#" +SELECT + vocoder.token as vocoder_token, + vocoder.vocoder_type, + vocoder.creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_gravatar_hash, + vocoder.title, + vocoder.is_staff_recommended, + vocoder.is_mod_disabled_from_public_use, + vocoder.is_mod_disabled_from_author_use, + vocoder.is_mod_author_editing_locked, + vocoder.created_at, + vocoder.updated_at, + vocoder.user_deleted_at, + vocoder.mod_deleted_at +FROM vocoder_models as vocoder +JOIN users + ON users.token = vocoder.creator_user_token +WHERE + vocoder.is_mod_disabled_from_public_use IS FALSE + AND vocoder.is_mod_disabled_from_author_use IS FALSE + AND vocoder.user_deleted_at IS NULL + AND vocoder.mod_deleted_at IS NULL + "#) + .fetch_all(mysql_pool) + .await? + } else { + info!("listing tts models for everyone; all visibility states (undeleted only)"); + sqlx::query_as!( + InternalVocoderModelListItemRaw, + r#" +SELECT + vocoder.token as vocoder_token, + vocoder.vocoder_type, + vocoder.creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_gravatar_hash, + vocoder.title, + vocoder.is_staff_recommended, + vocoder.is_mod_disabled_from_public_use, + vocoder.is_mod_disabled_from_author_use, + vocoder.is_mod_author_editing_locked, + vocoder.created_at, + vocoder.updated_at, + vocoder.user_deleted_at, + vocoder.mod_deleted_at +FROM vocoder_models as vocoder +JOIN users + ON users.token = vocoder.creator_user_token + "#) + .fetch_all(mysql_pool) + .await? + }; + + Ok(maybe_models) +} + +async fn list_vocoder_models_creator_scoped( + mysql_pool: &MySqlPool, + scope_creator_username: &str, + can_see_deleted_and_hidden: bool +) -> AnyhowResult> { + // NB: Sqlx doesn't like non-string literal queries, so we have to branch. + // Repeating the query is ugly, but that's the best we can do without a + // full-on query builder pattern. + let maybe_models = if !can_see_deleted_and_hidden { + info!("listing tts models for user; mod-approved only"); + sqlx::query_as!( + InternalVocoderModelListItemRaw, + r#" +SELECT + vocoder.token as vocoder_token, + vocoder.vocoder_type, + vocoder.creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_gravatar_hash, + vocoder.title, + vocoder.is_staff_recommended, + vocoder.is_mod_disabled_from_public_use, + vocoder.is_mod_disabled_from_author_use, + vocoder.is_mod_author_editing_locked, + vocoder.created_at, + vocoder.updated_at, + vocoder.user_deleted_at, + vocoder.mod_deleted_at +FROM vocoder_models as vocoder +JOIN users + ON users.token = vocoder.creator_user_token +WHERE + users.username = ? + AND vocoder.is_mod_disabled_from_public_use IS FALSE + AND vocoder.is_mod_disabled_from_author_use IS FALSE + AND vocoder.user_deleted_at IS NULL + AND vocoder.mod_deleted_at IS NULL + "#, + scope_creator_username) + .fetch_all(mysql_pool) + .await? + } else { + info!("listing tts models for user; all"); + sqlx::query_as!( + InternalVocoderModelListItemRaw, + r#" +SELECT + vocoder.token as vocoder_token, + vocoder.vocoder_type, + vocoder.creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_gravatar_hash, + vocoder.title, + vocoder.is_staff_recommended, + vocoder.is_mod_disabled_from_public_use, + vocoder.is_mod_disabled_from_author_use, + vocoder.is_mod_author_editing_locked, + vocoder.created_at, + vocoder.updated_at, + vocoder.user_deleted_at, + vocoder.mod_deleted_at +FROM vocoder_models as vocoder +JOIN users + ON users.token = vocoder.creator_user_token +WHERE + users.username = ? + "#, + scope_creator_username) + .fetch_all(mysql_pool) + .await? + }; + + Ok(maybe_models) +} + +struct InternalVocoderModelListItemRaw { + pub vocoder_token: String, + pub vocoder_type: String, + + pub title: String, + pub is_staff_recommended: i8, + + pub creator_user_token: String, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, + + pub created_at: DateTime, + pub updated_at: DateTime, + + // Moderator fields + pub is_mod_disabled_from_public_use: i8, + pub is_mod_disabled_from_author_use: i8, + pub is_mod_author_editing_locked: i8, + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} diff --git a/crates/lib/database_queries/src/queries/vocoder/mod.rs b/crates/lib/database_queries/src/queries/vocoder/mod.rs index 8a5ac172c9..476d76040f 100644 --- a/crates/lib/database_queries/src/queries/vocoder/mod.rs +++ b/crates/lib/database_queries/src/queries/vocoder/mod.rs @@ -1 +1,2 @@ -pub mod insert_vocoder_model; \ No newline at end of file +pub mod insert_vocoder_model; +pub mod list_vocoder_models; \ No newline at end of file diff --git a/crates/service/storyteller_web/src/http_server/endpoints/users/list_user_vocoders.rs b/crates/service/storyteller_web/src/http_server/endpoints/users/list_user_vocoders.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/service/storyteller_web/src/http_server/endpoints/users/mod.rs b/crates/service/storyteller_web/src/http_server/endpoints/users/mod.rs index 8d5324ab12..39f8c475ae 100644 --- a/crates/service/storyteller_web/src/http_server/endpoints/users/mod.rs +++ b/crates/service/storyteller_web/src/http_server/endpoints/users/mod.rs @@ -3,6 +3,7 @@ pub mod edit_profile; pub mod get_profile; pub mod list_user_tts_inference_results; pub mod list_user_tts_models; +pub mod list_user_vocoders; pub mod list_user_w2l_inference_results; pub mod list_user_w2l_templates; pub mod login; diff --git a/crates/service/storyteller_web/src/http_server/mod.rs b/crates/service/storyteller_web/src/http_server/mod.rs index 43daf6085b..4cc47aa324 100644 --- a/crates/service/storyteller_web/src/http_server/mod.rs +++ b/crates/service/storyteller_web/src/http_server/mod.rs @@ -1,3 +1,4 @@ pub mod endpoints; pub mod middleware; +pub mod vocoders; pub mod web_utils; diff --git a/crates/service/storyteller_web/src/http_server/vocoders/edit_vocoder.rs b/crates/service/storyteller_web/src/http_server/vocoders/edit_vocoder.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/service/storyteller_web/src/http_server/vocoders/list_vocoders.rs b/crates/service/storyteller_web/src/http_server/vocoders/list_vocoders.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/service/storyteller_web/src/http_server/vocoders/mod.rs b/crates/service/storyteller_web/src/http_server/vocoders/mod.rs new file mode 100644 index 0000000000..873078e098 --- /dev/null +++ b/crates/service/storyteller_web/src/http_server/vocoders/mod.rs @@ -0,0 +1,2 @@ +pub mod edit_vocoder; +pub mod list_vocoders; \ No newline at end of file