//! Support ticket submission from the user dashboard. use axum::{ Form, extract::State, response::{Html, IntoResponse, Response}, }; use serde::Deserialize; use crate::{ Integrations, auth::AuthUser, email::EmailClient, error::Result, templates::FormStatusTemplate, }; /// Form input for submitting a support ticket. #[derive(Debug, Deserialize)] pub(crate) 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(email): State, State(integrations): 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.chars().count() > 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.chars().count() > 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) = integrations.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) = 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) = 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()) }