Added all routes actually

This commit is contained in:
Franklin 2023-05-09 18:55:39 -04:00
parent a27f2fcb9f
commit 2295e4b8f6
15 changed files with 393 additions and 150 deletions

View File

@ -5,6 +5,7 @@ use dao::main_dao;
mod dao; mod dao;
mod routes; mod routes;
mod services;
mod utils; mod utils;
#[tokio::main] #[tokio::main]

View File

@ -1,11 +1,19 @@
use std::sync::Arc;
use actix_web::{
post,
web::{self, Json},
};
use actix_web_utils::extensions::typed_response::TypedHttpResponse; use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{domain::click::Click, dto::payloads::click::ClickForCreationPayload}; use realtor_lp_types::{domain::click::Click, dto::payloads::click::ClickForCreationPayload};
use sqlx::PgPool; use sqlx::PgPool;
use crate::{dao, handle_db_write_op, handle_tx, success}; use crate::{dao, handle_db_write_op, handle_tx, services, success};
pub async fn new_click(conn: &PgPool, click: ClickForCreationPayload) -> TypedHttpResponse<()> { #[post("/click")]
let mut transaction = handle_tx!(conn.begin()); pub async fn new_click(
handle_db_write_op!(dao::click::insert_click(conn, click.into()), transaction); db_conn: web::Data<Arc<PgPool>>,
success!(()) click: Json<ClickForCreationPayload>,
) -> TypedHttpResponse<()> {
services::click::new_click(&db_conn, click.0).await
} }

View File

@ -13,6 +13,8 @@ use sqlx::PgPool;
use crate::utils::s3; use crate::utils::s3;
use super::{click, property, realtor, trackable, view};
pub const HOST_ADDR: &str = "0.0.0.0"; pub const HOST_ADDR: &str = "0.0.0.0";
pub const HOST_PORT: u16 = 8080; pub const HOST_PORT: u16 = 8080;
@ -30,8 +32,23 @@ pub async fn start_all_routes(start_time: i64, db_conn: Arc<PgPool>) -> Result<(
.app_data(MultipartFormConfig::default().memory_limit(52_428_800)) .app_data(MultipartFormConfig::default().memory_limit(52_428_800))
.service( .service(
web::scope("/api") web::scope("/api")
.service(web::scope("/admin")) .service(
.service(web::scope("/read")), web::scope("/admin")
.service(property::new_property)
.service(property::update_property)
.service(realtor::new_realtor_profile)
.service(realtor::update_realtor_profile),
)
.service(
web::scope("/public")
.service(click::new_click)
.service(property::fetch_realtor_properties_paged)
.service(realtor::get_realtor_by_shortcode)
.service(realtor::get_realtor_with_id)
.service(trackable::create_trackable_profile)
.service(trackable::validate_trackable_id)
.service(view::new_view),
),
) )
/*.service( /*.service(

View File

@ -1,3 +1,9 @@
use std::sync::Arc;
use actix_web::{
post,
web::{self, Json},
};
use actix_web_utils::extensions::typed_response::TypedHttpResponse; use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{ use realtor_lp_types::{
domain::project::Project, dto::payloads::project::ProjectForCreationPayload, domain::project::Project, dto::payloads::project::ProjectForCreationPayload,
@ -7,19 +13,12 @@ use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found}; use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found};
#[post("/project")]
pub async fn create_project( pub async fn create_project(
conn: &PgPool, db_conn: web::Data<Arc<PgPool>>,
project: ProjectForCreationPayload, project: Json<ProjectForCreationPayload>,
) -> TypedHttpResponse<Project> { ) -> TypedHttpResponse<Project> {
unwrap_or_not_found!( todo!()
handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &project.realtor_id)),
"Realtor"
);
let mut transaction = handle_tx!(conn.begin());
success!(handle_db_write_op!(
dao::project::insert_project(&mut transaction, project.into()),
transaction
));
} }
pub async fn fetch_realtor_projects( pub async fn fetch_realtor_projects(

View File

@ -1,100 +1,58 @@
use std::sync::Arc; use std::{collections::HashMap, sync::Arc};
use actix_web::{ use actix_web::{
get, get, post, put,
web::{Data, Path}, web::{self, Data, Json, Path},
}; };
use actix_web_utils::extensions::typed_response::TypedHttpResponse; use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use err::MessageResource; use err::MessageResource;
use realtor_lp_types::{ use realtor_lp_types::{
domain::property::Property, dto::payloads::property::PropertyForCreationPayload, domain::property::Property,
dto::{filter::Filter, payloads::property::PropertyForCreationPayload},
}; };
use sqlx::PgPool; use sqlx::PgPool;
use uuid::Uuid; use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found}; use crate::{
dao, handle_db_read_op, handle_db_write_op, handle_tx, services, success, unwrap_or_not_found,
};
pub async fn create_property( /// Admin
conn: &PgPool, #[post("/property")]
property: PropertyForCreationPayload, pub async fn new_property(
db_conn: web::Data<Arc<PgPool>>,
property: Json<PropertyForCreationPayload>,
) -> TypedHttpResponse<Property> { ) -> TypedHttpResponse<Property> {
let mut transaction = handle_tx!(conn.begin()); services::property::create_property(&db_conn, property.0).await
let realtor = unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_id(
conn,
&property.realtor_id
)),
"Realtor"
);
// Check for project existing
match property.project_id {
Some(project_id) => {
let project = unwrap_or_not_found!(
handle_db_read_op!(dao::project::get_project_with_id(conn, &project_id)),
"Project"
);
if project.realtor_id != realtor.id {
return TypedHttpResponse::return_standard_error(
400,
MessageResource::new_from_str(
"Realtor Id in project does not match realtor id in property.",
),
);
}
}
None => {}
};
success!(handle_db_write_op!(
dao::property::insert_property(&mut transaction, property.into()),
transaction
))
} }
pub async fn udpate_property( /// Admin
conn: &PgPool, #[put("/property/{property_id}")]
property_id: Uuid, pub async fn update_property(
property: PropertyForCreationPayload, db_conn: web::Data<Arc<PgPool>>,
property: Json<PropertyForCreationPayload>,
property_id: Path<Uuid>,
) -> TypedHttpResponse<Property> { ) -> TypedHttpResponse<Property> {
let mut transaction = handle_tx!(conn.begin()); services::property::udpate_property(&db_conn, *property_id, property.0).await
let realtor = unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_id(
conn,
&property.realtor_id
)),
"Realtor"
);
// Check for project existing
match property.project_id {
Some(project_id) => {
let project = unwrap_or_not_found!(
handle_db_read_op!(dao::project::get_project_with_id(conn, &project_id)),
"Project"
);
if project.realtor_id != realtor.id {
return TypedHttpResponse::return_standard_error(
400,
MessageResource::new_from_str(
"Realtor Id in project does not match realtor id in property.",
),
);
}
}
None => {}
};
let mut property_insertable: Property = property.into();
property_insertable.id = property_id;
success!(handle_db_write_op!(
dao::property::update_property(&mut transaction, property_insertable),
transaction
))
} }
#[get("/properties/{realtor_id}/{page}")] #[get("/properties/{realtor_id}/{page}")]
pub async fn fetch_realtor_properties_paged( pub async fn fetch_realtor_properties_paged(
conn: Data<Arc<PgPool>>, conn: Data<Arc<PgPool>>,
path_vars: Path<(Uuid, i64)>, path_vars: Path<(Uuid, i64)>,
query_params: web::Query<HashMap<String, String>>,
) -> TypedHttpResponse<Vec<Property>> { ) -> TypedHttpResponse<Vec<Property>> {
success!(Default::default()) let filters = parse_params_into_filters(query_params.0);
services::property::fetch_realtor_properties_paged(&conn, path_vars.0, path_vars.1, filters)
.await
}
fn parse_params_into_filters(params: HashMap<String, String>) -> Vec<Filter> {
let mut filters: Vec<Filter> = Vec::new();
for (key, val) in params.into_iter() {
if let Some(filter) = Filter::from_query_param(key, val) {
filters.push(filter);
}
}
filters
} }

View File

@ -1,3 +1,9 @@
use std::sync::Arc;
use actix_web::{
get, post, put,
web::{Data, Json, Path},
};
use actix_web_utils::extensions::typed_response::TypedHttpResponse; use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{ use realtor_lp_types::{
domain::realtor::Realtor, dto::payloads::realtor::RealtorForCreationPayload, domain::realtor::Realtor, dto::payloads::realtor::RealtorForCreationPayload,
@ -5,49 +11,39 @@ use realtor_lp_types::{
use sqlx::PgPool; use sqlx::PgPool;
use uuid::Uuid; use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found}; use crate::{
dao, handle_db_read_op, handle_db_write_op, handle_tx, services, success, unwrap_or_not_found,
};
#[post("/realtor")]
pub async fn new_realtor_profile( pub async fn new_realtor_profile(
conn: &PgPool, db_conn: Data<Arc<PgPool>>,
realtor: RealtorForCreationPayload, realtor: Json<RealtorForCreationPayload>,
) -> TypedHttpResponse<Realtor> { ) -> TypedHttpResponse<Realtor> {
let mut transaction = handle_tx!(conn.begin()); services::realtor::new_realtor_profile(&db_conn, realtor.0).await
success!(handle_db_write_op!(
dao::realtor::insert_realtor(conn, realtor.into()),
transaction
));
} }
#[put("/realtor/{realtor_id}")]
pub async fn update_realtor_profile( pub async fn update_realtor_profile(
conn: &PgPool, db_conn: Data<Arc<PgPool>>,
realtor_id: Uuid, realtor_id: Path<Uuid>,
realtor: RealtorForCreationPayload, realtor: Json<RealtorForCreationPayload>,
) -> TypedHttpResponse<Realtor> { ) -> TypedHttpResponse<Realtor> {
let mut transaction = handle_tx!(conn.begin()); services::realtor::update_realtor_profile(&db_conn, *realtor_id, realtor.0).await
let mut realtor_insertable: Realtor = realtor.into();
realtor_insertable.id = realtor_id;
success!(handle_db_write_op!(
dao::realtor::update_realtor(conn, realtor_insertable),
transaction
));
} }
#[get("/realtor/shortcode/{shortcode}")]
pub async fn get_realtor_by_shortcode( pub async fn get_realtor_by_shortcode(
conn: &PgPool, db_conn: Data<Arc<PgPool>>,
realtor_shortcode: String, realtor_shortcode: Path<String>,
) -> TypedHttpResponse<Realtor> { ) -> TypedHttpResponse<Realtor> {
success!(unwrap_or_not_found!( services::realtor::get_realtor_by_shortcode(&db_conn, realtor_shortcode.clone()).await
handle_db_read_op!(dao::realtor::get_realtor_with_shortcode(
conn,
&realtor_shortcode
)),
"Realtors"
))
} }
pub async fn get_realtor_with_id(conn: &PgPool, realtor_id: Uuid) -> TypedHttpResponse<Realtor> { #[get("/realtor/{realtor_id}")]
success!(unwrap_or_not_found!( pub async fn get_realtor_with_id(
handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &realtor_id)), db_conn: Data<Arc<PgPool>>,
"Realtors" realtor_id: Path<Uuid>,
)) ) -> TypedHttpResponse<Realtor> {
services::realtor::get_realtor_with_id(&db_conn, *realtor_id).await
} }

View File

@ -1,3 +1,9 @@
use std::sync::Arc;
use actix_web::{
get, post,
web::{Data, Json, Path},
};
use actix_web_utils::extensions::typed_response::TypedHttpResponse; use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{ use realtor_lp_types::{
domain::trackable::Trackable, dto::payloads::trackable::TrackableForCreationPayload, domain::trackable::Trackable, dto::payloads::trackable::TrackableForCreationPayload,
@ -5,26 +11,22 @@ use realtor_lp_types::{
use sqlx::PgPool; use sqlx::PgPool;
use uuid::Uuid; use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found}; use crate::{
dao, handle_db_read_op, handle_db_write_op, handle_tx, services, success, unwrap_or_not_found,
};
#[post("/tr")]
pub async fn create_trackable_profile( pub async fn create_trackable_profile(
conn: &PgPool, db_conn: Data<Arc<PgPool>>,
trackable: TrackableForCreationPayload, trackable: Json<TrackableForCreationPayload>,
) -> TypedHttpResponse<Trackable> { ) -> TypedHttpResponse<Trackable> {
let mut transaction = handle_tx!(conn.begin()); services::trackable::create_trackable_profile(&db_conn, trackable.0).await
let persisted_trackable = handle_db_write_op!(
dao::trackable::insert_trackable(&mut transaction, trackable.into()),
transaction
);
success!(persisted_trackable)
} }
#[get("/tr/{trackable_id}")]
pub async fn validate_trackable_id( pub async fn validate_trackable_id(
conn: &PgPool, db_conn: Data<Arc<PgPool>>,
trackable_id: Uuid, trackable_id: Path<Uuid>,
) -> TypedHttpResponse<Trackable> { ) -> TypedHttpResponse<Trackable> {
success!(unwrap_or_not_found!( services::trackable::validate_trackable_id(&db_conn, *trackable_id).await
handle_db_read_op!(dao::trackable::get_trackable_with_id(conn, &trackable_id)),
"Trackables"
))
} }

View File

@ -1,14 +1,19 @@
use std::sync::Arc;
use actix_web::{
post,
web::{Data, Json},
};
use actix_web_utils::extensions::typed_response::TypedHttpResponse; use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::dto::payloads::view::ViewForCreationPayload; use realtor_lp_types::dto::payloads::view::ViewForCreationPayload;
use sqlx::PgPool; use sqlx::PgPool;
use crate::{dao, handle_db_write_op, handle_tx, success}; use crate::{dao, handle_db_write_op, handle_tx, services, success};
pub async fn new_view(conn: &PgPool, view: ViewForCreationPayload) -> TypedHttpResponse<()> { #[post("/view")]
let mut transaction = handle_tx!(conn.begin()); pub async fn new_view(
handle_db_write_op!( db_conn: Data<Arc<PgPool>>,
dao::view::insert_view(&mut transaction, view.into()), view: Json<ViewForCreationPayload>,
transaction ) -> TypedHttpResponse<()> {
); services::view::new_view(&db_conn, view.0).await
success!(())
} }

11
src/services/click.rs Normal file
View File

@ -0,0 +1,11 @@
use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{domain::click::Click, dto::payloads::click::ClickForCreationPayload};
use sqlx::PgPool;
use crate::{dao, handle_db_write_op, handle_tx, success};
pub async fn new_click(conn: &PgPool, click: ClickForCreationPayload) -> TypedHttpResponse<()> {
let mut transaction = handle_tx!(conn.begin());
handle_db_write_op!(dao::click::insert_click(conn, click.into()), transaction);
success!(())
}

12
src/services/mod.rs Normal file
View File

@ -0,0 +1,12 @@
#[allow(unused)]
pub mod click;
#[allow(unused)]
pub mod project;
#[allow(unused)]
pub mod property;
#[allow(unused)]
pub mod realtor;
#[allow(unused)]
pub mod trackable;
#[allow(unused)]
pub mod view;

33
src/services/project.rs Normal file
View File

@ -0,0 +1,33 @@
use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{
domain::project::Project, dto::payloads::project::ProjectForCreationPayload,
};
use sqlx::PgPool;
use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found};
pub async fn create_project(
conn: &PgPool,
project: ProjectForCreationPayload,
) -> TypedHttpResponse<Project> {
unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &project.realtor_id)),
"Realtor"
);
let mut transaction = handle_tx!(conn.begin());
success!(handle_db_write_op!(
dao::project::insert_project(&mut transaction, project.into()),
transaction
));
}
pub async fn fetch_realtor_projects(
conn: &PgPool,
realtor_id: Uuid,
) -> TypedHttpResponse<Vec<Project>> {
success!(handle_db_read_op!(dao::project::fetch_with_realtor_id(
conn,
&realtor_id
)))
}

104
src/services/property.rs Normal file
View File

@ -0,0 +1,104 @@
use std::sync::Arc;
use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use err::MessageResource;
use realtor_lp_types::{
domain::property::Property,
dto::{filter::Filter, payloads::property::PropertyForCreationPayload},
};
use sqlx::PgPool;
use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found};
pub async fn create_property(
conn: &PgPool,
property: PropertyForCreationPayload,
) -> TypedHttpResponse<Property> {
let mut transaction = handle_tx!(conn.begin());
let realtor = unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_id(
conn,
&property.realtor_id
)),
"Realtor"
);
// Check for project existing
match property.project_id {
Some(project_id) => {
let project = unwrap_or_not_found!(
handle_db_read_op!(dao::project::get_project_with_id(conn, &project_id)),
"Project"
);
if project.realtor_id != realtor.id {
return TypedHttpResponse::return_standard_error(
400,
MessageResource::new_from_str(
"Realtor Id in project does not match realtor id in property.",
),
);
}
}
None => {}
};
success!(handle_db_write_op!(
dao::property::insert_property(&mut transaction, property.into()),
transaction
))
}
pub async fn udpate_property(
conn: &PgPool,
property_id: Uuid,
property: PropertyForCreationPayload,
) -> TypedHttpResponse<Property> {
let mut transaction = handle_tx!(conn.begin());
let realtor = unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_id(
conn,
&property.realtor_id
)),
"Realtor"
);
// Check for project existing
match property.project_id {
Some(project_id) => {
let project = unwrap_or_not_found!(
handle_db_read_op!(dao::project::get_project_with_id(conn, &project_id)),
"Project"
);
if project.realtor_id != realtor.id {
return TypedHttpResponse::return_standard_error(
400,
MessageResource::new_from_str(
"Realtor Id in project does not match realtor id in property.",
),
);
}
}
None => {}
};
let mut property_insertable: Property = property.into();
property_insertable.id = property_id;
success!(handle_db_write_op!(
dao::property::update_property(&mut transaction, property_insertable),
transaction
))
}
pub async fn fetch_realtor_properties_paged(
conn: &PgPool,
realtor_id: Uuid,
page: i64,
filters: Vec<Filter>,
) -> TypedHttpResponse<Vec<Property>> {
let mut all_properties_filtered = handle_db_read_op!(
dao::property::fetch_with_realtor_id_paged(conn, &realtor_id, &filters, &page)
);
all_properties_filtered
.iter_mut()
.for_each(|property| property.admin_tag = None); // Remove admin tag for all
success!(all_properties_filtered)
}

53
src/services/realtor.rs Normal file
View File

@ -0,0 +1,53 @@
use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{
domain::realtor::Realtor, dto::payloads::realtor::RealtorForCreationPayload,
};
use sqlx::PgPool;
use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found};
pub async fn new_realtor_profile(
conn: &PgPool,
realtor: RealtorForCreationPayload,
) -> TypedHttpResponse<Realtor> {
let mut transaction = handle_tx!(conn.begin());
success!(handle_db_write_op!(
dao::realtor::insert_realtor(conn, realtor.into()),
transaction
));
}
pub async fn update_realtor_profile(
conn: &PgPool,
realtor_id: Uuid,
realtor: RealtorForCreationPayload,
) -> TypedHttpResponse<Realtor> {
let mut transaction = handle_tx!(conn.begin());
let mut realtor_insertable: Realtor = realtor.into();
realtor_insertable.id = realtor_id;
success!(handle_db_write_op!(
dao::realtor::update_realtor(conn, realtor_insertable),
transaction
));
}
pub async fn get_realtor_by_shortcode(
conn: &PgPool,
realtor_shortcode: String,
) -> TypedHttpResponse<Realtor> {
success!(unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_shortcode(
conn,
&realtor_shortcode
)),
"Realtors"
))
}
pub async fn get_realtor_with_id(conn: &PgPool, realtor_id: Uuid) -> TypedHttpResponse<Realtor> {
success!(unwrap_or_not_found!(
handle_db_read_op!(dao::realtor::get_realtor_with_id(conn, &realtor_id)),
"Realtors"
))
}

30
src/services/trackable.rs Normal file
View File

@ -0,0 +1,30 @@
use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::{
domain::trackable::Trackable, dto::payloads::trackable::TrackableForCreationPayload,
};
use sqlx::PgPool;
use uuid::Uuid;
use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found};
pub async fn create_trackable_profile(
conn: &PgPool,
trackable: TrackableForCreationPayload,
) -> TypedHttpResponse<Trackable> {
let mut transaction = handle_tx!(conn.begin());
let persisted_trackable = handle_db_write_op!(
dao::trackable::insert_trackable(&mut transaction, trackable.into()),
transaction
);
success!(persisted_trackable)
}
pub async fn validate_trackable_id(
conn: &PgPool,
trackable_id: Uuid,
) -> TypedHttpResponse<Trackable> {
success!(unwrap_or_not_found!(
handle_db_read_op!(dao::trackable::get_trackable_with_id(conn, &trackable_id)),
"Trackables"
))
}

14
src/services/view.rs Normal file
View File

@ -0,0 +1,14 @@
use actix_web_utils::extensions::typed_response::TypedHttpResponse;
use realtor_lp_types::dto::payloads::view::ViewForCreationPayload;
use sqlx::PgPool;
use crate::{dao, handle_db_write_op, handle_tx, success};
pub async fn new_view(conn: &PgPool, view: ViewForCreationPayload) -> TypedHttpResponse<()> {
let mut transaction = handle_tx!(conn.begin());
handle_db_write_op!(
dao::view::insert_view(&mut transaction, view.into()),
transaction
);
success!(())
}