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 {