From 5b1cc5b605eb67818901c17010a89bc9692803a9 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 12:09:08 +0900 Subject: [PATCH 01/59] refactor: move routes --- src/appv2/drivers/mod.rs | 1 + src/{ => appv2/drivers}/routes.rs | 0 src/appv2/mod.rs | 1 + src/main.rs | 4 ++-- 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 src/appv2/drivers/mod.rs rename src/{ => appv2/drivers}/routes.rs (100%) create mode 100644 src/appv2/mod.rs diff --git a/src/appv2/drivers/mod.rs b/src/appv2/drivers/mod.rs new file mode 100644 index 0000000..6a664ab --- /dev/null +++ b/src/appv2/drivers/mod.rs @@ -0,0 +1 @@ +pub mod routes; diff --git a/src/routes.rs b/src/appv2/drivers/routes.rs similarity index 100% rename from src/routes.rs rename to src/appv2/drivers/routes.rs diff --git a/src/appv2/mod.rs b/src/appv2/mod.rs new file mode 100644 index 0000000..2c554a7 --- /dev/null +++ b/src/appv2/mod.rs @@ -0,0 +1 @@ +pub mod drivers; diff --git a/src/main.rs b/src/main.rs index fa2d998..abdc316 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,10 +7,10 @@ extern crate log; use actix_web::middleware::Logger; use actix_web::{App, HttpServer}; mod app; +mod appv2; mod constants; mod error; mod middleware; -mod routes; mod schema; mod utils; @@ -31,7 +31,7 @@ async fn main() -> std::io::Result<()> { .app_data(actix_web::web::Data::new(state.clone())) .wrap(middleware::cors::cors()) .wrap(middleware::auth::Authentication) - .configure(routes::api) + .configure(appv2::drivers::routes::api) }) .bind(constants::BIND)? .run() From 82ce3d77f2a401ff98d5d5e346819bdecb43b696 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 12:14:38 +0900 Subject: [PATCH 02/59] refactor: move middlewares to drivers --- src/app/article/api.rs | 4 ++-- src/app/comment/api.rs | 4 ++-- src/app/favorite/api.rs | 4 ++-- src/app/profile/api.rs | 2 +- src/app/tag/api.rs | 2 +- src/app/user/api.rs | 4 ++-- src/{middleware => appv2/drivers/middlewares}/auth.rs | 2 +- src/{middleware => appv2/drivers/middlewares}/cors.rs | 0 src/{middleware => appv2/drivers/middlewares}/error.rs | 0 src/{middleware => appv2/drivers/middlewares}/mod.rs | 0 src/{middleware => appv2/drivers/middlewares}/state.rs | 0 src/appv2/drivers/mod.rs | 1 + src/main.rs | 7 +++---- 13 files changed, 15 insertions(+), 15 deletions(-) rename src/{middleware => appv2/drivers/middlewares}/auth.rs (99%) rename src/{middleware => appv2/drivers/middlewares}/cors.rs (100%) rename src/{middleware => appv2/drivers/middlewares}/error.rs (100%) rename src/{middleware => appv2/drivers/middlewares}/mod.rs (100%) rename src/{middleware => appv2/drivers/middlewares}/state.rs (100%) diff --git a/src/app/article/api.rs b/src/app/article/api.rs index ee6b81b..fc3bb12 100644 --- a/src/app/article/api.rs +++ b/src/app/article/api.rs @@ -4,8 +4,8 @@ use super::{ response::{MultipleArticlesResponse, SingleArticleResponse}, service, }; -use crate::middleware::auth; -use crate::middleware::state::AppState; +use crate::appv2::drivers::middlewares::auth; +use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; use serde::Deserialize; diff --git a/src/app/comment/api.rs b/src/app/comment/api.rs index 69e320e..967ce8d 100644 --- a/src/app/comment/api.rs +++ b/src/app/comment/api.rs @@ -3,8 +3,8 @@ use super::{ response::{MultipleCommentsResponse, SingleCommentResponse}, service, }; -use crate::middleware::auth; -use crate::middleware::state::AppState; +use crate::appv2::drivers::middlewares::auth; +use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use crate::utils::uuid; use actix_web::{web, HttpRequest, HttpResponse}; diff --git a/src/app/favorite/api.rs b/src/app/favorite/api.rs index 52568b2..a21a372 100644 --- a/src/app/favorite/api.rs +++ b/src/app/favorite/api.rs @@ -2,8 +2,8 @@ use super::{ response::SingleArticleResponse, service::{self, UnfavoriteService}, }; -use crate::middleware::auth; -use crate::middleware::state::AppState; +use crate::appv2::drivers::middlewares::auth; +use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; diff --git a/src/app/profile/api.rs b/src/app/profile/api.rs index 073ec35..907cc5b 100644 --- a/src/app/profile/api.rs +++ b/src/app/profile/api.rs @@ -1,6 +1,6 @@ use super::response::ProfileResponse; use super::service; -use crate::middleware::{auth, state::AppState}; +use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; diff --git a/src/app/tag/api.rs b/src/app/tag/api.rs index 8955b91..1e8e021 100644 --- a/src/app/tag/api.rs +++ b/src/app/tag/api.rs @@ -1,7 +1,7 @@ extern crate serde_json; use super::model::Tag; use super::response::TagsResponse; -use crate::middleware::state::AppState; +use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpResponse}; diff --git a/src/app/user/api.rs b/src/app/user/api.rs index f544240..e323fc3 100644 --- a/src/app/user/api.rs +++ b/src/app/user/api.rs @@ -1,7 +1,7 @@ use super::model::{UpdateUser, User}; use super::{request, response::UserResponse}; -use crate::middleware::auth; -use crate::middleware::state::AppState; +use crate::appv2::drivers::middlewares::auth; +use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; diff --git a/src/middleware/auth.rs b/src/appv2/drivers/middlewares/auth.rs similarity index 99% rename from src/middleware/auth.rs rename to src/appv2/drivers/middlewares/auth.rs index acb27d3..cee6e79 100644 --- a/src/middleware/auth.rs +++ b/src/appv2/drivers/middlewares/auth.rs @@ -1,7 +1,7 @@ use crate::app::user::model::User; +use crate::appv2::drivers::middlewares::state::AppState; use crate::constants; use crate::error::AppError; -use crate::middleware::state::AppState; use crate::utils::token; use actix_web::HttpMessage; use actix_web::{ diff --git a/src/middleware/cors.rs b/src/appv2/drivers/middlewares/cors.rs similarity index 100% rename from src/middleware/cors.rs rename to src/appv2/drivers/middlewares/cors.rs diff --git a/src/middleware/error.rs b/src/appv2/drivers/middlewares/error.rs similarity index 100% rename from src/middleware/error.rs rename to src/appv2/drivers/middlewares/error.rs diff --git a/src/middleware/mod.rs b/src/appv2/drivers/middlewares/mod.rs similarity index 100% rename from src/middleware/mod.rs rename to src/appv2/drivers/middlewares/mod.rs diff --git a/src/middleware/state.rs b/src/appv2/drivers/middlewares/state.rs similarity index 100% rename from src/middleware/state.rs rename to src/appv2/drivers/middlewares/state.rs diff --git a/src/appv2/drivers/mod.rs b/src/appv2/drivers/mod.rs index 6a664ab..c58f3b1 100644 --- a/src/appv2/drivers/mod.rs +++ b/src/appv2/drivers/mod.rs @@ -1 +1,2 @@ +pub mod middlewares; pub mod routes; diff --git a/src/main.rs b/src/main.rs index abdc316..8cd55c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,6 @@ mod app; mod appv2; mod constants; mod error; -mod middleware; mod schema; mod utils; @@ -22,15 +21,15 @@ async fn main() -> std::io::Result<()> { let state = { let pool = utils::db::establish_connection(); - middleware::state::AppState { pool } + appv2::drivers::middlewares::state::AppState { pool } }; HttpServer::new(move || { App::new() .wrap(Logger::default()) .app_data(actix_web::web::Data::new(state.clone())) - .wrap(middleware::cors::cors()) - .wrap(middleware::auth::Authentication) + .wrap(appv2::drivers::middlewares::cors::cors()) + .wrap(appv2::drivers::middlewares::auth::Authentication) .configure(appv2::drivers::routes::api) }) .bind(constants::BIND)? From 5f01bbcedf589944a7cd6334b0d9d3bc3c92ccfb Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 12:38:08 +0900 Subject: [PATCH 03/59] refactor: move profile modules to v2 --- src/app/article/response.rs | 2 +- src/app/article/service.rs | 2 +- src/app/comment/response.rs | 2 +- src/app/comment/service.rs | 6 ++++-- src/app/favorite/service.rs | 2 +- src/app/mod.rs | 3 +-- src/app/profile/mod.rs | 4 ---- src/app/user/model.rs | 2 +- src/appv2/drivers/routes.rs | 13 ++++++++++--- src/appv2/features/mod.rs | 1 + .../features/profile/adapters/controllers.rs} | 8 ++++---- src/appv2/features/profile/adapters/mod.rs | 2 ++ .../features/profile/adapters/presenters.rs} | 2 +- src/appv2/features/profile/entities/mod.rs | 1 + .../features/profile/entities/profile.rs} | 0 src/appv2/features/profile/mod.rs | 3 +++ src/appv2/features/profile/usecases/mod.rs | 1 + .../features/profile/usecases/services.rs} | 2 +- src/appv2/mod.rs | 1 + 19 files changed, 35 insertions(+), 22 deletions(-) delete mode 100644 src/app/profile/mod.rs create mode 100644 src/appv2/features/mod.rs rename src/{app/profile/api.rs => appv2/features/profile/adapters/controllers.rs} (89%) create mode 100644 src/appv2/features/profile/adapters/mod.rs rename src/{app/profile/response.rs => appv2/features/profile/adapters/presenters.rs} (92%) create mode 100644 src/appv2/features/profile/entities/mod.rs rename src/{app/profile/model.rs => appv2/features/profile/entities/profile.rs} (100%) create mode 100644 src/appv2/features/profile/mod.rs create mode 100644 src/appv2/features/profile/usecases/mod.rs rename src/{app/profile/service.rs => appv2/features/profile/usecases/services.rs} (95%) diff --git a/src/app/article/response.rs b/src/app/article/response.rs index 3d7ea7d..b729f3b 100644 --- a/src/app/article/response.rs +++ b/src/app/article/response.rs @@ -1,7 +1,7 @@ use crate::app::article::model::Article; use crate::app::favorite::model::FavoriteInfo; -use crate::app::profile::model::Profile; use crate::app::tag::model::Tag; +use crate::appv2::features::profile::entities::profile::Profile; use crate::utils::date::Iso8601; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/app/article/service.rs b/src/app/article/service.rs index 9972950..2c93848 100644 --- a/src/app/article/service.rs +++ b/src/app/article/service.rs @@ -1,9 +1,9 @@ use crate::app::article::model::{Article, CreateArticle, UpdateArticle}; use crate::app::favorite::model::{Favorite, FavoriteInfo}; use crate::app::follow::model::Follow; -use crate::app::profile::model::Profile; use crate::app::tag::model::{CreateTag, Tag}; use crate::app::user::model::User; +use crate::appv2::features::profile::entities::profile::Profile; use crate::error::AppError; use crate::schema::articles::dsl::*; use crate::schema::{articles, tags, users}; diff --git a/src/app/comment/response.rs b/src/app/comment/response.rs index 379f2cb..20a1f98 100644 --- a/src/app/comment/response.rs +++ b/src/app/comment/response.rs @@ -1,5 +1,5 @@ use crate::app::comment::model::Comment; -use crate::app::profile::model::Profile; +use crate::appv2::features::profile::entities::profile::Profile; use crate::utils::date::Iso8601; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/app/comment/service.rs b/src/app/comment/service.rs index f00b777..da3766d 100644 --- a/src/app/comment/service.rs +++ b/src/app/comment/service.rs @@ -1,8 +1,10 @@ use super::model::{Comment, CreateComment, DeleteComment}; use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; -use crate::app::profile::model::Profile; -use crate::app::profile::service::{conver_user_to_profile, ConverUserToProfile}; use crate::app::user::model::User; +use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::usecases::services::{ + conver_user_to_profile, ConverUserToProfile, +}; use crate::error::AppError; use diesel::pg::PgConnection; use uuid::Uuid; diff --git a/src/app/favorite/service.rs b/src/app/favorite/service.rs index 1243731..c3ac76d 100644 --- a/src/app/favorite/service.rs +++ b/src/app/favorite/service.rs @@ -1,9 +1,9 @@ use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; use crate::app::article::service::{fetch_article, FetchArticle}; use crate::app::favorite::model::{CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo}; -use crate::app::profile::model::Profile; use crate::app::tag::model::Tag; use crate::app::user::model::User; +use crate::appv2::features::profile::entities::profile::Profile; use crate::error::AppError; use diesel::pg::PgConnection; diff --git a/src/app/mod.rs b/src/app/mod.rs index d8e1fa0..93c5395 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -2,7 +2,6 @@ pub mod article; pub mod comment; pub mod favorite; pub mod follow; -pub mod profile; +pub mod healthcheck; pub mod tag; pub mod user; -pub mod healthcheck; \ No newline at end of file diff --git a/src/app/profile/mod.rs b/src/app/profile/mod.rs deleted file mode 100644 index a451d09..0000000 --- a/src/app/profile/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod api; -pub mod model; -pub mod response; -pub mod service; diff --git a/src/app/user/model.rs b/src/app/user/model.rs index 82f911a..256985a 100644 --- a/src/app/user/model.rs +++ b/src/app/user/model.rs @@ -1,6 +1,6 @@ use crate::app::favorite::model::Favorite; use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; -use crate::app::profile::model::Profile; +use crate::appv2::features::profile::entities::profile::Profile; use crate::error::AppError; use crate::schema::users; use crate::utils::{hasher, token}; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index 5825366..b1a9ae0 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -1,4 +1,5 @@ use crate::app; +use crate::appv2; use actix_web::web; use actix_web::web::{delete, get, post, put}; @@ -19,11 +20,17 @@ pub fn api(cfg: &mut web::ServiceConfig) { ) .service( web::scope("/profiles") - .route("/{username}", get().to(app::profile::api::show)) - .route("/{username}/follow", post().to(app::profile::api::follow)) + .route( + "/{username}", + get().to(appv2::features::profile::adapters::controllers::show), + ) + .route( + "/{username}/follow", + post().to(appv2::features::profile::adapters::controllers::follow), + ) .route( "/{username}/follow", - delete().to(app::profile::api::unfollow), + delete().to(appv2::features::profile::adapters::controllers::unfollow), ), ) .service( diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs new file mode 100644 index 0000000..6b76aba --- /dev/null +++ b/src/appv2/features/mod.rs @@ -0,0 +1 @@ +pub mod profile; diff --git a/src/app/profile/api.rs b/src/appv2/features/profile/adapters/controllers.rs similarity index 89% rename from src/app/profile/api.rs rename to src/appv2/features/profile/adapters/controllers.rs index 907cc5b..d37b460 100644 --- a/src/app/profile/api.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,5 +1,5 @@ -use super::response::ProfileResponse; -use super::service; +use super::super::usecases::services; +use super::presenters::ProfileResponse; use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; @@ -14,9 +14,9 @@ pub async fn show( let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let _username = path.into_inner(); - let profile = service::fetch_by_name( + let profile = services::fetch_by_name( conn, - &service::FetchProfileByName { + &services::FetchProfileByName { current_user, username: _username, }, diff --git a/src/appv2/features/profile/adapters/mod.rs b/src/appv2/features/profile/adapters/mod.rs new file mode 100644 index 0000000..d312732 --- /dev/null +++ b/src/appv2/features/profile/adapters/mod.rs @@ -0,0 +1,2 @@ +pub mod controllers; +pub mod presenters; diff --git a/src/app/profile/response.rs b/src/appv2/features/profile/adapters/presenters.rs similarity index 92% rename from src/app/profile/response.rs rename to src/appv2/features/profile/adapters/presenters.rs index c7e3320..82773ac 100644 --- a/src/app/profile/response.rs +++ b/src/appv2/features/profile/adapters/presenters.rs @@ -1,4 +1,4 @@ -use crate::app::profile::model::Profile as ProfileModel; +use super::super::entities::profile::Profile as ProfileModel; use serde::{Deserialize, Serialize}; use std::convert::From; #[derive(Deserialize, Serialize, Debug, Clone)] diff --git a/src/appv2/features/profile/entities/mod.rs b/src/appv2/features/profile/entities/mod.rs new file mode 100644 index 0000000..6b76aba --- /dev/null +++ b/src/appv2/features/profile/entities/mod.rs @@ -0,0 +1 @@ +pub mod profile; diff --git a/src/app/profile/model.rs b/src/appv2/features/profile/entities/profile.rs similarity index 100% rename from src/app/profile/model.rs rename to src/appv2/features/profile/entities/profile.rs diff --git a/src/appv2/features/profile/mod.rs b/src/appv2/features/profile/mod.rs new file mode 100644 index 0000000..a0da85c --- /dev/null +++ b/src/appv2/features/profile/mod.rs @@ -0,0 +1,3 @@ +pub mod adapters; +pub mod entities; +pub mod usecases; diff --git a/src/appv2/features/profile/usecases/mod.rs b/src/appv2/features/profile/usecases/mod.rs new file mode 100644 index 0000000..4e379ae --- /dev/null +++ b/src/appv2/features/profile/usecases/mod.rs @@ -0,0 +1 @@ +pub mod services; diff --git a/src/app/profile/service.rs b/src/appv2/features/profile/usecases/services.rs similarity index 95% rename from src/app/profile/service.rs rename to src/appv2/features/profile/usecases/services.rs index fcfbb81..034120d 100644 --- a/src/app/profile/service.rs +++ b/src/appv2/features/profile/usecases/services.rs @@ -1,4 +1,4 @@ -use super::model::Profile; +use super::super::entities::profile::Profile; use crate::app::user::model::User; use crate::error::AppError; use diesel::pg::PgConnection; diff --git a/src/appv2/mod.rs b/src/appv2/mod.rs index 2c554a7..710b127 100644 --- a/src/appv2/mod.rs +++ b/src/appv2/mod.rs @@ -1 +1,2 @@ pub mod drivers; +pub mod features; From b7cfc2a0399db7e480b8c8db67d2322694216a96 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 18:21:22 +0900 Subject: [PATCH 04/59] refactor: add profile-repository tmp --- src/appv2/drivers/middlewares/state.rs | 17 ++++++++- .../features/profile/adapters/controllers.rs | 18 ++++----- src/appv2/features/profile/domains/mod.rs | 1 + .../profile/domains/profile_repository.rs | 38 +++++++++++++++++++ src/appv2/features/profile/mod.rs | 1 + src/main.rs | 3 +- 6 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 src/appv2/features/profile/domains/mod.rs create mode 100644 src/appv2/features/profile/domains/profile_repository.rs diff --git a/src/appv2/drivers/middlewares/state.rs b/src/appv2/drivers/middlewares/state.rs index fee3577..440b56a 100644 --- a/src/appv2/drivers/middlewares/state.rs +++ b/src/appv2/drivers/middlewares/state.rs @@ -1,16 +1,29 @@ +// use crate::appv2::features::profile::domains::profile_repository::{ +// IProfileRepository, ProfileRepository, +// }; use crate::error::AppError; -use crate::utils; +use crate::utils::db::DbPool; use diesel::pg::PgConnection; use diesel::r2d2::{ConnectionManager, PooledConnection}; +// use std::sync::Arc; type AppConn = PooledConnection>; #[derive(Clone)] pub struct AppState { - pub pool: utils::db::DbPool, + pub pool: DbPool, + // pub profile_repository: Arc, } impl AppState { + pub fn new(pool: DbPool) -> Self { + // let profile_repository = ProfileRepository::new(pool); + Self { + pool, + // profile_repository: Arc::new(profile_repository), + } + } + pub fn get_conn(&self) -> Result { let conn = self.pool.get()?; Ok(conn) diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index d37b460..27e669b 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,4 +1,4 @@ -use super::super::usecases::services; +use super::super::domains::profile_repository::ProfileRepository; use super::presenters::ProfileResponse; use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; @@ -11,16 +11,12 @@ pub async fn show( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let conn = &mut state.get_conn()?; - let current_user = auth::get_current_user(&req)?; - let _username = path.into_inner(); - let profile = services::fetch_by_name( - conn, - &services::FetchProfileByName { - current_user, - username: _username, - }, - )?; + let repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let profile = { + let current_user = auth::get_current_user(&req)?; + let username = path.into_inner(); + repository.fetch_by_name(¤t_user, &username)? + }; let res = ProfileResponse::from(profile); Ok(HttpResponse::Ok().json(res)) } diff --git a/src/appv2/features/profile/domains/mod.rs b/src/appv2/features/profile/domains/mod.rs new file mode 100644 index 0000000..d9e49c4 --- /dev/null +++ b/src/appv2/features/profile/domains/mod.rs @@ -0,0 +1 @@ +pub mod profile_repository; diff --git a/src/appv2/features/profile/domains/profile_repository.rs b/src/appv2/features/profile/domains/profile_repository.rs new file mode 100644 index 0000000..acc3119 --- /dev/null +++ b/src/appv2/features/profile/domains/profile_repository.rs @@ -0,0 +1,38 @@ +use super::super::entities::profile::Profile; +use crate::app::user::model::User; +use crate::error::AppError; +use crate::utils::db::DbPool; + +pub trait IProfileRepository { + fn fetch_by_name(&self, current_user: &User, username: &str) -> Result; +} + +pub struct ProfileRepository { + pool: DbPool, +} + +impl ProfileRepository { + pub fn new(pool: DbPool) -> Self { + Self { pool } + } + + pub fn fetch_by_name(&self, current_user: &User, username: &str) -> Result { + let conn = &mut self.pool.get()?; + let profile = { + let followee = User::find_by_username(conn, username)?; + current_user.fetch_profile(conn, &followee.id)? + }; + Ok(profile) + } +} + +// impl IProfileRepository for ProfileRepository { +// fn fetch_by_name(&self, current_user: &User, username: &str) -> Result { +// let conn = &mut self.pool.get()?; +// let profile = { +// let followee = User::find_by_username(conn, username)?; +// current_user.fetch_profile(conn, &followee.id)? +// }; +// Ok(profile) +// } +// } diff --git a/src/appv2/features/profile/mod.rs b/src/appv2/features/profile/mod.rs index a0da85c..f6a5324 100644 --- a/src/appv2/features/profile/mod.rs +++ b/src/appv2/features/profile/mod.rs @@ -1,3 +1,4 @@ pub mod adapters; +pub mod domains; pub mod entities; pub mod usecases; diff --git a/src/main.rs b/src/main.rs index 8cd55c8..21526cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,8 @@ async fn main() -> std::io::Result<()> { let state = { let pool = utils::db::establish_connection(); - appv2::drivers::middlewares::state::AppState { pool } + use appv2::drivers::middlewares::state::AppState; + AppState::new(pool) }; HttpServer::new(move || { From 89003be5c6164c564789b0cef65f6d79debd0184 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 19:03:48 +0900 Subject: [PATCH 05/59] refactor: add profile repo/usecase/presenter --- .../features/profile/adapters/controllers.rs | 11 ++++++---- .../features/profile/adapters/presenters.rs | 11 ++++++++++ .../profile/domains/profile_repository.rs | 11 ---------- src/appv2/features/profile/usecases/mod.rs | 1 + .../profile/usecases/show_profile_usecase.rs | 20 +++++++++++++++++++ 5 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 src/appv2/features/profile/usecases/show_profile_usecase.rs diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index 27e669b..3159d48 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,5 +1,6 @@ use super::super::domains::profile_repository::ProfileRepository; -use super::presenters::ProfileResponse; +use super::super::usecases::show_profile_usecase::ShowProfileUsecase; +use super::presenters::{ProfilePresenter, ProfileResponse}; use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; @@ -12,13 +13,15 @@ pub async fn show( path: web::Path, ) -> ApiResponse { let repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let presenter = ProfilePresenter::new(); // TODO: move to DI container. + let usecase = ShowProfileUsecase::new(repository, presenter); // TODO: move to DI container. + let profile = { let current_user = auth::get_current_user(&req)?; let username = path.into_inner(); - repository.fetch_by_name(¤t_user, &username)? + usecase.handle(¤t_user, &username)? }; - let res = ProfileResponse::from(profile); - Ok(HttpResponse::Ok().json(res)) + Ok(HttpResponse::Ok().json(profile)) } pub async fn follow( diff --git a/src/appv2/features/profile/adapters/presenters.rs b/src/appv2/features/profile/adapters/presenters.rs index 82773ac..5261154 100644 --- a/src/appv2/features/profile/adapters/presenters.rs +++ b/src/appv2/features/profile/adapters/presenters.rs @@ -1,6 +1,7 @@ use super::super::entities::profile::Profile as ProfileModel; use serde::{Deserialize, Serialize}; use std::convert::From; + #[derive(Deserialize, Serialize, Debug, Clone)] pub struct ProfileResponse { pub profile: ProfileContent, @@ -25,3 +26,13 @@ impl From for ProfileResponse { ProfileResponse { profile } } } + +pub struct ProfilePresenter {} +impl ProfilePresenter { + pub fn new() -> Self { + Self {} + } + pub fn complete(&self, output: ProfileModel) -> ProfileResponse { + ProfileResponse::from(output) + } +} diff --git a/src/appv2/features/profile/domains/profile_repository.rs b/src/appv2/features/profile/domains/profile_repository.rs index acc3119..c519bd8 100644 --- a/src/appv2/features/profile/domains/profile_repository.rs +++ b/src/appv2/features/profile/domains/profile_repository.rs @@ -25,14 +25,3 @@ impl ProfileRepository { Ok(profile) } } - -// impl IProfileRepository for ProfileRepository { -// fn fetch_by_name(&self, current_user: &User, username: &str) -> Result { -// let conn = &mut self.pool.get()?; -// let profile = { -// let followee = User::find_by_username(conn, username)?; -// current_user.fetch_profile(conn, &followee.id)? -// }; -// Ok(profile) -// } -// } diff --git a/src/appv2/features/profile/usecases/mod.rs b/src/appv2/features/profile/usecases/mod.rs index 4e379ae..4992fb8 100644 --- a/src/appv2/features/profile/usecases/mod.rs +++ b/src/appv2/features/profile/usecases/mod.rs @@ -1 +1,2 @@ pub mod services; +pub mod show_profile_usecase; diff --git a/src/appv2/features/profile/usecases/show_profile_usecase.rs b/src/appv2/features/profile/usecases/show_profile_usecase.rs new file mode 100644 index 0000000..2d149d4 --- /dev/null +++ b/src/appv2/features/profile/usecases/show_profile_usecase.rs @@ -0,0 +1,20 @@ +use super::super::adapters::presenters::{ProfilePresenter, ProfileResponse}; +use super::super::domains::profile_repository::ProfileRepository; +use crate::app::user::model::User; +use crate::error::AppError; + +pub struct ShowProfileUsecase { + repo: ProfileRepository, + presenter: ProfilePresenter, +} + +impl ShowProfileUsecase { + pub fn new(repo: ProfileRepository, presenter: ProfilePresenter) -> Self { + Self { repo, presenter } + } + + pub fn handle(&self, current_user: &User, username: &str) -> Result { + let profile = self.repo.fetch_by_name(current_user, username)?; + Ok(self.presenter.complete(profile)) + } +} From e73d4eae6f171c49643054da710f43eef3e5ecf2 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 19:09:01 +0900 Subject: [PATCH 06/59] refactor: remove unused modules --- README.md | 9 +++++++++ .../features/profile/usecases/services.rs | 20 ------------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index f2f39bc..05f15ba 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,15 @@ $ APIURL=http://localhost:8080/api zsh e2e/run-api-tests.sh ## Architecture +TODO: + +- Clean Architecture + - drivers + - adapters + - domains + - entities + - usecases + ### Flow from Request to Response ```mermaid diff --git a/src/appv2/features/profile/usecases/services.rs b/src/appv2/features/profile/usecases/services.rs index 034120d..839368b 100644 --- a/src/appv2/features/profile/usecases/services.rs +++ b/src/appv2/features/profile/usecases/services.rs @@ -1,27 +1,7 @@ use super::super::entities::profile::Profile; use crate::app::user::model::User; -use crate::error::AppError; use diesel::pg::PgConnection; -pub struct FetchProfileByName { - pub current_user: User, - pub username: String, -} - -pub fn fetch_by_name( - conn: &mut PgConnection, - FetchProfileByName { - current_user, - username, - }: &FetchProfileByName, -) -> Result { - let profile = { - let followee = User::find_by_username(conn, username)?; - current_user.fetch_profile(conn, &followee.id)? - }; - Ok(profile) -} - pub struct ConverUserToProfile<'a> { pub user: &'a User, pub current_user: &'a Option, From 973303aa2d3c8a92e5f72f8232446fd96ed81c2a Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 19:37:17 +0900 Subject: [PATCH 07/59] refactor: update follow on profile features --- src/app/user/model.rs | 40 +++++++++---------- src/appv2/features/mod.rs | 1 + .../features/profile/adapters/controllers.rs | 33 ++++++++++----- .../profile/usecases/show_profile_usecase.rs | 30 ++++++++++---- src/appv2/features/user/domains/mod.rs | 1 + .../features/user/domains/user_repository.rs | 40 +++++++++++++++++++ src/appv2/features/user/mod.rs | 1 + 7 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 src/appv2/features/user/domains/mod.rs create mode 100644 src/appv2/features/user/domains/user_repository.rs create mode 100644 src/appv2/features/user/mod.rs diff --git a/src/app/user/model.rs b/src/app/user/model.rs index 256985a..23eb8a8 100644 --- a/src/app/user/model.rs +++ b/src/app/user/model.rs @@ -46,7 +46,7 @@ impl User { users::username.eq(username) } - fn by_username(username: &str) -> ByUsername + pub fn by_username(username: &str) -> ByUsername where DB: Backend, { @@ -125,25 +125,25 @@ impl User { Ok(user) } - pub fn follow(&self, conn: &mut PgConnection, username: &str) -> Result { - let t = Self::by_username(username); - let followee = t.first::(conn)?; - - Follow::create( - conn, - &CreateFollow { - follower_id: self.id, - followee_id: followee.id, - }, - )?; - - Ok(Profile { - username: self.username.clone(), - bio: self.bio.clone(), - image: self.image.clone(), - following: true, - }) - } + // pub fn follow(&self, conn: &mut PgConnection, username: &str) -> Result { + // let t = Self::by_username(username); + // let followee = t.first::(conn)?; + + // Follow::create( + // conn, + // &CreateFollow { + // follower_id: self.id, + // followee_id: followee.id, + // }, + // )?; + + // Ok(Profile { + // username: self.username.clone(), + // bio: self.bio.clone(), + // image: self.image.clone(), + // following: true, + // }) + // } pub fn unfollow(&self, conn: &mut PgConnection, username: &str) -> Result { let t = Self::by_username(username); diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index 6b76aba..322b928 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -1 +1,2 @@ pub mod profile; +pub mod user; diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index 3159d48..2137358 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,7 +1,8 @@ use super::super::domains::profile_repository::ProfileRepository; -use super::super::usecases::show_profile_usecase::ShowProfileUsecase; +use super::super::usecases::show_profile_usecase::ProfileUsecase; use super::presenters::{ProfilePresenter, ProfileResponse}; use crate::appv2::drivers::middlewares::{auth, state::AppState}; +use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; @@ -12,14 +13,18 @@ pub async fn show( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let repositories = { + let profileRepository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let userRepository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. + (profileRepository, userRepository) + }; let presenter = ProfilePresenter::new(); // TODO: move to DI container. - let usecase = ShowProfileUsecase::new(repository, presenter); // TODO: move to DI container. + let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. let profile = { let current_user = auth::get_current_user(&req)?; let username = path.into_inner(); - usecase.handle(¤t_user, &username)? + usecase.show(¤t_user, &username)? }; Ok(HttpResponse::Ok().json(profile)) } @@ -29,12 +34,20 @@ pub async fn follow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let conn = &mut state.get_conn()?; - let current_user = auth::get_current_user(&req)?; - let username = path.into_inner(); - let profile = current_user.follow(conn, &username)?; - let res = ProfileResponse::from(profile); - Ok(HttpResponse::Ok().json(res)) + let repositories = { + let profileRepository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let userRepository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. + (profileRepository, userRepository) + }; + let presenter = ProfilePresenter::new(); // TODO: move to DI container. + let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. + + let profile = { + let current_user = auth::get_current_user(&req)?; + let username = path.into_inner(); + usecase.follow(¤t_user, &username)? + }; + Ok(HttpResponse::Ok().json(profile)) } pub async fn unfollow( diff --git a/src/appv2/features/profile/usecases/show_profile_usecase.rs b/src/appv2/features/profile/usecases/show_profile_usecase.rs index 2d149d4..93ceda8 100644 --- a/src/appv2/features/profile/usecases/show_profile_usecase.rs +++ b/src/appv2/features/profile/usecases/show_profile_usecase.rs @@ -1,20 +1,36 @@ use super::super::adapters::presenters::{ProfilePresenter, ProfileResponse}; use super::super::domains::profile_repository::ProfileRepository; use crate::app::user::model::User; +use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::error::AppError; -pub struct ShowProfileUsecase { - repo: ProfileRepository, +pub struct ProfileUsecase { + userRepository: UserRepository, + profileRepository: ProfileRepository, presenter: ProfilePresenter, } -impl ShowProfileUsecase { - pub fn new(repo: ProfileRepository, presenter: ProfilePresenter) -> Self { - Self { repo, presenter } +impl ProfileUsecase { + pub fn new( + (profileRepository, userRepository): (ProfileRepository, UserRepository), + presenter: ProfilePresenter, + ) -> Self { + Self { + profileRepository, + userRepository, + presenter, + } } - pub fn handle(&self, current_user: &User, username: &str) -> Result { - let profile = self.repo.fetch_by_name(current_user, username)?; + pub fn show(&self, current_user: &User, username: &str) -> Result { + let profile = self + .profileRepository + .fetch_by_name(current_user, username)?; + Ok(self.presenter.complete(profile)) + } + + pub fn follow(&self, current_user: &User, username: &str) -> Result { + let profile = current_user.follow(conn, &username)?; Ok(self.presenter.complete(profile)) } } diff --git a/src/appv2/features/user/domains/mod.rs b/src/appv2/features/user/domains/mod.rs new file mode 100644 index 0000000..a5188ff --- /dev/null +++ b/src/appv2/features/user/domains/mod.rs @@ -0,0 +1 @@ +pub mod user_repository; diff --git a/src/appv2/features/user/domains/user_repository.rs b/src/appv2/features/user/domains/user_repository.rs new file mode 100644 index 0000000..d519bad --- /dev/null +++ b/src/appv2/features/user/domains/user_repository.rs @@ -0,0 +1,40 @@ +use crate::app::follow::model::{CreateFollow, Follow}; +use crate::app::user::model::User; +use crate::appv2::features::profile::entities::profile::Profile; +use crate::error::AppError; +use crate::utils::db::DbPool; + +pub struct UserRepository { + pool: DbPool, +} + +impl UserRepository { + pub fn new(pool: DbPool) -> Self { + Self { pool } + } + + pub fn follow(&self, current_user: &User, target_username: &str) -> Result { + let conn = &mut self.pool.get()?; + let t = User::by_username(target_username); + + let followee = { + use diesel::prelude::*; + t.first::(conn)? + }; + + Follow::create( + conn, + &CreateFollow { + follower_id: current_user.id, + followee_id: followee.id, + }, + )?; + + Ok(Profile { + username: current_user.username.clone(), + bio: current_user.bio.clone(), + image: current_user.image.clone(), + following: true, + }) + } +} diff --git a/src/appv2/features/user/mod.rs b/src/appv2/features/user/mod.rs new file mode 100644 index 0000000..979f2a2 --- /dev/null +++ b/src/appv2/features/user/mod.rs @@ -0,0 +1 @@ +pub mod domains; From 24c119aca08708a56fbbfd3b9da8b0093a17db57 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 19:44:56 +0900 Subject: [PATCH 08/59] fix: update profile_usecase --- .../features/profile/adapters/controllers.rs | 2 +- src/appv2/features/profile/usecases/mod.rs | 2 +- ..._profile_usecase.rs => profile_usecase.rs} | 20 +++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) rename src/appv2/features/profile/usecases/{show_profile_usecase.rs => profile_usecase.rs} (61%) diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index 2137358..99a3f1e 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,5 +1,5 @@ use super::super::domains::profile_repository::ProfileRepository; -use super::super::usecases::show_profile_usecase::ProfileUsecase; +use super::super::usecases::profile_usecase::ProfileUsecase; use super::presenters::{ProfilePresenter, ProfileResponse}; use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::appv2::features::user::domains::user_repository::UserRepository; diff --git a/src/appv2/features/profile/usecases/mod.rs b/src/appv2/features/profile/usecases/mod.rs index 4992fb8..59b447e 100644 --- a/src/appv2/features/profile/usecases/mod.rs +++ b/src/appv2/features/profile/usecases/mod.rs @@ -1,2 +1,2 @@ +pub mod profile_usecase; pub mod services; -pub mod show_profile_usecase; diff --git a/src/appv2/features/profile/usecases/show_profile_usecase.rs b/src/appv2/features/profile/usecases/profile_usecase.rs similarity index 61% rename from src/appv2/features/profile/usecases/show_profile_usecase.rs rename to src/appv2/features/profile/usecases/profile_usecase.rs index 93ceda8..5aec3b1 100644 --- a/src/appv2/features/profile/usecases/show_profile_usecase.rs +++ b/src/appv2/features/profile/usecases/profile_usecase.rs @@ -5,32 +5,36 @@ use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::error::AppError; pub struct ProfileUsecase { - userRepository: UserRepository, - profileRepository: ProfileRepository, + user_repository: UserRepository, + profile_repository: ProfileRepository, presenter: ProfilePresenter, } impl ProfileUsecase { pub fn new( - (profileRepository, userRepository): (ProfileRepository, UserRepository), + (profile_repository, user_repository): (ProfileRepository, UserRepository), presenter: ProfilePresenter, ) -> Self { Self { - profileRepository, - userRepository, + profile_repository, + user_repository, presenter, } } pub fn show(&self, current_user: &User, username: &str) -> Result { let profile = self - .profileRepository + .profile_repository .fetch_by_name(current_user, username)?; Ok(self.presenter.complete(profile)) } - pub fn follow(&self, current_user: &User, username: &str) -> Result { - let profile = current_user.follow(conn, &username)?; + pub fn follow( + &self, + current_user: &User, + target_username: &str, + ) -> Result { + let profile = self.user_repository.follow(current_user, target_username)?; Ok(self.presenter.complete(profile)) } } From f3e02958c33d8e0e652a03ceec26453a62301667 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 19:47:05 +0900 Subject: [PATCH 09/59] refactor: update unfollow on profile --- src/app/user/model.rs | 42 +------------------ .../features/profile/adapters/controllers.rs | 36 +++++++++------- .../profile/usecases/profile_usecase.rs | 11 +++++ .../features/user/domains/user_repository.rs | 30 ++++++++++++- 4 files changed, 63 insertions(+), 56 deletions(-) diff --git a/src/app/user/model.rs b/src/app/user/model.rs index 23eb8a8..14bc101 100644 --- a/src/app/user/model.rs +++ b/src/app/user/model.rs @@ -1,5 +1,5 @@ use crate::app::favorite::model::Favorite; -use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; +use crate::app::follow::model::Follow; use crate::appv2::features::profile::entities::profile::Profile; use crate::error::AppError; use crate::schema::users; @@ -125,46 +125,6 @@ impl User { Ok(user) } - // pub fn follow(&self, conn: &mut PgConnection, username: &str) -> Result { - // let t = Self::by_username(username); - // let followee = t.first::(conn)?; - - // Follow::create( - // conn, - // &CreateFollow { - // follower_id: self.id, - // followee_id: followee.id, - // }, - // )?; - - // Ok(Profile { - // username: self.username.clone(), - // bio: self.bio.clone(), - // image: self.image.clone(), - // following: true, - // }) - // } - - pub fn unfollow(&self, conn: &mut PgConnection, username: &str) -> Result { - let t = Self::by_username(username); - let followee = t.first::(conn)?; - - Follow::delete( - conn, - &DeleteFollow { - followee_id: followee.id, - follower_id: self.id, - }, - )?; - - Ok(Profile { - username: self.username.clone(), - bio: self.bio.clone(), - image: self.image.clone(), - following: false, - }) - } - pub fn is_following(&self, conn: &mut PgConnection, followee_id: &Uuid) -> bool { use crate::schema::follows; let t = follows::table diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index 99a3f1e..a14829c 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -14,9 +14,9 @@ pub async fn show( path: web::Path, ) -> ApiResponse { let repositories = { - let profileRepository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. - let userRepository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. - (profileRepository, userRepository) + let profile_repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let user_repository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. + (profile_repository, user_repository) }; let presenter = ProfilePresenter::new(); // TODO: move to DI container. let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. @@ -35,17 +35,17 @@ pub async fn follow( path: web::Path, ) -> ApiResponse { let repositories = { - let profileRepository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. - let userRepository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. - (profileRepository, userRepository) + let profile_repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let user_repository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. + (profile_repository, user_repository) }; let presenter = ProfilePresenter::new(); // TODO: move to DI container. let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. let profile = { let current_user = auth::get_current_user(&req)?; - let username = path.into_inner(); - usecase.follow(¤t_user, &username)? + let target_username = path.into_inner(); + usecase.follow(¤t_user, &target_username)? }; Ok(HttpResponse::Ok().json(profile)) } @@ -55,10 +55,18 @@ pub async fn unfollow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let conn = &mut state.get_conn()?; - let current_user = auth::get_current_user(&req)?; - let username = path.into_inner(); - let profile = current_user.unfollow(conn, &username)?; - let res = ProfileResponse::from(profile); - Ok(HttpResponse::Ok().json(res)) + let repositories = { + let profile_repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. + let user_repository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. + (profile_repository, user_repository) + }; + let presenter = ProfilePresenter::new(); // TODO: move to DI container. + let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. + + let profile = { + let current_user = auth::get_current_user(&req)?; + let target_username = path.into_inner(); + usecase.unfollow(¤t_user, &target_username)? + }; + Ok(HttpResponse::Ok().json(profile)) } diff --git a/src/appv2/features/profile/usecases/profile_usecase.rs b/src/appv2/features/profile/usecases/profile_usecase.rs index 5aec3b1..0422708 100644 --- a/src/appv2/features/profile/usecases/profile_usecase.rs +++ b/src/appv2/features/profile/usecases/profile_usecase.rs @@ -37,4 +37,15 @@ impl ProfileUsecase { let profile = self.user_repository.follow(current_user, target_username)?; Ok(self.presenter.complete(profile)) } + + pub fn unfollow( + &self, + current_user: &User, + target_username: &str, + ) -> Result { + let profile = self + .user_repository + .unfollow(current_user, target_username)?; + Ok(self.presenter.complete(profile)) + } } diff --git a/src/appv2/features/user/domains/user_repository.rs b/src/appv2/features/user/domains/user_repository.rs index d519bad..969dea6 100644 --- a/src/appv2/features/user/domains/user_repository.rs +++ b/src/appv2/features/user/domains/user_repository.rs @@ -1,4 +1,4 @@ -use crate::app::follow::model::{CreateFollow, Follow}; +use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; use crate::app::user::model::User; use crate::appv2::features::profile::entities::profile::Profile; use crate::error::AppError; @@ -37,4 +37,32 @@ impl UserRepository { following: true, }) } + + pub fn unfollow( + &self, + current_user: &User, + target_username: &str, + ) -> Result { + let conn = &mut self.pool.get()?; + let t = User::by_username(target_username); + let followee = { + use diesel::prelude::*; + t.first::(conn)? + }; + + Follow::delete( + conn, + &DeleteFollow { + followee_id: followee.id, + follower_id: current_user.id, + }, + )?; + + Ok(Profile { + username: current_user.username.clone(), + bio: current_user.bio.clone(), + image: current_user.image.clone(), + following: false, + }) + } } From 026ca7acbb46a98ecc11cb458cf3d3abb68e1ca9 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 21:04:36 +0900 Subject: [PATCH 10/59] feat: create di container --- .../features/profile/adapters/controllers.rs | 42 +++++-------------- .../features/profile/adapters/presenters.rs | 1 + .../profile/domains/profile_repository.rs | 1 + .../features/user/domains/user_repository.rs | 1 + src/utils/di.rs | 38 +++++++++++++++++ src/utils/mod.rs | 1 + 6 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 src/utils/di.rs diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index a14829c..16c665d 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,9 +1,6 @@ -use super::super::domains::profile_repository::ProfileRepository; -use super::super::usecases::profile_usecase::ProfileUsecase; -use super::presenters::{ProfilePresenter, ProfileResponse}; use crate::appv2::drivers::middlewares::{auth, state::AppState}; -use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::utils::api::ApiResponse; +use crate::utils::di::DiContainer; use actix_web::{web, HttpRequest, HttpResponse}; type UsernameSlug = String; @@ -13,18 +10,11 @@ pub async fn show( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let repositories = { - let profile_repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. - let user_repository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. - (profile_repository, user_repository) - }; - let presenter = ProfilePresenter::new(); // TODO: move to DI container. - let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. - + let container = DiContainer::new(&state.pool); // TODO: move di to top let profile = { let current_user = auth::get_current_user(&req)?; let username = path.into_inner(); - usecase.show(¤t_user, &username)? + container.profile_usecase.show(¤t_user, &username)? }; Ok(HttpResponse::Ok().json(profile)) } @@ -34,18 +24,13 @@ pub async fn follow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let repositories = { - let profile_repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. - let user_repository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. - (profile_repository, user_repository) - }; - let presenter = ProfilePresenter::new(); // TODO: move to DI container. - let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. - + let container = DiContainer::new(&state.pool); // TODO: move di to top let profile = { let current_user = auth::get_current_user(&req)?; let target_username = path.into_inner(); - usecase.follow(¤t_user, &target_username)? + container + .profile_usecase + .follow(¤t_user, &target_username)? }; Ok(HttpResponse::Ok().json(profile)) } @@ -55,18 +40,13 @@ pub async fn unfollow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let repositories = { - let profile_repository = ProfileRepository::new(state.pool.clone()); // TODO: move to DI container. - let user_repository = UserRepository::new(state.pool.clone()); // TODO: move to DI container. - (profile_repository, user_repository) - }; - let presenter = ProfilePresenter::new(); // TODO: move to DI container. - let usecase = ProfileUsecase::new(repositories, presenter); // TODO: move to DI container. - + let container = DiContainer::new(&state.pool); // TODO: move di to top let profile = { let current_user = auth::get_current_user(&req)?; let target_username = path.into_inner(); - usecase.unfollow(¤t_user, &target_username)? + container + .profile_usecase + .unfollow(¤t_user, &target_username)? }; Ok(HttpResponse::Ok().json(profile)) } diff --git a/src/appv2/features/profile/adapters/presenters.rs b/src/appv2/features/profile/adapters/presenters.rs index 5261154..db524d0 100644 --- a/src/appv2/features/profile/adapters/presenters.rs +++ b/src/appv2/features/profile/adapters/presenters.rs @@ -27,6 +27,7 @@ impl From for ProfileResponse { } } +#[derive(Clone)] pub struct ProfilePresenter {} impl ProfilePresenter { pub fn new() -> Self { diff --git a/src/appv2/features/profile/domains/profile_repository.rs b/src/appv2/features/profile/domains/profile_repository.rs index c519bd8..7ac7cbb 100644 --- a/src/appv2/features/profile/domains/profile_repository.rs +++ b/src/appv2/features/profile/domains/profile_repository.rs @@ -7,6 +7,7 @@ pub trait IProfileRepository { fn fetch_by_name(&self, current_user: &User, username: &str) -> Result; } +#[derive(Clone)] pub struct ProfileRepository { pool: DbPool, } diff --git a/src/appv2/features/user/domains/user_repository.rs b/src/appv2/features/user/domains/user_repository.rs index 969dea6..7184b35 100644 --- a/src/appv2/features/user/domains/user_repository.rs +++ b/src/appv2/features/user/domains/user_repository.rs @@ -4,6 +4,7 @@ use crate::appv2::features::profile::entities::profile::Profile; use crate::error::AppError; use crate::utils::db::DbPool; +#[derive(Clone)] pub struct UserRepository { pool: DbPool, } diff --git a/src/utils/di.rs b/src/utils/di.rs new file mode 100644 index 0000000..b5de4bb --- /dev/null +++ b/src/utils/di.rs @@ -0,0 +1,38 @@ +use crate::appv2::features::profile::adapters::presenters::ProfilePresenter; +use crate::appv2::features::profile::domains::profile_repository::ProfileRepository; +use crate::appv2::features::profile::usecases::profile_usecase::ProfileUsecase; +use crate::appv2::features::user::domains::user_repository::UserRepository; + +use crate::utils::db::DbPool; + +pub struct DiContainer { + /** + * Profile + */ + pub profile_repository: ProfileRepository, + pub profile_presenter: ProfilePresenter, + pub profile_usecase: ProfileUsecase, + + /** + * User + */ + pub user_repository: UserRepository, +} + +impl DiContainer { + pub fn new(pool: &DbPool) -> Self { + let profile_repository = ProfileRepository::new(pool.clone()); + let user_repository = UserRepository::new(pool.clone()); + let profile_presenter = ProfilePresenter::new(); + let profile_usecase = ProfileUsecase::new( + (profile_repository.clone(), user_repository.clone()), + profile_presenter.clone(), + ); + Self { + profile_presenter, + profile_repository, + profile_usecase, + user_repository, + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index a3f00b1..5c0f2cf 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,6 +2,7 @@ pub mod api; pub mod converter; pub mod date; pub mod db; +pub mod di; pub mod hasher; pub mod token; pub mod uuid; From 932d126d457b3d2b6e354d35ae8790e8781dd550 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 21:10:36 +0900 Subject: [PATCH 11/59] fix: replace with di-container --- src/appv2/drivers/middlewares/state.rs | 11 +++++------ .../features/profile/adapters/controllers.rs | 15 ++++++++------- .../features/profile/usecases/profile_usecase.rs | 1 + src/utils/di.rs | 1 + 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/appv2/drivers/middlewares/state.rs b/src/appv2/drivers/middlewares/state.rs index 440b56a..cd6ede1 100644 --- a/src/appv2/drivers/middlewares/state.rs +++ b/src/appv2/drivers/middlewares/state.rs @@ -6,22 +6,21 @@ use crate::utils::db::DbPool; use diesel::pg::PgConnection; use diesel::r2d2::{ConnectionManager, PooledConnection}; // use std::sync::Arc; +use crate::utils::di::DiContainer; type AppConn = PooledConnection>; #[derive(Clone)] pub struct AppState { + #[deprecated] pub pool: DbPool, - // pub profile_repository: Arc, + pub di_container: DiContainer, } impl AppState { pub fn new(pool: DbPool) -> Self { - // let profile_repository = ProfileRepository::new(pool); - Self { - pool, - // profile_repository: Arc::new(profile_repository), - } + let di_container = DiContainer::new(&pool); + Self { pool, di_container } } pub fn get_conn(&self) -> Result { diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index 16c665d..d4ac29c 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,6 +1,5 @@ use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; -use crate::utils::di::DiContainer; use actix_web::{web, HttpRequest, HttpResponse}; type UsernameSlug = String; @@ -10,11 +9,13 @@ pub async fn show( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let container = DiContainer::new(&state.pool); // TODO: move di to top let profile = { let current_user = auth::get_current_user(&req)?; let username = path.into_inner(); - container.profile_usecase.show(¤t_user, &username)? + state + .di_container + .profile_usecase + .show(¤t_user, &username)? }; Ok(HttpResponse::Ok().json(profile)) } @@ -24,11 +25,11 @@ pub async fn follow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let container = DiContainer::new(&state.pool); // TODO: move di to top let profile = { let current_user = auth::get_current_user(&req)?; let target_username = path.into_inner(); - container + state + .di_container .profile_usecase .follow(¤t_user, &target_username)? }; @@ -40,11 +41,11 @@ pub async fn unfollow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let container = DiContainer::new(&state.pool); // TODO: move di to top let profile = { let current_user = auth::get_current_user(&req)?; let target_username = path.into_inner(); - container + state + .di_container .profile_usecase .unfollow(¤t_user, &target_username)? }; diff --git a/src/appv2/features/profile/usecases/profile_usecase.rs b/src/appv2/features/profile/usecases/profile_usecase.rs index 0422708..3802be5 100644 --- a/src/appv2/features/profile/usecases/profile_usecase.rs +++ b/src/appv2/features/profile/usecases/profile_usecase.rs @@ -4,6 +4,7 @@ use crate::app::user::model::User; use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::error::AppError; +#[derive(Clone)] pub struct ProfileUsecase { user_repository: UserRepository, profile_repository: ProfileRepository, diff --git a/src/utils/di.rs b/src/utils/di.rs index b5de4bb..2df1afd 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -5,6 +5,7 @@ use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::utils::db::DbPool; +#[derive(Clone)] pub struct DiContainer { /** * Profile From c398021a6754bf839e86ac236a3e15ec1417795f Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 21:21:15 +0900 Subject: [PATCH 12/59] refactor: update presenter --- .../features/profile/adapters/controllers.rs | 50 ++++++++----------- .../features/profile/adapters/presenters.rs | 6 ++- .../profile/usecases/profile_usecase.rs | 7 +-- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/adapters/controllers.rs index d4ac29c..ccdb2f0 100644 --- a/src/appv2/features/profile/adapters/controllers.rs +++ b/src/appv2/features/profile/adapters/controllers.rs @@ -1,6 +1,6 @@ use crate::appv2::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; type UsernameSlug = String; @@ -9,15 +9,13 @@ pub async fn show( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let profile = { - let current_user = auth::get_current_user(&req)?; - let username = path.into_inner(); - state - .di_container - .profile_usecase - .show(¤t_user, &username)? - }; - Ok(HttpResponse::Ok().json(profile)) + let current_user = auth::get_current_user(&req)?; + let username = path.into_inner(); + let res = state + .di_container + .profile_usecase + .show(¤t_user, &username)?; + Ok(res) } pub async fn follow( @@ -25,15 +23,13 @@ pub async fn follow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let profile = { - let current_user = auth::get_current_user(&req)?; - let target_username = path.into_inner(); - state - .di_container - .profile_usecase - .follow(¤t_user, &target_username)? - }; - Ok(HttpResponse::Ok().json(profile)) + let current_user = auth::get_current_user(&req)?; + let target_username = path.into_inner(); + let res = state + .di_container + .profile_usecase + .follow(¤t_user, &target_username)?; + Ok(res) } pub async fn unfollow( @@ -41,13 +37,11 @@ pub async fn unfollow( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let profile = { - let current_user = auth::get_current_user(&req)?; - let target_username = path.into_inner(); - state - .di_container - .profile_usecase - .unfollow(¤t_user, &target_username)? - }; - Ok(HttpResponse::Ok().json(profile)) + let current_user = auth::get_current_user(&req)?; + let target_username = path.into_inner(); + let res = state + .di_container + .profile_usecase + .unfollow(¤t_user, &target_username)?; + Ok(res) } diff --git a/src/appv2/features/profile/adapters/presenters.rs b/src/appv2/features/profile/adapters/presenters.rs index db524d0..8dba906 100644 --- a/src/appv2/features/profile/adapters/presenters.rs +++ b/src/appv2/features/profile/adapters/presenters.rs @@ -1,4 +1,5 @@ use super::super::entities::profile::Profile as ProfileModel; +use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; use std::convert::From; @@ -33,7 +34,8 @@ impl ProfilePresenter { pub fn new() -> Self { Self {} } - pub fn complete(&self, output: ProfileModel) -> ProfileResponse { - ProfileResponse::from(output) + pub fn complete(&self, model: ProfileModel) -> HttpResponse { + let res_model = ProfileResponse::from(model); + HttpResponse::Ok().json(res_model) } } diff --git a/src/appv2/features/profile/usecases/profile_usecase.rs b/src/appv2/features/profile/usecases/profile_usecase.rs index 3802be5..c91895a 100644 --- a/src/appv2/features/profile/usecases/profile_usecase.rs +++ b/src/appv2/features/profile/usecases/profile_usecase.rs @@ -3,6 +3,7 @@ use super::super::domains::profile_repository::ProfileRepository; use crate::app::user::model::User; use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::error::AppError; +use actix_web::HttpResponse; #[derive(Clone)] pub struct ProfileUsecase { @@ -23,7 +24,7 @@ impl ProfileUsecase { } } - pub fn show(&self, current_user: &User, username: &str) -> Result { + pub fn show(&self, current_user: &User, username: &str) -> Result { let profile = self .profile_repository .fetch_by_name(current_user, username)?; @@ -34,7 +35,7 @@ impl ProfileUsecase { &self, current_user: &User, target_username: &str, - ) -> Result { + ) -> Result { let profile = self.user_repository.follow(current_user, target_username)?; Ok(self.presenter.complete(profile)) } @@ -43,7 +44,7 @@ impl ProfileUsecase { &self, current_user: &User, target_username: &str, - ) -> Result { + ) -> Result { let profile = self .user_repository .unfollow(current_user, target_username)?; From 7be6f4c60d03566b32ae3de43ac7d9367b9c1b61 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 22:24:41 +0900 Subject: [PATCH 13/59] refactor: organize dir on profile --- src/app/article/response.rs | 2 +- src/app/article/service.rs | 2 +- src/app/comment/response.rs | 2 +- src/app/comment/service.rs | 2 +- src/app/favorite/service.rs | 2 +- src/app/user/model.rs | 2 +- src/appv2/drivers/routes.rs | 6 +++--- src/appv2/features/profile/adapters/mod.rs | 2 -- src/appv2/features/profile/{adapters => }/controllers.rs | 0 src/appv2/features/profile/domains/mod.rs | 1 - .../features/profile/{entities/profile.rs => entities.rs} | 0 src/appv2/features/profile/entities/mod.rs | 1 - src/appv2/features/profile/mod.rs | 6 ++++-- src/appv2/features/profile/{adapters => }/presenters.rs | 2 +- .../{domains/profile_repository.rs => repositories.rs} | 2 +- src/appv2/features/profile/{usecases => }/services.rs | 4 +++- .../profile/{usecases/profile_usecase.rs => usecases.rs} | 4 ++-- src/appv2/features/profile/usecases/mod.rs | 2 -- src/appv2/features/user/domains/user_repository.rs | 2 +- 19 files changed, 21 insertions(+), 23 deletions(-) delete mode 100644 src/appv2/features/profile/adapters/mod.rs rename src/appv2/features/profile/{adapters => }/controllers.rs (100%) delete mode 100644 src/appv2/features/profile/domains/mod.rs rename src/appv2/features/profile/{entities/profile.rs => entities.rs} (100%) delete mode 100644 src/appv2/features/profile/entities/mod.rs rename src/appv2/features/profile/{adapters => }/presenters.rs (94%) rename src/appv2/features/profile/{domains/profile_repository.rs => repositories.rs} (93%) rename src/appv2/features/profile/{usecases => }/services.rs (85%) rename src/appv2/features/profile/{usecases/profile_usecase.rs => usecases.rs} (91%) delete mode 100644 src/appv2/features/profile/usecases/mod.rs diff --git a/src/app/article/response.rs b/src/app/article/response.rs index b729f3b..dde8f06 100644 --- a/src/app/article/response.rs +++ b/src/app/article/response.rs @@ -1,7 +1,7 @@ use crate::app::article::model::Article; use crate::app::favorite::model::FavoriteInfo; use crate::app::tag::model::Tag; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::utils::date::Iso8601; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/app/article/service.rs b/src/app/article/service.rs index 2c93848..6b71f7d 100644 --- a/src/app/article/service.rs +++ b/src/app/article/service.rs @@ -3,7 +3,7 @@ use crate::app::favorite::model::{Favorite, FavoriteInfo}; use crate::app::follow::model::Follow; use crate::app::tag::model::{CreateTag, Tag}; use crate::app::user::model::User; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::error::AppError; use crate::schema::articles::dsl::*; use crate::schema::{articles, tags, users}; diff --git a/src/app/comment/response.rs b/src/app/comment/response.rs index 20a1f98..ec06c3d 100644 --- a/src/app/comment/response.rs +++ b/src/app/comment/response.rs @@ -1,5 +1,5 @@ use crate::app::comment::model::Comment; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::utils::date::Iso8601; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/app/comment/service.rs b/src/app/comment/service.rs index da3766d..6763194 100644 --- a/src/app/comment/service.rs +++ b/src/app/comment/service.rs @@ -1,7 +1,7 @@ use super::model::{Comment, CreateComment, DeleteComment}; use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; use crate::app::user::model::User; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::profile::usecases::services::{ conver_user_to_profile, ConverUserToProfile, }; diff --git a/src/app/favorite/service.rs b/src/app/favorite/service.rs index c3ac76d..05d61aa 100644 --- a/src/app/favorite/service.rs +++ b/src/app/favorite/service.rs @@ -3,7 +3,7 @@ use crate::app::article::service::{fetch_article, FetchArticle}; use crate::app::favorite::model::{CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo}; use crate::app::tag::model::Tag; use crate::app::user::model::User; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::error::AppError; use diesel::pg::PgConnection; diff --git a/src/app/user/model.rs b/src/app/user/model.rs index 14bc101..b3b4a81 100644 --- a/src/app/user/model.rs +++ b/src/app/user/model.rs @@ -1,6 +1,6 @@ use crate::app::favorite::model::Favorite; use crate::app::follow::model::Follow; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::error::AppError; use crate::schema::users; use crate::utils::{hasher, token}; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index b1a9ae0..7180c56 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -22,15 +22,15 @@ pub fn api(cfg: &mut web::ServiceConfig) { web::scope("/profiles") .route( "/{username}", - get().to(appv2::features::profile::adapters::controllers::show), + get().to(appv2::features::profile::controllers::show), ) .route( "/{username}/follow", - post().to(appv2::features::profile::adapters::controllers::follow), + post().to(appv2::features::profile::controllers::follow), ) .route( "/{username}/follow", - delete().to(appv2::features::profile::adapters::controllers::unfollow), + delete().to(appv2::features::profile::controllers::unfollow), ), ) .service( diff --git a/src/appv2/features/profile/adapters/mod.rs b/src/appv2/features/profile/adapters/mod.rs deleted file mode 100644 index d312732..0000000 --- a/src/appv2/features/profile/adapters/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod controllers; -pub mod presenters; diff --git a/src/appv2/features/profile/adapters/controllers.rs b/src/appv2/features/profile/controllers.rs similarity index 100% rename from src/appv2/features/profile/adapters/controllers.rs rename to src/appv2/features/profile/controllers.rs diff --git a/src/appv2/features/profile/domains/mod.rs b/src/appv2/features/profile/domains/mod.rs deleted file mode 100644 index d9e49c4..0000000 --- a/src/appv2/features/profile/domains/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod profile_repository; diff --git a/src/appv2/features/profile/entities/profile.rs b/src/appv2/features/profile/entities.rs similarity index 100% rename from src/appv2/features/profile/entities/profile.rs rename to src/appv2/features/profile/entities.rs diff --git a/src/appv2/features/profile/entities/mod.rs b/src/appv2/features/profile/entities/mod.rs deleted file mode 100644 index 6b76aba..0000000 --- a/src/appv2/features/profile/entities/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod profile; diff --git a/src/appv2/features/profile/mod.rs b/src/appv2/features/profile/mod.rs index f6a5324..923a07e 100644 --- a/src/appv2/features/profile/mod.rs +++ b/src/appv2/features/profile/mod.rs @@ -1,4 +1,6 @@ -pub mod adapters; -pub mod domains; +pub mod controllers; pub mod entities; +pub mod presenters; +pub mod repositories; +pub mod services; pub mod usecases; diff --git a/src/appv2/features/profile/adapters/presenters.rs b/src/appv2/features/profile/presenters.rs similarity index 94% rename from src/appv2/features/profile/adapters/presenters.rs rename to src/appv2/features/profile/presenters.rs index 8dba906..622ff96 100644 --- a/src/appv2/features/profile/adapters/presenters.rs +++ b/src/appv2/features/profile/presenters.rs @@ -1,4 +1,4 @@ -use super::super::entities::profile::Profile as ProfileModel; +use super::entities::Profile as ProfileModel; use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/appv2/features/profile/domains/profile_repository.rs b/src/appv2/features/profile/repositories.rs similarity index 93% rename from src/appv2/features/profile/domains/profile_repository.rs rename to src/appv2/features/profile/repositories.rs index 7ac7cbb..7330207 100644 --- a/src/appv2/features/profile/domains/profile_repository.rs +++ b/src/appv2/features/profile/repositories.rs @@ -1,4 +1,4 @@ -use super::super::entities::profile::Profile; +use super::entities::Profile; use crate::app::user::model::User; use crate::error::AppError; use crate::utils::db::DbPool; diff --git a/src/appv2/features/profile/usecases/services.rs b/src/appv2/features/profile/services.rs similarity index 85% rename from src/appv2/features/profile/usecases/services.rs rename to src/appv2/features/profile/services.rs index 839368b..a3b9571 100644 --- a/src/appv2/features/profile/usecases/services.rs +++ b/src/appv2/features/profile/services.rs @@ -1,12 +1,14 @@ -use super::super::entities::profile::Profile; +use super::entities::Profile; use crate::app::user::model::User; use diesel::pg::PgConnection; +#[deprecated(note = "use repository")] pub struct ConverUserToProfile<'a> { pub user: &'a User, pub current_user: &'a Option, } +#[deprecated(note = "use repository")] pub fn conver_user_to_profile(conn: &mut PgConnection, params: &ConverUserToProfile) -> Profile { let following = match params.current_user.as_ref() { Some(current_user) => current_user.is_following(conn, ¶ms.user.id), diff --git a/src/appv2/features/profile/usecases/profile_usecase.rs b/src/appv2/features/profile/usecases.rs similarity index 91% rename from src/appv2/features/profile/usecases/profile_usecase.rs rename to src/appv2/features/profile/usecases.rs index c91895a..a243b57 100644 --- a/src/appv2/features/profile/usecases/profile_usecase.rs +++ b/src/appv2/features/profile/usecases.rs @@ -1,5 +1,5 @@ -use super::super::adapters::presenters::{ProfilePresenter, ProfileResponse}; -use super::super::domains::profile_repository::ProfileRepository; +use super::presenters::ProfilePresenter; +use super::repositories::ProfileRepository; use crate::app::user::model::User; use crate::appv2::features::user::domains::user_repository::UserRepository; use crate::error::AppError; diff --git a/src/appv2/features/profile/usecases/mod.rs b/src/appv2/features/profile/usecases/mod.rs deleted file mode 100644 index 59b447e..0000000 --- a/src/appv2/features/profile/usecases/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod profile_usecase; -pub mod services; diff --git a/src/appv2/features/user/domains/user_repository.rs b/src/appv2/features/user/domains/user_repository.rs index 7184b35..b931bc6 100644 --- a/src/appv2/features/user/domains/user_repository.rs +++ b/src/appv2/features/user/domains/user_repository.rs @@ -1,6 +1,6 @@ use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; use crate::app::user::model::User; -use crate::appv2::features::profile::entities::profile::Profile; +use crate::appv2::features::profile::entities::Profile; use crate::error::AppError; use crate::utils::db::DbPool; From 31760807b44a81896cf7581b0cec4236be125ee9 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 22:29:47 +0900 Subject: [PATCH 14/59] refactor: organize user/profile dir --- src/app/comment/service.rs | 4 +--- src/appv2/drivers/middlewares/state.rs | 6 +----- src/appv2/features/profile/usecases.rs | 2 +- src/appv2/features/user/domains/mod.rs | 1 - src/appv2/features/user/mod.rs | 2 +- .../user/{domains/user_repository.rs => repositories.rs} | 0 src/utils/di.rs | 8 ++++---- 7 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 src/appv2/features/user/domains/mod.rs rename src/appv2/features/user/{domains/user_repository.rs => repositories.rs} (100%) diff --git a/src/app/comment/service.rs b/src/app/comment/service.rs index 6763194..19f18a5 100644 --- a/src/app/comment/service.rs +++ b/src/app/comment/service.rs @@ -2,9 +2,7 @@ use super::model::{Comment, CreateComment, DeleteComment}; use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; use crate::app::user::model::User; use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::profile::usecases::services::{ - conver_user_to_profile, ConverUserToProfile, -}; +use crate::appv2::features::profile::services::{conver_user_to_profile, ConverUserToProfile}; use crate::error::AppError; use diesel::pg::PgConnection; use uuid::Uuid; diff --git a/src/appv2/drivers/middlewares/state.rs b/src/appv2/drivers/middlewares/state.rs index cd6ede1..65ea3ec 100644 --- a/src/appv2/drivers/middlewares/state.rs +++ b/src/appv2/drivers/middlewares/state.rs @@ -1,12 +1,8 @@ -// use crate::appv2::features::profile::domains::profile_repository::{ -// IProfileRepository, ProfileRepository, -// }; use crate::error::AppError; use crate::utils::db::DbPool; +use crate::utils::di::DiContainer; use diesel::pg::PgConnection; use diesel::r2d2::{ConnectionManager, PooledConnection}; -// use std::sync::Arc; -use crate::utils::di::DiContainer; type AppConn = PooledConnection>; diff --git a/src/appv2/features/profile/usecases.rs b/src/appv2/features/profile/usecases.rs index a243b57..5440c5d 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/appv2/features/profile/usecases.rs @@ -1,7 +1,7 @@ use super::presenters::ProfilePresenter; use super::repositories::ProfileRepository; use crate::app::user::model::User; -use crate::appv2::features::user::domains::user_repository::UserRepository; +use crate::appv2::features::user::repositories::UserRepository; use crate::error::AppError; use actix_web::HttpResponse; diff --git a/src/appv2/features/user/domains/mod.rs b/src/appv2/features/user/domains/mod.rs deleted file mode 100644 index a5188ff..0000000 --- a/src/appv2/features/user/domains/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod user_repository; diff --git a/src/appv2/features/user/mod.rs b/src/appv2/features/user/mod.rs index 979f2a2..21b552a 100644 --- a/src/appv2/features/user/mod.rs +++ b/src/appv2/features/user/mod.rs @@ -1 +1 @@ -pub mod domains; +pub mod repositories; diff --git a/src/appv2/features/user/domains/user_repository.rs b/src/appv2/features/user/repositories.rs similarity index 100% rename from src/appv2/features/user/domains/user_repository.rs rename to src/appv2/features/user/repositories.rs diff --git a/src/utils/di.rs b/src/utils/di.rs index 2df1afd..951a8e9 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,7 +1,7 @@ -use crate::appv2::features::profile::adapters::presenters::ProfilePresenter; -use crate::appv2::features::profile::domains::profile_repository::ProfileRepository; -use crate::appv2::features::profile::usecases::profile_usecase::ProfileUsecase; -use crate::appv2::features::user::domains::user_repository::UserRepository; +use crate::appv2::features::profile::{ + presenters::ProfilePresenter, repositories::ProfileRepository, usecases::ProfileUsecase, +}; +use crate::appv2::features::user::repositories::UserRepository; use crate::utils::db::DbPool; From b9e864888cdcf0eb1c7b25e57b07afa1e65a5048 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 22:37:09 +0900 Subject: [PATCH 15/59] refactor: move user to v2 --- src/app/article/model.rs | 2 +- src/app/article/service.rs | 2 +- src/app/comment/model.rs | 2 +- src/app/comment/service.rs | 2 +- src/app/favorite/model.rs | 2 +- src/app/favorite/service.rs | 2 +- src/app/follow/model.rs | 2 +- src/app/mod.rs | 1 - src/app/user/mod.rs | 4 ---- src/appv2/drivers/middlewares/auth.rs | 2 +- src/appv2/drivers/routes.rs | 11 +++++++---- src/appv2/features/profile/repositories.rs | 2 +- src/appv2/features/profile/services.rs | 2 +- src/appv2/features/profile/usecases.rs | 2 +- .../api.rs => appv2/features/user/controllers.rs} | 10 +++++----- .../user/model.rs => appv2/features/user/entities.rs} | 0 src/appv2/features/user/mod.rs | 4 ++++ .../response.rs => appv2/features/user/presenters.rs} | 2 +- src/appv2/features/user/repositories.rs | 2 +- .../request.rs => appv2/features/user/requests.rs} | 0 20 files changed, 29 insertions(+), 27 deletions(-) delete mode 100644 src/app/user/mod.rs rename src/{app/user/api.rs => appv2/features/user/controllers.rs} (89%) rename src/{app/user/model.rs => appv2/features/user/entities.rs} (100%) rename src/{app/user/response.rs => appv2/features/user/presenters.rs} (94%) rename src/{app/user/request.rs => appv2/features/user/requests.rs} (100%) diff --git a/src/app/article/model.rs b/src/app/article/model.rs index 65daa95..f8fab5f 100644 --- a/src/app/article/model.rs +++ b/src/app/article/model.rs @@ -1,5 +1,5 @@ use crate::app::favorite::model::Favorite; -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::articles; use crate::utils::converter; diff --git a/src/app/article/service.rs b/src/app/article/service.rs index 6b71f7d..67b4816 100644 --- a/src/app/article/service.rs +++ b/src/app/article/service.rs @@ -2,8 +2,8 @@ use crate::app::article::model::{Article, CreateArticle, UpdateArticle}; use crate::app::favorite::model::{Favorite, FavoriteInfo}; use crate::app::follow::model::Follow; use crate::app::tag::model::{CreateTag, Tag}; -use crate::app::user::model::User; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::articles::dsl::*; use crate::schema::{articles, tags, users}; diff --git a/src/app/comment/model.rs b/src/app/comment/model.rs index 949288c..0e009fd 100644 --- a/src/app/comment/model.rs +++ b/src/app/comment/model.rs @@ -1,5 +1,5 @@ use crate::app::article::model::Article; -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::comments; use chrono::NaiveDateTime; diff --git a/src/app/comment/service.rs b/src/app/comment/service.rs index 19f18a5..ecbc3e7 100644 --- a/src/app/comment/service.rs +++ b/src/app/comment/service.rs @@ -1,8 +1,8 @@ use super::model::{Comment, CreateComment, DeleteComment}; use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; -use crate::app::user::model::User; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::profile::services::{conver_user_to_profile, ConverUserToProfile}; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use diesel::pg::PgConnection; use uuid::Uuid; diff --git a/src/app/favorite/model.rs b/src/app/favorite/model.rs index 01009b1..0a91c7c 100644 --- a/src/app/favorite/model.rs +++ b/src/app/favorite/model.rs @@ -1,5 +1,5 @@ use crate::app::article::model::Article; -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::favorites; use chrono::NaiveDateTime; diff --git a/src/app/favorite/service.rs b/src/app/favorite/service.rs index 05d61aa..fb5751d 100644 --- a/src/app/favorite/service.rs +++ b/src/app/favorite/service.rs @@ -2,8 +2,8 @@ use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; use crate::app::article::service::{fetch_article, FetchArticle}; use crate::app::favorite::model::{CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo}; use crate::app::tag::model::Tag; -use crate::app::user::model::User; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use diesel::pg::PgConnection; diff --git a/src/app/follow/model.rs b/src/app/follow/model.rs index f31e992..59acb85 100644 --- a/src/app/follow/model.rs +++ b/src/app/follow/model.rs @@ -1,4 +1,4 @@ -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::follows; use chrono::NaiveDateTime; diff --git a/src/app/mod.rs b/src/app/mod.rs index 93c5395..724b78b 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -4,4 +4,3 @@ pub mod favorite; pub mod follow; pub mod healthcheck; pub mod tag; -pub mod user; diff --git a/src/app/user/mod.rs b/src/app/user/mod.rs deleted file mode 100644 index 27976bc..0000000 --- a/src/app/user/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod api; -pub mod model; -pub mod request; -pub mod response; diff --git a/src/appv2/drivers/middlewares/auth.rs b/src/appv2/drivers/middlewares/auth.rs index cee6e79..20878d2 100644 --- a/src/appv2/drivers/middlewares/auth.rs +++ b/src/appv2/drivers/middlewares/auth.rs @@ -1,5 +1,5 @@ -use crate::app::user::model::User; use crate::appv2::drivers::middlewares::state::AppState; +use crate::appv2::features::user::entities::User; use crate::constants; use crate::error::AppError; use crate::utils::token; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index 7180c56..c9de28a 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -10,13 +10,16 @@ pub fn api(cfg: &mut web::ServiceConfig) { .service(web::scope("/tags").route("", get().to(app::tag::api::index))) .service( web::scope("/users") - .route("/login", post().to(app::user::api::signin)) - .route("", post().to(app::user::api::signup)), + .route( + "/login", + post().to(appv2::features::user::controllers::signin), + ) + .route("", post().to(appv2::features::user::controllers::signup)), ) .service( web::scope("/user") - .route("", get().to(app::user::api::me)) - .route("", put().to(app::user::api::update)), + .route("", get().to(appv2::features::user::controllers::me)) + .route("", put().to(appv2::features::user::controllers::update)), ) .service( web::scope("/profiles") diff --git a/src/appv2/features/profile/repositories.rs b/src/appv2/features/profile/repositories.rs index 7330207..0f6706e 100644 --- a/src/appv2/features/profile/repositories.rs +++ b/src/appv2/features/profile/repositories.rs @@ -1,5 +1,5 @@ use super::entities::Profile; -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; diff --git a/src/appv2/features/profile/services.rs b/src/appv2/features/profile/services.rs index a3b9571..f773174 100644 --- a/src/appv2/features/profile/services.rs +++ b/src/appv2/features/profile/services.rs @@ -1,5 +1,5 @@ use super::entities::Profile; -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use diesel::pg::PgConnection; #[deprecated(note = "use repository")] diff --git a/src/appv2/features/profile/usecases.rs b/src/appv2/features/profile/usecases.rs index 5440c5d..2176953 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/appv2/features/profile/usecases.rs @@ -1,6 +1,6 @@ use super::presenters::ProfilePresenter; use super::repositories::ProfileRepository; -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use crate::appv2::features::user::repositories::UserRepository; use crate::error::AppError; use actix_web::HttpResponse; diff --git a/src/app/user/api.rs b/src/appv2/features/user/controllers.rs similarity index 89% rename from src/app/user/api.rs rename to src/appv2/features/user/controllers.rs index e323fc3..1c6d1db 100644 --- a/src/app/user/api.rs +++ b/src/appv2/features/user/controllers.rs @@ -1,18 +1,18 @@ -use super::model::{UpdateUser, User}; -use super::{request, response::UserResponse}; +use super::entities::{UpdateUser, User}; +use super::{presenters::UserResponse, requests}; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; -pub async fn signin(state: web::Data, form: web::Json) -> ApiResponse { +pub async fn signin(state: web::Data, form: web::Json) -> ApiResponse { let conn = &mut state.get_conn()?; let (user, token) = User::signin(conn, &form.user.email, &form.user.password)?; let res = UserResponse::from((user, token)); Ok(HttpResponse::Ok().json(res)) } -pub async fn signup(state: web::Data, form: web::Json) -> ApiResponse { +pub async fn signup(state: web::Data, form: web::Json) -> ApiResponse { let conn = &mut state.get_conn()?; let (user, token) = User::signup( conn, @@ -34,7 +34,7 @@ pub async fn me(req: HttpRequest) -> ApiResponse { pub async fn update( state: web::Data, req: HttpRequest, - form: web::Json, + form: web::Json, ) -> ApiResponse { let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; diff --git a/src/app/user/model.rs b/src/appv2/features/user/entities.rs similarity index 100% rename from src/app/user/model.rs rename to src/appv2/features/user/entities.rs diff --git a/src/appv2/features/user/mod.rs b/src/appv2/features/user/mod.rs index 21b552a..4512ebf 100644 --- a/src/appv2/features/user/mod.rs +++ b/src/appv2/features/user/mod.rs @@ -1 +1,5 @@ +pub mod controllers; +pub mod entities; +pub mod presenters; pub mod repositories; +pub mod requests; diff --git a/src/app/user/response.rs b/src/appv2/features/user/presenters.rs similarity index 94% rename from src/app/user/response.rs rename to src/appv2/features/user/presenters.rs index afeac3d..025486a 100644 --- a/src/app/user/response.rs +++ b/src/appv2/features/user/presenters.rs @@ -1,4 +1,4 @@ -use crate::app::user::model::User; +use crate::appv2::features::user::entities::User; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index b931bc6..ff5f13d 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -1,6 +1,6 @@ use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; -use crate::app::user::model::User; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; diff --git a/src/app/user/request.rs b/src/appv2/features/user/requests.rs similarity index 100% rename from src/app/user/request.rs rename to src/appv2/features/user/requests.rs From 432b299b958af1a5429050e224b6fdd3996cf2d5 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 23:04:09 +0900 Subject: [PATCH 16/59] refactor: follow clean-arch for signin on user --- src/appv2/features/user/controllers.rs | 9 ++++---- src/appv2/features/user/mod.rs | 1 + src/appv2/features/user/presenters.rs | 13 ++++++++++++ src/appv2/features/user/repositories.rs | 7 +++++++ src/appv2/features/user/usecases.rs | 25 ++++++++++++++++++++++ src/utils/di.rs | 28 ++++++++++++++++++------- 6 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 src/appv2/features/user/usecases.rs diff --git a/src/appv2/features/user/controllers.rs b/src/appv2/features/user/controllers.rs index 1c6d1db..d675b3f 100644 --- a/src/appv2/features/user/controllers.rs +++ b/src/appv2/features/user/controllers.rs @@ -6,10 +6,11 @@ use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; pub async fn signin(state: web::Data, form: web::Json) -> ApiResponse { - let conn = &mut state.get_conn()?; - let (user, token) = User::signin(conn, &form.user.email, &form.user.password)?; - let res = UserResponse::from((user, token)); - Ok(HttpResponse::Ok().json(res)) + let res = state + .di_container + .user_usecase + .signin(&form.user.email, &form.user.password)?; + Ok(res) } pub async fn signup(state: web::Data, form: web::Json) -> ApiResponse { diff --git a/src/appv2/features/user/mod.rs b/src/appv2/features/user/mod.rs index 4512ebf..7f85232 100644 --- a/src/appv2/features/user/mod.rs +++ b/src/appv2/features/user/mod.rs @@ -3,3 +3,4 @@ pub mod entities; pub mod presenters; pub mod repositories; pub mod requests; +pub mod usecases; diff --git a/src/appv2/features/user/presenters.rs b/src/appv2/features/user/presenters.rs index 025486a..a527665 100644 --- a/src/appv2/features/user/presenters.rs +++ b/src/appv2/features/user/presenters.rs @@ -1,4 +1,5 @@ use crate::appv2::features::user::entities::User; +use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; use std::convert::From; @@ -30,3 +31,15 @@ pub struct AuthUser { pub bio: Option, pub image: Option, } + +#[derive(Clone)] +pub struct UserPresenter {} +impl UserPresenter { + pub fn new() -> Self { + Self {} + } + pub fn signin(&self, user: User, token: String) -> HttpResponse { + let res_model = UserResponse::from((user, token)); + HttpResponse::Ok().json(res_model) + } +} diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index ff5f13d..c6e9dfd 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -4,6 +4,8 @@ use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; +type Token = String; + #[derive(Clone)] pub struct UserRepository { pool: DbPool, @@ -14,6 +16,11 @@ impl UserRepository { Self { pool } } + pub fn signin(&self, email: &str, naive_password: &str) -> Result<(User, Token), AppError> { + let conn = &mut self.pool.get()?; + User::signin(conn, email, naive_password) + } + pub fn follow(&self, current_user: &User, target_username: &str) -> Result { let conn = &mut self.pool.get()?; let t = User::by_username(target_username); diff --git a/src/appv2/features/user/usecases.rs b/src/appv2/features/user/usecases.rs new file mode 100644 index 0000000..e1b66f1 --- /dev/null +++ b/src/appv2/features/user/usecases.rs @@ -0,0 +1,25 @@ +use super::presenters::UserPresenter; +use super::repositories::UserRepository; +use crate::error::AppError; +use actix_web::HttpResponse; + +#[derive(Clone)] +pub struct UserUsecase { + user_repository: UserRepository, + user_presenter: UserPresenter, +} + +impl UserUsecase { + pub fn new(user_repository: UserRepository, user_presenter: UserPresenter) -> Self { + Self { + user_repository, + user_presenter, + } + } + + pub fn signin(&self, email: &str, password: &str) -> Result { + let (user, token) = self.user_repository.signin(email, password)?; + let res = self.user_presenter.signin(user, token); + Ok(res) + } +} diff --git a/src/utils/di.rs b/src/utils/di.rs index 951a8e9..1379ac3 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,39 +1,51 @@ use crate::appv2::features::profile::{ presenters::ProfilePresenter, repositories::ProfileRepository, usecases::ProfileUsecase, }; -use crate::appv2::features::user::repositories::UserRepository; +use crate::appv2::features::user::{ + presenters::UserPresenter, repositories::UserRepository, usecases::UserUsecase, +}; use crate::utils::db::DbPool; #[derive(Clone)] pub struct DiContainer { + /** + * User + */ + pub user_repository: UserRepository, + pub user_usecase: UserUsecase, + pub user_presenter: UserPresenter, + /** * Profile */ pub profile_repository: ProfileRepository, pub profile_presenter: ProfilePresenter, pub profile_usecase: ProfileUsecase, - - /** - * User - */ - pub user_repository: UserRepository, } impl DiContainer { pub fn new(pool: &DbPool) -> Self { - let profile_repository = ProfileRepository::new(pool.clone()); + // User let user_repository = UserRepository::new(pool.clone()); + let user_presenter = UserPresenter::new(); + let user_usecase = UserUsecase::new(user_repository.clone(), user_presenter.clone()); + + // Profile + let profile_repository = ProfileRepository::new(pool.clone()); let profile_presenter = ProfilePresenter::new(); let profile_usecase = ProfileUsecase::new( (profile_repository.clone(), user_repository.clone()), profile_presenter.clone(), ); + Self { + user_repository, + user_usecase, + user_presenter, profile_presenter, profile_repository, profile_usecase, - user_repository, } } } From 81151246c3b5d82d6432d3297c43ecbada3c284a Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 23:13:03 +0900 Subject: [PATCH 17/59] refactor: follow clean-arch for signup on user --- src/appv2/features/profile/presenters.rs | 2 +- src/appv2/features/profile/usecases.rs | 6 +++--- src/appv2/features/user/controllers.rs | 7 ++----- src/appv2/features/user/presenters.rs | 2 +- src/appv2/features/user/repositories.rs | 10 ++++++++++ src/appv2/features/user/usecases.rs | 13 ++++++++++++- 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/appv2/features/profile/presenters.rs b/src/appv2/features/profile/presenters.rs index 622ff96..c089b93 100644 --- a/src/appv2/features/profile/presenters.rs +++ b/src/appv2/features/profile/presenters.rs @@ -34,7 +34,7 @@ impl ProfilePresenter { pub fn new() -> Self { Self {} } - pub fn complete(&self, model: ProfileModel) -> HttpResponse { + pub fn from_profile(&self, model: ProfileModel) -> HttpResponse { let res_model = ProfileResponse::from(model); HttpResponse::Ok().json(res_model) } diff --git a/src/appv2/features/profile/usecases.rs b/src/appv2/features/profile/usecases.rs index 2176953..029ea44 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/appv2/features/profile/usecases.rs @@ -28,7 +28,7 @@ impl ProfileUsecase { let profile = self .profile_repository .fetch_by_name(current_user, username)?; - Ok(self.presenter.complete(profile)) + Ok(self.presenter.from_profile(profile)) } pub fn follow( @@ -37,7 +37,7 @@ impl ProfileUsecase { target_username: &str, ) -> Result { let profile = self.user_repository.follow(current_user, target_username)?; - Ok(self.presenter.complete(profile)) + Ok(self.presenter.from_profile(profile)) } pub fn unfollow( @@ -48,6 +48,6 @@ impl ProfileUsecase { let profile = self .user_repository .unfollow(current_user, target_username)?; - Ok(self.presenter.complete(profile)) + Ok(self.presenter.from_profile(profile)) } } diff --git a/src/appv2/features/user/controllers.rs b/src/appv2/features/user/controllers.rs index d675b3f..121ff22 100644 --- a/src/appv2/features/user/controllers.rs +++ b/src/appv2/features/user/controllers.rs @@ -14,15 +14,12 @@ pub async fn signin(state: web::Data, form: web::Json, form: web::Json) -> ApiResponse { - let conn = &mut state.get_conn()?; - let (user, token) = User::signup( - conn, + let res = state.di_container.user_usecase.signup( &form.user.email, &form.user.username, &form.user.password, )?; - let res = UserResponse::from((user, token)); - Ok(HttpResponse::Ok().json(res)) + Ok(res) } pub async fn me(req: HttpRequest) -> ApiResponse { diff --git a/src/appv2/features/user/presenters.rs b/src/appv2/features/user/presenters.rs index a527665..a362b6e 100644 --- a/src/appv2/features/user/presenters.rs +++ b/src/appv2/features/user/presenters.rs @@ -38,7 +38,7 @@ impl UserPresenter { pub fn new() -> Self { Self {} } - pub fn signin(&self, user: User, token: String) -> HttpResponse { + pub fn from_user_and_token(&self, user: User, token: String) -> HttpResponse { let res_model = UserResponse::from((user, token)); HttpResponse::Ok().json(res_model) } diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index c6e9dfd..c427aa9 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -21,6 +21,16 @@ impl UserRepository { User::signin(conn, email, naive_password) } + pub fn signup( + &self, + email: &str, + username: &str, + naive_password: &str, + ) -> Result<(User, Token), AppError> { + let conn = &mut self.pool.get()?; + User::signup(conn, email, username, naive_password) + } + pub fn follow(&self, current_user: &User, target_username: &str) -> Result { let conn = &mut self.pool.get()?; let t = User::by_username(target_username); diff --git a/src/appv2/features/user/usecases.rs b/src/appv2/features/user/usecases.rs index e1b66f1..09e45b5 100644 --- a/src/appv2/features/user/usecases.rs +++ b/src/appv2/features/user/usecases.rs @@ -19,7 +19,18 @@ impl UserUsecase { pub fn signin(&self, email: &str, password: &str) -> Result { let (user, token) = self.user_repository.signin(email, password)?; - let res = self.user_presenter.signin(user, token); + let res = self.user_presenter.from_user_and_token(user, token); + Ok(res) + } + + pub fn signup( + &self, + email: &str, + username: &str, + password: &str, + ) -> Result { + let (user, token) = self.user_repository.signup(email, username, password)?; + let res = self.user_presenter.from_user_and_token(user, token); Ok(res) } } From eb005ee1df7ca2da585c4659dc5540ed7052f793 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 23:24:46 +0900 Subject: [PATCH 18/59] refactor: follow clean-arch for me on user --- src/appv2/features/user/controllers.rs | 9 ++++----- src/appv2/features/user/repositories.rs | 5 +++++ src/appv2/features/user/usecases.rs | 7 +++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/appv2/features/user/controllers.rs b/src/appv2/features/user/controllers.rs index 121ff22..1fd1c5b 100644 --- a/src/appv2/features/user/controllers.rs +++ b/src/appv2/features/user/controllers.rs @@ -22,11 +22,10 @@ pub async fn signup(state: web::Data, form: web::Json ApiResponse { - let user = auth::get_current_user(&req)?; - let token = user.generate_token()?; - let res = UserResponse::from((user, token)); - Ok(HttpResponse::Ok().json(res)) +pub async fn me(state: web::Data, req: HttpRequest) -> ApiResponse { + let current_user = auth::get_current_user(&req)?; + let res = state.di_container.user_usecase.me(¤t_user)?; + Ok(res) } pub async fn update( diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index c427aa9..579dcca 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -16,6 +16,11 @@ impl UserRepository { Self { pool } } + pub fn me<'a>(&self, current_user: &'a User) -> Result<(&'a User, Token), AppError> { + let token = current_user.generate_token()?; + Ok((current_user, token)) + } + pub fn signin(&self, email: &str, naive_password: &str) -> Result<(User, Token), AppError> { let conn = &mut self.pool.get()?; User::signin(conn, email, naive_password) diff --git a/src/appv2/features/user/usecases.rs b/src/appv2/features/user/usecases.rs index 09e45b5..2a78287 100644 --- a/src/appv2/features/user/usecases.rs +++ b/src/appv2/features/user/usecases.rs @@ -1,3 +1,4 @@ +use super::entities::User; use super::presenters::UserPresenter; use super::repositories::UserRepository; use crate::error::AppError; @@ -33,4 +34,10 @@ impl UserUsecase { let res = self.user_presenter.from_user_and_token(user, token); Ok(res) } + + pub fn me(&self, current_user: &User) -> Result { + let (user, token) = self.user_repository.me(current_user)?; + let res = self.user_presenter.from_user_and_token(user.clone(), token); + Ok(res) + } } From 6f728301f8c81e9370fdf5ce91df7c7a3097400b Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 23:40:46 +0900 Subject: [PATCH 19/59] refactor: follow clean-arch for user-update on user --- src/appv2/features/user/controllers.rs | 14 +++++--------- src/appv2/features/user/repositories.rs | 11 +++++++++++ src/appv2/features/user/usecases.rs | 9 ++++++++- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/appv2/features/user/controllers.rs b/src/appv2/features/user/controllers.rs index 1fd1c5b..01b3a3b 100644 --- a/src/appv2/features/user/controllers.rs +++ b/src/appv2/features/user/controllers.rs @@ -1,9 +1,9 @@ -use super::entities::{UpdateUser, User}; -use super::{presenters::UserResponse, requests}; +use super::entities::UpdateUser; +use super::requests; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; pub async fn signin(state: web::Data, form: web::Json) -> ApiResponse { let res = state @@ -33,10 +33,8 @@ pub async fn update( req: HttpRequest, form: web::Json, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; - let user = User::update( - conn, + let res = state.di_container.user_usecase.update( current_user.id, UpdateUser { email: form.user.email.clone(), @@ -46,7 +44,5 @@ pub async fn update( bio: form.user.bio.clone(), }, )?; - let token = &user.generate_token()?; - let res = UserResponse::from((user, token.to_string())); - Ok(HttpResponse::Ok().json(res)) + Ok(res) } diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index 579dcca..6eee318 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -1,9 +1,13 @@ +use uuid::Uuid; + use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; +use super::entities::UpdateUser; + type Token = String; #[derive(Clone)] @@ -88,4 +92,11 @@ impl UserRepository { following: false, }) } + + pub fn update(&self, user_id: Uuid, changeset: UpdateUser) -> Result<(User, Token), AppError> { + let conn = &mut self.pool.get()?; + let new_user = User::update(conn, user_id, changeset)?; + let token = &new_user.generate_token()?; + Ok((new_user, token.clone())) + } } diff --git a/src/appv2/features/user/usecases.rs b/src/appv2/features/user/usecases.rs index 2a78287..b2fd5be 100644 --- a/src/appv2/features/user/usecases.rs +++ b/src/appv2/features/user/usecases.rs @@ -1,8 +1,9 @@ -use super::entities::User; +use super::entities::{UpdateUser, User}; use super::presenters::UserPresenter; use super::repositories::UserRepository; use crate::error::AppError; use actix_web::HttpResponse; +use uuid::Uuid; #[derive(Clone)] pub struct UserUsecase { @@ -40,4 +41,10 @@ impl UserUsecase { let res = self.user_presenter.from_user_and_token(user.clone(), token); Ok(res) } + + pub fn update(&self, user_id: Uuid, changeset: UpdateUser) -> Result { + let (new_user, token) = self.user_repository.update(user_id, changeset)?; + let res = self.user_presenter.from_user_and_token(new_user, token); + Ok(res) + } } From 3100613cfb6947caeb02f0ff55625886128e380f Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Sun, 11 Jun 2023 23:50:43 +0900 Subject: [PATCH 20/59] refactor: move favorite to v2 --- src/app/article/model.rs | 2 +- src/app/article/response.rs | 2 +- src/app/article/service.rs | 2 +- src/app/favorite/mod.rs | 4 ---- src/app/mod.rs | 1 - src/appv2/drivers/routes.rs | 11 +++++++++-- .../api.rs => appv2/features/favorite/controllers.rs} | 10 +++++----- .../model.rs => appv2/features/favorite/entities.rs} | 0 src/appv2/features/favorite/mod.rs | 4 ++++ .../features/favorite/presenters.rs} | 0 .../features/favorite/services.rs} | 4 +++- src/appv2/features/mod.rs | 1 + src/appv2/features/user/entities.rs | 2 +- 13 files changed, 26 insertions(+), 17 deletions(-) delete mode 100644 src/app/favorite/mod.rs rename src/{app/favorite/api.rs => appv2/features/favorite/controllers.rs} (82%) rename src/{app/favorite/model.rs => appv2/features/favorite/entities.rs} (100%) create mode 100644 src/appv2/features/favorite/mod.rs rename src/{app/favorite/response.rs => appv2/features/favorite/presenters.rs} (100%) rename src/{app/favorite/service.rs => appv2/features/favorite/services.rs} (94%) diff --git a/src/app/article/model.rs b/src/app/article/model.rs index f8fab5f..2816d52 100644 --- a/src/app/article/model.rs +++ b/src/app/article/model.rs @@ -1,4 +1,4 @@ -use crate::app::favorite::model::Favorite; +use crate::appv2::features::favorite::entities::Favorite; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::articles; diff --git a/src/app/article/response.rs b/src/app/article/response.rs index dde8f06..7a8142f 100644 --- a/src/app/article/response.rs +++ b/src/app/article/response.rs @@ -1,6 +1,6 @@ use crate::app::article::model::Article; -use crate::app::favorite::model::FavoriteInfo; use crate::app::tag::model::Tag; +use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; use crate::utils::date::Iso8601; use serde::{Deserialize, Serialize}; diff --git a/src/app/article/service.rs b/src/app/article/service.rs index 67b4816..2d61110 100644 --- a/src/app/article/service.rs +++ b/src/app/article/service.rs @@ -1,7 +1,7 @@ use crate::app::article::model::{Article, CreateArticle, UpdateArticle}; -use crate::app::favorite::model::{Favorite, FavoriteInfo}; use crate::app::follow::model::Follow; use crate::app::tag::model::{CreateTag, Tag}; +use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::user::entities::User; use crate::error::AppError; diff --git a/src/app/favorite/mod.rs b/src/app/favorite/mod.rs deleted file mode 100644 index a451d09..0000000 --- a/src/app/favorite/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod api; -pub mod model; -pub mod response; -pub mod service; diff --git a/src/app/mod.rs b/src/app/mod.rs index 724b78b..84a51d3 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,6 +1,5 @@ pub mod article; pub mod comment; -pub mod favorite; pub mod follow; pub mod healthcheck; pub mod tag; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index c9de28a..3db8d8b 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -48,8 +48,15 @@ pub fn api(cfg: &mut web::ServiceConfig) { .route("", delete().to(app::article::api::delete)) .service( web::scope("/favorite") - .route("", post().to(app::favorite::api::favorite)) - .route("", delete().to(app::favorite::api::unfavorite)), + .route( + "", + post().to(appv2::features::favorite::controllers::favorite), + ) + .route( + "", + delete() + .to(appv2::features::favorite::controllers::unfavorite), + ), ) .service( web::scope("/comments") diff --git a/src/app/favorite/api.rs b/src/appv2/features/favorite/controllers.rs similarity index 82% rename from src/app/favorite/api.rs rename to src/appv2/features/favorite/controllers.rs index a21a372..bfccc1f 100644 --- a/src/app/favorite/api.rs +++ b/src/appv2/features/favorite/controllers.rs @@ -1,6 +1,6 @@ use super::{ - response::SingleArticleResponse, - service::{self, UnfavoriteService}, + presenters::SingleArticleResponse, + services::{self, UnfavoriteService}, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; @@ -17,9 +17,9 @@ pub async fn favorite( let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - let (article, profile, favorite_info, tags_list) = service::favorite( + let (article, profile, favorite_info, tags_list) = services::favorite( conn, - &service::FavoriteService { + &services::FavoriteService { current_user, article_title_slug, }, @@ -36,7 +36,7 @@ pub async fn unfavorite( let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - let (article, profile, favorite_info, tags_list) = service::unfavorite( + let (article, profile, favorite_info, tags_list) = services::unfavorite( conn, &UnfavoriteService { current_user, diff --git a/src/app/favorite/model.rs b/src/appv2/features/favorite/entities.rs similarity index 100% rename from src/app/favorite/model.rs rename to src/appv2/features/favorite/entities.rs diff --git a/src/appv2/features/favorite/mod.rs b/src/appv2/features/favorite/mod.rs new file mode 100644 index 0000000..c0a936b --- /dev/null +++ b/src/appv2/features/favorite/mod.rs @@ -0,0 +1,4 @@ +pub mod controllers; +pub mod entities; +pub mod presenters; +pub mod services; diff --git a/src/app/favorite/response.rs b/src/appv2/features/favorite/presenters.rs similarity index 100% rename from src/app/favorite/response.rs rename to src/appv2/features/favorite/presenters.rs diff --git a/src/app/favorite/service.rs b/src/appv2/features/favorite/services.rs similarity index 94% rename from src/app/favorite/service.rs rename to src/appv2/features/favorite/services.rs index fb5751d..ae55e7f 100644 --- a/src/app/favorite/service.rs +++ b/src/appv2/features/favorite/services.rs @@ -1,7 +1,9 @@ use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; use crate::app::article::service::{fetch_article, FetchArticle}; -use crate::app::favorite::model::{CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo}; use crate::app::tag::model::Tag; +use crate::appv2::features::favorite::entities::{ + CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo, +}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::user::entities::User; use crate::error::AppError; diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index 322b928..0083df8 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -1,2 +1,3 @@ +pub mod favorite; pub mod profile; pub mod user; diff --git a/src/appv2/features/user/entities.rs b/src/appv2/features/user/entities.rs index b3b4a81..045c968 100644 --- a/src/appv2/features/user/entities.rs +++ b/src/appv2/features/user/entities.rs @@ -1,5 +1,5 @@ -use crate::app::favorite::model::Favorite; use crate::app::follow::model::Follow; +use crate::appv2::features::favorite::entities::Favorite; use crate::appv2::features::profile::entities::Profile; use crate::error::AppError; use crate::schema::users; From 5d74c2afa0fa96bc478699ebf4038542d2c3d575 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:15:12 +0900 Subject: [PATCH 21/59] refactor: follow clean-arch for favorite --- src/appv2/features/favorite/controllers.rs | 14 +++----- src/appv2/features/favorite/mod.rs | 2 ++ src/appv2/features/favorite/presenters.rs | 24 +++++++++++++ src/appv2/features/favorite/repositories.rs | 35 +++++++++++++++++++ src/appv2/features/favorite/usecases.rs | 37 +++++++++++++++++++++ src/utils/di.rs | 24 +++++++++++++ 6 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 src/appv2/features/favorite/repositories.rs create mode 100644 src/appv2/features/favorite/usecases.rs diff --git a/src/appv2/features/favorite/controllers.rs b/src/appv2/features/favorite/controllers.rs index bfccc1f..b55b854 100644 --- a/src/appv2/features/favorite/controllers.rs +++ b/src/appv2/features/favorite/controllers.rs @@ -14,18 +14,12 @@ pub async fn favorite( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - let (article, profile, favorite_info, tags_list) = services::favorite( - conn, - &services::FavoriteService { - current_user, - article_title_slug, - }, - )?; - let res = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); - Ok(HttpResponse::Ok().json(res)) + state + .di_container + .favorite_usecase + .favorite(current_user, article_title_slug) } pub async fn unfavorite( diff --git a/src/appv2/features/favorite/mod.rs b/src/appv2/features/favorite/mod.rs index c0a936b..923a07e 100644 --- a/src/appv2/features/favorite/mod.rs +++ b/src/appv2/features/favorite/mod.rs @@ -1,4 +1,6 @@ pub mod controllers; pub mod entities; pub mod presenters; +pub mod repositories; pub mod services; +pub mod usecases; diff --git a/src/appv2/features/favorite/presenters.rs b/src/appv2/features/favorite/presenters.rs index ca699d6..e01480d 100644 --- a/src/appv2/features/favorite/presenters.rs +++ b/src/appv2/features/favorite/presenters.rs @@ -1 +1,25 @@ +use actix_web::HttpResponse; + pub use crate::app::article::response::SingleArticleResponse; +use crate::{ + app::{article::model::Article, tag::model::Tag}, + appv2::features::profile::entities::Profile, +}; + +use super::entities::FavoriteInfo; + +#[derive(Clone)] +pub struct FavoritePresenter {} +impl FavoritePresenter { + pub fn new() -> Self { + Self {} + } + + pub fn complete( + &self, + (article, profile, favorite_info, tags_list): (Article, Profile, FavoriteInfo, Vec), + ) -> HttpResponse { + let res_model = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); + HttpResponse::Ok().json(res_model) + } +} diff --git a/src/appv2/features/favorite/repositories.rs b/src/appv2/features/favorite/repositories.rs new file mode 100644 index 0000000..3533973 --- /dev/null +++ b/src/appv2/features/favorite/repositories.rs @@ -0,0 +1,35 @@ +use super::entities::FavoriteInfo; +use super::services; +use crate::app::article::model::Article; +use crate::app::tag::model::Tag; +use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::user::entities::User; +use crate::error::AppError; +use crate::utils::db::DbPool; + +#[derive(Clone)] +pub struct FavoriteRepository { + pool: DbPool, +} + +impl FavoriteRepository { + pub fn new(pool: DbPool) -> Self { + Self { pool } + } + + pub fn favorite( + &self, + user: User, + article_title_slug: String, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + let conn = &mut self.pool.get()?; + let (article, profile, favorite_info, tags_list) = services::favorite( + conn, + &services::FavoriteService { + current_user: user, + article_title_slug, + }, + )?; + Ok((article, profile, favorite_info, tags_list)) + } +} diff --git a/src/appv2/features/favorite/usecases.rs b/src/appv2/features/favorite/usecases.rs new file mode 100644 index 0000000..f50f1be --- /dev/null +++ b/src/appv2/features/favorite/usecases.rs @@ -0,0 +1,37 @@ +// use super::entities::{UpdateUser, User}; +use super::presenters::FavoritePresenter; +use super::repositories::FavoriteRepository; +use crate::appv2::features::user::entities::User; +use crate::error::AppError; +use actix_web::HttpResponse; +use uuid::Uuid; + +#[derive(Clone)] +pub struct FavoriteUsecase { + favorite_repository: FavoriteRepository, + favorite_presenter: FavoritePresenter, +} + +impl FavoriteUsecase { + pub fn new( + favorite_repository: FavoriteRepository, + favorite_presenter: FavoritePresenter, + ) -> Self { + Self { + favorite_repository, + favorite_presenter, + } + } + + pub fn favorite( + &self, + user: User, + article_title_slug: String, + ) -> Result { + let result = self + .favorite_repository + .favorite(user, article_title_slug)?; + let res = self.favorite_presenter.complete(result); + Ok(res) + } +} diff --git a/src/utils/di.rs b/src/utils/di.rs index 1379ac3..f8a46af 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,3 +1,6 @@ +use crate::appv2::features::favorite::{ + presenters::FavoritePresenter, repositories::FavoriteRepository, usecases::FavoriteUsecase, +}; use crate::appv2::features::profile::{ presenters::ProfilePresenter, repositories::ProfileRepository, usecases::ProfileUsecase, }; @@ -22,6 +25,13 @@ pub struct DiContainer { pub profile_repository: ProfileRepository, pub profile_presenter: ProfilePresenter, pub profile_usecase: ProfileUsecase, + + /** + * Favorite + */ + pub favorite_repository: FavoriteRepository, + pub favorite_presenter: FavoritePresenter, + pub favorite_usecase: FavoriteUsecase, } impl DiContainer { @@ -39,13 +49,27 @@ impl DiContainer { profile_presenter.clone(), ); + // Favorite + let favorite_repository = FavoriteRepository::new(pool.clone()); + let favorite_presenter = FavoritePresenter::new(); + let favorite_usecase = + FavoriteUsecase::new(favorite_repository.clone(), favorite_presenter.clone()); + Self { + // User user_repository, user_usecase, user_presenter, + + // Profile profile_presenter, profile_repository, profile_usecase, + + // Favorite + favorite_repository, + favorite_presenter, + favorite_usecase, } } } From 0e7edfcb366f57f27035a3bbf819e62557b105ee Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:17:23 +0900 Subject: [PATCH 22/59] refactor: update controllers res way --- src/appv2/features/profile/controllers.rs | 15 ++++++--------- src/appv2/features/user/controllers.rs | 18 +++++++----------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/appv2/features/profile/controllers.rs b/src/appv2/features/profile/controllers.rs index ccdb2f0..919cc1d 100644 --- a/src/appv2/features/profile/controllers.rs +++ b/src/appv2/features/profile/controllers.rs @@ -11,11 +11,10 @@ pub async fn show( ) -> ApiResponse { let current_user = auth::get_current_user(&req)?; let username = path.into_inner(); - let res = state + state .di_container .profile_usecase - .show(¤t_user, &username)?; - Ok(res) + .show(¤t_user, &username) } pub async fn follow( @@ -25,11 +24,10 @@ pub async fn follow( ) -> ApiResponse { let current_user = auth::get_current_user(&req)?; let target_username = path.into_inner(); - let res = state + state .di_container .profile_usecase - .follow(¤t_user, &target_username)?; - Ok(res) + .follow(¤t_user, &target_username) } pub async fn unfollow( @@ -39,9 +37,8 @@ pub async fn unfollow( ) -> ApiResponse { let current_user = auth::get_current_user(&req)?; let target_username = path.into_inner(); - let res = state + state .di_container .profile_usecase - .unfollow(¤t_user, &target_username)?; - Ok(res) + .unfollow(¤t_user, &target_username) } diff --git a/src/appv2/features/user/controllers.rs b/src/appv2/features/user/controllers.rs index 01b3a3b..c66ffe9 100644 --- a/src/appv2/features/user/controllers.rs +++ b/src/appv2/features/user/controllers.rs @@ -6,26 +6,23 @@ use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest}; pub async fn signin(state: web::Data, form: web::Json) -> ApiResponse { - let res = state + state .di_container .user_usecase - .signin(&form.user.email, &form.user.password)?; - Ok(res) + .signin(&form.user.email, &form.user.password) } pub async fn signup(state: web::Data, form: web::Json) -> ApiResponse { - let res = state.di_container.user_usecase.signup( + state.di_container.user_usecase.signup( &form.user.email, &form.user.username, &form.user.password, - )?; - Ok(res) + ) } pub async fn me(state: web::Data, req: HttpRequest) -> ApiResponse { let current_user = auth::get_current_user(&req)?; - let res = state.di_container.user_usecase.me(¤t_user)?; - Ok(res) + state.di_container.user_usecase.me(¤t_user) } pub async fn update( @@ -34,7 +31,7 @@ pub async fn update( form: web::Json, ) -> ApiResponse { let current_user = auth::get_current_user(&req)?; - let res = state.di_container.user_usecase.update( + state.di_container.user_usecase.update( current_user.id, UpdateUser { email: form.user.email.clone(), @@ -43,6 +40,5 @@ pub async fn update( image: form.user.image.clone(), bio: form.user.bio.clone(), }, - )?; - Ok(res) + ) } From 496d0c548cf89fa5373b8197b1a0649ddff68cce Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:22:59 +0900 Subject: [PATCH 23/59] refactor: update unfavorite --- src/appv2/features/favorite/controllers.rs | 20 +++++--------------- src/appv2/features/favorite/repositories.rs | 16 ++++++++++++++++ src/appv2/features/favorite/services.rs | 3 ++- src/appv2/features/favorite/usecases.rs | 12 ++++++++++++ 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/appv2/features/favorite/controllers.rs b/src/appv2/features/favorite/controllers.rs index b55b854..8665fff 100644 --- a/src/appv2/features/favorite/controllers.rs +++ b/src/appv2/features/favorite/controllers.rs @@ -1,11 +1,7 @@ -use super::{ - presenters::SingleArticleResponse, - services::{self, UnfavoriteService}, -}; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; type ArticleIdSlug = String; @@ -27,16 +23,10 @@ pub async fn unfavorite( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - let (article, profile, favorite_info, tags_list) = services::unfavorite( - conn, - &UnfavoriteService { - current_user, - article_title_slug, - }, - )?; - let res = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); - Ok(HttpResponse::Ok().json(res)) + state + .di_container + .favorite_usecase + .unfavorite(current_user, article_title_slug) } diff --git a/src/appv2/features/favorite/repositories.rs b/src/appv2/features/favorite/repositories.rs index 3533973..24c1047 100644 --- a/src/appv2/features/favorite/repositories.rs +++ b/src/appv2/features/favorite/repositories.rs @@ -32,4 +32,20 @@ impl FavoriteRepository { )?; Ok((article, profile, favorite_info, tags_list)) } + + pub fn unfavorite( + &self, + user: User, + article_title_slug: String, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + let conn = &mut self.pool.get()?; + let (article, profile, favorite_info, tags_list) = services::unfavorite( + conn, + &services::UnfavoriteService { + current_user: user, + article_title_slug, + }, + )?; + Ok((article, profile, favorite_info, tags_list)) + } } diff --git a/src/appv2/features/favorite/services.rs b/src/appv2/features/favorite/services.rs index ae55e7f..c6a4a1b 100644 --- a/src/appv2/features/favorite/services.rs +++ b/src/appv2/features/favorite/services.rs @@ -14,7 +14,7 @@ pub struct FavoriteService { pub article_title_slug: String, } -// TODO: move to User model +#[deprecated(note = "use repository instead")] pub fn favorite( conn: &mut PgConnection, params: &FavoriteService, @@ -48,6 +48,7 @@ pub struct UnfavoriteService { pub article_title_slug: String, } +#[deprecated(note = "use repository instead")] pub fn unfavorite( conn: &mut PgConnection, params: &UnfavoriteService, diff --git a/src/appv2/features/favorite/usecases.rs b/src/appv2/features/favorite/usecases.rs index f50f1be..eed5b69 100644 --- a/src/appv2/features/favorite/usecases.rs +++ b/src/appv2/features/favorite/usecases.rs @@ -34,4 +34,16 @@ impl FavoriteUsecase { let res = self.favorite_presenter.complete(result); Ok(res) } + + pub fn unfavorite( + &self, + user: User, + article_title_slug: String, + ) -> Result { + let result = self + .favorite_repository + .unfavorite(user, article_title_slug)?; + let res = self.favorite_presenter.complete(result); + Ok(res) + } } From b61494133101fc802d3a7259d025325db39e4ba4 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:25:02 +0900 Subject: [PATCH 24/59] refactor: update healthcheck --- src/app/healthcheck/mod.rs | 1 - src/app/mod.rs | 1 - src/appv2/drivers/routes.rs | 5 ++++- .../api.rs => appv2/features/healthcheck/controllers.rs} | 0 src/appv2/features/healthcheck/mod.rs | 1 + src/appv2/features/mod.rs | 1 + 6 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 src/app/healthcheck/mod.rs rename src/{app/healthcheck/api.rs => appv2/features/healthcheck/controllers.rs} (100%) create mode 100644 src/appv2/features/healthcheck/mod.rs diff --git a/src/app/healthcheck/mod.rs b/src/app/healthcheck/mod.rs deleted file mode 100644 index e5fdf85..0000000 --- a/src/app/healthcheck/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod api; diff --git a/src/app/mod.rs b/src/app/mod.rs index 84a51d3..367ce24 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,5 +1,4 @@ pub mod article; pub mod comment; pub mod follow; -pub mod healthcheck; pub mod tag; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index 3db8d8b..6d81b46 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -6,7 +6,10 @@ use actix_web::web::{delete, get, post, put}; pub fn api(cfg: &mut web::ServiceConfig) { cfg.service( web::scope("/api") - .service(web::scope("/healthcheck").route("", get().to(app::healthcheck::api::index))) + .service(web::scope("/healthcheck").route( + "", + get().to(appv2::features::healthcheck::controllers::index), + )) .service(web::scope("/tags").route("", get().to(app::tag::api::index))) .service( web::scope("/users") diff --git a/src/app/healthcheck/api.rs b/src/appv2/features/healthcheck/controllers.rs similarity index 100% rename from src/app/healthcheck/api.rs rename to src/appv2/features/healthcheck/controllers.rs diff --git a/src/appv2/features/healthcheck/mod.rs b/src/appv2/features/healthcheck/mod.rs new file mode 100644 index 0000000..f916674 --- /dev/null +++ b/src/appv2/features/healthcheck/mod.rs @@ -0,0 +1 @@ +pub mod controllers; diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index 0083df8..a905e64 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -1,3 +1,4 @@ pub mod favorite; +pub mod healthcheck; pub mod profile; pub mod user; From b7de2266b20249abb312af45706dc4022585412c Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:27:13 +0900 Subject: [PATCH 25/59] refactor: update follow --- src/app/article/service.rs | 2 +- src/app/follow/mod.rs | 1 - src/app/mod.rs | 1 - src/{app/follow/model.rs => appv2/features/follow/entities.rs} | 0 src/appv2/features/follow/mod.rs | 1 + src/appv2/features/mod.rs | 1 + src/appv2/features/user/entities.rs | 2 +- src/appv2/features/user/repositories.rs | 2 +- 8 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 src/app/follow/mod.rs rename src/{app/follow/model.rs => appv2/features/follow/entities.rs} (100%) create mode 100644 src/appv2/features/follow/mod.rs diff --git a/src/app/article/service.rs b/src/app/article/service.rs index 2d61110..cdbc859 100644 --- a/src/app/article/service.rs +++ b/src/app/article/service.rs @@ -1,7 +1,7 @@ use crate::app::article::model::{Article, CreateArticle, UpdateArticle}; -use crate::app::follow::model::Follow; use crate::app::tag::model::{CreateTag, Tag}; use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; +use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::user::entities::User; use crate::error::AppError; diff --git a/src/app/follow/mod.rs b/src/app/follow/mod.rs deleted file mode 100644 index 65880be..0000000 --- a/src/app/follow/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod model; diff --git a/src/app/mod.rs b/src/app/mod.rs index 367ce24..74daf13 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,4 +1,3 @@ pub mod article; pub mod comment; -pub mod follow; pub mod tag; diff --git a/src/app/follow/model.rs b/src/appv2/features/follow/entities.rs similarity index 100% rename from src/app/follow/model.rs rename to src/appv2/features/follow/entities.rs diff --git a/src/appv2/features/follow/mod.rs b/src/appv2/features/follow/mod.rs new file mode 100644 index 0000000..0b8f0b5 --- /dev/null +++ b/src/appv2/features/follow/mod.rs @@ -0,0 +1 @@ +pub mod entities; diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index a905e64..a4de399 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -1,4 +1,5 @@ pub mod favorite; +pub mod follow; pub mod healthcheck; pub mod profile; pub mod user; diff --git a/src/appv2/features/user/entities.rs b/src/appv2/features/user/entities.rs index 045c968..b8ea1a1 100644 --- a/src/appv2/features/user/entities.rs +++ b/src/appv2/features/user/entities.rs @@ -1,5 +1,5 @@ -use crate::app::follow::model::Follow; use crate::appv2::features::favorite::entities::Favorite; +use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; use crate::error::AppError; use crate::schema::users; diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index 6eee318..ba224f2 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -1,6 +1,6 @@ use uuid::Uuid; -use crate::app::follow::model::{CreateFollow, DeleteFollow, Follow}; +use crate::appv2::features::follow::entities::{CreateFollow, DeleteFollow, Follow}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::user::entities::User; use crate::error::AppError; From 85c1ffb07e40c434abc075c58a53ee75e7c3061f Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:36:19 +0900 Subject: [PATCH 26/59] refactor: update tag feature --- src/app/article/response.rs | 3 +-- src/app/article/service.rs | 2 +- src/app/mod.rs | 1 - src/app/tag/mod.rs | 3 --- src/appv2/drivers/routes.rs | 4 +++- src/appv2/features/favorite/presenters.rs | 6 ++---- src/appv2/features/favorite/repositories.rs | 2 +- src/appv2/features/favorite/services.rs | 2 +- src/appv2/features/mod.rs | 1 + src/{app/tag/api.rs => appv2/features/tag/controllers.rs} | 4 ++-- src/{app/tag/model.rs => appv2/features/tag/entities.rs} | 0 src/appv2/features/tag/mod.rs | 3 +++ .../tag/response.rs => appv2/features/tag/presenters.rs} | 2 +- 13 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 src/app/tag/mod.rs rename src/{app/tag/api.rs => appv2/features/tag/controllers.rs} (85%) rename src/{app/tag/model.rs => appv2/features/tag/entities.rs} (100%) create mode 100644 src/appv2/features/tag/mod.rs rename src/{app/tag/response.rs => appv2/features/tag/presenters.rs} (94%) diff --git a/src/app/article/response.rs b/src/app/article/response.rs index 7a8142f..b3f277f 100644 --- a/src/app/article/response.rs +++ b/src/app/article/response.rs @@ -1,8 +1,7 @@ -use crate::app::article::model::Article; -use crate::app::tag::model::Tag; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; use crate::utils::date::Iso8601; +use crate::{app::article::model::Article, appv2::features::tag::entities::Tag}; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/app/article/service.rs b/src/app/article/service.rs index cdbc859..5fc57ba 100644 --- a/src/app/article/service.rs +++ b/src/app/article/service.rs @@ -1,8 +1,8 @@ use crate::app::article::model::{Article, CreateArticle, UpdateArticle}; -use crate::app::tag::model::{CreateTag, Tag}; use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::tag::entities::{CreateTag, Tag}; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::articles::dsl::*; diff --git a/src/app/mod.rs b/src/app/mod.rs index 74daf13..a111b38 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,3 +1,2 @@ pub mod article; pub mod comment; -pub mod tag; diff --git a/src/app/tag/mod.rs b/src/app/tag/mod.rs deleted file mode 100644 index 7e6b406..0000000 --- a/src/app/tag/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod api; -pub mod model; -pub mod response; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index 6d81b46..9d82360 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -10,7 +10,9 @@ pub fn api(cfg: &mut web::ServiceConfig) { "", get().to(appv2::features::healthcheck::controllers::index), )) - .service(web::scope("/tags").route("", get().to(app::tag::api::index))) + .service( + web::scope("/tags").route("", get().to(appv2::features::tag::controllers::index)), + ) .service( web::scope("/users") .route( diff --git a/src/appv2/features/favorite/presenters.rs b/src/appv2/features/favorite/presenters.rs index e01480d..fdda223 100644 --- a/src/appv2/features/favorite/presenters.rs +++ b/src/appv2/features/favorite/presenters.rs @@ -1,10 +1,8 @@ use actix_web::HttpResponse; pub use crate::app::article::response::SingleArticleResponse; -use crate::{ - app::{article::model::Article, tag::model::Tag}, - appv2::features::profile::entities::Profile, -}; +use crate::appv2::features::tag::entities::Tag; +use crate::{app::article::model::Article, appv2::features::profile::entities::Profile}; use super::entities::FavoriteInfo; diff --git a/src/appv2/features/favorite/repositories.rs b/src/appv2/features/favorite/repositories.rs index 24c1047..d77b5e0 100644 --- a/src/appv2/features/favorite/repositories.rs +++ b/src/appv2/features/favorite/repositories.rs @@ -1,8 +1,8 @@ use super::entities::FavoriteInfo; use super::services; use crate::app::article::model::Article; -use crate::app::tag::model::Tag; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::tag::entities::Tag; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; diff --git a/src/appv2/features/favorite/services.rs b/src/appv2/features/favorite/services.rs index c6a4a1b..4d98b77 100644 --- a/src/appv2/features/favorite/services.rs +++ b/src/appv2/features/favorite/services.rs @@ -1,10 +1,10 @@ use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; use crate::app::article::service::{fetch_article, FetchArticle}; -use crate::app::tag::model::Tag; use crate::appv2::features::favorite::entities::{ CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo, }; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::tag::entities::Tag; use crate::appv2::features::user::entities::User; use crate::error::AppError; use diesel::pg::PgConnection; diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index a4de399..374a3bd 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -2,4 +2,5 @@ pub mod favorite; pub mod follow; pub mod healthcheck; pub mod profile; +pub mod tag; pub mod user; diff --git a/src/app/tag/api.rs b/src/appv2/features/tag/controllers.rs similarity index 85% rename from src/app/tag/api.rs rename to src/appv2/features/tag/controllers.rs index 1e8e021..2d545e9 100644 --- a/src/app/tag/api.rs +++ b/src/appv2/features/tag/controllers.rs @@ -1,6 +1,6 @@ extern crate serde_json; -use super::model::Tag; -use super::response::TagsResponse; +use super::entities::Tag; +use super::presenters::TagsResponse; use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpResponse}; diff --git a/src/app/tag/model.rs b/src/appv2/features/tag/entities.rs similarity index 100% rename from src/app/tag/model.rs rename to src/appv2/features/tag/entities.rs diff --git a/src/appv2/features/tag/mod.rs b/src/appv2/features/tag/mod.rs new file mode 100644 index 0000000..5b53859 --- /dev/null +++ b/src/appv2/features/tag/mod.rs @@ -0,0 +1,3 @@ +pub mod controllers; +pub mod entities; +pub mod presenters; diff --git a/src/app/tag/response.rs b/src/appv2/features/tag/presenters.rs similarity index 94% rename from src/app/tag/response.rs rename to src/appv2/features/tag/presenters.rs index d9ba5de..22adfbd 100644 --- a/src/app/tag/response.rs +++ b/src/appv2/features/tag/presenters.rs @@ -1,4 +1,4 @@ -use super::model::Tag; +use super::entities::Tag; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, Debug, Clone)] From ccf1a7f65fcd4e24e738db791dc249cbd32d7b13 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:48:02 +0900 Subject: [PATCH 27/59] refactor: update tag list --- src/appv2/features/tag/controllers.rs | 9 ++------- src/appv2/features/tag/mod.rs | 2 ++ src/appv2/features/tag/presenters.rs | 13 +++++++++++++ src/appv2/features/tag/repositories.rs | 21 +++++++++++++++++++++ src/appv2/features/tag/usecases.rs | 25 +++++++++++++++++++++++++ src/utils/di.rs | 20 ++++++++++++++++++++ 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 src/appv2/features/tag/repositories.rs create mode 100644 src/appv2/features/tag/usecases.rs diff --git a/src/appv2/features/tag/controllers.rs b/src/appv2/features/tag/controllers.rs index 2d545e9..1502c7a 100644 --- a/src/appv2/features/tag/controllers.rs +++ b/src/appv2/features/tag/controllers.rs @@ -1,13 +1,8 @@ extern crate serde_json; -use super::entities::Tag; -use super::presenters::TagsResponse; use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; -use actix_web::{web, HttpResponse}; +use actix_web::web; pub async fn index(state: web::Data) -> ApiResponse { - let conn = &mut state.get_conn()?; - let list = Tag::fetch(conn)?; - let res = TagsResponse::from(list); - Ok(HttpResponse::Ok().json(res)) + state.di_container.tag_usecase.list() } diff --git a/src/appv2/features/tag/mod.rs b/src/appv2/features/tag/mod.rs index 5b53859..9c2709f 100644 --- a/src/appv2/features/tag/mod.rs +++ b/src/appv2/features/tag/mod.rs @@ -1,3 +1,5 @@ pub mod controllers; pub mod entities; pub mod presenters; +pub mod repositories; +pub mod usecases; diff --git a/src/appv2/features/tag/presenters.rs b/src/appv2/features/tag/presenters.rs index 22adfbd..6c5d99f 100644 --- a/src/appv2/features/tag/presenters.rs +++ b/src/appv2/features/tag/presenters.rs @@ -1,4 +1,5 @@ use super::entities::Tag; +use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, Debug, Clone)] @@ -13,3 +14,15 @@ impl std::convert::From> for TagsResponse { TagsResponse { tags: list } } } + +#[derive(Clone)] +pub struct TagPresenter {} +impl TagPresenter { + pub fn new() -> Self { + Self {} + } + pub fn from_list(&self, list: Vec) -> HttpResponse { + let res = TagsResponse::from(list); + HttpResponse::Ok().json(res) + } +} diff --git a/src/appv2/features/tag/repositories.rs b/src/appv2/features/tag/repositories.rs new file mode 100644 index 0000000..4a5465a --- /dev/null +++ b/src/appv2/features/tag/repositories.rs @@ -0,0 +1,21 @@ +use super::entities::Tag; +use crate::error::AppError; +use crate::utils::db::DbPool; + +type Token = String; + +#[derive(Clone)] +pub struct TagRepository { + pool: DbPool, +} + +impl TagRepository { + pub fn new(pool: DbPool) -> Self { + Self { pool } + } + + pub fn list(&self) -> Result, AppError> { + let conn = &mut self.pool.get()?; + Tag::fetch(conn) + } +} diff --git a/src/appv2/features/tag/usecases.rs b/src/appv2/features/tag/usecases.rs new file mode 100644 index 0000000..7ee8b88 --- /dev/null +++ b/src/appv2/features/tag/usecases.rs @@ -0,0 +1,25 @@ +use super::presenters::TagPresenter; +use super::repositories::TagRepository; +use crate::error::AppError; +use actix_web::HttpResponse; + +#[derive(Clone)] +pub struct TagUsecase { + tag_repository: TagRepository, + tag_presenter: TagPresenter, +} + +impl TagUsecase { + pub fn new(tag_repository: TagRepository, tag_presenter: TagPresenter) -> Self { + Self { + tag_repository, + tag_presenter, + } + } + + pub fn list(&self) -> Result { + let list = self.tag_repository.list()?; + let res = self.tag_presenter.from_list(list); + Ok(res) + } +} diff --git a/src/utils/di.rs b/src/utils/di.rs index f8a46af..9c33541 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -4,6 +4,9 @@ use crate::appv2::features::favorite::{ use crate::appv2::features::profile::{ presenters::ProfilePresenter, repositories::ProfileRepository, usecases::ProfileUsecase, }; +use crate::appv2::features::tag::presenters::TagPresenter; +use crate::appv2::features::tag::repositories::TagRepository; +use crate::appv2::features::tag::usecases::TagUsecase; use crate::appv2::features::user::{ presenters::UserPresenter, repositories::UserRepository, usecases::UserUsecase, }; @@ -32,6 +35,13 @@ pub struct DiContainer { pub favorite_repository: FavoriteRepository, pub favorite_presenter: FavoritePresenter, pub favorite_usecase: FavoriteUsecase, + + /** + * Tag + */ + pub tag_repository: TagRepository, + pub tag_presenter: TagPresenter, + pub tag_usecase: TagUsecase, } impl DiContainer { @@ -55,6 +65,11 @@ impl DiContainer { let favorite_usecase = FavoriteUsecase::new(favorite_repository.clone(), favorite_presenter.clone()); + // Tag + let tag_repository = TagRepository::new(pool.clone()); + let tag_presenter = TagPresenter::new(); + let tag_usecase = TagUsecase::new(tag_repository.clone(), tag_presenter.clone()); + Self { // User user_repository, @@ -70,6 +85,11 @@ impl DiContainer { favorite_repository, favorite_presenter, favorite_usecase, + + // Tag + tag_repository, + tag_presenter, + tag_usecase, } } } From 46c0e90538370177997a5ee59e195224e6db69e3 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 00:57:05 +0900 Subject: [PATCH 28/59] refactor: update article feature --- src/app/article/mod.rs | 5 --- src/app/comment/model.rs | 2 +- src/app/comment/service.rs | 2 +- src/app/mod.rs | 1 - src/appv2/drivers/routes.rs | 18 ++++++---- .../features/article/controllers.rs} | 33 ++++++++++--------- .../features/article/entities.rs} | 0 src/appv2/features/article/mod.rs | 5 +++ .../features/article/presenters.rs} | 3 +- .../features/article/requests.rs} | 0 .../features/article/services.rs} | 2 +- src/appv2/features/favorite/entities.rs | 2 +- src/appv2/features/favorite/presenters.rs | 5 +-- src/appv2/features/favorite/repositories.rs | 2 +- src/appv2/features/favorite/services.rs | 4 +-- src/appv2/features/mod.rs | 1 + src/appv2/features/tag/entities.rs | 2 +- 17 files changed, 48 insertions(+), 39 deletions(-) delete mode 100644 src/app/article/mod.rs rename src/{app/article/api.rs => appv2/features/article/controllers.rs} (81%) rename src/{app/article/model.rs => appv2/features/article/entities.rs} (100%) create mode 100644 src/appv2/features/article/mod.rs rename src/{app/article/response.rs => appv2/features/article/presenters.rs} (97%) rename src/{app/article/request.rs => appv2/features/article/requests.rs} (100%) rename src/{app/article/service.rs => appv2/features/article/services.rs} (99%) diff --git a/src/app/article/mod.rs b/src/app/article/mod.rs deleted file mode 100644 index c4c0061..0000000 --- a/src/app/article/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod api; -pub mod model; -pub mod request; -pub mod response; -pub mod service; diff --git a/src/app/comment/model.rs b/src/app/comment/model.rs index 0e009fd..c85a741 100644 --- a/src/app/comment/model.rs +++ b/src/app/comment/model.rs @@ -1,4 +1,4 @@ -use crate::app::article::model::Article; +use crate::appv2::features::article::entities::Article; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::comments; diff --git a/src/app/comment/service.rs b/src/app/comment/service.rs index ecbc3e7..f208a4e 100644 --- a/src/app/comment/service.rs +++ b/src/app/comment/service.rs @@ -1,5 +1,5 @@ use super::model::{Comment, CreateComment, DeleteComment}; -use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; +use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::profile::services::{conver_user_to_profile, ConverUserToProfile}; use crate::appv2::features::user::entities::User; diff --git a/src/app/mod.rs b/src/app/mod.rs index a111b38..2e9f320 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,2 +1 @@ -pub mod article; pub mod comment; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index 9d82360..1f405b1 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -43,14 +43,20 @@ pub fn api(cfg: &mut web::ServiceConfig) { ) .service( web::scope("/articles") - .route("/feed", get().to(app::article::api::feed)) - .route("", get().to(app::article::api::index)) - .route("", post().to(app::article::api::create)) + .route( + "/feed", + get().to(appv2::features::article::controllers::feed), + ) + .route("", get().to(appv2::features::article::controllers::index)) + .route("", post().to(appv2::features::article::controllers::create)) .service( web::scope("/{article_title_slug}") - .route("", get().to(app::article::api::show)) - .route("", put().to(app::article::api::update)) - .route("", delete().to(app::article::api::delete)) + .route("", get().to(appv2::features::article::controllers::show)) + .route("", put().to(appv2::features::article::controllers::update)) + .route( + "", + delete().to(appv2::features::article::controllers::delete), + ) .service( web::scope("/favorite") .route( diff --git a/src/app/article/api.rs b/src/appv2/features/article/controllers.rs similarity index 81% rename from src/app/article/api.rs rename to src/appv2/features/article/controllers.rs index fc3bb12..85c6501 100644 --- a/src/app/article/api.rs +++ b/src/appv2/features/article/controllers.rs @@ -1,8 +1,7 @@ use super::{ - model::{Article, DeleteArticle}, - request, - response::{MultipleArticlesResponse, SingleArticleResponse}, - service, + entities::{Article, DeleteArticle}, + presenters::{MultipleArticlesResponse, SingleArticleResponse}, + requests, services, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; @@ -29,9 +28,9 @@ pub async fn index( let offset = std::cmp::min(params.offset.to_owned().unwrap_or(0), 100); let limit = params.limit.unwrap_or(20); - let (articles_list, articles_count) = service::fetch_articles_list( + let (articles_list, articles_count) = services::fetch_articles_list( conn, - service::FetchArticlesList { + services::FetchArticlesList { tag: params.tag.clone(), author: params.author.clone(), favorited: params.favorited.clone(), @@ -59,9 +58,9 @@ pub async fn feed( let current_user = auth::get_current_user(&req)?; let offset = std::cmp::min(params.offset.to_owned().unwrap_or(0), 100); let limit = params.limit.unwrap_or(20); - let (articles_list, articles_count) = service::fetch_following_articles( + let (articles_list, articles_count) = services::fetch_following_articles( conn, - &service::FetchFollowedArticlesSerivce { + &services::FetchFollowedArticlesSerivce { current_user, offset, limit, @@ -75,8 +74,10 @@ pub async fn feed( pub async fn show(state: web::Data, path: web::Path) -> ApiResponse { let conn = &mut state.get_conn()?; let article_title_slug = path.into_inner(); - let (article, profile, favorite_info, tags_list) = - service::fetch_article_by_slug(conn, &service::FetchArticleBySlug { article_title_slug })?; + let (article, profile, favorite_info, tags_list) = services::fetch_article_by_slug( + conn, + &services::FetchArticleBySlug { article_title_slug }, + )?; let res = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); Ok(HttpResponse::Ok().json(res)) } @@ -84,13 +85,13 @@ pub async fn show(state: web::Data, path: web::Path) pub async fn create( state: web::Data, req: HttpRequest, - form: web::Json, + form: web::Json, ) -> ApiResponse { let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; - let (article, profile, favorite_info, tag_list) = service::create( + let (article, profile, favorite_info, tag_list) = services::create( conn, - &service::CreateArticleSerivce { + &services::CreateArticleSerivce { title: form.article.title.clone(), slug: Article::convert_title_to_slug(&form.article.title), description: form.article.description.clone(), @@ -107,7 +108,7 @@ pub async fn update( state: web::Data, req: HttpRequest, path: web::Path, - form: web::Json, + form: web::Json, ) -> ApiResponse { let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; @@ -118,9 +119,9 @@ pub async fn update( .as_ref() .map(|_title| Article::convert_title_to_slug(_title)); - let (article, profile, favorite_info, tag_list) = service::update_article( + let (article, profile, favorite_info, tag_list) = services::update_article( conn, - &service::UpdateArticleService { + &services::UpdateArticleService { current_user, article_title_slug, slug: article_slug.to_owned(), diff --git a/src/app/article/model.rs b/src/appv2/features/article/entities.rs similarity index 100% rename from src/app/article/model.rs rename to src/appv2/features/article/entities.rs diff --git a/src/appv2/features/article/mod.rs b/src/appv2/features/article/mod.rs new file mode 100644 index 0000000..3434960 --- /dev/null +++ b/src/appv2/features/article/mod.rs @@ -0,0 +1,5 @@ +pub mod controllers; +pub mod entities; +pub mod presenters; +pub mod requests; +pub mod services; diff --git a/src/app/article/response.rs b/src/appv2/features/article/presenters.rs similarity index 97% rename from src/app/article/response.rs rename to src/appv2/features/article/presenters.rs index b3f277f..1b4feb9 100644 --- a/src/app/article/response.rs +++ b/src/appv2/features/article/presenters.rs @@ -1,7 +1,8 @@ +use super::entities::Article; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::tag::entities::Tag; use crate::utils::date::Iso8601; -use crate::{app::article::model::Article, appv2::features::tag::entities::Tag}; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/app/article/request.rs b/src/appv2/features/article/requests.rs similarity index 100% rename from src/app/article/request.rs rename to src/appv2/features/article/requests.rs diff --git a/src/app/article/service.rs b/src/appv2/features/article/services.rs similarity index 99% rename from src/app/article/service.rs rename to src/appv2/features/article/services.rs index 5fc57ba..45346e0 100644 --- a/src/app/article/service.rs +++ b/src/appv2/features/article/services.rs @@ -1,4 +1,4 @@ -use crate::app::article::model::{Article, CreateArticle, UpdateArticle}; +use crate::appv2::features::article::entities::{Article, CreateArticle, UpdateArticle}; use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; diff --git a/src/appv2/features/favorite/entities.rs b/src/appv2/features/favorite/entities.rs index 0a91c7c..8d10943 100644 --- a/src/appv2/features/favorite/entities.rs +++ b/src/appv2/features/favorite/entities.rs @@ -1,4 +1,4 @@ -use crate::app::article::model::Article; +use crate::appv2::features::article::entities::Article; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::favorites; diff --git a/src/appv2/features/favorite/presenters.rs b/src/appv2/features/favorite/presenters.rs index fdda223..33b8892 100644 --- a/src/appv2/features/favorite/presenters.rs +++ b/src/appv2/features/favorite/presenters.rs @@ -1,8 +1,9 @@ use actix_web::HttpResponse; -pub use crate::app::article::response::SingleArticleResponse; +use crate::appv2::features::article::entities::Article; +pub use crate::appv2::features::article::presenters::SingleArticleResponse; +use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::Tag; -use crate::{app::article::model::Article, appv2::features::profile::entities::Profile}; use super::entities::FavoriteInfo; diff --git a/src/appv2/features/favorite/repositories.rs b/src/appv2/features/favorite/repositories.rs index d77b5e0..be74a72 100644 --- a/src/appv2/features/favorite/repositories.rs +++ b/src/appv2/features/favorite/repositories.rs @@ -1,6 +1,6 @@ use super::entities::FavoriteInfo; use super::services; -use crate::app::article::model::Article; +use crate::appv2::features::article::entities::Article; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::Tag; use crate::appv2::features::user::entities::User; diff --git a/src/appv2/features/favorite/services.rs b/src/appv2/features/favorite/services.rs index 4d98b77..b74d2e8 100644 --- a/src/appv2/features/favorite/services.rs +++ b/src/appv2/features/favorite/services.rs @@ -1,5 +1,5 @@ -use crate::app::article::model::{Article, FetchBySlugAndAuthorId}; -use crate::app::article::service::{fetch_article, FetchArticle}; +use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; +use crate::appv2::features::article::services::{fetch_article, FetchArticle}; use crate::appv2::features::favorite::entities::{ CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo, }; diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index 374a3bd..e6d5264 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -1,3 +1,4 @@ +pub mod article; pub mod favorite; pub mod follow; pub mod healthcheck; diff --git a/src/appv2/features/tag/entities.rs b/src/appv2/features/tag/entities.rs index c7dcd13..6637472 100644 --- a/src/appv2/features/tag/entities.rs +++ b/src/appv2/features/tag/entities.rs @@ -1,4 +1,4 @@ -use crate::app::article::model::Article; +use crate::appv2::features::article::entities::Article; use crate::error::AppError; use crate::schema::tags; use chrono::NaiveDateTime; From de4e1e9acc8f3356b161825a77e8f6d55d8e2ddd Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 01:45:30 +0900 Subject: [PATCH 29/59] refactor: update article list --- src/appv2/features/article/controllers.rs | 15 +++------ src/appv2/features/article/mod.rs | 2 ++ src/appv2/features/article/presenters.rs | 15 ++++++++- src/appv2/features/article/repositories.rs | 33 +++++++++++++++++++ src/appv2/features/article/services.rs | 9 +++--- src/appv2/features/article/usecases.rs | 37 ++++++++++++++++++++++ src/utils/di.rs | 21 ++++++++++++ 7 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 src/appv2/features/article/repositories.rs create mode 100644 src/appv2/features/article/usecases.rs diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index 85c6501..fb4d3c1 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -24,23 +24,18 @@ pub async fn index( state: web::Data, params: web::Query, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let offset = std::cmp::min(params.offset.to_owned().unwrap_or(0), 100); let limit = params.limit.unwrap_or(20); - - let (articles_list, articles_count) = services::fetch_articles_list( - conn, - services::FetchArticlesList { + state + .di_container + .article_usecase + .fetch_articles_list(services::FetchArticlesList { tag: params.tag.clone(), author: params.author.clone(), favorited: params.favorited.clone(), offset, limit, - }, - )?; - - let res = MultipleArticlesResponse::from((articles_list, articles_count)); - Ok(HttpResponse::Ok().json(res)) + }) } #[derive(Deserialize)] diff --git a/src/appv2/features/article/mod.rs b/src/appv2/features/article/mod.rs index 3434960..71c5a4d 100644 --- a/src/appv2/features/article/mod.rs +++ b/src/appv2/features/article/mod.rs @@ -1,5 +1,7 @@ pub mod controllers; pub mod entities; pub mod presenters; +pub mod repositories; pub mod requests; pub mod services; +pub mod usecases; diff --git a/src/appv2/features/article/presenters.rs b/src/appv2/features/article/presenters.rs index 1b4feb9..08537bf 100644 --- a/src/appv2/features/article/presenters.rs +++ b/src/appv2/features/article/presenters.rs @@ -1,8 +1,10 @@ use super::entities::Article; +use super::services::ArticlesList; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::Tag; use crate::utils::date::Iso8601; +use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; use std::convert::From; @@ -51,7 +53,6 @@ pub struct MultipleArticlesResponse { type ArticlesCount = i64; type Inner = ((Article, Profile, FavoriteInfo), Vec); -type ArticlesList = Vec; type Item = (ArticlesList, ArticlesCount); impl From for MultipleArticlesResponse { fn from((list, articles_count): (Vec, ArticleCount)) -> Self { @@ -119,3 +120,15 @@ pub struct AuthorContent { pub image: Option, pub following: bool, } + +#[derive(Clone)] +pub struct ArticlePresenter {} +impl ArticlePresenter { + pub fn new() -> Self { + Self {} + } + pub fn from_list_and_count(&self, list: ArticlesList, count: i64) -> HttpResponse { + let res = MultipleArticlesResponse::from((list, count)); + HttpResponse::Ok().json(res) + } +} diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs new file mode 100644 index 0000000..0422606 --- /dev/null +++ b/src/appv2/features/article/repositories.rs @@ -0,0 +1,33 @@ +use super::services::{self, FetchArticlesListResult}; +use crate::error::AppError; +use crate::utils::db::DbPool; + +type ArticleCount = i64; +#[derive(Clone)] +pub struct ArticleRepository { + pool: DbPool, +} + +impl ArticleRepository { + pub fn new(pool: DbPool) -> Self { + Self { pool } + } + + pub fn fetch_articles_list( + &self, + params: services::FetchArticlesList, + ) -> Result { + let conn = &mut self.pool.get()?; + let result = services::fetch_articles_list( + conn, + services::FetchArticlesList { + tag: params.tag.clone(), + author: params.author.clone(), + favorited: params.favorited.clone(), + offset: params.offset, + limit: params.limit, + }, + )?; + Ok(result) + } +} diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index 45346e0..9c66bc8 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -79,11 +79,12 @@ pub struct FetchArticlesList { type ArticlesCount = i64; type ArticlesListInner = (Article, Profile, FavoriteInfo); -type ArticlesList = Vec<(ArticlesListInner, Vec)>; +pub type ArticlesList = Vec<(ArticlesListInner, Vec)>; +pub type FetchArticlesListResult = (ArticlesList, ArticlesCount); pub fn fetch_articles_list( conn: &mut PgConnection, params: FetchArticlesList, -) -> Result<(ArticlesList, ArticlesCount), AppError> { +) -> Result { use diesel::prelude::*; let query = { @@ -114,7 +115,7 @@ pub fn fetch_articles_list( .select(diesel::dsl::count(articles::id)) .first::(conn)?; - let list = { + let result = { let query = { let mut query = articles::table.inner_join(users::table).into_boxed(); @@ -190,7 +191,7 @@ pub fn fetch_articles_list( .collect::>() }; - Ok((list, articles_count)) + Ok((result, articles_count)) } pub struct FetchArticle { diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs new file mode 100644 index 0000000..7e3a6d8 --- /dev/null +++ b/src/appv2/features/article/usecases.rs @@ -0,0 +1,37 @@ +use super::presenters::ArticlePresenter; +use super::repositories::ArticleRepository; +use super::services; +use crate::error::AppError; +use actix_web::HttpResponse; + +#[derive(Clone)] +pub struct ArticleUsecase { + article_repository: ArticleRepository, + article_presenter: ArticlePresenter, +} + +impl ArticleUsecase { + pub fn new(article_repository: ArticleRepository, article_presenter: ArticlePresenter) -> Self { + Self { + article_repository, + article_presenter, + } + } + + pub fn fetch_articles_list( + &self, + params: services::FetchArticlesList, + ) -> Result { + let (list, count) = + self.article_repository + .fetch_articles_list(services::FetchArticlesList { + tag: params.tag.clone(), + author: params.author.clone(), + favorited: params.favorited.clone(), + offset: params.offset, + limit: params.limit, + })?; + let res = self.article_presenter.from_list_and_count(list, count); + Ok(res) + } +} diff --git a/src/utils/di.rs b/src/utils/di.rs index 9c33541..2cd2991 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,3 +1,6 @@ +use crate::appv2::features::article::presenters::ArticlePresenter; +use crate::appv2::features::article::repositories::ArticleRepository; +use crate::appv2::features::article::usecases::ArticleUsecase; use crate::appv2::features::favorite::{ presenters::FavoritePresenter, repositories::FavoriteRepository, usecases::FavoriteUsecase, }; @@ -36,6 +39,13 @@ pub struct DiContainer { pub favorite_presenter: FavoritePresenter, pub favorite_usecase: FavoriteUsecase, + /** + * Article + */ + pub article_repository: ArticleRepository, + pub article_presenter: ArticlePresenter, + pub article_usecase: ArticleUsecase, + /** * Tag */ @@ -65,6 +75,12 @@ impl DiContainer { let favorite_usecase = FavoriteUsecase::new(favorite_repository.clone(), favorite_presenter.clone()); + // Article + let article_repository = ArticleRepository::new(pool.clone()); + let article_presenter = ArticlePresenter::new(); + let article_usecase = + ArticleUsecase::new(article_repository.clone(), article_presenter.clone()); + // Tag let tag_repository = TagRepository::new(pool.clone()); let tag_presenter = TagPresenter::new(); @@ -86,6 +102,11 @@ impl DiContainer { favorite_presenter, favorite_usecase, + // Article + article_repository, + article_presenter, + article_usecase, + // Tag tag_repository, tag_presenter, From 4a0db63223bba5b7996f3dd06df29b2d96bbc96c Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 02:19:12 +0900 Subject: [PATCH 30/59] refactor: update article show feature --- src/appv2/features/article/controllers.rs | 11 ++++------- src/appv2/features/article/presenters.rs | 4 ++++ src/appv2/features/article/repositories.rs | 8 ++++++++ src/appv2/features/article/services.rs | 3 ++- src/appv2/features/article/usecases.rs | 12 ++++++++++++ 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index fb4d3c1..81af7bc 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -67,14 +67,11 @@ pub async fn feed( } pub async fn show(state: web::Data, path: web::Path) -> ApiResponse { - let conn = &mut state.get_conn()?; let article_title_slug = path.into_inner(); - let (article, profile, favorite_info, tags_list) = services::fetch_article_by_slug( - conn, - &services::FetchArticleBySlug { article_title_slug }, - )?; - let res = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); - Ok(HttpResponse::Ok().json(res)) + state + .di_container + .article_usecase + .fetch_article_by_slug(&services::FetchArticleBySlug { article_title_slug }) } pub async fn create( diff --git a/src/appv2/features/article/presenters.rs b/src/appv2/features/article/presenters.rs index 08537bf..8918596 100644 --- a/src/appv2/features/article/presenters.rs +++ b/src/appv2/features/article/presenters.rs @@ -131,4 +131,8 @@ impl ArticlePresenter { let res = MultipleArticlesResponse::from((list, count)); HttpResponse::Ok().json(res) } + pub fn from_item(&self, item: (Article, Profile, FavoriteInfo, Vec)) -> HttpResponse { + let res = SingleArticleResponse::from(item); + HttpResponse::Ok().json(res) + } } diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 0422606..9c907c9 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -30,4 +30,12 @@ impl ArticleRepository { )?; Ok(result) } + + pub fn fetch_article_by_slug( + &self, + article_title_slug: String, + ) -> Result { + let conn = &mut self.pool.get()?; + services::fetch_article_by_slug(conn, &services::FetchArticleBySlug { article_title_slug }) + } } diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index 9c66bc8..363fefb 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -223,13 +223,14 @@ pub fn fetch_article( Ok((article, profile, favorite_info, tags_list)) } +pub type FetchArticleBySlugResult = (Article, Profile, FavoriteInfo, Vec); pub struct FetchArticleBySlug { pub article_title_slug: String, } pub fn fetch_article_by_slug( conn: &mut PgConnection, params: &FetchArticleBySlug, -) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { +) -> Result { let (article, author) = Article::fetch_by_slug_with_author(conn, ¶ms.article_title_slug)?; let profile = author.fetch_profile(conn, &author.id)?; diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 7e3a6d8..046e6a8 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -34,4 +34,16 @@ impl ArticleUsecase { let res = self.article_presenter.from_list_and_count(list, count); Ok(res) } + + pub fn fetch_article_by_slug( + &self, + params: &services::FetchArticleBySlug, + ) -> Result { + let article_title_slug = params.article_title_slug.clone(); + let result = self + .article_repository + .fetch_article_by_slug(article_title_slug)?; + let res = self.article_presenter.from_item(result); + Ok(res) + } } From 903558493df3b27a48ad06dcff8f903a90154eed Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 09:14:52 +0900 Subject: [PATCH 31/59] refactor: update create-article feature --- src/appv2/features/article/controllers.rs | 15 +++---- src/appv2/features/article/repositories.rs | 48 ++++++++++++++++++++++ src/appv2/features/article/services.rs | 44 +------------------- src/appv2/features/article/usecases.rs | 28 ++++++++++++- 4 files changed, 83 insertions(+), 52 deletions(-) diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index 81af7bc..ab6af96 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -2,6 +2,7 @@ use super::{ entities::{Article, DeleteArticle}, presenters::{MultipleArticlesResponse, SingleArticleResponse}, requests, services, + usecases::CreateArticleUsecaseInput, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; @@ -79,21 +80,17 @@ pub async fn create( req: HttpRequest, form: web::Json, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; - let (article, profile, favorite_info, tag_list) = services::create( - conn, - &services::CreateArticleSerivce { + state + .di_container + .article_usecase + .create(CreateArticleUsecaseInput { title: form.article.title.clone(), - slug: Article::convert_title_to_slug(&form.article.title), description: form.article.description.clone(), body: form.article.body.clone(), tag_name_list: form.article.tag_list.to_owned(), current_user, - }, - )?; - let res = SingleArticleResponse::from((article, profile, favorite_info, tag_list)); - Ok(HttpResponse::Ok().json(res)) + }) } pub async fn update( diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 9c907c9..258b0af 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -1,4 +1,9 @@ +use super::entities::{Article, CreateArticle}; use super::services::{self, FetchArticlesListResult}; +use crate::appv2::features::favorite::entities::FavoriteInfo; +use crate::appv2::features::profile::entities::Profile; +use crate::appv2::features::tag::entities::Tag; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; @@ -38,4 +43,47 @@ impl ArticleRepository { let conn = &mut self.pool.get()?; services::fetch_article_by_slug(conn, &services::FetchArticleBySlug { article_title_slug }) } + + pub fn create( + &self, + params: CreateArticleRepositoryInput, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + let conn = &mut self.pool.get()?; + + let article = Article::create( + conn, + &CreateArticle { + author_id: params.current_user.id, + slug: params.slug.clone(), + title: params.title.clone(), + description: params.description.clone(), + body: params.body.clone(), + }, + )?; + let tag_list = services::create_tag_list(conn, ¶ms.tag_name_list, &article.id)?; + + let profile = params + .current_user + .fetch_profile(conn, &article.author_id)?; + + let favorite_info = { + let is_favorited = article.is_favorited_by_user_id(conn, ¶ms.current_user.id)?; + let favorites_count = article.fetch_favorites_count(conn)?; + FavoriteInfo { + is_favorited, + favorites_count, + } + }; + + Ok((article, profile, favorite_info, tag_list)) + } +} + +pub struct CreateArticleRepositoryInput { + pub slug: String, + pub title: String, + pub description: String, + pub body: String, + pub tag_name_list: Option>, + pub current_user: User, } diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index 363fefb..15fcbf1 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -1,4 +1,4 @@ -use crate::appv2::features::article::entities::{Article, CreateArticle, UpdateArticle}; +use crate::appv2::features::article::entities::{Article, UpdateArticle}; use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; @@ -11,47 +11,7 @@ use diesel::pg::PgConnection; use diesel::prelude::*; use uuid::Uuid; -pub struct CreateArticleSerivce { - pub slug: String, - pub title: String, - pub description: String, - pub body: String, - pub tag_name_list: Option>, - pub current_user: User, -} -pub fn create( - conn: &mut PgConnection, - params: &CreateArticleSerivce, -) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { - let article = Article::create( - conn, - &CreateArticle { - author_id: params.current_user.id, - slug: params.slug.clone(), - title: params.title.clone(), - description: params.description.clone(), - body: params.body.clone(), - }, - )?; - let tag_list = create_tag_list(conn, ¶ms.tag_name_list, &article.id)?; - - let profile = params - .current_user - .fetch_profile(conn, &article.author_id)?; - - let favorite_info = { - let is_favorited = article.is_favorited_by_user_id(conn, ¶ms.current_user.id)?; - let favorites_count = article.fetch_favorites_count(conn)?; - FavoriteInfo { - is_favorited, - favorites_count, - } - }; - - Ok((article, profile, favorite_info, tag_list)) -} - -fn create_tag_list( +pub fn create_tag_list( conn: &mut PgConnection, tag_name_list: &Option>, article_id: &Uuid, diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 046e6a8..94b9a11 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -1,6 +1,8 @@ +use super::entities::Article; use super::presenters::ArticlePresenter; -use super::repositories::ArticleRepository; +use super::repositories::{ArticleRepository, CreateArticleRepositoryInput}; use super::services; +use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; @@ -46,4 +48,28 @@ impl ArticleUsecase { let res = self.article_presenter.from_item(result); Ok(res) } + + pub fn create(&self, params: CreateArticleUsecaseInput) -> Result { + let slug = Article::convert_title_to_slug(¶ms.title); + let result = self + .article_repository + .create(CreateArticleRepositoryInput { + body: params.body, + current_user: params.current_user, + description: params.description, + tag_name_list: params.tag_name_list, + title: params.title, + slug, + })?; + let res = self.article_presenter.from_item(result); + Ok(res) + } +} + +pub struct CreateArticleUsecaseInput { + pub title: String, + pub description: String, + pub body: String, + pub tag_name_list: Option>, + pub current_user: User, } From 4c9f12fb65a5168d808913a385183e145466c5e3 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 10:08:52 +0900 Subject: [PATCH 32/59] refactor: update delete article feature --- src/appv2/features/article/controllers.rs | 16 +++++++--------- src/appv2/features/article/presenters.rs | 4 ++++ src/appv2/features/article/repositories.rs | 20 +++++++++++++++++++- src/appv2/features/article/usecases.rs | 20 +++++++++++++++++++- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index ab6af96..4b37326 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -2,7 +2,7 @@ use super::{ entities::{Article, DeleteArticle}, presenters::{MultipleArticlesResponse, SingleArticleResponse}, requests, services, - usecases::CreateArticleUsecaseInput, + usecases::{CreateArticleUsecaseInput, DeleteArticleUsercaseInput}, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; @@ -129,15 +129,13 @@ pub async fn delete( req: HttpRequest, path: web::Path, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - Article::delete( - conn, - &DeleteArticle { - slug: article_title_slug, + state + .di_container + .article_usecase + .delete(DeleteArticleUsercaseInput { author_id: current_user.id, - }, - )?; - Ok(HttpResponse::Ok().json(())) + slug: article_title_slug, + }) } diff --git a/src/appv2/features/article/presenters.rs b/src/appv2/features/article/presenters.rs index 8918596..92e6b12 100644 --- a/src/appv2/features/article/presenters.rs +++ b/src/appv2/features/article/presenters.rs @@ -135,4 +135,8 @@ impl ArticlePresenter { let res = SingleArticleResponse::from(item); HttpResponse::Ok().json(res) } + pub fn toHttpRes(&self) -> HttpResponse { + let res = (); + HttpResponse::Ok().json(res) + } } diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 258b0af..a3b513a 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -1,4 +1,6 @@ -use super::entities::{Article, CreateArticle}; +use uuid::Uuid; + +use super::entities::{Article, CreateArticle, DeleteArticle}; use super::services::{self, FetchArticlesListResult}; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; @@ -77,6 +79,17 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tag_list)) } + + pub fn delete(&self, input: DeleteArticleRepositoryInput) -> Result<(), AppError> { + let conn = &mut self.pool.get()?; + Article::delete( + conn, + &DeleteArticle { + slug: input.slug, + author_id: input.author_id, + }, + ) + } } pub struct CreateArticleRepositoryInput { @@ -87,3 +100,8 @@ pub struct CreateArticleRepositoryInput { pub tag_name_list: Option>, pub current_user: User, } + +pub struct DeleteArticleRepositoryInput { + pub slug: String, + pub author_id: Uuid, +} diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 94b9a11..082cf1b 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -1,10 +1,13 @@ use super::entities::Article; use super::presenters::ArticlePresenter; -use super::repositories::{ArticleRepository, CreateArticleRepositoryInput}; +use super::repositories::{ + ArticleRepository, CreateArticleRepositoryInput, DeleteArticleRepositoryInput, +}; use super::services; use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; +use uuid::Uuid; #[derive(Clone)] pub struct ArticleUsecase { @@ -64,6 +67,16 @@ impl ArticleUsecase { let res = self.article_presenter.from_item(result); Ok(res) } + + pub fn delete(&self, input: DeleteArticleUsercaseInput) -> Result { + self.article_repository + .delete(DeleteArticleRepositoryInput { + slug: input.slug, + author_id: input.author_id, + })?; + let res = self.article_presenter.toHttpRes(); + Ok(res) + } } pub struct CreateArticleUsecaseInput { @@ -73,3 +86,8 @@ pub struct CreateArticleUsecaseInput { pub tag_name_list: Option>, pub current_user: User, } + +pub struct DeleteArticleUsercaseInput { + pub slug: String, + pub author_id: Uuid, +} From e33a238fe5b8d1e1724ab6c8d4117709cd7d40a2 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 10:38:25 +0900 Subject: [PATCH 33/59] refactor: update update-article feature --- src/appv2/features/article/controllers.rs | 34 ++++----- src/appv2/features/article/repositories.rs | 45 +++++++++++- src/appv2/features/article/services.rs | 82 +++++++++++----------- src/appv2/features/article/usecases.rs | 33 ++++++++- 4 files changed, 129 insertions(+), 65 deletions(-) diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index 4b37326..48b9516 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -2,7 +2,7 @@ use super::{ entities::{Article, DeleteArticle}, presenters::{MultipleArticlesResponse, SingleArticleResponse}, requests, services, - usecases::{CreateArticleUsecaseInput, DeleteArticleUsercaseInput}, + usecases::{CreateArticleUsecaseInput, DeleteArticleUsecaseInput, UpdateArticleUsecaseInput}, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; @@ -99,29 +99,21 @@ pub async fn update( path: web::Path, form: web::Json, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - let article_slug = &form - .article - .title - .as_ref() - .map(|_title| Article::convert_title_to_slug(_title)); - - let (article, profile, favorite_info, tag_list) = services::update_article( - conn, - &services::UpdateArticleService { + let title = form.article.title.clone(); + let description = form.article.description.clone(); + let body = form.article.body.clone(); + state + .di_container + .article_usecase + .update(UpdateArticleUsecaseInput { current_user, article_title_slug, - slug: article_slug.to_owned(), - title: form.article.title.clone(), - description: form.article.description.clone(), - body: form.article.body.clone(), - }, - )?; - - let res = SingleArticleResponse::from((article, profile, favorite_info, tag_list)); - Ok(HttpResponse::Ok().json(res)) + title, + description, + body, + }) } pub async fn delete( @@ -134,7 +126,7 @@ pub async fn delete( state .di_container .article_usecase - .delete(DeleteArticleUsercaseInput { + .delete(DeleteArticleUsecaseInput { author_id: current_user.id, slug: article_title_slug, }) diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index a3b513a..d9def47 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -1,6 +1,6 @@ use uuid::Uuid; -use super::entities::{Article, CreateArticle, DeleteArticle}; +use super::entities::{Article, CreateArticle, DeleteArticle, UpdateArticle}; use super::services::{self, FetchArticlesListResult}; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; @@ -90,6 +90,40 @@ impl ArticleRepository { }, ) } + + pub fn update( + &self, + input: UpdateArticleRepositoryInput, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + let conn = &mut self.pool.get()?; + + let article = Article::update( + conn, + &input.article_title_slug, + &input.current_user.id, + &UpdateArticle { + slug: input.slug.to_owned(), + title: input.title.to_owned(), + description: input.description.to_owned(), + body: input.body.to_owned(), + }, + )?; + + let tag_list = Tag::fetch_by_article_id(conn, &article.id)?; + + let profile = input.current_user.fetch_profile(conn, &article.author_id)?; + + let favorite_info = { + let is_favorited = article.is_favorited_by_user_id(conn, &input.current_user.id)?; + let favorites_count = article.fetch_favorites_count(conn)?; + FavoriteInfo { + is_favorited, + favorites_count, + } + }; + + Ok((article, profile, favorite_info, tag_list)) + } } pub struct CreateArticleRepositoryInput { @@ -105,3 +139,12 @@ pub struct DeleteArticleRepositoryInput { pub slug: String, pub author_id: Uuid, } + +pub struct UpdateArticleRepositoryInput { + pub current_user: User, + pub article_title_slug: String, + pub slug: Option, + pub title: Option, + pub description: Option, + pub body: Option, +} diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index 15fcbf1..4b1f9a7 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -309,44 +309,44 @@ pub fn fetch_following_articles( Ok((articles_list, articles_count)) } -pub struct UpdateArticleService { - pub current_user: User, - pub article_title_slug: String, - pub slug: Option, - pub title: Option, - pub description: Option, - pub body: Option, -} -pub fn update_article( - conn: &mut PgConnection, - params: &UpdateArticleService, -) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { - let article = Article::update( - conn, - ¶ms.article_title_slug, - ¶ms.current_user.id, - &UpdateArticle { - slug: params.slug.to_owned(), - title: params.title.to_owned(), - description: params.description.to_owned(), - body: params.body.to_owned(), - }, - )?; - - let tag_list = Tag::fetch_by_article_id(conn, &article.id)?; - - let profile = params - .current_user - .fetch_profile(conn, &article.author_id)?; - - let favorite_info = { - let is_favorited = article.is_favorited_by_user_id(conn, ¶ms.current_user.id)?; - let favorites_count = article.fetch_favorites_count(conn)?; - FavoriteInfo { - is_favorited, - favorites_count, - } - }; - - Ok((article, profile, favorite_info, tag_list)) -} +// pub struct UpdateArticleService { +// pub current_user: User, +// pub article_title_slug: String, +// pub slug: Option, +// pub title: Option, +// pub description: Option, +// pub body: Option, +// } +// pub fn update_article( +// conn: &mut PgConnection, +// params: &UpdateArticleService, +// ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { +// // let article = Article::update( +// // conn, +// // ¶ms.article_title_slug, +// // ¶ms.current_user.id, +// // &UpdateArticle { +// // slug: params.slug.to_owned(), +// // title: params.title.to_owned(), +// // description: params.description.to_owned(), +// // body: params.body.to_owned(), +// // }, +// // )?; + +// // let tag_list = Tag::fetch_by_article_id(conn, &article.id)?; + +// // let profile = params +// // .current_user +// // .fetch_profile(conn, &article.author_id)?; + +// // let favorite_info = { +// // let is_favorited = article.is_favorited_by_user_id(conn, ¶ms.current_user.id)?; +// // let favorites_count = article.fetch_favorites_count(conn)?; +// // FavoriteInfo { +// // is_favorited, +// // favorites_count, +// // } +// // }; + +// // Ok((article, profile, favorite_info, tag_list)) +// } diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 082cf1b..c90e1ca 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -2,6 +2,7 @@ use super::entities::Article; use super::presenters::ArticlePresenter; use super::repositories::{ ArticleRepository, CreateArticleRepositoryInput, DeleteArticleRepositoryInput, + UpdateArticleRepositoryInput, }; use super::services; use crate::appv2::features::user::entities::User; @@ -68,7 +69,7 @@ impl ArticleUsecase { Ok(res) } - pub fn delete(&self, input: DeleteArticleUsercaseInput) -> Result { + pub fn delete(&self, input: DeleteArticleUsecaseInput) -> Result { self.article_repository .delete(DeleteArticleRepositoryInput { slug: input.slug, @@ -77,6 +78,26 @@ impl ArticleUsecase { let res = self.article_presenter.toHttpRes(); Ok(res) } + + pub fn update(&self, input: UpdateArticleUsecaseInput) -> Result { + let article_slug = &input + .title + .as_ref() + .map(|_title| Article::convert_title_to_slug(_title)); + let slug = article_slug.to_owned(); + let result = self + .article_repository + .update(UpdateArticleRepositoryInput { + current_user: input.current_user, + article_title_slug: input.article_title_slug, + slug, + title: input.title, + description: input.description, + body: input.body, + })?; + let res = self.article_presenter.from_item(result); + Ok(res) + } } pub struct CreateArticleUsecaseInput { @@ -87,7 +108,15 @@ pub struct CreateArticleUsecaseInput { pub current_user: User, } -pub struct DeleteArticleUsercaseInput { +pub struct DeleteArticleUsecaseInput { pub slug: String, pub author_id: Uuid, } + +pub struct UpdateArticleUsecaseInput { + pub current_user: User, + pub article_title_slug: String, + pub title: Option, + pub description: Option, + pub body: Option, +} From ef305530b7744cd14290852ae06933e8a9a63e86 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 10:44:07 +0900 Subject: [PATCH 34/59] refactor: remove create-tag-list on services --- src/appv2/features/article/repositories.rs | 25 +++++++-- src/appv2/features/article/services.rs | 60 ---------------------- 2 files changed, 22 insertions(+), 63 deletions(-) diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index d9def47..fec4226 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -1,15 +1,15 @@ +use diesel::PgConnection; use uuid::Uuid; use super::entities::{Article, CreateArticle, DeleteArticle, UpdateArticle}; use super::services::{self, FetchArticlesListResult}; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::Tag; +use crate::appv2::features::tag::entities::{CreateTag, Tag}; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; -type ArticleCount = i64; #[derive(Clone)] pub struct ArticleRepository { pool: DbPool, @@ -62,7 +62,8 @@ impl ArticleRepository { body: params.body.clone(), }, )?; - let tag_list = services::create_tag_list(conn, ¶ms.tag_name_list, &article.id)?; + + let tag_list = Self::create_tag_list(conn, ¶ms.tag_name_list, &article.id)?; let profile = params .current_user @@ -124,6 +125,24 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tag_list)) } + + fn create_tag_list( + conn: &mut PgConnection, + tag_name_list: &Option>, + article_id: &Uuid, + ) -> Result, AppError> { + let list = tag_name_list + .as_ref() + .map(|tag_name_list| { + let records = tag_name_list + .iter() + .map(|name| CreateTag { name, article_id }) + .collect(); + Tag::create_list(conn, records) + }) + .unwrap_or_else(|| Ok(vec![])); + list + } } pub struct CreateArticleRepositoryInput { diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index 4b1f9a7..490dc93 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -11,24 +11,6 @@ use diesel::pg::PgConnection; use diesel::prelude::*; use uuid::Uuid; -pub fn create_tag_list( - conn: &mut PgConnection, - tag_name_list: &Option>, - article_id: &Uuid, -) -> Result, AppError> { - let list = tag_name_list - .as_ref() - .map(|tag_name_list| { - let records = tag_name_list - .iter() - .map(|name| CreateTag { name, article_id }) - .collect(); - Tag::create_list(conn, records) - }) - .unwrap_or_else(|| Ok(vec![])); - list -} - pub struct FetchArticlesList { pub tag: Option, pub author: Option, @@ -308,45 +290,3 @@ pub fn fetch_following_articles( Ok((articles_list, articles_count)) } - -// pub struct UpdateArticleService { -// pub current_user: User, -// pub article_title_slug: String, -// pub slug: Option, -// pub title: Option, -// pub description: Option, -// pub body: Option, -// } -// pub fn update_article( -// conn: &mut PgConnection, -// params: &UpdateArticleService, -// ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { -// // let article = Article::update( -// // conn, -// // ¶ms.article_title_slug, -// // ¶ms.current_user.id, -// // &UpdateArticle { -// // slug: params.slug.to_owned(), -// // title: params.title.to_owned(), -// // description: params.description.to_owned(), -// // body: params.body.to_owned(), -// // }, -// // )?; - -// // let tag_list = Tag::fetch_by_article_id(conn, &article.id)?; - -// // let profile = params -// // .current_user -// // .fetch_profile(conn, &article.author_id)?; - -// // let favorite_info = { -// // let is_favorited = article.is_favorited_by_user_id(conn, ¶ms.current_user.id)?; -// // let favorites_count = article.fetch_favorites_count(conn)?; -// // FavoriteInfo { -// // is_favorited, -// // favorites_count, -// // } -// // }; - -// // Ok((article, profile, favorite_info, tag_list)) -// } From ac559e07f67633248be42590a8c609a68f746235 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 10:51:17 +0900 Subject: [PATCH 35/59] refactor: remove fetch-articles-by-slug on service --- src/appv2/features/article/controllers.rs | 2 +- src/appv2/features/article/repositories.rs | 25 +++++++++++++++++++-- src/appv2/features/article/services.rs | 26 ---------------------- src/appv2/features/article/usecases.rs | 4 ++-- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index 48b9516..cfc9280 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -72,7 +72,7 @@ pub async fn show(state: web::Data, path: web::Path) state .di_container .article_usecase - .fetch_article_by_slug(&services::FetchArticleBySlug { article_title_slug }) + .fetch_article_by_slug(article_title_slug) } pub async fn create( diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index fec4226..609b08f 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -41,9 +41,28 @@ impl ArticleRepository { pub fn fetch_article_by_slug( &self, article_title_slug: String, - ) -> Result { + ) -> Result { let conn = &mut self.pool.get()?; - services::fetch_article_by_slug(conn, &services::FetchArticleBySlug { article_title_slug }) + + let (article, author) = Article::fetch_by_slug_with_author(conn, &article_title_slug)?; + + let profile = author.fetch_profile(conn, &author.id)?; + + let tags_list = { + use diesel::prelude::*; + Tag::belonging_to(&article).load::(conn)? + }; + + let favorite_info = { + let is_favorited = article.is_favorited_by_user_id(conn, &author.id)?; + let favorites_count = article.fetch_favorites_count(conn)?; + FavoriteInfo { + is_favorited, + favorites_count, + } + }; + + Ok((article, profile, favorite_info, tags_list)) } pub fn create( @@ -167,3 +186,5 @@ pub struct UpdateArticleRepositoryInput { pub description: Option, pub body: Option, } + +pub type FetchArticleBySlugOutput = (Article, Profile, FavoriteInfo, Vec); diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index 490dc93..aa0a34a 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -165,32 +165,6 @@ pub fn fetch_article( Ok((article, profile, favorite_info, tags_list)) } -pub type FetchArticleBySlugResult = (Article, Profile, FavoriteInfo, Vec); -pub struct FetchArticleBySlug { - pub article_title_slug: String, -} -pub fn fetch_article_by_slug( - conn: &mut PgConnection, - params: &FetchArticleBySlug, -) -> Result { - let (article, author) = Article::fetch_by_slug_with_author(conn, ¶ms.article_title_slug)?; - - let profile = author.fetch_profile(conn, &author.id)?; - - let tags_list = Tag::belonging_to(&article).load::(conn)?; - - let favorite_info = { - let is_favorited = article.is_favorited_by_user_id(conn, &author.id)?; - let favorites_count = article.fetch_favorites_count(conn)?; - FavoriteInfo { - is_favorited, - favorites_count, - } - }; - - Ok((article, profile, favorite_info, tags_list)) -} - use crate::schema::follows; pub struct FetchFollowedArticlesSerivce { pub current_user: User, diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index c90e1ca..82cb138 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -43,9 +43,9 @@ impl ArticleUsecase { pub fn fetch_article_by_slug( &self, - params: &services::FetchArticleBySlug, + article_title_slug: String, ) -> Result { - let article_title_slug = params.article_title_slug.clone(); + let article_title_slug = article_title_slug.clone(); let result = self .article_repository .fetch_article_by_slug(article_title_slug)?; From b546752f33c7afd6e4bc0484d45ecb441900315d Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 10:54:52 +0900 Subject: [PATCH 36/59] refactor: remove fetch-article on service --- src/appv2/features/article/repositories.rs | 30 +++++++++++++++++++ src/appv2/features/article/services.rs | 34 ++-------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 609b08f..47bf0cd 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -162,6 +162,31 @@ impl ArticleRepository { .unwrap_or_else(|| Ok(vec![])); list } + + pub fn fetch_article( + conn: &mut PgConnection, + input: &FetchArticleInput, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + let (article, author) = Article::find_with_author(conn, &input.article_id)?; + + let profile = input.current_user.fetch_profile(conn, &author.id)?; + + let favorite_info = { + let is_favorited = article.is_favorited_by_user_id(conn, &input.current_user.id)?; + let favorites_count = article.fetch_favorites_count(conn)?; + FavoriteInfo { + is_favorited, + favorites_count, + } + }; + + let tags_list = { + use diesel::prelude::*; + Tag::belonging_to(&article).load::(conn)? + }; + + Ok((article, profile, favorite_info, tags_list)) + } } pub struct CreateArticleRepositoryInput { @@ -188,3 +213,8 @@ pub struct UpdateArticleRepositoryInput { } pub type FetchArticleBySlugOutput = (Article, Profile, FavoriteInfo, Vec); + +pub struct FetchArticleInput { + pub article_id: Uuid, + pub current_user: User, +} diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index aa0a34a..d42ee41 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -1,15 +1,14 @@ -use crate::appv2::features::article::entities::{Article, UpdateArticle}; +use crate::appv2::features::article::entities::Article; use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::{CreateTag, Tag}; +use crate::appv2::features::tag::entities::Tag; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::schema::articles::dsl::*; use crate::schema::{articles, tags, users}; use diesel::pg::PgConnection; use diesel::prelude::*; -use uuid::Uuid; pub struct FetchArticlesList { pub tag: Option, @@ -136,35 +135,6 @@ pub fn fetch_articles_list( Ok((result, articles_count)) } -pub struct FetchArticle { - pub article_id: Uuid, - pub current_user: User, -} -pub fn fetch_article( - conn: &mut PgConnection, - FetchArticle { - article_id, - current_user, - }: &FetchArticle, -) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { - let (article, author) = Article::find_with_author(conn, article_id)?; - - let profile = current_user.fetch_profile(conn, &author.id)?; - - let favorite_info = { - let is_favorited = article.is_favorited_by_user_id(conn, ¤t_user.id)?; - let favorites_count = article.fetch_favorites_count(conn)?; - FavoriteInfo { - is_favorited, - favorites_count, - } - }; - - let tags_list = Tag::belonging_to(&article).load::(conn)?; - - Ok((article, profile, favorite_info, tags_list)) -} - use crate::schema::follows; pub struct FetchFollowedArticlesSerivce { pub current_user: User, From 2d3163b56f7ed3d724a0f9bb19fda459a76961a3 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 12:32:57 +0900 Subject: [PATCH 37/59] refactor: remove services --- src/appv2/features/article/repositories.rs | 9 +-- src/appv2/features/favorite/mod.rs | 1 - src/appv2/features/favorite/repositories.rs | 55 ++++++++------- src/appv2/features/favorite/services.rs | 78 --------------------- src/appv2/features/favorite/usecases.rs | 29 ++++++-- src/utils/di.rs | 37 +++++----- 6 files changed, 78 insertions(+), 131 deletions(-) delete mode 100644 src/appv2/features/favorite/services.rs diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 47bf0cd..510c353 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -163,10 +163,11 @@ impl ArticleRepository { list } - pub fn fetch_article( - conn: &mut PgConnection, - input: &FetchArticleInput, + pub fn fetch_article_item( + &self, + input: &FetchArticleRepositoryInput, ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + let conn = &mut self.pool.get()?; let (article, author) = Article::find_with_author(conn, &input.article_id)?; let profile = input.current_user.fetch_profile(conn, &author.id)?; @@ -214,7 +215,7 @@ pub struct UpdateArticleRepositoryInput { pub type FetchArticleBySlugOutput = (Article, Profile, FavoriteInfo, Vec); -pub struct FetchArticleInput { +pub struct FetchArticleRepositoryInput { pub article_id: Uuid, pub current_user: User, } diff --git a/src/appv2/features/favorite/mod.rs b/src/appv2/features/favorite/mod.rs index 923a07e..9c2709f 100644 --- a/src/appv2/features/favorite/mod.rs +++ b/src/appv2/features/favorite/mod.rs @@ -2,5 +2,4 @@ pub mod controllers; pub mod entities; pub mod presenters; pub mod repositories; -pub mod services; pub mod usecases; diff --git a/src/appv2/features/favorite/repositories.rs b/src/appv2/features/favorite/repositories.rs index be74a72..2935f94 100644 --- a/src/appv2/features/favorite/repositories.rs +++ b/src/appv2/features/favorite/repositories.rs @@ -1,8 +1,5 @@ -use super::entities::FavoriteInfo; -use super::services; -use crate::appv2::features::article::entities::Article; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::Tag; +use super::entities::{CreateFavorite, DeleteFavorite, Favorite}; +use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; @@ -17,35 +14,43 @@ impl FavoriteRepository { Self { pool } } - pub fn favorite( - &self, - user: User, - article_title_slug: String, - ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + pub fn favorite(&self, user: User, article_title_slug: String) -> Result { let conn = &mut self.pool.get()?; - let (article, profile, favorite_info, tags_list) = services::favorite( + + let article = Article::fetch_by_slug_and_author_id( + conn, + &FetchBySlugAndAuthorId { + slug: article_title_slug.to_owned(), + author_id: user.id, + }, + )?; + Favorite::create( conn, - &services::FavoriteService { - current_user: user, - article_title_slug, + &CreateFavorite { + user_id: user.id, + article_id: article.id, }, )?; - Ok((article, profile, favorite_info, tags_list)) + + Ok(article) } - pub fn unfavorite( - &self, - user: User, - article_title_slug: String, - ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { + pub fn unfavorite(&self, user: User, article_title_slug: String) -> Result { let conn = &mut self.pool.get()?; - let (article, profile, favorite_info, tags_list) = services::unfavorite( + let article = Article::fetch_by_slug_and_author_id( + conn, + &FetchBySlugAndAuthorId { + slug: article_title_slug.to_owned(), + author_id: user.id, + }, + )?; + Favorite::delete( conn, - &services::UnfavoriteService { - current_user: user, - article_title_slug, + &DeleteFavorite { + user_id: user.id, + article_id: article.id, }, )?; - Ok((article, profile, favorite_info, tags_list)) + Ok(article) } } diff --git a/src/appv2/features/favorite/services.rs b/src/appv2/features/favorite/services.rs deleted file mode 100644 index b74d2e8..0000000 --- a/src/appv2/features/favorite/services.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; -use crate::appv2::features::article::services::{fetch_article, FetchArticle}; -use crate::appv2::features::favorite::entities::{ - CreateFavorite, DeleteFavorite, Favorite, FavoriteInfo, -}; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::Tag; -use crate::appv2::features::user::entities::User; -use crate::error::AppError; -use diesel::pg::PgConnection; - -pub struct FavoriteService { - pub current_user: User, - pub article_title_slug: String, -} - -#[deprecated(note = "use repository instead")] -pub fn favorite( - conn: &mut PgConnection, - params: &FavoriteService, -) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { - let article = Article::fetch_by_slug_and_author_id( - conn, - &FetchBySlugAndAuthorId { - slug: params.article_title_slug.to_owned(), - author_id: params.current_user.id, - }, - )?; - Favorite::create( - conn, - &CreateFavorite { - user_id: params.current_user.id, - article_id: article.id, - }, - )?; - let item = fetch_article( - conn, - &FetchArticle { - article_id: article.id, - current_user: params.current_user.to_owned(), - }, - )?; - Ok(item) -} - -pub struct UnfavoriteService { - pub current_user: User, - pub article_title_slug: String, -} - -#[deprecated(note = "use repository instead")] -pub fn unfavorite( - conn: &mut PgConnection, - params: &UnfavoriteService, -) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { - let article = Article::fetch_by_slug_and_author_id( - conn, - &FetchBySlugAndAuthorId { - slug: params.article_title_slug.to_owned(), - author_id: params.current_user.id, - }, - )?; - Favorite::delete( - conn, - &DeleteFavorite { - user_id: params.current_user.id, - article_id: article.id, - }, - )?; - let item = fetch_article( - conn, - &FetchArticle { - article_id: article.id, - current_user: params.current_user.to_owned(), - }, - )?; - Ok(item) -} diff --git a/src/appv2/features/favorite/usecases.rs b/src/appv2/features/favorite/usecases.rs index eed5b69..008358e 100644 --- a/src/appv2/features/favorite/usecases.rs +++ b/src/appv2/features/favorite/usecases.rs @@ -1,6 +1,9 @@ // use super::entities::{UpdateUser, User}; use super::presenters::FavoritePresenter; use super::repositories::FavoriteRepository; +use crate::appv2::features::article::repositories::{ + ArticleRepository, FetchArticleRepositoryInput, +}; use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; @@ -10,16 +13,19 @@ use uuid::Uuid; pub struct FavoriteUsecase { favorite_repository: FavoriteRepository, favorite_presenter: FavoritePresenter, + article_repository: ArticleRepository, } impl FavoriteUsecase { pub fn new( favorite_repository: FavoriteRepository, favorite_presenter: FavoritePresenter, + article_repository: ArticleRepository, ) -> Self { Self { favorite_repository, favorite_presenter, + article_repository, } } @@ -28,9 +34,16 @@ impl FavoriteUsecase { user: User, article_title_slug: String, ) -> Result { - let result = self + let article = self .favorite_repository - .favorite(user, article_title_slug)?; + .favorite(user.clone(), article_title_slug)?; + + let result = self + .article_repository + .fetch_article_item(&FetchArticleRepositoryInput { + article_id: article.id, + current_user: user, + })?; let res = self.favorite_presenter.complete(result); Ok(res) } @@ -40,9 +53,17 @@ impl FavoriteUsecase { user: User, article_title_slug: String, ) -> Result { - let result = self + let article = self .favorite_repository - .unfavorite(user, article_title_slug)?; + .unfavorite(user.clone(), article_title_slug)?; + + let result = self + .article_repository + .fetch_article_item(&FetchArticleRepositoryInput { + article_id: article.id, + current_user: user, + })?; + let res = self.favorite_presenter.complete(result); Ok(res) } diff --git a/src/utils/di.rs b/src/utils/di.rs index 2cd2991..08d0abf 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -56,34 +56,33 @@ pub struct DiContainer { impl DiContainer { pub fn new(pool: &DbPool) -> Self { - // User + // Repository let user_repository = UserRepository::new(pool.clone()); - let user_presenter = UserPresenter::new(); - let user_usecase = UserUsecase::new(user_repository.clone(), user_presenter.clone()); - - // Profile let profile_repository = ProfileRepository::new(pool.clone()); + let favorite_repository = FavoriteRepository::new(pool.clone()); + let article_repository = ArticleRepository::new(pool.clone()); + let tag_repository = TagRepository::new(pool.clone()); + + // Presenter + let user_presenter = UserPresenter::new(); let profile_presenter = ProfilePresenter::new(); + let favorite_presenter = FavoritePresenter::new(); + let article_presenter = ArticlePresenter::new(); + let tag_presenter = TagPresenter::new(); + + // Usecase + let user_usecase = UserUsecase::new(user_repository.clone(), user_presenter.clone()); let profile_usecase = ProfileUsecase::new( (profile_repository.clone(), user_repository.clone()), profile_presenter.clone(), ); - - // Favorite - let favorite_repository = FavoriteRepository::new(pool.clone()); - let favorite_presenter = FavoritePresenter::new(); - let favorite_usecase = - FavoriteUsecase::new(favorite_repository.clone(), favorite_presenter.clone()); - - // Article - let article_repository = ArticleRepository::new(pool.clone()); - let article_presenter = ArticlePresenter::new(); + let favorite_usecase = FavoriteUsecase::new( + favorite_repository.clone(), + favorite_presenter.clone(), + article_repository.clone(), + ); let article_usecase = ArticleUsecase::new(article_repository.clone(), article_presenter.clone()); - - // Tag - let tag_repository = TagRepository::new(pool.clone()); - let tag_presenter = TagPresenter::new(); let tag_usecase = TagUsecase::new(tag_repository.clone(), tag_presenter.clone()); Self { From b407a03b92df86f64145e22856b7b4b34714da6e Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 12:48:36 +0900 Subject: [PATCH 38/59] refactor: move service fn to repo --- src/appv2/features/article/controllers.rs | 17 +-- src/appv2/features/article/repositories.rs | 120 +++++++++++++++++++++ src/appv2/features/article/services.rs | 98 ----------------- src/appv2/features/article/usecases.rs | 19 +++- 4 files changed, 143 insertions(+), 111 deletions(-) diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index cfc9280..ac03bc9 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -1,6 +1,7 @@ use super::{ entities::{Article, DeleteArticle}, presenters::{MultipleArticlesResponse, SingleArticleResponse}, + repositories::FetchFollowingArticlesRepositoryInput, requests, services, usecases::{CreateArticleUsecaseInput, DeleteArticleUsecaseInput, UpdateArticleUsecaseInput}, }; @@ -50,21 +51,13 @@ pub async fn feed( req: HttpRequest, params: web::Query, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let offset = std::cmp::min(params.offset.to_owned().unwrap_or(0), 100); let limit = params.limit.unwrap_or(20); - let (articles_list, articles_count) = services::fetch_following_articles( - conn, - &services::FetchFollowedArticlesSerivce { - current_user, - offset, - limit, - }, - )?; - - let res = MultipleArticlesResponse::from((articles_list, articles_count)); - Ok(HttpResponse::Ok().json(res)) + state + .di_container + .article_usecase + .fetch_following_articles(current_user, offset, limit) } pub async fn show(state: web::Data, path: web::Path) -> ApiResponse { diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 510c353..584dbbc 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -4,6 +4,7 @@ use uuid::Uuid; use super::entities::{Article, CreateArticle, DeleteArticle, UpdateArticle}; use super::services::{self, FetchArticlesListResult}; use crate::appv2::features::favorite::entities::FavoriteInfo; +use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::{CreateTag, Tag}; use crate::appv2::features::user::entities::User; @@ -188,6 +189,115 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tags_list)) } + + pub fn fetch_following_articles( + &self, + params: &FetchFollowingArticlesRepositoryInput, + ) -> Result<(ArticlesList, ArticlesCount), AppError> { + use crate::appv2::features::article::entities::Article; + use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; + use crate::appv2::features::follow::entities::Follow; + use crate::appv2::features::profile::entities::Profile; + use crate::appv2::features::tag::entities::Tag; + use crate::appv2::features::user::entities::User; + use crate::error::AppError; + use crate::schema::articles::dsl::*; + use crate::schema::follows; + use crate::schema::{articles, tags, users}; + use diesel::pg::PgConnection; + use diesel::prelude::*; + // == + let conn = &mut self.pool.get()?; + + let create_query = { + let ids = Follow::fetch_folowee_ids_by_follower_id(conn, ¶ms.current_user.id)?; + articles.filter(articles::author_id.eq_any(ids)) + }; + + let articles_list = { + let article_and_user_list = create_query + .to_owned() + .inner_join(users::table) + .limit(params.limit) + .offset(params.offset) + .order(articles::created_at.desc()) + .get_results::<(Article, User)>(conn)?; + + let tags_list = { + let articles_list = article_and_user_list + .clone() // TODO: avoid clone + .into_iter() + .map(|(article, _)| article) + .collect::>(); + + let tags_list = Tag::belonging_to(&articles_list).load::(conn)?; + let tags_list: Vec> = tags_list.grouped_by(&articles_list); + tags_list + }; + + let follows_list = { + let user_ids_list = article_and_user_list + .clone() // TODO: avoid clone + .into_iter() + .map(|(_, user)| user.id) + .collect::>(); + + let list = follows::table + .filter(Follow::with_follower(¶ms.current_user.id)) + .filter(follows::followee_id.eq_any(user_ids_list)) + .get_results::(conn)?; + + list.into_iter() + }; + + let favorites_count_list = { + let list: Result, _> = article_and_user_list + .clone() + .into_iter() + .map(|(article, _)| article.fetch_favorites_count(conn)) + .collect(); + + list? + }; + + let favorited_article_ids = params.current_user.fetch_favorited_article_ids(conn)?; + let is_favorited_by_me = |article: &Article| { + favorited_article_ids + .iter() + .copied() + .any(|_id| _id == article.id) + }; + + article_and_user_list + .into_iter() + .zip(favorites_count_list) + .map(|((article, user), favorites_count)| { + let following = follows_list.clone().any(|item| item.followee_id == user.id); + let is_favorited = is_favorited_by_me(&article); + ( + article, + Profile { + username: user.username, + bio: user.bio, + image: user.image, + following: following.to_owned(), + }, + FavoriteInfo { + is_favorited, + favorites_count, + }, + ) + }) + .zip(tags_list) + .collect::>() + }; + + let articles_count = create_query + .select(diesel::dsl::count(articles::id)) + .first::(conn)?; + + Ok((articles_list, articles_count)) + } } pub struct CreateArticleRepositoryInput { @@ -219,3 +329,13 @@ pub struct FetchArticleRepositoryInput { pub article_id: Uuid, pub current_user: User, } + +pub struct FetchFollowingArticlesRepositoryInput { + pub current_user: User, + pub offset: i64, + pub limit: i64, +} + +type ArticlesCount = i64; +type ArticlesListInner = (Article, Profile, FavoriteInfo); +pub type ArticlesList = Vec<(ArticlesListInner, Vec)>; diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs index d42ee41..71146f8 100644 --- a/src/appv2/features/article/services.rs +++ b/src/appv2/features/article/services.rs @@ -136,101 +136,3 @@ pub fn fetch_articles_list( } use crate::schema::follows; -pub struct FetchFollowedArticlesSerivce { - pub current_user: User, - pub offset: i64, - pub limit: i64, -} -pub fn fetch_following_articles( - conn: &mut PgConnection, - params: &FetchFollowedArticlesSerivce, -) -> Result<(ArticlesList, ArticlesCount), AppError> { - let create_query = { - let ids = Follow::fetch_folowee_ids_by_follower_id(conn, ¶ms.current_user.id)?; - articles.filter(articles::author_id.eq_any(ids)) - }; - - let articles_list = { - let article_and_user_list = create_query - .to_owned() - .inner_join(users::table) - .limit(params.limit) - .offset(params.offset) - .order(articles::created_at.desc()) - .get_results::<(Article, User)>(conn)?; - - let tags_list = { - let articles_list = article_and_user_list - .clone() // TODO: avoid clone - .into_iter() - .map(|(article, _)| article) - .collect::>(); - - let tags_list = Tag::belonging_to(&articles_list).load::(conn)?; - let tags_list: Vec> = tags_list.grouped_by(&articles_list); - tags_list - }; - - let follows_list = { - let user_ids_list = article_and_user_list - .clone() // TODO: avoid clone - .into_iter() - .map(|(_, user)| user.id) - .collect::>(); - - let list = follows::table - .filter(Follow::with_follower(¶ms.current_user.id)) - .filter(follows::followee_id.eq_any(user_ids_list)) - .get_results::(conn)?; - - list.into_iter() - }; - - let favorites_count_list = { - let list: Result, _> = article_and_user_list - .clone() - .into_iter() - .map(|(article, _)| article.fetch_favorites_count(conn)) - .collect(); - - list? - }; - - let favorited_article_ids = params.current_user.fetch_favorited_article_ids(conn)?; - let is_favorited_by_me = |article: &Article| { - favorited_article_ids - .iter() - .copied() - .any(|_id| _id == article.id) - }; - - article_and_user_list - .into_iter() - .zip(favorites_count_list) - .map(|((article, user), favorites_count)| { - let following = follows_list.clone().any(|item| item.followee_id == user.id); - let is_favorited = is_favorited_by_me(&article); - ( - article, - Profile { - username: user.username, - bio: user.bio, - image: user.image, - following: following.to_owned(), - }, - FavoriteInfo { - is_favorited, - favorites_count, - }, - ) - }) - .zip(tags_list) - .collect::>() - }; - - let articles_count = create_query - .select(diesel::dsl::count(articles::id)) - .first::(conn)?; - - Ok((articles_list, articles_count)) -} diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 82cb138..1c52e23 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -2,7 +2,7 @@ use super::entities::Article; use super::presenters::ArticlePresenter; use super::repositories::{ ArticleRepository, CreateArticleRepositoryInput, DeleteArticleRepositoryInput, - UpdateArticleRepositoryInput, + FetchFollowingArticlesRepositoryInput, UpdateArticleRepositoryInput, }; use super::services; use crate::appv2::features::user::entities::User; @@ -53,6 +53,23 @@ impl ArticleUsecase { Ok(res) } + pub fn fetch_following_articles( + &self, + user: User, + offset: i64, + limit: i64, + ) -> Result { + let (list, count) = self.article_repository.fetch_following_articles( + &FetchFollowingArticlesRepositoryInput { + current_user: user, + offset, + limit, + }, + )?; + let res = self.article_presenter.from_list_and_count(list, count); + Ok(res) + } + pub fn create(&self, params: CreateArticleUsecaseInput) -> Result { let slug = Article::convert_title_to_slug(¶ms.title); let result = self From 4bec1f476d0b90eb8b0f0606f71561461c6a5ecf Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 13:01:00 +0900 Subject: [PATCH 39/59] refactor: remove article service --- src/appv2/features/article/controllers.rs | 9 +- src/appv2/features/article/mod.rs | 1 - src/appv2/features/article/presenters.rs | 3 +- src/appv2/features/article/repositories.rs | 151 ++++++++++++++++++--- src/appv2/features/article/services.rs | 138 ------------------- src/appv2/features/article/usecases.rs | 16 ++- 6 files changed, 152 insertions(+), 166 deletions(-) delete mode 100644 src/appv2/features/article/services.rs diff --git a/src/appv2/features/article/controllers.rs b/src/appv2/features/article/controllers.rs index ac03bc9..edb9857 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/appv2/features/article/controllers.rs @@ -2,8 +2,11 @@ use super::{ entities::{Article, DeleteArticle}, presenters::{MultipleArticlesResponse, SingleArticleResponse}, repositories::FetchFollowingArticlesRepositoryInput, - requests, services, - usecases::{CreateArticleUsecaseInput, DeleteArticleUsecaseInput, UpdateArticleUsecaseInput}, + requests, + usecases::{ + CreateArticleUsecaseInput, DeleteArticleUsecaseInput, FetchArticlesListUsecaseInput, + UpdateArticleUsecaseInput, + }, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; @@ -31,7 +34,7 @@ pub async fn index( state .di_container .article_usecase - .fetch_articles_list(services::FetchArticlesList { + .fetch_articles_list(FetchArticlesListUsecaseInput { tag: params.tag.clone(), author: params.author.clone(), favorited: params.favorited.clone(), diff --git a/src/appv2/features/article/mod.rs b/src/appv2/features/article/mod.rs index 71c5a4d..7f85232 100644 --- a/src/appv2/features/article/mod.rs +++ b/src/appv2/features/article/mod.rs @@ -3,5 +3,4 @@ pub mod entities; pub mod presenters; pub mod repositories; pub mod requests; -pub mod services; pub mod usecases; diff --git a/src/appv2/features/article/presenters.rs b/src/appv2/features/article/presenters.rs index 92e6b12..cb568d2 100644 --- a/src/appv2/features/article/presenters.rs +++ b/src/appv2/features/article/presenters.rs @@ -1,5 +1,4 @@ -use super::entities::Article; -use super::services::ArticlesList; +use super::{entities::Article, repositories::ArticlesList}; use crate::appv2::features::favorite::entities::FavoriteInfo; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::Tag; diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 584dbbc..9efcc9d 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -1,15 +1,12 @@ -use diesel::PgConnection; -use uuid::Uuid; - use super::entities::{Article, CreateArticle, DeleteArticle, UpdateArticle}; -use super::services::{self, FetchArticlesListResult}; use crate::appv2::features::favorite::entities::FavoriteInfo; -use crate::appv2::features::follow::entities::Follow; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::{CreateTag, Tag}; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; +use diesel::PgConnection; +use uuid::Uuid; #[derive(Clone)] pub struct ArticleRepository { @@ -23,20 +20,128 @@ impl ArticleRepository { pub fn fetch_articles_list( &self, - params: services::FetchArticlesList, - ) -> Result { + params: FetchArticlesListRepositoryInput, + ) -> Result<(ArticlesList, ArticlesCount), AppError> { + use crate::appv2::features::article::entities::Article; + use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; + use crate::appv2::features::follow::entities::Follow; + use crate::appv2::features::profile::entities::Profile; + use crate::appv2::features::tag::entities::Tag; + use crate::appv2::features::user::entities::User; + use crate::error::AppError; + use crate::schema::articles::dsl::*; + use crate::schema::{articles, tags, users}; + use diesel::pg::PgConnection; + use diesel::prelude::*; + use diesel::prelude::*; + // ==== let conn = &mut self.pool.get()?; - let result = services::fetch_articles_list( - conn, - services::FetchArticlesList { - tag: params.tag.clone(), - author: params.author.clone(), - favorited: params.favorited.clone(), - offset: params.offset, - limit: params.limit, - }, - )?; - Ok(result) + + let query = { + let mut query = articles::table.inner_join(users::table).into_boxed(); + + if let Some(tag_name) = ¶ms.tag { + let ids = Tag::fetch_article_ids_by_name(conn, tag_name) + .expect("could not fetch tagged article ids."); // TODO: use ? or error handling + query = query.filter(articles::id.eq_any(ids)); + } + + if let Some(author_name) = ¶ms.author { + let ids = Article::fetch_ids_by_author_name(conn, author_name) + .expect("could not fetch authors id."); // TODO: use ? or error handling + query = query.filter(articles::id.eq_any(ids)); + } + + if let Some(username) = ¶ms.favorited { + let ids = Favorite::fetch_favorited_article_ids_by_username(conn, username) + .expect("could not fetch favorited articles id."); // TODO: use ? or error handling + + query = query.filter(articles::id.eq_any(ids)); + } + + query + }; + let articles_count = query + .select(diesel::dsl::count(articles::id)) + .first::(conn)?; + + let result = { + let query = { + let mut query = articles::table.inner_join(users::table).into_boxed(); + + if let Some(tag_name) = ¶ms.tag { + let ids = Tag::fetch_article_ids_by_name(conn, tag_name) + .expect("could not fetch tagged article ids."); // TODO: use ? or error handling + query = query.filter(articles::id.eq_any(ids)); + } + + if let Some(author_name) = ¶ms.author { + let ids = Article::fetch_ids_by_author_name(conn, author_name) + .expect("could not fetch authors id."); // TODO: use ? or error handling + query = query.filter(articles::id.eq_any(ids)); + } + + if let Some(username) = ¶ms.favorited { + let ids = Favorite::fetch_favorited_article_ids_by_username(conn, username) + .expect("could not fetch favorited articles id."); // TODO: use ? or error handling + + query = query.filter(articles::id.eq_any(ids)); + } + + query + }; + let article_and_user_list = + query + .offset(params.offset) + .limit(params.limit) + .load::<(Article, User)>(conn)?; + + let tags_list = { + let articles_list = article_and_user_list + .clone() + .into_iter() + .map(|(article, _)| article) + .collect::>(); + let tags_list = Tag::belonging_to(&articles_list) + .order(tags::name.asc()) + .load::(conn)?; + let tags_list: Vec> = tags_list.grouped_by(&articles_list); + tags_list + }; + + let favorites_count_list = { + let list: Result, _> = article_and_user_list + .clone() + .into_iter() + .map(|(article, _)| article.fetch_favorites_count(conn)) + .collect(); + + list? + }; + + article_and_user_list + .into_iter() + .zip(favorites_count_list) + .map(|((article, user), favorites_count)| { + ( + article, + Profile { + username: user.username, + bio: user.bio, + image: user.image, + following: false, // NOTE: because not authz + }, + FavoriteInfo { + is_favorited: false, // NOTE: because not authz + favorites_count, + }, + ) + }) + .zip(tags_list) + .collect::>() + }; + + Ok((result, articles_count)) } pub fn fetch_article_by_slug( @@ -325,11 +430,21 @@ pub struct UpdateArticleRepositoryInput { pub type FetchArticleBySlugOutput = (Article, Profile, FavoriteInfo, Vec); +pub struct FetchArticlesListRepositoryInput { + pub tag: Option, + pub author: Option, + pub favorited: Option, + pub offset: i64, + pub limit: i64, +} + pub struct FetchArticleRepositoryInput { pub article_id: Uuid, pub current_user: User, } +// pub struct FetchArticleRepositoryOutput(); + pub struct FetchFollowingArticlesRepositoryInput { pub current_user: User, pub offset: i64, diff --git a/src/appv2/features/article/services.rs b/src/appv2/features/article/services.rs deleted file mode 100644 index 71146f8..0000000 --- a/src/appv2/features/article/services.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::appv2::features::article::entities::Article; -use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; -use crate::appv2::features::follow::entities::Follow; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::Tag; -use crate::appv2::features::user::entities::User; -use crate::error::AppError; -use crate::schema::articles::dsl::*; -use crate::schema::{articles, tags, users}; -use diesel::pg::PgConnection; -use diesel::prelude::*; - -pub struct FetchArticlesList { - pub tag: Option, - pub author: Option, - pub favorited: Option, - pub offset: i64, - pub limit: i64, -} - -type ArticlesCount = i64; -type ArticlesListInner = (Article, Profile, FavoriteInfo); -pub type ArticlesList = Vec<(ArticlesListInner, Vec)>; -pub type FetchArticlesListResult = (ArticlesList, ArticlesCount); -pub fn fetch_articles_list( - conn: &mut PgConnection, - params: FetchArticlesList, -) -> Result { - use diesel::prelude::*; - - let query = { - let mut query = articles::table.inner_join(users::table).into_boxed(); - - if let Some(tag_name) = ¶ms.tag { - let ids = Tag::fetch_article_ids_by_name(conn, tag_name) - .expect("could not fetch tagged article ids."); // TODO: use ? or error handling - query = query.filter(articles::id.eq_any(ids)); - } - - if let Some(author_name) = ¶ms.author { - let ids = Article::fetch_ids_by_author_name(conn, author_name) - .expect("could not fetch authors id."); // TODO: use ? or error handling - query = query.filter(articles::id.eq_any(ids)); - } - - if let Some(username) = ¶ms.favorited { - let ids = Favorite::fetch_favorited_article_ids_by_username(conn, username) - .expect("could not fetch favorited articles id."); // TODO: use ? or error handling - - query = query.filter(articles::id.eq_any(ids)); - } - - query - }; - let articles_count = query - .select(diesel::dsl::count(articles::id)) - .first::(conn)?; - - let result = { - let query = { - let mut query = articles::table.inner_join(users::table).into_boxed(); - - if let Some(tag_name) = ¶ms.tag { - let ids = Tag::fetch_article_ids_by_name(conn, tag_name) - .expect("could not fetch tagged article ids."); // TODO: use ? or error handling - query = query.filter(articles::id.eq_any(ids)); - } - - if let Some(author_name) = ¶ms.author { - let ids = Article::fetch_ids_by_author_name(conn, author_name) - .expect("could not fetch authors id."); // TODO: use ? or error handling - query = query.filter(articles::id.eq_any(ids)); - } - - if let Some(username) = ¶ms.favorited { - let ids = Favorite::fetch_favorited_article_ids_by_username(conn, username) - .expect("could not fetch favorited articles id."); // TODO: use ? or error handling - - query = query.filter(articles::id.eq_any(ids)); - } - - query - }; - let article_and_user_list = - query - .offset(params.offset) - .limit(params.limit) - .load::<(Article, User)>(conn)?; - - let tags_list = { - let articles_list = article_and_user_list - .clone() - .into_iter() - .map(|(article, _)| article) - .collect::>(); - let tags_list = Tag::belonging_to(&articles_list) - .order(tags::name.asc()) - .load::(conn)?; - let tags_list: Vec> = tags_list.grouped_by(&articles_list); - tags_list - }; - - let favorites_count_list = { - let list: Result, _> = article_and_user_list - .clone() - .into_iter() - .map(|(article, _)| article.fetch_favorites_count(conn)) - .collect(); - - list? - }; - - article_and_user_list - .into_iter() - .zip(favorites_count_list) - .map(|((article, user), favorites_count)| { - ( - article, - Profile { - username: user.username, - bio: user.bio, - image: user.image, - following: false, // NOTE: because not authz - }, - FavoriteInfo { - is_favorited: false, // NOTE: because not authz - favorites_count, - }, - ) - }) - .zip(tags_list) - .collect::>() - }; - - Ok((result, articles_count)) -} - -use crate::schema::follows; diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 1c52e23..6c22bf0 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -2,9 +2,9 @@ use super::entities::Article; use super::presenters::ArticlePresenter; use super::repositories::{ ArticleRepository, CreateArticleRepositoryInput, DeleteArticleRepositoryInput, - FetchFollowingArticlesRepositoryInput, UpdateArticleRepositoryInput, + FetchArticlesListRepositoryInput, FetchFollowingArticlesRepositoryInput, + UpdateArticleRepositoryInput, }; -use super::services; use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; @@ -26,11 +26,11 @@ impl ArticleUsecase { pub fn fetch_articles_list( &self, - params: services::FetchArticlesList, + params: FetchArticlesListUsecaseInput, ) -> Result { let (list, count) = self.article_repository - .fetch_articles_list(services::FetchArticlesList { + .fetch_articles_list(FetchArticlesListRepositoryInput { tag: params.tag.clone(), author: params.author.clone(), favorited: params.favorited.clone(), @@ -137,3 +137,11 @@ pub struct UpdateArticleUsecaseInput { pub description: Option, pub body: Option, } + +pub struct FetchArticlesListUsecaseInput { + pub tag: Option, + pub author: Option, + pub favorited: Option, + pub offset: i64, + pub limit: i64, +} From 9c4880f05b5bc5c155beb3c4a55da3bed3a83066 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 13:05:27 +0900 Subject: [PATCH 40/59] refactor: move comment to clean-arch --- src/app/comment/mod.rs | 5 ----- src/app/mod.rs | 1 - src/appv2/drivers/routes.rs | 16 ++++++++++++---- .../features/comment/controllers.rs} | 5 ++--- .../features/comment/entities.rs} | 0 src/appv2/features/comment/mod.rs | 5 +++++ .../features/comment/presenters.rs} | 2 +- src/{app => appv2/features}/comment/request.rs | 0 src/{app => appv2/features}/comment/service.rs | 2 +- src/appv2/features/mod.rs | 1 + src/main.rs | 1 - 11 files changed, 22 insertions(+), 16 deletions(-) delete mode 100644 src/app/comment/mod.rs delete mode 100644 src/app/mod.rs rename src/{app/comment/api.rs => appv2/features/comment/controllers.rs} (95%) rename src/{app/comment/model.rs => appv2/features/comment/entities.rs} (100%) create mode 100644 src/appv2/features/comment/mod.rs rename src/{app/comment/response.rs => appv2/features/comment/presenters.rs} (97%) rename src/{app => appv2/features}/comment/request.rs (100%) rename src/{app => appv2/features}/comment/service.rs (97%) diff --git a/src/app/comment/mod.rs b/src/app/comment/mod.rs deleted file mode 100644 index c4c0061..0000000 --- a/src/app/comment/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod api; -pub mod model; -pub mod request; -pub mod response; -pub mod service; diff --git a/src/app/mod.rs b/src/app/mod.rs deleted file mode 100644 index 2e9f320..0000000 --- a/src/app/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod comment; diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs index 1f405b1..fd67cab 100644 --- a/src/appv2/drivers/routes.rs +++ b/src/appv2/drivers/routes.rs @@ -1,4 +1,3 @@ -use crate::app; use crate::appv2; use actix_web::web; use actix_web::web::{delete, get, post, put}; @@ -71,9 +70,18 @@ pub fn api(cfg: &mut web::ServiceConfig) { ) .service( web::scope("/comments") - .route("", get().to(app::comment::api::index)) - .route("", post().to(app::comment::api::create)) - .route("/{comment_id}", delete().to(app::comment::api::delete)), + .route( + "", + get().to(appv2::features::comment::controllers::index), + ) + .route( + "", + post().to(appv2::features::comment::controllers::create), + ) + .route( + "/{comment_id}", + delete().to(appv2::features::comment::controllers::delete), + ), ), ), ), diff --git a/src/app/comment/api.rs b/src/appv2/features/comment/controllers.rs similarity index 95% rename from src/app/comment/api.rs rename to src/appv2/features/comment/controllers.rs index 967ce8d..ef84094 100644 --- a/src/app/comment/api.rs +++ b/src/appv2/features/comment/controllers.rs @@ -1,7 +1,6 @@ use super::{ - request, - response::{MultipleCommentsResponse, SingleCommentResponse}, - service, + presenters::{MultipleCommentsResponse, SingleCommentResponse}, + request, service, }; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; diff --git a/src/app/comment/model.rs b/src/appv2/features/comment/entities.rs similarity index 100% rename from src/app/comment/model.rs rename to src/appv2/features/comment/entities.rs diff --git a/src/appv2/features/comment/mod.rs b/src/appv2/features/comment/mod.rs new file mode 100644 index 0000000..07b1596 --- /dev/null +++ b/src/appv2/features/comment/mod.rs @@ -0,0 +1,5 @@ +pub mod controllers; +pub mod entities; +pub mod presenters; +pub mod request; +pub mod service; diff --git a/src/app/comment/response.rs b/src/appv2/features/comment/presenters.rs similarity index 97% rename from src/app/comment/response.rs rename to src/appv2/features/comment/presenters.rs index ec06c3d..5ba6b7c 100644 --- a/src/app/comment/response.rs +++ b/src/appv2/features/comment/presenters.rs @@ -1,4 +1,4 @@ -use crate::app::comment::model::Comment; +use crate::appv2::features::comment::entities::Comment; use crate::appv2::features::profile::entities::Profile; use crate::utils::date::Iso8601; use serde::{Deserialize, Serialize}; diff --git a/src/app/comment/request.rs b/src/appv2/features/comment/request.rs similarity index 100% rename from src/app/comment/request.rs rename to src/appv2/features/comment/request.rs diff --git a/src/app/comment/service.rs b/src/appv2/features/comment/service.rs similarity index 97% rename from src/app/comment/service.rs rename to src/appv2/features/comment/service.rs index f208a4e..1e7c505 100644 --- a/src/app/comment/service.rs +++ b/src/appv2/features/comment/service.rs @@ -1,4 +1,4 @@ -use super::model::{Comment, CreateComment, DeleteComment}; +use super::entities::{Comment, CreateComment, DeleteComment}; use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::profile::services::{conver_user_to_profile, ConverUserToProfile}; diff --git a/src/appv2/features/mod.rs b/src/appv2/features/mod.rs index e6d5264..4ef9b41 100644 --- a/src/appv2/features/mod.rs +++ b/src/appv2/features/mod.rs @@ -1,4 +1,5 @@ pub mod article; +pub mod comment; pub mod favorite; pub mod follow; pub mod healthcheck; diff --git a/src/main.rs b/src/main.rs index 21526cc..98dcf6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ extern crate log; use actix_web::middleware::Logger; use actix_web::{App, HttpServer}; -mod app; mod appv2; mod constants; mod error; From 202df62c512600692b0d17c16075689a453d0f39 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 13:16:38 +0900 Subject: [PATCH 41/59] refactor: move comment to clean-arch --- src/appv2/features/comment/mod.rs | 2 + src/appv2/features/comment/presenters.rs | 20 ++++++++++ src/appv2/features/comment/repositories.rs | 33 ++++++++++++++++ src/appv2/features/comment/usecases.rs | 44 ++++++++++++++++++++++ src/utils/di.rs | 19 ++++++++++ 5 files changed, 118 insertions(+) create mode 100644 src/appv2/features/comment/repositories.rs create mode 100644 src/appv2/features/comment/usecases.rs diff --git a/src/appv2/features/comment/mod.rs b/src/appv2/features/comment/mod.rs index 07b1596..8235325 100644 --- a/src/appv2/features/comment/mod.rs +++ b/src/appv2/features/comment/mod.rs @@ -1,5 +1,7 @@ pub mod controllers; pub mod entities; pub mod presenters; +pub mod repositories; pub mod request; pub mod service; +pub mod usecases; diff --git a/src/appv2/features/comment/presenters.rs b/src/appv2/features/comment/presenters.rs index 5ba6b7c..868b1f1 100644 --- a/src/appv2/features/comment/presenters.rs +++ b/src/appv2/features/comment/presenters.rs @@ -1,6 +1,7 @@ use crate::appv2::features::comment::entities::Comment; use crate::appv2::features::profile::entities::Profile; use crate::utils::date::Iso8601; +use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; use std::convert::From; use uuid::Uuid; @@ -76,3 +77,22 @@ pub struct InnerAuthor { pub image: Option, pub following: bool, } + +#[derive(Clone)] +pub struct CommentPresenter {} +impl CommentPresenter { + pub fn new() -> Self { + Self {} + } + + // pub fn complete( + // &self, + // (article, profile, favorite_info, tags_list): (Article, Profile, FavoriteInfo, Vec), + // ) -> HttpResponse { + // let res_model = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); + // HttpResponse::Ok().json(res_model) + // } + pub fn toHttpRes(&self) -> HttpResponse { + HttpResponse::Ok().json("OK") + } +} diff --git a/src/appv2/features/comment/repositories.rs b/src/appv2/features/comment/repositories.rs new file mode 100644 index 0000000..2b1546e --- /dev/null +++ b/src/appv2/features/comment/repositories.rs @@ -0,0 +1,33 @@ +use crate::utils::db::DbPool; + +#[derive(Clone)] +pub struct CommentRepository { + pool: DbPool, +} + +impl CommentRepository { + pub fn new(pool: DbPool) -> Self { + Self { pool } + } + + // pub fn favorite(&self, user: User, article_title_slug: String) -> Result { + // // let conn = &mut self.pool.get()?; + + // // let article = Article::fetch_by_slug_and_author_id( + // // conn, + // // &FetchBySlugAndAuthorId { + // // slug: article_title_slug.to_owned(), + // // author_id: user.id, + // // }, + // // )?; + // // Favorite::create( + // // conn, + // // &CreateFavorite { + // // user_id: user.id, + // // article_id: article.id, + // // }, + // // )?; + + // // Ok(article) + // } +} diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs new file mode 100644 index 0000000..eac8ca5 --- /dev/null +++ b/src/appv2/features/comment/usecases.rs @@ -0,0 +1,44 @@ +use crate::appv2::features::article::repositories::{ + ArticleRepository, FetchArticleRepositoryInput, +}; +use crate::appv2::features::user::entities::User; +use crate::error::AppError; +use actix_web::HttpResponse; +use uuid::Uuid; + +use super::presenters::CommentPresenter; +use super::repositories::CommentRepository; + +#[derive(Clone)] +pub struct CommentUsecase { + comment_repository: CommentRepository, + comment_presenter: CommentPresenter, +} + +impl CommentUsecase { + pub fn new(comment_repository: CommentRepository, comment_presenter: CommentPresenter) -> Self { + Self { + comment_repository, + comment_presenter, + } + } + + // pub fn favorite( + // &self, + // user: User, + // article_title_slug: String, + // ) -> Result { + // let article = self + // .favorite_repository + // .favorite(user.clone(), article_title_slug)?; + + // let result = self + // .article_repository + // .fetch_article_item(&FetchArticleRepositoryInput { + // article_id: article.id, + // current_user: user, + // })?; + // let res = self.favorite_presenter.complete(result); + // Ok(res) + // } +} diff --git a/src/utils/di.rs b/src/utils/di.rs index 08d0abf..96debfe 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,6 +1,9 @@ use crate::appv2::features::article::presenters::ArticlePresenter; use crate::appv2::features::article::repositories::ArticleRepository; use crate::appv2::features::article::usecases::ArticleUsecase; +use crate::appv2::features::comment::presenters::CommentPresenter; +use crate::appv2::features::comment::repositories::CommentRepository; +use crate::appv2::features::comment::usecases::CommentUsecase; use crate::appv2::features::favorite::{ presenters::FavoritePresenter, repositories::FavoriteRepository, usecases::FavoriteUsecase, }; @@ -52,6 +55,13 @@ pub struct DiContainer { pub tag_repository: TagRepository, pub tag_presenter: TagPresenter, pub tag_usecase: TagUsecase, + + /** + * Comment + */ + pub comment_repository: CommentRepository, + pub comment_presenter: CommentPresenter, + pub comment_usecase: CommentUsecase, } impl DiContainer { @@ -62,6 +72,7 @@ impl DiContainer { let favorite_repository = FavoriteRepository::new(pool.clone()); let article_repository = ArticleRepository::new(pool.clone()); let tag_repository = TagRepository::new(pool.clone()); + let comment_repository = CommentRepository::new(pool.clone()); // Presenter let user_presenter = UserPresenter::new(); @@ -69,6 +80,7 @@ impl DiContainer { let favorite_presenter = FavoritePresenter::new(); let article_presenter = ArticlePresenter::new(); let tag_presenter = TagPresenter::new(); + let comment_presenter = CommentPresenter::new(); // Usecase let user_usecase = UserUsecase::new(user_repository.clone(), user_presenter.clone()); @@ -84,6 +96,8 @@ impl DiContainer { let article_usecase = ArticleUsecase::new(article_repository.clone(), article_presenter.clone()); let tag_usecase = TagUsecase::new(tag_repository.clone(), tag_presenter.clone()); + let comment_usecase = + CommentUsecase::new(comment_repository.clone(), comment_presenter.clone()); Self { // User @@ -110,6 +124,11 @@ impl DiContainer { tag_repository, tag_presenter, tag_usecase, + + // Comment + comment_repository, + comment_presenter, + comment_usecase, } } } From fc6cc46ae6c5cd31fd804454087362bda7780b07 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 13:28:01 +0900 Subject: [PATCH 42/59] refactor: update comment delete feature --- src/appv2/features/comment/controllers.rs | 14 ++---- src/appv2/features/comment/repositories.rs | 35 ++++++++++++++- src/appv2/features/comment/service.rs | 52 +++++++++++----------- src/appv2/features/comment/usecases.rs | 11 +++++ 4 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/appv2/features/comment/controllers.rs b/src/appv2/features/comment/controllers.rs index ef84094..9c50c05 100644 --- a/src/appv2/features/comment/controllers.rs +++ b/src/appv2/features/comment/controllers.rs @@ -45,17 +45,11 @@ pub async fn delete( req: HttpRequest, path: web::Path<(ArticleIdSlug, CommentIdSlug)>, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let (article_title_slug, comment_id) = path.into_inner(); let comment_id = uuid::parse(&comment_id)?; - service::delete_comment( - conn, - &service::DeleteCommentService { - article_title_slug, - comment_id, - author_id: current_user.id, - }, - )?; - Ok(HttpResponse::Ok().json("Ok")) + state + .di_container + .comment_usecase + .delete(&article_title_slug, comment_id, current_user.id) } diff --git a/src/appv2/features/comment/repositories.rs b/src/appv2/features/comment/repositories.rs index 2b1546e..01abddc 100644 --- a/src/appv2/features/comment/repositories.rs +++ b/src/appv2/features/comment/repositories.rs @@ -1,4 +1,12 @@ -use crate::utils::db::DbPool; +use uuid::Uuid; + +use crate::{ + appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}, + error::AppError, + utils::db::DbPool, +}; + +use super::entities::{Comment, DeleteComment}; #[derive(Clone)] pub struct CommentRepository { @@ -10,6 +18,31 @@ impl CommentRepository { Self { pool } } + pub fn delete( + &self, + article_title_slug: &str, + comment_id: Uuid, + author_id: Uuid, + ) -> Result<(), AppError> { + let conn = &mut self.pool.get()?; + let article = Article::fetch_by_slug_and_author_id( + conn, + &FetchBySlugAndAuthorId { + slug: article_title_slug.to_owned(), + author_id, + }, + )?; + Comment::delete( + conn, + &DeleteComment { + comment_id, + article_id: article.id, + author_id, + }, + )?; + Ok(()) + } + // pub fn favorite(&self, user: User, article_title_slug: String) -> Result { // // let conn = &mut self.pool.get()?; diff --git a/src/appv2/features/comment/service.rs b/src/appv2/features/comment/service.rs index 1e7c505..b8b69b6 100644 --- a/src/appv2/features/comment/service.rs +++ b/src/appv2/features/comment/service.rs @@ -69,30 +69,30 @@ pub fn fetch_comments_list( Ok(comments) } -pub struct DeleteCommentService { - pub article_title_slug: String, - pub author_id: Uuid, - pub comment_id: Uuid, -} +// pub struct DeleteCommentService { +// pub article_title_slug: String, +// pub author_id: Uuid, +// pub comment_id: Uuid, +// } -pub fn delete_comment( - conn: &mut PgConnection, - params: &DeleteCommentService, -) -> Result<(), AppError> { - let article = Article::fetch_by_slug_and_author_id( - conn, - &FetchBySlugAndAuthorId { - slug: params.article_title_slug.to_owned(), - author_id: params.author_id, - }, - )?; - Comment::delete( - conn, - &DeleteComment { - comment_id: params.comment_id, - article_id: article.id, - author_id: params.author_id, - }, - )?; - Ok(()) -} +// pub fn delete_comment( +// conn: &mut PgConnection, +// params: &DeleteCommentService, +// ) -> Result<(), AppError> { +// let article = Article::fetch_by_slug_and_author_id( +// conn, +// &FetchBySlugAndAuthorId { +// slug: params.article_title_slug.to_owned(), +// author_id: params.author_id, +// }, +// )?; +// Comment::delete( +// conn, +// &DeleteComment { +// comment_id: params.comment_id, +// article_id: article.id, +// author_id: params.author_id, +// }, +// )?; +// Ok(()) +// } diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs index eac8ca5..f0d7216 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/appv2/features/comment/usecases.rs @@ -22,6 +22,17 @@ impl CommentUsecase { comment_presenter, } } + pub fn delete( + &self, + article_title_slug: &str, + comment_id: Uuid, + author_id: Uuid, + ) -> Result { + self.comment_repository + .delete(&article_title_slug, comment_id, author_id); + let res = self.comment_presenter.toHttpRes(); + Ok(res) + } // pub fn favorite( // &self, From f589a6633b57ea60b7fb4df285dad763341fafd1 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 13:44:16 +0900 Subject: [PATCH 43/59] refactor: update comment list feature --- src/appv2/features/comment/controllers.rs | 12 ++++--- src/appv2/features/comment/presenters.rs | 5 +++ src/appv2/features/comment/repositories.rs | 41 +++++++++++++++++++++- src/appv2/features/comment/usecases.rs | 26 ++++---------- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/appv2/features/comment/controllers.rs b/src/appv2/features/comment/controllers.rs index 9c50c05..21ee679 100644 --- a/src/appv2/features/comment/controllers.rs +++ b/src/appv2/features/comment/controllers.rs @@ -12,11 +12,15 @@ type ArticleIdSlug = String; type CommentIdSlug = String; pub async fn index(state: web::Data, req: HttpRequest) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req).ok(); - let list = service::fetch_comments_list(conn, ¤t_user)?; - let res = MultipleCommentsResponse::from(list); - Ok(HttpResponse::Ok().json(res)) + state + .di_container + .comment_usecase + .fetch_comments_list(¤t_user) + // let conn = &mut state.get_conn()?; + // let list = service::fetch_comments_list(conn, ¤t_user)?; + // let res = MultipleCommentsResponse::from(list); + // Ok(HttpResponse::Ok().json(res)) } pub async fn create( diff --git a/src/appv2/features/comment/presenters.rs b/src/appv2/features/comment/presenters.rs index 868b1f1..9c95219 100644 --- a/src/appv2/features/comment/presenters.rs +++ b/src/appv2/features/comment/presenters.rs @@ -95,4 +95,9 @@ impl CommentPresenter { pub fn toHttpRes(&self) -> HttpResponse { HttpResponse::Ok().json("OK") } + + pub fn from_comment_and_profile_list(&self, list: Vec<(Comment, Profile)>) -> HttpResponse { + let res = MultipleCommentsResponse::from(list); + HttpResponse::Ok().json(res) + } } diff --git a/src/appv2/features/comment/repositories.rs b/src/appv2/features/comment/repositories.rs index 01abddc..51e5290 100644 --- a/src/appv2/features/comment/repositories.rs +++ b/src/appv2/features/comment/repositories.rs @@ -1,7 +1,14 @@ use uuid::Uuid; use crate::{ - appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}, + appv2::features::{ + article::entities::{Article, FetchBySlugAndAuthorId}, + profile::{ + entities::Profile, + services::{conver_user_to_profile, ConverUserToProfile}, + }, + user::entities::User, + }, error::AppError, utils::db::DbPool, }; @@ -18,6 +25,38 @@ impl CommentRepository { Self { pool } } + pub fn fetch_comments_list( + &self, + current_user: &Option, + ) -> Result, AppError> { + let conn = &mut self.pool.get()?; + + let comments = { + use crate::schema::comments; + // use crate::schema::comments::dsl::*; + use crate::schema::users; + use diesel::prelude::*; + comments::table + .inner_join(users::table) + // .filter(comments::article_id.eq(article_id)) + .get_results::<(Comment, User)>(conn)? + }; + + let comments = comments + .iter() + .map(|(comment, user)| { + // TODO: avoid N+1. Write one query to fetch all data somehow. + let profile = + conver_user_to_profile(conn, &ConverUserToProfile { user, current_user }); + + // TODO: avoid copy + (comment.to_owned(), profile) + }) + .collect::>(); + + Ok(comments) + } + pub fn delete( &self, article_title_slug: &str, diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs index f0d7216..7be55c5 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/appv2/features/comment/usecases.rs @@ -22,6 +22,13 @@ impl CommentUsecase { comment_presenter, } } + + pub fn fetch_comments_list(&self, user: &Option) -> Result { + let result = self.comment_repository.fetch_comments_list(user)?; + let res = self.comment_presenter.from_comment_and_profile_list(result); + Ok(res) + } + pub fn delete( &self, article_title_slug: &str, @@ -33,23 +40,4 @@ impl CommentUsecase { let res = self.comment_presenter.toHttpRes(); Ok(res) } - - // pub fn favorite( - // &self, - // user: User, - // article_title_slug: String, - // ) -> Result { - // let article = self - // .favorite_repository - // .favorite(user.clone(), article_title_slug)?; - - // let result = self - // .article_repository - // .fetch_article_item(&FetchArticleRepositoryInput { - // article_id: article.id, - // current_user: user, - // })?; - // let res = self.favorite_presenter.complete(result); - // Ok(res) - // } } From c48639b91602105ae4c0b1e7c24329359e90017d Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 13:55:08 +0900 Subject: [PATCH 44/59] refactor: remove comment service --- src/appv2/features/comment/controllers.rs | 27 ++---- src/appv2/features/comment/mod.rs | 1 - src/appv2/features/comment/presenters.rs | 5 ++ src/appv2/features/comment/repositories.rs | 29 ++++++- src/appv2/features/comment/service.rs | 98 ---------------------- src/appv2/features/comment/usecases.rs | 13 +++ 6 files changed, 53 insertions(+), 120 deletions(-) delete mode 100644 src/appv2/features/comment/service.rs diff --git a/src/appv2/features/comment/controllers.rs b/src/appv2/features/comment/controllers.rs index 21ee679..eb54183 100644 --- a/src/appv2/features/comment/controllers.rs +++ b/src/appv2/features/comment/controllers.rs @@ -1,12 +1,9 @@ -use super::{ - presenters::{MultipleCommentsResponse, SingleCommentResponse}, - request, service, -}; +use super::request; use crate::appv2::drivers::middlewares::auth; use crate::appv2::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use crate::utils::uuid; -use actix_web::{web, HttpRequest, HttpResponse}; +use actix_web::{web, HttpRequest}; type ArticleIdSlug = String; type CommentIdSlug = String; @@ -17,10 +14,6 @@ pub async fn index(state: web::Data, req: HttpRequest) -> ApiResponse .di_container .comment_usecase .fetch_comments_list(¤t_user) - // let conn = &mut state.get_conn()?; - // let list = service::fetch_comments_list(conn, ¤t_user)?; - // let res = MultipleCommentsResponse::from(list); - // Ok(HttpResponse::Ok().json(res)) } pub async fn create( @@ -29,19 +22,13 @@ pub async fn create( path: web::Path, form: web::Json, ) -> ApiResponse { - let conn = &mut state.get_conn()?; let current_user = auth::get_current_user(&req)?; let article_title_slug = path.into_inner(); - let (comment, profile) = service::create( - conn, - &service::CreateCommentService { - body: form.comment.body.to_owned(), - article_title_slug, - author: current_user, - }, - )?; - let res = SingleCommentResponse::from((comment, profile)); - Ok(HttpResponse::Ok().json(res)) + let body = form.comment.body.to_owned(); + state + .di_container + .comment_usecase + .create(body, article_title_slug, current_user) } pub async fn delete( diff --git a/src/appv2/features/comment/mod.rs b/src/appv2/features/comment/mod.rs index 8235325..8b19374 100644 --- a/src/appv2/features/comment/mod.rs +++ b/src/appv2/features/comment/mod.rs @@ -3,5 +3,4 @@ pub mod entities; pub mod presenters; pub mod repositories; pub mod request; -pub mod service; pub mod usecases; diff --git a/src/appv2/features/comment/presenters.rs b/src/appv2/features/comment/presenters.rs index 9c95219..1af01d1 100644 --- a/src/appv2/features/comment/presenters.rs +++ b/src/appv2/features/comment/presenters.rs @@ -100,4 +100,9 @@ impl CommentPresenter { let res = MultipleCommentsResponse::from(list); HttpResponse::Ok().json(res) } + + pub fn from_comment_and_profile(&self, item: (Comment, Profile)) -> HttpResponse { + let res = SingleCommentResponse::from(item); + HttpResponse::Ok().json(res) + } } diff --git a/src/appv2/features/comment/repositories.rs b/src/appv2/features/comment/repositories.rs index 51e5290..f42879b 100644 --- a/src/appv2/features/comment/repositories.rs +++ b/src/appv2/features/comment/repositories.rs @@ -13,7 +13,7 @@ use crate::{ utils::db::DbPool, }; -use super::entities::{Comment, DeleteComment}; +use super::entities::{Comment, CreateComment, DeleteComment}; #[derive(Clone)] pub struct CommentRepository { @@ -57,6 +57,33 @@ impl CommentRepository { Ok(comments) } + pub fn create( + &self, + body: String, + article_title_slug: String, + author: User, + ) -> Result<(Comment, Profile), AppError> { + let conn = &mut self.pool.get()?; + + let article = Article::fetch_by_slug_and_author_id( + conn, + &FetchBySlugAndAuthorId { + slug: article_title_slug.to_owned(), + author_id: author.id, + }, + )?; + let comment = Comment::create( + conn, + &CreateComment { + body: body.to_string(), + author_id: author.id, + article_id: article.id.to_owned(), + }, + )?; + let profile = author.fetch_profile(conn, &author.id)?; + Ok((comment, profile)) + } + pub fn delete( &self, article_title_slug: &str, diff --git a/src/appv2/features/comment/service.rs b/src/appv2/features/comment/service.rs deleted file mode 100644 index b8b69b6..0000000 --- a/src/appv2/features/comment/service.rs +++ /dev/null @@ -1,98 +0,0 @@ -use super::entities::{Comment, CreateComment, DeleteComment}; -use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::profile::services::{conver_user_to_profile, ConverUserToProfile}; -use crate::appv2::features::user::entities::User; -use crate::error::AppError; -use diesel::pg::PgConnection; -use uuid::Uuid; - -pub struct CreateCommentService { - pub body: String, - pub article_title_slug: String, - pub author: User, -} -pub fn create( - conn: &mut PgConnection, - params: &CreateCommentService, -) -> Result<(Comment, Profile), AppError> { - let CreateCommentService { - body, - article_title_slug, - author, - } = params; - let article = Article::fetch_by_slug_and_author_id( - conn, - &FetchBySlugAndAuthorId { - slug: article_title_slug.to_owned(), - author_id: author.id, - }, - )?; - let comment = Comment::create( - conn, - &CreateComment { - body: body.to_string(), - author_id: author.id, - article_id: article.id.to_owned(), - }, - )?; - let profile = author.fetch_profile(conn, &author.id)?; - Ok((comment, profile)) -} - -pub fn fetch_comments_list( - conn: &mut PgConnection, - current_user: &Option, -) -> Result, AppError> { - let comments = { - use crate::schema::comments; - // use crate::schema::comments::dsl::*; - use crate::schema::users; - use diesel::prelude::*; - comments::table - .inner_join(users::table) - // .filter(comments::article_id.eq(article_id)) - .get_results::<(Comment, User)>(conn)? - }; - - let comments = comments - .iter() - .map(|(comment, user)| { - // TODO: avoid N+1. Write one query to fetch all data somehow. - let profile = conver_user_to_profile(conn, &ConverUserToProfile { user, current_user }); - - // TODO: avoid copy - (comment.to_owned(), profile) - }) - .collect::>(); - - Ok(comments) -} - -// pub struct DeleteCommentService { -// pub article_title_slug: String, -// pub author_id: Uuid, -// pub comment_id: Uuid, -// } - -// pub fn delete_comment( -// conn: &mut PgConnection, -// params: &DeleteCommentService, -// ) -> Result<(), AppError> { -// let article = Article::fetch_by_slug_and_author_id( -// conn, -// &FetchBySlugAndAuthorId { -// slug: params.article_title_slug.to_owned(), -// author_id: params.author_id, -// }, -// )?; -// Comment::delete( -// conn, -// &DeleteComment { -// comment_id: params.comment_id, -// article_id: article.id, -// author_id: params.author_id, -// }, -// )?; -// Ok(()) -// } diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs index 7be55c5..83eddd2 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/appv2/features/comment/usecases.rs @@ -29,6 +29,19 @@ impl CommentUsecase { Ok(res) } + pub fn create( + &self, + body: String, + article_title_slug: String, + author: User, + ) -> Result { + let result = self + .comment_repository + .create(body, article_title_slug, author)?; + let res = self.comment_presenter.from_comment_and_profile(result); + Ok(res) + } + pub fn delete( &self, article_title_slug: &str, From af60251cdd39f78499132c34036b9bf4dfb1e568 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Mon, 12 Jun 2023 14:05:38 +0900 Subject: [PATCH 45/59] refactor: remove profile service --- src/appv2/features/comment/repositories.rs | 30 +++------------------- src/appv2/features/profile/mod.rs | 1 - src/appv2/features/profile/services.rs | 24 ----------------- src/appv2/features/user/entities.rs | 15 +++++++++++ 4 files changed, 18 insertions(+), 52 deletions(-) delete mode 100644 src/appv2/features/profile/services.rs diff --git a/src/appv2/features/comment/repositories.rs b/src/appv2/features/comment/repositories.rs index f42879b..67e3914 100644 --- a/src/appv2/features/comment/repositories.rs +++ b/src/appv2/features/comment/repositories.rs @@ -3,10 +3,7 @@ use uuid::Uuid; use crate::{ appv2::features::{ article::entities::{Article, FetchBySlugAndAuthorId}, - profile::{ - entities::Profile, - services::{conver_user_to_profile, ConverUserToProfile}, - }, + profile::entities::Profile, user::entities::User, }, error::AppError, @@ -46,8 +43,8 @@ impl CommentRepository { .iter() .map(|(comment, user)| { // TODO: avoid N+1. Write one query to fetch all data somehow. - let profile = - conver_user_to_profile(conn, &ConverUserToProfile { user, current_user }); + let profile = user.to_profile(conn, current_user); + // Self::conver_user_to_profile(&ConverUserToProfile { user, current_user }); // TODO: avoid copy (comment.to_owned(), profile) @@ -108,25 +105,4 @@ impl CommentRepository { )?; Ok(()) } - - // pub fn favorite(&self, user: User, article_title_slug: String) -> Result { - // // let conn = &mut self.pool.get()?; - - // // let article = Article::fetch_by_slug_and_author_id( - // // conn, - // // &FetchBySlugAndAuthorId { - // // slug: article_title_slug.to_owned(), - // // author_id: user.id, - // // }, - // // )?; - // // Favorite::create( - // // conn, - // // &CreateFavorite { - // // user_id: user.id, - // // article_id: article.id, - // // }, - // // )?; - - // // Ok(article) - // } } diff --git a/src/appv2/features/profile/mod.rs b/src/appv2/features/profile/mod.rs index 923a07e..9c2709f 100644 --- a/src/appv2/features/profile/mod.rs +++ b/src/appv2/features/profile/mod.rs @@ -2,5 +2,4 @@ pub mod controllers; pub mod entities; pub mod presenters; pub mod repositories; -pub mod services; pub mod usecases; diff --git a/src/appv2/features/profile/services.rs b/src/appv2/features/profile/services.rs deleted file mode 100644 index f773174..0000000 --- a/src/appv2/features/profile/services.rs +++ /dev/null @@ -1,24 +0,0 @@ -use super::entities::Profile; -use crate::appv2::features::user::entities::User; -use diesel::pg::PgConnection; - -#[deprecated(note = "use repository")] -pub struct ConverUserToProfile<'a> { - pub user: &'a User, - pub current_user: &'a Option, -} - -#[deprecated(note = "use repository")] -pub fn conver_user_to_profile(conn: &mut PgConnection, params: &ConverUserToProfile) -> Profile { - let following = match params.current_user.as_ref() { - Some(current_user) => current_user.is_following(conn, ¶ms.user.id), - None => false, - }; - - Profile { - username: params.user.username.to_owned(), - bio: params.user.bio.to_owned(), - image: params.user.image.to_owned(), - following, - } -} diff --git a/src/appv2/features/user/entities.rs b/src/appv2/features/user/entities.rs index b8ea1a1..d5c0656 100644 --- a/src/appv2/features/user/entities.rs +++ b/src/appv2/features/user/entities.rs @@ -168,6 +168,21 @@ impl User { }; Ok(profile) } + + pub fn to_profile(&self, conn: &mut PgConnection, current_user: &Option) -> Profile { + let user = self; + let following = match current_user { + Some(current_user) => current_user.is_following(conn, &user.id), + None => false, + }; + + Profile { + username: user.username.to_owned(), + bio: user.bio.to_owned(), + image: user.image.to_owned(), + following, + } + } } #[derive(Insertable, Debug, Deserialize)] From 744ad88909f82fb5da9434da12021dff9fc1c520 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:16:29 +0900 Subject: [PATCH 46/59] fix: implement dyn constructor-injection on user repo --- src/appv2/features/profile/usecases.rs | 5 +-- src/appv2/features/user/repositories.rs | 42 +++++++++++++++---------- src/appv2/features/user/usecases.rs | 5 +-- src/utils/di.rs | 31 ++++++++++-------- 4 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/appv2/features/profile/usecases.rs b/src/appv2/features/profile/usecases.rs index 029ea44..1c7adfe 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/appv2/features/profile/usecases.rs @@ -4,17 +4,18 @@ use crate::appv2::features::user::entities::User; use crate::appv2::features::user::repositories::UserRepository; use crate::error::AppError; use actix_web::HttpResponse; +use std::sync::Arc; #[derive(Clone)] pub struct ProfileUsecase { - user_repository: UserRepository, + user_repository: Arc, profile_repository: ProfileRepository, presenter: ProfilePresenter, } impl ProfileUsecase { pub fn new( - (profile_repository, user_repository): (ProfileRepository, UserRepository), + (profile_repository, user_repository): (ProfileRepository, Arc), presenter: ProfilePresenter, ) -> Self { Self { diff --git a/src/appv2/features/user/repositories.rs b/src/appv2/features/user/repositories.rs index ba224f2..32aaae6 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/appv2/features/user/repositories.rs @@ -1,36 +1,50 @@ -use uuid::Uuid; - +use super::entities::UpdateUser; use crate::appv2::features::follow::entities::{CreateFollow, DeleteFollow, Follow}; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; - -use super::entities::UpdateUser; +use uuid::Uuid; type Token = String; +pub trait UserRepository: Send + Sync + 'static { + fn me<'a>(&self, user: &'a User) -> Result<(&'a User, Token), AppError>; + fn signin(&self, email: &str, naive_password: &str) -> Result<(User, Token), AppError>; + fn signup( + &self, + email: &str, + username: &str, + naive_password: &str, + ) -> Result<(User, Token), AppError>; + fn follow(&self, current_user: &User, target_username: &str) -> Result; + fn unfollow(&self, current_user: &User, target_username: &str) -> Result; + fn update(&self, user_id: Uuid, changeset: UpdateUser) -> Result<(User, Token), AppError>; +} + #[derive(Clone)] -pub struct UserRepository { +pub struct UserRepositoryImpl { pool: DbPool, } -impl UserRepository { +impl UserRepositoryImpl { pub fn new(pool: DbPool) -> Self { Self { pool } } +} - pub fn me<'a>(&self, current_user: &'a User) -> Result<(&'a User, Token), AppError> { +impl UserRepository for UserRepositoryImpl { + fn me<'a>(&self, current_user: &'a User) -> Result<(&'a User, Token), AppError> { let token = current_user.generate_token()?; Ok((current_user, token)) } - pub fn signin(&self, email: &str, naive_password: &str) -> Result<(User, Token), AppError> { + fn signin(&self, email: &str, naive_password: &str) -> Result<(User, Token), AppError> { let conn = &mut self.pool.get()?; User::signin(conn, email, naive_password) } - pub fn signup( + fn signup( &self, email: &str, username: &str, @@ -40,7 +54,7 @@ impl UserRepository { User::signup(conn, email, username, naive_password) } - pub fn follow(&self, current_user: &User, target_username: &str) -> Result { + fn follow(&self, current_user: &User, target_username: &str) -> Result { let conn = &mut self.pool.get()?; let t = User::by_username(target_username); @@ -65,11 +79,7 @@ impl UserRepository { }) } - pub fn unfollow( - &self, - current_user: &User, - target_username: &str, - ) -> Result { + fn unfollow(&self, current_user: &User, target_username: &str) -> Result { let conn = &mut self.pool.get()?; let t = User::by_username(target_username); let followee = { @@ -93,7 +103,7 @@ impl UserRepository { }) } - pub fn update(&self, user_id: Uuid, changeset: UpdateUser) -> Result<(User, Token), AppError> { + fn update(&self, user_id: Uuid, changeset: UpdateUser) -> Result<(User, Token), AppError> { let conn = &mut self.pool.get()?; let new_user = User::update(conn, user_id, changeset)?; let token = &new_user.generate_token()?; diff --git a/src/appv2/features/user/usecases.rs b/src/appv2/features/user/usecases.rs index b2fd5be..2864f74 100644 --- a/src/appv2/features/user/usecases.rs +++ b/src/appv2/features/user/usecases.rs @@ -3,16 +3,17 @@ use super::presenters::UserPresenter; use super::repositories::UserRepository; use crate::error::AppError; use actix_web::HttpResponse; +use std::sync::Arc; use uuid::Uuid; #[derive(Clone)] pub struct UserUsecase { - user_repository: UserRepository, + user_repository: Arc, user_presenter: UserPresenter, } impl UserUsecase { - pub fn new(user_repository: UserRepository, user_presenter: UserPresenter) -> Self { + pub fn new(user_repository: Arc, user_presenter: UserPresenter) -> Self { Self { user_repository, user_presenter, diff --git a/src/utils/di.rs b/src/utils/di.rs index 96debfe..abb1dc2 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -4,18 +4,19 @@ use crate::appv2::features::article::usecases::ArticleUsecase; use crate::appv2::features::comment::presenters::CommentPresenter; use crate::appv2::features::comment::repositories::CommentRepository; use crate::appv2::features::comment::usecases::CommentUsecase; -use crate::appv2::features::favorite::{ - presenters::FavoritePresenter, repositories::FavoriteRepository, usecases::FavoriteUsecase, -}; -use crate::appv2::features::profile::{ - presenters::ProfilePresenter, repositories::ProfileRepository, usecases::ProfileUsecase, -}; +use crate::appv2::features::favorite::presenters::FavoritePresenter; +use crate::appv2::features::favorite::repositories::FavoriteRepository; +use crate::appv2::features::favorite::usecases::FavoriteUsecase; +use crate::appv2::features::profile::presenters::ProfilePresenter; +use crate::appv2::features::profile::repositories::ProfileRepository; +use crate::appv2::features::profile::usecases::ProfileUsecase; use crate::appv2::features::tag::presenters::TagPresenter; use crate::appv2::features::tag::repositories::TagRepository; use crate::appv2::features::tag::usecases::TagUsecase; -use crate::appv2::features::user::{ - presenters::UserPresenter, repositories::UserRepository, usecases::UserUsecase, -}; +use crate::appv2::features::user::presenters::UserPresenter; +use crate::appv2::features::user::repositories::UserRepositoryImpl; +use crate::appv2::features::user::usecases::UserUsecase; +use std::sync::Arc; use crate::utils::db::DbPool; @@ -24,7 +25,7 @@ pub struct DiContainer { /** * User */ - pub user_repository: UserRepository, + pub user_repository: UserRepositoryImpl, pub user_usecase: UserUsecase, pub user_presenter: UserPresenter, @@ -67,7 +68,7 @@ pub struct DiContainer { impl DiContainer { pub fn new(pool: &DbPool) -> Self { // Repository - let user_repository = UserRepository::new(pool.clone()); + let user_repository = UserRepositoryImpl::new(pool.clone()); let profile_repository = ProfileRepository::new(pool.clone()); let favorite_repository = FavoriteRepository::new(pool.clone()); let article_repository = ArticleRepository::new(pool.clone()); @@ -83,9 +84,13 @@ impl DiContainer { let comment_presenter = CommentPresenter::new(); // Usecase - let user_usecase = UserUsecase::new(user_repository.clone(), user_presenter.clone()); + let user_usecase = + UserUsecase::new(Arc::new(user_repository.clone()), user_presenter.clone()); let profile_usecase = ProfileUsecase::new( - (profile_repository.clone(), user_repository.clone()), + ( + profile_repository.clone(), + Arc::new(user_repository.clone()), + ), profile_presenter.clone(), ); let favorite_usecase = FavoriteUsecase::new( From 20ed3a132ec11e61eb08a25803154d9a1a9ede5b Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:31:12 +0900 Subject: [PATCH 47/59] fix: implement dyn constructor-injection on profile repo --- src/appv2/features/profile/repositories.rs | 10 ++++++---- src/appv2/features/profile/usecases.rs | 5 +++-- src/utils/di.rs | 12 +++++------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/appv2/features/profile/repositories.rs b/src/appv2/features/profile/repositories.rs index 0f6706e..edf7c58 100644 --- a/src/appv2/features/profile/repositories.rs +++ b/src/appv2/features/profile/repositories.rs @@ -3,21 +3,23 @@ use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; -pub trait IProfileRepository { +pub trait ProfileRepository: Send + Sync + 'static { fn fetch_by_name(&self, current_user: &User, username: &str) -> Result; } #[derive(Clone)] -pub struct ProfileRepository { +pub struct ProfileRepositoryImpl { pool: DbPool, } -impl ProfileRepository { +impl ProfileRepositoryImpl { pub fn new(pool: DbPool) -> Self { Self { pool } } +} - pub fn fetch_by_name(&self, current_user: &User, username: &str) -> Result { +impl ProfileRepository for ProfileRepositoryImpl { + fn fetch_by_name(&self, current_user: &User, username: &str) -> Result { let conn = &mut self.pool.get()?; let profile = { let followee = User::find_by_username(conn, username)?; diff --git a/src/appv2/features/profile/usecases.rs b/src/appv2/features/profile/usecases.rs index 1c7adfe..9c4f319 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/appv2/features/profile/usecases.rs @@ -9,13 +9,14 @@ use std::sync::Arc; #[derive(Clone)] pub struct ProfileUsecase { user_repository: Arc, - profile_repository: ProfileRepository, + profile_repository: Arc, presenter: ProfilePresenter, } impl ProfileUsecase { pub fn new( - (profile_repository, user_repository): (ProfileRepository, Arc), + profile_repository: Arc, + user_repository: Arc, presenter: ProfilePresenter, ) -> Self { Self { diff --git a/src/utils/di.rs b/src/utils/di.rs index abb1dc2..12b0f40 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -8,7 +8,7 @@ use crate::appv2::features::favorite::presenters::FavoritePresenter; use crate::appv2::features::favorite::repositories::FavoriteRepository; use crate::appv2::features::favorite::usecases::FavoriteUsecase; use crate::appv2::features::profile::presenters::ProfilePresenter; -use crate::appv2::features::profile::repositories::ProfileRepository; +use crate::appv2::features::profile::repositories::ProfileRepositoryImpl; use crate::appv2::features::profile::usecases::ProfileUsecase; use crate::appv2::features::tag::presenters::TagPresenter; use crate::appv2::features::tag::repositories::TagRepository; @@ -32,7 +32,7 @@ pub struct DiContainer { /** * Profile */ - pub profile_repository: ProfileRepository, + pub profile_repository: ProfileRepositoryImpl, pub profile_presenter: ProfilePresenter, pub profile_usecase: ProfileUsecase, @@ -69,7 +69,7 @@ impl DiContainer { pub fn new(pool: &DbPool) -> Self { // Repository let user_repository = UserRepositoryImpl::new(pool.clone()); - let profile_repository = ProfileRepository::new(pool.clone()); + let profile_repository = ProfileRepositoryImpl::new(pool.clone()); let favorite_repository = FavoriteRepository::new(pool.clone()); let article_repository = ArticleRepository::new(pool.clone()); let tag_repository = TagRepository::new(pool.clone()); @@ -87,10 +87,8 @@ impl DiContainer { let user_usecase = UserUsecase::new(Arc::new(user_repository.clone()), user_presenter.clone()); let profile_usecase = ProfileUsecase::new( - ( - profile_repository.clone(), - Arc::new(user_repository.clone()), - ), + Arc::new(profile_repository.clone()), + Arc::new(user_repository.clone()), profile_presenter.clone(), ); let favorite_usecase = FavoriteUsecase::new( From d265c7fa7eeed3928c4558c9d366b6ff65d1f223 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:34:48 +0900 Subject: [PATCH 48/59] fix: implement dyn constructor-injection on favorite repo --- src/appv2/features/favorite/repositories.rs | 16 +++++++++++----- src/appv2/features/favorite/usecases.rs | 7 +++---- src/utils/di.rs | 8 ++++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/appv2/features/favorite/repositories.rs b/src/appv2/features/favorite/repositories.rs index 2935f94..25c5763 100644 --- a/src/appv2/features/favorite/repositories.rs +++ b/src/appv2/features/favorite/repositories.rs @@ -4,17 +4,23 @@ use crate::appv2::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; +pub trait FavoriteRepository: Send + Sync + 'static { + fn favorite(&self, user: User, article_title_slug: String) -> Result; + fn unfavorite(&self, user: User, article_title_slug: String) -> Result; +} + #[derive(Clone)] -pub struct FavoriteRepository { +pub struct FavoriteRepositoryImpl { pool: DbPool, } -impl FavoriteRepository { +impl FavoriteRepositoryImpl { pub fn new(pool: DbPool) -> Self { Self { pool } } - - pub fn favorite(&self, user: User, article_title_slug: String) -> Result { +} +impl FavoriteRepository for FavoriteRepositoryImpl { + fn favorite(&self, user: User, article_title_slug: String) -> Result { let conn = &mut self.pool.get()?; let article = Article::fetch_by_slug_and_author_id( @@ -35,7 +41,7 @@ impl FavoriteRepository { Ok(article) } - pub fn unfavorite(&self, user: User, article_title_slug: String) -> Result { + fn unfavorite(&self, user: User, article_title_slug: String) -> Result { let conn = &mut self.pool.get()?; let article = Article::fetch_by_slug_and_author_id( conn, diff --git a/src/appv2/features/favorite/usecases.rs b/src/appv2/features/favorite/usecases.rs index 008358e..a741e8a 100644 --- a/src/appv2/features/favorite/usecases.rs +++ b/src/appv2/features/favorite/usecases.rs @@ -1,4 +1,3 @@ -// use super::entities::{UpdateUser, User}; use super::presenters::FavoritePresenter; use super::repositories::FavoriteRepository; use crate::appv2::features::article::repositories::{ @@ -7,18 +6,18 @@ use crate::appv2::features::article::repositories::{ use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; -use uuid::Uuid; +use std::sync::Arc; #[derive(Clone)] pub struct FavoriteUsecase { - favorite_repository: FavoriteRepository, + favorite_repository: Arc, favorite_presenter: FavoritePresenter, article_repository: ArticleRepository, } impl FavoriteUsecase { pub fn new( - favorite_repository: FavoriteRepository, + favorite_repository: Arc, favorite_presenter: FavoritePresenter, article_repository: ArticleRepository, ) -> Self { diff --git a/src/utils/di.rs b/src/utils/di.rs index 12b0f40..0cfba84 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -5,7 +5,7 @@ use crate::appv2::features::comment::presenters::CommentPresenter; use crate::appv2::features::comment::repositories::CommentRepository; use crate::appv2::features::comment::usecases::CommentUsecase; use crate::appv2::features::favorite::presenters::FavoritePresenter; -use crate::appv2::features::favorite::repositories::FavoriteRepository; +use crate::appv2::features::favorite::repositories::FavoriteRepositoryImpl; use crate::appv2::features::favorite::usecases::FavoriteUsecase; use crate::appv2::features::profile::presenters::ProfilePresenter; use crate::appv2::features::profile::repositories::ProfileRepositoryImpl; @@ -39,7 +39,7 @@ pub struct DiContainer { /** * Favorite */ - pub favorite_repository: FavoriteRepository, + pub favorite_repository: FavoriteRepositoryImpl, pub favorite_presenter: FavoritePresenter, pub favorite_usecase: FavoriteUsecase, @@ -70,7 +70,7 @@ impl DiContainer { // Repository let user_repository = UserRepositoryImpl::new(pool.clone()); let profile_repository = ProfileRepositoryImpl::new(pool.clone()); - let favorite_repository = FavoriteRepository::new(pool.clone()); + let favorite_repository = FavoriteRepositoryImpl::new(pool.clone()); let article_repository = ArticleRepository::new(pool.clone()); let tag_repository = TagRepository::new(pool.clone()); let comment_repository = CommentRepository::new(pool.clone()); @@ -92,7 +92,7 @@ impl DiContainer { profile_presenter.clone(), ); let favorite_usecase = FavoriteUsecase::new( - favorite_repository.clone(), + Arc::new(favorite_repository.clone()), favorite_presenter.clone(), article_repository.clone(), ); From 64c2649b30a8c9bb886ea08af5339cd403ea6851 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:40:44 +0900 Subject: [PATCH 49/59] fix: implement dyn constructor-injection on article repo --- src/appv2/features/article/repositories.rs | 91 +++++++++++++++------- src/appv2/features/article/usecases.rs | 8 +- src/appv2/features/comment/usecases.rs | 2 +- src/appv2/features/favorite/usecases.rs | 4 +- src/utils/di.rs | 14 ++-- 5 files changed, 79 insertions(+), 40 deletions(-) diff --git a/src/appv2/features/article/repositories.rs b/src/appv2/features/article/repositories.rs index 9efcc9d..7e9d2f2 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/appv2/features/article/repositories.rs @@ -8,17 +8,70 @@ use crate::utils::db::DbPool; use diesel::PgConnection; use uuid::Uuid; +pub trait ArticleRepository: Send + Sync + 'static { + fn fetch_articles_list( + &self, + params: FetchArticlesListRepositoryInput, + ) -> Result<(ArticlesList, ArticlesCount), AppError>; + + fn fetch_article_by_slug( + &self, + article_title_slug: String, + ) -> Result; + + fn create( + &self, + params: CreateArticleRepositoryInput, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError>; + + fn delete(&self, input: DeleteArticleRepositoryInput) -> Result<(), AppError>; + + fn update( + &self, + input: UpdateArticleRepositoryInput, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError>; + + fn fetch_article_item( + &self, + input: &FetchArticleRepositoryInput, + ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError>; + + fn fetch_following_articles( + &self, + params: &FetchFollowingArticlesRepositoryInput, + ) -> Result<(ArticlesList, ArticlesCount), AppError>; +} #[derive(Clone)] -pub struct ArticleRepository { +pub struct ArticleRepositoryImpl { pool: DbPool, } -impl ArticleRepository { +impl ArticleRepositoryImpl { pub fn new(pool: DbPool) -> Self { Self { pool } } - pub fn fetch_articles_list( + fn create_tag_list( + conn: &mut PgConnection, + tag_name_list: &Option>, + article_id: &Uuid, + ) -> Result, AppError> { + let list = tag_name_list + .as_ref() + .map(|tag_name_list| { + let records = tag_name_list + .iter() + .map(|name| CreateTag { name, article_id }) + .collect(); + Tag::create_list(conn, records) + }) + .unwrap_or_else(|| Ok(vec![])); + list + } +} + +impl ArticleRepository for ArticleRepositoryImpl { + fn fetch_articles_list( &self, params: FetchArticlesListRepositoryInput, ) -> Result<(ArticlesList, ArticlesCount), AppError> { @@ -144,7 +197,7 @@ impl ArticleRepository { Ok((result, articles_count)) } - pub fn fetch_article_by_slug( + fn fetch_article_by_slug( &self, article_title_slug: String, ) -> Result { @@ -171,7 +224,7 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tags_list)) } - pub fn create( + fn create( &self, params: CreateArticleRepositoryInput, ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { @@ -206,7 +259,7 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tag_list)) } - pub fn delete(&self, input: DeleteArticleRepositoryInput) -> Result<(), AppError> { + fn delete(&self, input: DeleteArticleRepositoryInput) -> Result<(), AppError> { let conn = &mut self.pool.get()?; Article::delete( conn, @@ -217,7 +270,7 @@ impl ArticleRepository { ) } - pub fn update( + fn update( &self, input: UpdateArticleRepositoryInput, ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { @@ -251,25 +304,7 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tag_list)) } - fn create_tag_list( - conn: &mut PgConnection, - tag_name_list: &Option>, - article_id: &Uuid, - ) -> Result, AppError> { - let list = tag_name_list - .as_ref() - .map(|tag_name_list| { - let records = tag_name_list - .iter() - .map(|name| CreateTag { name, article_id }) - .collect(); - Tag::create_list(conn, records) - }) - .unwrap_or_else(|| Ok(vec![])); - list - } - - pub fn fetch_article_item( + fn fetch_article_item( &self, input: &FetchArticleRepositoryInput, ) -> Result<(Article, Profile, FavoriteInfo, Vec), AppError> { @@ -295,7 +330,7 @@ impl ArticleRepository { Ok((article, profile, favorite_info, tags_list)) } - pub fn fetch_following_articles( + fn fetch_following_articles( &self, params: &FetchFollowingArticlesRepositoryInput, ) -> Result<(ArticlesList, ArticlesCount), AppError> { @@ -443,8 +478,6 @@ pub struct FetchArticleRepositoryInput { pub current_user: User, } -// pub struct FetchArticleRepositoryOutput(); - pub struct FetchFollowingArticlesRepositoryInput { pub current_user: User, pub offset: i64, diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 6c22bf0..1d65122 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -8,16 +8,20 @@ use super::repositories::{ use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; +use std::sync::Arc; use uuid::Uuid; #[derive(Clone)] pub struct ArticleUsecase { - article_repository: ArticleRepository, + article_repository: Arc, article_presenter: ArticlePresenter, } impl ArticleUsecase { - pub fn new(article_repository: ArticleRepository, article_presenter: ArticlePresenter) -> Self { + pub fn new( + article_repository: Arc, + article_presenter: ArticlePresenter, + ) -> Self { Self { article_repository, article_presenter, diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs index 83eddd2..4e17efe 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/appv2/features/comment/usecases.rs @@ -1,5 +1,5 @@ use crate::appv2::features::article::repositories::{ - ArticleRepository, FetchArticleRepositoryInput, + ArticleRepositoryImpl, FetchArticleRepositoryInput, }; use crate::appv2::features::user::entities::User; use crate::error::AppError; diff --git a/src/appv2/features/favorite/usecases.rs b/src/appv2/features/favorite/usecases.rs index a741e8a..b9d0ea7 100644 --- a/src/appv2/features/favorite/usecases.rs +++ b/src/appv2/features/favorite/usecases.rs @@ -12,14 +12,14 @@ use std::sync::Arc; pub struct FavoriteUsecase { favorite_repository: Arc, favorite_presenter: FavoritePresenter, - article_repository: ArticleRepository, + article_repository: Arc, } impl FavoriteUsecase { pub fn new( favorite_repository: Arc, favorite_presenter: FavoritePresenter, - article_repository: ArticleRepository, + article_repository: Arc, ) -> Self { Self { favorite_repository, diff --git a/src/utils/di.rs b/src/utils/di.rs index 0cfba84..25996b4 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,5 +1,5 @@ use crate::appv2::features::article::presenters::ArticlePresenter; -use crate::appv2::features::article::repositories::ArticleRepository; +use crate::appv2::features::article::repositories::ArticleRepositoryImpl; use crate::appv2::features::article::usecases::ArticleUsecase; use crate::appv2::features::comment::presenters::CommentPresenter; use crate::appv2::features::comment::repositories::CommentRepository; @@ -46,7 +46,7 @@ pub struct DiContainer { /** * Article */ - pub article_repository: ArticleRepository, + pub article_repository: ArticleRepositoryImpl, pub article_presenter: ArticlePresenter, pub article_usecase: ArticleUsecase, @@ -71,7 +71,7 @@ impl DiContainer { let user_repository = UserRepositoryImpl::new(pool.clone()); let profile_repository = ProfileRepositoryImpl::new(pool.clone()); let favorite_repository = FavoriteRepositoryImpl::new(pool.clone()); - let article_repository = ArticleRepository::new(pool.clone()); + let article_repository = ArticleRepositoryImpl::new(pool.clone()); let tag_repository = TagRepository::new(pool.clone()); let comment_repository = CommentRepository::new(pool.clone()); @@ -94,10 +94,12 @@ impl DiContainer { let favorite_usecase = FavoriteUsecase::new( Arc::new(favorite_repository.clone()), favorite_presenter.clone(), - article_repository.clone(), + Arc::new(article_repository.clone()), + ); + let article_usecase = ArticleUsecase::new( + Arc::new(article_repository.clone()), + article_presenter.clone(), ); - let article_usecase = - ArticleUsecase::new(article_repository.clone(), article_presenter.clone()); let tag_usecase = TagUsecase::new(tag_repository.clone(), tag_presenter.clone()); let comment_usecase = CommentUsecase::new(comment_repository.clone(), comment_presenter.clone()); From 1a0bf2565bcb296e8d6538623cb4f6f72b91a2ef Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:43:08 +0900 Subject: [PATCH 50/59] fix: implement dyn constructor-injection on tag repo --- src/appv2/features/tag/repositories.rs | 12 ++++++++---- src/appv2/features/tag/usecases.rs | 5 +++-- src/utils/di.rs | 8 ++++---- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/appv2/features/tag/repositories.rs b/src/appv2/features/tag/repositories.rs index 4a5465a..2b8b025 100644 --- a/src/appv2/features/tag/repositories.rs +++ b/src/appv2/features/tag/repositories.rs @@ -2,19 +2,23 @@ use super::entities::Tag; use crate::error::AppError; use crate::utils::db::DbPool; -type Token = String; +pub trait TagRepository: Send + Sync + 'static { + fn list(&self) -> Result, AppError>; +} #[derive(Clone)] -pub struct TagRepository { +pub struct TagRepositoryImpl { pool: DbPool, } -impl TagRepository { +impl TagRepositoryImpl { pub fn new(pool: DbPool) -> Self { Self { pool } } +} - pub fn list(&self) -> Result, AppError> { +impl TagRepository for TagRepositoryImpl { + fn list(&self) -> Result, AppError> { let conn = &mut self.pool.get()?; Tag::fetch(conn) } diff --git a/src/appv2/features/tag/usecases.rs b/src/appv2/features/tag/usecases.rs index 7ee8b88..7ba14e1 100644 --- a/src/appv2/features/tag/usecases.rs +++ b/src/appv2/features/tag/usecases.rs @@ -2,15 +2,16 @@ use super::presenters::TagPresenter; use super::repositories::TagRepository; use crate::error::AppError; use actix_web::HttpResponse; +use std::sync::Arc; #[derive(Clone)] pub struct TagUsecase { - tag_repository: TagRepository, + tag_repository: Arc, tag_presenter: TagPresenter, } impl TagUsecase { - pub fn new(tag_repository: TagRepository, tag_presenter: TagPresenter) -> Self { + pub fn new(tag_repository: Arc, tag_presenter: TagPresenter) -> Self { Self { tag_repository, tag_presenter, diff --git a/src/utils/di.rs b/src/utils/di.rs index 25996b4..d8cc944 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -11,7 +11,7 @@ use crate::appv2::features::profile::presenters::ProfilePresenter; use crate::appv2::features::profile::repositories::ProfileRepositoryImpl; use crate::appv2::features::profile::usecases::ProfileUsecase; use crate::appv2::features::tag::presenters::TagPresenter; -use crate::appv2::features::tag::repositories::TagRepository; +use crate::appv2::features::tag::repositories::TagRepositoryImpl; use crate::appv2::features::tag::usecases::TagUsecase; use crate::appv2::features::user::presenters::UserPresenter; use crate::appv2::features::user::repositories::UserRepositoryImpl; @@ -53,7 +53,7 @@ pub struct DiContainer { /** * Tag */ - pub tag_repository: TagRepository, + pub tag_repository: TagRepositoryImpl, pub tag_presenter: TagPresenter, pub tag_usecase: TagUsecase, @@ -72,7 +72,7 @@ impl DiContainer { let profile_repository = ProfileRepositoryImpl::new(pool.clone()); let favorite_repository = FavoriteRepositoryImpl::new(pool.clone()); let article_repository = ArticleRepositoryImpl::new(pool.clone()); - let tag_repository = TagRepository::new(pool.clone()); + let tag_repository = TagRepositoryImpl::new(pool.clone()); let comment_repository = CommentRepository::new(pool.clone()); // Presenter @@ -100,7 +100,7 @@ impl DiContainer { Arc::new(article_repository.clone()), article_presenter.clone(), ); - let tag_usecase = TagUsecase::new(tag_repository.clone(), tag_presenter.clone()); + let tag_usecase = TagUsecase::new(Arc::new(tag_repository.clone()), tag_presenter.clone()); let comment_usecase = CommentUsecase::new(comment_repository.clone(), comment_presenter.clone()); From 034a066a91fcbc3e13792e9a2abc48fb30666883 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:46:30 +0900 Subject: [PATCH 51/59] fix: implement dyn constructor-injection on comment repo --- src/appv2/features/comment/repositories.rs | 38 +++++++++++++++++----- src/appv2/features/comment/usecases.rs | 16 ++++----- src/utils/di.rs | 12 ++++--- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/appv2/features/comment/repositories.rs b/src/appv2/features/comment/repositories.rs index 67e3914..2a0a557 100644 --- a/src/appv2/features/comment/repositories.rs +++ b/src/appv2/features/comment/repositories.rs @@ -1,5 +1,4 @@ -use uuid::Uuid; - +use super::entities::{Comment, CreateComment, DeleteComment}; use crate::{ appv2::features::{ article::entities::{Article, FetchBySlugAndAuthorId}, @@ -9,20 +8,41 @@ use crate::{ error::AppError, utils::db::DbPool, }; +use uuid::Uuid; -use super::entities::{Comment, CreateComment, DeleteComment}; +pub trait CommentRepository: Send + Sync + 'static { + fn fetch_comments_list( + &self, + current_user: &Option, + ) -> Result, AppError>; + + fn create( + &self, + body: String, + article_title_slug: String, + author: User, + ) -> Result<(Comment, Profile), AppError>; + + fn delete( + &self, + article_title_slug: &str, + comment_id: Uuid, + author_id: Uuid, + ) -> Result<(), AppError>; +} #[derive(Clone)] -pub struct CommentRepository { +pub struct CommentRepositoryImpl { pool: DbPool, } -impl CommentRepository { +impl CommentRepositoryImpl { pub fn new(pool: DbPool) -> Self { Self { pool } } - - pub fn fetch_comments_list( +} +impl CommentRepository for CommentRepositoryImpl { + fn fetch_comments_list( &self, current_user: &Option, ) -> Result, AppError> { @@ -54,7 +74,7 @@ impl CommentRepository { Ok(comments) } - pub fn create( + fn create( &self, body: String, article_title_slug: String, @@ -81,7 +101,7 @@ impl CommentRepository { Ok((comment, profile)) } - pub fn delete( + fn delete( &self, article_title_slug: &str, comment_id: Uuid, diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs index 4e17efe..ec8bf7a 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/appv2/features/comment/usecases.rs @@ -1,22 +1,22 @@ -use crate::appv2::features::article::repositories::{ - ArticleRepositoryImpl, FetchArticleRepositoryInput, -}; +use super::presenters::CommentPresenter; +use super::repositories::CommentRepository; use crate::appv2::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; +use std::sync::Arc; use uuid::Uuid; -use super::presenters::CommentPresenter; -use super::repositories::CommentRepository; - #[derive(Clone)] pub struct CommentUsecase { - comment_repository: CommentRepository, + comment_repository: Arc, comment_presenter: CommentPresenter, } impl CommentUsecase { - pub fn new(comment_repository: CommentRepository, comment_presenter: CommentPresenter) -> Self { + pub fn new( + comment_repository: Arc, + comment_presenter: CommentPresenter, + ) -> Self { Self { comment_repository, comment_presenter, diff --git a/src/utils/di.rs b/src/utils/di.rs index d8cc944..cc8069f 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -2,7 +2,7 @@ use crate::appv2::features::article::presenters::ArticlePresenter; use crate::appv2::features::article::repositories::ArticleRepositoryImpl; use crate::appv2::features::article::usecases::ArticleUsecase; use crate::appv2::features::comment::presenters::CommentPresenter; -use crate::appv2::features::comment::repositories::CommentRepository; +use crate::appv2::features::comment::repositories::CommentRepositoryImpl; use crate::appv2::features::comment::usecases::CommentUsecase; use crate::appv2::features::favorite::presenters::FavoritePresenter; use crate::appv2::features::favorite::repositories::FavoriteRepositoryImpl; @@ -60,7 +60,7 @@ pub struct DiContainer { /** * Comment */ - pub comment_repository: CommentRepository, + pub comment_repository: CommentRepositoryImpl, pub comment_presenter: CommentPresenter, pub comment_usecase: CommentUsecase, } @@ -73,7 +73,7 @@ impl DiContainer { let favorite_repository = FavoriteRepositoryImpl::new(pool.clone()); let article_repository = ArticleRepositoryImpl::new(pool.clone()); let tag_repository = TagRepositoryImpl::new(pool.clone()); - let comment_repository = CommentRepository::new(pool.clone()); + let comment_repository = CommentRepositoryImpl::new(pool.clone()); // Presenter let user_presenter = UserPresenter::new(); @@ -101,8 +101,10 @@ impl DiContainer { article_presenter.clone(), ); let tag_usecase = TagUsecase::new(Arc::new(tag_repository.clone()), tag_presenter.clone()); - let comment_usecase = - CommentUsecase::new(comment_repository.clone(), comment_presenter.clone()); + let comment_usecase = CommentUsecase::new( + Arc::new(comment_repository.clone()), + comment_presenter.clone(), + ); Self { // User From 6b6424299586770ac26e3ac1fa275617c2499fdf Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:49:12 +0900 Subject: [PATCH 52/59] fix: implement dyn constructor-injection on user presenter --- src/appv2/features/user/presenters.rs | 11 ++++++++--- src/appv2/features/user/usecases.rs | 7 +++++-- src/utils/di.rs | 12 +++++++----- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/appv2/features/user/presenters.rs b/src/appv2/features/user/presenters.rs index a362b6e..976312a 100644 --- a/src/appv2/features/user/presenters.rs +++ b/src/appv2/features/user/presenters.rs @@ -32,13 +32,18 @@ pub struct AuthUser { pub image: Option, } +pub trait UserPresenter: Send + Sync + 'static { + fn from_user_and_token(&self, user: User, token: String) -> HttpResponse; +} #[derive(Clone)] -pub struct UserPresenter {} -impl UserPresenter { +pub struct UserPresenterImpl {} +impl UserPresenterImpl { pub fn new() -> Self { Self {} } - pub fn from_user_and_token(&self, user: User, token: String) -> HttpResponse { +} +impl UserPresenter for UserPresenterImpl { + fn from_user_and_token(&self, user: User, token: String) -> HttpResponse { let res_model = UserResponse::from((user, token)); HttpResponse::Ok().json(res_model) } diff --git a/src/appv2/features/user/usecases.rs b/src/appv2/features/user/usecases.rs index 2864f74..9f5c795 100644 --- a/src/appv2/features/user/usecases.rs +++ b/src/appv2/features/user/usecases.rs @@ -9,11 +9,14 @@ use uuid::Uuid; #[derive(Clone)] pub struct UserUsecase { user_repository: Arc, - user_presenter: UserPresenter, + user_presenter: Arc, } impl UserUsecase { - pub fn new(user_repository: Arc, user_presenter: UserPresenter) -> Self { + pub fn new( + user_repository: Arc, + user_presenter: Arc, + ) -> Self { Self { user_repository, user_presenter, diff --git a/src/utils/di.rs b/src/utils/di.rs index cc8069f..7293cbd 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -13,7 +13,7 @@ use crate::appv2::features::profile::usecases::ProfileUsecase; use crate::appv2::features::tag::presenters::TagPresenter; use crate::appv2::features::tag::repositories::TagRepositoryImpl; use crate::appv2::features::tag::usecases::TagUsecase; -use crate::appv2::features::user::presenters::UserPresenter; +use crate::appv2::features::user::presenters::UserPresenterImpl; use crate::appv2::features::user::repositories::UserRepositoryImpl; use crate::appv2::features::user::usecases::UserUsecase; use std::sync::Arc; @@ -27,7 +27,7 @@ pub struct DiContainer { */ pub user_repository: UserRepositoryImpl, pub user_usecase: UserUsecase, - pub user_presenter: UserPresenter, + pub user_presenter: UserPresenterImpl, /** * Profile @@ -76,7 +76,7 @@ impl DiContainer { let comment_repository = CommentRepositoryImpl::new(pool.clone()); // Presenter - let user_presenter = UserPresenter::new(); + let user_presenter = UserPresenterImpl::new(); let profile_presenter = ProfilePresenter::new(); let favorite_presenter = FavoritePresenter::new(); let article_presenter = ArticlePresenter::new(); @@ -84,8 +84,10 @@ impl DiContainer { let comment_presenter = CommentPresenter::new(); // Usecase - let user_usecase = - UserUsecase::new(Arc::new(user_repository.clone()), user_presenter.clone()); + let user_usecase = UserUsecase::new( + Arc::new(user_repository.clone()), + Arc::new(user_presenter.clone()), + ); let profile_usecase = ProfileUsecase::new( Arc::new(profile_repository.clone()), Arc::new(user_repository.clone()), From a76dbaa3f6c9a56e849c73d214abc1bb57736b6f Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:51:42 +0900 Subject: [PATCH 53/59] fix: implement dyn constructor-injection on profile presenter --- src/appv2/features/profile/presenters.rs | 12 +++++++++--- src/appv2/features/profile/usecases.rs | 4 ++-- src/utils/di.rs | 8 ++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/appv2/features/profile/presenters.rs b/src/appv2/features/profile/presenters.rs index c089b93..ebefafa 100644 --- a/src/appv2/features/profile/presenters.rs +++ b/src/appv2/features/profile/presenters.rs @@ -28,13 +28,19 @@ impl From for ProfileResponse { } } +pub trait ProfilePresenter: Send + Sync + 'static { + fn from_profile(&self, model: ProfileModel) -> HttpResponse; +} + #[derive(Clone)] -pub struct ProfilePresenter {} -impl ProfilePresenter { +pub struct ProfilePresenterImpl {} +impl ProfilePresenterImpl { pub fn new() -> Self { Self {} } - pub fn from_profile(&self, model: ProfileModel) -> HttpResponse { +} +impl ProfilePresenter for ProfilePresenterImpl { + fn from_profile(&self, model: ProfileModel) -> HttpResponse { let res_model = ProfileResponse::from(model); HttpResponse::Ok().json(res_model) } diff --git a/src/appv2/features/profile/usecases.rs b/src/appv2/features/profile/usecases.rs index 9c4f319..74b81cc 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/appv2/features/profile/usecases.rs @@ -10,14 +10,14 @@ use std::sync::Arc; pub struct ProfileUsecase { user_repository: Arc, profile_repository: Arc, - presenter: ProfilePresenter, + presenter: Arc, } impl ProfileUsecase { pub fn new( profile_repository: Arc, user_repository: Arc, - presenter: ProfilePresenter, + presenter: Arc, ) -> Self { Self { profile_repository, diff --git a/src/utils/di.rs b/src/utils/di.rs index 7293cbd..cdc543b 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -7,7 +7,7 @@ use crate::appv2::features::comment::usecases::CommentUsecase; use crate::appv2::features::favorite::presenters::FavoritePresenter; use crate::appv2::features::favorite::repositories::FavoriteRepositoryImpl; use crate::appv2::features::favorite::usecases::FavoriteUsecase; -use crate::appv2::features::profile::presenters::ProfilePresenter; +use crate::appv2::features::profile::presenters::ProfilePresenterImpl; use crate::appv2::features::profile::repositories::ProfileRepositoryImpl; use crate::appv2::features::profile::usecases::ProfileUsecase; use crate::appv2::features::tag::presenters::TagPresenter; @@ -33,7 +33,7 @@ pub struct DiContainer { * Profile */ pub profile_repository: ProfileRepositoryImpl, - pub profile_presenter: ProfilePresenter, + pub profile_presenter: ProfilePresenterImpl, pub profile_usecase: ProfileUsecase, /** @@ -77,7 +77,7 @@ impl DiContainer { // Presenter let user_presenter = UserPresenterImpl::new(); - let profile_presenter = ProfilePresenter::new(); + let profile_presenter = ProfilePresenterImpl::new(); let favorite_presenter = FavoritePresenter::new(); let article_presenter = ArticlePresenter::new(); let tag_presenter = TagPresenter::new(); @@ -91,7 +91,7 @@ impl DiContainer { let profile_usecase = ProfileUsecase::new( Arc::new(profile_repository.clone()), Arc::new(user_repository.clone()), - profile_presenter.clone(), + Arc::new(profile_presenter.clone()), ); let favorite_usecase = FavoriteUsecase::new( Arc::new(favorite_repository.clone()), From 8aa5429257448c2106c038e4da064013a5077e7f Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:55:11 +0900 Subject: [PATCH 54/59] fix: implement dyn constructor-injection on favorite presenter --- src/appv2/features/favorite/presenters.rs | 17 ++++++++++------- src/appv2/features/favorite/usecases.rs | 4 ++-- src/utils/di.rs | 8 ++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/appv2/features/favorite/presenters.rs b/src/appv2/features/favorite/presenters.rs index 33b8892..6e1ed16 100644 --- a/src/appv2/features/favorite/presenters.rs +++ b/src/appv2/features/favorite/presenters.rs @@ -1,20 +1,23 @@ -use actix_web::HttpResponse; - +use super::entities::FavoriteInfo; use crate::appv2::features::article::entities::Article; pub use crate::appv2::features::article::presenters::SingleArticleResponse; use crate::appv2::features::profile::entities::Profile; use crate::appv2::features::tag::entities::Tag; +use actix_web::HttpResponse; -use super::entities::FavoriteInfo; +pub trait FavoritePresenter: Send + Sync + 'static { + fn complete(&self, item: (Article, Profile, FavoriteInfo, Vec)) -> HttpResponse; +} #[derive(Clone)] -pub struct FavoritePresenter {} -impl FavoritePresenter { +pub struct FavoritePresenterImpl {} +impl FavoritePresenterImpl { pub fn new() -> Self { Self {} } - - pub fn complete( +} +impl FavoritePresenter for FavoritePresenterImpl { + fn complete( &self, (article, profile, favorite_info, tags_list): (Article, Profile, FavoriteInfo, Vec), ) -> HttpResponse { diff --git a/src/appv2/features/favorite/usecases.rs b/src/appv2/features/favorite/usecases.rs index b9d0ea7..267cf21 100644 --- a/src/appv2/features/favorite/usecases.rs +++ b/src/appv2/features/favorite/usecases.rs @@ -11,14 +11,14 @@ use std::sync::Arc; #[derive(Clone)] pub struct FavoriteUsecase { favorite_repository: Arc, - favorite_presenter: FavoritePresenter, + favorite_presenter: Arc, article_repository: Arc, } impl FavoriteUsecase { pub fn new( favorite_repository: Arc, - favorite_presenter: FavoritePresenter, + favorite_presenter: Arc, article_repository: Arc, ) -> Self { Self { diff --git a/src/utils/di.rs b/src/utils/di.rs index cdc543b..f0e1f9a 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -4,7 +4,7 @@ use crate::appv2::features::article::usecases::ArticleUsecase; use crate::appv2::features::comment::presenters::CommentPresenter; use crate::appv2::features::comment::repositories::CommentRepositoryImpl; use crate::appv2::features::comment::usecases::CommentUsecase; -use crate::appv2::features::favorite::presenters::FavoritePresenter; +use crate::appv2::features::favorite::presenters::FavoritePresenterImpl; use crate::appv2::features::favorite::repositories::FavoriteRepositoryImpl; use crate::appv2::features::favorite::usecases::FavoriteUsecase; use crate::appv2::features::profile::presenters::ProfilePresenterImpl; @@ -40,7 +40,7 @@ pub struct DiContainer { * Favorite */ pub favorite_repository: FavoriteRepositoryImpl, - pub favorite_presenter: FavoritePresenter, + pub favorite_presenter: FavoritePresenterImpl, pub favorite_usecase: FavoriteUsecase, /** @@ -78,7 +78,7 @@ impl DiContainer { // Presenter let user_presenter = UserPresenterImpl::new(); let profile_presenter = ProfilePresenterImpl::new(); - let favorite_presenter = FavoritePresenter::new(); + let favorite_presenter = FavoritePresenterImpl::new(); let article_presenter = ArticlePresenter::new(); let tag_presenter = TagPresenter::new(); let comment_presenter = CommentPresenter::new(); @@ -95,7 +95,7 @@ impl DiContainer { ); let favorite_usecase = FavoriteUsecase::new( Arc::new(favorite_repository.clone()), - favorite_presenter.clone(), + Arc::new(favorite_presenter.clone()), Arc::new(article_repository.clone()), ); let article_usecase = ArticleUsecase::new( From 332738e5722cf2cc45b09229fd8a5ecbf9e19c5d Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 10:57:39 +0900 Subject: [PATCH 55/59] fix: implement dyn constructor-injection on article presenter --- src/appv2/features/article/presenters.rs | 18 +++++++++++++----- src/appv2/features/article/usecases.rs | 4 ++-- src/utils/di.rs | 8 ++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/appv2/features/article/presenters.rs b/src/appv2/features/article/presenters.rs index cb568d2..d60edad 100644 --- a/src/appv2/features/article/presenters.rs +++ b/src/appv2/features/article/presenters.rs @@ -120,21 +120,29 @@ pub struct AuthorContent { pub following: bool, } +pub trait ArticlePresenter: Send + Sync + 'static { + fn from_list_and_count(&self, list: ArticlesList, count: i64) -> HttpResponse; + fn from_item(&self, item: (Article, Profile, FavoriteInfo, Vec)) -> HttpResponse; + fn toHttpRes(&self) -> HttpResponse; +} + #[derive(Clone)] -pub struct ArticlePresenter {} -impl ArticlePresenter { +pub struct ArticlePresenterImpl {} +impl ArticlePresenterImpl { pub fn new() -> Self { Self {} } - pub fn from_list_and_count(&self, list: ArticlesList, count: i64) -> HttpResponse { +} +impl ArticlePresenter for ArticlePresenterImpl { + fn from_list_and_count(&self, list: ArticlesList, count: i64) -> HttpResponse { let res = MultipleArticlesResponse::from((list, count)); HttpResponse::Ok().json(res) } - pub fn from_item(&self, item: (Article, Profile, FavoriteInfo, Vec)) -> HttpResponse { + fn from_item(&self, item: (Article, Profile, FavoriteInfo, Vec)) -> HttpResponse { let res = SingleArticleResponse::from(item); HttpResponse::Ok().json(res) } - pub fn toHttpRes(&self) -> HttpResponse { + fn toHttpRes(&self) -> HttpResponse { let res = (); HttpResponse::Ok().json(res) } diff --git a/src/appv2/features/article/usecases.rs b/src/appv2/features/article/usecases.rs index 1d65122..d144fdc 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/appv2/features/article/usecases.rs @@ -14,13 +14,13 @@ use uuid::Uuid; #[derive(Clone)] pub struct ArticleUsecase { article_repository: Arc, - article_presenter: ArticlePresenter, + article_presenter: Arc, } impl ArticleUsecase { pub fn new( article_repository: Arc, - article_presenter: ArticlePresenter, + article_presenter: Arc, ) -> Self { Self { article_repository, diff --git a/src/utils/di.rs b/src/utils/di.rs index f0e1f9a..f77ee83 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,4 +1,4 @@ -use crate::appv2::features::article::presenters::ArticlePresenter; +use crate::appv2::features::article::presenters::ArticlePresenterImpl; use crate::appv2::features::article::repositories::ArticleRepositoryImpl; use crate::appv2::features::article::usecases::ArticleUsecase; use crate::appv2::features::comment::presenters::CommentPresenter; @@ -47,7 +47,7 @@ pub struct DiContainer { * Article */ pub article_repository: ArticleRepositoryImpl, - pub article_presenter: ArticlePresenter, + pub article_presenter: ArticlePresenterImpl, pub article_usecase: ArticleUsecase, /** @@ -79,7 +79,7 @@ impl DiContainer { let user_presenter = UserPresenterImpl::new(); let profile_presenter = ProfilePresenterImpl::new(); let favorite_presenter = FavoritePresenterImpl::new(); - let article_presenter = ArticlePresenter::new(); + let article_presenter = ArticlePresenterImpl::new(); let tag_presenter = TagPresenter::new(); let comment_presenter = CommentPresenter::new(); @@ -100,7 +100,7 @@ impl DiContainer { ); let article_usecase = ArticleUsecase::new( Arc::new(article_repository.clone()), - article_presenter.clone(), + Arc::new(article_presenter.clone()), ); let tag_usecase = TagUsecase::new(Arc::new(tag_repository.clone()), tag_presenter.clone()); let comment_usecase = CommentUsecase::new( From 16b6b499e947c981d13331769dcd9e6a45be38b5 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 11:00:39 +0900 Subject: [PATCH 56/59] fix: implement dyn constructor-injection on tag presenter --- src/appv2/features/tag/presenters.rs | 12 +++++++++--- src/appv2/features/tag/usecases.rs | 7 +++++-- src/utils/di.rs | 11 +++++++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/appv2/features/tag/presenters.rs b/src/appv2/features/tag/presenters.rs index 6c5d99f..9c70b31 100644 --- a/src/appv2/features/tag/presenters.rs +++ b/src/appv2/features/tag/presenters.rs @@ -15,13 +15,19 @@ impl std::convert::From> for TagsResponse { } } +pub trait TagPresenter: Send + Sync + 'static { + fn from_list(&self, list: Vec) -> HttpResponse; +} + #[derive(Clone)] -pub struct TagPresenter {} -impl TagPresenter { +pub struct TagPresenterImpl {} +impl TagPresenterImpl { pub fn new() -> Self { Self {} } - pub fn from_list(&self, list: Vec) -> HttpResponse { +} +impl TagPresenter for TagPresenterImpl { + fn from_list(&self, list: Vec) -> HttpResponse { let res = TagsResponse::from(list); HttpResponse::Ok().json(res) } diff --git a/src/appv2/features/tag/usecases.rs b/src/appv2/features/tag/usecases.rs index 7ba14e1..72f02c4 100644 --- a/src/appv2/features/tag/usecases.rs +++ b/src/appv2/features/tag/usecases.rs @@ -7,11 +7,14 @@ use std::sync::Arc; #[derive(Clone)] pub struct TagUsecase { tag_repository: Arc, - tag_presenter: TagPresenter, + tag_presenter: Arc, } impl TagUsecase { - pub fn new(tag_repository: Arc, tag_presenter: TagPresenter) -> Self { + pub fn new( + tag_repository: Arc, + tag_presenter: Arc, + ) -> Self { Self { tag_repository, tag_presenter, diff --git a/src/utils/di.rs b/src/utils/di.rs index f77ee83..975aa5f 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -10,7 +10,7 @@ use crate::appv2::features::favorite::usecases::FavoriteUsecase; use crate::appv2::features::profile::presenters::ProfilePresenterImpl; use crate::appv2::features::profile::repositories::ProfileRepositoryImpl; use crate::appv2::features::profile::usecases::ProfileUsecase; -use crate::appv2::features::tag::presenters::TagPresenter; +use crate::appv2::features::tag::presenters::TagPresenterImpl; use crate::appv2::features::tag::repositories::TagRepositoryImpl; use crate::appv2::features::tag::usecases::TagUsecase; use crate::appv2::features::user::presenters::UserPresenterImpl; @@ -54,7 +54,7 @@ pub struct DiContainer { * Tag */ pub tag_repository: TagRepositoryImpl, - pub tag_presenter: TagPresenter, + pub tag_presenter: TagPresenterImpl, pub tag_usecase: TagUsecase, /** @@ -80,7 +80,7 @@ impl DiContainer { let profile_presenter = ProfilePresenterImpl::new(); let favorite_presenter = FavoritePresenterImpl::new(); let article_presenter = ArticlePresenterImpl::new(); - let tag_presenter = TagPresenter::new(); + let tag_presenter = TagPresenterImpl::new(); let comment_presenter = CommentPresenter::new(); // Usecase @@ -102,7 +102,10 @@ impl DiContainer { Arc::new(article_repository.clone()), Arc::new(article_presenter.clone()), ); - let tag_usecase = TagUsecase::new(Arc::new(tag_repository.clone()), tag_presenter.clone()); + let tag_usecase = TagUsecase::new( + Arc::new(tag_repository.clone()), + Arc::new(tag_presenter.clone()), + ); let comment_usecase = CommentUsecase::new( Arc::new(comment_repository.clone()), comment_presenter.clone(), From 051dc7b6d8b42afe0b6d0e6e913b2860ce36a0f9 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 11:03:52 +0900 Subject: [PATCH 57/59] fix: implement dyn constructor-injection on comment presenter --- src/appv2/features/comment/presenters.rs | 26 ++++++++++++------------ src/appv2/features/comment/usecases.rs | 4 ++-- src/utils/di.rs | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/appv2/features/comment/presenters.rs b/src/appv2/features/comment/presenters.rs index 1af01d1..c065e35 100644 --- a/src/appv2/features/comment/presenters.rs +++ b/src/appv2/features/comment/presenters.rs @@ -78,30 +78,30 @@ pub struct InnerAuthor { pub following: bool, } +pub trait CommentPresenter: Send + Sync + 'static { + fn toHttpRes(&self) -> HttpResponse; + fn from_comment_and_profile(&self, item: (Comment, Profile)) -> HttpResponse; + fn from_comment_and_profile_list(&self, list: Vec<(Comment, Profile)>) -> HttpResponse; +} + #[derive(Clone)] -pub struct CommentPresenter {} -impl CommentPresenter { +pub struct CommentPresenterImpl {} +impl CommentPresenterImpl { pub fn new() -> Self { Self {} } - - // pub fn complete( - // &self, - // (article, profile, favorite_info, tags_list): (Article, Profile, FavoriteInfo, Vec), - // ) -> HttpResponse { - // let res_model = SingleArticleResponse::from((article, profile, favorite_info, tags_list)); - // HttpResponse::Ok().json(res_model) - // } - pub fn toHttpRes(&self) -> HttpResponse { +} +impl CommentPresenter for CommentPresenterImpl { + fn toHttpRes(&self) -> HttpResponse { HttpResponse::Ok().json("OK") } - pub fn from_comment_and_profile_list(&self, list: Vec<(Comment, Profile)>) -> HttpResponse { + fn from_comment_and_profile_list(&self, list: Vec<(Comment, Profile)>) -> HttpResponse { let res = MultipleCommentsResponse::from(list); HttpResponse::Ok().json(res) } - pub fn from_comment_and_profile(&self, item: (Comment, Profile)) -> HttpResponse { + fn from_comment_and_profile(&self, item: (Comment, Profile)) -> HttpResponse { let res = SingleCommentResponse::from(item); HttpResponse::Ok().json(res) } diff --git a/src/appv2/features/comment/usecases.rs b/src/appv2/features/comment/usecases.rs index ec8bf7a..0e51a9b 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/appv2/features/comment/usecases.rs @@ -9,13 +9,13 @@ use uuid::Uuid; #[derive(Clone)] pub struct CommentUsecase { comment_repository: Arc, - comment_presenter: CommentPresenter, + comment_presenter: Arc, } impl CommentUsecase { pub fn new( comment_repository: Arc, - comment_presenter: CommentPresenter, + comment_presenter: Arc, ) -> Self { Self { comment_repository, diff --git a/src/utils/di.rs b/src/utils/di.rs index 975aa5f..e44df6e 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,7 +1,7 @@ use crate::appv2::features::article::presenters::ArticlePresenterImpl; use crate::appv2::features::article::repositories::ArticleRepositoryImpl; use crate::appv2::features::article::usecases::ArticleUsecase; -use crate::appv2::features::comment::presenters::CommentPresenter; +use crate::appv2::features::comment::presenters::CommentPresenterImpl; use crate::appv2::features::comment::repositories::CommentRepositoryImpl; use crate::appv2::features::comment::usecases::CommentUsecase; use crate::appv2::features::favorite::presenters::FavoritePresenterImpl; @@ -61,7 +61,7 @@ pub struct DiContainer { * Comment */ pub comment_repository: CommentRepositoryImpl, - pub comment_presenter: CommentPresenter, + pub comment_presenter: CommentPresenterImpl, pub comment_usecase: CommentUsecase, } @@ -81,7 +81,7 @@ impl DiContainer { let favorite_presenter = FavoritePresenterImpl::new(); let article_presenter = ArticlePresenterImpl::new(); let tag_presenter = TagPresenterImpl::new(); - let comment_presenter = CommentPresenter::new(); + let comment_presenter = CommentPresenterImpl::new(); // Usecase let user_usecase = UserUsecase::new( @@ -108,7 +108,7 @@ impl DiContainer { ); let comment_usecase = CommentUsecase::new( Arc::new(comment_repository.clone()), - comment_presenter.clone(), + Arc::new(comment_presenter.clone()), ); Self { From 504aac920f38c032fb6e6965728faa0780e17793 Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 14:52:10 +0900 Subject: [PATCH 58/59] refactor: rename appv2 to app --- .../drivers/middlewares/auth.rs | 4 +- .../drivers/middlewares/cors.rs | 0 .../drivers/middlewares/error.rs | 0 src/{appv2 => app}/drivers/middlewares/mod.rs | 0 .../drivers/middlewares/state.rs | 0 src/{appv2 => app}/drivers/mod.rs | 0 src/app/drivers/routes.rs | 80 +++++++++++++++++ .../features/article/controllers.rs | 4 +- .../features/article/entities.rs | 4 +- src/{appv2 => app}/features/article/mod.rs | 0 .../features/article/presenters.rs | 6 +- .../features/article/repositories.rs | 32 +++---- .../features/article/requests.rs | 0 .../features/article/usecases.rs | 2 +- .../features/comment/controllers.rs | 4 +- .../features/comment/entities.rs | 4 +- src/{appv2 => app}/features/comment/mod.rs | 0 .../features/comment/presenters.rs | 4 +- .../features/comment/repositories.rs | 2 +- .../features/comment/request.rs | 0 .../features/comment/usecases.rs | 2 +- .../features/favorite/controllers.rs | 4 +- .../features/favorite/entities.rs | 4 +- src/{appv2 => app}/features/favorite/mod.rs | 0 .../features/favorite/presenters.rs | 8 +- .../features/favorite/repositories.rs | 4 +- .../features/favorite/usecases.rs | 6 +- .../features/follow/entities.rs | 2 +- src/{appv2 => app}/features/follow/mod.rs | 0 .../features/healthcheck/controllers.rs | 0 .../features/healthcheck/mod.rs | 0 src/{appv2 => app}/features/mod.rs | 0 .../features/profile/controllers.rs | 2 +- .../features/profile/entities.rs | 0 src/{appv2 => app}/features/profile/mod.rs | 0 .../features/profile/presenters.rs | 0 .../features/profile/repositories.rs | 2 +- .../features/profile/usecases.rs | 4 +- .../features/tag/controllers.rs | 2 +- src/{appv2 => app}/features/tag/entities.rs | 2 +- src/{appv2 => app}/features/tag/mod.rs | 0 src/{appv2 => app}/features/tag/presenters.rs | 0 .../features/tag/repositories.rs | 0 src/{appv2 => app}/features/tag/usecases.rs | 0 .../features/user/controllers.rs | 4 +- src/{appv2 => app}/features/user/entities.rs | 6 +- src/{appv2 => app}/features/user/mod.rs | 0 .../features/user/presenters.rs | 2 +- .../features/user/repositories.rs | 6 +- src/{appv2 => app}/features/user/requests.rs | 0 src/{appv2 => app}/features/user/usecases.rs | 0 src/{appv2 => app}/mod.rs | 0 src/appv2/drivers/routes.rs | 89 ------------------- src/main.rs | 10 +-- src/utils/di.rs | 36 ++++---- 55 files changed, 165 insertions(+), 176 deletions(-) rename src/{appv2 => app}/drivers/middlewares/auth.rs (98%) rename src/{appv2 => app}/drivers/middlewares/cors.rs (100%) rename src/{appv2 => app}/drivers/middlewares/error.rs (100%) rename src/{appv2 => app}/drivers/middlewares/mod.rs (100%) rename src/{appv2 => app}/drivers/middlewares/state.rs (100%) rename src/{appv2 => app}/drivers/mod.rs (100%) create mode 100644 src/app/drivers/routes.rs rename src/{appv2 => app}/features/article/controllers.rs (97%) rename src/{appv2 => app}/features/article/entities.rs (97%) rename src/{appv2 => app}/features/article/mod.rs (100%) rename src/{appv2 => app}/features/article/presenters.rs (96%) rename src/{appv2 => app}/features/article/repositories.rs (94%) rename src/{appv2 => app}/features/article/requests.rs (100%) rename src/{appv2 => app}/features/article/usecases.rs (98%) rename src/{appv2 => app}/features/comment/controllers.rs (92%) rename src/{appv2 => app}/features/comment/entities.rs (94%) rename src/{appv2 => app}/features/comment/mod.rs (100%) rename src/{appv2 => app}/features/comment/presenters.rs (96%) rename src/{appv2 => app}/features/comment/repositories.rs (99%) rename src/{appv2 => app}/features/comment/request.rs (100%) rename src/{appv2 => app}/features/comment/usecases.rs (96%) rename src/{appv2 => app}/features/favorite/controllers.rs (88%) rename src/{appv2 => app}/features/favorite/entities.rs (95%) rename src/{appv2 => app}/features/favorite/mod.rs (100%) rename src/{appv2 => app}/features/favorite/presenters.rs (74%) rename src/{appv2 => app}/features/favorite/repositories.rs (92%) rename src/{appv2 => app}/features/favorite/usecases.rs (92%) rename src/{appv2 => app}/features/follow/entities.rs (97%) rename src/{appv2 => app}/features/follow/mod.rs (100%) rename src/{appv2 => app}/features/healthcheck/controllers.rs (100%) rename src/{appv2 => app}/features/healthcheck/mod.rs (100%) rename src/{appv2 => app}/features/mod.rs (100%) rename src/{appv2 => app}/features/profile/controllers.rs (94%) rename src/{appv2 => app}/features/profile/entities.rs (100%) rename src/{appv2 => app}/features/profile/mod.rs (100%) rename src/{appv2 => app}/features/profile/presenters.rs (100%) rename src/{appv2 => app}/features/profile/repositories.rs (94%) rename src/{appv2 => app}/features/profile/usecases.rs (93%) rename src/{appv2 => app}/features/tag/controllers.rs (76%) rename src/{appv2 => app}/features/tag/entities.rs (98%) rename src/{appv2 => app}/features/tag/mod.rs (100%) rename src/{appv2 => app}/features/tag/presenters.rs (100%) rename src/{appv2 => app}/features/tag/repositories.rs (100%) rename src/{appv2 => app}/features/tag/usecases.rs (100%) rename src/{appv2 => app}/features/user/controllers.rs (92%) rename src/{appv2 => app}/features/user/entities.rs (97%) rename src/{appv2 => app}/features/user/mod.rs (100%) rename src/{appv2 => app}/features/user/presenters.rs (96%) rename src/{appv2 => app}/features/user/repositories.rs (94%) rename src/{appv2 => app}/features/user/requests.rs (100%) rename src/{appv2 => app}/features/user/usecases.rs (100%) rename src/{appv2 => app}/mod.rs (100%) delete mode 100644 src/appv2/drivers/routes.rs diff --git a/src/appv2/drivers/middlewares/auth.rs b/src/app/drivers/middlewares/auth.rs similarity index 98% rename from src/appv2/drivers/middlewares/auth.rs rename to src/app/drivers/middlewares/auth.rs index 20878d2..502cb39 100644 --- a/src/appv2/drivers/middlewares/auth.rs +++ b/src/app/drivers/middlewares/auth.rs @@ -1,5 +1,5 @@ -use crate::appv2::drivers::middlewares::state::AppState; -use crate::appv2::features::user::entities::User; +use crate::app::drivers::middlewares::state::AppState; +use crate::app::features::user::entities::User; use crate::constants; use crate::error::AppError; use crate::utils::token; diff --git a/src/appv2/drivers/middlewares/cors.rs b/src/app/drivers/middlewares/cors.rs similarity index 100% rename from src/appv2/drivers/middlewares/cors.rs rename to src/app/drivers/middlewares/cors.rs diff --git a/src/appv2/drivers/middlewares/error.rs b/src/app/drivers/middlewares/error.rs similarity index 100% rename from src/appv2/drivers/middlewares/error.rs rename to src/app/drivers/middlewares/error.rs diff --git a/src/appv2/drivers/middlewares/mod.rs b/src/app/drivers/middlewares/mod.rs similarity index 100% rename from src/appv2/drivers/middlewares/mod.rs rename to src/app/drivers/middlewares/mod.rs diff --git a/src/appv2/drivers/middlewares/state.rs b/src/app/drivers/middlewares/state.rs similarity index 100% rename from src/appv2/drivers/middlewares/state.rs rename to src/app/drivers/middlewares/state.rs diff --git a/src/appv2/drivers/mod.rs b/src/app/drivers/mod.rs similarity index 100% rename from src/appv2/drivers/mod.rs rename to src/app/drivers/mod.rs diff --git a/src/app/drivers/routes.rs b/src/app/drivers/routes.rs new file mode 100644 index 0000000..8951eb3 --- /dev/null +++ b/src/app/drivers/routes.rs @@ -0,0 +1,80 @@ +use crate::app; +use actix_web::web; +use actix_web::web::{delete, get, post, put}; + +pub fn api(cfg: &mut web::ServiceConfig) { + cfg.service( + web::scope("/api") + .service( + web::scope("/healthcheck") + .route("", get().to(app::features::healthcheck::controllers::index)), + ) + .service( + web::scope("/tags").route("", get().to(app::features::tag::controllers::index)), + ) + .service( + web::scope("/users") + .route( + "/login", + post().to(app::features::user::controllers::signin), + ) + .route("", post().to(app::features::user::controllers::signup)), + ) + .service( + web::scope("/user") + .route("", get().to(app::features::user::controllers::me)) + .route("", put().to(app::features::user::controllers::update)), + ) + .service( + web::scope("/profiles") + .route( + "/{username}", + get().to(app::features::profile::controllers::show), + ) + .route( + "/{username}/follow", + post().to(app::features::profile::controllers::follow), + ) + .route( + "/{username}/follow", + delete().to(app::features::profile::controllers::unfollow), + ), + ) + .service( + web::scope("/articles") + .route("/feed", get().to(app::features::article::controllers::feed)) + .route("", get().to(app::features::article::controllers::index)) + .route("", post().to(app::features::article::controllers::create)) + .service( + web::scope("/{article_title_slug}") + .route("", get().to(app::features::article::controllers::show)) + .route("", put().to(app::features::article::controllers::update)) + .route("", delete().to(app::features::article::controllers::delete)) + .service( + web::scope("/favorite") + .route( + "", + post().to(app::features::favorite::controllers::favorite), + ) + .route( + "", + delete() + .to(app::features::favorite::controllers::unfavorite), + ), + ) + .service( + web::scope("/comments") + .route("", get().to(app::features::comment::controllers::index)) + .route( + "", + post().to(app::features::comment::controllers::create), + ) + .route( + "/{comment_id}", + delete().to(app::features::comment::controllers::delete), + ), + ), + ), + ), + ); +} diff --git a/src/appv2/features/article/controllers.rs b/src/app/features/article/controllers.rs similarity index 97% rename from src/appv2/features/article/controllers.rs rename to src/app/features/article/controllers.rs index edb9857..f1d2b69 100644 --- a/src/appv2/features/article/controllers.rs +++ b/src/app/features/article/controllers.rs @@ -8,8 +8,8 @@ use super::{ UpdateArticleUsecaseInput, }, }; -use crate::appv2::drivers::middlewares::auth; -use crate::appv2::drivers::middlewares::state::AppState; +use crate::app::drivers::middlewares::auth; +use crate::app::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest, HttpResponse}; use serde::Deserialize; diff --git a/src/appv2/features/article/entities.rs b/src/app/features/article/entities.rs similarity index 97% rename from src/appv2/features/article/entities.rs rename to src/app/features/article/entities.rs index 2816d52..7aff2e6 100644 --- a/src/appv2/features/article/entities.rs +++ b/src/app/features/article/entities.rs @@ -1,5 +1,5 @@ -use crate::appv2::features::favorite::entities::Favorite; -use crate::appv2::features::user::entities::User; +use crate::app::features::favorite::entities::Favorite; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::schema::articles; use crate::utils::converter; diff --git a/src/appv2/features/article/mod.rs b/src/app/features/article/mod.rs similarity index 100% rename from src/appv2/features/article/mod.rs rename to src/app/features/article/mod.rs diff --git a/src/appv2/features/article/presenters.rs b/src/app/features/article/presenters.rs similarity index 96% rename from src/appv2/features/article/presenters.rs rename to src/app/features/article/presenters.rs index d60edad..76e171e 100644 --- a/src/appv2/features/article/presenters.rs +++ b/src/app/features/article/presenters.rs @@ -1,7 +1,7 @@ use super::{entities::Article, repositories::ArticlesList}; -use crate::appv2::features::favorite::entities::FavoriteInfo; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::Tag; +use crate::app::features::favorite::entities::FavoriteInfo; +use crate::app::features::profile::entities::Profile; +use crate::app::features::tag::entities::Tag; use crate::utils::date::Iso8601; use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; diff --git a/src/appv2/features/article/repositories.rs b/src/app/features/article/repositories.rs similarity index 94% rename from src/appv2/features/article/repositories.rs rename to src/app/features/article/repositories.rs index 7e9d2f2..129ebdc 100644 --- a/src/appv2/features/article/repositories.rs +++ b/src/app/features/article/repositories.rs @@ -1,8 +1,8 @@ use super::entities::{Article, CreateArticle, DeleteArticle, UpdateArticle}; -use crate::appv2::features::favorite::entities::FavoriteInfo; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::{CreateTag, Tag}; -use crate::appv2::features::user::entities::User; +use crate::app::features::favorite::entities::FavoriteInfo; +use crate::app::features::profile::entities::Profile; +use crate::app::features::tag::entities::{CreateTag, Tag}; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; use diesel::PgConnection; @@ -75,12 +75,12 @@ impl ArticleRepository for ArticleRepositoryImpl { &self, params: FetchArticlesListRepositoryInput, ) -> Result<(ArticlesList, ArticlesCount), AppError> { - use crate::appv2::features::article::entities::Article; - use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; - use crate::appv2::features::follow::entities::Follow; - use crate::appv2::features::profile::entities::Profile; - use crate::appv2::features::tag::entities::Tag; - use crate::appv2::features::user::entities::User; + use crate::app::features::article::entities::Article; + use crate::app::features::favorite::entities::{Favorite, FavoriteInfo}; + use crate::app::features::follow::entities::Follow; + use crate::app::features::profile::entities::Profile; + use crate::app::features::tag::entities::Tag; + use crate::app::features::user::entities::User; use crate::error::AppError; use crate::schema::articles::dsl::*; use crate::schema::{articles, tags, users}; @@ -334,12 +334,12 @@ impl ArticleRepository for ArticleRepositoryImpl { &self, params: &FetchFollowingArticlesRepositoryInput, ) -> Result<(ArticlesList, ArticlesCount), AppError> { - use crate::appv2::features::article::entities::Article; - use crate::appv2::features::favorite::entities::{Favorite, FavoriteInfo}; - use crate::appv2::features::follow::entities::Follow; - use crate::appv2::features::profile::entities::Profile; - use crate::appv2::features::tag::entities::Tag; - use crate::appv2::features::user::entities::User; + use crate::app::features::article::entities::Article; + use crate::app::features::favorite::entities::{Favorite, FavoriteInfo}; + use crate::app::features::follow::entities::Follow; + use crate::app::features::profile::entities::Profile; + use crate::app::features::tag::entities::Tag; + use crate::app::features::user::entities::User; use crate::error::AppError; use crate::schema::articles::dsl::*; use crate::schema::follows; diff --git a/src/appv2/features/article/requests.rs b/src/app/features/article/requests.rs similarity index 100% rename from src/appv2/features/article/requests.rs rename to src/app/features/article/requests.rs diff --git a/src/appv2/features/article/usecases.rs b/src/app/features/article/usecases.rs similarity index 98% rename from src/appv2/features/article/usecases.rs rename to src/app/features/article/usecases.rs index d144fdc..6a97312 100644 --- a/src/appv2/features/article/usecases.rs +++ b/src/app/features/article/usecases.rs @@ -5,7 +5,7 @@ use super::repositories::{ FetchArticlesListRepositoryInput, FetchFollowingArticlesRepositoryInput, UpdateArticleRepositoryInput, }; -use crate::appv2::features::user::entities::User; +use crate::app::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; use std::sync::Arc; diff --git a/src/appv2/features/comment/controllers.rs b/src/app/features/comment/controllers.rs similarity index 92% rename from src/appv2/features/comment/controllers.rs rename to src/app/features/comment/controllers.rs index eb54183..b731c73 100644 --- a/src/appv2/features/comment/controllers.rs +++ b/src/app/features/comment/controllers.rs @@ -1,6 +1,6 @@ use super::request; -use crate::appv2::drivers::middlewares::auth; -use crate::appv2::drivers::middlewares::state::AppState; +use crate::app::drivers::middlewares::auth; +use crate::app::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use crate::utils::uuid; use actix_web::{web, HttpRequest}; diff --git a/src/appv2/features/comment/entities.rs b/src/app/features/comment/entities.rs similarity index 94% rename from src/appv2/features/comment/entities.rs rename to src/app/features/comment/entities.rs index c85a741..1f83934 100644 --- a/src/appv2/features/comment/entities.rs +++ b/src/app/features/comment/entities.rs @@ -1,5 +1,5 @@ -use crate::appv2::features::article::entities::Article; -use crate::appv2::features::user::entities::User; +use crate::app::features::article::entities::Article; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::schema::comments; use chrono::NaiveDateTime; diff --git a/src/appv2/features/comment/mod.rs b/src/app/features/comment/mod.rs similarity index 100% rename from src/appv2/features/comment/mod.rs rename to src/app/features/comment/mod.rs diff --git a/src/appv2/features/comment/presenters.rs b/src/app/features/comment/presenters.rs similarity index 96% rename from src/appv2/features/comment/presenters.rs rename to src/app/features/comment/presenters.rs index c065e35..3be869f 100644 --- a/src/appv2/features/comment/presenters.rs +++ b/src/app/features/comment/presenters.rs @@ -1,5 +1,5 @@ -use crate::appv2::features::comment::entities::Comment; -use crate::appv2::features::profile::entities::Profile; +use crate::app::features::comment::entities::Comment; +use crate::app::features::profile::entities::Profile; use crate::utils::date::Iso8601; use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; diff --git a/src/appv2/features/comment/repositories.rs b/src/app/features/comment/repositories.rs similarity index 99% rename from src/appv2/features/comment/repositories.rs rename to src/app/features/comment/repositories.rs index 2a0a557..d2cce2a 100644 --- a/src/appv2/features/comment/repositories.rs +++ b/src/app/features/comment/repositories.rs @@ -1,6 +1,6 @@ use super::entities::{Comment, CreateComment, DeleteComment}; use crate::{ - appv2::features::{ + app::features::{ article::entities::{Article, FetchBySlugAndAuthorId}, profile::entities::Profile, user::entities::User, diff --git a/src/appv2/features/comment/request.rs b/src/app/features/comment/request.rs similarity index 100% rename from src/appv2/features/comment/request.rs rename to src/app/features/comment/request.rs diff --git a/src/appv2/features/comment/usecases.rs b/src/app/features/comment/usecases.rs similarity index 96% rename from src/appv2/features/comment/usecases.rs rename to src/app/features/comment/usecases.rs index 0e51a9b..d74d1dd 100644 --- a/src/appv2/features/comment/usecases.rs +++ b/src/app/features/comment/usecases.rs @@ -1,6 +1,6 @@ use super::presenters::CommentPresenter; use super::repositories::CommentRepository; -use crate::appv2::features::user::entities::User; +use crate::app::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; use std::sync::Arc; diff --git a/src/appv2/features/favorite/controllers.rs b/src/app/features/favorite/controllers.rs similarity index 88% rename from src/appv2/features/favorite/controllers.rs rename to src/app/features/favorite/controllers.rs index 8665fff..925f2b6 100644 --- a/src/appv2/features/favorite/controllers.rs +++ b/src/app/features/favorite/controllers.rs @@ -1,5 +1,5 @@ -use crate::appv2::drivers::middlewares::auth; -use crate::appv2::drivers::middlewares::state::AppState; +use crate::app::drivers::middlewares::auth; +use crate::app::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest}; diff --git a/src/appv2/features/favorite/entities.rs b/src/app/features/favorite/entities.rs similarity index 95% rename from src/appv2/features/favorite/entities.rs rename to src/app/features/favorite/entities.rs index 8d10943..582f35a 100644 --- a/src/appv2/features/favorite/entities.rs +++ b/src/app/features/favorite/entities.rs @@ -1,5 +1,5 @@ -use crate::appv2::features::article::entities::Article; -use crate::appv2::features::user::entities::User; +use crate::app::features::article::entities::Article; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::schema::favorites; use chrono::NaiveDateTime; diff --git a/src/appv2/features/favorite/mod.rs b/src/app/features/favorite/mod.rs similarity index 100% rename from src/appv2/features/favorite/mod.rs rename to src/app/features/favorite/mod.rs diff --git a/src/appv2/features/favorite/presenters.rs b/src/app/features/favorite/presenters.rs similarity index 74% rename from src/appv2/features/favorite/presenters.rs rename to src/app/features/favorite/presenters.rs index 6e1ed16..86fe1a2 100644 --- a/src/appv2/features/favorite/presenters.rs +++ b/src/app/features/favorite/presenters.rs @@ -1,8 +1,8 @@ use super::entities::FavoriteInfo; -use crate::appv2::features::article::entities::Article; -pub use crate::appv2::features::article::presenters::SingleArticleResponse; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::tag::entities::Tag; +use crate::app::features::article::entities::Article; +pub use crate::app::features::article::presenters::SingleArticleResponse; +use crate::app::features::profile::entities::Profile; +use crate::app::features::tag::entities::Tag; use actix_web::HttpResponse; pub trait FavoritePresenter: Send + Sync + 'static { diff --git a/src/appv2/features/favorite/repositories.rs b/src/app/features/favorite/repositories.rs similarity index 92% rename from src/appv2/features/favorite/repositories.rs rename to src/app/features/favorite/repositories.rs index 25c5763..2553c89 100644 --- a/src/appv2/features/favorite/repositories.rs +++ b/src/app/features/favorite/repositories.rs @@ -1,6 +1,6 @@ use super::entities::{CreateFavorite, DeleteFavorite, Favorite}; -use crate::appv2::features::article::entities::{Article, FetchBySlugAndAuthorId}; -use crate::appv2::features::user::entities::User; +use crate::app::features::article::entities::{Article, FetchBySlugAndAuthorId}; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; diff --git a/src/appv2/features/favorite/usecases.rs b/src/app/features/favorite/usecases.rs similarity index 92% rename from src/appv2/features/favorite/usecases.rs rename to src/app/features/favorite/usecases.rs index 267cf21..bb431ce 100644 --- a/src/appv2/features/favorite/usecases.rs +++ b/src/app/features/favorite/usecases.rs @@ -1,9 +1,7 @@ use super::presenters::FavoritePresenter; use super::repositories::FavoriteRepository; -use crate::appv2::features::article::repositories::{ - ArticleRepository, FetchArticleRepositoryInput, -}; -use crate::appv2::features::user::entities::User; +use crate::app::features::article::repositories::{ArticleRepository, FetchArticleRepositoryInput}; +use crate::app::features::user::entities::User; use crate::error::AppError; use actix_web::HttpResponse; use std::sync::Arc; diff --git a/src/appv2/features/follow/entities.rs b/src/app/features/follow/entities.rs similarity index 97% rename from src/appv2/features/follow/entities.rs rename to src/app/features/follow/entities.rs index 59acb85..89ddb1e 100644 --- a/src/appv2/features/follow/entities.rs +++ b/src/app/features/follow/entities.rs @@ -1,4 +1,4 @@ -use crate::appv2::features::user::entities::User; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::schema::follows; use chrono::NaiveDateTime; diff --git a/src/appv2/features/follow/mod.rs b/src/app/features/follow/mod.rs similarity index 100% rename from src/appv2/features/follow/mod.rs rename to src/app/features/follow/mod.rs diff --git a/src/appv2/features/healthcheck/controllers.rs b/src/app/features/healthcheck/controllers.rs similarity index 100% rename from src/appv2/features/healthcheck/controllers.rs rename to src/app/features/healthcheck/controllers.rs diff --git a/src/appv2/features/healthcheck/mod.rs b/src/app/features/healthcheck/mod.rs similarity index 100% rename from src/appv2/features/healthcheck/mod.rs rename to src/app/features/healthcheck/mod.rs diff --git a/src/appv2/features/mod.rs b/src/app/features/mod.rs similarity index 100% rename from src/appv2/features/mod.rs rename to src/app/features/mod.rs diff --git a/src/appv2/features/profile/controllers.rs b/src/app/features/profile/controllers.rs similarity index 94% rename from src/appv2/features/profile/controllers.rs rename to src/app/features/profile/controllers.rs index 919cc1d..628cee8 100644 --- a/src/appv2/features/profile/controllers.rs +++ b/src/app/features/profile/controllers.rs @@ -1,4 +1,4 @@ -use crate::appv2::drivers::middlewares::{auth, state::AppState}; +use crate::app::drivers::middlewares::{auth, state::AppState}; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest}; diff --git a/src/appv2/features/profile/entities.rs b/src/app/features/profile/entities.rs similarity index 100% rename from src/appv2/features/profile/entities.rs rename to src/app/features/profile/entities.rs diff --git a/src/appv2/features/profile/mod.rs b/src/app/features/profile/mod.rs similarity index 100% rename from src/appv2/features/profile/mod.rs rename to src/app/features/profile/mod.rs diff --git a/src/appv2/features/profile/presenters.rs b/src/app/features/profile/presenters.rs similarity index 100% rename from src/appv2/features/profile/presenters.rs rename to src/app/features/profile/presenters.rs diff --git a/src/appv2/features/profile/repositories.rs b/src/app/features/profile/repositories.rs similarity index 94% rename from src/appv2/features/profile/repositories.rs rename to src/app/features/profile/repositories.rs index edf7c58..a1ee8a7 100644 --- a/src/appv2/features/profile/repositories.rs +++ b/src/app/features/profile/repositories.rs @@ -1,5 +1,5 @@ use super::entities::Profile; -use crate::appv2::features::user::entities::User; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; diff --git a/src/appv2/features/profile/usecases.rs b/src/app/features/profile/usecases.rs similarity index 93% rename from src/appv2/features/profile/usecases.rs rename to src/app/features/profile/usecases.rs index 74b81cc..db6e262 100644 --- a/src/appv2/features/profile/usecases.rs +++ b/src/app/features/profile/usecases.rs @@ -1,7 +1,7 @@ use super::presenters::ProfilePresenter; use super::repositories::ProfileRepository; -use crate::appv2::features::user::entities::User; -use crate::appv2::features::user::repositories::UserRepository; +use crate::app::features::user::entities::User; +use crate::app::features::user::repositories::UserRepository; use crate::error::AppError; use actix_web::HttpResponse; use std::sync::Arc; diff --git a/src/appv2/features/tag/controllers.rs b/src/app/features/tag/controllers.rs similarity index 76% rename from src/appv2/features/tag/controllers.rs rename to src/app/features/tag/controllers.rs index 1502c7a..edc4e69 100644 --- a/src/appv2/features/tag/controllers.rs +++ b/src/app/features/tag/controllers.rs @@ -1,5 +1,5 @@ extern crate serde_json; -use crate::appv2::drivers::middlewares::state::AppState; +use crate::app::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::web; diff --git a/src/appv2/features/tag/entities.rs b/src/app/features/tag/entities.rs similarity index 98% rename from src/appv2/features/tag/entities.rs rename to src/app/features/tag/entities.rs index 6637472..d1755a0 100644 --- a/src/appv2/features/tag/entities.rs +++ b/src/app/features/tag/entities.rs @@ -1,4 +1,4 @@ -use crate::appv2::features::article::entities::Article; +use crate::app::features::article::entities::Article; use crate::error::AppError; use crate::schema::tags; use chrono::NaiveDateTime; diff --git a/src/appv2/features/tag/mod.rs b/src/app/features/tag/mod.rs similarity index 100% rename from src/appv2/features/tag/mod.rs rename to src/app/features/tag/mod.rs diff --git a/src/appv2/features/tag/presenters.rs b/src/app/features/tag/presenters.rs similarity index 100% rename from src/appv2/features/tag/presenters.rs rename to src/app/features/tag/presenters.rs diff --git a/src/appv2/features/tag/repositories.rs b/src/app/features/tag/repositories.rs similarity index 100% rename from src/appv2/features/tag/repositories.rs rename to src/app/features/tag/repositories.rs diff --git a/src/appv2/features/tag/usecases.rs b/src/app/features/tag/usecases.rs similarity index 100% rename from src/appv2/features/tag/usecases.rs rename to src/app/features/tag/usecases.rs diff --git a/src/appv2/features/user/controllers.rs b/src/app/features/user/controllers.rs similarity index 92% rename from src/appv2/features/user/controllers.rs rename to src/app/features/user/controllers.rs index c66ffe9..b8e7a1c 100644 --- a/src/appv2/features/user/controllers.rs +++ b/src/app/features/user/controllers.rs @@ -1,7 +1,7 @@ use super::entities::UpdateUser; use super::requests; -use crate::appv2::drivers::middlewares::auth; -use crate::appv2::drivers::middlewares::state::AppState; +use crate::app::drivers::middlewares::auth; +use crate::app::drivers::middlewares::state::AppState; use crate::utils::api::ApiResponse; use actix_web::{web, HttpRequest}; diff --git a/src/appv2/features/user/entities.rs b/src/app/features/user/entities.rs similarity index 97% rename from src/appv2/features/user/entities.rs rename to src/app/features/user/entities.rs index d5c0656..5b7aa8f 100644 --- a/src/appv2/features/user/entities.rs +++ b/src/app/features/user/entities.rs @@ -1,6 +1,6 @@ -use crate::appv2::features::favorite::entities::Favorite; -use crate::appv2::features::follow::entities::Follow; -use crate::appv2::features::profile::entities::Profile; +use crate::app::features::favorite::entities::Favorite; +use crate::app::features::follow::entities::Follow; +use crate::app::features::profile::entities::Profile; use crate::error::AppError; use crate::schema::users; use crate::utils::{hasher, token}; diff --git a/src/appv2/features/user/mod.rs b/src/app/features/user/mod.rs similarity index 100% rename from src/appv2/features/user/mod.rs rename to src/app/features/user/mod.rs diff --git a/src/appv2/features/user/presenters.rs b/src/app/features/user/presenters.rs similarity index 96% rename from src/appv2/features/user/presenters.rs rename to src/app/features/user/presenters.rs index 976312a..5967144 100644 --- a/src/appv2/features/user/presenters.rs +++ b/src/app/features/user/presenters.rs @@ -1,4 +1,4 @@ -use crate::appv2::features::user::entities::User; +use crate::app::features::user::entities::User; use actix_web::HttpResponse; use serde::{Deserialize, Serialize}; use std::convert::From; diff --git a/src/appv2/features/user/repositories.rs b/src/app/features/user/repositories.rs similarity index 94% rename from src/appv2/features/user/repositories.rs rename to src/app/features/user/repositories.rs index 32aaae6..c45db55 100644 --- a/src/appv2/features/user/repositories.rs +++ b/src/app/features/user/repositories.rs @@ -1,7 +1,7 @@ use super::entities::UpdateUser; -use crate::appv2::features::follow::entities::{CreateFollow, DeleteFollow, Follow}; -use crate::appv2::features::profile::entities::Profile; -use crate::appv2::features::user::entities::User; +use crate::app::features::follow::entities::{CreateFollow, DeleteFollow, Follow}; +use crate::app::features::profile::entities::Profile; +use crate::app::features::user::entities::User; use crate::error::AppError; use crate::utils::db::DbPool; use uuid::Uuid; diff --git a/src/appv2/features/user/requests.rs b/src/app/features/user/requests.rs similarity index 100% rename from src/appv2/features/user/requests.rs rename to src/app/features/user/requests.rs diff --git a/src/appv2/features/user/usecases.rs b/src/app/features/user/usecases.rs similarity index 100% rename from src/appv2/features/user/usecases.rs rename to src/app/features/user/usecases.rs diff --git a/src/appv2/mod.rs b/src/app/mod.rs similarity index 100% rename from src/appv2/mod.rs rename to src/app/mod.rs diff --git a/src/appv2/drivers/routes.rs b/src/appv2/drivers/routes.rs deleted file mode 100644 index fd67cab..0000000 --- a/src/appv2/drivers/routes.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::appv2; -use actix_web::web; -use actix_web::web::{delete, get, post, put}; - -pub fn api(cfg: &mut web::ServiceConfig) { - cfg.service( - web::scope("/api") - .service(web::scope("/healthcheck").route( - "", - get().to(appv2::features::healthcheck::controllers::index), - )) - .service( - web::scope("/tags").route("", get().to(appv2::features::tag::controllers::index)), - ) - .service( - web::scope("/users") - .route( - "/login", - post().to(appv2::features::user::controllers::signin), - ) - .route("", post().to(appv2::features::user::controllers::signup)), - ) - .service( - web::scope("/user") - .route("", get().to(appv2::features::user::controllers::me)) - .route("", put().to(appv2::features::user::controllers::update)), - ) - .service( - web::scope("/profiles") - .route( - "/{username}", - get().to(appv2::features::profile::controllers::show), - ) - .route( - "/{username}/follow", - post().to(appv2::features::profile::controllers::follow), - ) - .route( - "/{username}/follow", - delete().to(appv2::features::profile::controllers::unfollow), - ), - ) - .service( - web::scope("/articles") - .route( - "/feed", - get().to(appv2::features::article::controllers::feed), - ) - .route("", get().to(appv2::features::article::controllers::index)) - .route("", post().to(appv2::features::article::controllers::create)) - .service( - web::scope("/{article_title_slug}") - .route("", get().to(appv2::features::article::controllers::show)) - .route("", put().to(appv2::features::article::controllers::update)) - .route( - "", - delete().to(appv2::features::article::controllers::delete), - ) - .service( - web::scope("/favorite") - .route( - "", - post().to(appv2::features::favorite::controllers::favorite), - ) - .route( - "", - delete() - .to(appv2::features::favorite::controllers::unfavorite), - ), - ) - .service( - web::scope("/comments") - .route( - "", - get().to(appv2::features::comment::controllers::index), - ) - .route( - "", - post().to(appv2::features::comment::controllers::create), - ) - .route( - "/{comment_id}", - delete().to(appv2::features::comment::controllers::delete), - ), - ), - ), - ), - ); -} diff --git a/src/main.rs b/src/main.rs index 98dcf6d..c662ebf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ extern crate log; use actix_web::middleware::Logger; use actix_web::{App, HttpServer}; -mod appv2; +mod app; mod constants; mod error; mod schema; @@ -20,7 +20,7 @@ async fn main() -> std::io::Result<()> { let state = { let pool = utils::db::establish_connection(); - use appv2::drivers::middlewares::state::AppState; + use app::drivers::middlewares::state::AppState; AppState::new(pool) }; @@ -28,9 +28,9 @@ async fn main() -> std::io::Result<()> { App::new() .wrap(Logger::default()) .app_data(actix_web::web::Data::new(state.clone())) - .wrap(appv2::drivers::middlewares::cors::cors()) - .wrap(appv2::drivers::middlewares::auth::Authentication) - .configure(appv2::drivers::routes::api) + .wrap(app::drivers::middlewares::cors::cors()) + .wrap(app::drivers::middlewares::auth::Authentication) + .configure(app::drivers::routes::api) }) .bind(constants::BIND)? .run() diff --git a/src/utils/di.rs b/src/utils/di.rs index e44df6e..eaa9e58 100644 --- a/src/utils/di.rs +++ b/src/utils/di.rs @@ -1,21 +1,21 @@ -use crate::appv2::features::article::presenters::ArticlePresenterImpl; -use crate::appv2::features::article::repositories::ArticleRepositoryImpl; -use crate::appv2::features::article::usecases::ArticleUsecase; -use crate::appv2::features::comment::presenters::CommentPresenterImpl; -use crate::appv2::features::comment::repositories::CommentRepositoryImpl; -use crate::appv2::features::comment::usecases::CommentUsecase; -use crate::appv2::features::favorite::presenters::FavoritePresenterImpl; -use crate::appv2::features::favorite::repositories::FavoriteRepositoryImpl; -use crate::appv2::features::favorite::usecases::FavoriteUsecase; -use crate::appv2::features::profile::presenters::ProfilePresenterImpl; -use crate::appv2::features::profile::repositories::ProfileRepositoryImpl; -use crate::appv2::features::profile::usecases::ProfileUsecase; -use crate::appv2::features::tag::presenters::TagPresenterImpl; -use crate::appv2::features::tag::repositories::TagRepositoryImpl; -use crate::appv2::features::tag::usecases::TagUsecase; -use crate::appv2::features::user::presenters::UserPresenterImpl; -use crate::appv2::features::user::repositories::UserRepositoryImpl; -use crate::appv2::features::user::usecases::UserUsecase; +use crate::app::features::article::presenters::ArticlePresenterImpl; +use crate::app::features::article::repositories::ArticleRepositoryImpl; +use crate::app::features::article::usecases::ArticleUsecase; +use crate::app::features::comment::presenters::CommentPresenterImpl; +use crate::app::features::comment::repositories::CommentRepositoryImpl; +use crate::app::features::comment::usecases::CommentUsecase; +use crate::app::features::favorite::presenters::FavoritePresenterImpl; +use crate::app::features::favorite::repositories::FavoriteRepositoryImpl; +use crate::app::features::favorite::usecases::FavoriteUsecase; +use crate::app::features::profile::presenters::ProfilePresenterImpl; +use crate::app::features::profile::repositories::ProfileRepositoryImpl; +use crate::app::features::profile::usecases::ProfileUsecase; +use crate::app::features::tag::presenters::TagPresenterImpl; +use crate::app::features::tag::repositories::TagRepositoryImpl; +use crate::app::features::tag::usecases::TagUsecase; +use crate::app::features::user::presenters::UserPresenterImpl; +use crate::app::features::user::repositories::UserRepositoryImpl; +use crate::app::features::user::usecases::UserUsecase; use std::sync::Arc; use crate::utils::db::DbPool; From fd7bc0e8394dcbaa43201256d6f56b4427f8e9cd Mon Sep 17 00:00:00 2001 From: snamiki1212 Date: Tue, 13 Jun 2023 15:20:46 +0900 Subject: [PATCH 59/59] fix: update architecture section on readme --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 05f15ba..3f57e7b 100644 --- a/README.md +++ b/README.md @@ -68,35 +68,35 @@ $ APIURL=http://localhost:8080/api zsh e2e/run-api-tests.sh ## Architecture -TODO: - - Clean Architecture - - drivers - - adapters - - domains - - entities - - usecases - -### Flow from Request to Response +- DI container using Constructor Injection with dynamic dispatch (`/src/di.rs`) ```mermaid sequenceDiagram actor Client - participant Middleware as Middleware
/middleware/* - participant Controller as Controller
/[feature]/api.rs - participant Service as Service
/[feature]/service.rs + autonumber + participant Route as Middleware + Route

/src/app/drivers/{middlewares, routes} + participant Controller as Controller

/src/app/features/[feature]/controllers.rs + participant Presenter as Presenter

/src/app/features/[feature]/presenters.rs + participant Usecase as Usecase

/src/app/features/[feature]/usecases.rs + participant Repository as Repository

/src/app/features/[feature]/repositories.rs + participant Entity as Entity

/src/app/features/[feature]/entities.rs participant DB - Client ->> Middleware: request - Middleware ->> Controller: - - Controller ->> Controller: Assign to Request Object
(/[feature]/request.rs) - Controller ->> Service: - - Service ->> DB: - - - DB ->> Service: - - Service ->> Controller: - - Controller ->> Controller: Convert into Response Object
(/[feature]/response.rs) - Controller ->> Client: response + %% left to right + Client -->> Route: Request + Route ->> Controller:
+ Controller ->> Usecase:
+ Usecase ->> Repository:
+ Repository ->> Entity:
+ Entity ->> DB:
+ + %% right to left + DB ->> Entity:
+ Entity ->> Repository:
+ Repository ->> Usecase:
+ Usecase ->> Presenter:
+ Presenter -->> Client: Response ``` ## LICENSE