add: better layout
This commit is contained in:
parent
2cc9ed7445
commit
dbd70d9592
19 changed files with 451 additions and 87 deletions
100
src/routes.rs
100
src/routes.rs
|
@ -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)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue