add: better layout

This commit is contained in:
trisua 2025-07-25 15:12:15 -04:00
parent 2cc9ed7445
commit dbd70d9592
19 changed files with 451 additions and 87 deletions

View file

@ -8,6 +8,8 @@ use axum::{
response::{Html, IntoResponse},
routing::{get, get_service, post},
};
use axum_extra::extract::CookieJar;
use pathbufd::PathBufD;
use serde::Deserialize;
use serde_valid::Validate;
use tera::Context;
@ -32,6 +34,7 @@ pub fn routes() -> Router {
get_service(tower_http::services::ServeDir::new("./public")),
)
.fallback(not_found_request)
.route("/docs/{name}", get(view_doc_request))
// pages
.route("/", get(index_request))
.route("/{slug}", get(view_request))
@ -78,6 +81,39 @@ async fn index_request(Extension(data): Extension<State>) -> impl IntoResponse {
)
}
async fn view_doc_request(
Extension(data): Extension<State>,
Path(name): Path<String>,
) -> impl IntoResponse {
let (ref data, ref tera, ref build_code) = *data.read().await;
let path = PathBufD::current().extend(&["docs", &format!("{name}.md")]);
if !std::fs::exists(&path).unwrap_or(false) {
let mut ctx = default_context(&data, &build_code);
ctx.insert(
"error",
&Error::GeneralNotFound("entry".to_string()).to_string(),
);
return Html(tera.render("error.lisp", &ctx).unwrap());
}
let text = match std::fs::read_to_string(&path) {
Ok(t) => t,
Err(e) => {
let mut ctx = default_context(&data, &build_code);
ctx.insert("error", &Error::MiscError(e.to_string()).to_string());
return Html(tera.render("error.lisp", &ctx).unwrap());
}
};
let mut ctx = default_context(&data, &build_code);
ctx.insert("text", &text);
ctx.insert("file_name", &name);
return Html(tera.render("doc.lisp", &ctx).unwrap());
}
async fn view_request(
Extension(data): Extension<State>,
Path(slug): Path<String>,
@ -258,27 +294,46 @@ fn default_random() -> String {
salt()
}
/// The time that must be waited between each entry creation.
const CREATE_WAIT_TIME: usize = 5000;
async fn create_request(
jar: CookieJar,
Extension(data): Extension<State>,
Json(req): Json<CreateEntry>,
) -> impl IntoResponse {
) -> std::result::Result<impl IntoResponse, Json<ApiReturn<()>>> {
let (ref data, _, _) = *data.read().await;
// check wait time
if let Some(cookie) = jar.get("__Secure-Claim-Next") {
if unix_epoch_timestamp()
!= cookie
.to_string()
.replace("__Secure-Claim-Next=", "")
.parse::<usize>()
.unwrap_or(0)
{
return Err(Json(
Error::MiscError("You must wait a bit to create another entry".to_string()).into(),
));
}
}
// check lengths
if req.slug.len() < 2 {
return Json(Error::DataTooShort("slug".to_string()).into());
return Err(Json(Error::DataTooShort("slug".to_string()).into()));
}
if req.slug.len() > 32 {
return Json(Error::DataTooLong("slug".to_string()).into());
return Err(Json(Error::DataTooLong("slug".to_string()).into()));
}
if req.content.len() < 2 {
return Json(Error::DataTooShort("content".to_string()).into());
return Err(Json(Error::DataTooShort("content".to_string()).into()));
}
if req.content.len() > 150_000 {
return Json(Error::DataTooLong("content".to_string()).into());
return Err(Json(Error::DataTooLong("content".to_string()).into()));
}
// check slug
@ -288,17 +343,19 @@ async fn create_request(
.unwrap();
if regex.captures(&req.slug).is_some() {
return Json(Error::MiscError("This slug contains invalid characters".to_string()).into());
return Err(Json(
Error::MiscError("This slug contains invalid characters".to_string()).into(),
));
}
// check metadata
let metadata: EntryMetadata = match toml::from_str(&EntryMetadata::ini_to_toml(&req.metadata)) {
Ok(x) => x,
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
Err(e) => return Err(Json(Error::MiscError(e.to_string()).into())),
};
if let Err(e) = metadata.validate() {
return Json(Error::MiscError(e.to_string()).into());
return Err(Json(Error::MiscError(e.to_string()).into()));
}
// check for existing
@ -310,7 +367,9 @@ async fn create_request(
.await
.is_ok()
{
return Json(Error::MiscError("Slug already in use".to_string()).into());
return Err(Json(
Error::MiscError("Slug already in use".to_string()).into(),
));
}
// create
@ -333,22 +392,31 @@ async fn create_request(
)
.await
{
return Json(e.into());
return Err(Json(e.into()));
}
if let Err(e) = data
.insert(format!("entries.views('{}')", req.slug), 0.to_string())
.await
{
return Json(e.into());
return Err(Json(e.into()));
}
// return
Json(ApiReturn {
ok: true,
message: "Success".to_string(),
payload: Some((req.slug, req.edit_code)),
})
Ok((
[(
"Set-Cookie",
format!(
"__Secure-Claim-Next={}; SameSite=Lax; Secure; Path=/; HostOnly=true; HttpOnly=true; Max-Age=5",
unix_epoch_timestamp() + CREATE_WAIT_TIME
),
)],
Json(ApiReturn {
ok: true,
message: "Success".to_string(),
payload: Some((req.slug, req.edit_code)),
}),
))
}
#[derive(Deserialize)]