feat: add environment configuration for database and authentication, update router setup

This commit is contained in:
2025-09-06 01:55:59 +02:00
parent 3dd6c0f64b
commit 6e63dca513
12 changed files with 36 additions and 18 deletions

3
.env.example Normal file
View File

@@ -0,0 +1,3 @@
POSTGRES_USER=thoughts_user
POSTGRES_PASSWORD=postgres
POSTGRES_DB=thoughts_db

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
backend-codebase.txt
frontend-codebase.txt
frontend-codebase.txt
.env

View File

@@ -3,3 +3,5 @@ PORT=3000
DATABASE_URL="sqlite://dev.db"
# DATABASE_URL="postgresql://postgres:postgres@localhost/clean-axum"
PREFORK=1
AUTH_SECRET=your_secret_key_here
BASE_URL=http://localhost:3000

View File

@@ -1 +1,2 @@
/target
.env

View File

@@ -25,9 +25,8 @@ pub async fn federate_thought(
return;
}
let base_url = "http://localhost:3000"; // Replace in production
let thought_url = format!("{}/thoughts/{}", base_url, thought.id);
let author_url = format!("{}/users/{}", base_url, author.username);
let thought_url = format!("{}/thoughts/{}", &state.base_url, thought.id);
let author_url = format!("{}/users/{}", &state.base_url, author.username);
// Construct the "Create" activity containing the "Note" object
let activity = json!({
@@ -59,7 +58,7 @@ pub async fn federate_thought(
let client = reqwest::Client::new();
for follower in followers {
let inbox_url = format!("{}/users/{}/inbox", base_url, follower.username);
let inbox_url = format!("{}/users/{}/inbox", &state.base_url, follower.username);
tracing::info!("Federating post {} to {}", thought.id, inbox_url);
let res = client.post(&inbox_url).json(&activity).send().await;

View File

@@ -9,8 +9,11 @@ use app::state::AppState;
use crate::routers::create_router;
// TODO: middleware, logging, authentication
pub fn setup_router(conn: DatabaseConnection) -> Router {
create_router(AppState { conn })
pub fn setup_router(conn: DatabaseConnection, config: &Config) -> Router {
create_router(AppState {
conn,
base_url: config.base_url.clone(),
})
}
pub fn setup_config() -> Config {

View File

@@ -220,8 +220,7 @@ async fn get_user_by_param(
// This is the logic from `user_actor_get`.
match get_user_by_username(&state.conn, &username).await {
Ok(Some(user)) => {
let base_url = "http://localhost:3000";
let user_url = format!("{}/users/{}", base_url, user.username);
let user_url = format!("{}/users/{}", &state.base_url, user.username);
let actor = json!({
"@context": [
"https://www.w3.org/ns/activitystreams",
@@ -272,13 +271,12 @@ async fn user_outbox_get(
let thoughts = get_thoughts_by_user(&state.conn, user.id).await?;
// Format the outbox as an ActivityPub OrderedCollection
let base_url = "http://localhost:3000";
let outbox_url = format!("{}/users/{}/outbox", base_url, username);
let outbox_url = format!("{}/users/{}/outbox", &state.base_url, username);
let items: Vec<Value> = thoughts
.into_iter()
.map(|thought| {
let thought_url = format!("{}/thoughts/{}", base_url, thought.id);
let author_url = format!("{}/users/{}", base_url, thought.author_username);
let thought_url = format!("{}/thoughts/{}", &state.base_url, thought.id);
let author_url = format!("{}/users/{}", &state.base_url, thought.author_username);
json!({
"id": format!("{}/activity", thought_url),
"type": "Create",

View File

@@ -45,8 +45,7 @@ pub async fn webfinger(
_ => return Err((axum::http::StatusCode::NOT_FOUND, "User not found")),
};
let base_url = "http://localhost:3000";
let user_url = Url::parse(&format!("{}/users/{}", base_url, user.username)).unwrap();
let user_url = Url::parse(&format!("{}/users/{}", &state.base_url, user.username)).unwrap();
let response = WebFingerResponse {
subject: query.resource,

View File

@@ -4,6 +4,7 @@ pub struct Config {
pub port: u32,
pub prefork: bool,
pub auth_secret: String,
pub base_url: String,
}
impl Config {
@@ -16,7 +17,8 @@ impl Config {
.parse()
.expect("PORT is not a number"),
prefork: std::env::var("PREFORK").is_ok_and(|v| v == "1"),
auth_secret: std::env::var("AUTH_SECRET").unwrap_or_else(|_| "secret".into()),
auth_secret: std::env::var("AUTH_SECRET").expect("AUTH_SECRET is not set in .env file"),
base_url: std::env::var("BASE_URL").expect("BASE_URL is not set in .env file"),
}
}

View File

@@ -3,4 +3,5 @@ use sea_orm::DatabaseConnection;
#[derive(Clone)]
pub struct AppState {
pub conn: DatabaseConnection,
pub base_url: String,
}

View File

@@ -11,7 +11,9 @@ async fn worker(child_num: u32, db_url: &str, prefork: bool, listener: std::net:
migrate(&conn).await.expect("Migration failed!");
}
let router = setup_router(conn).attach_doc();
let config = setup_config();
let router = setup_router(conn, &config).attach_doc();
let listener = tokio::net::TcpListener::from_std(listener).expect("bind to port");
axum::serve(listener, router).await.expect("start server");

View File

@@ -13,10 +13,17 @@ pub struct TestApp {
}
pub async fn setup() -> TestApp {
std::env::set_var("DATABASE_URL", "sqlite::memory:");
std::env::set_var("AUTH_SECRET", "test_secret");
std::env::set_var("BASE_URL", "http://localhost:3000");
std::env::set_var("HOST", "localhost");
std::env::set_var("PORT", "3000");
std::env::set_var("LOG_LEVEL", "debug");
let db = setup_test_db("sqlite::memory:")
.await
.expect("Failed to set up test db");
let router = setup_router(db.clone());
let router = setup_router(db.clone(), &app::config::Config::from_env());
TestApp { router, db }
}