From 9778230e3fd5f938f735893274ef966392f7430e Mon Sep 17 00:00:00 2001 From: trisua Date: Sun, 20 Jul 2025 03:24:55 -0400 Subject: [PATCH] add: cache breaker "build code" --- app/public/app.js | 6 ++++-- app/templates_src/edit.lisp | 2 ++ app/templates_src/index.lisp | 1 + app/templates_src/root.lisp | 6 +++--- src/main.rs | 5 +++-- src/routes.rs | 34 +++++++++++++++++++--------------- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/app/public/app.js b/app/public/app.js index cac6874..725754f 100644 --- a/app/public/app.js +++ b/app/public/app.js @@ -97,8 +97,10 @@ globalThis.init_editor = () => { }); window.addEventListener("beforeunload", (e) => { - e.preventDefault(); - return null; + if (!globalThis.ALLOW_LEAVE) { + e.preventDefault(); + return null; + } }); }; diff --git a/app/templates_src/edit.lisp b/app/templates_src/edit.lisp index 3704b5c..c0548d6 100644 --- a/app/templates_src/edit.lisp +++ b/app/templates_src/edit.lisp @@ -104,6 +104,8 @@ .then(res => res.json()) .then((res) => { if (res.ok) { + globalThis.ALLOW_LEAVE = true; + if (!rm) { document.cookie = `Atto-Message=\"Entry updated\"; path=/`; document.cookie = \"Atto-Message-Good=true; path=/\"; diff --git a/app/templates_src/index.lisp b/app/templates_src/index.lisp index 6948f83..e9b110d 100644 --- a/app/templates_src/index.lisp +++ b/app/templates_src/index.lisp @@ -75,6 +75,7 @@ .then(res => res.json()) .then((res) => { if (res.ok) { + globalThis.ALLOW_LEAVE = true; document.cookie = `Atto-Message=\"Entry created! Your edit code: ${res.payload[1]}.\"; path=/`; document.cookie = \"Atto-Message-Good=true; path=/\"; window.location.href = `/${res.payload[0]}`; diff --git a/app/templates_src/root.lisp b/app/templates_src/root.lisp index 48d5143..8c59b81 100644 --- a/app/templates_src/root.lisp +++ b/app/templates_src/root.lisp @@ -8,15 +8,15 @@ (meta ("http-equiv" "X-UA-Compatible") ("content" "ie=edge")) (link ("rel" "icon") ("href" "/public/favicon.svg")) - (link ("rel" "stylesheet") ("href" "{{ tetratto }}/css/utility.css")) - (link ("rel" "stylesheet") ("href" "/public/style.css")) + (link ("rel" "stylesheet") ("href" "{{ tetratto }}/css/utility.css?v={{ build_code }}")) + (link ("rel" "stylesheet") ("href" "/public/style.css?v={{ build_code }}")) (meta ("name" "theme-color") ("content" "#fbc27f")) (meta ("name" "description") ("content" "{{ name }}")) (meta ("property" "og:type") ("content" "website")) (meta ("property" "og:site_name") ("content" "{{ name }}")) - (script ("src" "/public/app.js") ("defer")) + (script ("src" "/public/app.js?v={{ build_code }}") ("defer")) (text "{% block head %}{% endblock %}")) diff --git a/src/main.rs b/src/main.rs index d1e9c6b..e364a26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use nanoneo::core::element::Render; use std::{collections::HashMap, env::var, net::SocketAddr, process::exit, sync::Arc}; use tera::{Tera, Value}; use tetratto_core::sdk::DataClient; +use tetratto_shared::hash::salt; use tokio::sync::RwLock; use tower_http::{ catch_panic::CatchPanicLayer, @@ -14,7 +15,7 @@ use tower_http::{ }; use tracing::{Level, info}; -pub(crate) type InnerState = (DataClient, Tera); +pub(crate) type InnerState = (DataClient, Tera, String); pub(crate) type State = Arc>; fn render_markdown(value: &Value, _: &HashMap) -> tera::Result { @@ -93,7 +94,7 @@ async fn main() { // create app let app = Router::new() .merge(routes::routes()) - .layer(Extension(Arc::new(RwLock::new((database, tera))))) + .layer(Extension(Arc::new(RwLock::new((database, tera, salt()))))) .layer(axum::extract::DefaultBodyLimit::max( var("BODY_LIMIT") .unwrap_or("8388608".to_string()) diff --git a/src/routes.rs b/src/routes.rs index bb899b9..61ce2c9 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -36,7 +36,7 @@ pub fn routes() -> Router { .route("/api/v1/entries/{slug}", post(edit_request)) } -fn default_context(data: &DataClient) -> Context { +fn default_context(data: &DataClient, build_code: &str) -> Context { let mut ctx = Context::new(); ctx.insert( "name", @@ -47,14 +47,15 @@ fn default_context(data: &DataClient) -> Context { "what_page_slug", &std::env::var("WHAT_SLUG").unwrap_or("what".to_string()), ); + ctx.insert("build_code", &build_code); ctx } // pages async fn not_found_request(Extension(data): Extension) -> impl IntoResponse { - let (ref data, ref tera) = *data.read().await; + let (ref data, ref tera, ref build_code) = *data.read().await; - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert( "error", &Error::GeneralNotFound("page".to_string()).to_string(), @@ -63,15 +64,18 @@ async fn not_found_request(Extension(data): Extension) -> impl IntoRespon } async fn index_request(Extension(data): Extension) -> impl IntoResponse { - let (ref data, ref tera) = *data.read().await; - Html(tera.render("index.lisp", &default_context(&data)).unwrap()) + let (ref data, ref tera, ref build_code) = *data.read().await; + Html( + tera.render("index.lisp", &default_context(&data, &build_code)) + .unwrap(), + ) } async fn view_request( Extension(data): Extension, Path(slug): Path, ) -> impl IntoResponse { - let (ref data, ref tera) = *data.read().await; + let (ref data, ref tera, ref build_code) = *data.read().await; let entry = match data .query(&SimplifiedQuery { query: AppDataSelectQuery::KeyIs(format!("entries('{}')", slug)), @@ -84,7 +88,7 @@ async fn view_request( AppDataQueryResult::Many(_) => unreachable!(), }, Err(_) => { - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert( "error", &Error::GeneralNotFound("entry".to_string()).to_string(), @@ -106,7 +110,7 @@ async fn view_request( AppDataQueryResult::Many(_) => unreachable!(), }, Err(e) => { - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert("error", &e.to_string()); return Html(tera.render("error.lisp", &ctx).unwrap()); @@ -115,14 +119,14 @@ async fn view_request( // count view if let Err(e) = data.update(views_id, (views + 1).to_string()).await { - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert("error", &e.to_string()); return Html(tera.render("error.lisp", &ctx).unwrap()); } // ... - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert("entry", &entry); ctx.insert("views", &views); @@ -134,7 +138,7 @@ async fn editor_request( Extension(data): Extension, Path(slug): Path, ) -> impl IntoResponse { - let (ref data, ref tera) = *data.read().await; + let (ref data, ref tera, ref build_code) = *data.read().await; let entry = match data .query(&SimplifiedQuery { query: AppDataSelectQuery::KeyIs(format!("entries('{}')", slug)), @@ -147,7 +151,7 @@ async fn editor_request( AppDataQueryResult::Many(_) => unreachable!(), }, Err(_) => { - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert( "error", &Error::GeneralNotFound("entry".to_string()).to_string(), @@ -158,7 +162,7 @@ async fn editor_request( }; // ... - let mut ctx = default_context(&data); + let mut ctx = default_context(&data, &build_code); ctx.insert("entry", &entry); Html(tera.render("edit.lisp", &ctx).unwrap()) @@ -191,7 +195,7 @@ async fn create_request( Extension(data): Extension, Json(req): Json, ) -> impl IntoResponse { - let (ref data, _) = *data.read().await; + let (ref data, _, _) = *data.read().await; // check lengths if req.slug.len() < 2 { @@ -268,7 +272,7 @@ async fn edit_request( Path(slug): Path, Json(req): Json, ) -> impl IntoResponse { - let (ref data, _) = *data.read().await; + let (ref data, _, _) = *data.read().await; let (id, mut entry) = match data .query(&SimplifiedQuery {