Beacon/src/pocketbase.rs
RTSDA 1494472e3e Update API integration from PocketBase to new church API
- Replace PocketBase integration with new church API at api.rockvilletollandsda.church
- Use /api/events/upcoming endpoint to eliminate client-side filtering
- Update data structures to match new API response format
- Simplify event fetching logic by leveraging server-side filtering
- Increase image size limit to 2MB for better image support
- Rename PocketbaseEvent to ApiEvent and PocketbaseClient to ApiClient
- Update configuration to use api_url instead of pocketbase_url
2025-06-28 19:54:16 -04:00

92 lines
2.6 KiB
Rust

use anyhow::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::time::Duration;
const API_TIMEOUT: Duration = Duration::from_secs(10);
#[derive(Debug, Serialize, Deserialize)]
pub struct ApiEvent {
pub id: String,
pub title: String,
pub description: String,
pub start_time: DateTime<Utc>,
pub end_time: DateTime<Utc>,
pub location: String,
pub location_url: Option<String>,
pub image: Option<String>,
pub thumbnail: Option<String>,
pub category: String,
pub is_featured: bool,
pub recurring_type: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone)]
pub struct ApiClient {
client: reqwest::Client,
base_url: String,
}
impl ApiClient {
pub fn new(base_url: String) -> Self {
let client = reqwest::Client::builder()
.timeout(API_TIMEOUT)
.build()
.expect("Failed to create HTTP client");
Self { client, base_url }
}
pub async fn fetch_events(&self) -> Result<Vec<ApiEvent>> {
let url = format!("{}/api/events/upcoming", self.base_url);
tracing::info!("Fetching events from URL: {}", url);
let response = match self.client.get(&url)
.header("Cache-Control", "max-age=60") // Cache for 60 seconds
.send()
.await
{
Ok(resp) => {
tracing::info!("Got response with status: {}", resp.status());
resp
},
Err(e) => {
tracing::error!("HTTP request failed: {}", e);
return Err(e.into());
}
};
let response = match response.error_for_status() {
Ok(resp) => resp,
Err(e) => {
tracing::error!("HTTP error status: {}", e);
return Err(e.into());
}
};
#[derive(Deserialize)]
struct ApiResponse {
success: bool,
data: Vec<ApiEvent>,
}
match response.json().await {
Ok(api_response) => {
let ApiResponse { success, data } = api_response;
if success {
tracing::info!("Successfully parsed {} events from response", data.len());
Ok(data)
} else {
tracing::error!("API returned success: false");
Err(anyhow::anyhow!("API request failed"))
}
},
Err(e) => {
tracing::error!("Failed to parse JSON response: {}", e);
Err(e.into())
}
}
}
}