Füge Logik zur Durchsetzung der Wahlvorlaufzeit hinzu: Implementiere die Funktion enforce_election_lead_time, um sicherzustellen, dass Wahlen erst nach Ablauf von 2 Tagen seit ihrer Erstellung ausgewertet werden. Aktualisiere SQL-Abfragen zur Berücksichtigung des Vorlaufs bei der Planung neuer Wahlen.
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m41s
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m41s
This commit is contained in:
@@ -10,6 +10,7 @@ use crate::worker::sql::{
|
|||||||
QUERY_COUNT_OFFICES_PER_REGION,
|
QUERY_COUNT_OFFICES_PER_REGION,
|
||||||
QUERY_FIND_OFFICE_GAPS,
|
QUERY_FIND_OFFICE_GAPS,
|
||||||
QUERY_SELECT_NEEDED_ELECTIONS,
|
QUERY_SELECT_NEEDED_ELECTIONS,
|
||||||
|
QUERY_ENFORCE_ELECTION_LEAD_TIME,
|
||||||
QUERY_INSERT_CANDIDATES,
|
QUERY_INSERT_CANDIDATES,
|
||||||
QUERY_SELECT_ELECTIONS_NEEDING_CANDIDATES,
|
QUERY_SELECT_ELECTIONS_NEEDING_CANDIDATES,
|
||||||
QUERY_PROCESS_EXPIRED_AND_FILL,
|
QUERY_PROCESS_EXPIRED_AND_FILL,
|
||||||
@@ -181,10 +182,31 @@ impl PoliticsWorker {
|
|||||||
Self::notify_office_filled(pool, broker, &new_offices_direct)?;
|
Self::notify_office_filled(pool, broker, &new_offices_direct)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5) Neue Wahlen planen
|
// 4b) Nach dem Entfernen abgelaufener Aemter erneut Luecken
|
||||||
|
// synchronisieren. Das behebt Rueckstaende, wenn Aemter schon vor
|
||||||
|
// Tagen/Wochen abgelaufen sind und dadurch erst jetzt echte Gaps
|
||||||
|
// entstehen.
|
||||||
|
Self::sync_offices_with_types(pool)?;
|
||||||
|
|
||||||
|
// 5) Sicherstellen, dass Wahlen niemals vor Ablauf von 2 Tagen seit
|
||||||
|
// Anlegen ausgewertet werden.
|
||||||
|
Self::enforce_election_lead_time(pool)?;
|
||||||
|
|
||||||
|
// 6) Bereits faellige Wahlen auswerten und neu besetzte Aemter melden.
|
||||||
|
// Wichtig: Vor dem Anlegen neuer Wahlen ausfuehren, damit frisch
|
||||||
|
// angelegte Wahlen nicht im selben Tageslauf wieder verarbeitet werden.
|
||||||
|
let new_offices_from_elections = Self::process_elections(pool)?;
|
||||||
|
if let Err(e) = Self::notify_player_election_results(pool, broker) {
|
||||||
|
eprintln!("[PoliticsWorker] notify_player_election_results: {e}");
|
||||||
|
}
|
||||||
|
if !new_offices_from_elections.is_empty() {
|
||||||
|
Self::notify_office_filled(pool, broker, &new_offices_from_elections)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7) Neue Wahlen planen
|
||||||
let new_elections = Self::schedule_elections(pool)?;
|
let new_elections = Self::schedule_elections(pool)?;
|
||||||
|
|
||||||
// 6) Für alle Wahlen ohne Kandidaten (inkl. manuell
|
// 8) Fuer alle Wahlen ohne Kandidaten (inkl. manuell
|
||||||
// angelegter) Kandidaten eintragen.
|
// angelegter) Kandidaten eintragen.
|
||||||
let mut elections_to_fill = Self::find_elections_needing_candidates(pool)?;
|
let mut elections_to_fill = Self::find_elections_needing_candidates(pool)?;
|
||||||
// Die gerade neu angelegten Wahlen sind typischerweise auch
|
// Die gerade neu angelegten Wahlen sind typischerweise auch
|
||||||
@@ -207,16 +229,7 @@ impl PoliticsWorker {
|
|||||||
Self::notify_election_created(pool, broker, &user_ids)?;
|
Self::notify_election_created(pool, broker, &user_ids)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7) Wahlen auswerten und neu besetzte Ämter melden
|
// 9) Als letzter Schritt sicherstellen, dass es fuer keinen
|
||||||
let new_offices_from_elections = Self::process_elections(pool)?;
|
|
||||||
if let Err(e) = Self::notify_player_election_results(pool, broker) {
|
|
||||||
eprintln!("[PoliticsWorker] notify_player_election_results: {e}");
|
|
||||||
}
|
|
||||||
if !new_offices_from_elections.is_empty() {
|
|
||||||
Self::notify_office_filled(pool, broker, &new_offices_from_elections)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8) Als letzter Schritt sicherstellen, dass es für keinen
|
|
||||||
// Amtstyp/Region-Kombi mehr besetzte Ämter gibt als laut
|
// Amtstyp/Region-Kombi mehr besetzte Ämter gibt als laut
|
||||||
// `seats_per_region` erlaubt. Dieser Abgleich wird nach allen
|
// `seats_per_region` erlaubt. Dieser Abgleich wird nach allen
|
||||||
// Lösch- und Besetzungsvorgängen ausgeführt.
|
// Lösch- und Besetzungsvorgängen ausgeführt.
|
||||||
@@ -337,8 +350,8 @@ impl PoliticsWorker {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Für jede Lücke eine Wahl am aktuellen Tag anlegen, sofern es nicht
|
// Für jede Lücke eine Wahl mit 2 Tagen Vorlauf anlegen, sofern es nicht
|
||||||
// bereits eine Wahl für diesen Amtstyp/Region an einem heutigen oder
|
// bereits eine Wahl für diesen Amtstyp/Region an einem gleich späten oder
|
||||||
// zukünftigen Datum gibt. Das eigentliche Anlegen der Wahl und das
|
// zukünftigen Datum gibt. Das eigentliche Anlegen der Wahl und das
|
||||||
// Eintragen von Kandidaten läuft weiterhin über die bestehende
|
// Eintragen von Kandidaten läuft weiterhin über die bestehende
|
||||||
// Logik in der Datenbank (process_elections / schedule_elections).
|
// Logik in der Datenbank (process_elections / schedule_elections).
|
||||||
@@ -353,7 +366,7 @@ impl PoliticsWorker {
|
|||||||
(office_type_id, date, posts_to_fill, created_at, updated_at, region_id)
|
(office_type_id, date, posts_to_fill, created_at, updated_at, region_id)
|
||||||
SELECT
|
SELECT
|
||||||
$1::int AS office_type_id,
|
$1::int AS office_type_id,
|
||||||
CURRENT_DATE AS date,
|
(CURRENT_DATE + INTERVAL '2 days')::date AS date,
|
||||||
$2::int AS posts_to_fill,
|
$2::int AS posts_to_fill,
|
||||||
NOW() AS created_at,
|
NOW() AS created_at,
|
||||||
NOW() AS updated_at,
|
NOW() AS updated_at,
|
||||||
@@ -363,7 +376,7 @@ impl PoliticsWorker {
|
|||||||
FROM falukant_data.election e
|
FROM falukant_data.election e
|
||||||
WHERE e.office_type_id = $1::int
|
WHERE e.office_type_id = $1::int
|
||||||
AND e.region_id = $3::int
|
AND e.region_id = $3::int
|
||||||
AND e.date::date >= CURRENT_DATE
|
AND e.date::date >= (CURRENT_DATE + INTERVAL '2 days')::date
|
||||||
);
|
);
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@@ -634,6 +647,19 @@ impl PoliticsWorker {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enforce_election_lead_time(pool: &ConnectionPool) -> Result<(), DbError> {
|
||||||
|
let mut conn = pool
|
||||||
|
.get()
|
||||||
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
|
conn.prepare("enforce_election_lead_time", QUERY_ENFORCE_ELECTION_LEAD_TIME)
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] prepare enforce_election_lead_time: {e}")))?;
|
||||||
|
conn.execute("enforce_election_lead_time", &[])
|
||||||
|
.map_err(|e| DbError::new(format!("[PoliticsWorker] exec enforce_election_lead_time: {e}")))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Benachrichtigt Spieler-Kandidaten mit Wahlergebnis (Stimmen, Rang, Gewinner, gewonnen?).
|
/// Benachrichtigt Spieler-Kandidaten mit Wahlergebnis (Stimmen, Rang, Gewinner, gewonnen?).
|
||||||
/// `tr` = JSON mit `event: "election_result"` (siehe `QUERY_PLAYER_ELECTION_RESULT_ROWS`).
|
/// `tr` = JSON mit `event: "election_result"` (siehe `QUERY_PLAYER_ELECTION_RESULT_ROWS`).
|
||||||
fn notify_player_election_results(
|
fn notify_player_election_results(
|
||||||
|
|||||||
@@ -1113,7 +1113,7 @@ pub const QUERY_FIND_OFFICE_GAPS: &str = r#"
|
|||||||
pub const QUERY_SELECT_NEEDED_ELECTIONS: &str = r#"
|
pub const QUERY_SELECT_NEEDED_ELECTIONS: &str = r#"
|
||||||
WITH
|
WITH
|
||||||
target_date AS (
|
target_date AS (
|
||||||
SELECT NOW()::date AS election_date
|
SELECT (NOW()::date + INTERVAL '2 days')::date AS election_date
|
||||||
),
|
),
|
||||||
offices_ending_today AS (
|
offices_ending_today AS (
|
||||||
SELECT po.id,
|
SELECT po.id,
|
||||||
@@ -1186,6 +1186,14 @@ pub const QUERY_SELECT_NEEDED_ELECTIONS: &str = r#"
|
|||||||
ORDER BY ne.region_id, ne.election_id;
|
ORDER BY ne.region_id, ne.election_id;
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
pub const QUERY_ENFORCE_ELECTION_LEAD_TIME: &str = r#"
|
||||||
|
UPDATE falukant_data.election AS e
|
||||||
|
SET date = (e.created_at::date + INTERVAL '2 days')::date,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE e.created_at IS NOT NULL
|
||||||
|
AND e.date::date < (e.created_at::date + INTERVAL '2 days')::date;
|
||||||
|
"#;
|
||||||
|
|
||||||
pub const QUERY_INSERT_CANDIDATES: &str = r#"
|
pub const QUERY_INSERT_CANDIDATES: &str = r#"
|
||||||
INSERT INTO falukant_data.candidate
|
INSERT INTO falukant_data.candidate
|
||||||
(election_id, character_id, created_at, updated_at)
|
(election_id, character_id, created_at, updated_at)
|
||||||
|
|||||||
Reference in New Issue
Block a user