church-core/src/client/bible.rs
RTSDA 4d6b23beb3
Some checks are pending
iOS UniFFI Build / build-ios (push) Waiting to run
Initial commit: Church Core Rust library
Add church management API library with cross-platform support for iOS, Android, and WASM.
Features include event management, bulletin handling, contact forms, and authentication.
2025-08-16 19:25:01 -04:00

169 lines
5.8 KiB
Rust

use crate::{
client::ChurchApiClient,
error::Result,
models::{BibleVerse, VerseOfTheDay, VerseCategory, PaginationParams, ApiListResponse, ApiVersion},
};
pub async fn get_random_verse(client: &ChurchApiClient) -> Result<BibleVerse> {
// The response format is {success: bool, data: Verse}
#[derive(serde::Deserialize, serde::Serialize)]
struct VerseResponse {
success: bool,
data: ApiVerse,
}
#[derive(serde::Deserialize, serde::Serialize)]
struct ApiVerse {
id: String,
reference: String,
text: String,
#[serde(rename = "is_active")]
is_active: bool,
}
let url = client.build_url("/bible_verses/random");
let raw_response = client.client.get(&url).send().await?;
let response_text = raw_response.text().await?;
let response: VerseResponse = serde_json::from_str(&response_text)
.map_err(|e| crate::error::ChurchApiError::Json(e))?;
if response.success {
Ok(BibleVerse::new(response.data.text, response.data.reference))
} else {
Err(crate::error::ChurchApiError::Api("Bible verse API returned success=false".to_string()))
}
}
pub async fn get_verse_of_the_day(client: &ChurchApiClient) -> Result<VerseOfTheDay> {
client.get_api("/bible/verse-of-the-day").await
}
pub async fn get_verse_by_reference(client: &ChurchApiClient, reference: &str) -> Result<Option<BibleVerse>> {
let path = format!("/bible/verse?reference={}", urlencoding::encode(reference));
match client.get_api(&path).await {
Ok(verse) => Ok(Some(verse)),
Err(crate::error::ChurchApiError::NotFound) => Ok(None),
Err(e) => Err(e),
}
}
pub async fn get_verses_by_category(client: &ChurchApiClient, category: VerseCategory, limit: Option<u32>) -> Result<Vec<BibleVerse>> {
let mut path = format!("/bible/category/{}", category.display_name().to_lowercase());
if let Some(limit) = limit {
path.push_str(&format!("?limit={}", limit));
}
let response: crate::models::ApiListResponse<BibleVerse> = client.get_api_list(&path).await?;
Ok(response.data.items)
}
pub async fn search_verses(client: &ChurchApiClient, query: &str, limit: Option<u32>) -> Result<Vec<BibleVerse>> {
let mut path = format!("/bible_verses/search?q={}", urlencoding::encode(query));
if let Some(limit) = limit {
path.push_str(&format!("&limit={}", limit));
}
// The bible_verses/search endpoint returns a custom format with additional fields
#[derive(serde::Deserialize, serde::Serialize)]
struct ApiBibleVerse {
id: String,
reference: String,
text: String,
is_active: bool,
created_at: String,
updated_at: String,
}
#[derive(serde::Deserialize, serde::Serialize)]
struct BibleSearchResponse {
success: bool,
data: Vec<ApiBibleVerse>,
message: Option<String>,
}
let url = client.build_url(&path);
let raw_response = client.client.get(&url).send().await?;
let response_text = raw_response.text().await?;
let response: BibleSearchResponse = serde_json::from_str(&response_text)
.map_err(|e| crate::error::ChurchApiError::Json(e))?;
if response.success {
// Convert ApiBibleVerse to BibleVerse
let verses = response.data.into_iter()
.map(|api_verse| BibleVerse::new(api_verse.text, api_verse.reference))
.collect();
Ok(verses)
} else {
Ok(Vec::new())
}
}
// V2 API methods
pub async fn get_random_verse_v2(client: &ChurchApiClient) -> Result<BibleVerse> {
#[derive(serde::Deserialize, serde::Serialize)]
struct VerseResponse {
success: bool,
data: ApiVerse,
}
#[derive(serde::Deserialize, serde::Serialize)]
struct ApiVerse {
id: String,
reference: String,
text: String,
#[serde(rename = "is_active")]
is_active: bool,
}
let url = client.build_url_with_version("/bible_verses/random", ApiVersion::V2);
let raw_response = client.client.get(&url).send().await?;
let response_text = raw_response.text().await?;
let response: VerseResponse = serde_json::from_str(&response_text)
.map_err(|e| crate::error::ChurchApiError::Json(e))?;
if response.success {
Ok(BibleVerse::new(response.data.text, response.data.reference))
} else {
Err(crate::error::ChurchApiError::Api("Bible verse API returned success=false".to_string()))
}
}
pub async fn get_bible_verses_v2(client: &ChurchApiClient, params: Option<PaginationParams>) -> Result<ApiListResponse<BibleVerse>> {
let mut path = "/bible_verses".to_string();
if let Some(params) = params {
let mut query_params = Vec::new();
if let Some(page) = params.page {
query_params.push(("page", page.to_string()));
}
if let Some(per_page) = params.per_page {
query_params.push(("per_page", per_page.to_string()));
}
if !query_params.is_empty() {
let query_string = query_params
.iter()
.map(|(k, v)| format!("{}={}", k, urlencoding::encode(v)))
.collect::<Vec<_>>()
.join("&");
path.push_str(&format!("?{}", query_string));
}
}
client.get_api_list_with_version(&path, ApiVersion::V2).await
}
pub async fn search_verses_v2(client: &ChurchApiClient, query: &str, limit: Option<u32>) -> Result<Vec<BibleVerse>> {
let mut path = format!("/bible_verses/search?q={}", urlencoding::encode(query));
if let Some(limit) = limit {
path.push_str(&format!("&limit={}", limit));
}
let response: crate::models::ApiListResponse<BibleVerse> = client.get_api_list_with_version(&path, ApiVersion::V2).await?;
Ok(response.data.items)
}