Compare commits

..
Author SHA1 Message Date
Kasisnu afa91c032e fix typos in ratings endpoints docs 2023-12-27 16:43:07 +05:30
Kasisnu a76807ab7d document user rating endpoint 2023-12-27 16:32:09 +05:30
Kasisnu 15c1cb8e5e list weights/endpoints return public/private results based on user session 2023-12-27 16:04:10 +05:30
Kasisnu 4a69589f1d Merge pull request #247 from storytold/dec-26-mithoo
minor query builder updates for editing weights and paginatinating weights explore
2023-12-27 11:55:16 +05:30
Kasisnu ed72cf7f7f rename per_page -> page_size for consistency 2023-12-27 11:54:30 +05:30
Kasisnu ad093d3fa8 explore weights query builder offset 2023-12-26 20:02:39 +05:30
Kasisnu b505896864 update weights w/query builder 2023-12-26 16:16:47 +05:30
Brandon Thomas b680002c6b fix download job 2023-12-24 03:22:50 -05:00
Brandon Thomas 40bb91f024 fix lints 2023-12-24 02:42:58 -05:00
Brandon Thomas fa002d3fe3 Merge pull request #245 from storytold/brandon-make-model-weights-descriptions-optional
make model_weights descriptions optional
2023-12-24 02:25:12 -05:00
Brandon Thomas 02bec3655c make model_weights descriptions optional
- these will be bad to have on low-value weights, eg. zero shot.
- want to capture this change now
2023-12-24 02:24:20 -05:00
Brandon Thomas 12b7f4d25e fix broken download job query 2023-12-24 01:40:20 -05:00
Brandon Thomas 02d6f6c940 fix a class of model download failures 2023-12-24 01:24:58 -05:00
Brandon Thomas f5d7c93c22 media file scoping query bug fix 2023-12-23 23:46:03 -05:00
ArEnSc 0125eba7cc Merge pull request #244 from storytold/feature/missing-response-values
Fixed added weights type by request.
2023-12-23 23:26:49 -05:00
ArEnSc 033e42d1b1 Merge pull request #243 from storytold/feature/missing-response-values
Add missing data in response
2023-12-23 15:02:13 -05:00
Brandon Thomas aa0632bd41 Merge pull request #242 from storytold/dec-21-mithoo
media files pagination fix
2023-12-22 14:11:41 -05:00
Brandon Thomas 87cc49982e model weights es document 2023-12-22 12:57:50 -05:00
Brandon Thomas 853943f21a mimetype reuse 2023-12-22 11:01:21 -05:00
Kasisnu 6f9dd4d6e3 make user bookmarks pagination consistent with media/weights 2023-12-22 18:15:29 +05:30
Kasisnu 5de56cd11b make public weights & media list behave similarly wrt pagination 2023-12-22 13:14:31 +05:30
Kasisnu df16a4aa89 media files pagination fix 2023-12-22 13:06:30 +05:30
Brandon Thomas 613289f1ab update docs 2023-12-21 23:41:37 -05:00
Brandon Thomas ae49b9da7d fix image uploads 2023-12-21 23:16:15 -05:00
Brandon Thomas 3f531ae9f0 API doc, fix field name 2023-12-21 23:08:13 -05:00
Brandon Thomas 370bcf3f2d Merge pull request #241 from storytold/brandon-rename-avatar-to-cover
rename avatar to cover_image
2023-12-21 22:54:15 -05:00
Brandon Thomas 685264e20c fix seeding; codegen 2023-12-21 22:53:28 -05:00
Brandon Thomas 2c7400bf76 update code references (avatar -> cover_image) 2023-12-21 22:49:44 -05:00
Brandon Thomas fae36d485b migrations to simplify media files on a model 2023-12-21 22:26:41 -05:00
Brandon Thomas fe3107b1b0 fix lints/tests failures 2023-12-21 22:11:00 -05:00
Brandon Thomas bdde5da223 Merge pull request #240 from storytold/brandon-more-avatar-images
more "avatar" images on weights
2023-12-21 21:06:27 -05:00
Brandon Thomas 7539237ee4 more "avatar" images on weights 2023-12-21 21:05:14 -05:00
80 changed files with 1559 additions and 2250 deletions
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_cover_image_media_file_token = NULL,\n maybe_description_markdown = ?,\n maybe_description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_cover_image_media_file_token = NULL,\n maybe_description_markdown = ?,\n maybe_description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 43
},
"nullable": []
},
"hash": "0a392b6adb884a4bb4c08fbc2123d40c27e9fbb5c2b688b182f849b0c1cc5735"
}
@@ -1,212 +0,0 @@
{
"db_name": "MySQL",
"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 model_weights.title as maybe_descriptive_text_model_weight_title,\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 model_weights ON model_weights.token = f.entity_token\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::user_bookmarks::UserBookmarkToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"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",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 2,
"name": "entity_token",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 3,
"name": "user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 4,
"name": "username",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 5,
"name": "user_display_name",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 6,
"name": "user_gravatar_hash",
"type_info": {
"type": "String",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 7,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 9,
"name": "deleted_at",
"type_info": {
"type": "Timestamp",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 10,
"name": "maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 11,
"name": "maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 12,
"name": "maybe_descriptive_text_model_weight_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 13,
"name": "maybe_descriptive_text_tts_model_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 14,
"name": "maybe_descriptive_text_tts_result_inference_text",
"type_info": {
"type": "Blob",
"flags": "BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 15,
"name": "maybe_descriptive_text_user_display_name",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 16,
"name": "maybe_descriptive_text_voice_conversion_model_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 17,
"name": "maybe_descriptive_text_zs_voice_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true
]
},
"hash": "3a7ac7f979ac270dad1070031d0d663d0eb3d969365f6b2fd048ca41c5c455b2"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_cover_image_media_file_token = NULL,\n maybe_description_markdown = NULL,\n maybe_description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 15
},
"nullable": []
},
"hash": "6512f05410514927b52b8cc42f4eda0ad7a256254fd7fcf3b8a1cc429b06ad38"
}
@@ -1,212 +0,0 @@
{
"db_name": "MySQL",
"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 model_weights.title as maybe_descriptive_text_model_weight_title,\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 model_weights ON model_weights.token = f.entity_token\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::user_bookmarks::UserBookmarkToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"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",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 2,
"name": "entity_token",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 3,
"name": "user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 4,
"name": "username",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 5,
"name": "user_display_name",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 6,
"name": "user_gravatar_hash",
"type_info": {
"type": "String",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 7,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 8,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 9,
"name": "deleted_at",
"type_info": {
"type": "Timestamp",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 10,
"name": "maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 11,
"name": "maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory",
"type_info": {
"type": "VarString",
"flags": "MULTIPLE_KEY | BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 12,
"name": "maybe_descriptive_text_model_weight_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 13,
"name": "maybe_descriptive_text_tts_model_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 14,
"name": "maybe_descriptive_text_tts_result_inference_text",
"type_info": {
"type": "Blob",
"flags": "BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 15,
"name": "maybe_descriptive_text_user_display_name",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 16,
"name": "maybe_descriptive_text_voice_conversion_model_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 17,
"name": "maybe_descriptive_text_zs_voice_title",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true
]
},
"hash": "707af35ee4ab4519f28e6d69982944666e6c7c0f24b5da79dde828ffdb2c8302"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n ",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_description_markdown,\n wt.maybe_description_rendered_html,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = wt.maybe_cover_image_media_file_token\n WHERE\n wt.token = ?\n ",
"describe": {
"columns": [
{
@@ -45,36 +45,26 @@
},
{
"ordinal": 4,
"name": "maybe_thumbnail_token",
"name": "maybe_description_markdown",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"type": "Blob",
"flags": "BLOB | BINARY",
"char_set": 224,
"max_size": 128
"max_size": 262140
}
},
{
"ordinal": 5,
"name": "description_markdown",
"name": "maybe_description_rendered_html",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"flags": "BLOB | BINARY",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 6,
"name": "description_rendered_html",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 7,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -84,7 +74,7 @@
}
},
{
"ordinal": 8,
"ordinal": 7,
"name": "creator_username",
"type_info": {
"type": "VarString",
@@ -94,7 +84,7 @@
}
},
{
"ordinal": 9,
"ordinal": 8,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
@@ -104,7 +94,7 @@
}
},
{
"ordinal": 10,
"ordinal": 9,
"name": "creator_gravatar_hash",
"type_info": {
"type": "String",
@@ -114,7 +104,7 @@
}
},
{
"ordinal": 11,
"ordinal": 10,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
@@ -124,7 +114,7 @@
}
},
{
"ordinal": 12,
"ordinal": 11,
"name": "creator_set_visibility: enums::common::visibility::Visibility",
"type_info": {
"type": "String",
@@ -134,7 +124,7 @@
}
},
{
"ordinal": 13,
"ordinal": 12,
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -144,7 +134,7 @@
}
},
{
"ordinal": 14,
"ordinal": 13,
"name": "original_download_url",
"type_info": {
"type": "VarString",
@@ -154,7 +144,7 @@
}
},
{
"ordinal": 15,
"ordinal": 14,
"name": "original_filename",
"type_info": {
"type": "VarString",
@@ -164,7 +154,7 @@
}
},
{
"ordinal": 16,
"ordinal": 15,
"name": "file_size_bytes",
"type_info": {
"type": "Long",
@@ -174,7 +164,7 @@
}
},
{
"ordinal": 17,
"ordinal": 16,
"name": "file_checksum_sha2",
"type_info": {
"type": "String",
@@ -184,7 +174,7 @@
}
},
{
"ordinal": 18,
"ordinal": 17,
"name": "public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -194,7 +184,7 @@
}
},
{
"ordinal": 19,
"ordinal": 18,
"name": "maybe_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -204,7 +194,7 @@
}
},
{
"ordinal": 20,
"ordinal": 19,
"name": "maybe_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -214,8 +204,8 @@
}
},
{
"ordinal": 21,
"name": "maybe_avatar_public_bucket_hash",
"ordinal": 20,
"name": "maybe_cover_image_public_bucket_hash",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
@@ -223,9 +213,19 @@
"max_size": 128
}
},
{
"ordinal": 21,
"name": "maybe_cover_image_public_bucket_prefix",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 22,
"name": "maybe_avatar_public_bucket_prefix",
"name": "maybe_cover_image_public_bucket_extension",
"type_info": {
"type": "VarString",
"flags": "BINARY",
@@ -235,16 +235,6 @@
},
{
"ordinal": 23,
"name": "maybe_avatar_public_bucket_extension",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 24,
"name": "cached_user_ratings_negative_count",
"type_info": {
"type": "Long",
@@ -254,7 +244,7 @@
}
},
{
"ordinal": 25,
"ordinal": 24,
"name": "cached_user_ratings_positive_count",
"type_info": {
"type": "Long",
@@ -264,7 +254,7 @@
}
},
{
"ordinal": 26,
"ordinal": 25,
"name": "cached_user_ratings_total_count",
"type_info": {
"type": "Long",
@@ -274,7 +264,7 @@
}
},
{
"ordinal": 27,
"ordinal": 26,
"name": "maybe_cached_user_ratings_ratio",
"type_info": {
"type": "Float",
@@ -284,7 +274,7 @@
}
},
{
"ordinal": 28,
"ordinal": 27,
"name": "cached_user_ratings_last_updated_at",
"type_info": {
"type": "Timestamp",
@@ -294,7 +284,7 @@
}
},
{
"ordinal": 29,
"ordinal": 28,
"name": "version",
"type_info": {
"type": "Long",
@@ -304,7 +294,7 @@
}
},
{
"ordinal": 30,
"ordinal": 29,
"name": "created_at",
"type_info": {
"type": "Timestamp",
@@ -314,7 +304,7 @@
}
},
{
"ordinal": 31,
"ordinal": 30,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
@@ -324,7 +314,7 @@
}
},
{
"ordinal": 32,
"ordinal": 31,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -334,7 +324,7 @@
}
},
{
"ordinal": 33,
"ordinal": 32,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -353,8 +343,7 @@
false,
false,
true,
false,
false,
true,
false,
false,
false,
@@ -384,5 +373,5 @@
true
]
},
"hash": "4e30e34cdf7a5834a3981d5e634506966bac9f9c420e800d15ce313778272cee"
"hash": "7d3806f46b5cc96c0e3df22454190834c0294ad34db2d8271f2e2863a3cca3a1"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\n UPDATE model_weights\n SET\n title = COALESCE(?, title),\n description_markdown = COALESCE(?, description_markdown),\n maybe_thumbnail_token = COALESCE(?, maybe_thumbnail_token),\n description_rendered_html = COALESCE(?, description_rendered_html),\n creator_set_visibility = COALESCE(?, creator_set_visibility),\n version = version + 1\n WHERE token = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
},
"hash": "81df77a84fee48398e8a07e053b0393a0e341caf652c18c7160dd0a59247a19a"
}
@@ -1,355 +0,0 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.public_bucket_hash,\n mw.maybe_public_bucket_prefix,\n mw.maybe_public_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n AND mw.user_deleted_at IS NULL\n AND mw.mod_deleted_at IS NULL\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token: tokens::tokens::model_weights::ModelWeightToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "title",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 2,
"name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 3,
"name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 4,
"name": "maybe_thumbnail_token",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 5,
"name": "description_markdown",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 6,
"name": "description_rendered_html",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 7,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 8,
"name": "creator_username",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 9,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 10,
"name": "creator_email_gravatar_hash",
"type_info": {
"type": "String",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 11,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 12,
"name": "creator_set_visibility: enums::common::visibility::Visibility",
"type_info": {
"type": "String",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
"char_set": 224,
"max_size": 28
}
},
{
"ordinal": 13,
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 14,
"name": "original_download_url",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 2048
}
},
{
"ordinal": 15,
"name": "original_filename",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 16,
"name": "file_size_bytes",
"type_info": {
"type": "Long",
"flags": "NOT_NULL",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 17,
"name": "file_checksum_sha2",
"type_info": {
"type": "String",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 256
}
},
{
"ordinal": 18,
"name": "public_bucket_hash",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 19,
"name": "maybe_public_bucket_prefix",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 20,
"name": "maybe_public_bucket_extension",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 21,
"name": "cached_user_ratings_negative_count",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 22,
"name": "cached_user_ratings_positive_count",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 23,
"name": "cached_user_ratings_total_count",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 24,
"name": "maybe_cached_user_ratings_ratio",
"type_info": {
"type": "Float",
"flags": "",
"char_set": 63,
"max_size": 12
}
},
{
"ordinal": 25,
"name": "cached_user_ratings_last_updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 26,
"name": "version",
"type_info": {
"type": "Long",
"flags": "NOT_NULL",
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 27,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 28,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 29,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
"flags": "BINARY",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 30,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
"flags": "BINARY",
"char_set": 63,
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
false,
false,
false,
true,
true,
false,
false,
false,
true,
false,
false,
false,
false,
true,
true
]
},
"hash": "854da1bad28fbcf5a8f82c26c52c25a7727957b52b727831ce62518b3c5fc9bd"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = NULL,\n description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 15
},
"nullable": []
},
"hash": "8cb3ba5acb8dbef84408370810c98d4b99223761d4547ce7c8a9438ba92e8523"
}
@@ -0,0 +1,12 @@
{
"db_name": "MySQL",
"query": "\n INSERT INTO model_weights\n SET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_description_markdown = ?,\n maybe_description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = ?,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = ?,\n cached_user_ratings_positive_count = ?,\n cached_user_ratings_negative_count = ?,\n maybe_cached_user_ratings_ratio = ?,\n version = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 22
},
"nullable": []
},
"hash": "a18c5b1418d71fa9aefd3ae5c440be2afc1f9467808aa66d3b850a4d54c81e4d"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 43
},
"nullable": []
},
"hash": "aae28dc5fbeff858e4c9dd8b079752ce7892d76b56d2eff95db39c6b6d9f7f11"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ",
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_description_markdown,\n wt.maybe_description_rendered_html,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,\n cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,\n cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as cover_image\n ON cover_image.token = wt.maybe_cover_image_media_file_token\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ",
"describe": {
"columns": [
{
@@ -45,36 +45,26 @@
},
{
"ordinal": 4,
"name": "maybe_thumbnail_token",
"name": "maybe_description_markdown",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"type": "Blob",
"flags": "BLOB | BINARY",
"char_set": 224,
"max_size": 128
"max_size": 262140
}
},
{
"ordinal": 5,
"name": "description_markdown",
"name": "maybe_description_rendered_html",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"flags": "BLOB | BINARY",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 6,
"name": "description_rendered_html",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 7,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
@@ -84,7 +74,7 @@
}
},
{
"ordinal": 8,
"ordinal": 7,
"name": "creator_set_visibility: enums::common::visibility::Visibility",
"type_info": {
"type": "String",
@@ -94,7 +84,7 @@
}
},
{
"ordinal": 9,
"ordinal": 8,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -104,7 +94,7 @@
}
},
{
"ordinal": 10,
"ordinal": 9,
"name": "creator_username",
"type_info": {
"type": "VarString",
@@ -114,7 +104,7 @@
}
},
{
"ordinal": 11,
"ordinal": 10,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
@@ -124,7 +114,7 @@
}
},
{
"ordinal": 12,
"ordinal": 11,
"name": "creator_gravatar_hash",
"type_info": {
"type": "String",
@@ -134,7 +124,7 @@
}
},
{
"ordinal": 13,
"ordinal": 12,
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
@@ -144,7 +134,7 @@
}
},
{
"ordinal": 14,
"ordinal": 13,
"name": "original_download_url",
"type_info": {
"type": "VarString",
@@ -154,7 +144,7 @@
}
},
{
"ordinal": 15,
"ordinal": 14,
"name": "original_filename",
"type_info": {
"type": "VarString",
@@ -164,7 +154,7 @@
}
},
{
"ordinal": 16,
"ordinal": 15,
"name": "file_size_bytes",
"type_info": {
"type": "Long",
@@ -174,7 +164,7 @@
}
},
{
"ordinal": 17,
"ordinal": 16,
"name": "file_checksum_sha2",
"type_info": {
"type": "String",
@@ -184,7 +174,7 @@
}
},
{
"ordinal": 18,
"ordinal": 17,
"name": "public_bucket_hash",
"type_info": {
"type": "VarString",
@@ -194,7 +184,7 @@
}
},
{
"ordinal": 19,
"ordinal": 18,
"name": "maybe_public_bucket_prefix",
"type_info": {
"type": "VarString",
@@ -204,7 +194,7 @@
}
},
{
"ordinal": 20,
"ordinal": 19,
"name": "maybe_public_bucket_extension",
"type_info": {
"type": "VarString",
@@ -214,8 +204,8 @@
}
},
{
"ordinal": 21,
"name": "maybe_avatar_public_bucket_hash",
"ordinal": 20,
"name": "maybe_cover_image_public_bucket_hash",
"type_info": {
"type": "VarString",
"flags": "BINARY | NO_DEFAULT_VALUE",
@@ -223,9 +213,19 @@
"max_size": 128
}
},
{
"ordinal": 21,
"name": "maybe_cover_image_public_bucket_prefix",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 22,
"name": "maybe_avatar_public_bucket_prefix",
"name": "maybe_cover_image_public_bucket_extension",
"type_info": {
"type": "VarString",
"flags": "BINARY",
@@ -235,16 +235,6 @@
},
{
"ordinal": 23,
"name": "maybe_avatar_public_bucket_extension",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 24,
"name": "cached_user_ratings_negative_count",
"type_info": {
"type": "Long",
@@ -254,7 +244,7 @@
}
},
{
"ordinal": 25,
"ordinal": 24,
"name": "cached_user_ratings_positive_count",
"type_info": {
"type": "Long",
@@ -264,7 +254,7 @@
}
},
{
"ordinal": 26,
"ordinal": 25,
"name": "cached_user_ratings_total_count",
"type_info": {
"type": "Long",
@@ -274,7 +264,7 @@
}
},
{
"ordinal": 27,
"ordinal": 26,
"name": "maybe_cached_user_ratings_ratio",
"type_info": {
"type": "Float",
@@ -284,7 +274,7 @@
}
},
{
"ordinal": 28,
"ordinal": 27,
"name": "cached_user_ratings_last_updated_at",
"type_info": {
"type": "Timestamp",
@@ -294,7 +284,7 @@
}
},
{
"ordinal": 29,
"ordinal": 28,
"name": "version",
"type_info": {
"type": "Long",
@@ -304,7 +294,7 @@
}
},
{
"ordinal": 30,
"ordinal": 29,
"name": "created_at",
"type_info": {
"type": "Timestamp",
@@ -314,7 +304,7 @@
}
},
{
"ordinal": 31,
"ordinal": 30,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
@@ -324,7 +314,7 @@
}
},
{
"ordinal": 32,
"ordinal": 31,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -334,7 +324,7 @@
}
},
{
"ordinal": 33,
"ordinal": 32,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
@@ -353,8 +343,7 @@
false,
false,
true,
false,
false,
true,
false,
false,
false,
@@ -384,5 +373,5 @@
true
]
},
"hash": "93084dc42ae4ada186dc90bdd470122342586f4f19a3ac961286c1c54a5c32b2"
"hash": "bb2c5a81ab6f38ecef7ee177a4ea36e75c5d2180a897094f940f097bbbd66060"
}
@@ -1,12 +0,0 @@
{
"db_name": "MySQL",
"query": "\n INSERT INTO model_weights\n SET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = ?,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = ?,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = ?,\n cached_user_ratings_positive_count = ?,\n cached_user_ratings_negative_count = ?,\n maybe_cached_user_ratings_ratio = ?,\n version = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 23
},
"nullable": []
},
"hash": "cb07f1522d0d619e2f364af78250080c99e7930ec095c5600abb80a9d8c5154d"
}
@@ -1,6 +1,6 @@
{
"db_name": "MySQL",
"query": "\n UPDATE model_weights\n SET\n maybe_avatar_media_file_token = ?\n WHERE token = ?\n LIMIT 1\n ",
"query": "\n UPDATE model_weights\n SET\n maybe_cover_image_media_file_token = ?\n WHERE token = ?\n LIMIT 1\n ",
"describe": {
"columns": [],
"parameters": {
@@ -8,5 +8,5 @@
},
"nullable": []
},
"hash": "bda002b24b98328f0fb0440cfc82a47faf01e5d16d1030e15a7e2da161dd0d80"
"hash": "d7b28a5b4f0220b02eacb01df030c4d971fd191cf3cb5f0211ce29604d36bca3"
}
@@ -1,355 +0,0 @@
{
"db_name": "MySQL",
"query": "\n SELECT \n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.public_bucket_hash,\n mw.maybe_public_bucket_prefix,\n mw.maybe_public_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "token: tokens::tokens::model_weights::ModelWeightToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 1,
"name": "title",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 2,
"name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 3,
"name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 4,
"name": "maybe_thumbnail_token",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 5,
"name": "description_markdown",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 6,
"name": "description_rendered_html",
"type_info": {
"type": "Blob",
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 262140
}
},
{
"ordinal": 7,
"name": "creator_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 8,
"name": "creator_username",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 9,
"name": "creator_display_name",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 80
}
},
{
"ordinal": 10,
"name": "creator_email_gravatar_hash",
"type_info": {
"type": "String",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 11,
"name": "creator_ip_address",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 160
}
},
{
"ordinal": 12,
"name": "creator_set_visibility: enums::common::visibility::Visibility",
"type_info": {
"type": "String",
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM",
"char_set": 224,
"max_size": 28
}
},
{
"ordinal": 13,
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 14,
"name": "original_download_url",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 2048
}
},
{
"ordinal": 15,
"name": "original_filename",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 1020
}
},
{
"ordinal": 16,
"name": "file_size_bytes",
"type_info": {
"type": "Long",
"flags": "NOT_NULL",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 17,
"name": "file_checksum_sha2",
"type_info": {
"type": "String",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 256
}
},
{
"ordinal": 18,
"name": "public_bucket_hash",
"type_info": {
"type": "VarString",
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
"char_set": 224,
"max_size": 128
}
},
{
"ordinal": 19,
"name": "maybe_public_bucket_prefix",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 20,
"name": "maybe_public_bucket_extension",
"type_info": {
"type": "VarString",
"flags": "BINARY",
"char_set": 224,
"max_size": 64
}
},
{
"ordinal": 21,
"name": "cached_user_ratings_negative_count",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 22,
"name": "cached_user_ratings_positive_count",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 23,
"name": "cached_user_ratings_total_count",
"type_info": {
"type": "Long",
"flags": "NOT_NULL | UNSIGNED",
"char_set": 63,
"max_size": 10
}
},
{
"ordinal": 24,
"name": "maybe_cached_user_ratings_ratio",
"type_info": {
"type": "Float",
"flags": "",
"char_set": 63,
"max_size": 12
}
},
{
"ordinal": 25,
"name": "cached_user_ratings_last_updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 26,
"name": "version",
"type_info": {
"type": "Long",
"flags": "NOT_NULL",
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 27,
"name": "created_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 28,
"name": "updated_at",
"type_info": {
"type": "Timestamp",
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 29,
"name": "user_deleted_at",
"type_info": {
"type": "Timestamp",
"flags": "BINARY",
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 30,
"name": "mod_deleted_at",
"type_info": {
"type": "Timestamp",
"flags": "BINARY",
"char_set": 63,
"max_size": 19
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
false,
false,
false,
true,
true,
false,
false,
false,
true,
false,
false,
false,
false,
true,
true
]
},
"hash": "ec733ae6705dc03fb785e2299c35fcfef23422142735319c8cd091ca8179f97d"
}
Generated
+4 -3
View File
@@ -1914,6 +1914,7 @@ dependencies = [
"serde_derive",
"serde_json",
"sqlx",
"storyteller_root",
"subprocess",
"subprocess_common",
"tempdir",
@@ -2949,9 +2950,9 @@ dependencies = [
[[package]]
name = "infer"
version = "0.11.0"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6c16b11a665b26aeeb9b1d7f954cdeb034be38dd00adab4f2ae921a8fee804"
checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199"
dependencies = [
"cfb 0.7.3",
]
@@ -3564,7 +3565,7 @@ dependencies = [
name = "mimetypes"
version = "0.0.1"
dependencies = [
"infer 0.11.0",
"infer 0.15.0",
"my-workspace-hack",
]
+4 -4
View File
@@ -8,14 +8,14 @@ select
id,
token,
download_type,
title,
download_url,
SUBSTRING(title, 1, 35) as title,
SUBSTRING(download_url, 1, 100) as title,
status,
attempt_count
from generic_download_jobs
where status IN ('started', 'attempt_failed', 'complete_failure', 'dead')
and download_type NOT IN ('vits', 'hifigan')
and created_at > NOW() - INTERVAL 15 DAY;
and created_at > NOW() - INTERVAL 30 DAY;
-- 2) Then restart them
@@ -32,7 +32,7 @@ where token IN (
from generic_download_jobs
where status IN ('started', 'attempt_failed', 'complete_failure', 'dead')
and download_type NOT IN ('vits', 'hifigan')
and created_at > NOW() - INTERVAL 15 DAY
and created_at > NOW() - INTERVAL 30 DAY
) as x
);
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
RENAME COLUMN maybe_cover_image_media_file_token TO maybe_cover_media_file_token;
@@ -0,0 +1,6 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
RENAME COLUMN maybe_cover_media_file_token TO maybe_cover_image_media_file_token;
@@ -0,0 +1,13 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
ADD COLUMN maybe_thumbnail_token VARCHAR(32) DEFAULT NULL
AFTER title;
ALTER TABLE model_weights
ADD COLUMN maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL
AFTER maybe_thumbnail_token;
CREATE INDEX fk_maybe_avatar_media_file_token ON model_weights (maybe_avatar_media_file_token);
@@ -0,0 +1,7 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
-- Drop column
ALTER TABLE model_weights DROP COLUMN maybe_thumbnail_token;
ALTER TABLE model_weights DROP COLUMN maybe_avatar_media_file_token;
@@ -0,0 +1,9 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
CHANGE maybe_description_markdown description_markdown TEXT NOT NULL;
ALTER TABLE model_weights
CHANGE maybe_description_rendered_html description_rendered_html TEXT NOT NULL;
@@ -0,0 +1,9 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
-- noinspection SqlResolveForFile
ALTER TABLE model_weights
CHANGE description_markdown maybe_description_markdown TEXT DEFAULT NULL;
ALTER TABLE model_weights
CHANGE description_rendered_html maybe_description_rendered_html TEXT DEFAULT NULL;
@@ -39,23 +39,19 @@ CREATE TABLE model_weights (
-- The "name" of the model, which might be complicated.
title VARCHAR(255) NOT NULL,
-- TODO(bt, 2023-12-14): Delete the `maybe_thumbnail_token` column later.
-- We're using other columns instead.
maybe_thumbnail_token VARCHAR(32) DEFAULT NULL,
-- The "avatar" image is a media file of type image that serves as a
-- small avatar or profile picture icon.
maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL,
-- The "cover" image is a media file of type image that covers the
-- top of the page.
maybe_cover_media_file_token VARCHAR(32) DEFAULT NULL,
-- The "cover" image is a media file of type image that severs as a small
-- example of the model. Like album art or a user profile picture / avatar.
maybe_cover_image_media_file_token VARCHAR(32) DEFAULT NULL,
-- The description of the model in markdown.
description_markdown TEXT NOT NULL,
-- This is optional, since not all weights are of the same caliber (eg. zero shot models
-- don't deserve a description).
maybe_description_markdown TEXT DEFAULT NULL,
-- Generated HTML (not user-editable).
description_rendered_html TEXT NOT NULL,
-- This is optional, since not all weights are of the same caliber (eg. zero shot
-- models don't deserve a description).
maybe_description_rendered_html TEXT DEFAULT NULL,
-- ========== CREATOR DETAILS ==========
@@ -194,7 +190,6 @@ CREATE TABLE model_weights (
KEY index_weights_category (weights_category),
KEY fk_creator_user_token (creator_user_token),
KEY index_creator_set_visibility (creator_set_visibility),
KEY fk_maybe_avatar_media_file_token (maybe_avatar_media_file_token),
KEY fk_maybe_cover_media_file_token (maybe_cover_media_file_token)
KEY fk_maybe_cover_media_file_token (maybe_cover_image_media_file_token)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
@@ -50,6 +50,7 @@ pub enum UserBookmarkEntityType {
// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests!
impl_enum_display_and_debug_using_to_str!(UserBookmarkEntityType);
impl_mysql_enum_coders!(UserBookmarkEntityType);
impl_mysql_from_row!(UserBookmarkEntityType);
/// NB: Legacy API for older code.
impl UserBookmarkEntityType {
@@ -4,10 +4,11 @@ use serde::Serialize;
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// Used in the `user_ratings` table in a `VARCHAR(32)` field named `entity_type`.
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema)]
pub enum UserRatingEntityType {
/// Media files (inference results, uploads, etc.)
#[serde(rename = "media_file")]
@@ -2,6 +2,7 @@
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
/// UserRatingValue
///
@@ -17,7 +18,7 @@ use strum::EnumIter;
/// *DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY!*
///
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize, sqlx::Type)]
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize, sqlx::Type, ToSchema)]
#[serde(rename_all = "lowercase")]
#[sqlx(rename_all = "lowercase")]
pub enum UserRatingValue {
+1
View File
@@ -3,3 +3,4 @@ pub mod job_status_plus;
pub mod sqlite;
pub mod visibility;
pub mod vocoder_type;
pub mod view_as;
+153
View File
@@ -0,0 +1,153 @@
#[cfg(test)]
use strum::EnumCount;
#[cfg(test)]
use strum::EnumIter;
use utoipa::ToSchema;
#[cfg_attr(test, derive(EnumIter, EnumCount))]
#[derive(Clone, Copy, Eq, PartialEq, Deserialize, Serialize, sqlx::Type,ToSchema)]
#[serde(rename_all = "snake_case")]
#[sqlx(rename_all = "snake_case")]
pub enum ViewAs {
/// Public entities are able to be listed in public lists.
/// It does not mean that they necessarily will be (eg. they could be "mod unapproved" or deleted).
Author,
/// Hidden entities are not shown in public lists, but the URL to them may be given out freely.
/// They are available to non-logged-in users as long as they have the URL.
Moderator,
/// Private entities should only be available to the creator, a list of approved users, and
/// website moderation staff.
AnotherUser,
}
impl_enum_display_and_debug_using_to_str!(ViewAs);
impl_mysql_from_row!(ViewAs);
impl Default for ViewAs {
fn default() -> Self { Self::AnotherUser }
}
/// NB: Legacy API for older code.
impl ViewAs {
pub fn to_str(&self) -> &'static str {
match self {
Self::Author => "author",
Self::Moderator => "moderator",
Self::AnotherUser => "another_user",
}
}
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"author" => Ok(Self::Author),
"moderator" => Ok(Self::Moderator),
"another_user" => Ok(Self::AnotherUser),
_ => Err(format!("invalid value: {:?}", value)),
}
}
}
#[cfg(test)]
mod tests {
use crate::common::view_as::ViewAs;
use crate::test_helpers::assert_serialization;
#[test]
fn test_default() {
assert_eq!(ViewAs::default(), ViewAs::AnotherUser);
}
#[test]
fn test_serialization() {
assert_serialization(ViewAs::Author, "author");
assert_serialization(ViewAs::Moderator, "moderator");
assert_serialization(ViewAs::AnotherUser, "another_user");
}
#[test]
fn test_to_str() {
assert_eq!(ViewAs::Author.to_str(), "author");
assert_eq!(ViewAs::Moderator.to_str(), "moderator");
assert_eq!(ViewAs::AnotherUser.to_str(), "another_user");
}
#[test]
fn test_from_str() {
assert_eq!(ViewAs::from_str("author").unwrap(), ViewAs::Author);
assert_eq!(ViewAs::from_str("moderator").unwrap(), ViewAs::Moderator);
assert_eq!(ViewAs::from_str("another_user").unwrap(), ViewAs::AnotherUser);
assert!(ViewAs::from_str("foo").is_err());
}
mod traits {
use crate::common::view_as::ViewAs;
#[test]
fn display() {
let view_as = ViewAs::Moderator;
assert_eq!(format!("{}", view_as), "moderator".to_string());
}
#[test]
fn debug() {
let view_as = ViewAs::Moderator;
assert_eq!(format!("{:?}", view_as), "moderator".to_string());
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct CompositeType {
view_as: ViewAs,
string: String,
}
mod serde_serialization {
use crate::common::view_as::ViewAs;
use super::CompositeType;
#[test]
fn serialize() {
let expected = "\"author\"".to_string(); // NB: Quoted
assert_eq!(expected, toml::to_string(&ViewAs::Author).unwrap());
// Just to show this serializes the same as a string
assert_eq!(expected, toml::to_string("author").unwrap());
}
#[test]
fn nested_serialize() {
let value = CompositeType { view_as: ViewAs::Moderator, string: "bar".to_string() };
let expected = r#"{"view_as":"moderator","string":"bar"}"#.to_string();
assert_eq!(expected, serde_json::to_string(&value).unwrap());
}
}
mod serde_deserialization {
use crate::common::view_as::ViewAs;
use super::CompositeType;
#[test]
fn deserialize() {
let payload = "\"another_user\""; // NB: Quoted
let value: ViewAs = serde_json::from_str(payload).unwrap();
assert_eq!(value, ViewAs::AnotherUser);
}
#[test]
fn nested_deserialize() {
let payload = r#"{"view_as":"another_user","string":"bar"}"#.to_string();
let expected = CompositeType {
view_as: ViewAs::AnotherUser,
string: "bar".to_string(),
};
assert_eq!(expected, serde_json::from_str::<CompositeType>(&payload).unwrap());
}
}
}
@@ -111,8 +111,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
let mut description_rendered_html;
let mut original_filename;
let mut original_download_url;
let mut thumbnail_token;
let mut private_bucket_hash:String = "".to_string();
let mut private_bucket_prefix;
let mut private_bucket_extension;
@@ -140,9 +139,6 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
original_filename = format!("gura_gwar{}.safetensors", i);
original_download_url = format!("www.google.ca");
// NOTE TO SELF this will be a join for later on for now they can use this.
thumbnail_token = "";
// private_bucket_hash = format!("bucket_hash{}", i);
private_bucket_prefix = format!("_fake");
private_bucket_extension = format!("rvcV2");
@@ -171,9 +167,6 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
original_filename = format!("filename{}.txt", i);
original_download_url = format!("https://civitai.com/api/download/models/149193?type=Model&format=SafeTensor&size=pruned&fp=fp16");
// NOTE TO SELF this will be a join for later on for now they can use this.
thumbnail_token = "";
// private_bucket_hash = format!("bucket_hash{}", i);
private_bucket_prefix = format!("_fake");
private_bucket_extension = format!("tt2");
@@ -197,9 +190,6 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
original_filename = format!("filename{}.txt", i);
original_download_url = format!("https://civitai.com/api/download/models/149193?type=Model&format=SafeTensor&size=pruned&fp=fp16");
// NOTE TO SELF this will be a join for later on for now they can use this.
thumbnail_token = ""; //sd1_5_image_token;
// private_bucket_hash = format!("bucket_hash{}", i);
private_bucket_prefix = format!("_fake");
private_bucket_extension = format!("sd15");
@@ -245,9 +235,6 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
original_filename = format!("filename{}.txt", i);
original_download_url = format!("https://civitai.com/api/download/models/149193?type=Model&format=SafeTensor&size=pruned&fp=fp16");
// NOTE TO SELF this will be a join for later on for now they can use this.
thumbnail_token = "";
cached_user_ratings_total_count = i;
cached_user_ratings_positive_count = i;
cached_user_ratings_negative_count = i;
@@ -273,9 +260,6 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
original_filename = format!("filename{}.txt", i);
original_download_url = format!("https://civitai.com/api/download/models/149193?type=Model&format=SafeTensor&size=pruned&fp=fp16");
// NOTE TO SELF this will be a join for later on for now they can use this.
thumbnail_token = ""; // lora_image_token;
// private_bucket_hash = format!("bucket_hash{}", i);
private_bucket_prefix = format!("_fake");
private_bucket_extension = format!("loRA");
@@ -303,9 +287,6 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
original_filename = format!("gura_gwar{}.safetensors", i);
original_download_url = format!("www.google.ca");
// NOTE TO SELF this will be a join for later on for now they can use this.
thumbnail_token = "";
// private_bucket_hash = format!("bucket_hash{}", i);
private_bucket_prefix = format!("_fake");
private_bucket_extension = format!("rvcV2");
@@ -324,9 +305,8 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
weights_type: weights_types, // replace with actual WeightsType
weights_category, // replace with actual WeightsCategory
title,
maybe_thumbnail_token: Some(thumbnail_token.to_string()),
description_markdown: description,
description_rendered_html: description_rendered_html.to_string(),
maybe_description_markdown: Some(description),
maybe_description_rendered_html: Some(description_rendered_html.to_string()),
creator_user_token: Some(&user_token), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -370,9 +350,8 @@ pub async fn seed_weights_for_user_token(
weights_type: WeightsType::RvcV2, // replace with actual WeightsType
weights_category: WeightsCategory::VoiceConversion, // replace with actual WeightsCategory
title: "Title 1".to_string(),
maybe_thumbnail_token: Some("Thumbnail 1".to_string()),
description_markdown: "Description 1".to_string(),
description_rendered_html: "<p>Description 1</p>".to_string(),
maybe_description_markdown: Some("Description 1".to_string()),
maybe_description_rendered_html: Some("<p>Description 1</p>".to_string()),
creator_user_token: Some(&user_token), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -396,9 +375,8 @@ pub async fn seed_weights_for_user_token(
weights_type: WeightsType::HifiganTacotron2, // replace with actual WeightsType
weights_category: WeightsCategory::TextToSpeech, // replace with actual WeightsCategory
title: "Title 2".to_string(),
maybe_thumbnail_token: Some("Thumbnail 2".to_string()),
description_markdown: "Description 2".to_string(),
description_rendered_html: "<p>Description 2</p>".to_string(),
maybe_description_markdown: Some("Description 2".to_string()),
maybe_description_rendered_html: Some("<p>Description 2</p>".to_string()),
creator_user_token: Some(&user_token), // replace with actual UserToken
creator_ip_address: "292.268.2.2",
creator_set_visibility: Visibility::Public,
@@ -422,9 +400,8 @@ pub async fn seed_weights_for_user_token(
weights_type: WeightsType::StableDiffusion15, // replace with actual WeightsType
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
title: "Title 3".to_string(),
maybe_thumbnail_token: Some("Thumbnail 3".to_string()),
description_markdown: "Description 3".to_string(),
description_rendered_html: "<p>Description 3</p>".to_string(),
maybe_description_markdown: Some("Description 3".to_string()),
maybe_description_rendered_html: Some("<p>Description 3</p>".to_string()),
creator_user_token: Some(&user_token), // replace with actual UserToken
creator_ip_address: "392.368.3.3",
creator_set_visibility: Visibility::Public,
@@ -448,9 +425,8 @@ pub async fn seed_weights_for_user_token(
weights_type: WeightsType::LoRA, // replace with actual WeightsType
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
title: "Title 4".to_string(),
maybe_thumbnail_token: Some("Thumbnail 4".to_string()),
description_markdown: "Description 4".to_string(),
description_rendered_html: "<p>Description 4</p>".to_string(),
maybe_description_markdown: Some("Description 4".to_string()),
maybe_description_rendered_html: Some("<p>Description 4</p>".to_string()),
creator_user_token: Some(&user_token), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -474,9 +450,8 @@ pub async fn seed_weights_for_user_token(
weights_type: WeightsType::LoRA, // replace with actual WeightsType
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
title: "Title 5".to_string(),
maybe_thumbnail_token: Some("Thumbnail 4".to_string()),
description_markdown: "Description 4".to_string(),
description_rendered_html: "<p>Description 4</p>".to_string(),
maybe_description_markdown: Some("Description 4".to_string()),
maybe_description_rendered_html: Some("<p>Description 4</p>".to_string()),
creator_user_token: Some(&user_token), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -526,9 +501,8 @@ pub async fn original_seed_weights(mysql_pool: &Pool<MySql>,user_token: UserToke
weights_type: WeightsType::RvcV2, // replace with actual WeightsType
weights_category: WeightsCategory::VoiceConversion, // replace with actual WeightsCategory
title: "Title 1".to_string(),
maybe_thumbnail_token: Some("Thumbnail 1".to_string()),
description_markdown: "Description 1".to_string(),
description_rendered_html: "<p>Description 1</p>".to_string(),
maybe_description_markdown: Some("Description 1".to_string()),
maybe_description_rendered_html: Some("<p>Description 1</p>".to_string()),
creator_user_token: Some(&creator_token1), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -552,9 +526,8 @@ pub async fn original_seed_weights(mysql_pool: &Pool<MySql>,user_token: UserToke
weights_type: WeightsType::HifiganTacotron2, // replace with actual WeightsType
weights_category: WeightsCategory::TextToSpeech, // replace with actual WeightsCategory
title: "Title 2".to_string(),
maybe_thumbnail_token: Some("Thumbnail 2".to_string()),
description_markdown: "Description 2".to_string(),
description_rendered_html: "<p>Description 2</p>".to_string(),
maybe_description_markdown: Some("Description 2".to_string()),
maybe_description_rendered_html: Some("<p>Description 2</p>".to_string()),
creator_user_token: Some(&creator_token2), // replace with actual UserToken
creator_ip_address: "292.268.2.2",
creator_set_visibility: Visibility::Public,
@@ -578,9 +551,8 @@ pub async fn original_seed_weights(mysql_pool: &Pool<MySql>,user_token: UserToke
weights_type: WeightsType::StableDiffusion15, // replace with actual WeightsType
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
title: "Title 3".to_string(),
maybe_thumbnail_token: Some("Thumbnail 3".to_string()),
description_markdown: "Description 3".to_string(),
description_rendered_html: "<p>Description 3</p>".to_string(),
maybe_description_markdown: Some("Description 3".to_string()),
maybe_description_rendered_html: Some("<p>Description 3</p>".to_string()),
creator_user_token: Some(&creator_token3), // replace with actual UserToken
creator_ip_address: "392.368.3.3",
creator_set_visibility: Visibility::Public,
@@ -604,9 +576,8 @@ pub async fn original_seed_weights(mysql_pool: &Pool<MySql>,user_token: UserToke
weights_type: WeightsType::LoRA, // replace with actual WeightsType
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
title: "Title 4".to_string(),
maybe_thumbnail_token: Some("Thumbnail 4".to_string()),
description_markdown: "Description 4".to_string(),
description_rendered_html: "<p>Description 4</p>".to_string(),
maybe_description_markdown: Some("Description 4".to_string()),
maybe_description_rendered_html: Some("<p>Description 4</p>".to_string()),
creator_user_token: Some(&creator_token4), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -630,9 +601,8 @@ pub async fn original_seed_weights(mysql_pool: &Pool<MySql>,user_token: UserToke
weights_type: WeightsType::LoRA, // replace with actual WeightsType
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
title: "Title 5".to_string(),
maybe_thumbnail_token: Some("Thumbnail 5".to_string()),
description_markdown: "Description 5".to_string(),
description_rendered_html: "<p>Description 5</p>".to_string(),
maybe_description_markdown: Some("Description 5".to_string()),
maybe_description_rendered_html: Some("<p>Description 5</p>".to_string()),
creator_user_token: Some(&creator_token5), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -92,7 +92,6 @@ pub async fn seed_weights_files(
let description_rendered_html = "This is a description rendered html";
let original_filename = "model.safetensors";
let original_download_url = "https://example.com/model.safetensors";
let thumbnail_token = format!("{}", n);
// let public_bucket_hash: String = weights_file_token.to_string();
// let public_bucket_prefix = weights_type.to_string();
@@ -130,9 +129,8 @@ pub async fn seed_weights_files(
weights_type, // Assuming weights_type is defined elsewhere
weights_category, // Assuming weights_category is defined elsewhere
title: title.to_string(),
maybe_thumbnail_token: Some(thumbnail_token),
description_markdown: description.to_string(),
description_rendered_html: description_rendered_html.to_string(),
maybe_description_markdown: Some(description.to_string()),
maybe_description_rendered_html: Some(description_rendered_html.to_string()),
creator_user_token: Some(&user_token),
creator_ip_address: "127.0.0.1", // Assuming the IP address is localhost
creator_set_visibility: Visibility::Public, // Assuming the visibility is public
@@ -114,7 +114,7 @@ impl BucketClient {
if code != 200 {
let body = String::from_utf8_lossy(body_bytes);
warn!("upload body: {}", body);
return Err(anyhow!("upload failed: {}", code));
Err(anyhow!("upload failed: {}", code))
} else {
info!("upload success: {}", code);
Ok(())
@@ -5,7 +5,6 @@ use async_trait::async_trait;
use errors::AnyhowResult;
use crate::bucket_client::BucketClient;
use crate::remote_file_manager::file_meta_data::FileMetaData;
#[async_trait]
pub trait BucketOrchestrationCore {
@@ -85,11 +84,11 @@ impl BucketOrchestration {
public_bucket_name: String,
private_bucket_name: String) -> Self {
Self {
access_key: access_key,
secret_key: secret_key,
region_name: region_name,
public_bucket_name: public_bucket_name,
private_bucket_name: private_bucket_name,
access_key,
secret_key,
region_name,
public_bucket_name,
private_bucket_name,
}
}
@@ -7,18 +7,18 @@ const REMOTE_FILE_DIRECTORY: &str = "/implement_google_cloud_storage_bucket_name
pub trait FileDescriptor {
// By default a file belongs in the public bucket will help us figureout which bucket to use.
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file
// e.g requires! a period .safetensors .bin .jpg
fn get_suffix(&self)->String {
return "implement".to_string();
"implement".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "implement".to_string();
"implement".to_string()
}
// This will be ensure that the right bucket is picked
@@ -32,10 +32,10 @@ pub struct FileBucketDirectory {
let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name);
Self {
file_object_hash: entropy.to_string(),
remote_cloud_base_directory: remote_cloud_base_directory,
full_remote_cloud_file_path: full_remote_cloud_file_path,
file_name:file_name,
file_descriptor:file_descriptor
remote_cloud_base_directory,
full_remote_cloud_file_path,
file_name,
file_descriptor
}
}
@@ -53,10 +53,10 @@ pub struct FileBucketDirectory {
let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name);
Self {
file_object_hash: entropy,
remote_cloud_base_directory: remote_cloud_base_directory,
full_remote_cloud_file_path: full_remote_cloud_file_path,
file_name:file_name,
file_descriptor:file_descriptor
remote_cloud_base_directory,
full_remote_cloud_file_path,
file_name,
file_descriptor
}
}
@@ -1,7 +1,6 @@
use crate::remote_file_manager::weights_descriptor::{self};
use super::file_descriptor::FileDescriptor;
use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor, self};
pub struct RemoteCloudBucketDetails {
pub object_hash: String,
@@ -12,9 +11,9 @@ pub struct RemoteCloudBucketDetails {
impl RemoteCloudBucketDetails {
pub fn new(object_hash: String, prefix: String, suffix: String) -> Self {
Self {
object_hash: object_hash,
prefix: prefix,
suffix: suffix
object_hash,
prefix,
suffix
}
}
pub fn get_object_hash(&self) -> &str {
@@ -49,7 +48,6 @@ impl RemoteCloudBucketDetails {
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test() {
@@ -1,21 +1,15 @@
use crate::remote_file_manager::file_directory::FileBucketDirectory;
use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails;
use super::bucket_orchestration;
use super::file_descriptor::{FileDescriptor};
use super::file_meta_data::FileMetaData;
use errors:: AnyhowResult;
use errors::AnyhowResult;
use filesys::file_read_bytes::file_read_bytes;
use filesys::file_size::file_size;
use hashing::sha256::sha256_hash_file::sha256_hash_file;
use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes;
use crate::remote_file_manager::bucket_orchestration::{BucketOrchestrationCore};
use crate::remote_file_manager::bucket_orchestration::BucketOrchestrationCore;
use crate::remote_file_manager::file_directory::FileBucketDirectory;
use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails;
use super::file_descriptor::FileDescriptor;
use super::file_meta_data::FileMetaData;
struct RemoteCloudFileClient {
bucket_orchestration_client: Box<dyn BucketOrchestrationCore>
@@ -24,7 +18,7 @@ struct RemoteCloudFileClient {
impl RemoteCloudFileClient {
pub fn new(bucket_orchestration_client: Box<dyn BucketOrchestrationCore>) -> Self {
Self {
bucket_orchestration_client: bucket_orchestration_client
bucket_orchestration_client
}
}
@@ -73,8 +67,8 @@ impl RemoteCloudFileClient {
let mimetype: &str = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream");
Ok(FileMetaData {
file_size_bytes: file_size_bytes,
sha256_checksum: sha256_checksum,
file_size_bytes,
sha256_checksum,
mimetype: mimetype.to_string()
})
}
@@ -85,8 +79,9 @@ mod tests {
use async_trait::async_trait;
use env_logger;
use errors::AnyhowResult;
use crate::remote_file_manager::bucket_orchestration::BucketOrchestrationCore;
use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor};
use crate::remote_file_manager::weights_descriptor::WeightsLoRADescriptor;
struct BucketOrchestrationMock {}
@@ -127,7 +122,6 @@ mod tests {
}
#[tokio::test]
async fn remote_file_manager_descriptor_test() {
use super::*;
let remote_cloud_bucket_details = RemoteCloudBucketDetails::new("object_hash".to_string(), "loRA".to_string(), "safetensors".to_string());
@@ -138,6 +132,8 @@ mod tests {
assert_eq!(file_descriptor.is_public(), true);
}
#[ignore]
#[tokio::test]
async fn remote_file_manager_download_existing_file() {
use super::*;
@@ -1,23 +1,23 @@
use super::file_descriptor::FileDescriptor;
pub struct WeightsLoRADescriptor {}
pub struct WeightsLoRADescriptor;
const REMOTE_FILE_DIRECTORY: &str = "/weights";
impl FileDescriptor for WeightsLoRADescriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "safetensors".to_string();
"safetensors".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "loRA".to_string();
"loRA".to_string()
}
// This will be ensure that the right bucket is picked
@@ -26,22 +26,22 @@ impl FileDescriptor for WeightsLoRADescriptor {
}
}
pub struct WeightsSD15Descriptor {}
pub struct WeightsSD15Descriptor;
impl FileDescriptor for WeightsSD15Descriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "safetensors".to_string();
"safetensors".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "sd15".to_string();
"sd15".to_string()
}
// This will be ensure that the right bucket is picked
@@ -51,22 +51,22 @@ impl FileDescriptor for WeightsSD15Descriptor {
}
pub struct WeightsSDXLDescriptor {}
pub struct WeightsSDXLDescriptor;
impl FileDescriptor for WeightsSDXLDescriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "safetensors".to_string();
"safetensors".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "sdxl".to_string();
"sdxl".to_string()
}
// This will be ensure that the right bucket is picked
@@ -75,22 +75,22 @@ impl FileDescriptor for WeightsSDXLDescriptor {
}
}
pub struct WeightsSVCDescriptor {}
pub struct WeightsSVCDescriptor;
impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsSVCDescriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "safetensors".to_string();
"safetensors".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "svc".to_string();
"svc".to_string()
}
// This will be ensure that the right bucket is picked
@@ -99,22 +99,22 @@ impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsS
}
}
pub struct WeightsRVCDescriptor {}
pub struct WeightsRVCDescriptor;
impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsRVCDescriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "pth".to_string();
"pth".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "rvc".to_string();
"rvc".to_string()
}
// This will be ensure that the right bucket is picked
@@ -123,22 +123,22 @@ impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsR
}
}
pub struct WeightsRVCIndexDescriptor {}
pub struct WeightsRVCIndexDescriptor;
impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsRVCIndexDescriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "index".to_string();
"index".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "rvc".to_string();
"rvc".to_string()
}
// This will be ensure that the right bucket is picked
@@ -147,22 +147,22 @@ impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsR
}
}
pub struct WeightsVallePromptDescriptor {}
pub struct WeightsVallePromptDescriptor;
impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsVallePromptDescriptor {
fn remote_directory_path(&self) -> &str {
return REMOTE_FILE_DIRECTORY;
REMOTE_FILE_DIRECTORY
}
// this will be the type of file peroid is handled by the file formatter
// e.g safetensors bin jpg
fn get_suffix(&self)->String {
return "safetensors".to_string();
"safetensors".to_string()
}
// This will be the prefix of the media type or the weights type.
// name of the weights or the name of the media type
// vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end
fn get_prefix(&self)->String {
return "valle_prompt".to_string();
"valle_prompt".to_string()
}
// This will be ensure that the right bucket is picked
@@ -73,7 +73,7 @@ impl GoogleDriveDownloadCommand {
info!("Downloading {} to: {}", download_url, temp_filename);
let mut command = format!("{} --url {} --output_filename {}",
let mut command = format!("{} --url \"{}\" --output_filename {}",
&self.download_script,
download_url,
&temp_filename);
@@ -10,6 +10,14 @@ pub fn is_bad_download_url(url: &str) -> anyhow::Result<bool> {
return Ok(true);
}
let looks_malicious = url.contains("\"")
|| url.contains("\'")
|| url.contains("\\");
if looks_malicious {
return Ok(true);
}
let url = Url::parse(url)?;
match url.host() {
@@ -23,6 +31,8 @@ pub fn is_bad_download_url(url: &str) -> anyhow::Result<bool> {
|| domain.contains("youtu.be")
|| domain.contains("youtube.com");
println!("domain: {:?}", domain);
if bad_host {
return Ok(true)
}
@@ -39,15 +49,31 @@ mod tests {
#[test]
fn bad_download_url() {
assert_eq!(is_bad_download_url("").unwrap(), true);
assert_eq!(is_bad_download_url(" ").unwrap(), true);
assert_eq!(is_bad_download_url("https://vm.tiktok.com/ZMNYjT7Xy/?k=1 ").unwrap(), true); // NB: We get lots of these
assert_eq!(is_bad_download_url("https://m.youtube.com/watch?v=HY-vzGBiAZo").unwrap(), true); // NB: We get lots of these
assert_eq!(true, is_bad_download_url("").unwrap());
assert_eq!(true, is_bad_download_url(" ").unwrap());
assert_eq!(true, is_bad_download_url("https://vm.tiktok.com/ZMNYjT7Xy/?k=1 ").unwrap()); // NB: We get lots of these
assert_eq!(true, is_bad_download_url("https://m.youtube.com/watch?v=HY-vzGBiAZo").unwrap()); // NB: We get lots of these
}
#[test]
fn attacker_urls() {
// NB: These URLs may break escaping
assert_eq!(true, is_bad_download_url("https://huggingface.co/\"").unwrap());
assert_eq!(true, is_bad_download_url("https://huggingface.co/\"/bin/bash").unwrap());
assert_eq!(true, is_bad_download_url("https://huggingface.co/\\\'").unwrap());
assert_eq!(true, is_bad_download_url("https://huggingface.co/\\\"").unwrap());
}
#[test]
fn good_tts_model_url() {
assert_eq!(is_bad_download_url("https://drive.google.com/file/d/1-1kEoX4HGCwJm4R9cZhSVByWmUoQVGVm/view").unwrap(), false);
assert_eq!(is_bad_download_url("https://drive.google.com/file/d/1SofQhvSkDY-vi_zuBfHivBbJo4CqhJeH/view?usp=sharing").unwrap(), false);
assert_eq!(false, is_bad_download_url("https://drive.google.com/file/d/1-1kEoX4HGCwJm4R9cZhSVByWmUoQVGVm/view").unwrap());
assert_eq!(false, is_bad_download_url("https://drive.google.com/file/d/1SofQhvSkDY-vi_zuBfHivBbJo4CqhJeH/view?usp=sharing").unwrap());
}
#[test]
fn tricky_download_urls() {
// NB: These are URLs that have caused problems
assert_eq!(false, is_bad_download_url("https://huggingface.co/aaalby/nmixx/resolve/main/kyujin(1).zip").unwrap());
assert_eq!(false, is_bad_download_url("https://huggingface.co/datasets/Roscall/Elvis70s/resolve/main/Elvis%2070s%20RVC.zip?download=true").unwrap());
}
}
@@ -1 +1,2 @@
pub mod tts_model_document;
pub mod tts_model_document;
mod model_weight_document;
@@ -0,0 +1,65 @@
use std::path::PathBuf;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use enums::by_table::model_weights::weights_category::WeightsCategory;
use enums::by_table::model_weights::weights_types::WeightsType;
use enums::common::visibility::Visibility;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::model_weights::ModelWeightToken;
use tokens::tokens::users::UserToken;
use crate::traits::document::Document;
/// The current name for the index.
/// We may need to perform migrations in the future
pub const MODEL_WEIGHT_INDEX: &str = "model_weights_v1";
#[derive(Serialize, Deserialize, Debug)]
pub struct ModelWeightDocument {
pub token: ModelWeightToken,
pub creator_set_visibility: Visibility,
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub title: String,
pub maybe_cover_image_media_file_token: Option<MediaFileToken>,
pub maybe_cover_image_media_bucket_path: Option<String>,
//pub description_markdown: String,
//pub description_markdown_html: String,
// TODO(bt,2023-12-22): Populate these fields
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
pub cached_user_ratings_ratio: f32,
pub cached_user_ratings_last_updated_at: DateTime<Utc>,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
pub creator_gravatar_hash: String,
// Fields only used for TTS models and voice conversion models.
pub maybe_ietf_language_tag: Option<String>,
pub maybe_ietf_primary_language_subtag: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl Document for ModelWeightDocument {
fn get_document_id(&self) -> String {
self.token.to_string()
}
fn get_document_path(&self) -> PathBuf {
let document_id = self.get_document_id();
PathBuf::from(format!("/{MODEL_WEIGHT_INDEX}/_doc/{document_id}"))
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ path = "src/lib.rs"
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
# External
infer = "0.11" # Mimetype detection
infer = "0.15.0" # Mimetype detection
[dev-dependencies]
@@ -4,16 +4,23 @@
pub fn mimetype_to_extension(mimetype: &str) -> Option<&'static str> {
// TODO(bt,2023-11-17): maybe make a bidirectional map
match mimetype {
// Image
"image/gif" => Some("gif"),
"image/jpeg" => Some("jpg"),
"image/png" => Some("png"),
"image/webp" => Some("webp"),
// Audio
"audio/aac" => Some("aac"),
"audio/m4a" => Some("m4a"),
"audio/mpeg" => Some("mp3"),
"audio/ogg" => Some("ogg"),
"audio/opus" => Some("opus"),
"audio/x-flac" => Some("flac"),
"audio/wav" => Some("wav"),
"audio/x-flac" => Some("flac"),
"audio/x-wav" => Some("wav"),
// Video
"video/mp4" /* .mp4 */ => Some("mp4"),
"video/quicktime" /* .mov */ => Some("mov"),
"video/webm" => Some("webm"), // TODO: Browsers send this for audio?
_ => None
}
@@ -35,5 +42,8 @@ mod test {
assert_eq!(mimetype_to_extension("audio/mpeg"), Some("mp3"));
assert_eq!(mimetype_to_extension("audio/wav"), Some("wav"));
assert_eq!(mimetype_to_extension("audio/x-wav"), Some("wav"));
assert_eq!(mimetype_to_extension("image/png"), Some("png"));
assert_eq!(mimetype_to_extension("image/jpeg"), Some("jpg"));
assert_eq!(mimetype_to_extension("video/mp4"), Some("mp4"));
}
}
@@ -6,6 +6,7 @@ use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCat
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::common::view_as::ViewAs;
use enums::common::visibility::Visibility;
use enums::traits::mysql_from_row::MySqlFromRow;
use errors::AnyhowResult;
@@ -51,17 +52,12 @@ pub struct MediaFileListItem {
pub updated_at: DateTime<Utc>,
}
#[derive(Clone, Copy)]
pub enum ViewAs {
Moderator,
NonModerator,
}
pub struct ListMediaFilesArgs<'a> {
pub limit: usize,
pub maybe_filter_media_type: Option<MediaFileType>,
pub maybe_offset: Option<usize>,
pub cursor_is_reversed: bool,
pub sort_ascending: bool,
pub view_as: ViewAs,
pub mysql_pool: &'a MySqlPool,
}
@@ -73,6 +69,7 @@ pub async fn list_media_files(args: ListMediaFilesArgs<'_>) -> AnyhowResult<Medi
args.limit,
args.maybe_offset,
args.cursor_is_reversed,
args.sort_ascending,
args.view_as,
);
@@ -124,9 +121,11 @@ fn query_builder<'a>(
limit: usize,
maybe_offset: Option<usize>,
cursor_is_reversed: bool,
sort_ascending: bool,
view_as: ViewAs,
) -> QueryBuilder<'a, MySql> {
let mut sort_ascending = sort_ascending;
// NB: Query cannot be statically checked by sqlx
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
r#"
@@ -166,23 +165,35 @@ LEFT OUTER JOIN favorites as f
ON f.entity_type = 'media_file' AND f.entity_token = m.token
LEFT OUTER JOIN comments as c
ON c.entity_type = 'media_file' AND c.entity_token = c.token
WHERE
m.user_deleted_at IS NULL
AND m.mod_deleted_at IS NULL
"#
);
let mut first_predicate_added = false;
if let Some(media_type) = maybe_filter_media_type {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
// FIXME: Binding shouldn't require to_str().
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
// incorrect binding and runtime error.
query_builder.push(" AND m.media_file_type = ");
query_builder.push(" m.media_type = ");
query_builder.push_bind(media_type.to_str());
}
match view_as {
ViewAs::Moderator => {}
ViewAs::NonModerator=> {
ViewAs::Author | ViewAs::AnotherUser => {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
query_builder.push(" m.user_deleted_at IS NULL AND m.mod_deleted_at IS NULL ");
// FIXME: Binding shouldn't require to_str().
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
// incorrect binding and runtime error.
@@ -192,17 +203,36 @@ WHERE
}
if let Some(offset) = maybe_offset {
if cursor_is_reversed {
query_builder.push(format!(" AND m.id < {offset} "));
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(format!(" AND m.id > {offset} "));
query_builder.push(" AND ");
}
}
if sort_ascending {
if cursor_is_reversed {
// NB: We're searching backwards.
query_builder.push(" AND m.id < ");
sort_ascending = !sort_ascending;
} else {
query_builder.push(" AND m.id > ");
}
} else {
if cursor_is_reversed {
// NB: We're searching backwards.
query_builder.push(" AND m.id > ");
sort_ascending = !sort_ascending;
} else {
query_builder.push(" AND m.id < ");
}
}
query_builder.push_bind(offset as i64);
}
query_builder.push(" GROUP BY m.id");
if cursor_is_reversed {
if sort_ascending {
query_builder.push(" ORDER BY m.id ASC ");
} else {
query_builder.push(" ORDER BY m.id DESC ");
@@ -6,6 +6,7 @@ use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCat
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::common::view_as::ViewAs;
use enums::common::visibility::Visibility;
use enums::traits::mysql_from_row::MySqlFromRow;
use errors::AnyhowResult;
@@ -39,12 +40,6 @@ pub struct MediaFileListItem {
pub updated_at: DateTime<Utc>,
}
#[derive(Clone, Copy)]
pub enum ViewAs {
Author,
Moderator,
AnotherUser,
}
pub struct ListMediaFileForUserArgs<'a> {
pub username: &'a str,
@@ -168,27 +163,27 @@ SELECT
FROM media_files AS m
LEFT OUTER JOIN users AS u
ON m.maybe_creator_user_token = u.token
WHERE m.user_deleted_at IS NULL
AND m.mod_deleted_at IS NULL
"#
));
query_builder.push(" AND u.username = ");
query_builder.push(" WHERE u.username = ");
query_builder.push_bind(username);
if let Some(media_type) = maybe_filter_media_type {
// FIXME: Binding shouldn't require to_str().
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
// incorrect binding and runtime error.
query_builder.push(" AND m.media_file_type = ");
query_builder.push(" AND m.media_type = ");
query_builder.push_bind(media_type.to_str());
}
match view_as {
ViewAs::Author => {}
ViewAs::Author => {
query_builder.push(" AND m.user_deleted_at IS NULL AND m.mod_deleted_at IS NULL ");
}
ViewAs::Moderator => {}
ViewAs::AnotherUser => {
query_builder.push(" AND m.user_deleted_at IS NULL AND m.mod_deleted_at IS NULL ");
// FIXME: Binding shouldn't require to_str().
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
// incorrect binding and runtime error.
@@ -63,11 +63,9 @@ SET
weights_category = ?,
title = ?,
maybe_thumbnail_token = NULL,
maybe_avatar_media_file_token = NULL,
maybe_cover_media_file_token = NULL,
description_markdown = NULL,
description_rendered_html = NULL,
maybe_cover_image_media_file_token = NULL,
maybe_description_markdown = NULL,
maybe_description_rendered_html = NULL,
maybe_last_update_user_token = NULL,
original_download_url = ?,
@@ -13,9 +13,8 @@ pub struct CreateModelWeightsArgs<'a> {
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
pub creator_user_token: Option<&'a UserToken>,
pub creator_ip_address: &'a str,
pub creator_set_visibility: Visibility,
@@ -47,9 +46,8 @@ pub async fn create_weight(args: CreateModelWeightsArgs<'_>) -> AnyhowResult<Mod
weights_type = ?,
weights_category = ?,
title = ?,
maybe_thumbnail_token = ?,
description_markdown = ?,
description_rendered_html = ?,
maybe_description_markdown = ?,
maybe_description_rendered_html = ?,
creator_user_token = ?,
creator_ip_address = ?,
creator_set_visibility = ?,
@@ -71,9 +69,8 @@ pub async fn create_weight(args: CreateModelWeightsArgs<'_>) -> AnyhowResult<Mod
args.weights_type.to_str(),
args.weights_category.to_str(),
args.title,
args.maybe_thumbnail_token,
args.description_markdown,
args.description_rendered_html,
args.maybe_description_markdown,
args.maybe_description_rendered_html,
args.creator_user_token.as_deref(),
args.creator_ip_address,
args.creator_set_visibility.to_str(),
@@ -1,2 +1,2 @@
pub mod set_model_weight_avatar;
pub mod set_model_weight_cover_image;
pub mod update_weight;
@@ -6,23 +6,23 @@ use tokens::tokens::model_weights::ModelWeightToken;
pub struct UpdateArgs<'a> {
pub model_weight_token: &'a ModelWeightToken,
pub maybe_avatar_media_file_token: Option<&'a MediaFileToken>,
pub maybe_cover_image_media_file_token: Option<&'a MediaFileToken>,
//pub update_ip_address: &'a str,
pub mysql_pool: &'a MySqlPool
}
pub async fn set_model_weight_avatar(args: UpdateArgs<'_>) -> AnyhowResult<()>{
pub async fn set_model_weight_cover_image(args: UpdateArgs<'_>) -> AnyhowResult<()>{
let transaction = args.mysql_pool.begin().await?;
let query_result = sqlx::query!(
r#"
UPDATE model_weights
SET
maybe_avatar_media_file_token = ?
maybe_cover_image_media_file_token = ?
WHERE token = ?
LIMIT 1
"#,
args.maybe_avatar_media_file_token,
args.maybe_cover_image_media_file_token,
args.model_weight_token,
).execute(args.mysql_pool).await;
@@ -1,5 +1,5 @@
use anyhow::anyhow;
use sqlx::MySqlPool;
use sqlx::{MySql, MySqlPool, QueryBuilder};
use enums::common::visibility::Visibility;
use errors::AnyhowResult;
@@ -8,9 +8,8 @@ use tokens::tokens::model_weights::ModelWeightToken;
pub struct UpdateWeightArgs<'a> {
pub weight_token: &'a ModelWeightToken,
pub title: Option<&'a str>,
pub maybe_thumbnail_token: Option<&'a str>,
pub description_markdown: Option<&'a str>,
pub description_rendered_html: Option<&'a str>,
pub maybe_description_markdown: Option<&'a str>,
pub maybe_description_rendered_html: Option<&'a str>,
pub creator_set_visibility: Option<&'a Visibility>,
pub weights_type: Option<String>,
pub weights_category: Option<String>,
@@ -18,36 +17,63 @@ pub struct UpdateWeightArgs<'a> {
}
pub async fn update_weights(args: UpdateWeightArgs<'_>) -> AnyhowResult<()> {
let transaction = args.mysql_pool.begin().await?;
if args.title.is_none()
&& args.maybe_description_markdown.is_none()
&& args.maybe_description_rendered_html.is_none()
&& args.creator_set_visibility.is_none()
&& args.weights_type.is_none()
&& args.weights_category.is_none(){
return Err(anyhow!("No fields to update"));
}
let query_result = sqlx::query!(
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
r#"
UPDATE model_weights
SET
title = COALESCE(?, title),
description_markdown = COALESCE(?, description_markdown),
maybe_thumbnail_token = COALESCE(?, maybe_thumbnail_token),
description_rendered_html = COALESCE(?, description_rendered_html),
creator_set_visibility = COALESCE(?, creator_set_visibility),
version = version + 1
WHERE token = ?
"#,
args.title.as_deref(),
args.description_markdown.as_deref(),
args.maybe_thumbnail_token.as_deref(),
args.description_rendered_html.as_deref(),
args.creator_set_visibility.as_deref(),
args.weight_token.as_str()
)
.execute(args.mysql_pool).await;
UPDATE model_weights
SET
"#
);
let mut separated = query_builder.separated(", ");
if let Some(title) = args.title {
separated.push("title = ");
separated.push_bind_unseparated(title);
}
if let Some(maybe_description_markdown) = args.maybe_description_markdown {
separated.push("maybe_description_markdown = ");
separated.push_bind_unseparated(maybe_description_markdown);
}
if let Some(maybe_description_rendered_html) = args.maybe_description_rendered_html {
separated.push("maybe_description_rendered_html = ");
separated.push_bind_unseparated(maybe_description_rendered_html);
}
if let Some(creator_set_visibility) = args.creator_set_visibility {
separated.push("creator_set_visibility = ");
separated.push_bind_unseparated(creator_set_visibility.to_str());
}
if let Some(weights_type) = args.weights_type {
separated.push("weights_type = ");
separated.push_bind_unseparated(weights_type);
}
if let Some(weights_category) = args.weights_category {
separated.push("weights_category = ");
separated.push_bind_unseparated(weights_category);
}
separated.push("version = version + 1");
separated.push_unseparated(" WHERE token = ");
separated.push_bind_unseparated(args.weight_token.as_str());
separated.push_unseparated(" LIMIT 1");
let transaction = args.mysql_pool.begin().await?;
let query_result = query_builder.build().execute(args.mysql_pool).await;
transaction.commit().await?;
match query_result {
Ok(_) => Ok(()),
Err(err) => {
Err(anyhow!("weights update error: {:?}", err))
Err(anyhow!("weights update error: {:?}", err))
}
}
}
@@ -62,6 +88,7 @@ mod tests {
use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING;
use errors::AnyhowResult;
#[ignore]
#[tokio::test]
async fn test_update_weights() -> AnyhowResult<()> {
let db_connection_string = DEFAULT_MYSQL_CONNECTION_STRING;
@@ -19,9 +19,8 @@ pub struct RetrievedModelWeight {
pub title: String,
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
@@ -40,9 +39,9 @@ pub struct RetrievedModelWeight {
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_avatar_public_bucket_hash: Option<String>,
pub maybe_avatar_public_bucket_prefix: Option<String>,
pub maybe_avatar_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_negative_count: u32,
pub cached_user_ratings_positive_count: u32,
@@ -95,9 +94,8 @@ pub async fn get_weights_by_token_with_connection(
title: record.title,
weights_type: record.weights_type,
weights_category: record.weights_category,
maybe_thumbnail_token: record.maybe_thumbnail_token,
description_markdown: record.description_markdown,
description_rendered_html: record.description_rendered_html,
maybe_description_markdown: record.maybe_description_markdown,
maybe_description_rendered_html: record.maybe_description_rendered_html,
creator_user_token: record.creator_user_token,
creator_username: record.creator_username,
creator_display_name: record.creator_display_name,
@@ -112,9 +110,9 @@ pub async fn get_weights_by_token_with_connection(
public_bucket_hash: record.public_bucket_hash,
maybe_public_bucket_prefix: record.maybe_public_bucket_prefix,
maybe_public_bucket_extension: record.maybe_public_bucket_extension,
maybe_avatar_public_bucket_hash: record.maybe_avatar_public_bucket_hash,
maybe_avatar_public_bucket_prefix: record.maybe_avatar_public_bucket_prefix,
maybe_avatar_public_bucket_extension: record.maybe_avatar_public_bucket_extension,
maybe_cover_image_public_bucket_hash: record.maybe_cover_image_public_bucket_hash,
maybe_cover_image_public_bucket_prefix: record.maybe_cover_image_public_bucket_prefix,
maybe_cover_image_public_bucket_extension: record.maybe_cover_image_public_bucket_extension,
cached_user_ratings_negative_count: record.cached_user_ratings_negative_count,
cached_user_ratings_positive_count: record.cached_user_ratings_positive_count,
cached_user_ratings_total_count: record.cached_user_ratings_total_count,
@@ -142,9 +140,8 @@ async fn select_include_deleted(
wt.title,
wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,
wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,
wt.maybe_thumbnail_token,
wt.description_markdown,
wt.description_rendered_html,
wt.maybe_description_markdown,
wt.maybe_description_rendered_html,
wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,
users.username as creator_username,
@@ -158,13 +155,14 @@ async fn select_include_deleted(
wt.original_filename,
wt.file_size_bytes,
wt.file_checksum_sha2,
wt.public_bucket_hash,
wt.maybe_public_bucket_prefix,
wt.maybe_public_bucket_extension,
avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,
avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,
avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,
wt.cached_user_ratings_negative_count,
wt.cached_user_ratings_positive_count,
@@ -179,8 +177,8 @@ async fn select_include_deleted(
FROM model_weights as wt
JOIN users
ON users.token = wt.creator_user_token
LEFT OUTER JOIN media_files as avatar
ON avatar.token = wt.maybe_avatar_media_file_token
LEFT OUTER JOIN media_files as cover_image
ON cover_image.token = wt.maybe_cover_image_media_file_token
WHERE
wt.token = ?
"#,
@@ -204,9 +202,8 @@ async fn select_without_deleted(
wt.title,
wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,
wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,
wt.maybe_thumbnail_token,
wt.description_markdown,
wt.description_rendered_html,
wt.maybe_description_markdown,
wt.maybe_description_rendered_html,
wt.creator_ip_address,
wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,
@@ -224,9 +221,9 @@ async fn select_without_deleted(
wt.maybe_public_bucket_prefix,
wt.maybe_public_bucket_extension,
avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,
avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,
avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,
wt.cached_user_ratings_negative_count,
wt.cached_user_ratings_positive_count,
@@ -241,8 +238,8 @@ async fn select_without_deleted(
FROM model_weights as wt
JOIN users
ON users.token = wt.creator_user_token
LEFT OUTER JOIN media_files as avatar
ON avatar.token = wt.maybe_avatar_media_file_token
LEFT OUTER JOIN media_files as cover_image
ON cover_image.token = wt.maybe_cover_image_media_file_token
WHERE
wt.token = ?
AND wt.user_deleted_at IS NULL
@@ -260,9 +257,8 @@ pub struct RawWeight {
pub title: String,
pub weights_type: WeightsType,
pub weights_category: WeightsCategory,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
@@ -280,9 +276,9 @@ pub struct RawWeight {
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_avatar_public_bucket_hash: Option<String>,
pub maybe_avatar_public_bucket_prefix: Option<String>,
pub maybe_avatar_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_negative_count: u32,
pub cached_user_ratings_positive_count: u32,
@@ -20,8 +20,6 @@ pub struct WeightsByTokensRecord {
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
@@ -31,6 +29,10 @@ pub struct WeightsByTokensRecord {
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
@@ -71,7 +73,6 @@ async fn get_raw_weights_by_tokens(
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_thumbnail_token,
users.token as creator_user_token,
users.username as creator_username,
users.display_name as creator_display_name,
@@ -79,6 +80,9 @@ async fn get_raw_weights_by_tokens(
mw.public_bucket_hash,
mw.maybe_public_bucket_prefix,
mw.maybe_public_bucket_extension,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,
mw.cached_user_ratings_negative_count,
mw.cached_user_ratings_positive_count,
mw.cached_user_ratings_total_count,
@@ -91,6 +95,8 @@ async fn get_raw_weights_by_tokens(
FROM model_weights as mw
JOIN users
ON users.token = mw.creator_user_token
LEFT OUTER JOIN media_files as cover_image
ON cover_image.token = mw.maybe_cover_image_media_file_token
WHERE
mw.creator_set_visibility = "public"
AND mw.token IN (
@@ -104,7 +110,6 @@ async fn get_raw_weights_by_tokens(
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_thumbnail_token,
users.token as creator_user_token,
users.username as creator_username,
users.display_name as creator_display_name,
@@ -112,6 +117,9 @@ async fn get_raw_weights_by_tokens(
mw.public_bucket_hash,
mw.maybe_public_bucket_prefix,
mw.maybe_public_bucket_extension,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,
mw.cached_user_ratings_negative_count,
mw.cached_user_ratings_positive_count,
mw.cached_user_ratings_total_count,
@@ -124,6 +132,8 @@ async fn get_raw_weights_by_tokens(
FROM model_weights as mw
JOIN users
ON users.token = mw.creator_user_token
LEFT OUTER JOIN media_files as cover_image
ON cover_image.token = mw.maybe_cover_image_media_file_token
WHERE
mw.creator_set_visibility = "public"
AND mw.user_deleted_at IS NULL
@@ -157,34 +167,37 @@ fn token_predicate(tokens: &[ModelWeightToken]) -> String {
fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsByTokensRecord> {
let weights: Vec<WeightsByTokensRecord> = dataset
.into_iter()
.map(|dataset: RawWeightJoinUser| {
.map(|weight| {
WeightsByTokensRecord {
token: dataset.token,
title: dataset.title,
weights_type: dataset.weights_type,
weights_category: dataset.weights_category,
maybe_thumbnail_token: dataset.maybe_thumbnail_token,
token: weight.token,
title: weight.title,
weights_type: weight.weights_type,
weights_category: weight.weights_category,
creator_user_token: dataset.creator_user_token,
creator_username:dataset.creator_username,
creator_display_name:dataset.creator_display_name,
creator_email_gravatar_hash:dataset.creator_email_gravatar_hash,
creator_user_token: weight.creator_user_token,
creator_username: weight.creator_username,
creator_display_name: weight.creator_display_name,
creator_email_gravatar_hash: weight.creator_email_gravatar_hash,
public_bucket_hash: dataset.public_bucket_hash,
maybe_public_bucket_prefix: dataset.maybe_public_bucket_prefix,
maybe_public_bucket_extension: dataset.maybe_public_bucket_extension,
public_bucket_hash: weight.public_bucket_hash,
maybe_public_bucket_prefix: weight.maybe_public_bucket_prefix,
maybe_public_bucket_extension: weight.maybe_public_bucket_extension,
cached_user_ratings_negative_count: dataset.cached_user_ratings_negative_count,
cached_user_ratings_positive_count: dataset.cached_user_ratings_positive_count,
cached_user_ratings_total_count: dataset.cached_user_ratings_total_count,
maybe_cover_image_public_bucket_hash: weight.maybe_cover_image_public_bucket_hash,
maybe_cover_image_public_bucket_prefix: weight.maybe_cover_image_public_bucket_prefix,
maybe_cover_image_public_bucket_extension: weight.maybe_cover_image_public_bucket_extension,
maybe_cached_user_ratings_ratio: dataset.maybe_cached_user_ratings_ratio,
cached_user_ratings_last_updated_at: dataset.cached_user_ratings_last_updated_at,
cached_user_ratings_negative_count: weight.cached_user_ratings_negative_count,
cached_user_ratings_positive_count: weight.cached_user_ratings_positive_count,
cached_user_ratings_total_count: weight.cached_user_ratings_total_count,
created_at: dataset.created_at,
updated_at: dataset.updated_at,
user_deleted_at: dataset.user_deleted_at,
mod_deleted_at: dataset.mod_deleted_at,
maybe_cached_user_ratings_ratio: weight.maybe_cached_user_ratings_ratio,
cached_user_ratings_last_updated_at: weight.cached_user_ratings_last_updated_at,
created_at: weight.created_at,
updated_at: weight.updated_at,
user_deleted_at: weight.user_deleted_at,
mod_deleted_at: weight.mod_deleted_at,
}
}).collect();
@@ -200,8 +213,6 @@ fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsByTokensRecord>
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub creator_user_token: UserToken,
pub creator_username: String,
pub creator_display_name: String,
@@ -210,7 +221,11 @@ fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsByTokensRecord>
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
@@ -242,7 +257,6 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
weights_type: WeightsType::try_from_mysql_row(row, "weights_type")?,
weights_category: WeightsCategory::try_from_mysql_row(row, "weights_category")?,
title: row.try_get("title")?,
maybe_thumbnail_token: row.try_get("maybe_thumbnail_token")?,
creator_user_token: UserToken::new_from_str(row.try_get("creator_user_token")?),
creator_username: row.try_get("creator_username")?,
creator_display_name: row.try_get("creator_display_name")?,
@@ -250,6 +264,9 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
public_bucket_hash: row.try_get("public_bucket_hash")?,
maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?,
maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?,
maybe_cover_image_public_bucket_hash: row.try_get("maybe_cover_image_public_bucket_hash")?,
maybe_cover_image_public_bucket_prefix: row.try_get("maybe_cover_image_public_bucket_prefix")?,
maybe_cover_image_public_bucket_extension: row.try_get("maybe_cover_image_public_bucket_extension")?,
cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?,
cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?,
cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?,
@@ -6,6 +6,7 @@ use enums::by_table::model_weights::{
weights_category::WeightsCategory,
weights_types::WeightsType,
};
use enums::common::view_as::ViewAs;
use enums::common::visibility::Visibility;
use enums::traits::mysql_from_row::MySqlFromRow;
use errors::AnyhowResult;
@@ -21,7 +22,6 @@ pub struct WeightsForUserListPage {
pub total_page_count: usize,
}
#[derive(Serialize)]
pub struct WeightsJoinUserRecord {
pub token: ModelWeightToken,
@@ -30,11 +30,11 @@ pub struct WeightsJoinUserRecord {
pub weights_category: WeightsCategory,
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub maybe_description_markdown: String,
//pub maybe_description_rendered_html: String,
pub creator_user_token: UserToken,
pub creator_ip_address: String,
@@ -51,6 +51,10 @@ pub struct WeightsJoinUserRecord {
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
@@ -76,7 +80,7 @@ pub struct ListWeightsForUserArgs<'a> {
pub page_size: usize,
pub page_index: usize,
pub sort_ascending: bool,
pub can_see_deleted: bool,
pub view_as: ViewAs,
pub mysql_pool: &'a MySqlPool,
}
@@ -89,7 +93,7 @@ pub async fn list_weights_by_creator_username(args: ListWeightsForUserArgs<'_>)
0,
args.sort_ascending,
count_fields.as_str(),
args.can_see_deleted,
args.view_as,
);
let row_count_query = count_query_builder.build_query_scalar::<i64>();
@@ -104,7 +108,7 @@ pub async fn list_weights_by_creator_username(args: ListWeightsForUserArgs<'_>)
args.page_size,
args.sort_ascending,
result_fields.as_str(),
args.can_see_deleted,
args.view_as,
);
let query = query.build_query_as::<RawWeightJoinUser>();
@@ -112,11 +116,8 @@ pub async fn list_weights_by_creator_username(args: ListWeightsForUserArgs<'_>)
let number_of_pages = (row_count_result / args.page_size as i64) as usize;
let weights_records: Vec<WeightsJoinUserRecord> = map_to_weights(results).await;
Ok(WeightsForUserListPage {
records: weights_records,
sort_ascending: args.sort_ascending,
@@ -134,38 +135,41 @@ fn select_total_count_field() -> String {
fn select_result_fields() -> String {
r#"
mw.token,
mw.title,
mw.weights_type,
mw.weights_category,
mw.maybe_thumbnail_token,
mw.description_markdown,
mw.description_rendered_html,
u.token as creator_user_token,
u.username as creator_username,
u.display_name as creator_display_name,
u.email_gravatar_hash as creator_email_gravatar_hash,
mw.creator_ip_address,
mw.creator_set_visibility,
mw.maybe_last_update_user_token,
mw.original_download_url,
mw.original_filename,
mw.file_size_bytes,
mw.file_checksum_sha2,
mw.public_bucket_hash,
mw.maybe_public_bucket_prefix,
mw.maybe_public_bucket_extension,
mw.cached_user_ratings_negative_count,
mw.cached_user_ratings_positive_count,
mw.cached_user_ratings_total_count,
mw.maybe_cached_user_ratings_ratio,
mw.cached_user_ratings_last_updated_at,
mw.version,
mw.created_at,
mw.updated_at,
mw.user_deleted_at,
mw.mod_deleted_at
"#.to_string()
mw.token,
mw.title,
mw.weights_type,
mw.weights_category,
u.token as creator_user_token,
u.username as creator_username,
u.display_name as creator_display_name,
u.email_gravatar_hash as creator_email_gravatar_hash,
mw.creator_ip_address,
mw.creator_set_visibility,
mw.maybe_last_update_user_token,
mw.original_download_url,
mw.original_filename,
mw.file_size_bytes,
mw.file_checksum_sha2,
mw.public_bucket_hash,
mw.maybe_public_bucket_prefix,
mw.maybe_public_bucket_extension,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,
mw.cached_user_ratings_negative_count,
mw.cached_user_ratings_positive_count,
mw.cached_user_ratings_total_count,
mw.maybe_cached_user_ratings_ratio,
mw.cached_user_ratings_last_updated_at,
mw.version,
mw.created_at,
mw.updated_at,
mw.user_deleted_at,
mw.mod_deleted_at
"#.to_string()
}
fn query_builder<'a>(
@@ -175,7 +179,7 @@ fn query_builder<'a>(
page_size: usize,
sort_ascending: bool,
select_fields: &'a str,
can_see_deleted: bool,
view_as: ViewAs,
) -> QueryBuilder<'a, MySql> {
// NB: Query cannot be statically checked by sqlx
@@ -186,16 +190,25 @@ SELECT
FROM model_weights as mw
JOIN users as u
ON u.token = mw.creator_user_token
LEFT OUTER JOIN media_files as cover_image
ON cover_image.token = mw.maybe_cover_image_media_file_token
"#
));
if !can_see_deleted {
query_builder.push(" WHERE mw.user_deleted_at IS NULL AND mw.mod_deleted_at IS NULL ");
}
query_builder.push(" AND u.username = ");
query_builder.push(" WHERE u.username = ");
query_builder.push_bind(username);
match view_as {
ViewAs::Author => {
query_builder.push(" AND mw.user_deleted_at IS NULL AND mw.mod_deleted_at IS NULL ");
}
ViewAs::Moderator => {}
ViewAs::AnotherUser => {
query_builder.push(" AND mw.user_deleted_at IS NULL AND mw.mod_deleted_at IS NULL ");
query_builder.push(" AND mw.creator_set_visibility = ");
query_builder.push_bind(Visibility::Public.to_str());
}
}
if sort_ascending {
query_builder.push(" ORDER BY mw.created_at ASC ");
@@ -215,44 +228,47 @@ JOIN users as u
async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRecord> {
let weights: Vec<WeightsJoinUserRecord> = dataset
.into_iter()
.map(|dataset: RawWeightJoinUser| {
.map(|weight: RawWeightJoinUser| {
WeightsJoinUserRecord {
token: dataset.token,
title: dataset.title,
weights_type: dataset.weights_type,
weights_category: dataset.weights_category,
maybe_thumbnail_token: dataset.maybe_thumbnail_token,
description_markdown: dataset.description_markdown,
description_rendered_html: dataset.description_rendered_html,
token: weight.token,
title: weight.title,
weights_type: weight.weights_type,
weights_category: weight.weights_category,
//maybe_description_markdown: weight.maybe_description_markdown,
//maybe_description_rendered_html: weight.maybe_description_rendered_html,
creator_user_token: dataset.creator_user_token,
creator_ip_address: dataset.creator_ip_address,
creator_set_visibility: dataset.creator_set_visibility,
creator_user_token: weight.creator_user_token,
creator_ip_address: weight.creator_ip_address,
creator_set_visibility: weight.creator_set_visibility,
maybe_last_update_user_token: dataset.maybe_last_update_user_token,
original_download_url: dataset.original_download_url,
original_filename: dataset.original_filename,
file_size_bytes: dataset.file_size_bytes,
file_checksum_sha2: dataset.file_checksum_sha2,
public_bucket_hash: dataset.public_bucket_hash,
maybe_public_bucket_prefix: dataset.maybe_public_bucket_prefix,
maybe_public_bucket_extension: dataset.maybe_public_bucket_extension,
maybe_last_update_user_token: weight.maybe_last_update_user_token,
original_download_url: weight.original_download_url,
original_filename: weight.original_filename,
file_size_bytes: weight.file_size_bytes,
file_checksum_sha2: weight.file_checksum_sha2,
public_bucket_hash: weight.public_bucket_hash,
maybe_public_bucket_prefix: weight.maybe_public_bucket_prefix,
maybe_public_bucket_extension: weight.maybe_public_bucket_extension,
cached_user_ratings_negative_count: dataset.cached_user_ratings_negative_count,
cached_user_ratings_positive_count: dataset.cached_user_ratings_positive_count,
cached_user_ratings_total_count: dataset.cached_user_ratings_total_count,
maybe_cover_image_public_bucket_hash: weight.maybe_cover_image_public_bucket_hash,
maybe_cover_image_public_bucket_prefix: weight.maybe_cover_image_public_bucket_prefix,
maybe_cover_image_public_bucket_extension: weight.maybe_cover_image_public_bucket_extension,
maybe_cached_user_ratings_ratio: dataset.maybe_cached_user_ratings_ratio,
cached_user_ratings_last_updated_at: dataset.cached_user_ratings_last_updated_at,
version: dataset.version,
created_at: dataset.created_at,
updated_at: dataset.updated_at,
user_deleted_at: dataset.user_deleted_at,
mod_deleted_at: dataset.mod_deleted_at,
cached_user_ratings_negative_count: weight.cached_user_ratings_negative_count,
cached_user_ratings_positive_count: weight.cached_user_ratings_positive_count,
cached_user_ratings_total_count: weight.cached_user_ratings_total_count,
creator_username:dataset.creator_username,
creator_display_name:dataset.creator_display_name,
creator_email_gravatar_hash:dataset.creator_email_gravatar_hash
maybe_cached_user_ratings_ratio: weight.maybe_cached_user_ratings_ratio,
cached_user_ratings_last_updated_at: weight.cached_user_ratings_last_updated_at,
version: weight.version,
created_at: weight.created_at,
updated_at: weight.updated_at,
user_deleted_at: weight.user_deleted_at,
mod_deleted_at: weight.mod_deleted_at,
creator_username: weight.creator_username,
creator_display_name: weight.creator_display_name,
creator_email_gravatar_hash: weight.creator_email_gravatar_hash,
}
}).collect();
@@ -267,11 +283,11 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRe
pub weights_category: WeightsCategory,
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub description_markdown: String,
//pub description_rendered_html: String,
pub creator_user_token: UserToken,
pub creator_ip_address: String,
@@ -288,7 +304,11 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRe
pub public_bucket_hash: String,
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
@@ -309,15 +329,16 @@ async fn map_to_weights(dataset:Vec<RawWeightJoinUser>) -> Vec<WeightsJoinUserRe
}
impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
fn from_row(row: &MySqlRow) -> std::result::Result<Self, sqlx::Error> {
fn from_row(row: &MySqlRow) -> Result<Self, sqlx::Error> {
Ok(Self {
token: row.try_get("token")?,
weights_type: row.try_get("weights_type")?,
weights_category: row.try_get("weights_category")?,
title: row.try_get("title")?,
maybe_thumbnail_token: row.try_get("maybe_thumbnail_token")?,
description_markdown: row.try_get("description_markdown")?,
description_rendered_html: row.try_get("description_rendered_html")?,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//maybe_description_markdown: row.try_get("maybe_description_markdown")?,
//maybe_description_rendered_html: row.try_get("maybe_description_rendered_html")?,
creator_user_token: row.try_get("creator_user_token")?,
creator_ip_address: row.try_get("creator_ip_address")?,
creator_set_visibility: Visibility::try_from_mysql_row(row, "creator_set_visibility")?,
@@ -329,6 +350,9 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser {
public_bucket_hash: row.try_get("public_bucket_hash")?,
maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?,
maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?,
maybe_cover_image_public_bucket_hash: row.try_get("maybe_cover_image_public_bucket_hash")?,
maybe_cover_image_public_bucket_prefix: row.try_get("maybe_cover_image_public_bucket_prefix")?,
maybe_cover_image_public_bucket_extension: row.try_get("maybe_cover_image_public_bucket_extension")?,
cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?,
cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?,
cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?,
@@ -36,10 +36,8 @@ pub struct WeightJoinUser {
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
pub creator_user_token: UserToken,
pub creator_ip_address: String,
@@ -57,6 +55,10 @@ pub struct WeightJoinUser {
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
@@ -160,13 +162,15 @@ impl ListWeightsQueryBuilder {
mysql_pool: &MySqlPool
) -> AnyhowResult<Vec<RawWeightJoinUser>> {
let query = self.build_query_string();
//println!("HERE! query: {}", query);
//panic!("query: {:?}", query);
let mut query = sqlx::query_as::<_, RawWeightJoinUser>(&query);
// NB: The following bindings must match the order of the query builder !!
if let Some(offset) = self.offset {
query = query.bind(offset);
}
if let Some(username) = self.scope_creator_username.as_deref() {
query = query.bind(username);
}
@@ -181,9 +185,6 @@ impl ListWeightsQueryBuilder {
query = query.bind(self.limit);
if let Some(offset) = self.offset {
query = query.bind(offset);
}
let mut results = query.fetch_all(mysql_pool).await?;
@@ -216,9 +217,8 @@ impl ListWeightsQueryBuilder {
record.weights_category.as_str()
).unwrap(),
title: record.title,
maybe_thumbnail_token: record.maybe_thumbnail_token,
description_markdown: record.description_markdown,
description_rendered_html: record.description_rendered_html,
maybe_description_markdown: record.maybe_description_markdown,
maybe_description_rendered_html: record.maybe_description_rendered_html,
creator_user_token: UserToken::new_from_str(&record.creator_user_token),
creator_ip_address: record.creator_ip_address,
creator_set_visibility: Visibility::from_str(
@@ -234,6 +234,9 @@ impl ListWeightsQueryBuilder {
public_bucket_hash: record.public_bucket_hash,
maybe_public_bucket_prefix: record.maybe_public_bucket_prefix,
maybe_public_bucket_extension: record.maybe_public_bucket_extension,
maybe_cover_image_public_bucket_hash: record.maybe_cover_image_public_bucket_hash,
maybe_cover_image_public_bucket_prefix: record.maybe_cover_image_public_bucket_prefix,
maybe_cover_image_public_bucket_extension: record.maybe_cover_image_public_bucket_extension,
cached_user_ratings_total_count: record.cached_user_ratings_total_count,
cached_user_ratings_positive_count: record.cached_user_ratings_positive_count,
cached_user_ratings_negative_count: record.cached_user_ratings_negative_count,
@@ -268,9 +271,8 @@ impl ListWeightsQueryBuilder {
model_weights.weights_type,
model_weights.weights_category,
model_weights.title,
model_weights.maybe_thumbnail_token,
model_weights.description_markdown,
model_weights.description_rendered_html,
model_weights.maybe_description_markdown,
model_weights.maybe_description_rendered_html,
model_weights.creator_user_token,
model_weights.creator_ip_address,
model_weights.creator_set_visibility,
@@ -282,6 +284,9 @@ impl ListWeightsQueryBuilder {
model_weights.public_bucket_hash,
model_weights.maybe_public_bucket_prefix,
model_weights.maybe_public_bucket_extension,
cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash,
cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix,
cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension,
model_weights.cached_user_ratings_total_count,
model_weights.cached_user_ratings_positive_count,
model_weights.cached_user_ratings_negative_count,
@@ -298,6 +303,8 @@ impl ListWeightsQueryBuilder {
FROM model_weights
JOIN users
ON users.token = model_weights.creator_user_token
LEFT OUTER JOIN media_files as cover_image
ON cover_image.token = model_weights.maybe_cover_image_media_file_token
"#.to_string();
query.push_str(&self.build_predicates());
@@ -323,18 +330,18 @@ impl ListWeightsQueryBuilder {
if sort_ascending {
if self.cursor_is_reversed {
// NB: We're searching backwards.
query.push_str(" model_weights.id");
query.push_str(" model_weights.id < ? ");
sort_ascending = !sort_ascending;
} else {
query.push_str(" model_weights.id");
query.push_str(" model_weights.id > ? ");
}
} else {
if self.cursor_is_reversed {
// NB: We're searching backwards.
query.push_str(" model_weights.id");
query.push_str(" model_weights.id > ? ");
sort_ascending = !sort_ascending;
} else {
query.push_str(" model_weights.id");
query.push_str(" model_weights.id < ? ");
}
}
}
@@ -403,10 +410,6 @@ impl ListWeightsQueryBuilder {
query.push_str(" LIMIT ?");
}
if let Some(_) = self.offset {
query.push_str(" OFFSET ?");
}
query
}
}
@@ -422,10 +425,8 @@ struct RawWeightJoinUser {
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub description_markdown: String,
pub description_rendered_html: String,
pub maybe_description_markdown: Option<String>,
pub maybe_description_rendered_html: Option<String>,
pub creator_user_token: String,
pub creator_ip_address: String,
@@ -443,6 +444,10 @@ struct RawWeightJoinUser {
pub maybe_public_bucket_prefix: Option<String>,
pub maybe_public_bucket_extension: Option<String>,
pub maybe_cover_image_public_bucket_hash: Option<String>,
pub maybe_cover_image_public_bucket_prefix: Option<String>,
pub maybe_cover_image_public_bucket_extension: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
@@ -76,11 +76,9 @@ SET
weights_type = ?,
weights_category = ?,
title = ?,
maybe_thumbnail_token = NULL,
maybe_avatar_media_file_token = NULL,
maybe_cover_media_file_token = NULL,
description_markdown = ?,
description_rendered_html = ?,
maybe_cover_image_media_file_token = NULL,
maybe_description_markdown = ?,
maybe_description_rendered_html = ?,
creator_user_token = ?,
creator_ip_address = ?,
@@ -111,11 +109,9 @@ ON DUPLICATE KEY UPDATE
weights_type = ?,
weights_category = ?,
title = ?,
maybe_thumbnail_token = NULL,
maybe_avatar_media_file_token = NULL,
maybe_cover_media_file_token = NULL,
description_markdown = ?,
description_rendered_html = ?,
maybe_cover_image_media_file_token = NULL,
maybe_description_markdown = ?,
maybe_description_rendered_html = ?,
creator_user_token = ?,
creator_ip_address = ?,
creator_set_visibility = ?,
@@ -4,9 +4,8 @@ CREATE TABLE model_weights (
weights_type VARCHAR(32) NOT NULL,
weights_category VARCHAR(32) NOT NULL,
title VARCHAR(255) NOT NULL,
maybe_thumbnail_token VARCHAR(32) DEFAULT NULL,
description_markdown TEXT NOT NULL,
description_rendered_html TEXT NOT NULL,
maybe_description_markdown TEXT DEFAULT NULL,
maybe_description_rendered_html TEXT DEFAULT NULL,
creator_user_token VARCHAR(32) NOT NULL,
creator_ip_address VARCHAR(40) NOT NULL,
creator_set_visibility ENUM(
@@ -1,3 +1,4 @@
#[ignore]
#[cfg(test)]
mod tests {
use anyhow::Ok;
@@ -65,9 +66,8 @@ mod tests {
weights_type: WeightsType::RvcV2, // replace with actual WeightsType
weights_category: WeightsCategory::VoiceConversion, // replace with actual WeightsCategory
title: "Title 1".to_string(),
maybe_thumbnail_token: Some("Thumbnail 1".to_string()),
description_markdown: "Description 1".to_string(),
description_rendered_html: "<p>Description 1</p>".to_string(),
maybe_description_markdown: Some("Description 1".to_string()),
maybe_description_rendered_html: Some("<p>Description 1</p>".to_string()),
creator_user_token: Some(&creator_token1), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -98,9 +98,8 @@ mod tests {
assert_eq!(result.title, "Title 1".to_string());
assert_eq!(result.weights_type, WeightsType::RvcV2);
assert_eq!(result.weights_category, WeightsCategory::VoiceConversion);
assert_eq!(result.maybe_thumbnail_token, Some("Thumbnail 1".to_string()));
assert_eq!(result.description_markdown, "Description 1".to_string());
assert_eq!(result.description_rendered_html, "<p>Description 1</p>".to_string());
assert_eq!(result.maybe_description_markdown, Some("Description 1".to_string()));
assert_eq!(result.maybe_description_rendered_html, Some("<p>Description 1</p>".to_string()));
assert_eq!(result.creator_user_token, creator_token1);
assert_eq!(result.creator_ip_address, "192.168.1.1".to_string());
assert_eq!(result.creator_set_visibility, Visibility::Public);
@@ -140,9 +139,8 @@ mod tests {
weights_type: WeightsType::RvcV2, // replace with actual WeightsType
weights_category: WeightsCategory::VoiceConversion, // replace with actual WeightsCategory
title: "Title 1".to_string(),
maybe_thumbnail_token: Some("Thumbnail 1".to_string()),
description_markdown: "Description 1".to_string(),
description_rendered_html: "<p>Description 1</p>".to_string(),
maybe_description_markdown: Some("Description 1".to_string()),
maybe_description_rendered_html: Some("<p>Description 1</p>".to_string()),
creator_user_token: Some(&creator_token1), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -217,9 +215,8 @@ mod tests {
weights_type: WeightsType::RvcV2, // replace with actual WeightsType
weights_category: WeightsCategory::VoiceConversion, // replace with actual WeightsCategory
title: "Title 1".to_string(),
maybe_thumbnail_token: Some("Thumbnail 1".to_string()),
description_markdown: "Description 1".to_string(),
description_rendered_html: "<p>Description 1</p>".to_string(),
maybe_description_markdown: Some("Description 1".to_string()),
maybe_description_rendered_html: Some("<p>Description 1</p>".to_string()),
creator_user_token: Some(&creator_token1), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -329,12 +326,11 @@ mod tests {
let args = CreateModelWeightsArgs {
token: &model_weight_token, // replace with actual ModelWeightToken
weights_type: weights_type, // replace with actual WeightsType
weights_category: weights_category, // replace with actual WeightsCategory
weights_type, // replace with actual WeightsType
weights_category, // replace with actual WeightsCategory
title: format!("Title {}", i),
maybe_thumbnail_token: Some(format!("Thumbnail {}", i)),
description_markdown: format!("Description {}", i),
description_rendered_html: format!("<p>Description {}</p>", i),
maybe_description_markdown: Some(format!("Description {}", i)),
maybe_description_rendered_html: Some(format!("<p>Description {}</p>", i)),
creator_user_token: Some(&creator_token), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -572,12 +568,11 @@ mod tests {
let args = CreateModelWeightsArgs {
token: &model_weight_token, // replace with actual ModelWeightToken
weights_type: weights_type, // replace with actual WeightsType
weights_category: weights_category, // replace with actual WeightsCategory
weights_type, // replace with actual WeightsType
weights_category, // replace with actual WeightsCategory
title: format!("Title {}", i),
maybe_thumbnail_token: Some(format!("Thumbnail {}", i)),
description_markdown: format!("Description {}", i),
description_rendered_html: format!("<p>Description {}</p>", i),
maybe_description_markdown: Some(format!("Description {}", i)),
maybe_description_rendered_html: Some(format!("<p>Description {}</p>", i)),
creator_user_token: Some(&creator_token), // replace with actual UserToken
creator_ip_address: "192.168.1.1",
creator_set_visibility: Visibility::Public,
@@ -1,6 +1,4 @@
use anyhow::anyhow;
use log::warn;
use sqlx::MySqlPool;
use sqlx::{MySql, MySqlPool, QueryBuilder};
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
use errors::AnyhowResult;
@@ -8,21 +6,37 @@ use errors::AnyhowResult;
use crate::queries::user_bookmarks::list_user_bookmarks_result::RawUserBookmarkRecord;
use crate::queries::user_bookmarks::list_user_bookmarks_result::UserBookmark;
pub async fn list_user_bookmarks(
username: &str,
mysql_pool: &MySqlPool
) -> AnyhowResult<Vec<UserBookmark>> {
pub struct UserBookmarkListPage {
pub results: Vec<UserBookmark>,
/// TODO(bt,2023-11-21): Maybe this query can use a switch
/// See: https://stackoverflow.com/questions/2761574/mysql-use-case-else-value-as-join-parameter
let maybe_results= sqlx::query_as!(
RawUserBookmarkRecord,
r#"
SELECT
f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,
f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,
pub sort_ascending: bool,
pub current_page: usize,
pub total_page_count: usize,
}
pub struct ListUserBookmarksForUserArgs<'a> {
pub username: &'a str,
pub maybe_filter_entity_type: Option<UserBookmarkEntityType>,
pub page_size: usize,
pub page_index: usize,
pub sort_ascending: bool,
pub mysql_pool: &'a MySqlPool,
}
fn select_total_count_field() -> String {
r#"
COUNT(f.id) AS total_count
"#
.to_string()
}
fn select_result_fields() -> String {
r#"
f.token,
f.entity_type,
f.entity_token,
f.user_token as `user_token: tokens::tokens::users::UserToken`,
f.user_token,
u.username,
u.display_name as user_display_name,
u.email_gravatar_hash as user_gravatar_hash,
@@ -30,8 +44,8 @@ SELECT
f.updated_at,
f.deleted_at,
media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,
media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,
media_files.media_type as maybe_media_file_type,
media_files.origin_product_category as maybe_media_file_origin_category,
model_weights.title as maybe_descriptive_text_model_weight_title,
tts_models.title as maybe_descriptive_text_tts_model_title,
@@ -39,7 +53,25 @@ SELECT
users.display_name as maybe_descriptive_text_user_display_name,
voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,
zs_voices.title as maybe_descriptive_text_zs_voice_title
"#.to_string()
}
fn query_builder<'a>(
maybe_filter_entity_type: Option<UserBookmarkEntityType>,
maybe_username: Option<&'a str>,
enforce_limits: bool,
page_index: usize,
page_size: usize,
sort_ascending: bool,
select_fields: &'a str,
) -> QueryBuilder<'a, MySql> {
let mut first_predicate_added = false;
// NB: Query cannot be statically checked by sqlx
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
format!(r#"
SELECT
{select_fields}
FROM
user_bookmarks AS f
JOIN users AS u
@@ -52,99 +84,91 @@ LEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token
LEFT OUTER JOIN users ON users.token = f.entity_token
LEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token
LEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token
"#
));
WHERE
u.username = ?
AND f.deleted_at IS NULL
ORDER BY f.id DESC
LIMIT 50
"#,
username
)
.fetch_all(mysql_pool)
.await;
if let Some(username) = maybe_username {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
query_builder.push(" u.username = ");
query_builder.push_bind(username);
}
match maybe_results {
Err(err) => match err {
sqlx::Error::RowNotFound => Ok(Vec::new()),
_ => {
warn!("list user_bookmarks db error: {:?}", err);
Err(anyhow!("error with query: {:?}", err))
}
},
Ok(results) => Ok(results.into_iter()
.map(|user_bookmark| user_bookmark.into_public_type())
.collect()),
}
if let Some(entity_type) = maybe_filter_entity_type {
if !first_predicate_added {
query_builder.push(" WHERE ");
first_predicate_added = true;
} else {
query_builder.push(" AND ");
}
query_builder.push(" f.entity_type = ");
query_builder.push_bind(entity_type.to_str());
}
query_builder.push(" AND f.deleted_at IS NULL ");
if sort_ascending {
query_builder.push(" ORDER BY f.created_at ASC ");
} else {
query_builder.push(" ORDER BY f.created_at DESC ");
}
if enforce_limits {
let offset = page_index * page_size;
query_builder.push(format!(" LIMIT {page_size} OFFSET {offset} "));
}
query_builder
}
pub async fn list_user_user_bookmarks_by_entity_type(
username: &str,
entity_type: UserBookmarkEntityType,
mysql_pool: &MySqlPool
) -> AnyhowResult<Vec<UserBookmark>> {
pub async fn list_user_bookmarks_by_maybe_entity_type(
args: ListUserBookmarksForUserArgs<'_>
) -> AnyhowResult<UserBookmarkListPage> {
let maybe_results= sqlx::query_as!(
RawUserBookmarkRecord,
r#"
SELECT
f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,
f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,
f.entity_token,
f.user_token as `user_token: tokens::tokens::users::UserToken`,
u.username,
u.display_name as user_display_name,
u.email_gravatar_hash as user_gravatar_hash,
f.created_at,
f.updated_at,
f.deleted_at,
let count_fields = select_total_count_field();
let mut count_query_builder = query_builder(
args.maybe_filter_entity_type,
Some(args.username),
false,
0,
0,
args.sort_ascending,
count_fields.as_str(),
);
media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,
media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,
let row_count_query = count_query_builder.build_query_scalar::<i64>();
let row_count_result = row_count_query.fetch_one(args.mysql_pool).await?;
model_weights.title as maybe_descriptive_text_model_weight_title,
tts_models.title as maybe_descriptive_text_tts_model_title,
tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,
users.display_name as maybe_descriptive_text_user_display_name,
voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,
zs_voices.title as maybe_descriptive_text_zs_voice_title
/// Now fetch the actual results with all the fields
let result_fields = select_result_fields();
let mut query = query_builder(
args.maybe_filter_entity_type,
Some(args.username),
true,
args.page_index,
args.page_size,
args.sort_ascending,
result_fields.as_str(),
);
FROM
user_bookmarks AS f
JOIN users AS u
ON f.user_token = u.token
let query = query.build_query_as::<RawUserBookmarkRecord>();
let results = query.fetch_all(args.mysql_pool).await?;
LEFT OUTER JOIN model_weights ON model_weights.token = f.entity_token
LEFT OUTER JOIN media_files ON media_files.token = f.entity_token
LEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token
LEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token
LEFT OUTER JOIN users ON users.token = f.entity_token
LEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token
LEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token
let number_of_pages = (row_count_result / args.page_size as i64) as usize;
let results = results.into_iter()
.map(|record| {
record.into_public_type()
})
.collect::<Vec<_>>();
WHERE
u.username = ?
AND f.entity_type = ?
AND f.deleted_at IS NULL
ORDER BY f.id DESC
LIMIT 50
"#,
username,
entity_type
)
.fetch_all(mysql_pool)
.await;
match maybe_results {
Err(err) => match err {
sqlx::Error::RowNotFound => Ok(Vec::new()),
_ => {
warn!("list user_bookmarks db error: {:?}", err);
Err(anyhow!("error with query: {:?}", err))
}
},
Ok(results) => Ok(results.into_iter()
.map(|user_bookmark| user_bookmark.into_public_type())
.collect()),
}
Ok(UserBookmarkListPage {
results,
sort_ascending: args.sort_ascending,
current_page: args.page_index,
total_page_count: number_of_pages,
})
}
@@ -1,8 +1,11 @@
use chrono::{DateTime, Utc};
use sqlx::{FromRow, Row};
use sqlx::mysql::MySqlRow;
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
use enums::traits::mysql_from_row::MySqlFromRow;
use tokens::tokens::user_bookmarks::UserBookmarkToken;
use tokens::tokens::users::UserToken;
@@ -85,3 +88,28 @@ impl RawUserBookmarkRecord {
}
}
}
impl FromRow<'_, MySqlRow> for RawUserBookmarkRecord {
fn from_row(row: &MySqlRow) -> Result<Self, sqlx::Error> {
Ok(Self {
token: UserBookmarkToken::new(row.try_get("token")?),
entity_type: UserBookmarkEntityType::try_from_mysql_row(row, "entity_type")?,
entity_token: row.try_get("entity_token")?,
user_token: row.try_get("user_token")?,
username: row.try_get("username")?,
user_display_name: row.try_get("user_display_name")?,
user_gravatar_hash: row.try_get("user_gravatar_hash")?,
created_at: row.try_get("created_at")?,
updated_at: row.try_get("updated_at")?,
deleted_at: row.try_get("deleted_at")?,
maybe_media_file_type: MediaFileType::try_from_mysql_row_nullable(row,"maybe_media_file_type")?,
maybe_media_file_origin_category: MediaFileOriginCategory::try_from_mysql_row_nullable(row,"maybe_media_file_origin_category")?,
maybe_descriptive_text_model_weight_title: row.try_get("maybe_descriptive_text_model_weight_title")?,
maybe_descriptive_text_tts_model_title: row.try_get("maybe_descriptive_text_tts_model_title")?,
maybe_descriptive_text_tts_result_inference_text: row.try_get("maybe_descriptive_text_tts_result_inference_text")?,
maybe_descriptive_text_user_display_name: row.try_get("maybe_descriptive_text_user_display_name")?,
maybe_descriptive_text_voice_conversion_model_title: row.try_get("maybe_descriptive_text_voice_conversion_model_title")?,
maybe_descriptive_text_zs_voice_title: row.try_get("maybe_descriptive_text_zs_voice_title")?,
})
}
}
@@ -33,6 +33,7 @@ migration = { path = "../../../lib/migration" }
mimetypes = { path = "../../../lib/files/mimetypes" }
mysql_queries = { path = "../../../lib/mysql_queries" }
reusable_types = { path = "../../../_types/reusable_types" }
storyteller_root = { path = "../../../lib/storyteller_root" }
subprocess_common = { path = "../../../lib/subprocess_common" }
tokens = { path = "../../../_types/tokens" }
@@ -46,9 +46,10 @@ pub fn extract_rvc_files(download_file: &Path, temp_dir: &TempDir) -> AnyhowResu
return Ok(DownloadedRvcFile::ModelFileOnly { model_file: download_file.to_path_buf() });
}
if archive.len() > 3 {
// There's something suspicious if the model files has more than 3 entries.
if archive.len() > 7 {
// There's something suspicious if the model files has more than 7 entries.
// It should have the .pth file, a .index file, and _maybe_ a .txt file for credits.
// Mac users sometimes have a bogus __MACOSX directory, which may double the file count.
warn!("File has wrong number of entries to be a valid model: {}", archive.len());
return Ok(DownloadedRvcFile::InvalidModel);
}
@@ -62,6 +63,11 @@ pub fn extract_rvc_files(download_file: &Path, temp_dir: &TempDir) -> AnyhowResu
let mut file = archive.by_index(i)?;
let filename = file.name().to_lowercase();
if filename.starts_with("__macosx/") {
// Mac users sometimes have a bogus __MACOSX directory, which may double the file count.
continue;
}
let temp_file_path;
if filename.ends_with(".pth") {
@@ -103,3 +109,37 @@ pub fn extract_rvc_files(download_file: &Path, temp_dir: &TempDir) -> AnyhowResu
})
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use anyhow::bail;
use tempdir::TempDir;
use errors::AnyhowResult;
use storyteller_root::get_seed_tool_data_root;
use crate::job_types::voice_conversion::rvc_v2::extract_rvc_files::{DownloadedRvcFile, extract_rvc_files};
#[test]
#[ignore]
fn test_rvc_with_macos_directory() -> AnyhowResult<()> {
let root = get_seed_tool_data_root();
let broken_model = root.join("models/rvc/sakura-hkt48.zip");
let tempdir = TempDir::new("test").expect("tempdir creation failed");
let extracted = extract_rvc_files(&broken_model, &tempdir).unwrap();
match extracted {
DownloadedRvcFile::InvalidModel => bail!("should not be broken"),
DownloadedRvcFile::ModelFileOnly { .. } => bail!("should not be model file only"),
DownloadedRvcFile::ModelAndIndexFile { model_file, index_file } => {
assert!(model_file.ends_with("model.pth"));
assert!(index_file.ends_with("model.index"));
}
}
Ok(())
}
}
@@ -1,57 +1,66 @@
use crate::http_server::endpoints::voice_designer::inference::enqueue_tts_request::*;
use utoipa::OpenApi;
use crate::http_server::endpoints::weights::list_available_weights::*;
use crate::http_server::web_utils::response_success_helpers::*;
use crate::http_server::endpoints::weights::delete_weight::*;
use crate::http_server::endpoints::weights::get_weight::*;
use crate::http_server::endpoints::weights::update_weight::*;
use crate::http_server::endpoints::weights::list_weights_by_user::*;
use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight};
use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight;
use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
use crate::http_server::common_responses::pagination_page::PaginationPage;
use crate::http_server::endpoints::media_files::list_featured_media_files::*;
use crate::http_server::endpoints::media_files::list_media_files::*;
use crate::http_server::endpoints::media_files::list_media_files_for_user::*;
use enums::by_table::model_weights::{weights_types::WeightsType, weights_category::WeightsCategory};
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::by_table::model_weights::{weights_category::WeightsCategory, weights_types::WeightsType};
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
use enums::by_table::user_ratings::entity_type::UserRatingEntityType;
use enums::by_table::user_ratings::rating_value::UserRatingValue;
use enums::common::visibility::Visibility;
use tokens::tokens::generic_inference_jobs::*;
use tokens::tokens::media_files::*;
use tokens::tokens::model_weights::*;
use tokens::tokens::user_bookmarks::*;
use tokens::tokens::users::*;
use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight;
use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
use crate::http_server::common_responses::pagination_page::PaginationPage;
use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight};
use crate::http_server::endpoints::media_files::list_featured_media_files::*;
use crate::http_server::endpoints::media_files::list_media_files::*;
use crate::http_server::endpoints::media_files::list_media_files_for_user::*;
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
use crate::http_server::endpoints::media_files::upload_media_file::*;
use crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::*;
use crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::*;
use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::*;
use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_session_handler::*;
use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::*;
use crate::http_server::endpoints::voice_designer::inference::enqueue_tts_request::*;
use crate::http_server::endpoints::weights::delete_weight::*;
use crate::http_server::endpoints::weights::get_weight::*;
use crate::http_server::endpoints::weights::list_available_weights::*;
use crate::http_server::endpoints::weights::list_weights_by_user::*;
use crate::http_server::endpoints::weights::set_model_weight_cover_image::*;
use crate::http_server::endpoints::weights::update_weight::*;
use crate::http_server::web_utils::response_success_helpers::*;
use crate::http_server::endpoints::user_ratings::get_user_rating_handler::*;
use crate::http_server::endpoints::user_ratings::set_user_rating_handler::*;
use tokens::tokens::generic_inference_jobs::*;
use tokens::tokens::model_weights::*;
use tokens::tokens::users::*;
use tokens::tokens::media_files::*;
use tokens::tokens::user_bookmarks::*;
use enums::common::visibility::Visibility;
use chrono::{DateTime, Utc};
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(paths(crate::http_server::endpoints::voice_designer::inference::enqueue_tts_request::enqueue_tts_request,
crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler,
crate::http_server::endpoints::weights::delete_weight::delete_weight_handler,
crate::http_server::endpoints::weights::update_weight::update_weight_handler,
crate::http_server::endpoints::weights::get_weight::get_weight_handler,
crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler,
#[openapi(
paths(
crate::http_server::endpoints::media_files::list_featured_media_files::list_featured_media_files_handler,
crate::http_server::endpoints::media_files::list_media_files::list_media_files_handler,
crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler,
crate::http_server::endpoints::media_files::upload_media_file::upload_media_file_handler,
crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::create_user_bookmark_handler,
crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::delete_user_bookmark_handler,
crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler,
crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::list_user_bookmarks_for_entity_handler,
),components(schemas(
crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler,
crate::http_server::endpoints::voice_designer::inference::enqueue_tts_request::enqueue_tts_request,
crate::http_server::endpoints::weights::delete_weight::delete_weight_handler,
crate::http_server::endpoints::weights::get_weight::get_weight_handler,
crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler,
crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler,
crate::http_server::endpoints::weights::set_model_weight_cover_image::set_model_weight_cover_image_handler,
crate::http_server::endpoints::weights::update_weight::update_weight_handler,
crate::http_server::endpoints::user_ratings::get_user_rating_handler::get_user_rating_handler,
crate::http_server::endpoints::user_ratings::set_user_rating_handler::set_user_rating_handler,
),
components(schemas(
// Tokens
UserToken,Visibility,
//
@@ -62,7 +71,9 @@ use utoipa::OpenApi;
ModelWeightToken,WeightsCategory,WeightsType,
GetWeightPathInfo,GetWeightResponse,GetWeightError,
UpdateWeightRequest,UpdateWeightRequest,UpdateWeightPathInfo,UpdateWeightRequest,UpdateWeightError,
SetModelWeightCoverImageRequest,SetModelWeightCoverImageResponse,SetModelWeightCoverImagePathInfo,SetModelWeightCoverImageError,
DeleteWeightPathInfo,DeleteWeightRequest,DeleteWeightError,DeleteWeightRequest,DeleteWeightError,
UploadMediaSuccessResponse,MediaFileUploadError,
ListWeightError,ModelWeightForList,ListWeightError,
ListAvailableWeightsQuery,ListAvailableWeightsSuccessResponse,ModelWeightForList,
ListWeightsByUserError,ListWeightsByUserSuccessResponse,ListWeightsByUserPathInfo,Weight,
@@ -80,5 +91,8 @@ use utoipa::OpenApi;
DeleteUserBookmarkPathInfo,DeleteUserBookmarkError,DeleteUserBookmarkRequest,
ListUserBookmarksPathInfo,ListUserBookmarksForUserError,ListUserBookmarksForUserSuccessResponse,UserBookmarkListItem,
ListUserBookmarksForEntityPathInfo,ListUserBookmarksForEntityError,ListUserBookmarksForEntitySuccessResponse,UserBookmarkForEntityListItem,
)))]
GetUserRatingError,GetUserRatingResponse,UserRatingValue,UserRatingEntityType,
SetUserRatingError,SetUserRatingRequest,SetUserRatingResponse,
))
)]
pub struct ApiDoc;
@@ -13,8 +13,9 @@ use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCat
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::common::view_as::ViewAs;
use enums::common::visibility::Visibility;
use mysql_queries::queries::media_files::list::list_media_files::{list_media_files, ListMediaFilesArgs, ViewAs};
use mysql_queries::queries::media_files::list::list_media_files::{list_media_files, ListMediaFilesArgs};
use tokens::tokens::media_files::MediaFileToken;
use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight;
@@ -26,7 +27,7 @@ use crate::server_state::ServerState;
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListMediaFilesQueryParams {
pub sort_ascending: Option<bool>,
pub per_page: Option<usize>,
pub page_size: Option<usize>,
pub cursor: Option<String>,
pub cursor_is_reversed: Option<bool>,
pub filter_media_type: Option<MediaFileType>,
@@ -125,7 +126,7 @@ pub async fn list_media_files_handler(
};
// TODO(bt,2023-12-04): Enforce real maximums and defaults
let limit = query.per_page.unwrap_or(25);
let limit = query.page_size.unwrap_or(25);
let sort_ascending = query.sort_ascending.unwrap_or(false);
let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false);
@@ -144,7 +145,7 @@ pub async fn list_media_files_handler(
let view_as = if is_mod {
ViewAs::Moderator
} else {
ViewAs::NonModerator
ViewAs::AnotherUser
};
let query_results = list_media_files(ListMediaFilesArgs {
@@ -152,6 +153,7 @@ pub async fn list_media_files_handler(
maybe_filter_media_type: query.filter_media_type,
maybe_offset: cursor,
cursor_is_reversed,
sort_ascending,
view_as,
mysql_pool: &server_state.mysql_pool,
}).await;
@@ -13,8 +13,9 @@ use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCat
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::common::view_as::ViewAs;
use enums::common::visibility::Visibility;
use mysql_queries::queries::media_files::list::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs, ViewAs};
use mysql_queries::queries::media_files::list::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs};
use tokens::tokens::media_files::MediaFileToken;
use crate::http_server::common_responses::pagination_page::PaginationPage;
@@ -127,7 +128,6 @@ pub async fn list_media_files_for_user_handler(
};
// TODO(bt,2023-12-04): Enforce real maximums and defaults
let limit = query.page_size.unwrap_or(25);
let sort_ascending = query.sort_ascending.unwrap_or(false);
let page_size = query.page_size.unwrap_or_else(|| 25);
let page_index = query.page_index.unwrap_or_else(|| 0);
@@ -12,6 +12,7 @@ use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes;
use http_server_common::request::get_request_ip::get_request_ip;
use media::decode_basic_audio_info::decode_basic_audio_bytes_info;
use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes;
use mimetypes::mimetype_to_extension::mimetype_to_extension;
use mysql_queries::queries::media_files::create::insert_media_file_from_file_upload::{insert_media_file_from_file_upload, InsertMediaFileFromUploadArgs, UploadType};
use tokens::tokens::media_files::MediaFileToken;
@@ -194,6 +195,7 @@ pub async fn process_upload_media_file(
"audio/x-flac" /* .flac */ => Some(MediaFileType::Audio),
"audio/x-wav" /* .wav */ => Some(MediaFileType::Audio),
// Image
"image/gif" /* .gif */ => Some(MediaFileType::Image),
"image/jpeg" /* .jpg */ => Some(MediaFileType::Image),
"image/png" /* .png */ => Some(MediaFileType::Image),
"image/webp" /* .webp */ => Some(MediaFileType::Image),
@@ -277,30 +279,12 @@ pub async fn process_upload_media_file(
},
};
// TODO(bt,2023-12-20): Reasonable extensions.
let extension = match mime_type {
// Audio
"audio/aac" /* .aac */ => Some(".aac"),
"audio/m4a" /* .m4a */ => Some(".m4a"),
"audio/mpeg" /* .mp3 */ => Some(".mp3"),
"audio/ogg" /* .ogg */ => Some(".ogg"),
"audio/opus" /* .opus */ => Some(".opus"),
"audio/x-flac" /* .flac */ => Some(".flac"),
"audio/x-wav" /* .wav */ => Some(".wav"),
// Image
"image/jpeg" /* .jpg */ => Some(".jpg"),
"image/png" /* .png */ => Some(".png"),
"image/webp" /* .webp */ => Some(".webp"),
// Video
"video/mp4" /* .mp4 */ => Some(".mp4"),
"video/quicktime" /* .mov */ => Some(".mov"),
"video/webm" /* .webm */ => Some(".webm"),
_ => None,
};
let extension = mimetype_to_extension(mime_type)
.map(|extension| format!(".{extension}"));
const PREFIX : Option<&str> = Some("upload_");
let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, extension);
let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, extension.as_deref());
info!("Uploading media to bucket path: {}", public_upload_path.get_full_object_path_str());
@@ -327,7 +311,7 @@ pub async fn process_upload_media_file(
sha256_checksum: &hash,
public_bucket_directory_hash: public_upload_path.get_object_hash(),
maybe_public_bucket_prefix: PREFIX,
maybe_public_bucket_extension: extension,
maybe_public_bucket_extension: extension.as_deref(),
pool: &server_state.mysql_pool,
})
.await
@@ -1,10 +1,11 @@
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use utoipa::ToSchema;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub enum MediaFileUploadError {
BadInput(String),
NotAuthorized,
@@ -4,14 +4,15 @@ use std::sync::Arc;
use actix_multipart::Multipart;
use actix_web::{HttpRequest, HttpResponse, web};
use once_cell::sync::Lazy;
use utoipa::ToSchema;
use tokens::tokens::media_files::MediaFileToken;
use crate::http_server::endpoints::media_files::upload::process_upload_media_file::process_upload_media_file;
use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError;
use crate::server_state::ServerState;
#[derive(Serialize)]
#[derive(Serialize, ToSchema)]
pub struct UploadMediaSuccessResponse {
pub success: bool,
pub media_file_token: MediaFileToken,
@@ -33,9 +34,28 @@ static ALLOWED_MIME_TYPES : Lazy<HashSet<&'static str>> = Lazy::new(|| {
"video/mp4",
"video/webm",
//"video/quicktime",
// Image
"image/gif",
"image/jpeg",
"image/png",
"image/webp",
])
});
#[utoipa::path(
post,
path = "/v1/media_files/upload",
responses(
(status = 200, description = "Success Update", body = UploadMediaSuccessResponse),
(status = 400, description = "Bad input", body = MediaFileUploadError),
(status = 401, description = "Not authorized", body = MediaFileUploadError),
(status = 429, description = "Too many requests", body = MediaFileUploadError),
(status = 500, description = "Server error", body = MediaFileUploadError),
),
params(
("request" = (), description = "Ask Brandon. This is form-multipart."),
)
)]
pub async fn upload_media_file_handler(
http_request: HttpRequest,
server_state: web::Data<Arc<ServerState>>,
@@ -1,7 +1,3 @@
// NB: Incrementally getting rid of build warnings...
#![forbid(unused_imports)]
#![forbid(unused_mut)]
#![forbid(unused_variables)]
use std::fmt;
use std::sync::Arc;
@@ -14,7 +10,7 @@ use chrono::{DateTime, Utc};
use log::warn;
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type};
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{ list_user_bookmarks_by_maybe_entity_type};
use tokens::tokens::user_bookmarks::UserBookmarkToken;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
@@ -100,36 +96,17 @@ pub async fn list_user_bookmarks_for_session_handler(
})?
.ok_or(ListUserBookmarksError::NotAuthorizedError)?;
let query_results = match query.maybe_scoped_entity_type {
None => list_user_bookmarks(&user_session.username, &server_state.mysql_pool).await,
Some(entity_type) =>
list_user_user_bookmarks_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool)
.await,
};
// let query_results = match query.maybe_scoped_entity_type {
// None => list_user_bookmarks(&user_session.username, &server_state.mysql_pool).await,
// Some(entity_type) =>
// list_user_user_bookmarks_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool)
// .await,
// };
let user_bookmarks = match query_results {
Ok(results) => results,
Err(e) => {
warn!("Query error: {:?}", e);
return Err(ListUserBookmarksError::ServerError);
}
};
let response = ListUserBookmarksSuccessResponse {
success: true,
user_bookmarks: user_bookmarks.into_iter()
.map(|user_bookmark| UserBookmark {
token: user_bookmark.token,
details: UserBookmarkDetails {
entity_type: user_bookmark.entity_type,
entity_token: user_bookmark.entity_token,
maybe_summary_text: None,
maybe_thumbnail_url: None,
},
created_at: user_bookmark.created_at,
updated_at: user_bookmark.updated_at,
})
.collect(),
user_bookmarks: Vec::new()
};
let body = serde_json::to_string(&response)
@@ -15,9 +15,9 @@ use log::warn;
use utoipa::{IntoParams, ToSchema};
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type};
use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks_by_maybe_entity_type, ListUserBookmarksForUserArgs};
use tokens::tokens::user_bookmarks::UserBookmarkToken;
use crate::http_server::common_responses::pagination_page::PaginationPage;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::server_state::ServerState;
@@ -28,13 +28,17 @@ pub struct ListUserBookmarksPathInfo {
#[derive(Deserialize, ToSchema, IntoParams)]
pub struct ListUserBookmarksQueryData {
sort_ascending: Option<bool>,
page_size: Option<usize>,
page_index: Option<usize>,
maybe_scoped_entity_type: Option<UserBookmarkEntityType>,
}
#[derive(Serialize, ToSchema)]
pub struct ListUserBookmarksForUserSuccessResponse {
pub success: bool,
pub user_bookmarks: Vec<UserBookmarkListItem>,
pub results: Vec<UserBookmarkListItem>,
pub pagination: PaginationPage,
}
#[derive(Serialize, ToSchema)]
@@ -101,21 +105,37 @@ responses(
),
)]
pub async fn list_user_bookmarks_for_user_handler(
_http_request: HttpRequest,
http_request: HttpRequest,
path: Path<ListUserBookmarksPathInfo>,
query: Query<ListUserBookmarksQueryData>,
server_state: web::Data<Arc<ServerState>>
) -> Result<HttpResponse, ListUserBookmarksForUserError>
{
let _maybe_user_session = server_state
.session_checker
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
ListUserBookmarksForUserError::ServerError
})?;
let query_results = match query.maybe_scoped_entity_type {
None => list_user_bookmarks(&path.username, &server_state.mysql_pool).await,
Some(entity_type) =>
list_user_user_bookmarks_by_entity_type(&path.username, entity_type, &server_state.mysql_pool)
.await,
};
let user_bookmarks = match query_results {
let sort_ascending = query.sort_ascending.unwrap_or(false);
let page_size = query.page_size.unwrap_or_else(|| 25);
let page_index = query.page_index.unwrap_or_else(|| 0);
let query_results =
list_user_bookmarks_by_maybe_entity_type(ListUserBookmarksForUserArgs{
username: path.username.as_ref(),
maybe_filter_entity_type: query.maybe_scoped_entity_type.clone(),
sort_ascending,
page_size,
page_index,
mysql_pool: &server_state.mysql_pool,
}).await;
let results_page = match query_results {
Ok(results) => results,
Err(e) => {
warn!("Query error: {:?}", e);
@@ -125,7 +145,7 @@ pub async fn list_user_bookmarks_for_user_handler(
let response = ListUserBookmarksForUserSuccessResponse {
success: true,
user_bookmarks: user_bookmarks.into_iter()
results: results_page.results.into_iter()
.map(|user_bookmark| UserBookmarkListItem {
token: user_bookmark.token,
details: UserBookmarkDetailsForUserList {
@@ -140,6 +160,10 @@ pub async fn list_user_bookmarks_for_user_handler(
updated_at: user_bookmark.updated_at,
})
.collect(),
pagination: PaginationPage{
current: results_page.current_page,
total_page_count: results_page.total_page_count,
}
};
let body = serde_json::to_string(&response)
@@ -148,4 +172,4 @@ pub async fn list_user_bookmarks_for_user_handler(
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
}
@@ -3,6 +3,7 @@ use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, ResponseError, web};
use actix_web::http::StatusCode;
use log::{error, info};
use utoipa::ToSchema;
use enums::by_table::user_ratings::entity_type::UserRatingEntityType;
use enums::by_table::user_ratings::rating_value::UserRatingValue;
@@ -19,7 +20,7 @@ use crate::server_state::ServerState;
// =============== Request ===============
/// For the URL PathInfo
#[derive(Deserialize)]
#[derive(Deserialize, ToSchema)]
pub struct GetUserRatingPath {
/// The type of the entity being rated.
pub entity_type: UserRatingEntityType,
@@ -30,7 +31,7 @@ pub struct GetUserRatingPath {
// =============== Success Response ===============
#[derive(Serialize)]
#[derive(Serialize, ToSchema)]
pub struct GetUserRatingResponse {
pub success: bool,
@@ -41,7 +42,7 @@ pub struct GetUserRatingResponse {
// =============== Error Response ===============
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub enum GetUserRatingError {
BadInput(String),
NotAuthorized,
@@ -71,6 +72,21 @@ impl std::fmt::Display for GetUserRatingError {
// =============== Handler ===============
#[utoipa::path(
get,
path = "/v1/user_rating/view/{entity_type}/{entity_token}",
params(
("entity_type", description = "The type of the entity being rated."),
("entity_token", description = "Entity token"),
),
responses(
(status = 200, description = "List User Bookmarks", body = GetUserRatingResponse),
(status = 400, description = "Bad input", body = GetUserRatingError),
(status = 401, description = "Not authorized", body = GetUserRatingError),
(status = 500, description = "Server error", body = GetUserRatingError),
),
)]
pub async fn get_user_rating_handler(
http_request: HttpRequest,
path: web::Path<GetUserRatingPath>,
@@ -3,6 +3,7 @@ use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, ResponseError, web};
use actix_web::http::StatusCode;
use log::{error, info, warn};
use utoipa::ToSchema;
use enums::by_table::user_ratings::entity_type::UserRatingEntityType;
use enums::by_table::user_ratings::rating_value::UserRatingValue;
@@ -22,7 +23,7 @@ use crate::server_state::ServerState;
// =============== Request ===============
#[derive(Deserialize)]
#[derive(Deserialize, ToSchema)]
pub struct SetUserRatingRequest {
/// The type of the entity being rated.
pub entity_type: UserRatingEntityType,
@@ -35,14 +36,14 @@ pub struct SetUserRatingRequest {
// =============== Success Response ===============
#[derive(Serialize)]
#[derive(Serialize, ToSchema)]
pub struct SetUserRatingResponse {
pub success: bool,
}
// =============== Error Response ===============
#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, ToSchema)]
pub enum SetUserRatingError {
BadInput(String),
NotAuthorized,
@@ -72,6 +73,17 @@ impl std::fmt::Display for SetUserRatingError {
// =============== Handler ===============
#[utoipa::path(
post,
path = "/v1/user_rating/rate",
request_body = SetUserRatingRequest,
responses(
(status = 200, description = "Set user rating", body = SetUserRatingResponse),
(status = 400, description = "Bad input", body = SetUserRatingError),
(status = 401, description = "Not authorized", body = SetUserRatingError),
(status = 500, description = "Server error", body = SetUserRatingError),
),
)]
pub async fn set_user_rating_handler(
http_request: HttpRequest,
request: web::Json<SetUserRatingRequest>,
@@ -1,119 +0,0 @@
use std::collections::HashSet;
use std::sync::Arc;
use actix_multipart::Multipart;
use actix_web::{HttpRequest, HttpResponse, web};
use enums::by_table::model_weights::weights_category::WeightsCategory;
use enums::by_table::model_weights::weights_types::WeightsType;
use mysql_queries::queries::model_weights::create_weight::{self, create_weight};
use once_cell::sync::Lazy;
use tokens::tokens::model_weights::ModelWeightToken;
use crate::http_server::endpoints::media_uploads::common::upload_error::UploadError;
use crate::server_state::ServerState;
use log::{error, info, warn};
use buckets::public::weight_uploads::original_file::WeightUploadOriginalFilePath;
use enums::by_table::media_uploads::media_upload_source::MediaUploadSource;
use enums::by_table::media_uploads::media_upload_type::MediaUploadType;
use enums::common::visibility::Visibility;
use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes;
use http_server_common::request::get_request_ip::get_request_ip;
use media::decode_basic_audio_info::decode_basic_audio_bytes_info;
use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes;
use mysql_queries::queries::media_uploads::get_media_upload_by_uuid::get_media_upload_by_uuid_with_connection;
use mysql_queries::queries::media_uploads::insert_media_upload::{Args, insert_media_upload};
use crate::http_server::endpoints::media_uploads::common::drain_multipart_request::{drain_multipart_request, MediaSource};
use crate::validations::validate_idempotency_token_format::validate_idempotency_token_format;
use utoipa::ToSchema;
#[derive(Serialize,ToSchema)]
pub struct UploadWeightsSuccessResponse {
pub success: bool,
pub upload_token: ModelWeightToken,
}
static ALLOWED_MIME_TYPES : Lazy<HashSet<&'static str>> = Lazy::new(|| {
HashSet::from([
"binary/octet-stream",
])
});
// pub async fn create_weight_handler(
// http_request: HttpRequest,
// server_state: web::Data<Arc<ServerState>>,
// mut multipart_payload: Multipart,
// ) -> Result<HttpResponse, UploadError> {
// let weight_upload_token = response.to_model_token();
// let response: UploadWeightsSuccessResponse = UploadWeightsSuccessResponse {
// success: true,
// upload_token: weight_upload_token,
// };
// let body = serde_json::to_string(&response)
// .map_err(|e| UploadError::ServerError)?;
// return Ok(HttpResponse::Ok()
// .content_type("application/json")
// .body(body));
// }
// pub enum SuccessCase {
// WeightAlreadyUploaded {
// existing_upload_token: ModelWeightToken,
// },
// WeightSuccessfullyUploaded {
// upload_token: ModelWeightToken,
// }
// }
// impl SuccessCase {
// pub fn to_model_token(self) -> ModelWeightToken {
// match self {
// SuccessCase::WeightAlreadyUploaded { existing_upload_token } => existing_upload_token,
// SuccessCase::WeightSuccessfullyUploaded { upload_token } => upload_token,
// }
// }
// }
// let token = create_weight(CreateModelWeightsArgs {
// token: &ModelWeightToken::generate(),
// weights_type: WeightsType::LoRA, // to do parse multi part for this
// weights_category: WeightsCategory::ImageGeneration,
// title: upload_weights_request.file_name.as_deref(),
// maybe_thumbnail_token: &ThumbnailToken::generate(),
// description_markdown: "",
// description_rendered_html: "",
// creator_user_token: maybe_user_token.as_str(),
// creator_ip_address: &ip_address,
// creator_set_visibility,
// maybe_last_update_user_token: "",
// original_download_url: "",
// original_filename: upload_weights_request.file_name.as_deref(),
// file_size_bytes: file_size_bytes as i32,
// file_checksum_sha2: hash,
// private_bucket_hash: private_bucket_hash,
// maybe_private_bucket_prefix: None,
// maybe_private_bucket_extension: None,
// cached_user_ratings_total_count: 0,
// cached_user_ratings_positive_count: 0,
// cached_user_ratings_negative_count: 0,
// maybe_cached_user_ratings_ratio: None,
// version: 0,
// mysql_pool: &server_state.mysql_pool,
// }).await
// .map_err(|e| {
// error!("Error creating weights upload: {:?}", e);
// UploadError::ServerError
// })?;
// info!("new weights upload id: {} token: {:?}", record_id, &token);
// Ok()
// }
@@ -26,8 +26,11 @@ pub struct GetWeightResponse {
title: String,
weights_type: WeightsType,
weights_category: WeightsCategory,
maybe_thumbnail_token: Option<String>,
// TODO(bt,2023-12-24): Migrated the column. We should return nullables, but I don't want to break the frontend
description_markdown: String,
// TODO(bt,2023-12-24): Migrated the column. We should return nullables, but I don't want to break the frontend
description_rendered_html: String,
creator: UserDetailsLight,
@@ -36,8 +39,9 @@ pub struct GetWeightResponse {
file_size_bytes: i32,
file_checksum_sha2: String,
/// If an avatar is set, this is the path to the asset.
maybe_avatar_public_bucket_path: Option<String>,
/// Cover images are small descriptive images that can be set for any model.
/// If a cover image is set, this is the path to the asset.
maybe_cover_image_public_bucket_path: Option<String>,
cached_user_ratings_negative_count: u32,
cached_user_ratings_positive_count: u32,
@@ -144,13 +148,13 @@ pub async fn get_weight_handler(
return Err(GetWeightError::NotAuthorized);
}
let maybe_avatar = weight.maybe_avatar_public_bucket_hash
let maybe_cover_image = weight.maybe_cover_image_public_bucket_hash
.as_deref()
.map(|hash| {
MediaFileBucketPath::from_object_hash(
hash,
weight.maybe_public_bucket_prefix.as_deref(),
weight.maybe_public_bucket_extension.as_deref())
weight.maybe_cover_image_public_bucket_prefix.as_deref(),
weight.maybe_cover_image_public_bucket_extension.as_deref())
.get_full_object_path_str()
.to_string()
});
@@ -168,10 +172,10 @@ pub async fn get_weight_handler(
title: weight.title,
weights_type: weight.weights_type,
weights_category: weight.weights_category,
maybe_thumbnail_token: weight.maybe_thumbnail_token,
description_markdown: weight.description_markdown,
description_rendered_html: weight.description_rendered_html,
maybe_avatar_public_bucket_path: maybe_avatar,
// TODO(bt,2023-12-24): Migrated the column. We should return nullable fields, but I don't want to break the frontend
description_markdown: weight.maybe_description_markdown.unwrap_or_else(|| "".to_string()),
description_rendered_html: weight.maybe_description_rendered_html.unwrap_or_else(|| "".to_string()),
maybe_cover_image_public_bucket_path: maybe_cover_image,
creator,
creator_set_visibility: weight.creator_set_visibility,
file_size_bytes: weight.file_size_bytes,
@@ -6,7 +6,7 @@ use actix_web::http::StatusCode;
use chrono::{DateTime, Utc};
use log::{info, warn};
use rand::Rng;
use utoipa::ToSchema;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use enums::by_table::model_weights::{
weights_category::WeightsCategory,
@@ -16,27 +16,32 @@ use enums::common::visibility::Visibility;
use mysql_queries::queries::model_weights::list::list_weights_query_builder::ListWeightsQueryBuilder;
use tokens::tokens::model_weights::ModelWeightToken;
use tokens::tokens::users::UserToken;
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::server_state::ServerState;
use utoipa::ToSchema;
use crate::http_server::common_responses::pagination_cursors::PaginationCursors;
#[derive(Deserialize,ToSchema)]
pub struct ListAvailableWeightsQuery {
pub sort_ascending: Option<bool>,
pub page_size: u16,
pub page_index : u16,
pub page_size: Option<u16>,
pub username: Option<String>,
pub weights_type: Option<String>,
pub weights_category: Option<String>,
pub cursor_is_reversed: Option<bool>,
pub cursor: Option<String>,
}
#[derive(Serialize,ToSchema)]
pub struct ListAvailableWeightsSuccessResponse {
pub success: bool,
pub weights: Vec<ModelWeightForList>,
pub page_size: u16,
pub page_index : u16,
pub cursor_next: Option<String>,
pub cursor_previous: Option<String>,
pub results: Vec<ModelWeightForList>,
pub pagination: PaginationCursors,
}
#[derive(Serialize,ToSchema)]
@@ -48,12 +53,16 @@ pub struct ModelWeightForList {
pub title: String,
pub maybe_thumbnail_token: Option<String>,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//pub description_markdown: String,
//pub description_rendered_html: String,
pub description_markdown: String,
pub description_rendered_html: String,
/// Cover images are small descriptive images that can be set for any model.
/// If a cover image is set, this is the path to the asset.
pub maybe_cover_image_public_bucket_path: Option<String>,
pub creator_user_token: UserToken,
pub creator: UserDetailsLight,
pub creator_set_visibility: Visibility,
pub file_size_bytes: i32,
@@ -64,8 +73,6 @@ pub struct ModelWeightForList {
pub cached_user_ratings_negative_count: u32,
pub maybe_cached_user_ratings_ratio: Option<f32>,
pub version: i32,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
@@ -125,20 +132,28 @@ pub async fn list_available_weights_handler(
})?;
let mut is_mod = false;
let user_session = match maybe_user_session {
match maybe_user_session {
None => {},
Some(session) => {
is_mod = session.can_ban_users;
session
}
None => {
info!("not logged in");
return Err(ListWeightError::NotAuthorized);
}
};
let limit = query.page_size;
let limit = query.page_size.unwrap_or(25);
let sort_ascending = query.sort_ascending.unwrap_or(false);
let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false);
let cursor = if let Some(cursor) = query.cursor.as_deref() {
let cursor = server_state.sort_key_crypto.decrypt_id(cursor)
.map_err(|e| {
warn!("crypto error: {:?}", e);
ListWeightError::ServerError
})?;
Some(cursor)
} else {
None
};
let include_user_hidden = is_mod;
@@ -173,6 +188,7 @@ pub async fn list_available_weights_handler(
let mut query_builder = ListWeightsQueryBuilder::new()
.sort_ascending(sort_ascending)
.cursor_is_reversed(cursor_is_reversed)
.weights_category(weights_category)
.weights_type(weights_type)
.scope_creator_username(None)
@@ -180,7 +196,7 @@ pub async fn list_available_weights_handler(
.include_user_deleted_results(is_mod)
.include_mod_deleted_results(is_mod)
.limit(limit)
.offset(Some((query.page_index as u64) * (query.page_size as u64)));
.offset(cursor);
let query_results = query_builder.perform_query_for_page(&server_state.mysql_pool).await;
@@ -221,45 +237,61 @@ pub async fn list_available_weights_handler(
// generate parse a response
let response = ListAvailableWeightsSuccessResponse {
success: true,
weights: weights_page.weights.into_iter()
.map(|weights| ModelWeightForList {
weight_token: weights.token,
title: weights.title,
weights_type: weights.weights_type,
weights_category: weights.weights_category,
results: weights_page.weights.into_iter()
.map(|weight| {
maybe_thumbnail_token:weights.maybe_thumbnail_token,
description_markdown: weights.description_markdown,
description_rendered_html: weights.description_rendered_html,
let maybe_cover_image = weight.maybe_cover_image_public_bucket_hash
.as_deref()
.map(|hash| {
MediaFileBucketPath::from_object_hash(
hash,
weight.maybe_cover_image_public_bucket_prefix.as_deref(),
weight.maybe_cover_image_public_bucket_extension.as_deref())
.get_full_object_path_str()
.to_string()
});
creator_user_token: weights.creator_user_token,
creator_set_visibility: weights.creator_set_visibility,
ModelWeightForList {
weight_token: weight.token,
title: weight.title,
weights_type: weight.weights_type,
weights_category: weight.weights_category,
file_size_bytes:weights.file_size_bytes,
file_checksum_sha2: weights.file_checksum_sha2,
maybe_cover_image_public_bucket_path: maybe_cover_image,
cached_user_ratings_total_count: weights.cached_user_ratings_total_count,
cached_user_ratings_positive_count: weights.cached_user_ratings_positive_count,
cached_user_ratings_negative_count: weights.cached_user_ratings_negative_count,
maybe_cached_user_ratings_ratio: weights.maybe_cached_user_ratings_ratio,
creator: UserDetailsLight::from_db_fields(
&weight.creator_user_token,
&weight.creator_username,
&weight.creator_display_name,
&weight.creator_email_gravatar_hash
),
creator_set_visibility: weight.creator_set_visibility,
version: weights.version,
file_size_bytes: weight.file_size_bytes,
file_checksum_sha2: weight.file_checksum_sha2,
created_at: weights.created_at,
updated_at: weights.updated_at,
cached_user_ratings_total_count: weight.cached_user_ratings_total_count,
cached_user_ratings_positive_count: weight.cached_user_ratings_positive_count,
cached_user_ratings_negative_count: weight.cached_user_ratings_negative_count,
maybe_cached_user_ratings_ratio: weight.maybe_cached_user_ratings_ratio,
creator_username: weights.creator_username,
creator_display_name: weights.creator_display_name,
creator_email_gravatar_hash: weights.creator_email_gravatar_hash,
created_at: weight.created_at,
updated_at: weight.updated_at,
// TODO: FIX THIS when we align again.
bookmarks: random_bool,
likes: rng.gen_range(0..1000),
creator_username: weight.creator_username,
creator_display_name: weight.creator_display_name,
creator_email_gravatar_hash: weight.creator_email_gravatar_hash,
// TODO: FIX THIS when we align again.
bookmarks: random_bool,
likes: rng.gen_range(0..1000),
}
}).collect::<Vec<_>>(),
cursor_next,
cursor_previous,
page_index: query.page_index,
page_size: query.page_size
pagination: PaginationCursors {
maybe_next: cursor_next,
maybe_previous: cursor_previous,
cursor_is_reversed,
},
};
let body = serde_json::to_string(&response)
@@ -7,6 +7,7 @@ use chrono::{DateTime, Utc};
use log::{debug, error, warn};
use r2d2_redis::redis::Commands;
use utoipa::ToSchema;
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use enums::by_table::model_weights::{
weights_category::WeightsCategory,
@@ -33,10 +34,12 @@ pub struct ModelWeightForList {
pub title: String,
pub maybe_thumbnail_token: Option<String>,
pub creator: UserDetailsLight,
/// Cover images are small descriptive images that can be set for any model.
/// If a cover image is set, this is the path to the asset.
pub maybe_cover_image_public_bucket_path: Option<String>,
pub cached_user_ratings_total_count: u32,
pub cached_user_ratings_positive_count: u32,
pub cached_user_ratings_negative_count: u32,
@@ -125,24 +128,38 @@ pub async fn list_featured_weights_handler(
let response = ListFeaturedWeightsSuccessResponse {
success: true,
weights: weights.into_iter()
.map(|w| ModelWeightForList {
weight_token: w.token,
title: w.title,
weights_type: w.weights_type,
weights_category: w.weights_category,
maybe_thumbnail_token: w.maybe_thumbnail_token,
creator: UserDetailsLight::from_db_fields(
&w.creator_user_token,
&w.creator_username,
&w.creator_display_name,
&w.creator_email_gravatar_hash
),
cached_user_ratings_total_count: w.cached_user_ratings_total_count,
cached_user_ratings_positive_count: w.cached_user_ratings_positive_count,
cached_user_ratings_negative_count: w.cached_user_ratings_negative_count,
maybe_cached_user_ratings_ratio: w.maybe_cached_user_ratings_ratio,
created_at: w.created_at,
updated_at: w.updated_at,
.map(|w| {
let maybe_cover_image = w.maybe_cover_image_public_bucket_hash
.as_deref()
.map(|hash| {
MediaFileBucketPath::from_object_hash(
hash,
w.maybe_cover_image_public_bucket_prefix.as_deref(),
w.maybe_cover_image_public_bucket_extension.as_deref())
.get_full_object_path_str()
.to_string()
});
ModelWeightForList {
weight_token: w.token,
title: w.title,
weights_type: w.weights_type,
weights_category: w.weights_category,
maybe_cover_image_public_bucket_path: maybe_cover_image,
creator: UserDetailsLight::from_db_fields(
&w.creator_user_token,
&w.creator_username,
&w.creator_display_name,
&w.creator_email_gravatar_hash
),
cached_user_ratings_total_count: w.cached_user_ratings_total_count,
cached_user_ratings_positive_count: w.cached_user_ratings_positive_count,
cached_user_ratings_negative_count: w.cached_user_ratings_negative_count,
maybe_cached_user_ratings_ratio: w.maybe_cached_user_ratings_ratio,
created_at: w.created_at,
updated_at: w.updated_at,
}
}).collect::<Vec<_>>(),
};
@@ -8,6 +8,8 @@ use actix_web::web::{Path, Query};
use chrono::{DateTime, Utc};
use log::warn;
use utoipa::{IntoParams, ToSchema};
use buckets::public::media_files::bucket_file_path::MediaFileBucketPath;
use enums::common::view_as::ViewAs;
use enums::common::visibility::Visibility;
use mysql_queries::queries::model_weights::list::list_weights_by_user::{list_weights_by_creator_username, ListWeightsForUserArgs};
@@ -26,16 +28,22 @@ pub struct Weight {
creator: UserDetailsLight,
creator_set_visibility: Visibility,
maybe_thumbnail_token: Option<String>,
description_markdown: String,
description_rendered_html: String,
// TODO(bt,2023-12-24): These aren't really appropriate for a list endpoint.
// Hopefully we don't break the frontend by omitting these.
//description_markdown: String,
//description_rendered_html: String,
file_size_bytes: i32,
file_checksum_sha2: String,
/// Cover images are small descriptive images that can be set for any model.
/// If a cover image is set, this is the path to the asset.
maybe_cover_image_public_bucket_path: Option<String>,
cached_user_ratings_total_count: u32,
cached_user_ratings_positive_count: u32,
cached_user_ratings_negative_count: u32,
maybe_cached_user_ratings_ratio: Option<f32>,
cached_user_ratings_last_updated_at: DateTime<Utc>,
@@ -112,17 +120,27 @@ pub async fn list_weights_by_user_handler(
ListWeightsByUserError::ServerError
})?;
let user_session = match maybe_user_session {
Some(session) => session,
None => {
warn!("not logged in");
return Err(ListWeightsByUserError::NotAuthorized);
}
let mut is_author = false;
let mut is_mod = false;
match maybe_user_session {
None => {},
Some(session) => {
is_author = session.username == path.username;
is_mod = session.can_ban_users;
},
};
let view_as = if is_author {
ViewAs::Author
} else if is_mod {
ViewAs::Moderator
} else {
ViewAs::AnotherUser
};
let username = path.username.as_ref();
let creator_user_token = user_session.user_token.clone();
let is_mod = user_session.can_ban_users;
let limit = query.page_size.unwrap_or(25);
let sort_ascending = query.sort_ascending.unwrap_or(false);
let page_size = query.page_size.unwrap_or_else(|| 25);
@@ -133,8 +151,8 @@ pub async fn list_weights_by_user_handler(
creator_username: username,
page_size,
page_index,
can_see_deleted: is_mod,
sort_ascending,
view_as,
mysql_pool: &server_state.mysql_pool,
}
).await.map_err(|e| {
@@ -151,6 +169,18 @@ pub async fn list_weights_by_user_handler(
};
let weights:Vec<Weight> = results_page.records.into_iter().map(|weight| {
let maybe_cover_image = weight.maybe_cover_image_public_bucket_hash
.as_deref()
.map(|hash| {
MediaFileBucketPath::from_object_hash(
hash,
weight.maybe_cover_image_public_bucket_prefix.as_deref(),
weight.maybe_cover_image_public_bucket_extension.as_deref())
.get_full_object_path_str()
.to_string()
});
Weight {
weight_token: weight.token,
title: weight.title,
@@ -162,9 +192,9 @@ pub async fn list_weights_by_user_handler(
&weight.creator_display_name,
&weight.creator_email_gravatar_hash,
),
maybe_thumbnail_token: weight.maybe_thumbnail_token,
description_markdown: weight.description_markdown,
description_rendered_html: weight.description_rendered_html,
maybe_cover_image_public_bucket_path: maybe_cover_image,
//description_markdown: weight.maybe_description_markdown,
//description_rendered_html: weight.maybe_description_rendered_html,
file_size_bytes: weight.file_size_bytes,
file_checksum_sha2: weight.file_checksum_sha2,
cached_user_ratings_total_count: weight.cached_user_ratings_total_count,
@@ -178,23 +208,10 @@ pub async fn list_weights_by_user_handler(
}
}).collect();
let final_weights:Vec<Weight>;
// if it's not the user ... then only show public weights else show private and public
if creator_user_token != user_session.user_token {
final_weights = weights.into_iter().filter(|weight| {
weight.creator_set_visibility == Visibility::Public
}).collect();
}
else {
final_weights = weights;
}
let response: ListWeightsByUserSuccessResponse = ListWeightsByUserSuccessResponse {
success: true,
results: final_weights,
results: weights,
pagination: PaginationPage {
current: results_page.current_page,
total_page_count: results_page.total_page_count,
@@ -3,7 +3,5 @@ pub mod get_weight;
pub mod list_available_weights;
pub mod list_featured_weights;
pub mod list_weights_by_user;
pub mod set_model_weight_avatar;
pub mod update_weight;
// pub mod create_weight; this is a private api call internally
// pub mod drain_multipart_weights_request;
pub mod set_model_weight_cover_image;
pub mod update_weight;
@@ -6,6 +6,7 @@ use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::Path;
use log::warn;
use utoipa::ToSchema;
use enums::by_table::media_files::media_file_type::MediaFileType;
use enums::common::visibility::Visibility;
@@ -13,46 +14,46 @@ use http_server_common::request::get_request_ip::get_request_ip;
use http_server_common::response::response_success_helpers::simple_json_success;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use mysql_queries::queries::media_files::get_media_file::get_media_file;
use mysql_queries::queries::model_weights::edit::set_model_weight_avatar::{set_model_weight_avatar, UpdateArgs};
use mysql_queries::queries::model_weights::edit::set_model_weight_cover_image::{set_model_weight_cover_image, UpdateArgs};
use mysql_queries::queries::model_weights::get_weight::get_weight_by_token;
use tokens::tokens::media_files::MediaFileToken;
use tokens::tokens::model_weights::ModelWeightToken;
use crate::server_state::ServerState;
#[derive(Deserialize)]
pub struct SetModelWeightAvatarRequest {
pub avatar_media_file_token: Option<MediaFileToken>,
#[derive(Deserialize, ToSchema)]
pub struct SetModelWeightCoverImageRequest {
pub cover_image_media_file_token: Option<MediaFileToken>,
}
#[derive(Serialize)]
pub struct SetModelWeightAvatarResponse {
#[derive(Serialize, ToSchema)]
pub struct SetModelWeightCoverImageResponse {
pub success: bool,
}
/// For the URL PathInfo
#[derive(Deserialize)]
pub struct SetModelWeightAvatarPathInfo {
#[derive(Deserialize, ToSchema)]
pub struct SetModelWeightCoverImagePathInfo {
token: ModelWeightToken,
}
// =============== Error Response ===============
#[derive(Debug, Serialize)]
pub enum SetModelWeightAvatarError {
#[derive(Debug, Serialize, ToSchema)]
pub enum SetModelWeightCoverImageError {
BadInput(String),
NotFound,
NotAuthorized,
ServerError,
}
impl ResponseError for SetModelWeightAvatarError {
impl ResponseError for SetModelWeightCoverImageError {
fn status_code(&self) -> StatusCode {
match *self {
SetModelWeightAvatarError::BadInput(_) => StatusCode::BAD_REQUEST,
SetModelWeightAvatarError::NotFound => StatusCode::NOT_FOUND,
SetModelWeightAvatarError::NotAuthorized => StatusCode::UNAUTHORIZED,
SetModelWeightAvatarError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
SetModelWeightCoverImageError::BadInput(_) => StatusCode::BAD_REQUEST,
SetModelWeightCoverImageError::NotFound => StatusCode::NOT_FOUND,
SetModelWeightCoverImageError::NotAuthorized => StatusCode::UNAUTHORIZED,
SetModelWeightCoverImageError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
@@ -62,7 +63,7 @@ impl ResponseError for SetModelWeightAvatarError {
}
// NB: Not using derive_more::Display since Clion doesn't understand it.
impl fmt::Display for SetModelWeightAvatarError {
impl fmt::Display for SetModelWeightCoverImageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
@@ -70,11 +71,25 @@ impl fmt::Display for SetModelWeightAvatarError {
// =============== Handler ===============
pub async fn set_model_weight_avatar_handler(
#[utoipa::path(
post,
path = "/v1/weights/weight/{weight_token}/cover_image",
responses(
(status = 200, description = "Success Update", body = SetModelWeightCoverImageResponse),
(status = 400, description = "Bad input", body = SetModelWeightCoverImageError),
(status = 401, description = "Not authorized", body = SetModelWeightCoverImageError),
(status = 500, description = "Server error", body = SetModelWeightCoverImageError),
),
params(
("request" = SetModelWeightCoverImageRequest, description = "Payload for Request"),
("path" = SetModelWeightCoverImagePathInfo, description = "Path for Request")
)
)]
pub async fn set_model_weight_cover_image_handler(
http_request: HttpRequest,
path: Path<SetModelWeightAvatarPathInfo>,
request: web::Json<SetModelWeightAvatarRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetModelWeightAvatarError>
path: Path<SetModelWeightCoverImagePathInfo>,
request: web::Json<SetModelWeightCoverImageRequest>,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SetModelWeightCoverImageError>
{
let maybe_user_session = server_state
.session_checker
@@ -82,14 +97,14 @@ pub async fn set_model_weight_avatar_handler(
.await
.map_err(|e| {
warn!("Session checker error: {:?}", e);
SetModelWeightAvatarError::ServerError
SetModelWeightCoverImageError::ServerError
})?;
let user_session = match maybe_user_session {
Some(session) => session,
None => {
warn!("not logged in");
return Err(SetModelWeightAvatarError::NotAuthorized);
return Err(SetModelWeightCoverImageError::NotAuthorized);
}
};
@@ -107,11 +122,11 @@ pub async fn set_model_weight_avatar_handler(
Ok(Some(model_weight)) => model_weight,
Ok(None) => {
warn!("Model weight not found: {:?}", &path.token);
return Err(SetModelWeightAvatarError::NotFound);
return Err(SetModelWeightCoverImageError::NotFound);
},
Err(err) => {
warn!("Error looking up model_weights : {:?}", err);
return Err(SetModelWeightAvatarError::ServerError);
return Err(SetModelWeightCoverImageError::ServerError);
}
};
@@ -119,18 +134,18 @@ pub async fn set_model_weight_avatar_handler(
if !is_creator && !is_mod {
warn!("user is not allowed to edit this media_file: {}", user_session.user_token);
return Err(SetModelWeightAvatarError::NotAuthorized);
return Err(SetModelWeightCoverImageError::NotAuthorized);
}
let mut maybe_set_media_file_token = None;
let delete_avatar = request.avatar_media_file_token
let delete_cover_image = request.cover_image_media_file_token
.as_ref()
.map(|token| token.as_str().trim().is_empty())
.unwrap_or(true);
if !delete_avatar {
if let Some(media_file_token) = &request.avatar_media_file_token {
if !delete_cover_image {
if let Some(media_file_token) = &request.cover_image_media_file_token {
let media_file_lookup_result = get_media_file(
&media_file_token,
false,
@@ -141,17 +156,17 @@ pub async fn set_model_weight_avatar_handler(
Ok(Some(model_weight)) => model_weight,
Ok(None) => {
warn!("Media file not found: {:?}", media_file_token);
return Err(SetModelWeightAvatarError::NotFound);
return Err(SetModelWeightCoverImageError::NotFound);
},
Err(err) => {
warn!("Error looking up model_weights : {:?}", err);
return Err(SetModelWeightAvatarError::ServerError);
return Err(SetModelWeightCoverImageError::ServerError);
}
};
if media_file.creator_set_visibility != Visibility::Public
|| media_file.media_type != MediaFileType::Image {
return Err(SetModelWeightAvatarError::BadInput("Invalid media file token.".to_string()));
return Err(SetModelWeightCoverImageError::BadInput("Invalid media file token.".to_string()));
}
maybe_set_media_file_token = Some(media_file.token);
@@ -161,9 +176,9 @@ pub async fn set_model_weight_avatar_handler(
// TODO(bt,2023-12-21): DB needs a column, or we need an ip audit log
let _ip_address = get_request_ip(&http_request);
let query_result = set_model_weight_avatar(UpdateArgs {
let query_result = set_model_weight_cover_image(UpdateArgs {
model_weight_token: &path.token,
maybe_avatar_media_file_token: maybe_set_media_file_token.as_ref(),
maybe_cover_image_media_file_token: maybe_set_media_file_token.as_ref(),
mysql_pool: &server_state.mysql_pool,
}).await;
@@ -171,7 +186,7 @@ pub async fn set_model_weight_avatar_handler(
Ok(_) => {},
Err(err) => {
warn!("Update MediaFile DB error: {:?}", err);
return Err(SetModelWeightAvatarError::ServerError);
return Err(SetModelWeightCoverImageError::ServerError);
}
};
@@ -1,27 +1,31 @@
use std::fmt;
use std::sync::Arc;
use actix_web::{ HttpRequest, HttpResponse, web };
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::web::Path;
use log::{ error, warn };
use log::warn;
use utoipa::ToSchema;
use enums::common::visibility::Visibility;
use http_server_common::response::response_success_helpers::simple_json_success;
use http_server_common::response::serialize_as_json_error::serialize_as_json_error;
use mysql_queries::queries::model_weights::edit::update_weight::{update_weights, UpdateWeightArgs};
use mysql_queries::queries::model_weights::get_weight::get_weight_by_token;
use mysql_queries::queries::model_weights::edit::update_weight::{ update_weights, UpdateWeightArgs };
use tokens::tokens::model_weights::ModelWeightToken;
use user_input_common::check_for_slurs::contains_slurs;
use user_input_common::markdown_to_html::markdown_to_html;
use crate::server_state::ServerState;
use utoipa::ToSchema;
/// TODO will eventually be polymorphic
#[derive(Deserialize, ToSchema)]
pub struct UpdateWeightRequest {
pub title: Option<String>,
pub thumbnail_token: Option<String>,
pub description_markdown: Option<String>,
// KS: We should probably remove this
// Users have to update markdown, not html directly
pub description_rendered_html: Option<String>,
pub weight_type: Option<String>,
pub weight_category: Option<String>,
@@ -139,13 +143,34 @@ pub async fn update_weight_handler(
return Err(UpdateWeightError::NotAuthorized);
}
let mut weight_title = None;
let mut description_markdown = None;
let mut description_rendered_html = None;
if let Some(title) = &request.title {
if (contains_slurs(title)) {
return Err(UpdateWeightError::BadInput("Title contains slurs".to_string()));
}
weight_title = Some(title.trim().to_string());
}
if let Some(markdown) = &request.description_markdown {
if (contains_slurs(markdown)) {
return Err(UpdateWeightError::BadInput("Description contains slurs".to_string()));
}
let markdown = markdown.trim().to_string();
let html = markdown_to_html(&markdown);
description_markdown = Some(markdown);
description_rendered_html = Some(html);
}
let query_result = update_weights(UpdateWeightArgs {
weight_token: &ModelWeightToken::new(path.weight_token.clone()),
mysql_pool: &server_state.mysql_pool,
title: request.title.as_deref(),
maybe_thumbnail_token: request.thumbnail_token.as_deref(),
description_markdown: request.description_markdown.as_deref(),
description_rendered_html: request.description_rendered_html.as_deref(),
title: weight_title.as_deref(),
maybe_description_markdown: description_markdown.as_deref(),
maybe_description_rendered_html: description_rendered_html.as_deref(),
creator_set_visibility: request.visibility.as_ref(),
weights_type: request.weight_type.as_deref().map(|s| s.to_string()),
weights_category: request.weight_category.as_deref().map(|s| s.to_string()),
@@ -160,7 +160,7 @@ use crate::http_server::endpoints::weights::get_weight::get_weight_handler;
use crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler;
use crate::http_server::endpoints::weights::list_featured_weights::list_featured_weights_handler;
use crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler;
use crate::http_server::endpoints::weights::set_model_weight_avatar::set_model_weight_avatar_handler;
use crate::http_server::endpoints::weights::set_model_weight_cover_image::set_model_weight_cover_image_handler;
use crate::http_server::endpoints::weights::update_weight::update_weight_handler;
pub fn add_routes<T, B> (app: App<T>, server_environment: ServerEnvironment) -> App<T>
@@ -1278,8 +1278,8 @@ fn add_weights_routes<T, B>(app: App<T>) -> App<T>
.route(web::post().to(update_weight_handler))
.route(web::delete().to(delete_weight_handler))
)
.service(web::resource("/weight/{token}/avatar")
.route(web::post().to(set_model_weight_avatar_handler))
.service(web::resource("/weight/{token}/cover_image")
.route(web::post().to(set_model_weight_cover_image_handler))
)
.route("/by_user/{username}", web::get().to(list_weights_by_user_handler))
.route("/list", web::get().to(list_available_weights_handler))