Skip to content

Commit

Permalink
Merge pull request #6 from KaioFelps/dev
Browse files Browse the repository at this point in the history
Added article tag controller & routes
  • Loading branch information
KaioFelps authored Jul 21, 2024
2 parents 09406c1 + 259e4f5 commit bb31472
Show file tree
Hide file tree
Showing 14 changed files with 229 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/domain/factories/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub mod update_team_user_service_factory;
pub mod delete_team_user_service_factory;
pub mod fetch_many_team_users_service_factory;
pub mod fetch_many_comments_with_author_service_factory;
mod create_article_tag_service_factory;
pub mod create_article_tag_service_factory;
pub mod update_article_tag_service_factory;
pub mod fetch_many_article_tags_service_factory;
pub mod delete_article_tag_service_factory;
4 changes: 2 additions & 2 deletions src/domain/services/create_article_tag_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use crate::util::{generate_service_internal_error, RolePermissions, verify_role_
use crate::errors::error::DomainErrorTrait;

pub struct CreateArticleTagParams {
value: String,
user_role: Role,
pub value: String,
pub user_role: Role,
}

pub struct CreateArticleTagService<ArticleTagRepository: ArticleTagRepositoryTrait> {
Expand Down
4 changes: 2 additions & 2 deletions src/domain/services/delete_article_tag_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::errors::unauthorized_error::UnauthorizedError;
use crate::util::{generate_service_internal_error, RolePermissions, verify_role_has_permission};

pub struct DeleteArticleTagParams<'run> {
user_role: &'run Role,
tag_id: i32,
pub user_role: &'run Role,
pub tag_id: i32,
}

pub struct DeleteArticleTagService<ArticleTagRepository: ArticleTagRepositoryTrait> {
Expand Down
1 change: 1 addition & 0 deletions src/domain/services/fetch_many_article_tags_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct FetchManyArticleTagsParams {
pub query: Option<String>,
}

#[derive(Debug)]
pub struct FetchManyArticleTagsResponse {
pub data: Vec<ArticleTag>,
pub pagination: PaginationResponse
Expand Down
6 changes: 3 additions & 3 deletions src/domain/services/update_article_tag_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use crate::errors::unauthorized_error::UnauthorizedError;
use crate::util::{generate_service_internal_error, RolePermissions, verify_role_has_permission};

pub struct UpdateArticleTagParams {
user_role: Role,
value: Option<String>,
tag_id: i32,
pub user_role: Role,
pub value: Option<String>,
pub tag_id: i32,
}

pub struct UpdateArticleTagService<ArticleTagRepository: ArticleTagRepositoryTrait> {
Expand Down
165 changes: 165 additions & 0 deletions src/infra/http/controllers/article_tags_controller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
use actix_web::{web, HttpResponse, Responder};
use actix_web_lab::middleware::from_fn;
use either::{Left, Right};
use validator::Validate;
use crate::core::pagination::DEFAULT_PER_PAGE;
use super::controller::ControllerTrait;
use crate::domain::factories::{
delete_article_tag_service_factory,
fetch_many_article_tags_service_factory,
update_article_tag_service_factory,
create_article_tag_service_factory
};
use crate::domain::services::create_article_tag_service::CreateArticleTagParams;
use crate::domain::services::delete_article_tag_service::DeleteArticleTagParams;
use crate::domain::services::fetch_many_article_tags_service::FetchManyArticleTagsParams;
use crate::domain::services::update_article_tag_service::UpdateArticleTagParams;
use crate::infra::http::dtos::create_article_tag::CreateArticleTagDto;
use crate::infra::http::dtos::list_article_tags::ListArticleTagsDto;
use crate::infra::http::dtos::update_article_tag::UpdateArticleTagDto;
use crate::infra::http::extractors::req_user::ReqUser;
use crate::infra::http::middlewares::authentication_middleware;
use crate::infra::http::presenters::article_tag::{ArticleTagPresenter, MappedArticleTag};
use crate::infra::http::presenters::error::ErrorPresenter;
use crate::infra::http::presenters::pagination::PaginationPresenter;
use crate::infra::http::presenters::presenter::{JsonWrappedEntity, PresenterTrait};
use crate::util::generate_error_response;

pub struct ArticleTagsController;

impl ControllerTrait for ArticleTagsController {
fn register(cfg: &mut web::ServiceConfig) {
cfg.service(web::scope("/article_tags")
// CREATE
.route("/new", web::post().to(Self::create).wrap(from_fn(authentication_middleware)))

// READ
.route("/list", web::get().to(Self::list))

// UPDATE
.route("/{id}/update", web::put().to(Self::update).wrap(from_fn(authentication_middleware)))

// DELETE
.route("/{id}/delete", web::delete().to(Self::delete).wrap(from_fn(authentication_middleware)))
);
}
}

impl ArticleTagsController {
async fn create(body: web::Json<CreateArticleTagDto>, user: web::ReqData<ReqUser>) -> impl Responder {
match body.validate() {
Ok(()) => (),
Err(error) => return HttpResponse::BadRequest().json(ErrorPresenter::to_http_from_validator(error.field_errors())),
};

let body = body.into_inner();

let service = match create_article_tag_service_factory::exec().await {
Left(service) => service,
Right(error) => return error,
};

let result = service.exec(CreateArticleTagParams {
user_role: user.into_inner().user_role.unwrap(),
value: body.value
}).await;

if result.is_err() {
return generate_error_response(result.unwrap_err());
}

let article_tag = result.unwrap();
let mapped_article_tag = ArticleTagPresenter::to_http(article_tag);

return HttpResponse::Created().json(JsonWrappedEntity {
data: mapped_article_tag
});
}

async fn list(query: web::Query<ListArticleTagsDto>) -> impl Responder {
match query.validate() {
Ok(()) => (),
Err(error) => return HttpResponse::BadRequest().json(ErrorPresenter::to_http_from_validator(error.field_errors())),
};

let ListArticleTagsDto {
page,
per_page,
value
} = query.into_inner();

let service = match fetch_many_article_tags_service_factory::exec().await {
Left(service) => service,
Right(error) => return error,
};

let result = service.exec(FetchManyArticleTagsParams {
per_page: if per_page.is_none() { None } else { Some(per_page.unwrap() as u32) },
query: value,
page
}).await;

if result.is_err() {
return generate_error_response(result.unwrap_err());
}

let service_response = result.unwrap();
let mapped_article_tags = service_response.data.into_iter().map(ArticleTagPresenter::to_http).collect::<Vec<MappedArticleTag>>();
let mapped_pagination = PaginationPresenter::to_http(service_response.pagination, per_page.unwrap_or(DEFAULT_PER_PAGE));

return HttpResponse::Ok().json(ArticleTagPresenter::to_json_paginated_wrapper(mapped_article_tags, mapped_pagination));
}

async fn update(
body: web::Json<UpdateArticleTagDto>,
user: web::ReqData<ReqUser>,
tag_id: web::Path<i32>
) -> impl Responder {
match body.validate() {
Ok(()) => (),
Err(error) => return HttpResponse::BadRequest().json(ErrorPresenter::to_http_from_validator(error.field_errors())),
};

let body = body.into_inner();

let service = match update_article_tag_service_factory::exec().await {
Left(service) => service,
Right(error) => return error,
};

let service_response = service.exec(UpdateArticleTagParams {
value: body.value,
tag_id: tag_id.into_inner(),
user_role: user.into_inner().user_role.unwrap(),
}).await;

if service_response.is_err() {
return generate_error_response(service_response.unwrap_err());
}

let article_tag = service_response.unwrap();
let mapped_article_tag = ArticleTagPresenter::to_http(article_tag);

return HttpResponse::NoContent().json(JsonWrappedEntity {
data: mapped_article_tag
});
}

async fn delete(user: web::ReqData<ReqUser>, tag_id: web::Path<i32>) -> impl Responder {
let service = match delete_article_tag_service_factory::exec().await {
Left(service) => service,
Right(error) => return error,
};

let service_response = service.exec(DeleteArticleTagParams {
user_role: user.user_role.as_ref().unwrap(),
tag_id: tag_id.into_inner()
}).await;

if service_response.is_err() {
return generate_error_response(service_response.unwrap_err());
}

return HttpResponse::NoContent().finish();
}
}
1 change: 1 addition & 0 deletions src/infra/http/controllers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod comments_controller;
pub mod comment_reports_controller;
pub mod team_roles_controller;
pub mod team_users_controller;
pub mod article_tags_controller;
8 changes: 8 additions & 0 deletions src/infra/http/dtos/create_article_tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use serde::{Deserialize, Serialize};
use validator::Validate;

#[derive(Serialize, Deserialize, Validate)]
pub struct CreateArticleTagDto {
#[validate(length(min=1, message = "Article tag can't be empty."))]
pub value: String
}
10 changes: 10 additions & 0 deletions src/infra/http/dtos/list_article_tags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};
use validator::Validate;

#[derive(Serialize, Deserialize, Validate)]
pub struct ListArticleTagsDto {
pub page: Option<u32>,
#[serde(rename="perPage")]
pub per_page: Option<u8>,
pub value: Option<String>,
}
3 changes: 3 additions & 0 deletions src/infra/http/dtos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ pub mod update_team_role;
pub mod create_team_user;
pub mod list_team_user;
pub mod update_team_user;
pub mod create_article_tag;
pub mod list_article_tags;
pub mod update_article_tag;
8 changes: 8 additions & 0 deletions src/infra/http/dtos/update_article_tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use serde::{Deserialize, Serialize};
use validator::Validate;

#[derive(Serialize, Deserialize, Validate)]
pub struct UpdateArticleTagDto {
#[validate(length(min=1, message="Article tag value must be at least one char long."))]
pub value: Option<String>,
}
22 changes: 22 additions & 0 deletions src/infra/http/presenters/article_tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use serde::{Serialize, Deserialize};
use crate::domain::domain_entities::article_tag::ArticleTag;
use crate::infra::http::presenters::presenter::PresenterTrait;

#[derive(Serialize, Deserialize)]
pub struct MappedArticleTag {
id: i32,
value: String,
}

pub struct ArticleTagPresenter;

impl PresenterTrait<ArticleTag, MappedArticleTag> for ArticleTagPresenter {
fn to_http(tag: ArticleTag) -> MappedArticleTag {
MappedArticleTag {
id: tag.id(),
value: tag.value().into()
}
}
}

impl ArticleTagPresenter {}
1 change: 1 addition & 0 deletions src/infra/http/presenters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pub mod comment_report;
pub mod presenter;
pub mod team_role;
pub mod team_user;
pub mod article_tag;
3 changes: 2 additions & 1 deletion src/infra/http/routes/api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use actix_web::web;

use crate::infra::http::controllers::article_tags_controller::ArticleTagsController;
use crate::infra::http::controllers::articles_controller::ArticlesController;
use crate::infra::http::controllers::comment_reports_controller::CommentReportsController;
use crate::infra::http::controllers::comments_controller::CommentsController;
Expand All @@ -25,6 +25,7 @@ impl RouteTrait for ApiRoutes {
.configure(CommentReportsController::register)
.configure(TeamRolesController::register)
.configure(TeamUsersController::register)
.configure(ArticleTagsController::register)
);
}
}

0 comments on commit bb31472

Please sign in to comment.