//! Support ticket submission from the user dashboard. use axum::{ extract::State, response::{Html, IntoResponse, Response}, Form, }; use serde::Deserialize; use crate::{ auth::AuthUser, error::Result, templates::FormStatusTemplate, AppState, }; /// Form input for submitting a support ticket. #[derive(Debug, Deserialize)] pub struct SupportTicketForm { pub subject: String, pub message: String, pub category: String, } /// Submit a support ticket. Creates a WAM ticket and sends a confirmation email. #[tracing::instrument(skip_all, name = "users::submit_support_ticket")] pub(in crate::routes::api) async fn submit_support_ticket( State(state): State, AuthUser(user): AuthUser, Form(form): Form, ) -> Result { user.check_not_sandbox()?; let subject = form.subject.trim(); let message = form.message.trim(); let category = form.category.trim(); if subject.is_empty() || subject.len() > 200 { return Ok(Html(FormStatusTemplate { success: false, message: "Subject must be between 1 and 200 characters.".to_string(), }.render_string()).into_response()); } if message.is_empty() || message.len() > 5000 { return Ok(Html(FormStatusTemplate { success: false, message: "Message must be between 1 and 5000 characters.".to_string(), }.render_string()).into_response()); } let valid_categories = ["bug", "billing", "account", "content", "security", "other"]; if !valid_categories.contains(&category) { return Ok(Html(FormStatusTemplate { success: false, message: "Please select a valid category.".to_string(), }.render_string()).into_response()); } // Build ticket body let body = format!( "From: {} ({})\nCategory: {}\n\n{}", user.username, user.email, category, message ); // Create WAM ticket for triage if let Some(ref wam) = state.wam { let title = format!("[support] {}", subject); wam.create_ticket( &title, Some(&body), "medium", "support-ticket", Some(&user.id.to_string()), ).await; } // Send confirmation email to the user let confirmation = format!( r#"Hi {}, We received your support request: Subject: {} Category: {} {} We'll get back to you as soon as we can. Every response is from a real person. -- Makenotwork Support"#, user.display_name.as_deref().unwrap_or(user.username.as_ref()), subject, category, message, ); if let Err(e) = state.email.send_alert( &user.email, &format!("We received your request: {}", subject), &confirmation, ).await { tracing::warn!(error = ?e, "failed to send support confirmation email"); } // Send notification email to support let support_body = format!( "New support ticket from {} ({}):\n\nSubject: {}\nCategory: {}\nUser ID: {}\n\n{}", user.username, user.email, subject, category, user.id, message, ); if let Err(e) = state.email.send_alert( "info@makenot.work", &format!("[support] {}", subject), &support_body, ).await { tracing::warn!(error = ?e, "failed to send support notification email"); } Ok(Html(FormStatusTemplate { success: true, message: "Your message has been submitted. Check your email for a confirmation. We'll get back to you soon.".to_string(), }.render_string()).into_response()) }