
- Add complete hymnal API with search, themes, and responsive readings - Implement hymn title lookup for bulletins (#319 → #319 - Hymn Title) - Add Bible book abbreviation support (Matt → Matthew, etc.) - Enhance scripture processing to handle verse ranges (Matt 1:21-23) - Add hymnal database schema with SDA 1985 and 1941 hymnals support - Implement advanced hymnal search with fuzzy matching and themes - Update bulletin processing to auto-populate hymn titles from database
149 lines
5.2 KiB
Rust
149 lines
5.2 KiB
Rust
// SHARED PROCESSING FUNCTIONS for bulletins handler
|
|
use crate::{
|
|
error::Result,
|
|
models::Bulletin,
|
|
utils::db_operations::BibleVerseOperations,
|
|
services::HymnalService,
|
|
};
|
|
use regex::Regex;
|
|
|
|
/// Process multiple bulletins with shared logic
|
|
pub async fn process_bulletins_batch(
|
|
pool: &sqlx::PgPool,
|
|
bulletins: &mut [Bulletin]
|
|
) -> Result<()> {
|
|
for bulletin in bulletins.iter_mut() {
|
|
process_single_bulletin(pool, bulletin).await?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Process a single bulletin with all required transformations
|
|
pub async fn process_single_bulletin(
|
|
pool: &sqlx::PgPool,
|
|
bulletin: &mut Bulletin
|
|
) -> Result<()> {
|
|
// Process scripture reading to include full verse text
|
|
bulletin.scripture_reading = process_scripture_reading(pool, &bulletin.scripture_reading).await?;
|
|
|
|
// Process hymn references in worship content
|
|
if let Some(ref worship_content) = bulletin.divine_worship {
|
|
bulletin.divine_worship = Some(process_hymn_references(pool, worship_content).await?);
|
|
}
|
|
|
|
// Process hymn references in sabbath school content
|
|
if let Some(ref ss_content) = bulletin.sabbath_school {
|
|
bulletin.sabbath_school = Some(process_hymn_references(pool, ss_content).await?);
|
|
}
|
|
|
|
// Ensure sunset field compatibility
|
|
if bulletin.sunset.is_none() {
|
|
bulletin.sunset = Some("TBA".to_string());
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Process scripture reading field to lookup and include full verse text
|
|
async fn process_scripture_reading(
|
|
pool: &sqlx::PgPool,
|
|
scripture: &Option<String>,
|
|
) -> Result<Option<String>> {
|
|
let Some(scripture_text) = scripture else {
|
|
return Ok(None);
|
|
};
|
|
|
|
// If it already looks like it has full verse text (long), return as-is
|
|
if scripture_text.len() > 50 {
|
|
return Ok(Some(scripture_text.clone()));
|
|
}
|
|
|
|
// Try to find the verse(s) using existing search functionality
|
|
// Allow up to 10 verses for ranges like "Matt 1:21-23"
|
|
match BibleVerseOperations::search(pool, scripture_text, 10).await {
|
|
Ok(verses) if !verses.is_empty() => {
|
|
if verses.len() == 1 {
|
|
// Single verse - format as before
|
|
let verse = &verses[0];
|
|
Ok(Some(format!("{} - {}", verse.text, scripture_text)))
|
|
} else {
|
|
// Multiple verses - combine them
|
|
let combined_text = verses
|
|
.iter()
|
|
.map(|v| v.text.as_str())
|
|
.collect::<Vec<&str>>()
|
|
.join(" ");
|
|
Ok(Some(format!("{} - {}", combined_text, scripture_text)))
|
|
}
|
|
},
|
|
_ => {
|
|
// If no match found, return original text
|
|
Ok(Some(scripture_text.clone()))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Process hymn references in bulletin content to include titles
|
|
/// Looks for patterns like #319, Hymn 319, No. 319 and adds hymn titles
|
|
pub async fn process_hymn_references(
|
|
pool: &sqlx::PgPool,
|
|
content: &str,
|
|
) -> Result<String> {
|
|
// Create regex patterns to match hymn references
|
|
let hymn_patterns = vec![
|
|
// #319
|
|
Regex::new(r"#(\d{1,3})").unwrap(),
|
|
// Hymn 319 (case insensitive)
|
|
Regex::new(r"(?i)hymn\s+(\d{1,3})").unwrap(),
|
|
// No. 319
|
|
Regex::new(r"(?i)no\.\s*(\d{1,3})").unwrap(),
|
|
// Number 319
|
|
Regex::new(r"(?i)number\s+(\d{1,3})").unwrap(),
|
|
];
|
|
|
|
let mut result = content.to_string();
|
|
|
|
// Default to 1985 hymnal (most common)
|
|
let default_hymnal = "sda-1985";
|
|
|
|
// Process each pattern
|
|
for pattern in hymn_patterns {
|
|
let mut matches_to_replace = Vec::new();
|
|
|
|
// Find all matches for this pattern
|
|
for capture in pattern.captures_iter(&result) {
|
|
if let Some(number_match) = capture.get(1) {
|
|
if let Ok(hymn_number) = number_match.as_str().parse::<i32>() {
|
|
// Try to get hymn from 1985 hymnal first, then 1941
|
|
let hymn_title = match HymnalService::get_hymn_by_number(pool, default_hymnal, hymn_number).await {
|
|
Ok(Some(hymn)) => Some(hymn.title),
|
|
_ => {
|
|
// Try 1941 hymnal as fallback
|
|
match HymnalService::get_hymn_by_number(pool, "sda-1941", hymn_number).await {
|
|
Ok(Some(hymn)) => Some(hymn.title),
|
|
_ => None,
|
|
}
|
|
}
|
|
};
|
|
|
|
if let Some(title) = hymn_title {
|
|
let full_match = capture.get(0).unwrap();
|
|
matches_to_replace.push((
|
|
full_match.start(),
|
|
full_match.end(),
|
|
format!("{} - {}", full_match.as_str(), title)
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply replacements in reverse order to maintain string indices
|
|
matches_to_replace.reverse();
|
|
for (start, end, replacement) in matches_to_replace {
|
|
result.replace_range(start..end, &replacement);
|
|
}
|
|
}
|
|
|
|
Ok(result)
|
|
} |