The smokesignal.events web application
1use std::sync::Arc;
2
3use anyhow::Result;
4use atproto_identity::resolve::IdentityResolver;
5use axum::{
6 extract::{Form, State},
7 response::{IntoResponse, Redirect},
8};
9use serde::Deserialize;
10
11use crate::{
12 http::{context::AdminRequestContext, errors::WebError, import_utils::import_rsvp_records},
13 storage::identity_profile::handle_warm_up,
14};
15
16#[derive(Deserialize)]
17pub struct ImportRsvpForm {
18 pub aturi: String,
19}
20
21pub(crate) async fn handle_admin_import_rsvp(
22 admin_ctx: AdminRequestContext,
23 identity_resolver: State<Arc<dyn IdentityResolver>>,
24 Form(form): Form<ImportRsvpForm>,
25) -> Result<impl IntoResponse, WebError> {
26 // Split the aturi field by comma and process each value
27 let aturi_values: Vec<&str> = form.aturi.split(',').map(str::trim).collect();
28
29 for repository in aturi_values {
30 if repository.is_empty() {
31 continue;
32 }
33
34 let document = match identity_resolver.resolve(repository).await {
35 Ok(value) => value,
36 Err(err) => {
37 tracing::warn!("Failed to resolve repository {}: {}", repository, err);
38 continue;
39 }
40 };
41
42 let handle = match document.handles() {
43 Some(value) => value,
44 None => {
45 tracing::warn!("No handle found for repository: {}", repository);
46 continue;
47 }
48 };
49
50 let pds = match document.pds_endpoints().first().cloned() {
51 Some(value) => value,
52 None => {
53 tracing::warn!("No PDS found for repository: {}", repository);
54 continue;
55 }
56 };
57
58 if let Err(err) = admin_ctx
59 .web_context
60 .document_storage
61 .store_document(document.clone())
62 .await
63 {
64 tracing::warn!("Failed to store document for {}: {}", repository, err);
65 continue;
66 }
67
68 // Insert the handle if it doesn't exist
69 if let Err(err) =
70 handle_warm_up(&admin_ctx.web_context.pool, &document.id, handle, pds, None)
71 .await
72 .map(|_is_new_user| ())
73 {
74 tracing::warn!("Failed to warm up handle for {}: {}", repository, err);
75 continue;
76 }
77
78 // Import rsvp records for this repository
79 match import_rsvp_records(
80 &admin_ctx.web_context.http_client,
81 &admin_ctx.web_context.pool,
82 &document.id,
83 pds,
84 )
85 .await
86 {
87 Ok(results) => {
88 tracing::info!(
89 "Import results for {}: {} records processed",
90 repository,
91 results.len()
92 );
93 for (uri, error) in results {
94 if let Some(error_msg) = error {
95 tracing::warn!("Failed to import {}: {}", uri, error_msg);
96 }
97 }
98 }
99 Err(err) => {
100 tracing::error!("Failed to import legacy events for {}: {}", repository, err);
101 }
102 }
103 }
104
105 Ok(Redirect::to("/admin/rsvps").into_response())
106}