mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-14 13:52:11 +00:00
Merge pull request #237 from storytold/dec-21-mithoo
Document user bookmarks endpoints
This commit is contained in:
7 files changed
+124
-51
No files matched your search
@@ -4,10 +4,11 @@ use serde::Serialize;
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// Used in the `user_bookmarks` table in a `VARCHAR(32)` field named `entity_type`.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema)]
|
||||
pub enum UserBookmarkEntityType {
|
||||
/// User
|
||||
#[serde(rename = "user")]
|
||||
|
||||
@@ -2,11 +2,12 @@ use std::fmt::Debug;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
use crate::prefixes::TokenPrefix;
|
||||
|
||||
|
||||
/// The primary key for Audit Logs.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize, ToSchema)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct UserBookmarkToken(pub String);
|
||||
|
||||
|
||||
@@ -18,11 +18,21 @@ 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::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
|
||||
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::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;
|
||||
@@ -36,7 +46,11 @@ use utoipa::OpenApi;
|
||||
crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler,
|
||||
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::list_media_files_for_user::list_media_files_for_user_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(
|
||||
// Tokens
|
||||
UserToken,Visibility,
|
||||
@@ -60,6 +74,11 @@ use utoipa::OpenApi;
|
||||
ListMediaFilesSuccessResponse, ListMediaFilesError, MediaFileListItem, ListMediaFilesQueryParams,
|
||||
MediaFileSocialMetaLight,
|
||||
ListMediaFilesForUserSuccessResponse,ListMediaFilesForUserQueryParams,ListMediaFilesForUserError,ListMediaFilesForUserPathInfo,
|
||||
MediaFileForUserListItem, MediaFileForUserListItem
|
||||
MediaFileForUserListItem, MediaFileForUserListItem,
|
||||
UserBookmarkToken,UserBookmarkDetailsForUserList,UserBookmarkEntityType,
|
||||
CreateUserBookmarkRequest,CreateUserBookmarkError,CreateUserBookmarkSuccessResponse,
|
||||
DeleteUserBookmarkPathInfo,DeleteUserBookmarkError,DeleteUserBookmarkRequest,
|
||||
ListUserBookmarksPathInfo,ListUserBookmarksForUserError,ListUserBookmarksForUserSuccessResponse,UserBookmarkListItem,
|
||||
ListUserBookmarksForEntityPathInfo,ListUserBookmarksForEntityError,ListUserBookmarksForEntitySuccessResponse,UserBookmarkForEntityListItem,
|
||||
)))]
|
||||
pub struct ApiDoc;
|
||||
+13
-3
@@ -10,6 +10,7 @@ use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use log::warn;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use mysql_queries::queries::user_bookmarks::create_user_bookmark::{create_user_bookmark, CreateUserBookmarkArgs};
|
||||
@@ -28,19 +29,19 @@ use tokens::tokens::zs_voices::ZsVoiceToken;
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct CreateUserBookmarkRequest {
|
||||
entity_token: String,
|
||||
entity_type: UserBookmarkEntityType,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct CreateUserBookmarkSuccessResponse {
|
||||
pub success: bool,
|
||||
pub user_bookmark_token: UserBookmarkToken,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum CreateUserBookmarkError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
@@ -74,6 +75,15 @@ impl fmt::Display for CreateUserBookmarkError {
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/v1/user_bookmarks/create",
|
||||
request_body = CreateUserBookmarkRequest,
|
||||
responses(
|
||||
(status = 200, body = CreateUserBookmarkSuccessResponse),
|
||||
(status = 400, body = CreateUserBookmarkError),
|
||||
)
|
||||
)]
|
||||
pub async fn create_user_bookmark_handler(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<CreateUserBookmarkRequest>,
|
||||
|
||||
+18
-3
@@ -11,6 +11,7 @@ use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::Path;
|
||||
use log::warn;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use mysql_queries::queries::user_bookmarks::delete_user_bookmark::delete_user_bookmark;
|
||||
use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
@@ -20,18 +21,18 @@ use crate::http_server::web_utils::response_success_helpers::simple_json_success
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
/// For the URL PathInfo
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct DeleteUserBookmarkPathInfo {
|
||||
user_bookmark_token: UserBookmarkToken,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct DeleteUserBookmarkRequest {
|
||||
/// NB: this is only to disambiguate when a user is both a mod and an author.
|
||||
as_mod: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum DeleteUserBookmarkError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
@@ -68,6 +69,20 @@ impl fmt::Display for DeleteUserBookmarkError {
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/v1/user_bookmarks/delete/{user_bookmark_token}",
|
||||
params(
|
||||
("user_bookmark_token", description = "UserBookmarkToken"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Delete User Bookmark", body = SimpleGenericJsonSuccess),
|
||||
(status = 400, description = "Bad input", body = DeleteUserBookmarkError),
|
||||
(status = 401, description = "Not authorized", body = DeleteUserBookmarkError),
|
||||
(status = 404, description = "Not found", body = DeleteUserBookmarkError),
|
||||
(status = 500, description = "Server error", body = DeleteUserBookmarkError),
|
||||
),
|
||||
)]
|
||||
pub async fn delete_user_bookmark_handler(
|
||||
http_request: HttpRequest,
|
||||
path: Path<DeleteUserBookmarkPathInfo>,
|
||||
|
||||
+33
-19
@@ -12,6 +12,7 @@ use actix_web::http::StatusCode;
|
||||
use actix_web::web::Path;
|
||||
use chrono::{DateTime, Utc};
|
||||
use log::warn;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType;
|
||||
use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken;
|
||||
@@ -23,20 +24,20 @@ use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
/// For the URL PathInfo
|
||||
#[derive(Deserialize)]
|
||||
pub struct ListUserBookmarkPathInfo {
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ListUserBookmarksForEntityPathInfo {
|
||||
entity_type: UserBookmarkEntityType,
|
||||
entity_token: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ListUserBookmarksSuccessResponse {
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ListUserBookmarksForEntitySuccessResponse {
|
||||
pub success: bool,
|
||||
pub user_bookmarks: Vec<UserBookmark>,
|
||||
pub user_bookmarks: Vec<UserBookmarkForEntityListItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct UserBookmark {
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct UserBookmarkForEntityListItem {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub user: UserDetailsLight,
|
||||
@@ -45,21 +46,21 @@ pub struct UserBookmark {
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ListUserBookmarksError {
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum ListUserBookmarksForEntityError {
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for ListUserBookmarksError {
|
||||
impl ResponseError for ListUserBookmarksForEntityError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ListUserBookmarksForEntityError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
ListUserBookmarksError::ServerError => "server error".to_string(),
|
||||
ListUserBookmarksForEntityError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -67,17 +68,30 @@ impl ResponseError for ListUserBookmarksError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for ListUserBookmarksError {
|
||||
impl fmt::Display for ListUserBookmarksForEntityError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/v1/user_bookmarks/list/{entity_type}/{entity_token}",
|
||||
params(
|
||||
("entity_type", description="The type of entity to list bookmarks for"),
|
||||
("entity_token", description="The token of the entity to list bookmarks for"),
|
||||
),
|
||||
responses(
|
||||
(status = 200, body = ListUserBookmarksForEntitySuccessResponse),
|
||||
(status = 500, body = ListUserBookmarksForEntityError),
|
||||
),
|
||||
)]
|
||||
pub async fn list_user_bookmarks_for_entity_handler(
|
||||
_http_request: HttpRequest,
|
||||
path: Path<ListUserBookmarkPathInfo>,
|
||||
path: Path<ListUserBookmarksForEntityPathInfo>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListUserBookmarksError>
|
||||
) -> Result<HttpResponse, ListUserBookmarksForEntityError>
|
||||
{
|
||||
let entity_token = UserBookmarkEntityToken::from_entity_type_and_token(
|
||||
path.entity_type, &path.entity_token);
|
||||
@@ -91,14 +105,14 @@ pub async fn list_user_bookmarks_for_entity_handler(
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListUserBookmarksError::ServerError);
|
||||
return Err(ListUserBookmarksForEntityError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = ListUserBookmarksSuccessResponse {
|
||||
let response = ListUserBookmarksForEntitySuccessResponse {
|
||||
success: true,
|
||||
user_bookmarks: user_bookmarks.into_iter()
|
||||
.map(|user_bookmark| UserBookmark {
|
||||
.map(|user_bookmark| UserBookmarkForEntityListItem {
|
||||
token: user_bookmark.token,
|
||||
user: UserDetailsLight {
|
||||
user_token: user_bookmark.user_token.clone(),
|
||||
@@ -114,7 +128,7 @@ pub async fn list_user_bookmarks_for_entity_handler(
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| ListUserBookmarksError::ServerError)?;
|
||||
.map_err(|_e| ListUserBookmarksForEntityError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
|
||||
+35
-22
@@ -12,6 +12,7 @@ use actix_web::http::StatusCode;
|
||||
use actix_web::web::{Path, Query};
|
||||
use chrono::{DateTime, Utc};
|
||||
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};
|
||||
@@ -20,34 +21,34 @@ use tokens::tokens::user_bookmarks::UserBookmarkToken;
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ListUserBookmarksPathInfo {
|
||||
username: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, ToSchema, IntoParams)]
|
||||
pub struct ListUserBookmarksQueryData {
|
||||
maybe_scoped_entity_type: Option<UserBookmarkEntityType>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ListUserBookmarksSuccessResponse {
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ListUserBookmarksForUserSuccessResponse {
|
||||
pub success: bool,
|
||||
pub user_bookmarks: Vec<UserBookmark>,
|
||||
pub user_bookmarks: Vec<UserBookmarkListItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct UserBookmark {
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct UserBookmarkListItem {
|
||||
pub token: UserBookmarkToken,
|
||||
|
||||
pub details: UserBookmarkDetails,
|
||||
pub details: UserBookmarkDetailsForUserList,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct UserBookmarkDetails {
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct UserBookmarkDetailsForUserList {
|
||||
// TODO: This needs titles or some other summary metadata.
|
||||
pub entity_type: UserBookmarkEntityType,
|
||||
pub entity_token: String,
|
||||
@@ -59,21 +60,21 @@ pub struct UserBookmarkDetails {
|
||||
pub maybe_thumbnail_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ListUserBookmarksError {
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum ListUserBookmarksForUserError {
|
||||
ServerError,
|
||||
}
|
||||
|
||||
impl ResponseError for ListUserBookmarksError {
|
||||
impl ResponseError for ListUserBookmarksForUserError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ListUserBookmarksForUserError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
ListUserBookmarksError::ServerError => "server error".to_string(),
|
||||
ListUserBookmarksForUserError::ServerError => "server error".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -81,18 +82,30 @@ impl ResponseError for ListUserBookmarksError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl fmt::Display for ListUserBookmarksError {
|
||||
impl fmt::Display for ListUserBookmarksForUserError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/v1/user_bookmarks/list/user/{username}",
|
||||
params(
|
||||
("username", description = "The username of the user whose bookmarks to list."),
|
||||
ListUserBookmarksQueryData
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "List User Bookmarks", body = ListUserBookmarksForUserSuccessResponse),
|
||||
(status = 500, description = "Server error", body = ListUserBookmarksForUserError),
|
||||
),
|
||||
)]
|
||||
pub async fn list_user_bookmarks_for_user_handler(
|
||||
_http_request: HttpRequest,
|
||||
path: Path<ListUserBookmarksPathInfo>,
|
||||
query: Query<ListUserBookmarksQueryData>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, ListUserBookmarksError>
|
||||
) -> Result<HttpResponse, ListUserBookmarksForUserError>
|
||||
{
|
||||
|
||||
let query_results = match query.maybe_scoped_entity_type {
|
||||
@@ -106,16 +119,16 @@ pub async fn list_user_bookmarks_for_user_handler(
|
||||
Ok(results) => results,
|
||||
Err(e) => {
|
||||
warn!("Query error: {:?}", e);
|
||||
return Err(ListUserBookmarksError::ServerError);
|
||||
return Err(ListUserBookmarksForUserError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response = ListUserBookmarksSuccessResponse {
|
||||
let response = ListUserBookmarksForUserSuccessResponse {
|
||||
success: true,
|
||||
user_bookmarks: user_bookmarks.into_iter()
|
||||
.map(|user_bookmark| UserBookmark {
|
||||
.map(|user_bookmark| UserBookmarkListItem {
|
||||
token: user_bookmark.token,
|
||||
details: UserBookmarkDetails {
|
||||
details: UserBookmarkDetailsForUserList {
|
||||
entity_type: user_bookmark.entity_type,
|
||||
entity_token: user_bookmark.entity_token,
|
||||
maybe_summary_text: user_bookmark.maybe_entity_descriptive_text,
|
||||
@@ -130,7 +143,7 @@ pub async fn list_user_bookmarks_for_user_handler(
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| ListUserBookmarksError::ServerError)?;
|
||||
.map_err(|_e| ListUserBookmarksForUserError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
|
||||
Reference in new issue
Block a user