added matrix messages to do_reminder and do_announcement and improved their html formatting
This commit is contained in:
		
							parent
							
								
									1577d5de2e
								
							
						
					
					
						commit
						c2d9dcdd74
					
				
					 4 changed files with 68 additions and 72 deletions
				
			
		
							
								
								
									
										1
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -1483,6 +1483,7 @@ dependencies = [ | |||
|  "colored", | ||||
|  "futures", | ||||
|  "headers", | ||||
|  "lazy_static", | ||||
|  "lettre", | ||||
|  "log", | ||||
|  "mediawiki", | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ nom = "7.1.3" | |||
| mediawiki = "0.3.1" | ||||
| ollama-rs = "0.2.1" | ||||
| tokio = "1.0.0" | ||||
| lazy_static = "1.4" | ||||
| 
 | ||||
| [[bin]] | ||||
| name = "Plenum-Bot" | ||||
|  |  | |||
							
								
								
									
										62
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								src/main.rs
									
										
									
									
									
								
							|  | @ -59,7 +59,7 @@ const CONFIG_SPEC: CfgSpec<'static> = CfgSpec { | |||
|             description: "Various strings used.", | ||||
|             fields: &[ | ||||
|                 CfgField::Default { key: "email-greeting", | ||||
|                     default: "Hallo liebe Mitreisende,", | ||||
|                     default: "Hallo liebe Mitreisenden,", | ||||
|                     description: "\"Hello\"-greeting added at the start of every email.", | ||||
|                 }, | ||||
|                 CfgField::Default { key: "email-signature", | ||||
|  | @ -400,13 +400,23 @@ fn do_announcement( | |||
|         "Falls ihr noch Themen ergänzen wollt ist hier der Link zum Pad:\n  {}", | ||||
|         hedgedoc.format_url(¤t_pad_id) | ||||
|     ); | ||||
|     let body = format!("{line1}\n\n{line2}"); | ||||
|     let mut 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(); | ||||
|     config.set("email-state-toc", &toc).ok(); | ||||
|     let mut matrix = MatrixClient::new( | ||||
|         &config["matrix-homeserver-url"], | ||||
|         &config["matrix-user-id"], | ||||
|         &config["matrix-access-token"], | ||||
|         &config["matrix-room-id-1"], | ||||
|         &config["matrix-room-id-2"], | ||||
|         is_dry_run(), | ||||
|     ); | ||||
|     let message = format!("{}\n\n{}{}",&config["text-email-greeting"], &body, &config["text-email-signature"]); | ||||
|     matrix.send_message_to_two_rooms(&message)?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
|  | @ -436,7 +446,7 @@ fn do_reminder( | |||
|     } 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 { | ||||
|     let mut body = if n_topics > 0 { | ||||
|         format!( | ||||
|             "{body_prefix}Die vollen Details findet ihr im Pad:\n  {}\n\nBis {} um 20:00!", | ||||
|             hedgedoc.format_url(¤t_pad_id), | ||||
|  | @ -457,10 +467,21 @@ fn do_reminder( | |||
|         NYI!( | ||||
|             "do we skip ahead to ProgramState::Logged here or do we later add a note to the wiki?" | ||||
|         ); | ||||
|         // TODO: ADD SOMETHING TO WIKI
 | ||||
|     } | ||||
|     
 | ||||
|     config.set("state-name", &ProgramState::Reminded.to_string()).ok(); | ||||
|     config.set("state-toc", &toc).ok(); | ||||
|     config.set("email-state-toc", &toc).ok(); | ||||
|     let mut matrix = MatrixClient::new( | ||||
|         &config["matrix-homeserver-url"], | ||||
|         &config["matrix-user-id"], | ||||
|         &config["matrix-access-token"], | ||||
|         &config["matrix-room-id-1"], | ||||
|         &config["matrix-room-id-2"], | ||||
|         is_dry_run(), | ||||
|     ); | ||||
|     let message = format!("{}\n\n{}{}",&config["text-email-greeting"], &body, &config["text-email-signature"]); | ||||
|     matrix.send_message_to_two_rooms(&message)?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
|  | @ -501,7 +522,7 @@ fn do_protocol( | |||
|         let pad_content = pad_content.replace("[toc]", &toc); | ||||
|         let body = format!( | ||||
|             "Anbei das Protokoll vom {human_date}, ab sofort auch im Wiki zu finden.\n\n\ | ||||
|                 Das Pad für das nächste Plenum ist zu finden unter <{}/{}>.\nDie Protokolle der letzten Plena findet ihr im wiki unter <{}/index.php?title={}>.\n\n---Protokoll:---\n{}\n-----",
 | ||||
|                 Das Pad für das nächste Plenum ist zu finden unter <{}/{}>.\n\nDie Protokolle der letzten Plena findet ihr im wiki unter <{}/index.php?title={}>.\n\n---Protokoll:---\n{}\n-----",
 | ||||
|             &config["hedgedoc-server-url"], | ||||
|             &config["hedgedoc-next-id"], | ||||
|             &config["wiki-server-url"], | ||||
|  | @ -518,7 +539,7 @@ fn do_protocol( | |||
|         let pad_content = pad_content.replace("[toc]", &toc); | ||||
|         let body = format!( | ||||
|             "Anbei das Protokoll vom {human_date}, ab sofort auch im Wiki zu finden.\n\n\ | ||||
|                 Das Pad für das nächste Plenum ist zu finden unter {}/{}.\nDie Protokolle der letzten Plena findet ihr im wiki unter {}/index.php?title={}.\n\n---Protokoll:---{}",
 | ||||
|                 Das Pad für das nächste Plenum ist zu finden unter {}/{}.\n\nDie Protokolle der letzten Plena findet ihr im wiki unter {}/index.php?title={}.\n\n---Protokoll:---{}",
 | ||||
|             &config["hedgedoc-server-url"], | ||||
|             &config["hedgedoc-next-id"], | ||||
|             &config["wiki-server-url"], | ||||
|  | @ -533,39 +554,24 @@ fn do_protocol( | |||
|         &config["matrix-homeserver-url"], | ||||
|         &config["matrix-user-id"], | ||||
|         &config["matrix-access-token"], | ||||
|         &config["matrix-room-id-for-short-messages"], | ||||
|         &config["matrix-room-id-for-long-messages"], | ||||
|         &config["matrix-room-id-1"], | ||||
|         &config["matrix-room-id-2"], | ||||
|         is_dry_run(), | ||||
|     ); | ||||
|     // Send the matrix room message
 | ||||
|     let human_date = plenum_day.format("%d.%m.%Y"); | ||||
|     let pad_content = pad_content.replace("[toc]", &toc); | ||||
|     let long_message = format!( | ||||
|     let message = format!( | ||||
|         "Anbei das Protokoll vom {human_date}, ab sofort auch im Wiki zu finden.\n\n\ | ||||
|             Das Pad für das nächste Plenum ist zu finden unter {}/{}.\nDie Protokolle der letzten Plena findet ihr im wiki unter {}/index.php?title={}.\n**Hier die Zusammenfassung:**\n{}",
 | ||||
|             Das Pad für das nächste Plenum ist zu finden unter {}/{}.\n\nDie Protokolle der letzten Plena findet ihr im wiki unter {}/index.php?title={}.\n\n**Hier die Zusammenfassung:**\n\n{}",
 | ||||
|         &config["hedgedoc-server-url"], | ||||
|         &config["hedgedoc-next-id"], | ||||
|         &config["wiki-server-url"], | ||||
|         &config["wiki-plenum-page"], | ||||
|         &summary_or_toc | ||||
|     ); | ||||
|     let full_long_message = format!( | ||||
|         "{}\n{}{}", | ||||
|         &config["text-email-greeting"], long_message, &config["text-email-signature"] | ||||
|     ); | ||||
|     let short_message = format!( | ||||
|         "Das letzte Plenum hatte Anbei das Protokoll vom {human_date}, ab sofort auch im Wiki zu finden.\n\n\ | ||||
|             Das Pad für das nächste Plenum ist zu finden unter {}/{}.\nDie Protokolle der letzten Plena findet ihr im wiki unter {}/index.php?title={}.",
 | ||||
|         &config["hedgedoc-server-url"], | ||||
|         &config["hedgedoc-next-id"], | ||||
|         &config["wiki-server-url"], | ||||
|         &config["wiki-plenum-page"] | ||||
|     ); | ||||
|     let full_short_message = format!( | ||||
|         "{}\n{}{}", | ||||
|         &config["text-email-greeting"], short_message, &config["text-email-signature"].strip_prefix("[").unwrap_or(&config["text-email-signature"]).strip_suffix("]").unwrap_or(&config["text-email-signature"]) | ||||
|     ); | ||||
|     matrix.send_short_and_long_messages_to_two_rooms(&full_short_message, &full_long_message)?; | ||||
|     let full_message = format!("{}\n\n{}{}",&config["text-email-greeting"], &message, &config["text-email-signature"]); | ||||
|     matrix.send_message_to_two_rooms(&full_message)?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| use std::error::Error; | ||||
| use std::io::Read; | ||||
| use lazy_static::lazy_static; | ||||
| 
 | ||||
| use colored::Colorize; | ||||
| use regex::Regex; | ||||
|  | @ -32,12 +33,12 @@ pub const CONFIG: CfgGroup<'static> = CfgGroup { | |||
|             description: "Access Token / \"password\" used for authenticating as the bot.", | ||||
|         }, | ||||
|         CfgField::Default { | ||||
|             key: "room-id-for-long-messages", | ||||
|             key: "room-id-1", | ||||
|             default: "!someLongRoomIdentifier:matrix.org", | ||||
|             description: "API Username associated with the bot account used for writing messages.", | ||||
|         }, | ||||
|         CfgField::Default { | ||||
|             key: "room-id-for-short-messages", | ||||
|             key: "room-id-2", | ||||
|             default: "!someLongRoomIdentifier:matrix.org", | ||||
|             description: "API Username associated with the bot account used for writing messages.", | ||||
|         }, | ||||
|  | @ -51,8 +52,8 @@ pub struct MatrixClient { | |||
|     is_dry_run: bool, | ||||
|     client: Client, | ||||
|     txn_id: u64, | ||||
|     room_id_for_short_messages: String, | ||||
|     room_id_for_long_messages: String, | ||||
|     room_id_1: String, | ||||
|     room_id_2: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Deserialize, Debug)] | ||||
|  | @ -82,8 +83,8 @@ impl std::fmt::Debug for MatrixClient { | |||
| 
 | ||||
| impl MatrixClient { | ||||
|     pub fn new( | ||||
|         homeserver_url: &str, user_id: &str, access_token: &str, room_id_for_short_messages: &str, | ||||
|         room_id_for_long_messages: &str, is_dry_run: bool, | ||||
|         homeserver_url: &str, user_id: &str, access_token: &str, room_id_1: &str, | ||||
|         room_id_2: &str, is_dry_run: bool, | ||||
|     ) -> Self { | ||||
|         Self { | ||||
|             homeserver_url: homeserver_url.to_string(), | ||||
|  | @ -92,8 +93,8 @@ impl MatrixClient { | |||
|             is_dry_run, | ||||
|             client: Client::builder().cookie_store(true).build().unwrap(), | ||||
|             txn_id: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(), | ||||
|             room_id_for_long_messages: room_id_for_long_messages.to_string(), | ||||
|             room_id_for_short_messages: room_id_for_short_messages.to_string(), | ||||
|             room_id_2: room_id_2.to_string(), | ||||
|             room_id_1: room_id_1.to_string(), | ||||
|         } | ||||
|     } | ||||
|     fn request<T: Serialize>( | ||||
|  | @ -102,7 +103,7 @@ impl MatrixClient { | |||
|     ) -> Result<Value, Box<dyn Error>> { | ||||
|         let client = reqwest::blocking::Client::new(); | ||||
|         let url = format!("{}/_matrix/client{}", self.homeserver_url, endpoint); | ||||
|         print!("url: {}", url.yellow()); | ||||
|         verboseln!("url: {}\n", url.blue()); | ||||
| 
 | ||||
|         // Construct URL with query parameters
 | ||||
|         let mut request = client.request(method, &url); | ||||
|  | @ -176,41 +177,28 @@ impl MatrixClient { | |||
|         current | ||||
|     } | ||||
| 
 | ||||
|     pub fn pandoc_convert_md_to_html(markdown: String) -> Result<String, Box<dyn Error>> { | ||||
|         let (output, errors, status) = crate::pipe( | ||||
|             "pandoc", | ||||
|             &mut [ | ||||
|                 "--from", "markdown-auto_identifiers", | ||||
|                 "--to", "html5", | ||||
|                 "--wrap=none",  // Verhindert Zeilenumbrüche
 | ||||
|                 "--no-highlight", // Deaktiviert Syntax-Highlighting
 | ||||
|             ], | ||||
|             markdown, | ||||
|         )?; | ||||
|         if status.success() { | ||||
|             println!("Resultat von Pandoc: {}", output); | ||||
|             Ok(output) | ||||
|         } else { | ||||
|             Err(format!("Pandoc error, exit code {:?}\n{}", status, errors).into()) | ||||
|     pub fn format_text_to_html(markdown: String) -> Result<String, Box<dyn Error>> { | ||||
|         lazy_static! { | ||||
|             static ref MATRIX_BOLD: Regex = Regex::new(r"\*\*(.+?)\*\*").unwrap(); | ||||
|             static ref MATRIX_ITALIC: Regex = Regex::new(r"\*(.+?)\*").unwrap(); | ||||
|             static ref MATRIX_URL: Regex = Regex::new(r"(https?://\S+?)(?:[.,])?(?:\s|$)").unwrap(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn format_matrix_html(markdown: String) -> Result<String, Box<dyn Error>> { | ||||
|         let mut html = Self::pandoc_convert_md_to_html(markdown)?; | ||||
|         
 | ||||
|         let url_regex = Regex::new(r"(https?://[^\s<]+)")?; | ||||
|         html = url_regex.replace_all(&html, r#"<a href="$1">$1</a>"#).to_string(); | ||||
|         let mut html = markdown; | ||||
|         
 | ||||
|         html = html.replace("\n\n", "</p><p>"); | ||||
|         // Handle URLs first
 | ||||
|         html = MATRIX_URL.replace_all(&html, r"<a href='$1'>$1</a>").to_string(); | ||||
|         
 | ||||
|         // Basic formatting
 | ||||
|         html = MATRIX_BOLD.replace_all(&html, r"<b>$1</b>").to_string(); | ||||
|         html = MATRIX_ITALIC.replace_all(&html, r"<i>$1</i>").to_string(); | ||||
|         
 | ||||
|         // Convert newlines to <br>
 | ||||
|         html = html.replace("\n", "<br>"); | ||||
|         
 | ||||
|         html = html.replace("**", "<strong>"); | ||||
|         html = html.replace("__", "<strong>"); | ||||
|         
 | ||||
|         Ok(html) | ||||
|     } | ||||
| 
 | ||||
|     pub fn pandoc_convert_text_to_md(markdown: String) -> Result<String, Box<dyn Error>> { | ||||
|         pub fn pandoc_convert_text_to_md(markdown: String) -> Result<String, Box<dyn Error>> { | ||||
|         let (output, errors, status) = crate::pipe( | ||||
|             "pandoc", | ||||
|             &mut ["--from", "markdown-auto_identifiers", "--to", "html5"], | ||||
|  | @ -227,14 +215,14 @@ impl MatrixClient { | |||
|     pub fn send_room_message( | ||||
|         &mut self, room_id: &str, text: &str, | ||||
|     ) -> Result<Value, Box<dyn Error>> { | ||||
|         let formatted_text = Self::format_matrix_html(text.to_string())?; | ||||
|         let formatted_text = Self::format_text_to_html(text.to_string())?; | ||||
|         let content = HashMap::from([ | ||||
|             ("type", "m.room.message"), | ||||
|             ("msgtype", "m.text"), | ||||
|             ("body", text), | ||||
|             ("format", "org.matrix.custom.html"), | ||||
|             ("formatted_body", &formatted_text), | ||||
|             ("m.mentions", "{}"), | ||||
|             // ("m.mentions", "{}"),
 | ||||
|             ]); | ||||
|         self.send_room_event(&room_id, "m.room.message", &content) | ||||
|     } | ||||
|  | @ -243,14 +231,14 @@ impl MatrixClient { | |||
|         &mut self, room: &str, event_type: &str, content: &impl Serialize, | ||||
|     ) -> Result<Value, Box<dyn Error>> { | ||||
|         let endpoint = format!("/r0/rooms/{}/send/{}/{}", room, event_type, self.txn_id()); | ||||
|         println!("room event:{}", &endpoint.red()); | ||||
|         verboseln!("room event:{}", &endpoint.green()); | ||||
|         self.put(&endpoint, None, Some(content), false) | ||||
|     } | ||||
|     pub fn send_short_and_long_messages_to_two_rooms( | ||||
|         &mut self, short_message: &str, long_message: &str, | ||||
|     pub fn send_message_to_two_rooms( | ||||
|         &mut self, message: &str | ||||
|     ) -> Result<(), Box<dyn Error>> { | ||||
|         self.send_room_message( &self.room_id_for_long_messages.clone(), &long_message,)?; | ||||
|         self.send_room_message( &self.room_id_for_short_messages.clone(), &short_message,)?; | ||||
|         self.send_room_message( &self.room_id_2.clone(), &message,)?; | ||||
|         self.send_room_message( &self.room_id_1.clone(), &message,)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 murmeldin
						murmeldin