use axum::{extract::Path, response::IntoResponse}; use axum_extra::extract::Form; use axum_htmx::HxRedirect; use http::StatusCode; use minijinja::context as template_context; use serde::Deserialize; use crate::{ contextual_error, http::context::UserRequestContext, http::errors::{CommonError, WebError}, select_template, storage::{ event::{EventUpdateParams, event_get, event_update_with_full_metadata}, identity_profile::{handle_for_did, handle_for_handle}, }, }; use atproto_record::lexicon::community::lexicon::calendar::event::{ Event as LexiconCommunityEvent, NSID as LexiconCommunityEventNSID, }; #[derive(Debug, Deserialize)] pub(crate) struct EditSettingsForm { pub disable_direct_rsvp: Option, pub rsvp_redirect_url: Option, } pub(crate) async fn handle_edit_settings( ctx: UserRequestContext, Path((handle_slug, event_rkey)): Path<(String, String)>, Form(form): Form, ) -> Result { let current_handle = ctx.auth.require("/")?; let default_context = template_context! { current_handle, language => ctx.language.to_string(), }; let error_template = select_template!(false, false, ctx.language); // Lookup the event let profile = if handle_slug.starts_with("did:") { handle_for_did(&ctx.web_context.pool, &handle_slug) .await .map_err(WebError::from) } else { let handle = if let Some(handle) = handle_slug.strip_prefix('@') { handle } else { &handle_slug }; handle_for_handle(&ctx.web_context.pool, handle) .await .map_err(WebError::from) }?; let lookup_aturi = format!( "at://{}/{}/{}", profile.did, LexiconCommunityEventNSID, event_rkey ); // Check if the user is authorized to edit this event (must be the creator) if profile.did != current_handle.did { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, CommonError::NotAuthorized, StatusCode::FORBIDDEN ); } let event = event_get(&ctx.web_context.pool, &lookup_aturi).await; if let Err(err) = event { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, err, StatusCode::OK ); } let event = event.unwrap(); // Parse the existing event record let community_event = match serde_json::from_value::(event.record.0.clone()) { Ok(event) => event, Err(_) => { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, CommonError::InvalidEventFormat, StatusCode::BAD_REQUEST ); } }; // Validate redirect URL settings let disable_direct_rsvp = form.disable_direct_rsvp.unwrap_or(false); let rsvp_redirect_url = form.rsvp_redirect_url.as_deref().map(|s| s.trim()); // When disable_direct_rsvp is true, URL is required if disable_direct_rsvp { if let Some(url) = rsvp_redirect_url { if url.is_empty() || !url.starts_with("https://") { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, CommonError::FieldRequired, StatusCode::BAD_REQUEST ); } } else { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, CommonError::FieldRequired, StatusCode::BAD_REQUEST ); } } // When URL is provided, validate it's HTTPS (even if disable_direct_rsvp=false) if let Some(url) = rsvp_redirect_url { if !url.is_empty() && !url.starts_with("https://") { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, CommonError::FieldRequired, StatusCode::BAD_REQUEST ); } } // Convert empty string to None for database storage let rsvp_redirect_url = rsvp_redirect_url.filter(|url| !url.is_empty()); // Update the event in the database only (settings are not stored in AT Protocol) let event_update_result = event_update_with_full_metadata( &ctx.web_context.pool, EventUpdateParams { aturi: &lookup_aturi, cid: &event.cid, record: &community_event, name: &community_event.name, require_confirmed_email: event.require_confirmed_email, disable_direct_rsvp, rsvp_redirect_url, }, ) .await; if let Err(err) = event_update_result { return contextual_error!( ctx.web_context, ctx.language, error_template, default_context, err, StatusCode::INTERNAL_SERVER_ERROR ); } // Redirect back to settings tab let manage_url = format!("/{}/{}/manage?tab=settings", handle_slug, event_rkey); let hx_redirect = HxRedirect::from(manage_url.as_str()); Ok((StatusCode::OK, hx_redirect, "").into_response()) }