From f92b077f5687af4e01bf99d09119716e367b176b Mon Sep 17 00:00:00 2001 From: Franklin Date: Fri, 10 Mar 2023 06:03:27 -0400 Subject: [PATCH] admin creation functions --- .env | 2 +- Cargo.lock | 6 + Cargo.toml | 2 +- Readme.md | 9 +- migrations/4_contact_info.sql | 2 +- sqlx-data.json | 680 ++++++++++++++++++++++++++++++++++ src/dao/agent.rs | 8 +- src/dao/contact_info.rs | 16 +- src/dao/location.rs | 10 +- src/dao/mod.rs | 6 +- src/dao/property.rs | 6 +- src/dao/property_details.rs | 16 +- src/main.rs | 4 +- src/routes/main_router.rs | 7 +- src/service/admin.rs | 92 +++++ src/service/mod.rs | 1 + src/utils/macros.rs | 55 +++ src/utils/mod.rs | 1 + 18 files changed, 882 insertions(+), 41 deletions(-) create mode 100644 sqlx-data.json create mode 100644 src/service/admin.rs create mode 100644 src/service/mod.rs create mode 100644 src/utils/macros.rs create mode 100644 src/utils/mod.rs diff --git a/.env b/.env index b335040..7c7fa4c 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ DATABASE_URL="postgres://root:NMWrHZcu9QCu6wlmRUeEw1vXUYq7JhQYSPICTnl5yN9Pu5NIHUOcaj2noV9ejhFgfk5AfKIM2e9x97rbGCwbgTpVa3Fe8nfHgrYLZ2B36sOININQG60T2vIsQX3gkE6U@backend.blancoinfante.com:9102/postgres" -SQLX_OFFLINE=FALSE \ No newline at end of file +SQLX_OFFLINE=TRUE \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 60b9d4b..55ebc76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -680,6 +680,9 @@ name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" @@ -1788,9 +1791,12 @@ dependencies = [ "dotenvy", "either", "heck", + "hex", "once_cell", "proc-macro2", "quote", + "serde", + "serde_json", "sha2", "sqlx-core", "sqlx-rt", diff --git a/Cargo.toml b/Cargo.toml index 7e712f4..117a2ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ chrono = "0.4.23" chrono-tz = "0.8" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.88" -sqlx = { version = "0.6.0", features = [ "runtime-tokio-rustls", "postgres", "chrono", "uuid" ] } +sqlx = { version = "0.6.0", features = [ "runtime-tokio-rustls", "postgres", "chrono", "uuid", "offline" ] } dotenv = { version = "0.15.0" } actix-web = {version = "4.1.0"} actix-cors = "0.6.2" diff --git a/Readme.md b/Readme.md index 3c71fbc..cbf136d 100644 --- a/Readme.md +++ b/Readme.md @@ -3,9 +3,6 @@ by Franklin Blanco ### Todo's -- [x] Add properties -- [x] Add agents -- [ ] Fetch them both -- [ ] Delete, update -- [ ] Admin panel functions -- [ ] Pictures? \ No newline at end of file +- [x] Dao's made +- [ ] Admin functions in service +- [ ] Admin functions in routes \ No newline at end of file diff --git a/migrations/4_contact_info.sql b/migrations/4_contact_info.sql index 04f4c5e..183d20b 100644 --- a/migrations/4_contact_info.sql +++ b/migrations/4_contact_info.sql @@ -1,7 +1,7 @@ CREATE TABLE IF NOT EXISTS "contact_info" ( agent_id UUID PRIMARY KEY, phone_number VARCHAR NOT NULL, - email VARCHAR NOT NULL, + email VARCHAR, profile_picture_url TEXT, default_message TEXT ); \ No newline at end of file diff --git a/sqlx-data.json b/sqlx-data.json new file mode 100644 index 0000000..181b2e2 --- /dev/null +++ b/sqlx-data.json @@ -0,0 +1,680 @@ +{ + "db": "PostgreSQL", + "044ecd955f880a5d7e3185b6dc5217c01cb88100d2e94dea5323ee0a10a45fc0": { + "describe": { + "columns": [ + { + "name": "agent_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "phone_number", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "profile_picture_url", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_message", + "ordinal": 4, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + true, + true, + true + ], + "parameters": { + "Left": [ + "Uuid", + "Varchar", + "Varchar", + "Text", + "Text" + ] + } + }, + "query": "INSERT INTO contact_info (\n agent_id, phone_number, email, profile_picture_url, default_message\n) VALUES (\n $1, $2, $3, $4, $5\n) RETURNING *" + }, + "1338558f1d37cc1542fd505c891158f8ab5e8f3792dbb44a534d64ff05ffa62e": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "country", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "province", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "city", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "district", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "google_maps_url", + "ordinal": 5, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false, + true, + true + ], + "parameters": { + "Left": [ + "Uuid", + "Varchar", + "Varchar", + "Varchar", + "Varchar", + "Text" + ] + } + }, + "query": "INSERT INTO location (\n id, country, province, city, district, google_maps_url\n) VALUES (\n $1, $2, $3, $4, $5, $6\n) RETURNING *" + }, + "22cbe3af73d11e22b94e5b35b53004aae874b1a6286774a5569598ff8eb36ebc": { + "describe": { + "columns": [ + { + "name": "agent_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "phone_number", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "profile_picture_url", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_message", + "ordinal": 4, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + true, + true, + true + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Text", + "Text" + ] + } + }, + "query": "UPDATE contact_info SET \n phone_number = $1,\n email = $2,\n profile_picture_url = $3,\n default_message = $4\nRETURNING *" + }, + "2a7d2d72bb220e7c948cf7939e88524f5c29f68405a38e66be759493581b67f6": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "agent_id", + "ordinal": 3, + "type_info": "Uuid" + }, + { + "name": "state: _", + "ordinal": 4, + "type_info": "Bytea" + }, + { + "name": "time_created", + "ordinal": 5, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 6, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Uuid", + "Varchar", + "Varchar", + "Uuid", + "Bytea", + "Timestamptz" + ] + } + }, + "query": "INSERT INTO property (\n id,\n title,\n description,\n agent_id,\n state,\n time_created,\n last_updated\n) VALUES (\n $1,\n $2,\n $3,\n $4,\n $5,\n $6,\n $6\n) RETURNING\nid,\ntitle,\ndescription,\nagent_id,\nstate as \"state: _\",\ntime_created,\nlast_updated;" + }, + "403be6e4c7b32698eb9dd9c43f9c13f7f03dc95671f1c81a5391df05c51a92fc": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "agent_id", + "ordinal": 3, + "type_info": "Uuid" + }, + { + "name": "state: _", + "ordinal": 4, + "type_info": "Bytea" + }, + { + "name": "time_created", + "ordinal": 5, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 6, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Varchar", + "Varchar", + "Uuid", + "Bytea", + "Timestamptz" + ] + } + }, + "query": "UPDATE property SET\n title = $1,\n description = $2,\n agent_id = $3,\n state = $4,\n last_updated = $5\nRETURNING\n id,\n title,\n description,\n agent_id,\n state as \"state: _\",\n time_created,\n last_updated;" + }, + "428b88c19683cb7862ad8c9ef22a52a793f1dc303e11a7aebc6d2719357147bf": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "full_name", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "time_created", + "ordinal": 2, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 3, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Uuid", + "Varchar", + "Timestamptz" + ] + } + }, + "query": "INSERT INTO agent (\n id, full_name, time_created, last_updated\n) VALUES (\n $1, $2, $3, $3\n) RETURNING *" + }, + "75508bc7b114d6f9915cadf9708c376d2ca1a6dcdd6bff24b1a717cba0ec2fca": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "agent_id", + "ordinal": 3, + "type_info": "Uuid" + }, + { + "name": "state: _", + "ordinal": 4, + "type_info": "Bytea" + }, + { + "name": "time_created", + "ordinal": 5, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 6, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "UuidArray" + ] + } + }, + "query": "SELECT \nid,\ntitle,\ndescription,\nagent_id,\nstate as \"state: _\",\ntime_created,\nlast_updated\nFROM property where id = ANY($1);" + }, + "a05953d6326a1fa6da0444234846b6ee761c8c38c69145b84a2f8d321d879289": { + "describe": { + "columns": [ + { + "name": "property_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "meters", + "ordinal": 1, + "type_info": "Float4" + }, + { + "name": "listing_type: _", + "ordinal": 2, + "type_info": "Bytea" + }, + { + "name": "photo_urls: _", + "ordinal": 3, + "type_info": "Bytea" + }, + { + "name": "location_id", + "ordinal": 4, + "type_info": "Uuid" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Uuid", + "Float4", + "Bytea", + "Bytea", + "Uuid" + ] + } + }, + "query": "INSERT INTO property_details (\n property_id,\n meters,\n listing_type,\n photo_urls,\n location_id\n) VALUES (\n $1,\n $2,\n $3,\n $4,\n $5\n) RETURNING\nproperty_id,\nmeters,\nlisting_type as \"listing_type: _\",\nphoto_urls as \"photo_urls: _\",\nlocation_id;" + }, + "ad03e2715180d060696b5c01717a70c64e635e4521ee958fc027b6a95568a8f0": { + "describe": { + "columns": [ + { + "name": "property_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "meters", + "ordinal": 1, + "type_info": "Float4" + }, + { + "name": "listing_type: _", + "ordinal": 2, + "type_info": "Bytea" + }, + { + "name": "photo_urls: _", + "ordinal": 3, + "type_info": "Bytea" + }, + { + "name": "location_id", + "ordinal": 4, + "type_info": "Uuid" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "UuidArray" + ] + } + }, + "query": "SELECT \nproperty_id,\nmeters,\nlisting_type as \"listing_type: _\",\nphoto_urls as \"photo_urls: _\",\nlocation_id\nFROM property_details where property_id = ANY($1);" + }, + "ad2a4218c9f1bfdf669734ee14a797c4f66d9095fe1bfbba4c8d47b16bfb4f2c": { + "describe": { + "columns": [ + { + "name": "property_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "meters", + "ordinal": 1, + "type_info": "Float4" + }, + { + "name": "listing_type: _", + "ordinal": 2, + "type_info": "Bytea" + }, + { + "name": "photo_urls: _", + "ordinal": 3, + "type_info": "Bytea" + }, + { + "name": "location_id", + "ordinal": 4, + "type_info": "Uuid" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Float4", + "Bytea", + "Bytea", + "Uuid" + ] + } + }, + "query": "UPDATE property_details SET\n meters = $1,\n listing_type = $2,\n photo_urls = $3,\n location_id = $4\nRETURNING\n property_id,\n meters,\n listing_type as \"listing_type: _\",\n photo_urls as \"photo_urls: _\",\n location_id" + }, + "b45175d105229ca747253412acd6769726bfce4a511d75fd71238a7835b54669": { + "describe": { + "columns": [ + { + "name": "agent_id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "phone_number", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "profile_picture_url", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_message", + "ordinal": 4, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + true, + true, + true + ], + "parameters": { + "Left": [ + "UuidArray" + ] + } + }, + "query": "SELECT * FROM contact_info where agent_id = ANY($1);" + }, + "ccda00295a22931d00484841a95cb74c9541bc8d1c7f63069b6a069b8b6e942a": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "full_name", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "time_created", + "ordinal": 2, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 3, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "UuidArray" + ] + } + }, + "query": "SELECT * FROM agent WHERE id = ANY($1);" + }, + "d556cb1971f386a7997c2e3dbce191cde2d488c55c05edbfe3746208a782d5f6": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "country", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "province", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "city", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "district", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "google_maps_url", + "ordinal": 5, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false, + true, + true + ], + "parameters": { + "Left": [ + "Uuid" + ] + } + }, + "query": "SELECT * FROM location WHERE id = $1;" + }, + "f129da55e85f8ab1fbae9ec9553203b0e5083022003a35a370edc313b23b8007": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "full_name", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "time_created", + "ordinal": 2, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 3, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Varchar", + "Timestamptz" + ] + } + }, + "query": "UPDATE agent set \nfull_name = $1,\nlast_updated = $2\nRETURNING *" + } +} \ No newline at end of file diff --git a/src/dao/agent.rs b/src/dao/agent.rs index cb64e0d..b883363 100644 --- a/src/dao/agent.rs +++ b/src/dao/agent.rs @@ -1,9 +1,9 @@ use remax_types::domain::agent::Agent; -use sqlx::PgPool; +use sqlx::{PgPool, Postgres, Transaction}; use uuid::Uuid; pub async fn insert_agent( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, agent: &Agent, ) -> Result { sqlx::query_file_as!( @@ -16,7 +16,7 @@ pub async fn insert_agent( .fetch_one(conn) .await } -pub async fn get_properties_with_ids( +pub async fn get_agents_with_ids( conn: &PgPool, ids: &Vec, ) -> Result, sqlx::error::Error> { @@ -26,7 +26,7 @@ pub async fn get_properties_with_ids( } pub async fn update_agent( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, agent: &Agent, ) -> Result { sqlx::query_file_as!( diff --git a/src/dao/contact_info.rs b/src/dao/contact_info.rs index 9870cb2..fd11eca 100644 --- a/src/dao/contact_info.rs +++ b/src/dao/contact_info.rs @@ -1,9 +1,9 @@ use remax_types::domain::contact_info::ContactInformation; -use sqlx::PgPool; +use sqlx::{PgPool, Postgres, Transaction}; use uuid::Uuid; pub async fn insert_contact_info( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, contact_info: &ContactInformation, ) -> Result { sqlx::query_file_as!( @@ -22,13 +22,17 @@ pub async fn get_properties_with_ids( conn: &PgPool, ids: &Vec, ) -> Result, sqlx::error::Error> { - sqlx::query_file_as!(ContactInformation, "sql/contact_info/fetch_with_ids.sql", ids) - .fetch_all(conn) - .await + sqlx::query_file_as!( + ContactInformation, + "sql/contact_info/fetch_with_ids.sql", + ids + ) + .fetch_all(conn) + .await } pub async fn update_contact_info( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, contact_info: &ContactInformation, ) -> Result { sqlx::query_file_as!( diff --git a/src/dao/location.rs b/src/dao/location.rs index a05e187..56dbda4 100644 --- a/src/dao/location.rs +++ b/src/dao/location.rs @@ -1,9 +1,9 @@ use remax_types::domain::location::Location; -use sqlx::PgPool; +use sqlx::{PgPool, Postgres, Transaction}; use uuid::Uuid; pub async fn insert_location( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, location: &Location, ) -> Result { sqlx::query_file_as!( @@ -22,8 +22,8 @@ pub async fn insert_location( pub async fn get_location_with_id( conn: &PgPool, id: &Uuid, -) -> Result, sqlx::error::Error> { +) -> Result, sqlx::error::Error> { sqlx::query_file_as!(Location, "sql/location/get.sql", id) - .fetch_all(conn) + .fetch_optional(conn) .await -} \ No newline at end of file +} diff --git a/src/dao/mod.rs b/src/dao/mod.rs index b00be56..967704c 100644 --- a/src/dao/mod.rs +++ b/src/dao/mod.rs @@ -1,6 +1,6 @@ pub mod agent; +pub mod contact_info; +pub mod location; pub mod main_dao; pub mod property; -pub mod location; -pub mod contact_info; -pub mod property_details; \ No newline at end of file +pub mod property_details; diff --git a/src/dao/property.rs b/src/dao/property.rs index 9bfdc00..b9bbb3a 100644 --- a/src/dao/property.rs +++ b/src/dao/property.rs @@ -1,9 +1,9 @@ use remax_types::domain::property::Property; -use sqlx::PgPool; +use sqlx::{PgPool, Postgres, Transaction}; use uuid::Uuid; pub async fn insert_property( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, property: &Property, ) -> Result { sqlx::query_file_as!( @@ -29,7 +29,7 @@ pub async fn get_properties_with_ids( } pub async fn update_property( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, property: &Property, ) -> Result { sqlx::query_file_as!( diff --git a/src/dao/property_details.rs b/src/dao/property_details.rs index db1de5a..90f21c2 100644 --- a/src/dao/property_details.rs +++ b/src/dao/property_details.rs @@ -1,9 +1,9 @@ use remax_types::domain::property_details::PropertyDetails; -use sqlx::PgPool; +use sqlx::{PgPool, Postgres, Transaction}; use uuid::Uuid; pub async fn insert_property_details( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, property_details: &PropertyDetails, ) -> Result { sqlx::query_file_as!( @@ -22,13 +22,17 @@ pub async fn get_properties_with_ids( conn: &PgPool, ids: &Vec, ) -> Result, sqlx::error::Error> { - sqlx::query_file_as!(PropertyDetails, "sql/property_details/fetch_with_ids.sql", ids) - .fetch_all(conn) - .await + sqlx::query_file_as!( + PropertyDetails, + "sql/property_details/fetch_with_ids.sql", + ids + ) + .fetch_all(conn) + .await } pub async fn update_property_details( - conn: &PgPool, + conn: &mut Transaction<'_, Postgres>, property_details: &PropertyDetails, ) -> Result { sqlx::query_file_as!( diff --git a/src/main.rs b/src/main.rs index 40f0f4d..221d6b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ pub mod dao; pub mod routes; +pub mod service; +pub mod utils; use std::sync::Arc; use chrono::Utc; -use dao::{main_dao}; +use dao::main_dao; #[tokio::main] async fn main() { diff --git a/src/routes/main_router.rs b/src/routes/main_router.rs index 83e67a5..13180c8 100644 --- a/src/routes/main_router.rs +++ b/src/routes/main_router.rs @@ -10,15 +10,14 @@ pub const HOST_ADDR: &str = "0.0.0.0"; pub const HOST_PORT: u16 = 8095; pub async fn start_all_routes(start_time: i64, db_conn: Arc) -> Result<(), std::io::Error> { - let client_state = web::Data::new(Arc::new(Client::new())); // Start server code that turns into a future to be executed below let server_future = HttpServer::new(move || { let cors_policy = Cors::permissive(); App::new() - .wrap(cors_policy) - .app_data(client_state.clone()) - .app_data(db_conn.clone()) + .wrap(cors_policy) + .app_data(client_state.clone()) + .app_data(db_conn.clone()) //.service(web::scope("/league").service(SERVICE_HERE)) }) .bind((HOST_ADDR, HOST_PORT))? diff --git a/src/service/admin.rs b/src/service/admin.rs new file mode 100644 index 0000000..5e6c913 --- /dev/null +++ b/src/service/admin.rs @@ -0,0 +1,92 @@ +use actix_web_utils::extensions::typed_response::TypedHttpResponse; +use remax_types::{ + domain::location::Location, + dto::{ + agent::AgentContainer, + payload::{ + agent::{AgentWithContactInfo, NewAgentPayload}, + location::NewLocationPayload, + property::{NewPropertyPayload, PropertyWithDetails}, + }, + property::PropertyContainer, + }, +}; +use sqlx::PgPool; + +use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found}; + +/// Needs to create a Property, a Property Details +/// Create or reference an existing Location +/// and an Agent +/// Needs to be given all the property details, agent details, location details +pub async fn create_new_property( + conn: &PgPool, + new_property_payload: NewPropertyPayload, +) -> TypedHttpResponse { + let agent_ids = &vec![new_property_payload.agent_id]; + + let mut tx = handle_tx!(conn.begin()); + let persisted_agents = handle_db_read_op!(dao::agent::get_agents_with_ids(conn, agent_ids)); + let _ = unwrap_or_not_found!(persisted_agents.first(), "agents"); + let persisted_location = unwrap_or_not_found!( + handle_db_read_op!(dao::location::get_location_with_id( + conn, + &new_property_payload.location_id + )), + "locations" + ); + + let property_with_details: PropertyWithDetails = new_property_payload.into(); + let persisted_property = handle_db_write_op!( + dao::property::insert_property(&mut tx, &property_with_details.property), + tx + ); + let persisted_property_details = handle_db_write_op!( + dao::property_details::insert_property_details(&mut tx, &property_with_details.details), + tx + ); + + handle_tx!(tx.commit()); + success!(PropertyContainer { + property: persisted_property, + details: persisted_property_details, + location: persisted_location, + }) +} + +pub async fn create_new_agent_profile( + conn: &PgPool, + new_agent_payload: NewAgentPayload, +) -> TypedHttpResponse { + let agent_with_contact_info: AgentWithContactInfo = new_agent_payload.into(); + + let mut tx = handle_tx!(conn.begin()); + let persisted_agent = handle_db_write_op!( + dao::agent::insert_agent(&mut tx, &agent_with_contact_info.agent), + tx + ); + let persisted_contact_info = handle_db_write_op!( + dao::contact_info::insert_contact_info(&mut tx, &agent_with_contact_info.contact_info), + tx + ); + handle_tx!(tx.commit()); + + success!(AgentContainer { + agent: persisted_agent, + contact: persisted_contact_info, + }) +} + +pub async fn create_new_location( + conn: &PgPool, + new_location_payload: NewLocationPayload, +) -> TypedHttpResponse { + let location: Location = new_location_payload.into(); + + let mut tx = handle_tx!(conn.begin()); + let persisted_location = + handle_db_write_op!(dao::location::insert_location(&mut tx, &location), tx); + handle_tx!(tx.commit()); + + success!(persisted_location) +} diff --git a/src/service/mod.rs b/src/service/mod.rs new file mode 100644 index 0000000..92918b0 --- /dev/null +++ b/src/service/mod.rs @@ -0,0 +1 @@ +pub mod admin; diff --git a/src/utils/macros.rs b/src/utils/macros.rs new file mode 100644 index 0000000..14f0d97 --- /dev/null +++ b/src/utils/macros.rs @@ -0,0 +1,55 @@ +/// This macro unwraps the value and if its an error it rolls back the transaction and returns a TypedHttpResponse with the corresponding erorr. +#[macro_export] +macro_rules! handle_db_write_op { + ($e:expr, $tx:expr) => { + match $e.await { + Ok(value) => value, + Err(error) => { + handle_tx!($tx.rollback()); + return actix_web_utils::extensions::typed_response::TypedHttpResponse::return_standard_error(400, err::MessageResource::new_from_string(error.to_string())); + } + } + }; +} + +#[macro_export] +macro_rules! handle_db_read_op { + ($e:expr) => { + match $e.await { + Ok(value) => value, + Err(error) => return actix_web_utils::extensions::typed_response::TypedHttpResponse::return_standard_error(400, err::MessageResource::new_from_string(error.to_string())), + } + }; +} + +/// This macro calls await on whatever you give it and if it gets an error it returns a TypedHttpResponse with an InternalServerError status code (500) and an error message. +#[macro_export] +macro_rules! handle_tx { + ($e:expr) => { + match $e.await { + Ok(value) => value, + Err(_) => { + return actix_web_utils::extensions::typed_response::TypedHttpResponse::return_standard_error(500, err::MessageResource::new_from_str("Failed to acquire, commit or rollback tx...")); + } + } + }; +} + +/// This macro just returns a TypedHttpResponse with a success status code (200) and whatever you give it inside. +#[macro_export] +macro_rules! success { + ($e:expr) => { + return actix_web_utils::extensions::typed_response::TypedHttpResponse::return_standard_response(200, $e) + }; +} + +/// This macro just returns a TypedHttpResponse with a not found status code (404) and an error concatenated. +#[macro_export] +macro_rules! unwrap_or_not_found { + ($e:expr, $what:literal) => { + match $e { + Some(value) => value, + None => return actix_web_utils::extensions::typed_response::TypedHttpResponse::return_standard_error(404, err::MessageResource::new_from_string(format!("No {} found with specified Id.", $what))), + } + }; +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..eda363d --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod macros;