diff --git a/crates/adapters/template-askama/templates/base.html b/crates/adapters/template-askama/templates/base.html
index 8df3e0d..d048c93 100644
--- a/crates/adapters/template-askama/templates/base.html
+++ b/crates/adapters/template-askama/templates/base.html
@@ -3,7 +3,15 @@
- Movies Diary
+ {{ ctx.page_title }}
+
+
+
+
+
+
+
+
diff --git a/crates/application/src/config.rs b/crates/application/src/config.rs
index 84c3cce..c64eeff 100644
--- a/crates/application/src/config.rs
+++ b/crates/application/src/config.rs
@@ -1,6 +1,7 @@
#[derive(Clone)]
pub struct AppConfig {
pub allow_registration: bool,
+ pub base_url: String,
}
impl AppConfig {
@@ -8,6 +9,8 @@ impl AppConfig {
let allow_registration = std::env::var("ALLOW_REGISTRATION")
.map(|v| v == "true" || v == "1")
.unwrap_or(false);
- Self { allow_registration }
+ let base_url = std::env::var("BASE_URL")
+ .unwrap_or_else(|_| "http://localhost:3000".to_string());
+ Self { allow_registration, base_url }
}
}
diff --git a/crates/application/src/ports.rs b/crates/application/src/ports.rs
index adcb3fc..5521cad 100644
--- a/crates/application/src/ports.rs
+++ b/crates/application/src/ports.rs
@@ -7,6 +7,8 @@ pub struct HtmlPageContext {
pub user_id: Option,
pub register_enabled: bool,
pub rss_url: String,
+ pub page_title: String,
+ pub canonical_url: String,
}
impl HtmlPageContext {
diff --git a/crates/presentation/src/event_handlers.rs b/crates/presentation/src/event_handlers.rs
index 5179081..ded1938 100644
--- a/crates/presentation/src/event_handlers.rs
+++ b/crates/presentation/src/event_handlers.rs
@@ -160,7 +160,7 @@ mod tests {
auth_service: Arc::new(PanicAuth),
password_hasher: Arc::new(PanicHasher),
user_repository: Arc::new(PanicUserRepo),
- config: AppConfig { allow_registration: false },
+ config: AppConfig { allow_registration: false, base_url: "http://localhost:3000".to_string() },
}
}
diff --git a/crates/presentation/src/extractors.rs b/crates/presentation/src/extractors.rs
index e1e35ed..4deb4f4 100644
--- a/crates/presentation/src/extractors.rs
+++ b/crates/presentation/src/extractors.rs
@@ -175,7 +175,7 @@ mod tests {
auth_service: Arc::new(PanicAuth),
password_hasher: Arc::new(PanicHasher),
user_repository: Arc::new(PanicUserRepo),
- config: application::config::AppConfig { allow_registration: false },
+ config: application::config::AppConfig { allow_registration: false, base_url: "http://localhost:3000".to_string() },
},
html_renderer: Arc::new(PanicRenderer),
rss_renderer: Arc::new(PanicRssRenderer),
@@ -282,7 +282,7 @@ mod tests {
auth_service: Arc::new(PanicAuth2),
password_hasher: Arc::new(PanicHasher2),
user_repository: Arc::new(PanicUserRepo2),
- config: application::config::AppConfig { allow_registration: false },
+ config: application::config::AppConfig { allow_registration: false, base_url: "http://localhost:3000".to_string() },
},
html_renderer: Arc::new(PanicRenderer2),
rss_renderer: Arc::new(PanicRssRenderer2),
@@ -341,7 +341,7 @@ mod tests {
auth_service: Arc::new(RejectingAuth),
password_hasher: Arc::new(PanicHasher3),
user_repository: Arc::new(PanicUserRepo3),
- config: application::config::AppConfig { allow_registration: false },
+ config: application::config::AppConfig { allow_registration: false, base_url: "http://localhost:3000".to_string() },
},
html_renderer: Arc::new(PanicRenderer3),
rss_renderer: Arc::new(PanicRssRenderer3),
diff --git a/crates/presentation/src/handlers.rs b/crates/presentation/src/handlers.rs
index 47b04f1..30462d7 100644
--- a/crates/presentation/src/handlers.rs
+++ b/crates/presentation/src/handlers.rs
@@ -43,6 +43,8 @@ pub mod html {
user_id: uuid,
register_enabled: state.app_ctx.config.allow_registration,
rss_url: "/feed.rss".to_string(),
+ page_title: "Movies Diary".to_string(),
+ canonical_url: state.app_ctx.config.base_url.clone(),
}
}
@@ -74,6 +76,8 @@ pub mod html {
user_id: None,
register_enabled: state.app_ctx.config.allow_registration,
rss_url: "/feed.rss".to_string(),
+ page_title: "Login — Movies Diary".to_string(),
+ canonical_url: format!("{}/login", state.app_ctx.config.base_url),
};
let html = state
.html_renderer
@@ -125,6 +129,8 @@ pub mod html {
user_id: None,
register_enabled: true,
rss_url: "/feed.rss".to_string(),
+ page_title: "Register — Movies Diary".to_string(),
+ canonical_url: format!("{}/register", state.app_ctx.config.base_url),
};
let html = state
.html_renderer
@@ -175,7 +181,9 @@ pub mod html {
State(state): State,
Query(params): Query,
) -> impl IntoResponse {
- let ctx = build_page_context(&state, Some(user_id)).await;
+ let mut ctx = build_page_context(&state, Some(user_id)).await;
+ ctx.page_title = "Log a Review — Movies Diary".to_string();
+ ctx.canonical_url = format!("{}/reviews/new", state.app_ctx.config.base_url);
let html = state
.html_renderer
.render_new_review_page(NewReviewPageData {
@@ -262,7 +270,9 @@ pub mod html {
OptionalCookieUser(user_id): OptionalCookieUser,
State(state): State,
) -> impl IntoResponse {
- let ctx = build_page_context(&state, user_id).await;
+ let mut ctx = build_page_context(&state, user_id).await;
+ ctx.page_title = "Members — Movies Diary".to_string();
+ ctx.canonical_url = format!("{}/users", state.app_ctx.config.base_url);
match application::use_cases::get_users::execute(&state.app_ctx, application::queries::GetUsersQuery).await {
Ok(users) => {
let data = application::ports::UsersPageData { ctx, users };
@@ -293,6 +303,11 @@ pub mod html {
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
};
+ let display_name = profile_user.email().value()
+ .split('@').next().unwrap_or("User");
+ ctx.page_title = format!("{}'s Diary — Movies Diary", display_name);
+ ctx.canonical_url = format!("{}/users/{}", state.app_ctx.config.base_url, profile_user_uuid);
+
let query = application::queries::GetUserProfileQuery {
user_id: profile_user_uuid,
view: view.clone(),
diff --git a/crates/presentation/src/main.rs b/crates/presentation/src/main.rs
index db1ed5c..a5afadc 100644
--- a/crates/presentation/src/main.rs
+++ b/crates/presentation/src/main.rs
@@ -32,8 +32,11 @@ async fn main() -> anyhow::Result<()> {
let app = routes::build_router(state);
- let listener = TcpListener::bind("0.0.0.0:3000").await?;
- tracing::info!("Listening on 0.0.0.0:3000");
+ let host = std::env::var("HOST").unwrap_or_else(|_| "0.0.0.0".to_string());
+ let port = std::env::var("PORT").unwrap_or_else(|_| "3000".to_string());
+ let addr = format!("{}:{}", host, port);
+ let listener = TcpListener::bind(&addr).await?;
+ tracing::info!("Listening on {}", addr);
axum::serve(listener, app).await?;
Ok(())
diff --git a/crates/presentation/tests/api_test.rs b/crates/presentation/tests/api_test.rs
index b13b229..5670d31 100644
--- a/crates/presentation/tests/api_test.rs
+++ b/crates/presentation/tests/api_test.rs
@@ -105,7 +105,7 @@ async fn test_app() -> Router {
auth_service: Arc::new(PanicAuth),
password_hasher: Arc::new(PanicHasher),
user_repository: Arc::new(NobodyUserRepo),
- config: AppConfig { allow_registration: false },
+ config: AppConfig { allow_registration: false, base_url: "http://localhost:3000".to_string() },
},
html_renderer: Arc::new(AskamaHtmlRenderer::new()),
rss_renderer: Arc::new(RssAdapter::new("http://localhost:3000".into())),