From 4537fc379c48229e9093d84f1fd70bd559668cac Mon Sep 17 00:00:00 2001 From: JOLIMAITRE Matthieu Date: Thu, 25 Jul 2024 08:48:56 +0200 Subject: [PATCH] add posting --- src/common.rs | 1 + src/main.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/common.rs b/src/common.rs index 33dd676..ef2114b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -17,6 +17,7 @@ pub fn header() -> Markup { a href = "/" { h1 { "Motifs" } } a href = "/activity" { "activité" } a href = "/topics" { "sujets" } + a href = "/create" { "créer" } } ) } diff --git a/src/main.rs b/src/main.rs index d78da10..3c251b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,15 @@ -use std::fmt::Write; -use std::sync::{Arc, RwLock}; +use std::{ + fmt::Write, + sync::{Arc, RwLock}, +}; use anyhow::Result; use axum::{ extract::{Path, State}, - response::IntoResponse, + http::StatusCode, + response::{IntoResponse, Redirect, Response}, routing::get, - Json, Router, + Form, Json, Router, }; use chrono::prelude::*; use common::{footer, head, header, style}; @@ -33,6 +36,7 @@ async fn main() -> Result<()> { .route("/style.css", get(style)) .route("/topics", get(topics).post(post)) .route("/topic/:name", get(topic)) + .route("/create", get(create)) .route("/activity", get(activity)) .route("/", get(home)) .with_state(state); @@ -147,18 +151,30 @@ struct PostContent { async fn post( State(state): State, - Json(PostContent { + Form(PostContent { topic, content, author, - }): Json, -) -> impl IntoResponse { + }): Form, +) -> Response { let mut store = state.store.write().unwrap(); let date = Utc::now().format("%d/%m/%Y"); - let topic = sanithize_identifier(&topic); + let topic = sanithize_identifier(topic.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}"); store.insert(&topic, content).unwrap(); + Redirect::to("/activity").into_response() } fn sanithize_identifier(input: &str) -> String { @@ -177,6 +193,7 @@ fn sanithize_identifier(input: &str) -> String { ('ö', 'o'), ('û', 'u'), ('ü', 'u'), + (' ', '_'), ]; text.chars() .map(|c| { @@ -187,10 +204,41 @@ fn sanithize_identifier(input: &str) -> String { } c }) - .filter(char::is_ascii) + .filter(|c| c.is_ascii_lowercase() || *c == '_') .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 { let message = message.to_string(); html!(