//! Cross-service integration helpers: CSRF-token convenience and Multithreaded //! (MT) discussion-thread stats. use tower_sessions::Session; use crate::config::Config; /// Get or create a CSRF token for the session, returning `None` on failure. /// /// Convenience wrapper for templates that need an `Option`. pub async fn get_csrf_token(session: &Session) -> Option { crate::csrf::get_or_create_token(session).await.ok() } /// Fetch MT discussion thread stats (URL + post count) for a linked thread. /// Returns (discussion_url, discussion_count), both None if MT unavailable or no linked thread. pub async fn fetch_discussion_info( integrations: &crate::Integrations, config: &Config, mt_thread_id: Option, project_slug: &str, category_slug: &str, ) -> (Option, Option) { let Some(thread_id) = mt_thread_id else { return (None, None); }; let Some(ref mt) = integrations.mt_client else { return (None, None); }; let Some(ref mt_base_url) = config.integrations.mt_base_url else { return (None, None); }; let url = format!("{mt_base_url}/p/{project_slug}/{category_slug}/{thread_id}"); match tokio::time::timeout( std::time::Duration::from_secs(2), mt.get_thread_stats(thread_id), ) .await { Ok(Ok(stats)) => (Some(url), Some(stats.post_count)), Ok(Err(e)) => { tracing::debug!(error = ?e, "failed to fetch MT thread stats"); (Some(url), None) } Err(_) => { tracing::debug!("MT thread stats request timed out"); (Some(url), None) } } }