From 87d1b33d7c48dbd192b3967310f6e5eee17cabe3 Mon Sep 17 00:00:00 2001 From: Josef Rokos Date: Fri, 18 Apr 2025 11:57:40 +0200 Subject: [PATCH] Application can now run as Docker container. --- Cargo.lock | 1 + Cargo.toml | 1 + Dockerfile | 51 ++++++++++++++++++++++++++++++++ migrations/05_dyn_style_name.sql | 1 + src/backend/appearance.rs | 38 ++++++++++++++++++++---- src/backend/data.rs | 3 +- src/components/header.rs | 12 ++++++-- src/main.rs | 2 +- 8 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 Dockerfile create mode 100644 migrations/05_dyn_style_name.sql diff --git a/Cargo.lock b/Cargo.lock index 1105fa6..56d24d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3235,6 +3235,7 @@ dependencies = [ "lettre", "log", "pwhash", + "rand", "regex", "rust_decimal", "serde", diff --git a/Cargo.toml b/Cargo.toml index fa0df67..7a1f55a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ leptos-captcha = "0.2.0" charts-rs = { version = "0.3.5", optional = true} #image = { version = "0.24.8", optional = true } base64 = "0.22.0" +rand = "0.8.5" [features] csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..665f95b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +FROM rust:1.86.0-bookworm AS builder + +# Install cargo-binstall, which makes it easier to install other +# cargo extensions like cargo-leptos +RUN wget https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz +RUN tar -xvf cargo-binstall-x86_64-unknown-linux-musl.tgz +RUN cp cargo-binstall /usr/local/cargo/bin + +# Install required tools +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends clang + +# Install cargo-leptos +RUN cargo binstall cargo-leptos -y + +RUN rustup default stable + +# Add the WASM target +RUN rustup target add wasm32-unknown-unknown +#RUN rustup target add wasm32-unknown-unknown --toolchain nightly + + +# Make an /app dir, which everything will eventually live in +RUN mkdir -p /app +WORKDIR /app +COPY . . + +# Build the app +#RUN cargo leptos build --release -vv +RUN LEPTOS_OUTPUT_NAME="rezervator-$(tr -dc a-z0-9 Result<(), AppError> { let count: (i64,) = query_as("SELECT COUNT(id) FROM appearance") @@ -32,6 +35,11 @@ cfg_if! { if #[cfg(feature = "ssr")] { .await?; } + let app = query_as::<_, Appearance>("SELECT * FROM appearance").fetch_one(pool).await?; + if let None = app.css_name { + query("UPDATE appearance SET css_name = 'banner.css'").execute(pool).await?; + } + Ok(()) } @@ -44,8 +52,8 @@ cfg_if! { if #[cfg(feature = "ssr")] { Ok(()) } - async fn modify_style(file_name: &str) -> Result<(), AppError> { - let mut css_file = File::open("target/site/banner.css")?; + async fn modify_style(file_name: &str, pool: &PgPool) -> Result<(), AppError> { + let mut css_file = File::open("target/site/data/banner.css")?; let mut css_str= String::new(); css_file.read_to_string(&mut css_str)?; @@ -56,8 +64,26 @@ cfg_if! { if #[cfg(feature = "ssr")] { css_str = re.replace(&css_str, &format!("background-image: url('{}')", file_name)).to_string(); } - let mut css_file = File::create("target/site/banner.css")?; + let old_css: (String,) = query_as("SELECT css_name FROM appearance") + .fetch_one(pool) + .await?; + + if old_css.0 != "banner.css" { + fs::remove_file(format!("target/site/data/{}", old_css.0))?; + } + + let s: String = rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(5) + .map(char::from) + .collect(); + let css_name = format!("banner-{}.css", s); + let mut css_file = File::create(format!("target/site/data/{}", css_name))?; css_file.write_all(css_str.as_bytes())?; + query("UPDATE appearance SET css_name = $1") + .bind(css_name) + .execute(pool) + .await?; Ok(()) } @@ -84,14 +110,14 @@ cfg_if! { if #[cfg(feature = "ssr")] { return Redirect::to("/admin/appearance").see_other(); } - let mut file = File::create(format!("target/site/{}", file_name)).unwrap(); + let mut file = File::create(format!("target/site/data/{}", file_name)).unwrap(); let _name = field.name(); while let Some(chunk) = field.next().await { let c = chunk.unwrap(); let _ = file.write_all(&c); } let _ = set_banner_name(&file_name, &app_data.db_pool).await; - let _ = modify_style(&file_name).await; + let _ = modify_style(&file_name, &app_data.db_pool).await; } Redirect::to("/admin/appearance").see_other() @@ -149,7 +175,7 @@ pub async fn delete_banner() -> Result, ServerFnError> { .await?; if let Some(f) = appearance.banner { - fs::remove_file(format!("target/site/{}", f))?; + fs::remove_file(format!("target/site/data/{}", f))?; } Ok(ApiResponse::Data(())) diff --git a/src/backend/data.rs b/src/backend/data.rs index 54e1e50..b6da0af 100644 --- a/src/backend/data.rs +++ b/src/backend/data.rs @@ -719,7 +719,8 @@ pub struct Appearance { id: i32, pub banner: Option, pub text: Option, - pub title: Option + pub title: Option, + pub css_name: Option } impl Appearance { diff --git a/src/components/header.rs b/src/components/header.rs index 5640270..37db58b 100644 --- a/src/components/header.rs +++ b/src/components/header.rs @@ -1,13 +1,14 @@ use leptos::*; use leptos_meta::*; use crate::app::DialogHelper; +use crate::backend::appearance::get_appearance; use crate::components::user_menu::MenuOpener; #[component] pub fn Header() -> impl IntoView { let drawer = use_context::().expect("No drawer opener"); let dlg_helper = use_context::().expect("No dialog helper"); - //let banner_css = create_signal(String::new()); + let appearance = create_blocking_resource(||(), |_| get_appearance()); view! { impl IntoView { - + + { + appearance.get().map(|a| match a { + Ok(a) => view! {}, + Err(_) => view! {} + }) + } + // diff --git a/src/main.rs b/src/main.rs index 70995d8..5cb9c5a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,7 @@ async fn main() -> std::io::Result<()> { Pow::init_random().expect("Cannot init captcha"); let cfg_path = matches.opt_str("c").unwrap_or("config.toml".to_string()); - let srv_conf = load_config(&cfg_path); + let srv_conf = load_config(cfg_path.trim()); env_logger::Builder::from_env(Env::default().default_filter_or(srv_conf.logging().severity())).init(); info!("Starting server");