mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-10 20:11:49 +00:00
Merge pull request #198 from storytold/dec-07-mithoo-bookmarks
Rename favorites -> user_bookmarks, add new table
This commit is contained in:
39 files changed
+661
-608
No files matched your search
+4
-4
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n\n f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,\n f.entity_token,\n\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.token = ?\n ",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::favorites::FavoriteToken",
|
||||
"name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType",
|
||||
"name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -120,5 +120,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "f1ef63978793e7da5bd5e1a486254dd436db8021c8f049efa41f43cf7ce75f1d"
|
||||
"hash": "02136088e16742de2154cd9e84eeebbdb76045ad26aeb1c517a54c296bf31087"
|
||||
}
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.entity_type = ?\n AND f.entity_token = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.entity_type = ?\n AND f.entity_token = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::favorites::FavoriteToken",
|
||||
"name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -98,5 +98,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "99cff649bf75f5b05330e7db8536ecc832affbae7c9710e158099079609e5e16"
|
||||
"hash": "1c1ef2195e81362d0eb023ede236c6fa65ede80d9efcaa4996694ce32c12cc0c"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE user_bookmarks\nSET\ndeleted_at = CURRENT_TIMESTAMP,\nversion = version + 1\nWHERE\ntoken = ?\nAND user_token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "576e5a72e385d44a1e53dc473dd0b5a04e33d7c6b9c38bef96f275b064a12386"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE favorites\nSET\ndeleted_at = CURRENT_TIMESTAMP,\nversion = version + 1\nWHERE\ntoken = ?\nAND user_token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "6a9fc0a3d983eb1d2bdf7d4c80904d73b9f4a649098fc0ba78cbc20cfde12437"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO favorites\nSET\n token = ?,\n user_token = ?,\n entity_type = ?,\n entity_token = ?\n\nON DUPLICATE KEY UPDATE\n deleted_at = NULL,\n version = version + 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "72eaa9124662acf0ed354b868fcdfe33c94b61046c30940f55cdc73789f94041"
|
||||
}
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::favorites::FavoriteToken",
|
||||
"name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType",
|
||||
"name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -197,5 +197,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "4214d8e86b81eb0138a34702ce12960ee007ca602a7bd64b68924515f8fbb038"
|
||||
"hash": "d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO user_bookmarks\nSET\n token = ?,\n user_token = ?,\n entity_type = ?,\n entity_token = ?\n\nON DUPLICATE KEY UPDATE\n deleted_at = NULL,\n version = version + 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e8f3bb68896d316498b52fdaaf4c352624b79bd4e097f57db5ad59f53fd66995"
|
||||
}
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ",
|
||||
"query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::favorites::FavoriteToken",
|
||||
"name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType",
|
||||
"name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
@@ -197,5 +197,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c33f8df5a9ed1991366d6078460d9e936a5470d1794ea319d6cf19b0f5338fd4"
|
||||
"hash": "eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
DROP TABLE user_bookmarks;
|
||||
@@ -0,0 +1,46 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- Favorites that can be attached to just about anything.
|
||||
-- This is a polymorphic table and can apply to a wide variety of entities.
|
||||
CREATE TABLE user_bookmarks
|
||||
(
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- User making the favorite
|
||||
user_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The type of entity the favorite applies to
|
||||
entity_type VARCHAR(32) NOT NULL,
|
||||
|
||||
-- The token of the entity the favorite applies to
|
||||
entity_token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- Incremented with every update.
|
||||
version INT NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== TIMESTAMPS ==========
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP NULL,
|
||||
|
||||
-- INDICES --
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
KEY index_entity_type_entity_token (entity_type, entity_token),
|
||||
KEY index_user_token_entity_token (user_token, entity_type),
|
||||
KEY index_user_token (user_token),
|
||||
KEY index_created_at (created_at),
|
||||
KEY index_user_deleted_at (deleted_at)
|
||||
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_bin;
|
||||
@@ -1,128 +0,0 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `favorites` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum FavoriteEntityType {
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
|
||||
/// TTS model (architecture does not matter)
|
||||
#[serde(rename = "tts_model")]
|
||||
TtsModel,
|
||||
|
||||
/// TTS result (architecture does not matter)
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// W2L template
|
||||
#[serde(rename = "w2l_template")]
|
||||
W2lTemplate,
|
||||
|
||||
/// W2L result
|
||||
#[serde(rename = "w2l_result")]
|
||||
W2lResult,
|
||||
|
||||
/// MediaFile
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// VoiceConversionModel
|
||||
#[serde(rename = "voice_conversion_model")]
|
||||
VoiceConversionModel,
|
||||
|
||||
/// ZsVoice
|
||||
#[serde(rename = "zs_voice")]
|
||||
ZsVoice,
|
||||
}
|
||||
|
||||
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(FavoriteEntityType);
|
||||
impl_mysql_enum_coders!(FavoriteEntityType);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl FavoriteEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::User => "user",
|
||||
Self::TtsModel => "tts_model",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::W2lTemplate => "w2l_template",
|
||||
Self::W2lResult => "w2l_result",
|
||||
Self::MediaFile => "media_file",
|
||||
Self::VoiceConversionModel => "voice_conversion_model",
|
||||
Self::ZsVoice => "zs_voice",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"user" => Ok(Self::User),
|
||||
"tts_model" => Ok(Self::TtsModel),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"w2l_template" => Ok(Self::W2lTemplate),
|
||||
"w2l_result" => Ok(Self::W2lResult),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"voice_conversion_model" => Ok(Self::VoiceConversionModel),
|
||||
"zs_voice" => Ok(Self::ZsVoice),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(FavoriteEntityType::User, "user");
|
||||
assert_serialization(FavoriteEntityType::TtsModel, "tts_model");
|
||||
assert_serialization(FavoriteEntityType::TtsResult, "tts_result");
|
||||
assert_serialization(FavoriteEntityType::W2lTemplate, "w2l_template");
|
||||
assert_serialization(FavoriteEntityType::W2lResult, "w2l_result");
|
||||
assert_serialization(FavoriteEntityType::MediaFile, "media_file");
|
||||
assert_serialization(FavoriteEntityType::VoiceConversionModel, "voice_conversion_model");
|
||||
assert_serialization(FavoriteEntityType::ZsVoice, "zs_voice");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(FavoriteEntityType::User.to_str(), "user");
|
||||
assert_eq!(FavoriteEntityType::TtsModel.to_str(), "tts_model");
|
||||
assert_eq!(FavoriteEntityType::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(FavoriteEntityType::W2lTemplate.to_str(), "w2l_template");
|
||||
assert_eq!(FavoriteEntityType::W2lResult.to_str(), "w2l_result");
|
||||
assert_eq!(FavoriteEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(FavoriteEntityType::VoiceConversionModel.to_str(), "voice_conversion_model");
|
||||
assert_eq!(FavoriteEntityType::ZsVoice.to_str(), "zs_voice");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(FavoriteEntityType::from_str("user").unwrap(), FavoriteEntityType::User);
|
||||
assert_eq!(FavoriteEntityType::from_str("tts_model").unwrap(), FavoriteEntityType::TtsModel);
|
||||
assert_eq!(FavoriteEntityType::from_str("tts_result").unwrap(), FavoriteEntityType::TtsResult);
|
||||
assert_eq!(FavoriteEntityType::from_str("w2l_template").unwrap(), FavoriteEntityType::W2lTemplate);
|
||||
assert_eq!(FavoriteEntityType::from_str("w2l_result").unwrap(), FavoriteEntityType::W2lResult);
|
||||
assert_eq!(FavoriteEntityType::from_str("media_file").unwrap(), FavoriteEntityType::MediaFile);
|
||||
assert_eq!(FavoriteEntityType::from_str("voice_conversion_model").unwrap(), FavoriteEntityType::VoiceConversionModel);
|
||||
assert_eq!(FavoriteEntityType::from_str("zs_voice").unwrap(), FavoriteEntityType::ZsVoice);
|
||||
assert!(FavoriteEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod favorite_entity_type;
|
||||
@@ -10,6 +10,7 @@ pub mod media_uploads;
|
||||
pub mod model_categories;
|
||||
pub mod trending_model_analytics;
|
||||
pub mod tts_models;
|
||||
pub mod user_bookmarks;
|
||||
pub mod user_ratings;
|
||||
pub mod voice_conversion_models;
|
||||
pub mod voice_conversion_results;
|
||||
@@ -19,4 +20,3 @@ pub mod model_weights;
|
||||
pub mod tts_render_tasks;
|
||||
pub mod web_rendition_targets;
|
||||
pub mod web_scraping_targets;
|
||||
pub mod favorites;
|
||||
@@ -0,0 +1 @@
|
||||
pub mod user_bookmark_entity_type;
|
||||
@@ -0,0 +1,128 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
|
||||
/// Used in the `user_bookmarks` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
pub enum UserBookmarkEntityType {
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
User,
|
||||
|
||||
/// TTS model (architecture does not matter)
|
||||
#[serde(rename = "tts_model")]
|
||||
TtsModel,
|
||||
|
||||
/// TTS result (architecture does not matter)
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// W2L template
|
||||
#[serde(rename = "w2l_template")]
|
||||
W2lTemplate,
|
||||
|
||||
/// W2L result
|
||||
#[serde(rename = "w2l_result")]
|
||||
W2lResult,
|
||||
|
||||
/// MediaFile
|
||||
#[serde(rename = "media_file")]
|
||||
MediaFile,
|
||||
|
||||
/// VoiceConversionModel
|
||||
#[serde(rename = "voice_conversion_model")]
|
||||
VoiceConversionModel,
|
||||
|
||||
/// ZsVoice
|
||||
#[serde(rename = "zs_voice")]
|
||||
ZsVoice,
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl UserBookmarkEntityType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::User => "user",
|
||||
Self::TtsModel => "tts_model",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::W2lTemplate => "w2l_template",
|
||||
Self::W2lResult => "w2l_result",
|
||||
Self::MediaFile => "media_file",
|
||||
Self::VoiceConversionModel => "voice_conversion_model",
|
||||
Self::ZsVoice => "zs_voice",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"user" => Ok(Self::User),
|
||||
"tts_model" => Ok(Self::TtsModel),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"w2l_template" => Ok(Self::W2lTemplate),
|
||||
"w2l_result" => Ok(Self::W2lResult),
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"voice_conversion_model" => Ok(Self::VoiceConversionModel),
|
||||
"zs_voice" => Ok(Self::ZsVoice),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(UserBookmarkEntityType::User, "user");
|
||||
assert_serialization(UserBookmarkEntityType::TtsModel, "tts_model");
|
||||
assert_serialization(UserBookmarkEntityType::TtsResult, "tts_result");
|
||||
assert_serialization(UserBookmarkEntityType::W2lTemplate, "w2l_template");
|
||||
assert_serialization(UserBookmarkEntityType::W2lResult, "w2l_result");
|
||||
assert_serialization(UserBookmarkEntityType::MediaFile, "media_file");
|
||||
assert_serialization(UserBookmarkEntityType::VoiceConversionModel, "voice_conversion_model");
|
||||
assert_serialization(UserBookmarkEntityType::ZsVoice, "zs_voice");
|
||||
}
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(UserBookmarkEntityType::User.to_str(), "user");
|
||||
assert_eq!(UserBookmarkEntityType::TtsModel.to_str(), "tts_model");
|
||||
assert_eq!(UserBookmarkEntityType::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(UserBookmarkEntityType::W2lTemplate.to_str(), "w2l_template");
|
||||
assert_eq!(UserBookmarkEntityType::W2lResult.to_str(), "w2l_result");
|
||||
assert_eq!(UserBookmarkEntityType::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(UserBookmarkEntityType::VoiceConversionModel.to_str(), "voice_conversion_model");
|
||||
assert_eq!(UserBookmarkEntityType::ZsVoice.to_str(), "zs_voice");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(UserBookmarkEntityType::from_str("user").unwrap(), UserBookmarkEntityType::User);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("tts_model").unwrap(), UserBookmarkEntityType::TtsModel);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("tts_result").unwrap(), UserBookmarkEntityType::TtsResult);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("w2l_template").unwrap(), UserBookmarkEntityType::W2lTemplate);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("w2l_result").unwrap(), UserBookmarkEntityType::W2lResult);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("media_file").unwrap(), UserBookmarkEntityType::MediaFile);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("voice_conversion_model").unwrap(), UserBookmarkEntityType::VoiceConversionModel);
|
||||
assert_eq!(UserBookmarkEntityType::from_str("zs_voice").unwrap(), UserBookmarkEntityType::ZsVoice);
|
||||
assert!(UserBookmarkEntityType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ pub(crate) enum TokenPrefix {
|
||||
Comment,
|
||||
DownloadJob,
|
||||
EmailSenderJob,
|
||||
Favorite,
|
||||
InferenceJob,
|
||||
MediaFile,
|
||||
MediaUpload,
|
||||
@@ -36,6 +35,7 @@ pub(crate) enum TokenPrefix {
|
||||
PasswordReset,
|
||||
TtsRenderTask, // NB: aichatbot / sqlite
|
||||
User,
|
||||
UserBookmark,
|
||||
UserSession,
|
||||
VoiceConversionModel,
|
||||
VoiceConversionResult,
|
||||
@@ -94,7 +94,6 @@ impl PrefixGenerator for TokenPrefix {
|
||||
Self::DownloadJob => "jdown_", // NB: Previously "JGUP:"
|
||||
Self::EmailSenderJob => "email_job_",
|
||||
Self::InferenceJob => "jinf_",
|
||||
Self::Favorite => "fav_",
|
||||
Self::MediaFile => "m_",
|
||||
Self::MediaUpload => "mu_",
|
||||
Self::ModelWeight => "weight_",
|
||||
@@ -102,6 +101,7 @@ impl PrefixGenerator for TokenPrefix {
|
||||
Self::PasswordReset => "pw_reset_",
|
||||
Self::TtsRenderTask => "tts_task_",
|
||||
Self::User => "user_", // NB: Previously "U:"
|
||||
Self::UserBookmark => "ub_",
|
||||
Self::UserSession => "session_",
|
||||
Self::VoiceConversionModel => "vcm_",
|
||||
Self::VoiceConversionResult => "vcr_",
|
||||
|
||||
@@ -34,4 +34,4 @@ pub mod w2l_templates;
|
||||
pub mod zs_voice_dataset_samples;
|
||||
pub mod zs_voice_datasets;
|
||||
pub mod zs_voices;
|
||||
pub mod favorites;
|
||||
pub mod user_bookmarks;
|
||||
+3
-3
@@ -8,7 +8,7 @@ use crate::prefixes::TokenPrefix;
|
||||
/// The primary key for Audit Logs.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct FavoriteToken(pub String);
|
||||
pub struct UserBookmarkToken(pub String);
|
||||
|
||||
impl_string_token!(FavoriteToken);
|
||||
impl_crockford_generator!(FavoriteToken, 32usize, TokenPrefix::Favorite, CrockfordLower);
|
||||
impl_string_token!(UserBookmarkToken);
|
||||
impl_crockford_generator!(UserBookmarkToken, 32usize, TokenPrefix::UserBookmark, CrockfordLower);
|
||||
@@ -1,48 +0,0 @@
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::tts_models::TtsModelToken;
|
||||
use tokens::tokens::tts_results::TtsResultToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
use tokens::tokens::voice_conversion_models::VoiceConversionModelToken;
|
||||
use tokens::tokens::w2l_results::W2lResultToken;
|
||||
use tokens::tokens::w2l_templates::W2lTemplateToken;
|
||||
use tokens::tokens::zs_voices::ZsVoiceToken;
|
||||
|
||||
pub enum FavoriteEntityToken {
|
||||
User(UserToken),
|
||||
TtsModel(TtsModelToken),
|
||||
TtsResult(TtsResultToken),
|
||||
W2lTemplate(W2lTemplateToken),
|
||||
W2lResult(W2lResultToken),
|
||||
MediaFile(MediaFileToken),
|
||||
VoiceConversionModel(VoiceConversionModelToken),
|
||||
ZsVoice(ZsVoiceToken),
|
||||
}
|
||||
|
||||
impl FavoriteEntityToken {
|
||||
pub fn from_entity_type_and_token(entity_type: FavoriteEntityType, token: &str) -> Self {
|
||||
match entity_type {
|
||||
FavoriteEntityType::User => Self::User(UserToken::new_from_str(token)),
|
||||
FavoriteEntityType::TtsModel => Self::TtsModel(TtsModelToken::new_from_str(token)),
|
||||
FavoriteEntityType::TtsResult => Self::TtsResult(TtsResultToken::new_from_str(token)),
|
||||
FavoriteEntityType::W2lTemplate => Self::W2lTemplate(W2lTemplateToken::new_from_str(token)),
|
||||
FavoriteEntityType::W2lResult => Self::W2lResult(W2lResultToken::new_from_str(token)),
|
||||
FavoriteEntityType::MediaFile => Self::MediaFile(MediaFileToken::new_from_str(token)),
|
||||
FavoriteEntityType::VoiceConversionModel => Self::VoiceConversionModel(VoiceConversionModelToken::new_from_str(token)),
|
||||
FavoriteEntityType::ZsVoice => Self::ZsVoice(ZsVoiceToken::new_from_str(token)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_composite_keys(&self) -> (FavoriteEntityType, &str) {
|
||||
match self {
|
||||
FavoriteEntityToken::User(user_token) => (FavoriteEntityType::User, user_token.as_str()),
|
||||
FavoriteEntityToken::TtsModel(tts_model_token) => (FavoriteEntityType::TtsModel, tts_model_token.as_str()),
|
||||
FavoriteEntityToken::TtsResult(tts_result_token) => (FavoriteEntityType::TtsResult, tts_result_token.as_str()),
|
||||
FavoriteEntityToken::W2lTemplate(w2l_template_token) => (FavoriteEntityType::W2lTemplate, w2l_template_token.as_str()),
|
||||
FavoriteEntityToken::W2lResult(w2l_result_token) => (FavoriteEntityType::W2lResult, w2l_result_token.as_str()),
|
||||
FavoriteEntityToken::MediaFile(media_file_token) => (FavoriteEntityType::MediaFile, media_file_token.as_str()),
|
||||
FavoriteEntityToken::VoiceConversionModel(voice_conversion_model_token) => (FavoriteEntityType::VoiceConversionModel, voice_conversion_model_token.as_str()),
|
||||
FavoriteEntityToken::ZsVoice(zs_voice_token) => (FavoriteEntityType::ZsVoice, zs_voice_token.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
pub mod create_favorite;
|
||||
pub mod delete_favorite;
|
||||
pub mod favorite_entity_token;
|
||||
pub mod get_favorite;
|
||||
pub mod list_favorites_for_entity;
|
||||
pub mod list_user_favorites;
|
||||
pub mod list_user_favorites_result;
|
||||
@@ -3,7 +3,6 @@ pub mod audit_logs;
|
||||
pub mod billing;
|
||||
pub mod comments;
|
||||
pub mod email_sender_jobs;
|
||||
pub mod favorites;
|
||||
pub mod generic_download;
|
||||
pub mod generic_inference;
|
||||
pub mod generic_synthetic_ids;
|
||||
@@ -18,6 +17,7 @@ pub mod trending_model_analytics;
|
||||
pub mod tts;
|
||||
pub mod twitch;
|
||||
pub mod users;
|
||||
pub mod user_bookmarks;
|
||||
pub mod vocoder;
|
||||
pub mod voice_clone_requests;
|
||||
pub mod voice_conversion;
|
||||
|
||||
+11
-11
@@ -4,15 +4,15 @@ use anyhow::anyhow;
|
||||
use sqlx::{Executor, MySql};
|
||||
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::queries::favorites::favorite_entity_token::FavoriteEntityToken;
|
||||
use crate::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken;
|
||||
|
||||
pub struct CreateFavoriteArgs<'e, 'c, E>
|
||||
pub struct CreateUserBookmarkArgs<'e, 'c, E>
|
||||
where E: 'e + Executor<'c, Database = MySql>
|
||||
{
|
||||
pub entity_token: &'e FavoriteEntityToken,
|
||||
pub entity_token: &'e UserBookmarkEntityToken,
|
||||
|
||||
pub user_token: &'e UserToken,
|
||||
|
||||
@@ -23,19 +23,19 @@ pub struct CreateFavoriteArgs<'e, 'c, E>
|
||||
pub phantom: PhantomData<&'c E>,
|
||||
}
|
||||
|
||||
pub async fn create_favorite<'e, 'c : 'e, E>(
|
||||
args: CreateFavoriteArgs<'e, 'c, E>,
|
||||
pub async fn create_user_bookmark<'e, 'c : 'e, E>(
|
||||
args: CreateUserBookmarkArgs<'e, 'c, E>,
|
||||
)
|
||||
-> AnyhowResult<FavoriteToken>
|
||||
-> AnyhowResult<UserBookmarkToken>
|
||||
where E: 'e + Executor<'c, Database = MySql>
|
||||
{
|
||||
|
||||
let favorite_token = FavoriteToken::generate();
|
||||
let user_bookmark_token = UserBookmarkToken::generate();
|
||||
let (entity_type, entity_token) = args.entity_token.get_composite_keys();
|
||||
|
||||
let query_result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO favorites
|
||||
INSERT INTO user_bookmarks
|
||||
SET
|
||||
token = ?,
|
||||
user_token = ?,
|
||||
@@ -46,7 +46,7 @@ ON DUPLICATE KEY UPDATE
|
||||
deleted_at = NULL,
|
||||
version = version + 1
|
||||
"#,
|
||||
&favorite_token,
|
||||
&user_bookmark_token,
|
||||
args.user_token,
|
||||
entity_type,
|
||||
entity_token,
|
||||
@@ -59,5 +59,5 @@ ON DUPLICATE KEY UPDATE
|
||||
Err(err) => return Err(anyhow!("Mysql error: {:?}", err)),
|
||||
};
|
||||
|
||||
Ok(favorite_token)
|
||||
Ok(user_bookmark_token)
|
||||
}
|
||||
+8
-8
@@ -1,22 +1,22 @@
|
||||
use sqlx::{Executor, MySql};
|
||||
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
// NB: UserToken is only supplied as an optimistic form of validation
|
||||
pub async fn delete_favorite<'e, 'c, E>(
|
||||
favorite_token: &'e FavoriteToken,
|
||||
user_token: &'e UserToken,
|
||||
mysql_executor: E
|
||||
pub async fn delete_user_bookmark<'e, 'c, E>(
|
||||
user_bookmark_token: &'e UserBookmarkToken,
|
||||
user_token: &'e UserToken,
|
||||
mysql_executor: E
|
||||
)
|
||||
-> AnyhowResult<()>
|
||||
-> AnyhowResult<()>
|
||||
where E: 'e + Executor<'c, Database = MySql>
|
||||
{
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE favorites
|
||||
UPDATE user_bookmarks
|
||||
SET
|
||||
deleted_at = CURRENT_TIMESTAMP,
|
||||
version = version + 1
|
||||
@@ -25,7 +25,7 @@ token = ?
|
||||
AND user_token = ?
|
||||
LIMIT 1
|
||||
"#,
|
||||
favorite_token,
|
||||
user_bookmark_token,
|
||||
user_token
|
||||
)
|
||||
.execute(mysql_executor)
|
||||
+28
-28
@@ -2,15 +2,15 @@ use anyhow::anyhow;
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{Executor, MySql};
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
pub struct Favorite {
|
||||
pub token: FavoriteToken,
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub entity_type: FavoriteEntityType,
|
||||
pub entity_type: UserBookmarkEntityType,
|
||||
pub entity_token: String,
|
||||
|
||||
pub user_token: UserToken,
|
||||
@@ -23,21 +23,21 @@ pub struct Favorite {
|
||||
pub maybe_deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
pub async fn get_favorite<'e, 'c, E>(
|
||||
favorite_token: &'e FavoriteToken,
|
||||
mysql_executor: E
|
||||
pub async fn get_user_bookmark<'e, 'c, E>(
|
||||
user_bookmark_token: &'e UserBookmarkToken,
|
||||
mysql_executor: E
|
||||
)
|
||||
-> AnyhowResult<Option<Favorite>>
|
||||
-> AnyhowResult<Option<UserBookmark>>
|
||||
where E: 'e + Executor<'c, Database = MySql>
|
||||
{
|
||||
|
||||
let maybe_results = sqlx::query_as!(
|
||||
RawFavorite,
|
||||
RawUserBookmark,
|
||||
r#"
|
||||
SELECT
|
||||
f.token as `token: tokens::tokens::favorites::FavoriteToken`,
|
||||
f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,
|
||||
|
||||
f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,
|
||||
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`,
|
||||
@@ -50,29 +50,29 @@ SELECT
|
||||
f.deleted_at
|
||||
|
||||
FROM
|
||||
favorites AS f
|
||||
user_bookmarks AS f
|
||||
JOIN users AS u
|
||||
ON f.user_token = u.token
|
||||
WHERE
|
||||
f.token = ?
|
||||
"#,
|
||||
favorite_token
|
||||
user_bookmark_token
|
||||
)
|
||||
.fetch_one(mysql_executor)
|
||||
.await;
|
||||
|
||||
match maybe_results {
|
||||
Ok(favorite) => Ok(Some(Favorite {
|
||||
token: favorite.token,
|
||||
entity_type: favorite.entity_type,
|
||||
entity_token: favorite.entity_token,
|
||||
user_token: favorite.user_token,
|
||||
username: favorite.username,
|
||||
user_display_name: favorite.user_display_name,
|
||||
user_gravatar_hash: favorite.user_gravatar_hash,
|
||||
created_at: favorite.created_at,
|
||||
updated_at: favorite.updated_at,
|
||||
maybe_deleted_at: favorite.deleted_at,
|
||||
Ok(user_bookmark) => Ok(Some(UserBookmark {
|
||||
token: user_bookmark.token,
|
||||
entity_type: user_bookmark.entity_type,
|
||||
entity_token: user_bookmark.entity_token,
|
||||
user_token: user_bookmark.user_token,
|
||||
username: user_bookmark.username,
|
||||
user_display_name: user_bookmark.user_display_name,
|
||||
user_gravatar_hash: user_bookmark.user_gravatar_hash,
|
||||
created_at: user_bookmark.created_at,
|
||||
updated_at: user_bookmark.updated_at,
|
||||
maybe_deleted_at: user_bookmark.deleted_at,
|
||||
})),
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => Ok(None),
|
||||
@@ -81,10 +81,10 @@ WHERE
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawFavorite {
|
||||
pub token: FavoriteToken,
|
||||
pub struct RawUserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub entity_type: FavoriteEntityType,
|
||||
pub entity_type: UserBookmarkEntityType,
|
||||
pub entity_token: String,
|
||||
|
||||
pub user_token: UserToken,
|
||||
+23
-21
@@ -2,24 +2,26 @@ use anyhow::anyhow;
|
||||
use log::warn;
|
||||
use sqlx::MySqlPool;
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use errors::AnyhowResult;
|
||||
use crate::queries::user_bookmarks::list_user_bookmarks_result::UserBookmark;
|
||||
use crate::queries::user_bookmarks::list_user_bookmarks_result::RawUserBookmarkRecord;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::queries::favorites::list_user_favorites_result::{RawUserFavoriteRecord, UserFavorite};
|
||||
|
||||
pub async fn list_user_favorites(
|
||||
pub async fn list_user_bookmarks(
|
||||
username: &str,
|
||||
mysql_pool: &MySqlPool
|
||||
) -> AnyhowResult<Vec<UserFavorite>> {
|
||||
) -> 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!(
|
||||
RawUserFavoriteRecord,
|
||||
RawUserBookmarkRecord,
|
||||
r#"
|
||||
SELECT
|
||||
f.token as `token: tokens::tokens::favorites::FavoriteToken`,
|
||||
f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,
|
||||
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,
|
||||
@@ -39,7 +41,7 @@ SELECT
|
||||
zs_voices.title as maybe_descriptive_text_zs_voice_title
|
||||
|
||||
FROM
|
||||
favorites AS f
|
||||
user_bookmarks AS f
|
||||
JOIN users AS u
|
||||
ON f.user_token = u.token
|
||||
|
||||
@@ -65,28 +67,28 @@ LIMIT 50
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => Ok(Vec::new()),
|
||||
_ => {
|
||||
warn!("list favorites db error: {:?}", err);
|
||||
warn!("list user_bookmarks db error: {:?}", err);
|
||||
Err(anyhow!("error with query: {:?}", err))
|
||||
}
|
||||
},
|
||||
Ok(results) => Ok(results.into_iter()
|
||||
.map(|favorite| favorite.into_public_type())
|
||||
.map(|user_bookmark| user_bookmark.into_public_type())
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_user_favorites_by_entity_type(
|
||||
username: &str,
|
||||
entity_type: FavoriteEntityType,
|
||||
mysql_pool: &MySqlPool
|
||||
) -> AnyhowResult<Vec<UserFavorite>> {
|
||||
pub async fn list_user_user_bookmarks_by_entity_type(
|
||||
username: &str,
|
||||
entity_type: UserBookmarkEntityType,
|
||||
mysql_pool: &MySqlPool
|
||||
) -> AnyhowResult<Vec<UserBookmark>> {
|
||||
|
||||
let maybe_results= sqlx::query_as!(
|
||||
RawUserFavoriteRecord,
|
||||
RawUserBookmarkRecord,
|
||||
r#"
|
||||
SELECT
|
||||
f.token as `token: tokens::tokens::favorites::FavoriteToken`,
|
||||
f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,
|
||||
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,
|
||||
@@ -106,7 +108,7 @@ SELECT
|
||||
zs_voices.title as maybe_descriptive_text_zs_voice_title
|
||||
|
||||
FROM
|
||||
favorites AS f
|
||||
user_bookmarks AS f
|
||||
JOIN users AS u
|
||||
ON f.user_token = u.token
|
||||
|
||||
@@ -134,12 +136,12 @@ LIMIT 50
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => Ok(Vec::new()),
|
||||
_ => {
|
||||
warn!("list favorites db error: {:?}", err);
|
||||
warn!("list user_bookmarks db error: {:?}", err);
|
||||
Err(anyhow!("error with query: {:?}", err))
|
||||
}
|
||||
},
|
||||
Ok(results) => Ok(results.into_iter()
|
||||
.map(|favorite| favorite.into_public_type())
|
||||
.map(|user_bookmark| user_bookmark.into_public_type())
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
+18
-18
@@ -4,13 +4,13 @@ use log::warn;
|
||||
use sqlx::MySqlPool;
|
||||
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::queries::favorites::favorite_entity_token::FavoriteEntityToken;
|
||||
use crate::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken;
|
||||
|
||||
pub struct Favorite {
|
||||
pub token: FavoriteToken,
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub user_token: UserToken,
|
||||
pub username: String,
|
||||
@@ -22,18 +22,18 @@ pub struct Favorite {
|
||||
pub maybe_deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
pub async fn list_favorites_for_entity(
|
||||
favorite_entity_token: FavoriteEntityToken,
|
||||
pub async fn list_user_bookmarks_for_entity(
|
||||
user_bookmark_entity_token: UserBookmarkEntityToken,
|
||||
mysql_pool: &MySqlPool
|
||||
) -> AnyhowResult<Vec<Favorite>> {
|
||||
) -> AnyhowResult<Vec<UserBookmark>> {
|
||||
|
||||
let (entity_type, entity_token) = favorite_entity_token.get_composite_keys();
|
||||
let (entity_type, entity_token) = user_bookmark_entity_token.get_composite_keys();
|
||||
|
||||
let maybe_results= sqlx::query_as!(
|
||||
RawFavoriteRecord,
|
||||
RawUserBookmarkRecord,
|
||||
r#"
|
||||
SELECT
|
||||
f.token as `token: tokens::tokens::favorites::FavoriteToken`,
|
||||
f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,
|
||||
f.user_token as `user_token: tokens::tokens::users::UserToken`,
|
||||
u.username,
|
||||
u.display_name as user_display_name,
|
||||
@@ -44,7 +44,7 @@ SELECT
|
||||
f.deleted_at
|
||||
|
||||
FROM
|
||||
favorites AS f
|
||||
user_bookmarks AS f
|
||||
JOIN users AS u
|
||||
ON f.user_token = u.token
|
||||
WHERE
|
||||
@@ -64,18 +64,18 @@ LIMIT 50
|
||||
Err(err) => match err {
|
||||
sqlx::Error::RowNotFound => Ok(Vec::new()),
|
||||
_ => {
|
||||
warn!("list favorites db error: {:?}", err);
|
||||
warn!("list user_bookmarks db error: {:?}", err);
|
||||
Err(anyhow!("error with query: {:?}", err))
|
||||
}
|
||||
},
|
||||
Ok(results) => Ok(results.into_iter()
|
||||
.map(|favorite| favorite.into_public_type())
|
||||
.map(|user_bookmark| user_bookmark.into_public_type())
|
||||
.collect()),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawFavoriteRecord {
|
||||
token: FavoriteToken,
|
||||
pub struct RawUserBookmarkRecord {
|
||||
token: UserBookmarkToken,
|
||||
|
||||
user_token: UserToken,
|
||||
username: String,
|
||||
@@ -87,9 +87,9 @@ pub struct RawFavoriteRecord {
|
||||
deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl RawFavoriteRecord {
|
||||
pub fn into_public_type(self) -> Favorite {
|
||||
Favorite {
|
||||
impl RawUserBookmarkRecord {
|
||||
pub fn into_public_type(self) -> UserBookmark {
|
||||
UserBookmark {
|
||||
token: self.token,
|
||||
user_token: self.user_token,
|
||||
username: self.username,
|
||||
+20
-20
@@ -1,18 +1,18 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
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 tokens::tokens::favorites::FavoriteToken;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
pub struct UserFavorite {
|
||||
pub token: FavoriteToken,
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub entity_type: FavoriteEntityType,
|
||||
pub entity_type: UserBookmarkEntityType,
|
||||
pub entity_token: String,
|
||||
|
||||
/// Something descriptive about the favorited entity.
|
||||
/// Something descriptive about the bookmarked entity.
|
||||
/// This might be TTS text, a username, etc. It depends on the entity type.
|
||||
pub maybe_entity_descriptive_text: Option<String>,
|
||||
|
||||
@@ -26,10 +26,10 @@ pub struct UserFavorite {
|
||||
pub maybe_deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
pub struct RawUserFavoriteRecord {
|
||||
pub (crate) token: FavoriteToken,
|
||||
pub struct RawUserBookmarkRecord {
|
||||
pub (crate) token: UserBookmarkToken,
|
||||
|
||||
pub (crate) entity_type: FavoriteEntityType,
|
||||
pub (crate) entity_type: UserBookmarkEntityType,
|
||||
pub (crate) entity_token: String,
|
||||
|
||||
pub (crate) user_token: UserToken,
|
||||
@@ -51,27 +51,27 @@ pub struct RawUserFavoriteRecord {
|
||||
pub (crate) maybe_descriptive_text_zs_voice_title: Option<String>,
|
||||
}
|
||||
|
||||
impl RawUserFavoriteRecord {
|
||||
pub fn into_public_type(self) -> UserFavorite {
|
||||
UserFavorite {
|
||||
impl RawUserBookmarkRecord {
|
||||
pub fn into_public_type(self) -> UserBookmark {
|
||||
UserBookmark {
|
||||
token: self.token,
|
||||
entity_type: self.entity_type,
|
||||
entity_token: self.entity_token,
|
||||
maybe_entity_descriptive_text: match self.entity_type {
|
||||
FavoriteEntityType::User => self.maybe_descriptive_text_user_display_name,
|
||||
FavoriteEntityType::TtsModel => self.maybe_descriptive_text_tts_model_title,
|
||||
FavoriteEntityType::TtsResult => self.maybe_descriptive_text_tts_result_inference_text,
|
||||
FavoriteEntityType::W2lTemplate => None,
|
||||
FavoriteEntityType::W2lResult => None,
|
||||
UserBookmarkEntityType::User => self.maybe_descriptive_text_user_display_name,
|
||||
UserBookmarkEntityType::TtsModel => self.maybe_descriptive_text_tts_model_title,
|
||||
UserBookmarkEntityType::TtsResult => self.maybe_descriptive_text_tts_result_inference_text,
|
||||
UserBookmarkEntityType::W2lTemplate => None,
|
||||
UserBookmarkEntityType::W2lResult => None,
|
||||
// TODO(bt,2023-11-21): Summary text needs to be better enriched.
|
||||
FavoriteEntityType::MediaFile => self.maybe_media_file_type
|
||||
UserBookmarkEntityType::MediaFile => self.maybe_media_file_type
|
||||
.and_then(|media_file_type| match media_file_type {
|
||||
MediaFileType::Audio => Some("audio media file".to_string()),
|
||||
MediaFileType::Image => Some("image media file".to_string()),
|
||||
MediaFileType::Video => Some("video media file".to_string()),
|
||||
}),
|
||||
FavoriteEntityType::VoiceConversionModel => self.maybe_descriptive_text_voice_conversion_model_title,
|
||||
FavoriteEntityType::ZsVoice => self.maybe_descriptive_text_zs_voice_title,
|
||||
UserBookmarkEntityType::VoiceConversionModel => self.maybe_descriptive_text_voice_conversion_model_title,
|
||||
UserBookmarkEntityType::ZsVoice => self.maybe_descriptive_text_zs_voice_title,
|
||||
},
|
||||
user_token: self.user_token,
|
||||
username: self.username,
|
||||
@@ -0,0 +1,7 @@
|
||||
pub mod delete_user_bookmark;
|
||||
pub mod create_user_bookmark;
|
||||
pub mod user_bookmark_entity_token;
|
||||
pub mod get_user_bookmark;
|
||||
pub mod list_user_bookmarks_for_entity;
|
||||
pub mod list_user_bookmarks;
|
||||
pub mod list_user_bookmarks_result;
|
||||
@@ -0,0 +1,48 @@
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::tts_models::TtsModelToken;
|
||||
use tokens::tokens::tts_results::TtsResultToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
use tokens::tokens::voice_conversion_models::VoiceConversionModelToken;
|
||||
use tokens::tokens::w2l_results::W2lResultToken;
|
||||
use tokens::tokens::w2l_templates::W2lTemplateToken;
|
||||
use tokens::tokens::zs_voices::ZsVoiceToken;
|
||||
|
||||
pub enum UserBookmarkEntityToken {
|
||||
User(UserToken),
|
||||
TtsModel(TtsModelToken),
|
||||
TtsResult(TtsResultToken),
|
||||
W2lTemplate(W2lTemplateToken),
|
||||
W2lResult(W2lResultToken),
|
||||
MediaFile(MediaFileToken),
|
||||
VoiceConversionModel(VoiceConversionModelToken),
|
||||
ZsVoice(ZsVoiceToken),
|
||||
}
|
||||
|
||||
impl UserBookmarkEntityToken {
|
||||
pub fn from_entity_type_and_token(entity_type: UserBookmarkEntityType, token: &str) -> Self {
|
||||
match entity_type {
|
||||
UserBookmarkEntityType::User => Self::User(UserToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::TtsModel => Self::TtsModel(TtsModelToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::TtsResult => Self::TtsResult(TtsResultToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::W2lTemplate => Self::W2lTemplate(W2lTemplateToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::W2lResult => Self::W2lResult(W2lResultToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::MediaFile => Self::MediaFile(MediaFileToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::VoiceConversionModel => Self::VoiceConversionModel(VoiceConversionModelToken::new_from_str(token)),
|
||||
UserBookmarkEntityType::ZsVoice => Self::ZsVoice(ZsVoiceToken::new_from_str(token)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_composite_keys(&self) -> (UserBookmarkEntityType, &str) {
|
||||
match self {
|
||||
UserBookmarkEntityToken::User(user_token) => (UserBookmarkEntityType::User, user_token.as_str()),
|
||||
UserBookmarkEntityToken::TtsModel(tts_model_token) => (UserBookmarkEntityType::TtsModel, tts_model_token.as_str()),
|
||||
UserBookmarkEntityToken::TtsResult(tts_result_token) => (UserBookmarkEntityType::TtsResult, tts_result_token.as_str()),
|
||||
UserBookmarkEntityToken::W2lTemplate(w2l_template_token) => (UserBookmarkEntityType::W2lTemplate, w2l_template_token.as_str()),
|
||||
UserBookmarkEntityToken::W2lResult(w2l_result_token) => (UserBookmarkEntityType::W2lResult, w2l_result_token.as_str()),
|
||||
UserBookmarkEntityToken::MediaFile(media_file_token) => (UserBookmarkEntityType::MediaFile, media_file_token.as_str()),
|
||||
UserBookmarkEntityToken::VoiceConversionModel(voice_conversion_model_token) => (UserBookmarkEntityType::VoiceConversionModel, voice_conversion_model_token.as_str()),
|
||||
UserBookmarkEntityToken::ZsVoice(zs_voice_token) => (UserBookmarkEntityType::ZsVoice, zs_voice_token.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
-122
@@ -1,122 +0,0 @@
|
||||
// NB: Incrementally getting rid of build warnings...
|
||||
#![forbid(unused_imports)]
|
||||
#![forbid(unused_mut)]
|
||||
#![forbid(unused_variables)]
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::Path;
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::warn;
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use mysql_queries::queries::favorites::favorite_entity_token::FavoriteEntityToken;
|
||||
use mysql_queries::queries::favorites::list_favorites_for_entity::list_favorites_for_entity;
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
|
||||
use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight};
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
/// For the URL PathInfo
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListFavoritesPathInfo {
|
||||
entity_type: FavoriteEntityType,
|
||||
entity_token: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ListFavoritesSuccessResponse {
|
||||
pub success: bool,
|
||||
pub favorites: Vec<Favorite>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Favorite {
|
||||
pub token: FavoriteToken,
|
||||
|
||||
pub user: UserDetailsLight,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ListFavoritesError {
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for ListFavoritesError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ListFavoritesError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
ListFavoritesError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for ListFavoritesError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_favorites_for_entity_handler(
|
||||
_http_request: HttpRequest,
|
||||
path: Path<ListFavoritesPathInfo>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListFavoritesError>
|
||||
{
|
||||
let entity_token = FavoriteEntityToken::from_entity_type_and_token(
|
||||
path.entity_type, &path.entity_token);
|
||||
|
||||
let query_results = list_favorites_for_entity(
|
||||
entity_token,
|
||||
&server_state.mysql_pool,
|
||||
).await;
|
||||
|
||||
let favorites = match query_results {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListFavoritesError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = ListFavoritesSuccessResponse {
|
||||
success: true,
|
||||
favorites: favorites.into_iter()
|
||||
.map(|favorite| Favorite {
|
||||
token: favorite.token,
|
||||
user: UserDetailsLight {
|
||||
user_token: favorite.user_token.clone(),
|
||||
username: favorite.username.to_string(), // NB: Cloned because of ref use for avatar below
|
||||
display_name: favorite.user_display_name.clone(),
|
||||
gravatar_hash: favorite.user_gravatar_hash.clone(),
|
||||
default_avatar: DefaultAvatarInfo::from_username(&favorite.username),
|
||||
},
|
||||
created_at: favorite.created_at,
|
||||
updated_at: favorite.updated_at,
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| ListFavoritesError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(body))
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
pub mod create_favorite_handler;
|
||||
pub mod delete_favorite_handler;
|
||||
pub mod list_favorites_for_entity_handler;
|
||||
pub mod list_favorites_for_session_handler;
|
||||
pub mod list_favorites_for_user_handler;
|
||||
@@ -25,5 +25,5 @@ pub mod voice_clone_requests;
|
||||
pub mod voice_conversion;
|
||||
pub mod voice_designer;
|
||||
pub mod w2l;
|
||||
pub mod favorites;
|
||||
pub mod user_bookmarks;
|
||||
pub mod weights;
|
||||
+31
-31
@@ -11,46 +11,46 @@ use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use log::warn;
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use mysql_queries::queries::favorites::favorite_entity_token::FavoriteEntityToken;
|
||||
use mysql_queries::queries::favorites::create_favorite::{create_favorite, CreateFavoriteArgs};
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken;
|
||||
use mysql_queries::queries::user_bookmarks::create_user_bookmark::{create_user_bookmark, CreateUserBookmarkArgs};
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateFavoriteRequest {
|
||||
pub struct CreateUserBookmarkRequest {
|
||||
entity_token: String,
|
||||
entity_type: FavoriteEntityType,
|
||||
entity_type: UserBookmarkEntityType,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct CreateFavoriteSuccessResponse {
|
||||
pub struct CreateUserBookmarkSuccessResponse {
|
||||
pub success: bool,
|
||||
pub favorite_token: FavoriteToken,
|
||||
pub user_bookmark_token: UserBookmarkToken,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CreateFavoriteError {
|
||||
pub enum CreateUserBookmarkError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for CreateFavoriteError {
|
||||
impl ResponseError for CreateUserBookmarkError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
CreateFavoriteError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
CreateFavoriteError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
CreateFavoriteError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
CreateUserBookmarkError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
CreateUserBookmarkError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
CreateUserBookmarkError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
CreateFavoriteError::BadInput(reason) => reason.to_string(),
|
||||
CreateFavoriteError::NotAuthorized => "unauthorized".to_string(),
|
||||
CreateFavoriteError::ServerError => "server error".to_string(),
|
||||
CreateUserBookmarkError::BadInput(reason) => reason.to_string(),
|
||||
CreateUserBookmarkError::NotAuthorized => "unauthorized".to_string(),
|
||||
CreateUserBookmarkError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -58,24 +58,24 @@ impl ResponseError for CreateFavoriteError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for CreateFavoriteError {
|
||||
impl fmt::Display for CreateUserBookmarkError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_favorite_handler(
|
||||
pub async fn create_user_bookmark_handler(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<CreateFavoriteRequest>,
|
||||
request: web::Json<CreateUserBookmarkRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>,
|
||||
) -> Result<HttpResponse, CreateFavoriteError>
|
||||
) -> Result<HttpResponse, CreateUserBookmarkError>
|
||||
{
|
||||
let mut mysql_connection = server_state.mysql_pool
|
||||
.acquire()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("MySql pool error: {:?}", err);
|
||||
CreateFavoriteError::ServerError
|
||||
CreateUserBookmarkError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_user_session = server_state
|
||||
@@ -84,42 +84,42 @@ pub async fn create_favorite_handler(
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
CreateFavoriteError::ServerError
|
||||
CreateUserBookmarkError::ServerError
|
||||
})?;
|
||||
|
||||
let user_session = match maybe_user_session {
|
||||
Some(session) => session,
|
||||
None => {
|
||||
warn!("not logged in");
|
||||
return Err(CreateFavoriteError::NotAuthorized);
|
||||
return Err(CreateUserBookmarkError::NotAuthorized);
|
||||
}
|
||||
};
|
||||
|
||||
let entity_token = FavoriteEntityToken::from_entity_type_and_token(
|
||||
let entity_token = UserBookmarkEntityToken::from_entity_type_and_token(
|
||||
request.entity_type, &request.entity_token);
|
||||
|
||||
let query_result = create_favorite(CreateFavoriteArgs {
|
||||
let query_result = create_user_bookmark(CreateUserBookmarkArgs {
|
||||
entity_token: &entity_token,
|
||||
user_token: &user_session.user_token_typed,
|
||||
mysql_executor: &mut *mysql_connection,
|
||||
phantom: Default::default(),
|
||||
}).await;
|
||||
|
||||
let favorite_token = match query_result {
|
||||
let user_bookmark_token = match query_result {
|
||||
Ok(token) => token,
|
||||
Err(err) => {
|
||||
warn!("error inserting favorite: {:?}", err);
|
||||
return Err(CreateFavoriteError::ServerError);
|
||||
warn!("error inserting user_bookmark: {:?}", err);
|
||||
return Err(CreateUserBookmarkError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = CreateFavoriteSuccessResponse {
|
||||
let response = CreateUserBookmarkSuccessResponse {
|
||||
success: true,
|
||||
favorite_token,
|
||||
user_bookmark_token,
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| CreateFavoriteError::ServerError)?;
|
||||
.map_err(|_e| CreateUserBookmarkError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
+26
-26
@@ -12,8 +12,8 @@ use actix_web::http::StatusCode;
|
||||
use actix_web::web::Path;
|
||||
use log::warn;
|
||||
|
||||
use mysql_queries::queries::favorites::delete_favorite::delete_favorite;
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
use mysql_queries::queries::user_bookmarks::delete_user_bookmark::delete_user_bookmark;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::http_server::web_utils::response_success_helpers::simple_json_success;
|
||||
@@ -21,40 +21,40 @@ use crate::server_state::ServerState;
|
||||
|
||||
/// For the URL PathInfo
|
||||
#[derive(Deserialize)]
|
||||
pub struct DeleteFavoritePathInfo {
|
||||
favorite_token: FavoriteToken,
|
||||
pub struct DeleteUserBookmarkPathInfo {
|
||||
user_bookmark_token: UserBookmarkToken,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DeleteFavoriteRequest {
|
||||
pub struct DeleteUserBookmarkRequest {
|
||||
/// NB: this is only to disambiguate when a user is both a mod and an author.
|
||||
as_mod: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DeleteFavoriteError {
|
||||
pub enum DeleteUserBookmarkError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
NotFound,
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for DeleteFavoriteError {
|
||||
impl ResponseError for DeleteUserBookmarkError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
DeleteFavoriteError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
DeleteFavoriteError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
DeleteFavoriteError::NotFound => StatusCode::NOT_FOUND,
|
||||
DeleteFavoriteError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
DeleteUserBookmarkError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
DeleteUserBookmarkError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
DeleteUserBookmarkError::NotFound => StatusCode::NOT_FOUND,
|
||||
DeleteUserBookmarkError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
DeleteFavoriteError::BadInput(reason) => reason.to_string(),
|
||||
DeleteFavoriteError::NotAuthorized => "unauthorized".to_string(),
|
||||
DeleteFavoriteError::NotFound => "not found".to_string(),
|
||||
DeleteFavoriteError::ServerError => "server error".to_string(),
|
||||
DeleteUserBookmarkError::BadInput(reason) => reason.to_string(),
|
||||
DeleteUserBookmarkError::NotAuthorized => "unauthorized".to_string(),
|
||||
DeleteUserBookmarkError::NotFound => "not found".to_string(),
|
||||
DeleteUserBookmarkError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -62,24 +62,24 @@ impl ResponseError for DeleteFavoriteError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for DeleteFavoriteError {
|
||||
impl fmt::Display for DeleteUserBookmarkError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_favorite_handler(
|
||||
pub async fn delete_user_bookmark_handler(
|
||||
http_request: HttpRequest,
|
||||
path: Path<DeleteFavoritePathInfo>,
|
||||
_request: web::Json<DeleteFavoriteRequest>,
|
||||
path: Path<DeleteUserBookmarkPathInfo>,
|
||||
_request: web::Json<DeleteUserBookmarkRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, DeleteFavoriteError> {
|
||||
) -> Result<HttpResponse, DeleteUserBookmarkError> {
|
||||
let mut mysql_connection = server_state.mysql_pool
|
||||
.acquire()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("MySql pool error: {:?}", err);
|
||||
DeleteFavoriteError::ServerError
|
||||
DeleteUserBookmarkError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_user_session = server_state
|
||||
@@ -88,18 +88,18 @@ pub async fn delete_favorite_handler(
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
DeleteFavoriteError::ServerError
|
||||
DeleteUserBookmarkError::ServerError
|
||||
})?;
|
||||
|
||||
let user_session = match maybe_user_session {
|
||||
Some(session) => session,
|
||||
None => {
|
||||
return Err(DeleteFavoriteError::NotAuthorized);
|
||||
return Err(DeleteUserBookmarkError::NotAuthorized);
|
||||
}
|
||||
};
|
||||
|
||||
let query_result = delete_favorite(
|
||||
&path.favorite_token,
|
||||
let query_result = delete_user_bookmark(
|
||||
&path.user_bookmark_token,
|
||||
&user_session.user_token_typed,
|
||||
&mut *mysql_connection
|
||||
).await;
|
||||
@@ -108,7 +108,7 @@ pub async fn delete_favorite_handler(
|
||||
Ok(_) => {},
|
||||
Err(err) => {
|
||||
warn!("Update tts mod approval status DB error: {:?}", err);
|
||||
return Err(DeleteFavoriteError::ServerError);
|
||||
return Err(DeleteUserBookmarkError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
// NB: Incrementally getting rid of build warnings...
|
||||
#![forbid(unused_imports)]
|
||||
#![forbid(unused_mut)]
|
||||
#![forbid(unused_variables)]
|
||||
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::Path;
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::warn;
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken;
|
||||
use mysql_queries::queries::user_bookmarks::list_user_bookmarks_for_entity::list_user_bookmarks_for_entity;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight};
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
/// For the URL PathInfo
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListUserBookmarkPathInfo {
|
||||
entity_type: UserBookmarkEntityType,
|
||||
entity_token: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ListUserBookmarksSuccessResponse {
|
||||
pub success: bool,
|
||||
pub user_bookmarks: Vec<UserBookmark>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub user: UserDetailsLight,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ListUserBookmarksError {
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for ListUserBookmarksError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
ListUserBookmarksError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for ListUserBookmarksError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_user_bookmarks_for_entity_handler(
|
||||
_http_request: HttpRequest,
|
||||
path: Path<ListUserBookmarkPathInfo>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListUserBookmarksError>
|
||||
{
|
||||
let entity_token = UserBookmarkEntityToken::from_entity_type_and_token(
|
||||
path.entity_type, &path.entity_token);
|
||||
|
||||
let query_results = list_user_bookmarks_for_entity(
|
||||
entity_token,
|
||||
&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,
|
||||
user: UserDetailsLight {
|
||||
user_token: user_bookmark.user_token.clone(),
|
||||
username: user_bookmark.username.to_string(), // NB: Cloned because of ref use for avatar below
|
||||
display_name: user_bookmark.user_display_name.clone(),
|
||||
gravatar_hash: user_bookmark.user_gravatar_hash.clone(),
|
||||
default_avatar: DefaultAvatarInfo::from_username(&user_bookmark.username),
|
||||
},
|
||||
created_at: user_bookmark.created_at,
|
||||
updated_at: user_bookmark.updated_at,
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| ListUserBookmarksError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(body))
|
||||
}
|
||||
+38
-38
@@ -13,38 +13,38 @@ use actix_web::web::Query;
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::warn;
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use mysql_queries::queries::favorites::list_user_favorites::{list_user_favorites, list_user_favorites_by_entity_type};
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
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 tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListFavoritesQueryData {
|
||||
maybe_scoped_entity_type: Option<FavoriteEntityType>,
|
||||
pub struct ListUserBookmarksQueryData {
|
||||
maybe_scoped_entity_type: Option<UserBookmarkEntityType>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ListFavoritesSuccessResponse {
|
||||
pub struct ListUserBookmarksSuccessResponse {
|
||||
pub success: bool,
|
||||
pub favorites: Vec<Favorite>,
|
||||
pub user_bookmarks: Vec<UserBookmark>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Favorite {
|
||||
pub token: FavoriteToken,
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub details: FavoriteDetails,
|
||||
pub details: UserBookmarkDetails,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FavoriteDetails {
|
||||
pub struct UserBookmarkDetails {
|
||||
// TODO: This needs titles or some other summary metadata.
|
||||
pub entity_type: FavoriteEntityType,
|
||||
pub entity_type: UserBookmarkEntityType,
|
||||
pub entity_token: String,
|
||||
|
||||
// TODO: Populate this for TTS
|
||||
@@ -55,23 +55,23 @@ pub struct FavoriteDetails {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ListFavoritesError {
|
||||
pub enum ListUserBookmarksError {
|
||||
ServerError,
|
||||
NotAuthorizedError,
|
||||
}
|
||||
|
||||
impl ResponseError for ListFavoritesError {
|
||||
impl ResponseError for ListUserBookmarksError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ListFavoritesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ListFavoritesError::NotAuthorizedError => StatusCode::UNAUTHORIZED,
|
||||
ListUserBookmarksError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ListUserBookmarksError::NotAuthorizedError => StatusCode::UNAUTHORIZED,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
ListFavoritesError::ServerError => "server error".to_string(),
|
||||
ListFavoritesError::NotAuthorizedError => "not authorized".to_string(),
|
||||
ListUserBookmarksError::ServerError => "server error".to_string(),
|
||||
ListUserBookmarksError::NotAuthorizedError => "not authorized".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -79,61 +79,61 @@ impl ResponseError for ListFavoritesError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for ListFavoritesError {
|
||||
impl fmt::Display for ListUserBookmarksError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_favorites_for_session_handler(
|
||||
pub async fn list_user_bookmarks_for_session_handler(
|
||||
http_request: HttpRequest,
|
||||
query: Query<ListFavoritesQueryData>,
|
||||
query: Query<ListUserBookmarksQueryData>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListFavoritesError>
|
||||
) -> Result<HttpResponse, ListUserBookmarksError>
|
||||
{
|
||||
let 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);
|
||||
ListFavoritesError::ServerError
|
||||
ListUserBookmarksError::ServerError
|
||||
})?
|
||||
.ok_or(ListFavoritesError::NotAuthorizedError)?;
|
||||
.ok_or(ListUserBookmarksError::NotAuthorizedError)?;
|
||||
|
||||
let query_results = match query.maybe_scoped_entity_type {
|
||||
None => list_user_favorites(&user_session.username, &server_state.mysql_pool).await,
|
||||
None => list_user_bookmarks(&user_session.username, &server_state.mysql_pool).await,
|
||||
Some(entity_type) =>
|
||||
list_user_favorites_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool)
|
||||
list_user_user_bookmarks_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool)
|
||||
.await,
|
||||
};
|
||||
|
||||
let favorites = match query_results {
|
||||
let user_bookmarks = match query_results {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListFavoritesError::ServerError);
|
||||
return Err(ListUserBookmarksError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = ListFavoritesSuccessResponse {
|
||||
let response = ListUserBookmarksSuccessResponse {
|
||||
success: true,
|
||||
favorites: favorites.into_iter()
|
||||
.map(|favorite| Favorite {
|
||||
token: favorite.token,
|
||||
details: FavoriteDetails {
|
||||
entity_type: favorite.entity_type,
|
||||
entity_token: favorite.entity_token,
|
||||
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: favorite.created_at,
|
||||
updated_at: favorite.updated_at,
|
||||
created_at: user_bookmark.created_at,
|
||||
updated_at: user_bookmark.updated_at,
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| ListFavoritesError::ServerError)?;
|
||||
.map_err(|_e| ListUserBookmarksError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
+37
-37
@@ -13,43 +13,43 @@ use actix_web::web::{Path, Query};
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::warn;
|
||||
|
||||
use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType;
|
||||
use mysql_queries::queries::favorites::list_user_favorites::{list_user_favorites, list_user_favorites_by_entity_type};
|
||||
use tokens::tokens::favorites::FavoriteToken;
|
||||
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 tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListFavoritesPathInfo {
|
||||
pub struct ListUserBookmarksPathInfo {
|
||||
username: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListFavoritesQueryData {
|
||||
maybe_scoped_entity_type: Option<FavoriteEntityType>,
|
||||
pub struct ListUserBookmarksQueryData {
|
||||
maybe_scoped_entity_type: Option<UserBookmarkEntityType>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ListFavoritesSuccessResponse {
|
||||
pub struct ListUserBookmarksSuccessResponse {
|
||||
pub success: bool,
|
||||
pub favorites: Vec<Favorite>,
|
||||
pub user_bookmarks: Vec<UserBookmark>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Favorite {
|
||||
pub token: FavoriteToken,
|
||||
pub struct UserBookmark {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub details: FavoriteDetails,
|
||||
pub details: UserBookmarkDetails,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FavoriteDetails {
|
||||
pub struct UserBookmarkDetails {
|
||||
// TODO: This needs titles or some other summary metadata.
|
||||
pub entity_type: FavoriteEntityType,
|
||||
pub entity_type: UserBookmarkEntityType,
|
||||
pub entity_token: String,
|
||||
|
||||
// TODO: Populate this for TTS
|
||||
@@ -60,20 +60,20 @@ pub struct FavoriteDetails {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ListFavoritesError {
|
||||
pub enum ListUserBookmarksError {
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for ListFavoritesError {
|
||||
impl ResponseError for ListUserBookmarksError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ListFavoritesError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
ListFavoritesError::ServerError => "server error".to_string(),
|
||||
ListUserBookmarksError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -81,56 +81,56 @@ impl ResponseError for ListFavoritesError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for ListFavoritesError {
|
||||
impl fmt::Display for ListUserBookmarksError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_favorites_for_user_handler(
|
||||
pub async fn list_user_bookmarks_for_user_handler(
|
||||
_http_request: HttpRequest,
|
||||
path: Path<ListFavoritesPathInfo>,
|
||||
query: Query<ListFavoritesQueryData>,
|
||||
path: Path<ListUserBookmarksPathInfo>,
|
||||
query: Query<ListUserBookmarksQueryData>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListFavoritesError>
|
||||
) -> Result<HttpResponse, ListUserBookmarksError>
|
||||
{
|
||||
|
||||
let query_results = match query.maybe_scoped_entity_type {
|
||||
None => list_user_favorites(&path.username, &server_state.mysql_pool).await,
|
||||
None => list_user_bookmarks(&path.username, &server_state.mysql_pool).await,
|
||||
Some(entity_type) =>
|
||||
list_user_favorites_by_entity_type(&path.username, entity_type, &server_state.mysql_pool)
|
||||
list_user_user_bookmarks_by_entity_type(&path.username, entity_type, &server_state.mysql_pool)
|
||||
.await,
|
||||
};
|
||||
|
||||
let favorites = match query_results {
|
||||
let user_bookmarks = match query_results {
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListFavoritesError::ServerError);
|
||||
return Err(ListUserBookmarksError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = ListFavoritesSuccessResponse {
|
||||
let response = ListUserBookmarksSuccessResponse {
|
||||
success: true,
|
||||
favorites: favorites.into_iter()
|
||||
.map(|favorite| Favorite {
|
||||
token: favorite.token,
|
||||
details: FavoriteDetails {
|
||||
entity_type: favorite.entity_type,
|
||||
entity_token: favorite.entity_token,
|
||||
maybe_summary_text: favorite.maybe_entity_descriptive_text,
|
||||
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: user_bookmark.maybe_entity_descriptive_text,
|
||||
// TODO(bt,2023-11-21): Thumbnails need proper support. We should build them as a
|
||||
// first-class system before handling the backfill here.
|
||||
maybe_thumbnail_url: None,
|
||||
},
|
||||
created_at: favorite.created_at,
|
||||
updated_at: favorite.updated_at,
|
||||
created_at: user_bookmark.created_at,
|
||||
updated_at: user_bookmark.updated_at,
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| ListFavoritesError::ServerError)?;
|
||||
.map_err(|_e| ListUserBookmarksError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod create_user_bookmark_handler;
|
||||
pub mod delete_user_bookmark_handler;
|
||||
pub mod list_user_bookmarks_for_entity_handler;
|
||||
pub mod list_user_bookmarks_for_session_handler;
|
||||
pub mod list_user_bookmarks_for_user_handler;
|
||||
@@ -28,11 +28,11 @@ use crate::http_server::endpoints::comments::list_comments_handler::list_comment
|
||||
use crate::http_server::endpoints::download_job::enqueue_generic_download::enqueue_generic_download_handler;
|
||||
use crate::http_server::endpoints::download_job::get_generic_upload_job_status::get_generic_download_job_status_handler;
|
||||
use crate::http_server::endpoints::events::list_events::list_events_handler;
|
||||
use crate::http_server::endpoints::favorites::create_favorite_handler::create_favorite_handler;
|
||||
use crate::http_server::endpoints::favorites::delete_favorite_handler::delete_favorite_handler;
|
||||
use crate::http_server::endpoints::favorites::list_favorites_for_entity_handler::list_favorites_for_entity_handler;
|
||||
use crate::http_server::endpoints::favorites::list_favorites_for_session_handler::list_favorites_for_session_handler;
|
||||
use crate::http_server::endpoints::favorites::list_favorites_for_user_handler::list_favorites_for_user_handler;
|
||||
use crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::create_user_bookmark_handler;
|
||||
use crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::delete_user_bookmark_handler;
|
||||
use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::list_user_bookmarks_for_entity_handler;
|
||||
use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_session_handler::list_user_bookmarks_for_session_handler;
|
||||
use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler;
|
||||
use crate::http_server::endpoints::flags::design_refresh_flag::disable_design_refresh_flag_handler::disable_design_refresh_flag_handler;
|
||||
use crate::http_server::endpoints::flags::design_refresh_flag::enable_design_refresh_flag_handler::enable_design_refresh_flag_handler;
|
||||
use crate::http_server::endpoints::inference_job::get_inference_job_status::get_inference_job_status_handler;
|
||||
@@ -202,14 +202,14 @@ pub fn add_routes<T, B> (app: App<T>, server_environment: ServerEnvironment) ->
|
||||
.add_post("/v1/comments/delete/{comment_token}", delete_comment_handler)
|
||||
.into_app();
|
||||
|
||||
// ==================== Favorites ====================
|
||||
// ==================== User Bookmarks ====================
|
||||
|
||||
let mut app = RouteBuilder::from_app(app)
|
||||
.add_post("/v1/favorites/create", create_favorite_handler)
|
||||
.add_post("/v1/favorites/delete/{favorite_token}", delete_favorite_handler)
|
||||
.add_get("/v1/favorites/list/session", list_favorites_for_session_handler)
|
||||
.add_get("/v1/favorites/list/user/{username}", list_favorites_for_user_handler)
|
||||
.add_get("/v1/favorites/list/entity/{entity_type}/{entity_token}", list_favorites_for_entity_handler)
|
||||
.add_post("/v1/user_bookmarks/create", create_user_bookmark_handler)
|
||||
.add_post("/v1/user_bookmarks/delete/{user_bookmark_token}", delete_user_bookmark_handler)
|
||||
.add_get("/v1/user_bookmarks/list/session", list_user_bookmarks_for_session_handler)
|
||||
.add_get("/v1/user_bookmarks/list/user/{username}", list_user_bookmarks_for_user_handler)
|
||||
.add_get("/v1/user_bookmarks/list/entity/{entity_type}/{entity_token}", list_user_bookmarks_for_entity_handler)
|
||||
.into_app();
|
||||
|
||||
// ==================== Animations ====================
|
||||
|
||||
Reference in new issue
Block a user