The smokesignal.events web application
at main 71 lines 2.3 kB view raw
1use axum::Json; 2use axum::extract::State; 3use axum::http::StatusCode; 4use axum::response::IntoResponse; 5use axum_extra::extract::Cached; 6use serde::{Deserialize, Serialize}; 7use serde_json::json; 8 9use crate::facets::{FacetLimits, parse_facets_from_text, render_text_with_facets_html}; 10use crate::http::context::WebContext; 11use crate::http::errors::WebError; 12use crate::http::middleware_auth::Auth; 13 14#[derive(Debug, Deserialize)] 15pub(crate) struct PreviewDescriptionRequest { 16 pub description: String, 17} 18 19#[derive(Debug, Serialize)] 20pub(crate) struct PreviewDescriptionResponse { 21 pub html: String, 22} 23 24/// Handler for previewing event descriptions with rendered facets 25/// 26/// This endpoint accepts description text, parses facets (mentions, links, hashtags), 27/// and returns rendered HTML showing how the description will appear to users. 28pub(crate) async fn handle_preview_description( 29 State(web_context): State<WebContext>, 30 Cached(_auth): Cached<Auth>, 31 Json(request): Json<PreviewDescriptionRequest>, 32) -> Result<impl IntoResponse, WebError> { 33 // Validate description length (same as create event validation) 34 if request.description.trim().len() < 10 { 35 return Ok(( 36 StatusCode::BAD_REQUEST, 37 Json(json!({"error": "Description must be at least 10 characters"})), 38 ) 39 .into_response()); 40 } 41 42 if request.description.len() > 3000 { 43 return Ok(( 44 StatusCode::BAD_REQUEST, 45 Json(json!({"error": "Description must be no more than 3000 characters"})), 46 ) 47 .into_response()); 48 } 49 50 // Trim description to match create/edit behavior - facets must be parsed from the same text 51 let description = request.description.trim(); 52 53 // Parse facets from the description 54 let limits = FacetLimits::default(); 55 let facets = 56 parse_facets_from_text(description, web_context.identity_resolver.as_ref(), &limits).await; 57 58 // Render HTML with facets 59 let html = render_text_with_facets_html(description, facets.as_ref(), &limits); 60 61 // Convert newlines to <br> tags for proper display 62 let html_with_breaks = html.replace('\n', "<br>"); 63 64 Ok(( 65 StatusCode::OK, 66 Json(PreviewDescriptionResponse { 67 html: html_with_breaks, 68 }), 69 ) 70 .into_response()) 71}