use std::sync::Arc; use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use axum::{Extension, Json}; use serde::Deserialize; use tracing::warn; use crate::auth::OptionalUser; use crate::pocketbase::auth_superuser; use crate::state::AppState; #[derive(Deserialize)] pub struct UpdateNewsletterRequest { newsletter: bool, } pub async fn patch_newsletter( state: Arc, Extension(user): Extension, Json(req): Json, ) -> Response { let user = match user.0 { Some(u) => u, None => return StatusCode::UNAUTHORIZED.into_response(), }; let pb_url = state.pocketbase_url.trim_end_matches('/'); let token = match auth_superuser( &state.http_client, pb_url, &state.pocketbase_admin_email, &state.pocketbase_admin_password, ) .await { Ok(t) => t, Err(err) => { warn!("Failed to authenticate as PocketBase superuser: {err}"); return StatusCode::BAD_GATEWAY.into_response(); } }; let url = format!("{pb_url}/api/collections/users/records/{}", user.id); let res = state .http_client .patch(&url) .header("Authorization", format!("Bearer {token}")) .json(&serde_json::json!({ "newsletter": req.newsletter })) .send() .await; match res { Ok(resp) if resp.status().is_success() => { state.token_cache.invalidate_by_user_id(&user.id); StatusCode::OK.into_response() } Ok(resp) => { let status = resp.status(); let text = resp.text().await.unwrap_or_default(); warn!("PocketBase user update failed ({status}): {text}"); StatusCode::BAD_GATEWAY.into_response() } Err(err) => { warn!("PocketBase request error: {err}"); StatusCode::BAD_GATEWAY.into_response() } } }