diff --git a/src/main.rs b/src/main.rs index 221d6b7..15fdb57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,4 +18,4 @@ async fn main() { routes::main_router::start_all_routes(start_time, db_conn) .await .unwrap(); -} +} \ No newline at end of file diff --git a/src/routes/main_router.rs b/src/routes/main_router.rs index 5fc7308..1059c24 100644 --- a/src/routes/main_router.rs +++ b/src/routes/main_router.rs @@ -17,7 +17,7 @@ pub async fn start_all_routes(start_time: i64, db_conn: Arc) -> Result<( App::new() .wrap(cors_policy) .app_data(client_state.clone()) - .app_data(db_conn.clone()) + .app_data(web::Data::new(db_conn.clone())) .service(web::scope("/admin") .service(super::admin::create_new_agent_profile) .service(super::admin::create_new_location) @@ -25,9 +25,9 @@ pub async fn start_all_routes(start_time: i64, db_conn: Arc) -> Result<( .service(super::admin::update_agent_info) .service(super::admin::update_listing)) .service(web::scope("/read") - - ) - + .service(super::read::get_all_agents) + .service(super::read::get_listing_container) + .service(super::read::get_property_listings_paged)) }) .bind((HOST_ADDR, HOST_PORT))? .run(); diff --git a/src/routes/read.rs b/src/routes/read.rs index 29c5928..216f32d 100644 --- a/src/routes/read.rs +++ b/src/routes/read.rs @@ -1,3 +1,109 @@ -//TODO: Property -// - Get properties by novelty, by title, by size, by page, by cost, by contract_type -// - Properties should come with agents, property details, contact_info +use std::{sync::Arc, collections::HashMap, str::FromStr}; + +use actix_web::{web, get}; +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use chrono::{DateTime, Utc}; +use err::MessageResource; +use remax_types::{dto::{property::{PropertyContainer, ListingContainer}, agent::AgentContainer}, domain::{filters::property::PropertyFilter, property_details::ListingType}}; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::service; + +#[get("/properties/{page}")] +pub async fn get_property_listings_paged( + db_conn: web::Data>, + page: web::Path, + query_params: web::Query> +) -> TypedHttpResponse> { + let filters = match parse_params_into_filters(query_params.0) { + Ok(filters) => filters, + Err(msg) => return TypedHttpResponse::return_standard_error(400, msg), + }; + service::read::get_property_listings_paged(&db_conn, &filters, &page).await +} + +#[get("/property/{property_id}")] +pub async fn get_listing_container( + db_conn: web::Data>, + property_id: web::Path, +) -> TypedHttpResponse { + service::read::get_listing_container(&db_conn, &property_id).await +} + +#[get("/agents/{page}")] +pub async fn get_all_agents( + db_conn: web::Data>, + page: web::Path, +) -> TypedHttpResponse> { + service::read::get_all_agents(&db_conn, &page).await +} + +fn parse_params_into_filters(params: HashMap) -> Result, MessageResource> { + let mut filters: Vec = Vec::new(); + for key in params.keys() { + match key.as_str() { + "before" => { + let parsed_date = match DateTime::::from_str(params.get(key).unwrap()) { + Ok(date) => date, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::Before(parsed_date)); + }, + "after" => { + let parsed_date = match DateTime::::from_str(params.get(key).unwrap()) { + Ok(date) => date, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::After(parsed_date)); + }, + "title" => { + let title_like = params.get(key).unwrap(); + filters.push(PropertyFilter::Title(title_like.clone())); + }, + "description" => { + let description_like = params.get(key).unwrap(); + filters.push(PropertyFilter::Description(description_like.clone())); + }, + "location" => { + let uid = match Uuid::from_str(params.get(key).unwrap()) { + Ok(id) => id, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::Location(uid)); + }, + "cheaperthan" => { + let cheaper_than = params.get(key).unwrap().clone(); + let listing_type: ListingType = match serde_json::from_str(&cheaper_than) { + Ok(value) => value, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::CheaperThan(listing_type)); + }, + "moreexpensivethan" => { + let more_expensive_than = params.get(key).unwrap().clone(); + let listing_type: ListingType = match serde_json::from_str(&more_expensive_than) { + Ok(value) => value, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::MoreExpensiveThan(listing_type)); + }, + "biggerorquealto" => { + let bigger_than = match f32::from_str(¶ms.get(key).unwrap().clone()) { + Ok(value) => value, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::BiggerOrEqualTo(bigger_than)); + }, + "smallerorequalto" => { + let smaller_than = match f32::from_str(¶ms.get(key).unwrap().clone()) { + Ok(value) => value, + Err(error) => return Err(MessageResource::new_from_string(error.to_string())), + }; + filters.push(PropertyFilter::SmallerOrEqualTo(smaller_than)); + }, + _ => {} + }; + } + Ok(filters) +} \ No newline at end of file diff --git a/src/service/read.rs b/src/service/read.rs index 04cffd2..a790668 100644 --- a/src/service/read.rs +++ b/src/service/read.rs @@ -1,6 +1,6 @@ use actix_web_utils::extensions::typed_response::TypedHttpResponse; use remax_types::{ - domain::{agent::Agent, filters::property::PropertyFilter}, + domain::{filters::property::PropertyFilter}, dto::{ agent::AgentContainer, property::{ListingContainer, PropertyContainer}, @@ -121,7 +121,18 @@ pub async fn get_listing_container( }) } -pub async fn get_all_agents(conn: &PgPool, page: &i64) -> TypedHttpResponse> { +pub async fn get_all_agents(conn: &PgPool, page: &i64) -> TypedHttpResponse> { let agents = handle_db_read_op!(dao::agent::get_agents_paged(conn, page)); - success!(agents) + let agent_ids: Vec = agents.iter().map(|agent| agent.id.clone()).collect(); + let contact_infos = handle_db_read_op!(dao::contact_info::get_contact_infos_with_ids(conn, &agent_ids)); + let mut agent_containers = Vec::new(); + for agent in agents { + let contact = unwrap_or_not_found!(contact_infos.iter().find(|contact_info| contact_info.agent_id == agent.id), "contact_infos").clone(); + agent_containers.push(AgentContainer { + agent, + contact, + }) + } + + success!(agent_containers) }