4 Commits
Author SHA1 Message Date
phoenix 79f9fc3972 Update rust (#31)
Rust Build / Check (push) Successful in 2m28s
Rust Build / Test Suite (push) Successful in 3m12s
Rust Build / Rustfmt (push) Successful in 1m8s
Rust Build / Clippy (push) Successful in 1m27s
Rust Build / build (push) Successful in 3m59s
textsender_api PR / Clippy (pull_request) Has been cancelled
textsender_api PR / Check (pull_request) Has been cancelled
textsender_api PR / Rustfmt (pull_request) Has been cancelled
Reviewed-on: phoenix/textsender_api#31
2026-07-06 22:31:22 -04:00
phoenix 23f9a1430a Update dependencies (#30)
Rust Build / Test Suite (push) Failing after 58s
Rust Build / Rustfmt (push) Successful in 27s
Rust Build / Clippy (push) Successful in 1m21s
Rust Build / Check (push) Successful in 2m7s
Rust Build / build (push) Successful in 3m5s
textsender_api PR / Rustfmt (pull_request) Successful in 2m0s
textsender_api PR / Check (pull_request) Successful in 2m2s
textsender_api PR / Clippy (pull_request) Successful in 2m37s
Reviewed-on: phoenix/textsender_api#30
2026-07-04 21:07:30 -04:00
phoenix ba485261da Fixed issue (#29)
Rust Build / Rustfmt (push) Successful in 46s
Rust Build / Test Suite (push) Successful in 1m21s
Rust Build / Check (push) Successful in 2m20s
Rust Build / Clippy (push) Successful in 1m48s
Rust Build / build (push) Successful in 2m11s
textsender_api PR / Rustfmt (pull_request) Successful in 1m6s
textsender_api PR / Clippy (pull_request) Successful in 1m22s
textsender_api PR / Check (pull_request) Successful in 2m9s
Reviewed-on: phoenix/textsender_api#29
2026-07-04 18:34:51 -04:00
phoenix 71da521a53 CORS bug fix (#28)
Rust Build / Test Suite (push) Successful in 2m15s
Rust Build / Rustfmt (push) Successful in 48s
Rust Build / Check (push) Successful in 1m59s
Rust Build / Clippy (push) Successful in 1m38s
Rust Build / build (push) Successful in 3m44s
Reviewed-on: phoenix/textsender_api#28
2026-06-30 11:55:32 -04:00
14 changed files with 190 additions and 710 deletions
+2 -1
View File
@@ -10,4 +10,5 @@ TWILIO_AUTH_SID=9M438C93R943U4329MCU43C34U
TWILIO_SERVICE_SID=9M4J3X8439U398NUVT3342MC349C348T TWILIO_SERVICE_SID=9M4J3X8439U398NUVT3342MC349C348T
TWILIO_AUTH_TOKEN="MA08HJp9tYtkfs72m8JIIROofRVm74oR0ixEYBHGYpB9" TWILIO_AUTH_TOKEN="MA08HJp9tYtkfs72m8JIIROofRVm74oR0ixEYBHGYpB9"
TWILIO_PHONE_NUMBER=+10123456789 TWILIO_PHONE_NUMBER=+10123456789
ALLOWED_ORIGINS="http://textsender.com" ALLOWED_ORIGINS="http://textsender.com,http://localhost:5173,http://localhost:9080,http://localhost:9081"
APP_ENV=production
+2 -1
View File
@@ -10,4 +10,5 @@ TWILIO_AUTH_SID=9M438C93R943U4329MCU43C34U
TWILIO_SERVICE_SID=9M4J3X8439U398NUVT3342MC349C348T TWILIO_SERVICE_SID=9M4J3X8439U398NUVT3342MC349C348T
TWILIO_AUTH_TOKEN="MA08HJp9tYtkfs72m8JIIROofRVm74oR0ixEYBHGYpB9" TWILIO_AUTH_TOKEN="MA08HJp9tYtkfs72m8JIIROofRVm74oR0ixEYBHGYpB9"
TWILIO_PHONE_NUMBER=+10123456789 TWILIO_PHONE_NUMBER=+10123456789
ALLOWED_ORIGINS="http://textsender.com" ALLOWED_ORIGINS="http://textsender.com,http://localhost:5173,http://localhost:9080,http://localhost:9081"
APP_ENV=production
+10 -6
View File
@@ -5,15 +5,19 @@ on:
branches: branches:
- main - main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
check: check:
name: Check name: Check
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -30,10 +34,10 @@ jobs:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add rustfmt - run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
@@ -50,10 +54,10 @@ jobs:
name: Clippy name: Clippy
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add clippy - run: rustup component add clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
+4 -4
View File
@@ -32,10 +32,10 @@ jobs:
--health-retries 5 --health-retries 5
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
# --- Add this step for explicit verification --- # --- Add this step for explicit verification ---
- name: Verify Docker Environment - name: Verify Docker Environment
run: | run: |
@@ -74,10 +74,10 @@ jobs:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add rustfmt - run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
+10 -10
View File
@@ -15,10 +15,10 @@ jobs:
name: Check name: Check
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -52,10 +52,10 @@ jobs:
--health-retries 5 --health-retries 5
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
# --- Add this step for explicit verification --- # --- Add this step for explicit verification ---
- name: Verify Docker Environment - name: Verify Docker Environment
run: | run: |
@@ -94,10 +94,10 @@ jobs:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add rustfmt - run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
@@ -114,10 +114,10 @@ jobs:
name: Clippy name: Clippy
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- run: rustup component add clippy - run: rustup component add clippy
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
@@ -134,10 +134,10 @@ jobs:
name: build name: build
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1 - uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.96 toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- run: | - run: |
mkdir -p ~/.ssh mkdir -p ~/.ssh
Generated
+117 -636
View File
File diff suppressed because it is too large Load Diff
+8 -11
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "textsender_api" name = "textsender_api"
version = "0.2.0" version = "0.2.3"
edition = "2024" edition = "2024"
rust-version = "1.96" rust-version = "1.96.1"
[dependencies] [dependencies]
axum = { version = "0.8.9", features = ["multipart"] } axum = { version = "0.8.9", features = ["multipart"] }
@@ -10,21 +10,18 @@ axum-extra = { version = "0.12.6", features = ["cookie"] }
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.150" } serde_json = { version = "1.0.150" }
tokio = { version = "1.52.3", features = ["full"] } tokio = { version = "1.52.3", features = ["full"] }
tokio-util = { version = "0.7.18", features = ["io"] } tower-http = { version = "0.7.0", features = ["cors", "timeout"] }
tower = { version = "0.5.3", features = ["full"] }
tower-http = { version = "0.6.11", features = ["cors", "timeout"] }
tracing-subscriber = "0.3.23" tracing-subscriber = "0.3.23"
futures = { version = "0.3.32" }
uuid = { version = "1.23.3", features = ["v4", "serde"] } uuid = { version = "1.23.3", features = ["v4", "serde"] }
sqlx = { version = "0.9.0", features = ["runtime-tokio", "tls-native-tls", "postgres", "time", "uuid"] } sqlx = { version = "0.9.0", features = ["runtime-tokio", "tls-native-tls", "postgres", "time", "uuid"] }
time = { version = "0.3.49", features = ["formatting", "macros", "parsing", "serde"] } time = { version = "0.3.53", features = ["formatting", "macros", "parsing", "serde"] }
jsonwebtoken = { version = "10.4.0", features = ["rust_crypto"] } jsonwebtoken = { version = "10.4.0", features = ["rust_crypto"] }
josekit = { version = "0.10.3" }
utoipa = { version = "5.5.0", features = ["axum_extras"] } utoipa = { version = "5.5.0", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] } utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.4.10" } textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.5.1" }
swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.4.2.0" } swoosh = { git = "ssh://git@git.kundeng.us/phoenix/swoosh.git", tag = "v0.5.2" }
[dev-dependencies] [dev-dependencies]
tower = { version = "0.5.3", features = ["full"] }
josekit = { version = "0.10.3" }
url = { version = "2.5.8" } url = { version = "2.5.8" }
tempfile = { version = "3.27.0" }
+1 -1
View File
@@ -1,5 +1,5 @@
# Stage 1: Build the application # Stage 1: Build the application
FROM rust:1.96 as builder FROM rust:1.96.1 as builder
# Set the working directory inside the container # Set the working directory inside the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
+1 -3
View File
@@ -36,9 +36,7 @@ pub async fn auth<B>(
(StatusCode::UNAUTHORIZED, Json(json_error)) (StatusCode::UNAUTHORIZED, Json(json_error))
})?; })?;
let secret_key = textsender_models::envy::environment::get_secret_main_key() let secret_key = textsender_models::envy::environment::get_secret_main_key().value;
.await
.value;
let mut validation = Validation::new(jsonwebtoken::Algorithm::HS256); let mut validation = Validation::new(jsonwebtoken::Algorithm::HS256);
validation.set_audience(&["textsender"]); // Must match exactly what's in the token validation.set_audience(&["textsender"]); // Must match exactly what's in the token
+22 -17
View File
@@ -81,18 +81,17 @@ pub mod endpoint {
match message_repo::get(&pool, &payload.message_id).await { match message_repo::get(&pool, &payload.message_id).await {
Ok(message) => { Ok(message) => {
println!("Valid message"); println!("Valid message");
let t_config = let t_config = match textsender_models::config::auxiliary::load_config() {
match textsender_models::config::auxiliary::load_config().await { Ok(config) => config,
Ok(config) => config, Err(err) => {
Err(err) => { eprintln!("Error: {err:?}");
eprintln!("Error: {err:?}"); response.message = String::from("Error getting config");
response.message = String::from("Error getting config"); return (
return ( axum::http::StatusCode::INTERNAL_SERVER_ERROR,
axum::http::StatusCode::INTERNAL_SERVER_ERROR, axum::Json(response),
axum::Json(response), );
); }
} };
};
let mut results: Vec< let mut results: Vec<
textsender_models::message::event::MessageEventResponse, textsender_models::message::event::MessageEventResponse,
> = Vec::new(); > = Vec::new();
@@ -101,12 +100,18 @@ pub mod endpoint {
schedule_at: None, schedule_at: None,
}; };
let mut sendmsg = swoosh::SendMsg::default();
sendmsg.load_config(
&t_config.auth_token,
&t_config.phone_number,
&t_config.service_sid,
&t_config.account_sid,
);
for contact in &contacts { for contact in &contacts {
match swoosh::twilio::api::send_message( sendmsg.load_message(&message.content);
&message, contact, &pp, &t_config, sendmsg.load_recipient(&contact.phone_number);
) match sendmsg.send_message(&pp).await {
.await
{
Ok(result) => { Ok(result) => {
let val = swoosh::twilio::api::response_to_json(result).await; let val = swoosh::twilio::api::response_to_json(result).await;
let mer = textsender_models::message::event::MessageEventResponse { let mer = textsender_models::message::event::MessageEventResponse {
+2 -1
View File
@@ -33,6 +33,7 @@ pub mod init {
let cors = tower_http::cors::CorsLayer::new() let cors = tower_http::cors::CorsLayer::new()
.allow_methods([ .allow_methods([
axum::http::Method::GET, axum::http::Method::GET,
axum::http::Method::PATCH,
axum::http::Method::POST, axum::http::Method::POST,
axum::http::Method::PUT, axum::http::Method::PUT,
axum::http::Method::DELETE, axum::http::Method::DELETE,
@@ -49,7 +50,7 @@ pub mod init {
Ok("production") => { Ok("production") => {
// In production, allow only your specific, trusted origins // In production, allow only your specific, trusted origins
let allowed_origins_env = let allowed_origins_env =
textsender_models::envy::environment::get_allowed_origins().await; textsender_models::envy::environment::get_allowed_origins();
match textsender_models::envy::utility::delimitize(&allowed_origins_env) { match textsender_models::envy::utility::delimitize(&allowed_origins_env) {
Ok(alwd) => { Ok(alwd) => {
let allowed_origins: Vec<axum::http::HeaderValue> = alwd let allowed_origins: Vec<axum::http::HeaderValue> = alwd
+1 -3
View File
@@ -5,9 +5,7 @@ pub mod connection_settings {
} }
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> { pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let database_url = textsender_models::envy::environment::get_db_url() let database_url = textsender_models::envy::environment::get_db_url().value;
.await
.value;
println!("Database url: {database_url}"); println!("Database url: {database_url}");
PgPoolOptions::new() PgPoolOptions::new()
+4 -2
View File
@@ -96,7 +96,9 @@ async fn parse_row(
let contact_id: uuid::Uuid = row.try_get("contact_id")?; let contact_id: uuid::Uuid = row.try_get("contact_id")?;
let message_id: uuid::Uuid = row.try_get("message_id")?; let message_id: uuid::Uuid = row.try_get("message_id")?;
let sent: time::OffsetDateTime = row.try_get("sent")?; let sent: time::OffsetDateTime = row.try_get("sent")?;
let scheduled_message_event_id: uuid::Uuid = row.try_get("scheduled_message_event_id")?; let scheduled_message_event_id: Option<uuid::Uuid> = row
.try_get("scheduled_message_event_id")
.unwrap_or_default();
let user_id: uuid::Uuid = row.try_get("user_id")?; let user_id: uuid::Uuid = row.try_get("user_id")?;
Ok(textsender_models::message::event::MessageEventResponse { Ok(textsender_models::message::event::MessageEventResponse {
@@ -106,7 +108,7 @@ async fn parse_row(
message_id, message_id,
status, status,
sent: Some(sent), sent: Some(sent),
scheduled_message_event_id: Some(scheduled_message_event_id), scheduled_message_event_id,
user_id, user_id,
}) })
} }
+6 -14
View File
@@ -6,9 +6,7 @@ mod db_mgr {
pub const LIMIT: usize = 6; pub const LIMIT: usize = 6;
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> { pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let tm_db_url = textsender_models::envy::environment::get_db_url() let tm_db_url = textsender_models::envy::environment::get_db_url().value;
.await
.value;
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
sqlx::PgPool::connect_with(tm_options).await sqlx::PgPool::connect_with(tm_options).await
} }
@@ -20,9 +18,7 @@ mod db_mgr {
} }
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> { pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
let db_url = textsender_models::envy::environment::get_db_url() let db_url = textsender_models::envy::environment::get_db_url().value;
.await
.value;
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
sqlx::PgPool::connect_with(options).await sqlx::PgPool::connect_with(options).await
} }
@@ -81,9 +77,7 @@ mod db_mgr {
} }
pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> { pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
let database_url = textsender_models::envy::environment::get_db_url() let database_url = textsender_models::envy::environment::get_db_url().value;
.await
.value;
let parsed_url = url::Url::parse(&database_url)?; let parsed_url = url::Url::parse(&database_url)?;
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" { if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
@@ -191,9 +185,7 @@ pub fn test_mer_response() -> serde_json::Value {
} }
pub async fn test_token() -> Result<String, josekit::JoseError> { pub async fn test_token() -> Result<String, josekit::JoseError> {
let key: String = textsender_models::envy::environment::get_secret_main_key() let key: String = textsender_models::envy::environment::get_secret_main_key().value;
.await
.value;
let (message, issuer, audience) = token_fields(); let (message, issuer, audience) = token_fields();
let token_resource = textsender_models::token::TokenResource { let token_resource = textsender_models::token::TokenResource {
@@ -203,8 +195,8 @@ pub async fn test_token() -> Result<String, josekit::JoseError> {
user_id: TEST_USER_ID, user_id: TEST_USER_ID,
}; };
match textsender_models::token::create_token(&key, &token_resource, time::Duration::hours(1)) { match textsender_models::token::create_token(&key, token_resource, time::Duration::hours(1)) {
Ok((access_token, _some_time)) => Ok(access_token), Ok(access_token) => Ok(access_token.access_token),
Err(err) => Err(err), Err(err) => Err(err),
} }
} }