diff --git a/blog-generic/src/author_slug_utils.rs b/blog-generic/src/author_slug_utils.rs new file mode 100644 index 0000000..157b142 --- /dev/null +++ b/blog-generic/src/author_slug_utils.rs @@ -0,0 +1,11 @@ +pub const SPLIT_SYMBOL: char = '^'; + +pub fn clean(slug: &String) -> String { + slug.rsplit_once(SPLIT_SYMBOL) + .map(|r| r.0.to_owned()) + .unwrap_or(slug.clone()) +} + +pub fn extend(slug: &String, suffix: &String) -> String { + format!("{slug}{SPLIT_SYMBOL}{suffix}") +} diff --git a/blog-generic/src/lib.rs b/blog-generic/src/lib.rs index be84cda..e4c7960 100644 --- a/blog-generic/src/lib.rs +++ b/blog-generic/src/lib.rs @@ -1,14 +1,6 @@ +pub mod author_slug_utils; pub mod entities; pub mod events; +mod page_processor; -const AUTHOR_SLUG_SPLIT_SYMBOL: char = '^'; - -pub fn clean_author_slug(slug: &String) -> String { - slug.rsplit_once(AUTHOR_SLUG_SPLIT_SYMBOL) - .map(|r| r.0.to_owned()) - .unwrap_or(slug.clone()) -} - -pub fn extend_author_slug(slug: &String, suffix: &String) -> String { - format!("{slug}{AUTHOR_SLUG_SPLIT_SYMBOL}{suffix}") -} +pub use page_processor::*; diff --git a/blog-generic/src/page_processor.rs b/blog-generic/src/page_processor.rs new file mode 100644 index 0000000..f6473d8 --- /dev/null +++ b/blog-generic/src/page_processor.rs @@ -0,0 +1,25 @@ +pub trait PageProcessor { + fn create_for_page(page: &u64) -> Self; + fn limit(&self) -> u64; + fn offset(&self) -> u64; +} + +pub struct DefaultPageProcessor { + page: u64, +} + +impl PageProcessor for DefaultPageProcessor { + fn create_for_page(page: &u64) -> Self { + Self { page: *page } + } + fn limit(&self) -> u64 { + LIMIT + } + fn offset(&self) -> u64 { + let Some(real_page) = self.page.checked_sub(1) else { + return 0; + }; + let offset = real_page * LIMIT; + offset + } +} diff --git a/blog-server-api/src/endpoints/author/handler.rs b/blog-server-api/src/endpoints/author/handler.rs index b03e413..295a76d 100644 --- a/blog-server-api/src/endpoints/author/handler.rs +++ b/blog-server-api/src/endpoints/author/handler.rs @@ -1,3 +1,8 @@ +use std::sync::Arc; + +use blog_generic::entities::AuthorContainer; +use blog_server_services::traits::author_service::AuthorService; + use super::request_content::AuthorRequestContent; use super::response_content_failure::AuthorResponseContentFailure; use super::response_content_failure::AuthorResponseContentFailure::*; @@ -23,3 +28,16 @@ pub async fn http_handler( Ok(author.into()) } + +pub async fn direct_handler( + slug: String, + author_service: Arc>, +) -> Option { + http_handler((AuthorRequestContent { + slug, + author_service, + },)) + .await + .ok() + .map(|s| s.container) +} diff --git a/blog-server-api/src/endpoints/author/mod.rs b/blog-server-api/src/endpoints/author/mod.rs index 9bed8a6..c95b83d 100644 --- a/blog-server-api/src/endpoints/author/mod.rs +++ b/blog-server-api/src/endpoints/author/mod.rs @@ -4,6 +4,3 @@ mod response_content_failure; mod response_content_success; pub use handler::*; -pub use request_content::*; -pub use response_content_failure::*; -pub use response_content_success::*; diff --git a/blog-server-api/src/endpoints/author/request_content.rs b/blog-server-api/src/endpoints/author/request_content.rs index f6da7a8..38654c8 100644 --- a/blog-server-api/src/endpoints/author/request_content.rs +++ b/blog-server-api/src/endpoints/author/request_content.rs @@ -4,8 +4,8 @@ use screw_api::request::{ApiRequestContent, ApiRequestOriginContent}; use std::sync::Arc; pub struct AuthorRequestContent { - pub slug: String, - pub author_service: Arc>, + pub(super) slug: String, + pub(super) author_service: Arc>, } impl ApiRequestContent for AuthorRequestContent diff --git a/blog-server-api/src/endpoints/author/response_content_success.rs b/blog-server-api/src/endpoints/author/response_content_success.rs index b8f8793..7aa36bb 100644 --- a/blog-server-api/src/endpoints/author/response_content_success.rs +++ b/blog-server-api/src/endpoints/author/response_content_success.rs @@ -5,7 +5,7 @@ use screw_api::response::{ApiResponseContentBase, ApiResponseContentSuccess}; #[derive(Debug, Clone)] pub struct AuthorResponseContentSuccess { - pub container: AuthorContainer, + pub(super) container: AuthorContainer, } impl Into for ServiceAuthor { diff --git a/blog-server-api/src/endpoints/authors/handler.rs b/blog-server-api/src/endpoints/authors/handler.rs index f72e47d..02aab04 100644 --- a/blog-server-api/src/endpoints/authors/handler.rs +++ b/blog-server-api/src/endpoints/authors/handler.rs @@ -1,4 +1,7 @@ +use std::sync::Arc; + use blog_generic::entities::{AuthorsContainer, TotalOffsetLimitContainer}; +use blog_server_services::traits::author_service::AuthorService; use super::request_content::AuthorsRequestContent; use super::response_content_failure::AuthorsResponseContentFailure; @@ -50,3 +53,19 @@ pub async fn http_handler( } .into()) } + +pub async fn direct_handler( + offset: u64, + limit: u64, + author_service: Arc>, +) -> Option { + http_handler((AuthorsRequestContent { + query: None, + offset: Some(offset), + limit: Some(limit), + author_service, + },)) + .await + .ok() + .map(|s| s.container) +} diff --git a/blog-server-api/src/endpoints/authors/mod.rs b/blog-server-api/src/endpoints/authors/mod.rs index 3426965..c95b83d 100644 --- a/blog-server-api/src/endpoints/authors/mod.rs +++ b/blog-server-api/src/endpoints/authors/mod.rs @@ -3,4 +3,4 @@ mod request_content; mod response_content_failure; mod response_content_success; -pub use handler::http_handler; +pub use handler::*; diff --git a/blog-server-api/src/endpoints/client_handler.rs b/blog-server-api/src/endpoints/client_handler.rs index b48a274..50eb3e2 100644 --- a/blog-server-api/src/endpoints/client_handler.rs +++ b/blog-server-api/src/endpoints/client_handler.rs @@ -1,5 +1,5 @@ +use crate::endpoints::*; use crate::extensions::Resolve; -use crate::utils::auth; use blog_server_services::traits::author_service::*; use blog_server_services::traits::entity_post_service::*; use blog_server_services::traits::post_service::*; @@ -8,6 +8,7 @@ use screw_core::request::*; use screw_core::response::*; use screw_core::routing::*; +use blog_generic::*; use blog_ui::*; const INDEX_HTML: &str = include_str!("../../../index.html"); @@ -83,7 +84,7 @@ pub async fn client_handler< }; let status = status(&request).await; - let app_content = app_content(&request).await; + let app_content = app_content::<_, DefaultPageProcessor>(&request).await; let rendered = server_renderer( request.path.as_str().to_string(), @@ -164,72 +165,60 @@ async fn status( } } -async fn app_content( +// TODO: to think, if it's not a cringe +async fn app_content( request: &router::RoutedRequest>, ) -> Option where Extensions: Resolve>> + Resolve>> + Resolve>>, + PP: PageProcessor, { + let page_processor = PP::create_for_page( + &request + .query + .get("page") + .map(|v| v.parse().ok()) + .flatten() + .unwrap_or(1), + ); match Route::recognize_path(request.path.as_str())? { - Route::Post { slug: _, id } | Route::EditPost { id } => { - use crate::endpoints::post; - let post_service: std::sync::Arc> = - request.origin.extensions.resolve(); - let entity_post_service: std::sync::Arc> = - request.origin.extensions.resolve(); - - let Ok(post::PostResponseContentSuccess { container }) = - post::http_handler((post::PostRequestContent { - id: id.to_string(), - post_service, - entity_post_service, - auth_author_future: Box::pin(std::future::ready(Err( - auth::Error::TokenMissing, - ))), - },)) - .await - else { - return None; - }; - - app_content_encode(&container.post) - } - Route::Author { slug } => { - use crate::endpoints::author; - let author_service: std::sync::Arc> = - request.origin.extensions.resolve(); - - let Ok(author::AuthorResponseContentSuccess { container }) = - author::http_handler((author::AuthorRequestContent { - slug, - author_service, - },)) - .await - else { - return None; - }; - - app_content_encode(&container.author) - } + Route::Post { slug: _, id } | Route::EditPost { id } => post::direct_handler( + id.to_string(), + request.origin.extensions.resolve(), + request.origin.extensions.resolve(), + ) + .await + .map(|v| app_content_encode(&v.post)) + .flatten(), + Route::Author { slug } => author::direct_handler(slug, request.origin.extensions.resolve()) + .await + .map(|v| app_content_encode(&v.author)) + .flatten(), Route::Tag { slug: _, id } => { - use crate::endpoints::tag; - let post_service: std::sync::Arc> = - request.origin.extensions.resolve(); - - let Ok(tag::TagResponseContentSuccess { container }) = - tag::http_handler((tag::TagRequestContent { - id: id.to_string(), - post_service, - },)) + tag::direct_handler(id.to_string(), request.origin.extensions.resolve()) .await - else { - return None; - }; - - app_content_encode(&container.tag) + .map(|v| app_content_encode(&v.tag)) + .flatten() } + Route::Posts => posts::direct_handler( + page_processor.offset(), + page_processor.limit(), + request.origin.extensions.resolve(), + request.origin.extensions.resolve(), + ) + .await + .map(|v| app_content_encode(&v)) + .flatten(), + Route::Authors => authors::direct_handler( + page_processor.offset(), + page_processor.limit(), + request.origin.extensions.resolve(), + ) + .await + .map(|v| app_content_encode(&v)) + .flatten(), _ => None, } } diff --git a/blog-server-api/src/endpoints/post/handler.rs b/blog-server-api/src/endpoints/post/handler.rs index ad9cef4..2bc5704 100644 --- a/blog-server-api/src/endpoints/post/handler.rs +++ b/blog-server-api/src/endpoints/post/handler.rs @@ -1,3 +1,11 @@ +use std::sync::Arc; + +use blog_generic::entities::PostContainer; +use blog_server_services::traits::entity_post_service::EntityPostService; +use blog_server_services::traits::post_service::PostService; + +use crate::utils::auth; + use super::request_content::PostRequestContent; use super::response_content_failure::PostResponseContentFailure; use super::response_content_failure::PostResponseContentFailure::*; @@ -44,3 +52,19 @@ pub async fn http_handler( Ok(post_entity.into()) } + +pub async fn direct_handler( + id: String, + post_service: Arc>, + entity_post_service: Arc>, +) -> Option { + http_handler((PostRequestContent { + id, + post_service, + entity_post_service, + auth_author_future: Box::pin(std::future::ready(Err(auth::Error::TokenMissing))), + },)) + .await + .ok() + .map(|s| s.container) +} diff --git a/blog-server-api/src/endpoints/post/mod.rs b/blog-server-api/src/endpoints/post/mod.rs index 9bed8a6..c95b83d 100644 --- a/blog-server-api/src/endpoints/post/mod.rs +++ b/blog-server-api/src/endpoints/post/mod.rs @@ -4,6 +4,3 @@ mod response_content_failure; mod response_content_success; pub use handler::*; -pub use request_content::*; -pub use response_content_failure::*; -pub use response_content_success::*; diff --git a/blog-server-api/src/endpoints/post/request_content.rs b/blog-server-api/src/endpoints/post/request_content.rs index cc94025..e3188fc 100644 --- a/blog-server-api/src/endpoints/post/request_content.rs +++ b/blog-server-api/src/endpoints/post/request_content.rs @@ -9,10 +9,10 @@ use screw_components::dyn_fn::DFuture; use std::sync::Arc; pub struct PostRequestContent { - pub id: String, - pub post_service: Arc>, - pub entity_post_service: Arc>, - pub auth_author_future: DFuture>, + pub(super) id: String, + pub(super) post_service: Arc>, + pub(super) entity_post_service: Arc>, + pub(super) auth_author_future: DFuture>, } impl ApiRequestContent for PostRequestContent diff --git a/blog-server-api/src/endpoints/post/response_content_success.rs b/blog-server-api/src/endpoints/post/response_content_success.rs index 2772db5..4f0c79c 100644 --- a/blog-server-api/src/endpoints/post/response_content_success.rs +++ b/blog-server-api/src/endpoints/post/response_content_success.rs @@ -4,7 +4,7 @@ use screw_api::response::{ApiResponseContentBase, ApiResponseContentSuccess}; #[derive(Debug, Clone)] pub struct PostResponseContentSuccess { - pub container: PostContainer, + pub(super) container: PostContainer, } impl Into for Post { diff --git a/blog-server-api/src/endpoints/posts/handler.rs b/blog-server-api/src/endpoints/posts/handler.rs index 26d30b9..7e75ce8 100644 --- a/blog-server-api/src/endpoints/posts/handler.rs +++ b/blog-server-api/src/endpoints/posts/handler.rs @@ -1,6 +1,10 @@ +use std::sync::Arc; + use crate::utils::auth; use blog_generic::entities::{PostsContainer, TotalOffsetLimitContainer}; use blog_server_services::traits::author_service::Author; +use blog_server_services::traits::entity_post_service::EntityPostService; +use blog_server_services::traits::post_service::PostService; use screw_components::dyn_fn::DFuture; use super::request_content::{PostsRequestContentFilter as Filter, *}; @@ -124,3 +128,21 @@ async fn handler( } .into()) } + +pub async fn direct_handler( + offset: u64, + limit: u64, + post_service: Arc>, + entity_post_service: Arc>, +) -> Option { + http_handler((PostsRequestContent { + filter: None, + offset: Some(offset), + limit: Some(limit), + post_service, + entity_post_service, + },)) + .await + .ok() + .map(|s| s.container) +} diff --git a/blog-server-api/src/endpoints/posts/mod.rs b/blog-server-api/src/endpoints/posts/mod.rs index 53f9ef5..c95b83d 100644 --- a/blog-server-api/src/endpoints/posts/mod.rs +++ b/blog-server-api/src/endpoints/posts/mod.rs @@ -3,4 +3,4 @@ mod request_content; mod response_content_failure; mod response_content_success; -pub use handler::{http_handler, http_handler_unpublished}; +pub use handler::*; diff --git a/blog-server-api/src/endpoints/tag/handler.rs b/blog-server-api/src/endpoints/tag/handler.rs index 7921dc9..b780c94 100644 --- a/blog-server-api/src/endpoints/tag/handler.rs +++ b/blog-server-api/src/endpoints/tag/handler.rs @@ -1,3 +1,8 @@ +use std::sync::Arc; + +use blog_generic::entities::TagContainer; +use blog_server_services::traits::post_service::PostService; + use super::request_content::TagRequestContent; use super::response_content_failure::TagResponseContentFailure; use super::response_content_failure::TagResponseContentFailure::*; @@ -20,3 +25,13 @@ pub async fn http_handler( Ok(tag.into()) } + +pub async fn direct_handler( + id: String, + post_service: Arc>, +) -> Option { + http_handler((TagRequestContent { id, post_service },)) + .await + .ok() + .map(|s| s.container) +} diff --git a/blog-server-api/src/endpoints/tag/mod.rs b/blog-server-api/src/endpoints/tag/mod.rs index 9bed8a6..c95b83d 100644 --- a/blog-server-api/src/endpoints/tag/mod.rs +++ b/blog-server-api/src/endpoints/tag/mod.rs @@ -4,6 +4,3 @@ mod response_content_failure; mod response_content_success; pub use handler::*; -pub use request_content::*; -pub use response_content_failure::*; -pub use response_content_success::*; diff --git a/blog-server-api/src/endpoints/tag/request_content.rs b/blog-server-api/src/endpoints/tag/request_content.rs index 09b9f44..62776d8 100644 --- a/blog-server-api/src/endpoints/tag/request_content.rs +++ b/blog-server-api/src/endpoints/tag/request_content.rs @@ -4,8 +4,8 @@ use screw_api::request::{ApiRequestContent, ApiRequestOriginContent}; use std::sync::Arc; pub struct TagRequestContent { - pub id: String, - pub post_service: Arc>, + pub(super) id: String, + pub(super) post_service: Arc>, } impl ApiRequestContent for TagRequestContent diff --git a/blog-server-api/src/endpoints/tag/response_content_success.rs b/blog-server-api/src/endpoints/tag/response_content_success.rs index 0f75dec..8b22c65 100644 --- a/blog-server-api/src/endpoints/tag/response_content_success.rs +++ b/blog-server-api/src/endpoints/tag/response_content_success.rs @@ -5,7 +5,7 @@ use screw_api::response::{ApiResponseContentBase, ApiResponseContentSuccess}; #[derive(Debug, Clone)] pub struct TagResponseContentSuccess { - pub container: TagContainer, + pub(super) container: TagContainer, } impl Into for ServiceTag { diff --git a/blog-server-api/src/endpoints/telegram_login/handler.rs b/blog-server-api/src/endpoints/telegram_login/handler.rs index 3001385..1a6eb60 100644 --- a/blog-server-api/src/endpoints/telegram_login/handler.rs +++ b/blog-server-api/src/endpoints/telegram_login/handler.rs @@ -1,4 +1,4 @@ -use blog_generic::entities::LoginTelegramQuestion; +use blog_generic::*; use blog_server_services::traits::author_service::BaseMinimalAuthor; use blog_server_services::traits::social_service::SocialId; use blog_server_services::utils::time_utils; @@ -31,7 +31,7 @@ pub async fn http_handler( social_service, },): (LoginTelegramRequestContent,), ) -> Result { - let LoginTelegramQuestion { + let entities::LoginTelegramQuestion { id, first_name, last_name, @@ -78,7 +78,7 @@ pub async fn http_handler( } let telegram_base_minimal_author = BaseMinimalAuthor { - slug: blog_generic::extend_author_slug( + slug: author_slug_utils::extend( &username.unwrap_or(id.to_string()), &"t".to_string(), ), diff --git a/blog-server-api/src/endpoints/yandex_login/handler.rs b/blog-server-api/src/endpoints/yandex_login/handler.rs index e870e5a..4a6c43c 100644 --- a/blog-server-api/src/endpoints/yandex_login/handler.rs +++ b/blog-server-api/src/endpoints/yandex_login/handler.rs @@ -1,4 +1,4 @@ -use blog_generic::entities::LoginYandexQuestion; +use blog_generic::*; use blog_server_services::traits::author_service::BaseMinimalAuthor; use blog_server_services::traits::social_service::SocialId; use blog_server_services::utils::time_utils; @@ -37,7 +37,7 @@ pub async fn http_handler( social_service, },): (LoginYandexRequestContent,), ) -> Result { - let LoginYandexQuestion { + let entities::LoginYandexQuestion { access_token, token_type: _, expires_in: _, @@ -66,7 +66,7 @@ pub async fn http_handler( }; let yandex_base_minimal_author = BaseMinimalAuthor { - slug: blog_generic::extend_author_slug(&yandex_login_response.login, &"y".to_string()), + slug: author_slug_utils::extend(&yandex_login_response.login, &"y".to_string()), first_name: yandex_login_response.first_name, last_name: yandex_login_response.last_name, image_url: if !yandex_login_response.is_avatar_empty { diff --git a/blog-server-api/src/utils/html.rs b/blog-server-api/src/utils/html.rs index b42df92..4d60663 100644 --- a/blog-server-api/src/utils/html.rs +++ b/blog-server-api/src/utils/html.rs @@ -9,7 +9,18 @@ pub fn clean(src: &str) -> String { .add_tags(&["source"]) .add_tag_attributes("source", &["src", "type"]) .add_tags(&["iframe"]) - .add_tag_attributes("iframe", &["src", "allowfullscreen", "width", "height", "frameBorder", "allow", "loading"]) + .add_tag_attributes( + "iframe", + &[ + "src", + "allowfullscreen", + "width", + "height", + "frameBorder", + "allow", + "loading", + ], + ) .add_allowed_classes("iframe", &["article-iframe"]) .clean(src) .to_string()