announcement/reminder

This commit is contained in:
nobody 2024-08-23 10:16:20 +02:00 committed by murmeldin
parent fecf6ebed5
commit 7093280d80
2 changed files with 107 additions and 45 deletions

View file

@ -80,6 +80,14 @@ impl SimpleEmail {
self.in_reply_to.clone(),
)
}
pub fn into_parts(self) -> (Email, String, Vec<String>, Option<String>) {
(self.base, self.from, self.to, self.in_reply_to)
}
pub fn from_parts(
base: Email, from: String, to: Vec<String>, in_reply_to: Option<String>,
) -> Self {
Self { base, from, to, in_reply_to }
}
}
impl Email {

View file

@ -76,6 +76,7 @@ const CONFIG_SPEC: CfgSpec<'static> = CfgSpec {
default: "NORMAL",
description: "Named state of the program logic. (NORMAL, ANNOUNCED, REMINDED, LOGGED)",
},
CfgField::Optional { key: "toc", description: "Table of contents / pad summary." },
CfgField::Optional { key: "last-run",
description: "Last run of the program (used to figure out state of previous plenum mails.)",
},
@ -267,7 +268,7 @@ fn main() -> Result<(), Box<dyn Error>> {
&config["email-password"],
is_dry_run(),
);
let email = SimpleEmail::new(
let mut email = SimpleEmail::new(
email_,
&config["email-from"],
&config["email-to"],
@ -299,8 +300,12 @@ fn main() -> Result<(), Box<dyn Error>> {
eprintln!("WARNING: last run was a long time ago, resetting state.");
last_state = ProgramState::Normal;
do_cleanup(999, &today, &config, &hedgedoc, &email, &wiki)?;
// reset will have cleared in-reply-to if it existed
let (base, from, to, _) = email.into_parts();
email = SimpleEmail::from_parts(base, from, to, config.get("email-in-reply-to").ok());
}
}
let email = email;
let last_state = last_state;
// figure out where we should be
// deltas has either 2 or 3 days, if 3 then the middle one is == 0 (i.e. today)
@ -415,7 +420,7 @@ fn main() -> Result<(), Box<dyn Error>> {
.get("hedgedoc-next-id")
.expect("ID des nächsten Pads undefiniert. Bitte in der DB eintragen oder generieren.");
let mut message_id: Option<String> = None;
let mut message_id: String;
// let in_3_days_is_plenum = true;
//TEMPORÄR ANFANG: BEI PRODUCTION MUSS DAS HIER RAUS
@ -453,7 +458,7 @@ Und hier ein TL;DR von den aktuellen Themen:
Bis morgen, 20 Uhr!"#
); // ADJ_TIMEYWIMEY
message_id = send_email(&betreff, &message, &email, &config);
message_id = send_email(&betreff, &message, &email, &config)?;
// .expect("Plenum findet statt. Mail wurde versucht zu senden, konnte aber nicht gesendet werden!")
} else {
// Mail an alle senden und absagen
@ -467,23 +472,9 @@ Hier ist der Link zum Pad vom nächsten Plenum, das am {} statt finden wird:
Bis zum nächsten Plenum."#,
nächster_plenumtermin
);
message_id = send_email(&betreff, &message, &email, &config);
message_id = send_email(&betreff, &message, &email, &config)?;
// .expect("Plenum wird abgesagt. Mail wurde versucht zu senden, konnte aber nicht gesendet werden!"))
}
} else if in_3_days_is_plenum {
println!("In 3 Tagen ist Plenum, deshalb wird eine Erinnerung raus geschickt!");
if number_of_tops(&pad_content_without_top_instructions) == 0 {
// Mail an alle senden und sagen, dass es noch keine Themen gibt
let betreff = format!("Plenum vom {}: Bisher noch keine Themen", nächster_plenumtermin);
let message: String = format!(
r#"Es sind bisher leider keine Themen zusammengekommen. Wenn es bis Sonntag Abend keine Themen gibt, wird das Plenum voraussichtlich nicht statt finden.
Hier ist der Link zum Pad, wo ihr noch Themen eintragen könnt:
{current_pad_link}"#
);
message_id = send_email(&betreff, &message, &email, &config);
// .expect("Noch nicht genug Themen. Mail wurde versucht zu senden, konnte aber nicht gesendet werden!"))
}
} else if yesterday_was_plenum {
// This logic breaks on 02/2034, but on every other month it works
let old_pad_content =
@ -516,7 +507,7 @@ Und hier ist das Protokoll des letzten Plenums:
let betreff: String =
format!("Plenumsprotokoll vom {}: Es gab {} TOPs", nächster_plenumtermin, top_anzahl);
// XXX option x expect
message_id = send_email(&betreff, &message, &email, &config);
message_id = send_email(&betreff, &message, &email, &config)?;
// .expect("Mail mit Plenumsprotokoll wurde versucht zu senden, konnte aber nicht gesendet werden!"));
mediawiki::pad_ins_wiki(old_pad_content_without_top_instructions);
}
@ -674,42 +665,103 @@ fn upper_first(s: &str) -> String {
}
}
/* ***** transition actions ***** */
fn topic_count(n: usize, dative: bool) -> String {
match n {
0 => format!("noch keine{} Themen", if dative { "n" } else { "" }),
1 => format!("ein{} Thema", if dative { "em" } else { "" }),
_ => format!("{} Themen", n),
}
}
// BBBBBBBBBB
/* ***** repeating action parts ***** */
#[allow(unused_variables)]
fn do_announcement(
ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail,
wiki: &Mediawiki,
) -> Result<(), Box<dyn Error>> {
fn get_pad_info(config: &KV, hedgedoc: &HedgeDoc) -> (String, String, usize) {
let current_pad_id = &config["hedgedoc-last-id"];
let pad_content = hedgedoc.download(current_pad_id).expect("Hedgedoc: Download-Fehler");
let toc = hedgedoc::summarize(pad_content);
verboseln!("Zusammenfassung des aktuellen Plenum-Pads:\n{}", toc.cyan());
let n_topics = toc.lines().count();
verboseln!("(Das sind {} Themen.)", n_topics.to_string().cyan());
// TODO: if
// summary empty: write message variant
// summary not empty: write other message variant
// TODO: set/write state as Announced
// TODO: write summary
todo!()
verboseln!("(Also {}.)", topic_count(n_topics, false).cyan());
(current_pad_id.to_string(), toc, n_topics)
}
/* ***** transition actions ***** */
// BBBBBBBBBB
fn do_announcement(
ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail,
_wiki: &Mediawiki,
) -> Result<(), Box<dyn Error>> {
// fetch current pad contents & summarize
let (current_pad_id, toc, n_topics) = get_pad_info(config, hedgedoc);
// construct email
let subject = format!(
"Plenum {} (am {}): bisher {}",
relative_date(ttp),
plenum_day.format("%d.%m.%Y"),
topic_count(n_topics, false)
);
let line1 = if n_topics == 0 {
format!( "Es sind bisher leider noch keine Themen zusammengekommen. Wenn am Montag immer noch nix ist, dann fällt das Plenum aus." )
} else {
format!("Die bisherigen Themen für das Plenum sind:\n\n{toc}")
};
let line2 = format!(
"Falls ihr noch Themen ergänzen wollt ist hier der Link zum Pad:\n {}",
hedgedoc.format_url(&current_pad_id)
);
let body = format!("{line1}\n\n{line2}");
// send it
let message_id = send_email(&subject, &body, &email, &config)?;
// on success, update state (ignore write errors, they'll be checked later)
config.set("email-message-id", &message_id).ok();
config.set("state-name", &ProgramState::Announced.to_string()).ok();
config.set("state-toc", &toc).ok();
Ok(())
}
#[allow(unused_variables)]
fn do_reminder(
ttp: i64, plenum_day: &NaiveDate, config: &KV, hedgedoc: &HedgeDoc, email: &SimpleEmail,
wiki: &Mediawiki,
_wiki: &Mediawiki,
) -> Result<(), Box<dyn Error>> {
// TODO: get pad
// TODO: make summary
// TODO: if
// summary empty: write message variant
// summary not empty: make diff, send diff etc.
// TODO: set/write state as Reminded
// TODO: write summary
todo!()
// fetch current pad contents & summarize
let (current_pad_id, toc, n_topics) = get_pad_info(config, hedgedoc);
let old_toc = config.get("state-toc").unwrap_or_default();
// construct email
let subject_suffix = if n_topics == 0 {
" fällt aus (keine Themen)".to_string()
} else {
format!(" findet mit {} statt", topic_count(n_topics, true))
};
let subject = format!(
"Plenum {} (am {}) {}",
relative_date(ttp),
plenum_day.format("%d.%m.%Y"),
subject_suffix
);
let body_prefix = if old_toc == toc {
format!("Die Themen sind gleich geblieben. ")
} else {
format!("Es gab nochmal Änderungen, die aktualisierten Themen für das Plenum sind:\n\n{toc}\n\n")
};
let body = if n_topics > 0 {
format!(
"{body_prefix}Die vollen Details findet ihr im Pad:\n {}",
hedgedoc.format_url(&current_pad_id)
)
} else {
"Da es immer noch keine Themen gibt fällt das Plenum aus.\n\n".to_string()
+ "(Natürlich könnt ihr im Bedarfsfall immer noch kurzfristig ein Treffen einberufen, aber bitte "
+ "kündigt das so früh wie möglich an, damit Leute sich darauf einstellen können.)"
// TODO generate + add link for next pad
};
// send it
let _message_id = send_email(&subject, &body, &email, &config)?;
// on success, update state (ignore write errors, they'll be checked later)
config.set("state-name", &ProgramState::Reminded.to_string()).ok();
config.set("state-toc", &toc).ok();
Ok(())
}
#[allow(unused_variables)]
@ -880,11 +932,13 @@ impl std::fmt::Display for ProgramState {
/* ***** wrappers ***** */
fn send_email(subject: &str, body: &str, email: &SimpleEmail, config: &KV) -> Option<String> {
fn send_email(
subject: &str, body: &str, email: &SimpleEmail, config: &KV,
) -> Result<String, Box<dyn Error>> {
let full_subject = format!("[PleB] {}", subject);
let full_body = format!(
"{}\n\n{}\n\n{}",
&config["text-email-greeting"], body, &config["text-email-signature"]
);
email.send_email(full_subject, full_body).ok()
email.send_email(full_subject, full_body)
}