add posting

This commit is contained in:
JOLIMAITRE Matthieu 2024-07-25 08:48:56 +02:00
parent e5cb7f3d69
commit 4537fc379c
2 changed files with 58 additions and 9 deletions

View file

@ -17,6 +17,7 @@ pub fn header() -> Markup {
a href = "/" { h1 { "Motifs" } } a href = "/" { h1 { "Motifs" } }
a href = "/activity" { "activité" } a href = "/activity" { "activité" }
a href = "/topics" { "sujets" } a href = "/topics" { "sujets" }
a href = "/create" { "créer" }
} }
) )
} }

View file

@ -1,12 +1,15 @@
use std::fmt::Write; use std::{
use std::sync::{Arc, RwLock}; fmt::Write,
sync::{Arc, RwLock},
};
use anyhow::Result; use anyhow::Result;
use axum::{ use axum::{
extract::{Path, State}, extract::{Path, State},
response::IntoResponse, http::StatusCode,
response::{IntoResponse, Redirect, Response},
routing::get, routing::get,
Json, Router, Form, Json, Router,
}; };
use chrono::prelude::*; use chrono::prelude::*;
use common::{footer, head, header, style}; use common::{footer, head, header, style};
@ -33,6 +36,7 @@ async fn main() -> Result<()> {
.route("/style.css", get(style)) .route("/style.css", get(style))
.route("/topics", get(topics).post(post)) .route("/topics", get(topics).post(post))
.route("/topic/:name", get(topic)) .route("/topic/:name", get(topic))
.route("/create", get(create))
.route("/activity", get(activity)) .route("/activity", get(activity))
.route("/", get(home)) .route("/", get(home))
.with_state(state); .with_state(state);
@ -147,18 +151,30 @@ struct PostContent {
async fn post( async fn post(
State(state): State<MainState>, State(state): State<MainState>,
Json(PostContent { Form(PostContent {
topic, topic,
content, content,
author, author,
}): Json<PostContent>, }): Form<PostContent>,
) -> impl IntoResponse { ) -> Response {
let mut store = state.store.write().unwrap(); let mut store = state.store.write().unwrap();
let date = Utc::now().format("%d/%m/%Y"); let date = Utc::now().format("%d/%m/%Y");
let topic = sanithize_identifier(&topic); let topic = sanithize_identifier(topic.trim());
let content = content.trim(); let content = content.trim();
if content.len() < 10 || content.len() > 10_000 {
return (StatusCode::BAD_REQUEST, "Bad content.").into_response();
}
if author.len() > 2 || author.len() > 32 {
return (StatusCode::BAD_REQUEST, "Bad author.").into_response();
}
if topic.len() > 32 || topic.is_empty() || topic.starts_with('_') || topic.ends_with('_') {
return (StatusCode::BAD_REQUEST, "Bad topic.").into_response();
}
let content = format!("{content}\n\t~{author}, {date}"); let content = format!("{content}\n\t~{author}, {date}");
store.insert(&topic, content).unwrap(); store.insert(&topic, content).unwrap();
Redirect::to("/activity").into_response()
} }
fn sanithize_identifier(input: &str) -> String { fn sanithize_identifier(input: &str) -> String {
@ -177,6 +193,7 @@ fn sanithize_identifier(input: &str) -> String {
('ö', 'o'), ('ö', 'o'),
('û', 'u'), ('û', 'u'),
('ü', 'u'), ('ü', 'u'),
(' ', '_'),
]; ];
text.chars() text.chars()
.map(|c| { .map(|c| {
@ -187,10 +204,41 @@ fn sanithize_identifier(input: &str) -> String {
} }
c c
}) })
.filter(char::is_ascii) .filter(|c| c.is_ascii_lowercase() || *c == '_')
.collect() .collect()
} }
async fn create() -> impl IntoResponse {
html!(
(head("créer"))
body {
content {
(header())
main {
h2 { "Créer" }
form id = "create" action = "/topics" method = "post" {
label for = "topic" { "Sujet" }
input type = "text" name = "topic";
br;
label for = "author" { "Auteur" }
input type = "text" name = "author";
br;
label for = "content" { "Contenu" }
textarea form = "create" name = "content" { }
br;
input type = "submit";
}
}
(footer())
}
}
)
}
fn error(message: impl ToString) -> Markup { fn error(message: impl ToString) -> Markup {
let message = message.to_string(); let message = message.to_string();
html!( html!(