diff --git a/src/worker/politics.rs b/src/worker/politics.rs index 75934b9..c97b391 100644 --- a/src/worker/politics.rs +++ b/src/worker/politics.rs @@ -32,6 +32,8 @@ use crate::worker::sql::{ QUERY_REJECT_CHURCH_APPLICATION, QUERY_CREATE_CHURCH_APPLICATION_JOB, QUERY_GET_CHARACTERS_FOR_CHURCH_OFFICE, + QUERY_GET_OLD_PENDING_CHURCH_APPLICATIONS, + QUERY_AUTO_APPROVE_CHURCH_APPLICATION, }; pub struct PoliticsWorker { @@ -106,6 +108,7 @@ impl PoliticsWorker { fn run_loop(pool: ConnectionPool, broker: MessageBroker, state: Arc) { let mut last_execution: Option = None; let mut last_church_office_run: Option = None; + let mut last_auto_approve_run: Option = None; while state.running_worker.load(Ordering::Relaxed) { let now = Instant::now(); @@ -140,6 +143,21 @@ impl PoliticsWorker { } } + // Automatische Annahme alter Applications (stündlich) + let should_run_auto_approve = match last_auto_approve_run { + None => true, + Some(prev) => { + now.saturating_duration_since(prev) >= Duration::from_secs(3600) + } + }; + + if should_run_auto_approve { + if let Err(err) = Self::auto_approve_old_church_applications(&pool, &broker) { + eprintln!("[PoliticsWorker] Fehler bei auto_approve_old_church_applications: {err}"); + } + last_auto_approve_run = Some(now); + } + // Entspricht ungefähr der 5-Sekunden-Schleife im C++-Code for _ in 0..5 { if !state.running_worker.load(Ordering::Relaxed) { @@ -999,6 +1017,94 @@ impl PoliticsWorker { Ok(()) } + /// Automatische Annahme von Church Applications, die älter als 36 Stunden sind + fn auto_approve_old_church_applications( + pool: &ConnectionPool, + broker: &MessageBroker, + ) -> Result<(), DbError> { + let mut conn = pool + .get() + .map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?; + + // Alle alten pending Applications abrufen + conn.prepare( + "get_old_pending_church_applications", + QUERY_GET_OLD_PENDING_CHURCH_APPLICATIONS, + ) + .map_err(|e| { + DbError::new(format!( + "[PoliticsWorker] prepare get_old_pending_church_applications: {e}" + )) + })?; + + let rows = conn + .execute("get_old_pending_church_applications", &[]) + .map_err(|e| { + DbError::new(format!( + "[PoliticsWorker] exec get_old_pending_church_applications: {e}" + )) + })?; + + let mut old_applications = Vec::new(); + for row in rows { + let application_id = parse_i32(&row, "application_id", -1); + let character_id = parse_i32(&row, "character_id", -1); + + if application_id >= 0 { + old_applications.push((application_id, character_id)); + } + } + + if old_applications.is_empty() { + return Ok(()); + } + + eprintln!( + "[PoliticsWorker] Gefunden: {} alte Church Applications (36h+), automatische Annahme", + old_applications.len() + ); + + // Prepare auto-approve query + conn.prepare( + "auto_approve_church_application", + QUERY_AUTO_APPROVE_CHURCH_APPLICATION, + ) + .map_err(|e| { + DbError::new(format!( + "[PoliticsWorker] prepare auto_approve_church_application: {e}" + )) + })?; + + // Alle alten Applications automatisch annehmen + for (application_id, character_id) in &old_applications { + let approve_rows = conn + .execute("auto_approve_church_application", &[application_id]) + .map_err(|e| { + DbError::new(format!( + "[PoliticsWorker] exec auto_approve_church_application: {e}" + )) + })?; + + if !approve_rows.is_empty() { + eprintln!( + "[PoliticsWorker] Church Application {} automatisch angenommen (36h+ alt, character_id={})", + application_id, character_id + ); + + // Benachrichtigung senden + if let Some(user_id) = Self::get_user_id_for_character(pool, *character_id)? { + let msg = format!( + r#"{{"event":"falukantUpdateStatus","user_id":{}}}"#, + user_id + ); + broker.publish(msg); + } + } + } + + Ok(()) + } + fn get_user_id_for_character( pool: &ConnectionPool, character_id: i32, diff --git a/src/worker/sql.rs b/src/worker/sql.rs index 244959c..1d80545 100644 --- a/src/worker/sql.rs +++ b/src/worker/sql.rs @@ -1836,6 +1836,62 @@ pub const QUERY_REJECT_CHURCH_APPLICATION: &str = r#" RETURNING id; "#; +pub const QUERY_GET_OLD_PENDING_CHURCH_APPLICATIONS: &str = r#" + SELECT + ca.id AS application_id, + ca.office_type_id, + ca.character_id, + ca.region_id, + ca.supervisor_id + FROM falukant_data.church_application ca + WHERE ca.status = 'pending' + AND ca.created_at <= NOW() - INTERVAL '36 hours' + ORDER BY ca.created_at ASC; +"#; + +pub const QUERY_AUTO_APPROVE_CHURCH_APPLICATION: &str = r#" + WITH updated_application AS ( + UPDATE falukant_data.church_application + SET status = 'approved', + decision_date = NOW(), + updated_at = NOW() + WHERE id = $1 + AND status = 'pending' + AND created_at <= NOW() - INTERVAL '36 hours' + RETURNING + office_type_id, + character_id, + region_id, + supervisor_id + ), + inserted_office AS ( + INSERT INTO falukant_data.church_office + (office_type_id, character_id, region_id, supervisor_id, created_at, updated_at) + SELECT + office_type_id, + character_id, + region_id, + supervisor_id, + NOW(), + NOW() + FROM updated_application + WHERE NOT EXISTS( + SELECT 1 + FROM falukant_data.church_office co + WHERE co.office_type_id = updated_application.office_type_id + AND co.region_id = updated_application.region_id + AND co.character_id = updated_application.character_id + ) + RETURNING id, office_type_id, character_id, region_id + ) + SELECT + id AS office_id, + office_type_id, + character_id, + region_id + FROM inserted_office; +"#; + pub const QUERY_CREATE_CHURCH_APPLICATION_JOB: &str = r#" INSERT INTO falukant_data.church_application (office_type_id, character_id, region_id, supervisor_id, status, created_at, updated_at)