forked from
smokesignal.events/smokesignal
The smokesignal.events web application
1use atproto_record::aturi::ATURI;
2use axum::{
3 extract::{Query, State},
4 response::{IntoResponse, Json},
5};
6use http::StatusCode;
7use serde::{Deserialize, Serialize};
8use std::str::FromStr;
9
10use crate::http::context::WebContext;
11use crate::storage::event::rsvp_get_by_event_and_did;
12
13#[derive(Debug, Deserialize)]
14pub struct GetRsvpParams {
15 /// AT-URI of the event
16 event: String,
17 /// DID of the identity to get the RSVP for
18 identity: String,
19}
20
21#[derive(Debug, Serialize)]
22pub struct GetRsvpResponse {
23 /// AT-URI of the RSVP record
24 uri: String,
25 /// CID of the RSVP record
26 cid: String,
27 /// The RSVP record
28 record: serde_json::Value,
29}
30
31#[derive(Debug, Serialize)]
32struct GetRsvpError {
33 error: String,
34 message: String,
35}
36
37impl GetRsvpError {
38 fn invalid_request(message: &str) -> Self {
39 Self {
40 error: "InvalidRequest".to_string(),
41 message: message.to_string(),
42 }
43 }
44
45 fn not_found(message: &str) -> Self {
46 Self {
47 error: "NotFound".to_string(),
48 message: message.to_string(),
49 }
50 }
51
52 fn internal_error(message: &str) -> Self {
53 Self {
54 error: "InternalServerError".to_string(),
55 message: message.to_string(),
56 }
57 }
58}
59
60/// XRPC query endpoint for getting an RSVP record.
61///
62/// This endpoint retrieves an RSVP record for a specific identity and event.
63/// No authentication is required as RSVP data is public.
64pub(crate) async fn handle_xrpc_get_rsvp(
65 State(web_context): State<WebContext>,
66 Query(params): Query<GetRsvpParams>,
67) -> impl IntoResponse {
68 // Validate event AT-URI format
69 if ATURI::from_str(¶ms.event).is_err() {
70 return (
71 StatusCode::BAD_REQUEST,
72 Json(GetRsvpError::invalid_request("Invalid event AT-URI format")),
73 )
74 .into_response();
75 }
76
77 let identity = match web_context
78 .identity_resolver
79 .resolve(¶ms.identity)
80 .await
81 {
82 Ok(value) => value,
83 Err(_) => {
84 return (
85 StatusCode::BAD_REQUEST,
86 Json(GetRsvpError::invalid_request("Invalid identity DID format")),
87 )
88 .into_response();
89 }
90 };
91
92 // Fetch the RSVP
93 let rsvp = match rsvp_get_by_event_and_did(&web_context.pool, ¶ms.event, &identity.id).await
94 {
95 Ok(Some(rsvp)) => rsvp,
96 Ok(None) => {
97 return (
98 StatusCode::NOT_FOUND,
99 Json(GetRsvpError::not_found("RSVP not found")),
100 )
101 .into_response();
102 }
103 Err(err) => {
104 tracing::error!(
105 ?err,
106 event = %params.event,
107 identity = %params.identity,
108 "Failed to fetch RSVP"
109 );
110 return (
111 StatusCode::INTERNAL_SERVER_ERROR,
112 Json(GetRsvpError::internal_error("Failed to fetch RSVP")),
113 )
114 .into_response();
115 }
116 };
117
118 let response = GetRsvpResponse {
119 uri: rsvp.aturi,
120 cid: rsvp.cid,
121 record: rsvp.record.0,
122 };
123
124 (StatusCode::OK, Json(response)).into_response()
125}