From e272cff3c5f57412a484ba26ce67d9c792f09cc4 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 17 Jun 2026 14:15:28 -0400 Subject: [PATCH 1/5] Adding messages table --- migrations/20260613211440_init.sql | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/migrations/20260613211440_init.sql b/migrations/20260613211440_init.sql index ef5cc2b..caf9db4 100644 --- a/migrations/20260613211440_init.sql +++ b/migrations/20260613211440_init.sql @@ -10,3 +10,9 @@ CREATE TABLE IF NOT EXISTS "contacts" ( lastname TEXT NULL, nickname TEXT NULL ); + +CREATE TABLE IF NOT EXISTS "messages" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + content TEXT NOT NULL, + user_id UUID NOT NULL +); -- 2.47.3 From ec0a310d761a2ae79c226789f5972b5d795eeacb Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 17 Jun 2026 14:16:16 -0400 Subject: [PATCH 2/5] Adding code for adding message --- src/caller/message.rs | 85 +++++++++++++++++++++++++++++++++++++++++++ src/caller/mod.rs | 3 ++ src/config/mod.rs | 16 ++++++-- src/repo/message.rs | 26 +++++++++++++ src/repo/mod.rs | 1 + 5 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 src/caller/message.rs create mode 100644 src/repo/message.rs diff --git a/src/caller/message.rs b/src/caller/message.rs new file mode 100644 index 0000000..0427aa3 --- /dev/null +++ b/src/caller/message.rs @@ -0,0 +1,85 @@ +pub mod request { + use serde::{Deserialize, Serialize}; + use utoipa::ToSchema; + + #[derive(Debug, Deserialize, Serialize, ToSchema)] + pub struct AddMessageRequest { + pub content: String, + pub user_id: uuid::Uuid + } + + impl AddMessageRequest { + pub fn is_valid(&self) -> bool { + !self.content.is_empty() || !self.user_id.is_nil() + } + } +} + +pub mod response { + use serde::{Deserialize, Serialize}; + use utoipa::ToSchema; + + #[derive(Debug, Default, Deserialize, Serialize, ToSchema)] + pub struct AddMessageResponse { + pub message: String, + pub data: Vec + } +} + +pub mod endpoint { + use crate::repo::message as message_repo; + + /// Endpoint to create Message + #[utoipa::path( + post, + path = super::super::endpoints::ADD_MESSAGE, + request_body( + content = super::request::AddMessageRequest, + description = "Data needed to create a Message", + content_type = "application/json" + ), + responses( + (status = 201, description = "Message created", body = super::response::AddMessageResponse), + (status = 400, description = "Error", body = super::response::AddMessageResponse), + (status = 500, description = "Error creating Message", body = super::response::AddMessageResponse) + ) +)] + pub async fn create_message( + axum::Extension(pool): axum::Extension, + axum::Json(payload): axum::Json, + ) -> ( + axum::http::StatusCode, + axum::Json, + ) { + let mut response = super::response::AddMessageResponse::default(); + + if payload.is_valid() { + let mut msg = textsender_models::message::Message { + content: payload.content, + user_id: Some(payload.user_id), + ..Default::default() + }; + match message_repo::insert(&pool, &msg, &payload.user_id) .await + { + Ok(message_id) => { + msg.id = Some(message_id); + response.data.push(msg); + response.message = String::from("Message created"); + (axum::http::StatusCode::CREATED, axum::Json(response)) + } + Err(err) => { + eprintln!("Error: {err:?}"); + response.message = String::from("Contact not created"); + + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response), + ) + } + } + } else { + response.message = String::from("Request body is not valid"); + (axum::http::StatusCode::BAD_REQUEST, axum::Json(response)) + } + } +} diff --git a/src/caller/mod.rs b/src/caller/mod.rs index 17bc20a..85b102e 100644 --- a/src/caller/mod.rs +++ b/src/caller/mod.rs @@ -1,4 +1,5 @@ pub mod contact; +pub mod message; pub mod endpoints { pub const ROOT: &str = "/"; @@ -9,6 +10,8 @@ pub mod endpoints { pub const GET_CONTACT: &str = "/api/v1/contact"; /// Constant for updating names of a Contact endpoint pub const UPDATE_CONTACT_NAME: &str = "/api/v1/contact/update"; + /// Constant for adding message endpoint + pub const ADD_MESSAGE: &str = "/api/v1/message/new"; } pub mod response { diff --git a/src/config/mod.rs b/src/config/mod.rs index 105fb1c..daf5acb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -15,8 +15,11 @@ pub mod init { use utoipa::OpenApi; use crate::caller::contact as contact_caller; + use crate::caller::message as message_caller; use contact_caller::endpoint as contact_endpoints; - // use contact_caller::response as contact_responses; + use message_caller::endpoint as message_endpoints; + use contact_caller::response as contact_responses; + use message_caller::response as message_responses; mod cors { pub async fn configure_cors() -> tower_http::cors::CorsLayer { @@ -73,8 +76,9 @@ pub mod init { #[derive(utoipa::OpenApi)] #[openapi( - paths(contact_endpoints::create_contact,), - components(schemas(contact_caller::response::AddContactResponse)), + paths(contact_endpoints::create_contact, + message_endpoints::create_message), + components(schemas(contact_responses::AddContactResponse)), tags( (name = "textsender API", description = "Web API to manage texting") ) @@ -101,6 +105,12 @@ pub mod init { axum::middleware::from_fn(crate::auth::auth::), ), ) + .route( + crate::caller::endpoints::ADD_MESSAGE, + patch(message_endpoints::create_message).route_layer( + axum::middleware::from_fn(crate::auth::auth::), + ), + ) .layer(cors::configure_cors().await) } diff --git a/src/repo/message.rs b/src/repo/message.rs new file mode 100644 index 0000000..a5bf5ae --- /dev/null +++ b/src/repo/message.rs @@ -0,0 +1,26 @@ +use sqlx::Row; + +pub async fn insert( + pool: &sqlx::PgPool, + message: &textsender_models::message::Message, + user_id: &uuid::Uuid, +) -> Result { + match sqlx::query( + r#" + INSERT INTO "contacts" (content, user_id) + VALUES($1, $2) RETURNING id; + "#, + ) + .bind(&message.content) + .bind(user_id) + .fetch_one(pool) + .await + { + Ok(row) => { + let id: uuid::Uuid = row.try_get("id")?; + Ok(id) + } + Err(_) => Err(sqlx::Error::RowNotFound), + } +} + diff --git a/src/repo/mod.rs b/src/repo/mod.rs index 40d6353..2af9758 100644 --- a/src/repo/mod.rs +++ b/src/repo/mod.rs @@ -1 +1,2 @@ pub mod contact; +pub mod message; -- 2.47.3 From e54a53a4962431fd062af6e6374c61418bed1ca6 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 17 Jun 2026 14:23:38 -0400 Subject: [PATCH 3/5] Got it working --- src/caller/message.rs | 19 +++++++++---------- src/config/mod.rs | 12 ++++++------ src/repo/message.rs | 3 +-- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/caller/message.rs b/src/caller/message.rs index 0427aa3..05d8280 100644 --- a/src/caller/message.rs +++ b/src/caller/message.rs @@ -5,7 +5,7 @@ pub mod request { #[derive(Debug, Deserialize, Serialize, ToSchema)] pub struct AddMessageRequest { pub content: String, - pub user_id: uuid::Uuid + pub user_id: uuid::Uuid, } impl AddMessageRequest { @@ -22,7 +22,7 @@ pub mod response { #[derive(Debug, Default, Deserialize, Serialize, ToSchema)] pub struct AddMessageResponse { pub message: String, - pub data: Vec + pub data: Vec, } } @@ -59,8 +59,7 @@ pub mod endpoint { user_id: Some(payload.user_id), ..Default::default() }; - match message_repo::insert(&pool, &msg, &payload.user_id) .await - { + match message_repo::insert(&pool, &msg, &payload.user_id).await { Ok(message_id) => { msg.id = Some(message_id); response.data.push(msg); @@ -68,13 +67,13 @@ pub mod endpoint { (axum::http::StatusCode::CREATED, axum::Json(response)) } Err(err) => { - eprintln!("Error: {err:?}"); - response.message = String::from("Contact not created"); + eprintln!("Error: {err:?}"); + response.message = String::from("Contact not created"); - ( - axum::http::StatusCode::INTERNAL_SERVER_ERROR, - axum::Json(response), - ) + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + axum::Json(response), + ) } } } else { diff --git a/src/config/mod.rs b/src/config/mod.rs index daf5acb..f8a03e9 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -17,8 +17,8 @@ pub mod init { use crate::caller::contact as contact_caller; use crate::caller::message as message_caller; use contact_caller::endpoint as contact_endpoints; - use message_caller::endpoint as message_endpoints; use contact_caller::response as contact_responses; + use message_caller::endpoint as message_endpoints; use message_caller::response as message_responses; mod cors { @@ -76,9 +76,9 @@ pub mod init { #[derive(utoipa::OpenApi)] #[openapi( - paths(contact_endpoints::create_contact, + paths(contact_endpoints::create_contact, message_endpoints::create_message), - components(schemas(contact_responses::AddContactResponse)), + components(schemas(contact_responses::AddContactResponse, message_responses::AddMessageResponse)), tags( (name = "textsender API", description = "Web API to manage texting") ) @@ -107,9 +107,9 @@ pub mod init { ) .route( crate::caller::endpoints::ADD_MESSAGE, - patch(message_endpoints::create_message).route_layer( - axum::middleware::from_fn(crate::auth::auth::), - ), + post(message_endpoints::create_message).route_layer(axum::middleware::from_fn( + crate::auth::auth::, + )), ) .layer(cors::configure_cors().await) } diff --git a/src/repo/message.rs b/src/repo/message.rs index a5bf5ae..312e893 100644 --- a/src/repo/message.rs +++ b/src/repo/message.rs @@ -7,7 +7,7 @@ pub async fn insert( ) -> Result { match sqlx::query( r#" - INSERT INTO "contacts" (content, user_id) + INSERT INTO "messages" (content, user_id) VALUES($1, $2) RETURNING id; "#, ) @@ -23,4 +23,3 @@ pub async fn insert( Err(_) => Err(sqlx::Error::RowNotFound), } } - -- 2.47.3 From c7b6f93675faa808b1c1a6f7099032461d4c0a69 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 17 Jun 2026 14:24:28 -0400 Subject: [PATCH 4/5] bump: textsender_api --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc3eaa9..29d1fdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2293,7 +2293,7 @@ dependencies = [ [[package]] name = "textsender_api" -version = "0.1.7" +version = "0.1.8" dependencies = [ "axum", "axum-extra", diff --git a/Cargo.toml b/Cargo.toml index ccf8ec5..5797080 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "textsender_api" -version = "0.1.7" +version = "0.1.8" edition = "2024" rust-version = "1.96" -- 2.47.3 From 29adc7c1b3d892a7e8c954a0f389cd37c4edbc80 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 17 Jun 2026 14:25:30 -0400 Subject: [PATCH 5/5] Removing unneeded schema file --- migrations/schema.sql | 49 ------------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 migrations/schema.sql diff --git a/migrations/schema.sql b/migrations/schema.sql deleted file mode 100644 index 9ca3c39..0000000 --- a/migrations/schema.sql +++ /dev/null @@ -1,49 +0,0 @@ --- CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; --- --- DROP TABLE IF EXISTS contacts CASCADE; --- DROP TABLE IF EXISTS messages CASCADE; --- DROP TABLE IF EXISTS scheduled_messages CASCADE; --- DROP TABLE IF EXISTS scheduled_message_events CASCADE; --- DROP TABLE IF EXISTS message_event_responses CASCADE; --- --- CREATE TABLE IF NOT EXISTS contacts ( --- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), --- phone_number TEXT NOT NULL, --- user_id UUID NOT NULL, --- first_name TEXT NULL, --- last_name TEXT NULL, --- nickname TEXT NULL --- ); --- --- CREATE TABLE IF NOT EXISTS messages ( --- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), --- content TEXT NOT NULL, --- user_id UUID NOT NULL --- ); --- --- CREATE TABLE IF NOT EXISTS scheduled_messages ( --- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), --- scheduled timestamptz NOT NULL, --- created timestamptz DEFAULT now(), --- status TEXT CHECK (status IN ('PENDING', 'READY', 'PROCESSING', 'DONE')), --- user_id UUID NOT NULL --- ); --- --- CREATE TABLE IF NOT EXISTS scheduled_message_events ( --- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), --- contact_id UUID NOT NULL, --- message_id UUID NOT NULL, --- scheduled_message_id UUID NOT NULL, --- created timestamptz DEFAULT now() --- ); --- --- CREATE TABLE IF NOT EXISTS message_event_responses ( --- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), --- scheduled_message_event_id UUID NULL, --- response JSONB NOT NULL, --- user_id UUID NOT NULL, --- sent timestamptz NOT NULL, --- contact_id UUID NULL, --- message_id UUID NULL, --- status TEXT CHECK (status IN ('INSTANT', 'SCHEDULED')) --- ); -- 2.47.3