mit cargo fmt alles formatiert
This commit is contained in:
		
							parent
							
								
									c026a38239
								
							
						
					
					
						commit
						c8031dfc01
					
				
					 5 changed files with 256 additions and 154 deletions
				
			
		|  | @ -3,14 +3,14 @@ use std::error::Error; | |||
| use std::io::{self, Write}; | ||||
| 
 | ||||
| /// Text shown for an empty field.
 | ||||
| const EMPTY_VALUE : &str = "(empty)"; | ||||
| const EMPTY_VALUE: &str = "(empty)"; | ||||
| /// Text shown in place of a password.
 | ||||
| const HIDDEN_PASSWORD : &str = "*****"; | ||||
| const HIDDEN_PASSWORD: &str = "*****"; | ||||
| 
 | ||||
| // highlight some of the info
 | ||||
| const ANSI_GROUP: &str = "\x1b[1;31m"; | ||||
| const ANSI_FIELD: &str = "\x1b[1;33m"; | ||||
| const ANSI_NOTICE: &str= "\x1b[33m"; | ||||
| const ANSI_NOTICE: &str = "\x1b[33m"; | ||||
| const ANSI_RESET: &str = "\x1b[0m"; | ||||
| 
 | ||||
| const CONFIG_SPEC: CfgSpec<'static> = CfgSpec { | ||||
|  | @ -70,7 +70,7 @@ pub fn populate_defaults(config: &KV) { | |||
|                 CfgField::Default { default, .. } => { | ||||
|                     config.default(&field.full_key(group.name), default) | ||||
|                 }, | ||||
|                 _ => {} | ||||
|                 _ => {}, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -80,33 +80,47 @@ pub fn populate_defaults(config: &KV) { | |||
| ///
 | ||||
| /// Will report if the config is fine or has missing values.
 | ||||
| pub fn interactive_check(config: KV) -> Result<(), Box<dyn Error>> { | ||||
|     let mut all_valid : bool = true; | ||||
|     let mut all_valid: bool = true; | ||||
|     for group in CONFIG_SPEC.groups { | ||||
|         group_header( group.name, group.description ); | ||||
|         group_header(group.name, group.description); | ||||
|         let todo = needs_info(&config, group); | ||||
|         // TODO: add distinction between edit all / edit necessary only
 | ||||
|         let choices = if !todo.is_empty() { | ||||
|             println!( "{}The following fields need adjustment: {}{}", ANSI_NOTICE, todo.join(", "), ANSI_RESET ); | ||||
|             println!( | ||||
|                 "{}The following fields need adjustment: {}{}", | ||||
|                 ANSI_NOTICE, | ||||
|                 todo.join(", "), | ||||
|                 ANSI_RESET | ||||
|             ); | ||||
|             &["[E]dit (default)", "[L]ist all", "[S]kip group"] | ||||
|         } else { | ||||
|             println!( "{}This group looks fine. OK to [S]kip, unless you want to adjust values here.{}", ANSI_NOTICE, ANSI_RESET ); | ||||
|             &["[S]kip group (default)", "[E]dit", "[L]ist all", ] | ||||
|             println!( | ||||
|                 "{}This group looks fine. OK to [S]kip, unless you want to adjust values here.{}", | ||||
|                 ANSI_NOTICE, ANSI_RESET | ||||
|             ); | ||||
|             &["[S]kip group (default)", "[E]dit", "[L]ist all"] | ||||
|         }; | ||||
|         loop { | ||||
|             let choice = prompt_action( choices ); | ||||
|             let choice = prompt_action(choices); | ||||
|             match choice { | ||||
|                 'L' => { show_group(&config, group); }, | ||||
|                 'L' => { | ||||
|                     show_group(&config, group); | ||||
|                 }, | ||||
|                 'E' => { | ||||
|                     for field in group.fields { | ||||
|                         check_field( &config, group.name, field, &mut all_valid )?; | ||||
|                         check_field(&config, group.name, field, &mut all_valid)?; | ||||
|                     } | ||||
|                     break; | ||||
|                 }, | ||||
|                 'S' => { | ||||
|                     if !todo.is_empty() { all_valid = false; } | ||||
|                     if !todo.is_empty() { | ||||
|                         all_valid = false; | ||||
|                     } | ||||
|                     break; | ||||
|                 }, | ||||
|                 _ => { unreachable!(); }, // (prompt already checks)
 | ||||
|                 _ => { | ||||
|                     unreachable!(); | ||||
|                 }, // (prompt already checks)
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -117,30 +131,49 @@ pub fn interactive_check(config: KV) -> Result<(), Box<dyn Error>> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| fn check_field( config: &KV, grpname: &str, field: &CfgField, ok: &mut bool ) -> Result<(), Box<dyn Error>> { | ||||
|     if field.is_silent() { return Ok(()) } | ||||
| fn check_field( | ||||
|     config: &KV, grpname: &str, field: &CfgField, ok: &mut bool, | ||||
| ) -> Result<(), Box<dyn Error>> { | ||||
|     if field.is_silent() { | ||||
|         return Ok(()); | ||||
|     } | ||||
|     show_field(config, grpname, field); | ||||
|     let key = field.full_key(grpname); | ||||
|     let value = config.get(&key).ok(); | ||||
|     let mut actions: Vec<&'static str> = Vec::new(); | ||||
|     // TODO: adjust order: empty password should offer input first
 | ||||
|     // TODO: RandomId should offer generating as [R]egenerate
 | ||||
|     if value.is_some() | field.is_password() | field.is_optional() { actions.push("[K]eep as-is"); } | ||||
|     if field.default_description().is_some() { actions.push("[R]eset to default"); } | ||||
|     if field.is_password() { actions.push( "[R]emove" ); } | ||||
|     actions.push( "[I]nput new value" ); | ||||
|     if !field.is_password() { actions.push( "[L]ong (multiline) input" ) }; | ||||
|     if value.is_some() | field.is_password() | field.is_optional() { | ||||
|         actions.push("[K]eep as-is"); | ||||
|     } | ||||
|     if field.default_description().is_some() { | ||||
|         actions.push("[R]eset to default"); | ||||
|     } | ||||
|     if field.is_password() { | ||||
|         actions.push("[R]emove"); | ||||
|     } | ||||
|     actions.push("[I]nput new value"); | ||||
|     if !field.is_password() { | ||||
|         actions.push("[L]ong (multiline) input") | ||||
|     }; | ||||
| 
 | ||||
|     match prompt_action(&actions) { | ||||
|         'K' => { | ||||
|             // we allow leaving a password empty, but that means config is incomplete
 | ||||
|             if value.is_none() & !field.is_optional() { *ok &= false; } | ||||
|             if value.is_none() & !field.is_optional() { | ||||
|                 *ok &= false; | ||||
|             } | ||||
|         }, | ||||
|         'R' => { | ||||
|             match field.default_value()? { | ||||
|                 Some(value) => { config.set(&key, &value)?; }, | ||||
|                 Some(value) => { | ||||
|                     config.set(&key, &value)?; | ||||
|                 }, | ||||
|                 // password again
 | ||||
|                 None => { config.delete(&key)?; *ok &= false; }, | ||||
|                 None => { | ||||
|                     config.delete(&key)?; | ||||
|                     *ok &= false; | ||||
|                 }, | ||||
|             } | ||||
|         }, | ||||
|         'I' => { | ||||
|  | @ -151,43 +184,49 @@ fn check_field( config: &KV, grpname: &str, field: &CfgField, ok: &mut bool ) -> | |||
|             let value = prompt_multiline(); | ||||
|             config.set(&key, &value)?; | ||||
|         }, | ||||
|         _ => { return Err("Wat.".into()); } | ||||
|         _ => { | ||||
|             return Err("Wat.".into()); | ||||
|         }, | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| /* ***** displaying various kinds of info ***** */ | ||||
| 
 | ||||
| fn group_header( name: &str, description: &str ) { | ||||
| fn group_header(name: &str, description: &str) { | ||||
|     println!("=============================="); | ||||
|     println!("{}{}{} - {}", ANSI_GROUP, name, ANSI_RESET, description); | ||||
|     println!(""); | ||||
| } | ||||
| 
 | ||||
| fn show_group( config: &KV, group: &CfgGroup ) { | ||||
| fn show_group(config: &KV, group: &CfgGroup) { | ||||
|     for field in group.fields { | ||||
|         show_field( &config, group.name, field ); | ||||
|         show_field(&config, group.name, field); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn show_field( config: &KV, grpname: &str, field: &CfgField ) { | ||||
|     if field.is_silent() { return } | ||||
| fn show_field(config: &KV, grpname: &str, field: &CfgField) { | ||||
|     if field.is_silent() { | ||||
|         return; | ||||
|     } | ||||
|     let key = field.full_key(grpname); | ||||
|     println!( "{}{}{} - {}", ANSI_FIELD, &key, ANSI_RESET, field.description() ); | ||||
|     println!( "  default: {}", field.default_description().unwrap_or(EMPTY_VALUE.to_string())); | ||||
|     let value = config.get(&key).ok() | ||||
|     println!("{}{}{} - {}", ANSI_FIELD, &key, ANSI_RESET, field.description()); | ||||
|     println!("  default: {}", field.default_description().unwrap_or(EMPTY_VALUE.to_string())); | ||||
|     let value = config | ||||
|         .get(&key) | ||||
|         .ok() | ||||
|         .map(|s| if field.is_password() { HIDDEN_PASSWORD.to_string() } else { s }) | ||||
|         .unwrap_or(EMPTY_VALUE.to_string()); | ||||
|     println!( "  current: {}", value ); | ||||
|     println!("  current: {}", value); | ||||
| } | ||||
| 
 | ||||
| /* ***** basic validation ***** */ | ||||
| 
 | ||||
| fn needs_info( config: &KV, group: &CfgGroup ) -> Vec<String> { | ||||
| fn needs_info(config: &KV, group: &CfgGroup) -> Vec<String> { | ||||
|     let mut acc = Vec::new(); | ||||
|     for field in group.fields { | ||||
|         if field.is_action_required(config, group.name) { | ||||
|             acc.push( field.key() ); | ||||
|             acc.push(field.key()); | ||||
|         } | ||||
|     } | ||||
|     acc | ||||
|  | @ -197,12 +236,12 @@ fn needs_info( config: &KV, group: &CfgGroup ) -> Vec<String> { | |||
| 
 | ||||
| /// Ask for a choice between several options.  First option is the default,
 | ||||
| /// format options with the first character in brackets like so: `"[E]xample"`.
 | ||||
| fn prompt_action( choices: &[&str] ) -> char { | ||||
| fn prompt_action(choices: &[&str]) -> char { | ||||
|     let prompt_message = choices.join(", "); | ||||
|     let default_choice = choices[0].to_uppercase().chars().nth(1).unwrap_or_default(); | ||||
|     loop { | ||||
|         println!( "{}", prompt_message ); | ||||
|         print!( "Select: " ); | ||||
|         println!("{}", prompt_message); | ||||
|         print!("Select: "); | ||||
|         io::stdout().flush().ok(); | ||||
| 
 | ||||
|         // Read line and take first non-space character
 | ||||
|  | @ -211,7 +250,10 @@ fn prompt_action( choices: &[&str] ) -> char { | |||
|         let input = input.trim().to_uppercase().chars().next().unwrap_or(default_choice); | ||||
| 
 | ||||
|         // Check list of choices for match
 | ||||
|         if choices.iter().any(|&choice| choice.to_uppercase().chars().nth(1).unwrap_or_default() == input) { | ||||
|         if choices | ||||
|             .iter() | ||||
|             .any(|&choice| choice.to_uppercase().chars().nth(1).unwrap_or_default() == input) | ||||
|         { | ||||
|             return input; | ||||
|         } else { | ||||
|             println!("Invalid choice. Try again!"); | ||||
|  | @ -220,7 +262,7 @@ fn prompt_action( choices: &[&str] ) -> char { | |||
| } | ||||
| 
 | ||||
| /// Read a single line of text.
 | ||||
| fn prompt_single_line( ) -> String { | ||||
| fn prompt_single_line() -> String { | ||||
|     print!("New value: "); | ||||
|     io::stdout().flush().ok(); | ||||
|     let mut input = String::new(); | ||||
|  | @ -229,7 +271,7 @@ fn prompt_single_line( ) -> String { | |||
| } | ||||
| 
 | ||||
| /// Read multiple lines of text, terminated by a line containing just a '.'.
 | ||||
| fn prompt_multiline( ) -> String { | ||||
| fn prompt_multiline() -> String { | ||||
|     println!("Enter new value: (end with '.' on a new line)"); | ||||
|     let mut acc = String::new(); | ||||
|     loop { | ||||
|  | @ -244,7 +286,7 @@ fn prompt_multiline( ) -> String { | |||
| } | ||||
| 
 | ||||
| /// Read a password without echoing it.
 | ||||
| fn prompt_password( ) -> String { | ||||
| fn prompt_password() -> String { | ||||
|     let pass = rpassword::prompt_password("New password (not shown) : ").unwrap(); | ||||
|     // disabled echo means the newline also isn't shown
 | ||||
|     println!(""); | ||||
|  | @ -264,7 +306,12 @@ enum CfgField<'a> { | |||
|     /// Empty by default, required, will prompt without echo.
 | ||||
|     Password { key: &'a str, description: &'a str }, | ||||
|     /// Empty by default, can be user-provided, or will be generated randomly.
 | ||||
|     RandomId { key: &'a str, generator: fn() -> Result<String,Box<dyn Error>>, generator_description: &'a str, description: &'a str }, | ||||
|     RandomId { | ||||
|         key: &'a str, | ||||
|         generator: fn() -> Result<String, Box<dyn Error>>, | ||||
|         generator_description: &'a str, | ||||
|         description: &'a str, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| /// A group of related config fields. The final key of an inner value will be
 | ||||
|  | @ -285,17 +332,17 @@ struct CfgSpec<'a> { | |||
| impl<'a> CfgField<'a> { | ||||
|     /// Silent fields don't get prompted or shown.
 | ||||
|     fn is_silent(&self) -> bool { | ||||
|         matches!( self, CfgField::Silent { .. } ) | ||||
|         matches!(self, CfgField::Silent { .. }) | ||||
|     } | ||||
| 
 | ||||
|     /// Password fields will be censored when displayed.
 | ||||
|     fn is_password(&self) -> bool { | ||||
|         matches!( self, CfgField::Password { .. } ) | ||||
|         matches!(self, CfgField::Password { .. }) | ||||
|     } | ||||
| 
 | ||||
|     /// Optional fields are allowed to be (and stay) empty.
 | ||||
|     fn is_optional(&self) -> bool { | ||||
|         matches!( self, CfgField::Optional { .. } ) | ||||
|         matches!(self, CfgField::Optional { .. }) | ||||
|     } | ||||
| 
 | ||||
|     /// Reports if the field needs changing or is ok as-is.
 | ||||
|  | @ -304,7 +351,10 @@ impl<'a> CfgField<'a> { | |||
|     /// *necessarily* always have a value. Optional is optional.  Only
 | ||||
|     /// Password and RandomId might need actions if they are missing.)
 | ||||
|     fn is_action_required(&self, config: &KV, grpname: &str) -> bool { | ||||
|         if matches!( self, CfgField::Silent { .. } | CfgField::Default { .. } | CfgField::Optional { .. } ) { | ||||
|         if matches!( | ||||
|             self, | ||||
|             CfgField::Silent { .. } | CfgField::Default { .. } | CfgField::Optional { .. } | ||||
|         ) { | ||||
|             false | ||||
|         } else { | ||||
|             config.get(self.full_key(grpname).as_str()).ok().is_none() | ||||
|  | @ -319,7 +369,8 @@ impl<'a> CfgField<'a> { | |||
|             CfgField::Optional { key, .. } => key, | ||||
|             CfgField::Password { key, .. } => key, | ||||
|             CfgField::RandomId { key, .. } => key, | ||||
|         }.to_string() | ||||
|         } | ||||
|         .to_string() | ||||
|     } | ||||
| 
 | ||||
|     /// Full field name / key used in the DB (currently `{grpname}-{fieldname}`.)
 | ||||
|  | @ -335,7 +386,8 @@ impl<'a> CfgField<'a> { | |||
|             CfgField::Optional { description, .. } => description, | ||||
|             CfgField::Password { description, .. } => description, | ||||
|             CfgField::RandomId { description, .. } => description, | ||||
|         }.to_string() | ||||
|         } | ||||
|         .to_string() | ||||
|     } | ||||
| 
 | ||||
|     /// Gets a description of the default value if one exists.  
 | ||||
|  | @ -344,7 +396,9 @@ impl<'a> CfgField<'a> { | |||
|         match self { | ||||
|             CfgField::Silent { default, .. } => Some(default.to_string()), | ||||
|             CfgField::Default { default, .. } => Some(default.to_string()), | ||||
|             CfgField::RandomId { generator_description, .. } => Some(format!("{}{}{}",'(',generator_description,')')), | ||||
|             CfgField::RandomId { generator_description, .. } => { | ||||
|                 Some(format!("{}{}{}", '(', generator_description, ')')) | ||||
|             }, | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -1,63 +1,61 @@ | |||
| use reqwest::blocking::Response; | ||||
| use reqwest::blocking::Client; | ||||
| use reqwest::blocking::Response; | ||||
| use std::error::Error; | ||||
| 
 | ||||
| // TODO: implement dry-run logic
 | ||||
| pub struct HedgeDoc { | ||||
|     server_url : String, | ||||
|     is_dry_run : bool, | ||||
|     client : Client, | ||||
|     server_url: String, | ||||
|     is_dry_run: bool, | ||||
|     client: Client, | ||||
| } | ||||
| 
 | ||||
| impl HedgeDoc { | ||||
|     pub fn new( server_url: &str, is_dry_run: bool ) -> Self { | ||||
|     pub fn new(server_url: &str, is_dry_run: bool) -> Self { | ||||
|         Self { server_url: server_url.to_string(), is_dry_run, client: Client::new() } | ||||
|     } | ||||
| 
 | ||||
|     pub fn format_url( &self, pad_name: &str ) -> String { | ||||
|         format!( "{}/{}", self.server_url, pad_name ) | ||||
|     pub fn format_url(&self, pad_name: &str) -> String { | ||||
|         format!("{}/{}", self.server_url, pad_name) | ||||
|     } | ||||
| 
 | ||||
|     fn format_action( &self, pad_name: &str, verb: &str ) -> String { | ||||
|         format!( "{}/{}/{}", self.server_url, pad_name, verb ) | ||||
|     fn format_action(&self, pad_name: &str, verb: &str) -> String { | ||||
|         format!("{}/{}/{}", self.server_url, pad_name, verb) | ||||
|     } | ||||
| 
 | ||||
|     fn do_request(&self, url : &str ) -> Result<Response, Box<dyn Error>> { | ||||
|         Ok(self.client.get( url ).send().unwrap()) | ||||
|     fn do_request(&self, url: &str) -> Result<Response, Box<dyn Error>> { | ||||
|         Ok(self.client.get(url).send().unwrap()) | ||||
|     } | ||||
| 
 | ||||
|     fn get_id_from_response( &self, res : Response ) -> String { | ||||
|         res.url().to_string().trim_start_matches( &format!( "{}/", self.server_url ) ).to_string() | ||||
|     fn get_id_from_response(&self, res: Response) -> String { | ||||
|         res.url().to_string().trim_start_matches(&format!("{}/", self.server_url)).to_string() | ||||
|     } | ||||
| 
 | ||||
|     pub fn download( &self, pad_name: &str ) -> Result<String, Box<dyn Error>> { | ||||
|         Ok(self.do_request( &self.format_action(pad_name, "download"))?.text()?) | ||||
|     pub fn download(&self, pad_name: &str) -> Result<String, Box<dyn Error>> { | ||||
|         Ok(self.do_request(&self.format_action(pad_name, "download"))?.text()?) | ||||
|     } | ||||
| 
 | ||||
|     pub fn create_pad( &self ) -> Result<String, Box<dyn Error>> { | ||||
|         let res = self.do_request( &format!( "{}/new", self.server_url ) ).unwrap(); | ||||
|     pub fn create_pad(&self) -> Result<String, Box<dyn Error>> { | ||||
|         let res = self.do_request(&format!("{}/new", self.server_url)).unwrap(); | ||||
|         if res.status().is_success() { | ||||
|             Ok(self.get_id_from_response(res)) | ||||
|         } else { | ||||
|             Err( format!("Failed to create pad {}", res.status()).into() ) | ||||
|             Err(format!("Failed to create pad {}", res.status()).into()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn import_note( &self, id: Option<&str>, content: String ) -> Result<String, Box<dyn Error>> { | ||||
|     pub fn import_note(&self, id: Option<&str>, content: String) -> Result<String, Box<dyn Error>> { | ||||
|         let url = match id { | ||||
|             Some(id) => self.format_url( &format!( "new/{id}" ) ), | ||||
|             Some(id) => self.format_url(&format!("new/{id}")), | ||||
|             None => self.format_url("new"), | ||||
|         }; | ||||
| 
 | ||||
|         let res = self.client.post(&url) | ||||
|             .header( "Content-Type", "text/markdown" ) | ||||
|             .body(content) | ||||
|             .send()?; | ||||
|         let res = | ||||
|             self.client.post(&url).header("Content-Type", "text/markdown").body(content).send()?; | ||||
| 
 | ||||
|         if res.status().is_success() { | ||||
|             Ok(self.get_id_from_response(res)) | ||||
|         } else { | ||||
|             Err( format!("Failed to import note: {}", res.status()).into() ) | ||||
|             Err(format!("Failed to import note: {}", res.status()).into()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										185
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										185
									
								
								src/main.rs
									
										
									
									
									
								
							|  | @ -32,12 +32,11 @@ mod mediawiki; | |||
| 
 | ||||
| mod config_check; | ||||
| 
 | ||||
| 
 | ||||
| pub mod variables_and_settings; | ||||
| 
 | ||||
| use std::borrow::Cow; | ||||
| use std::error::Error; | ||||
| use std::env; | ||||
| use std::error::Error; | ||||
| use std::fs::File; | ||||
| use std::io::Read; | ||||
| // use std::future::Future;
 | ||||
|  | @ -47,9 +46,9 @@ use clap::{Arg, Command}; | |||
| use regex::Regex; | ||||
| use uuid::Uuid; | ||||
| 
 | ||||
| use lettre::{Message, SmtpTransport, Transport}; | ||||
| use lettre::message::{header, SinglePart}; | ||||
| use lettre::transport::smtp::authentication::Credentials; | ||||
| use lettre::{Message, SmtpTransport, Transport}; | ||||
| 
 | ||||
| const FALLBACK_TEMPLATE: &str = variables_and_settings::FALLBACK_TEMPLATE; | ||||
| 
 | ||||
|  | @ -86,7 +85,8 @@ fn parse_args() -> Args { | |||
|                 .action(clap::ArgAction::Set) | ||||
|                 .default_value("config.sqlite") | ||||
|                 .help("specifies an alternate config file"), | ||||
|         ).get_matches(); | ||||
|         ) | ||||
|         .get_matches(); | ||||
|     Args { | ||||
|         check_mode: *matches.get_one::<bool>("check").unwrap(), | ||||
|         config_file: matches.get_one::<String>("config_file").unwrap().clone(), | ||||
|  | @ -102,12 +102,12 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
|     let config = KV::new(config_file).unwrap(); | ||||
|     config_check::populate_defaults(&config); | ||||
|     if args.check_mode { | ||||
|         return config_check::interactive_check( config ); | ||||
|         return config_check::interactive_check(config); | ||||
|     } | ||||
|     // config
 | ||||
|     let hedgedoc = HedgeDoc::new( &config["hedgedoc-server-url"], is_dry_run() ); | ||||
|     let hedgedoc = HedgeDoc::new(&config["hedgedoc-server-url"], is_dry_run()); | ||||
|     println!("[START]\nAktueller Zustand der DB:"); | ||||
|     config.dump_redacting(&["email-password","wiki-password","matrix-password"]).ok(); | ||||
|     config.dump_redacting(&["email-password", "wiki-password", "matrix-password"]).ok(); | ||||
| 
 | ||||
|     // Dienstage diesen Monat
 | ||||
|     let all_tuesdays: Vec<NaiveDate> = get_all_weekdays(0, Weekday::Tue); | ||||
|  | @ -120,7 +120,7 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
|     let vierter_dienstag_nächster_monat: String = all_tuesdays_next_month[3].to_string(); | ||||
| 
 | ||||
|     // Daten, die später benutzt werden, definieren
 | ||||
|     let today= Local::now(); | ||||
|     let today = Local::now(); | ||||
|     let today_simple = today.date_naive(); | ||||
|     let yesterday = today_simple.pred_opt().unwrap(); | ||||
|     let in_1_day = today_simple.succ_opt().unwrap(); | ||||
|  | @ -129,23 +129,25 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
| 
 | ||||
|     // Nächste Plena nachschauen:
 | ||||
| 
 | ||||
|     let nächster_plenumtermin: &String = if all_tuesdays[1] >= yesterday { // Für das Pad rumschicken am nächsten Tag wird das Datum einen Tag nach Hinten gesetzt,
 | ||||
|     let nächster_plenumtermin: &String = if all_tuesdays[1] >= yesterday { | ||||
|         // Für das Pad rumschicken am nächsten Tag wird das Datum einen Tag nach Hinten gesetzt,
 | ||||
|         &zweiter_dienstag | ||||
|         } else { | ||||
|     } else { | ||||
|         &vierter_dienstag | ||||
|     }; | ||||
|     let übernächster_plenumtermin = if all_tuesdays[1] >= yesterday { // hier das Gleiche.
 | ||||
|     let übernächster_plenumtermin = if all_tuesdays[1] >= yesterday { | ||||
|         // hier das Gleiche.
 | ||||
|         &vierter_dienstag | ||||
|     } else { | ||||
|         &zweiter_dienstag_nächster_monat | ||||
|     }; | ||||
|     let überübernächster_plenumtermin = if all_tuesdays[1] >= yesterday { // hier das Gleiche.
 | ||||
|     let überübernächster_plenumtermin = if all_tuesdays[1] >= yesterday { | ||||
|         // hier das Gleiche.
 | ||||
|         &zweiter_dienstag_nächster_monat | ||||
|     } else { | ||||
|         &vierter_dienstag_nächster_monat | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     // Der Code muss nur für vor dem 2. und vor dem 4. Dienstag gebaut werden, weil im nächsten Monat der Code frühestens 7 Tage vor dem Plenum wieder passt.
 | ||||
| 
 | ||||
|     let in_1_day_is_plenum: bool = check_if_plenum(nächster_plenumtermin.clone(), in_1_day); | ||||
|  | @ -153,8 +155,12 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
|     let yesterday_was_plenum: bool = check_if_plenum(nächster_plenumtermin.clone(), yesterday); | ||||
| 
 | ||||
|     // Pad-Links aus der Datenbank laden:
 | ||||
|     let current_pad_id = config.get("hedgedoc-last-id").expect("ID des aktuellen Pads undefiniert. Bitte in der DB eintragen oder generieren."); | ||||
|     let future_pad_id = config.get("hedgedoc-next-id").expect("ID des nächsten Pads undefiniert. Bitte in der DB eintragen oder generieren."); | ||||
|     let current_pad_id = config | ||||
|         .get("hedgedoc-last-id") | ||||
|         .expect("ID des aktuellen Pads undefiniert. Bitte in der DB eintragen oder generieren."); | ||||
|     let future_pad_id = config | ||||
|         .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; | ||||
| 
 | ||||
|  | @ -172,7 +178,7 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
|     if in_1_day_is_plenum { | ||||
|         println!("In 1 Tag ist Plenum, deshalb wird eine Erinnerung raus geschickt!"); | ||||
|         let tldr_vec = create_tldr(&pad_content_without_top_instructions); | ||||
|         let mut tldr  = String::new(); | ||||
|         let mut tldr = String::new(); | ||||
|         for element in tldr_vec { | ||||
|             tldr.push_str("\n"); | ||||
|             tldr.push_str(&element) | ||||
|  | @ -180,7 +186,8 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
|         if number_of_tops(&pad_content_without_top_instructions) != 0 { | ||||
|             // Mail an alle senden, findet statt
 | ||||
|             let betreff = "Morgen ist Plenum!".to_string(); // ADJ_TIMEYWIMEY
 | ||||
|             let message: String = format!(r#"{email_greeting}
 | ||||
|             let message: String = format!( | ||||
|                 r#"{email_greeting}
 | ||||
| 
 | ||||
| Es gibt Themen, deshalb wird das morgige Plenum statt finden. Anbei das Plenumspad: | ||||
|   {current_pad_link} | ||||
|  | @ -190,14 +197,16 @@ Und hier ein TL;DR von den aktuellen Themen: | |||
| 
 | ||||
| Bis morgen, 20 Uhr! | ||||
| 
 | ||||
| {email_signature}"#); // ADJ_TIMEYWIMEY
 | ||||
| {email_signature}"#
 | ||||
|             ); // ADJ_TIMEYWIMEY
 | ||||
|             println!("---E-Mail:---\n{}\n-----------", message); | ||||
|             // XXX option x expect
 | ||||
|             message_id = Some(mail_versenden(&config, betreff, message).expect("Plenum findet statt. Mail wurde versucht zu senden, konnte aber nicht gesendet werden!")) | ||||
|         } else { | ||||
|             // Mail an alle senden und absagen
 | ||||
|             let betreff = format!("Plenum am {} fällt mangels Themen aus", nächster_plenumtermin); | ||||
|             let message: String = format!(r#"{email_greeting}
 | ||||
|             let message: String = format!( | ||||
|                 r#"{email_greeting}
 | ||||
| 
 | ||||
| Es gibt keine Themen, deshalb wird das morgige Plenum leider nicht statt finden. | ||||
| 
 | ||||
|  | @ -206,7 +215,9 @@ Hier ist der Link zum Pad vom nächsten Plenum, das am {} statt finden wird: | |||
| 
 | ||||
| Bis zum nächsten Plenum. | ||||
| 
 | ||||
| {email_signature}"#, nächster_plenumtermin);
 | ||||
| {email_signature}"#,
 | ||||
|                 nächster_plenumtermin | ||||
|             ); | ||||
|             println!("---E-Mail:---\n{}\n-----------", message); | ||||
|             // XXX option x expect
 | ||||
|             message_id = Some(mail_versenden(&config, betreff, message).expect("Plenum wird abgesagt. Mail wurde versucht zu senden, konnte aber nicht gesendet werden!")) | ||||
|  | @ -216,29 +227,38 @@ Bis zum nächsten Plenum. | |||
|         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#"{email_greeting}
 | ||||
|             let message: String = format!( | ||||
|                 r#"{email_greeting}
 | ||||
| 
 | ||||
| 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} | ||||
| 
 | ||||
| {email_signature}"#);
 | ||||
| {email_signature}"#
 | ||||
|             ); | ||||
|             println!("---E-Mail:---\n{}\n-----------", message); | ||||
|             // XXX option x expect
 | ||||
|             message_id = Some(mail_versenden(&config, betreff, message).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 = hedgedoc.download(¤t_pad_id).expect("Fehler beim Hedgedoc-Pad-Download!"); | ||||
|         let old_pad_content = | ||||
|             hedgedoc.download(¤t_pad_id).expect("Fehler beim Hedgedoc-Pad-Download!"); | ||||
|         // MUSS WIEDER REIN NACH DEM TESTEN: generate_new_pad_for_following_date(übernächster_plenumtermin, überübernächster_plenumtermin, &config).await.expect("Fehler! Plenumspad konnte nicht generiert werden!");
 | ||||
|         println!("DATENBANK: aktuelles-plenumspad: {:?} und zukünftiges plenumspad: {:?}", &config.get("hedgedoc-last-id"), &config.get("hedgedoc-next-id")); | ||||
|         println!( | ||||
|             "DATENBANK: aktuelles-plenumspad: {:?} und zukünftiges plenumspad: {:?}", | ||||
|             &config.get("hedgedoc-last-id"), | ||||
|             &config.get("hedgedoc-next-id") | ||||
|         ); | ||||
| 
 | ||||
|         let old_pad_content_without_top_instructions = try_to_remove_top_instructions(old_pad_content); | ||||
|         let old_pad_content_without_top_instructions = | ||||
|             try_to_remove_top_instructions(old_pad_content); | ||||
|         let tldr_vec = create_tldr(&old_pad_content_without_top_instructions); | ||||
|         let tldr  = tldr_vec.join("\n"); | ||||
|         let tldr = tldr_vec.join("\n"); | ||||
|         // XXX nächstes/übernächstes?
 | ||||
|         let message: String = format!(r#"{email_greeting}
 | ||||
|         let message: String = format!( | ||||
|             r#"{email_greeting}
 | ||||
| 
 | ||||
| Anbei das gestrige Plenumspad. Hier sind die Links zum nächsten: | ||||
|   {current_pad_link} | ||||
|  | @ -252,8 +272,10 @@ Und hier ist das Protokoll des letzten Plenums: | |||
| 
 | ||||
| {old_pad_content_without_top_instructions} | ||||
| 
 | ||||
| {email_signature}"#);
 | ||||
|         let betreff: String = format!("Plenumsprotokoll vom {}: Es gab {} TOPs", nächster_plenumtermin, top_anzahl); | ||||
| {email_signature}"#
 | ||||
|         ); | ||||
|         let betreff: String = | ||||
|             format!("Plenumsprotokoll vom {}: Es gab {} TOPs", nächster_plenumtermin, top_anzahl); | ||||
|         println!("---E-Mail:---\n{}\n-----------", message); | ||||
|         // XXX option x expect
 | ||||
|         message_id = Some(mail_versenden(&config, betreff, message).expect("Mail mit Plenumsprotokoll wurde versucht zu senden, konnte aber nicht gesendet werden!")); | ||||
|  | @ -262,19 +284,24 @@ Und hier ist das Protokoll des letzten Plenums: | |||
|     println!("message id: {:?}", message_id); | ||||
| 
 | ||||
|     println!("[ENDE]\nAktueller Zustand der DB:"); | ||||
|     config.dump_redacting(&["email-password","matrix-password","wiki-password"]).ok(); | ||||
|     
 | ||||
|     if config.has_errors() { Err("There were errors.".into()) } else { Ok(()) } | ||||
|     config.dump_redacting(&["email-password", "matrix-password", "wiki-password"]).ok(); | ||||
| 
 | ||||
|     if config.has_errors() { | ||||
|         Err("There were errors.".into()) | ||||
|     } else { | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn get_all_weekdays(month_offset: i32, week_day: Weekday) -> Vec<NaiveDate>{ | ||||
| fn get_all_weekdays(month_offset: i32, week_day: Weekday) -> Vec<NaiveDate> { | ||||
|     let date = Local::now().date_naive(); | ||||
|     let date = match month_offset.signum() { | ||||
|         0  => Some(date), | ||||
|         1  => date.checked_add_months(chrono::Months::new(month_offset as u32)), | ||||
|         0 => Some(date), | ||||
|         1 => date.checked_add_months(chrono::Months::new(month_offset as u32)), | ||||
|         -1 => date.checked_sub_months(chrono::Months::new((-month_offset) as u32)), | ||||
|         _  => unreachable!(), | ||||
|     }.expect("(very) invalid month offset"); | ||||
|         _ => unreachable!(), | ||||
|     } | ||||
|     .expect("(very) invalid month offset"); | ||||
|     let month = date.month(); | ||||
|     let mut current_date = NaiveDate::from_ymd_opt(date.year(), date.month(), 1); | ||||
|     let mut dates = Vec::new(); | ||||
|  | @ -290,30 +317,28 @@ fn get_all_weekdays(month_offset: i32, week_day: Weekday) -> Vec<NaiveDate>{ | |||
| fn check_if_plenum(infrage_kommendes_plenum: String, date_to_check: NaiveDate) -> bool { | ||||
|     // Überprüfen, ob an dem Datum Plenum ist
 | ||||
|     let date_to_check = date_to_check.to_string(); | ||||
|     return if infrage_kommendes_plenum == date_to_check { | ||||
|         true | ||||
|     } else { | ||||
|         false | ||||
|     } | ||||
|     return if infrage_kommendes_plenum == date_to_check { true } else { false }; | ||||
| } | ||||
| 
 | ||||
| fn number_of_tops (pad_content: &String) -> i32 { | ||||
| fn number_of_tops(pad_content: &String) -> i32 { | ||||
|     // Logik: Wenn irgendwo TOP 2, top2, Top2 oder TOP2 steht, dann gibt es Themen
 | ||||
|     let re = Regex::new(r"^##+ *([Tt][Oo][Pp] +\d[.\d]*.*)$").unwrap(); | ||||
|     let m = re.find(&pad_content); | ||||
|     m.iter().len() as i32 | ||||
| } | ||||
| 
 | ||||
| fn create_tldr (pad_content: &String) -> Vec<&str> { | ||||
| fn create_tldr(pad_content: &String) -> Vec<&str> { | ||||
|     // Logik: Wenn irgendwo TOP 2, top2, Top2 oder TOP2 steht, dann gibt es Themen
 | ||||
|     let re_top = Regex::new(r"^##+ *([Tt][Oo][Pp] +\d[.\d]*.*)$").unwrap(); | ||||
|     let tldr: Vec<&str> = re_top.find_iter(&pad_content).map(|m|m.as_str()).collect(); | ||||
|     let tldr: Vec<&str> = re_top.find_iter(&pad_content).map(|m| m.as_str()).collect(); | ||||
|     //println!("{:?}", m);
 | ||||
|     tldr | ||||
|     //tldr_vec.append() = m.iter()
 | ||||
| } | ||||
| 
 | ||||
| fn mail_versenden(config: &KV, betreff: String, inhalt: String) -> std::result::Result<String, Box<dyn std::error::Error>> { | ||||
| fn mail_versenden( | ||||
|     config: &KV, betreff: String, inhalt: String, | ||||
| ) -> std::result::Result<String, Box<dyn std::error::Error>> { | ||||
|     // Define the email
 | ||||
|     let message_id: String = Uuid::new_v4().to_string() + &String::from("@berlin.ccc.de"); | ||||
| 
 | ||||
|  | @ -328,59 +353,74 @@ fn mail_versenden(config: &KV, betreff: String, inhalt: String) -> std::result:: | |||
|         .in_reply_to("19de3985-05b4-42f3-9a6a-e941479be2ed@berlin.ccc.de".to_string()) | ||||
|         // Set the subject of the email
 | ||||
|         .subject(betreff) | ||||
|         .singlepart(SinglePart::builder() | ||||
|             .header(header::ContentType::TEXT_PLAIN) | ||||
|             .body(inhalt)) | ||||
|         .singlepart(SinglePart::builder().header(header::ContentType::TEXT_PLAIN).body(inhalt)) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     if !is_dry_run() { | ||||
|         // Set up the SMTP client
 | ||||
|         let creds = Credentials::new(config["email-user"].to_string(), config["email-password"].to_string()); | ||||
|         let creds = Credentials::new( | ||||
|             config["email-user"].to_string(), | ||||
|             config["email-password"].to_string(), | ||||
|         ); | ||||
|         // Open a remote connection to gmail
 | ||||
| 
 | ||||
|         let mailer = SmtpTransport::starttls_relay(&config["email-server"])? | ||||
|             .credentials(creds) | ||||
|             .build(); | ||||
|         let mailer = | ||||
|             SmtpTransport::starttls_relay(&config["email-server"])?.credentials(creds).build(); | ||||
| 
 | ||||
|         // Send the email
 | ||||
|         match mailer.send(&email) { | ||||
|             Ok(_) => println!("Email sent successfully!"), | ||||
|             Err(e) => eprintln!("Could not send email: {:?}", e),    } | ||||
|             Err(e) => eprintln!("Could not send email: {:?}", e), | ||||
|         } | ||||
|         Ok(message_id) | ||||
|     } else { | ||||
|         println!( "[DRY RUN - NOT] sending email\n(raw message:)\n{}", std::str::from_utf8(&email.formatted()).unwrap_or("((UTF-8 error))") ); | ||||
|         println!( | ||||
|             "[DRY RUN - NOT] sending email\n(raw message:)\n{}", | ||||
|             std::str::from_utf8(&email.formatted()).unwrap_or("((UTF-8 error))") | ||||
|         ); | ||||
|         Ok("dummy-message-id@localhost".to_string()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn generate_new_pad_for_following_date(config : KV, hedgedoc : HedgeDoc, übernächster_plenumtermin: &String, überübernächster_plenumtermin: &String, kv: &KV) -> Result<(), Box<dyn Error>> { | ||||
| 
 | ||||
|     match hedgedoc.create_pad( ) { | ||||
| fn generate_new_pad_for_following_date( | ||||
|     config: KV, hedgedoc: HedgeDoc, übernächster_plenumtermin: &String, | ||||
|     überübernächster_plenumtermin: &String, kv: &KV, | ||||
| ) -> Result<(), Box<dyn Error>> { | ||||
|     match hedgedoc.create_pad() { | ||||
|         Err(e) => println!("Failed to create pad: {}", e), | ||||
|         Ok(pad_id) => { | ||||
|             println!("Pad created successfully with ID: {}", pad_id); | ||||
| 
 | ||||
|             // Get the most recent plenum template and replace the placeholders:
 | ||||
|             let template_content: String = match config.get("hedgedoc-template-name") { | ||||
|                 Ok(content) => hedgedoc.download(&content.clone()).unwrap_or_else(|_| FALLBACK_TEMPLATE.to_string()), | ||||
|                 Ok(content) => hedgedoc | ||||
|                     .download(&content.clone()) | ||||
|                     .unwrap_or_else(|_| FALLBACK_TEMPLATE.to_string()), | ||||
|                 Err(_) => FALLBACK_TEMPLATE.to_string(), | ||||
|             }; | ||||
|             // XXX you don't just use the template as-is…
 | ||||
|             let template_modified: String = replace_placeholders(&template_content, übernächster_plenumtermin, überübernächster_plenumtermin).unwrap_or_else(|error |template_content); // Try regex, if not successful use without regex
 | ||||
|             let template_modified: String = replace_placeholders( | ||||
|                 &template_content, | ||||
|                 übernächster_plenumtermin, | ||||
|                 überübernächster_plenumtermin, | ||||
|             ) | ||||
|             .unwrap_or_else(|error| template_content); // Try regex, if not successful use without regex
 | ||||
| 
 | ||||
|             match hedgedoc.import_note( Some(&pad_id), template_modified ) { | ||||
|             match hedgedoc.import_note(Some(&pad_id), template_modified) { | ||||
|                 Ok(_) => { | ||||
|                     println!("Pad updated successfully with template content."); | ||||
|                     rotate (&pad_id, kv); | ||||
|                     rotate(&pad_id, kv); | ||||
|                 }, | ||||
|                 Err(e) => println!("Failed to update pad: {}", e), | ||||
|             } | ||||
|         } | ||||
|         }, | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn replace_placeholders(template: &str, übernächster_plenumtermin: &str, überübernächster_plenumtermin: &str) -> Result<String, Box<dyn Error>> { | ||||
| fn replace_placeholders( | ||||
|     template: &str, übernächster_plenumtermin: &str, überübernächster_plenumtermin: &str, | ||||
| ) -> Result<String, Box<dyn Error>> { | ||||
|     let re_datum = Regex::new(r"\{\{Datum\}\}")?; | ||||
|     let result = re_datum.replace_all(template, übernächster_plenumtermin); | ||||
|     let re_naechstes_plenum = Regex::new(r"\{\{naechstes-plenum\}\}")?; | ||||
|  | @ -388,18 +428,23 @@ fn replace_placeholders(template: &str, übernächster_plenumtermin: &str, über | |||
|     Ok(result.to_string()) | ||||
| } | ||||
| 
 | ||||
| fn rotate (future_pad_id: &str, kv: &KV) { | ||||
| fn rotate(future_pad_id: &str, kv: &KV) { | ||||
|     let next_plenum_pad = kv.get("zukünftiges-plenumspad").ok(); | ||||
|     if next_plenum_pad == None { | ||||
|         kv.set("zukünftiges-plenumspad", &future_pad_id).expect("Fehler beim Beschreiben der Datenbank mit neuem Plenumslink!"); // Beispiel: aktuelles-plenumspad: Ok(Some("eCH24zXGS9S8Stg5xI3aRg"))
 | ||||
|         kv.set("zukünftiges-plenumspad", &future_pad_id) | ||||
|             .expect("Fehler beim Beschreiben der Datenbank mit neuem Plenumslink!"); | ||||
|     // Beispiel: aktuelles-plenumspad: Ok(Some("eCH24zXGS9S8Stg5xI3aRg"))
 | ||||
|     } else { | ||||
|         kv.set("aktuelles-plenumspad", &next_plenum_pad.unwrap()).expect("Fehler beim Beschreiben der Datenbank mit neuem Plenumslink!"); // Beispiel: aktuelles-plenumspad: Ok(Some("eCH24zXGS9S8Stg5xI3aRg"))
 | ||||
|         kv.set("zukünftiges-plenumspad", &future_pad_id).expect("Fehler beim Beschreiben der Datenbank mit neuem Plenumslink!"); // Beispiel: aktuelles-plenumspad: Ok(Some("eCH24zXGS9S8Stg5xI3aRg"))
 | ||||
|         kv.set("aktuelles-plenumspad", &next_plenum_pad.unwrap()) | ||||
|             .expect("Fehler beim Beschreiben der Datenbank mit neuem Plenumslink!"); // Beispiel: aktuelles-plenumspad: Ok(Some("eCH24zXGS9S8Stg5xI3aRg"))
 | ||||
|         kv.set("zukünftiges-plenumspad", &future_pad_id) | ||||
|             .expect("Fehler beim Beschreiben der Datenbank mit neuem Plenumslink!"); | ||||
|         // Beispiel: aktuelles-plenumspad: Ok(Some("eCH24zXGS9S8Stg5xI3aRg"))
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn try_to_remove_top_instructions (pad_content: String) -> String { | ||||
| fn try_to_remove_top_instructions(pad_content: String) -> String { | ||||
|     let re_top_instructions: Regex = Regex::new(r"(<!--(?:.||\n)*-->)").unwrap(); | ||||
|     let result: Cow<str> = re_top_instructions.replace_all(&pad_content, "---"); | ||||
|     result.to_string() // Wenn es nicht geklappt hat, wird einfach das Pad mit dem Kommentar zurückgegeben
 | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -6,18 +6,20 @@ pub fn pad_ins_wiki(old_pad_content: String) { | |||
|     convert_markdown_to_mediawiki_and_save_as_txt(old_pad_content); | ||||
| 
 | ||||
|     // Textdatei wieder einlesen
 | ||||
|     let mut file = File::open("pandoc-output.txt").expect("Fehler beim öffnen der MediaWiki-Textdatei!"); | ||||
|     let mut file = | ||||
|         File::open("pandoc-output.txt").expect("Fehler beim öffnen der MediaWiki-Textdatei!"); | ||||
|     let mut contents = String::new(); | ||||
|     file.read_to_string(&mut contents).expect("Fehler beim auslesen der MediaWiki-Textdatei!"); | ||||
| 
 | ||||
|     // Passwörter aus Datenbank lesen (ToBeDone)
 | ||||
|     let plenum_bot_user = String::from("PlenumBot@PlenumBot-PW1"); | ||||
|     let plenum_bot_pw = String::from("**OLD_API_PW_REMOVED**"); | ||||
|     let login_token = login_to_mediawiki(plenum_bot_user.clone(), plenum_bot_pw.clone()).expect("Fehler beim Einloggen!"); | ||||
|     let login_token = login_to_mediawiki(plenum_bot_user.clone(), plenum_bot_pw.clone()) | ||||
|         .expect("Fehler beim Einloggen!"); | ||||
|     println!("plenum_bot_user: {plenum_bot_user}, plenum_bot_pw: {plenum_bot_pw}, login_token: {login_token}") | ||||
| } | ||||
| 
 | ||||
| fn convert_markdown_to_mediawiki_and_save_as_txt (old_pad_content: String) { | ||||
| fn convert_markdown_to_mediawiki_and_save_as_txt(old_pad_content: String) { | ||||
|     //Convert Markdown into Mediawiki
 | ||||
|     // Vanilla pandoc Befehl: pandoc --from markdown --to mediawiki --no-highlight
 | ||||
|     let mut p = pandoc::new(); | ||||
|  | @ -25,10 +27,13 @@ fn convert_markdown_to_mediawiki_and_save_as_txt (old_pad_content: String) { | |||
|     p.set_input_format(pandoc::InputFormat::Markdown, vec![]); | ||||
|     p.set_output(pandoc::OutputKind::File("./pandoc-output.txt".parse().unwrap())); | ||||
|     p.set_output_format(pandoc::OutputFormat::MediaWiki, vec![]); | ||||
|     p.execute().expect("Fehler beim Umwandeln des und speichern des Pads in eine mediawiki-Textdatei"); | ||||
|     p.execute() | ||||
|         .expect("Fehler beim Umwandeln des und speichern des Pads in eine mediawiki-Textdatei"); | ||||
| } | ||||
| 
 | ||||
| fn login_to_mediawiki (plenum_bot_user: String, plenum_bot_pw: String) -> Result<String, Box<dyn Error>> { | ||||
| fn login_to_mediawiki( | ||||
|     plenum_bot_user: String, plenum_bot_pw: String, | ||||
| ) -> Result<String, Box<dyn Error>> { | ||||
|     //let mut map = HashMap::new();
 | ||||
|     //map.insert("logintoken", "result");
 | ||||
|     let username = "cccb-wiki"; | ||||
|  | @ -50,7 +55,7 @@ fn login_to_mediawiki (plenum_bot_user: String, plenum_bot_pw: String) -> Result | |||
|     let html_source = resp.text()?; | ||||
|     //let login_token: String = map.get("logintoken").unwrap().to_string().clone();
 | ||||
|     println!("---HTML:---\n{}\n-----------", html_source); | ||||
|     
 | ||||
| 
 | ||||
|      */ | ||||
|     Ok(String::from("unimplemented")) | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -40,4 +40,4 @@ Nächstes Plenum: Am 2024-08-13 um 20 Uhr | |||
| ---"#;
 | ||||
| 
 | ||||
| pub const PLENUM_TEMPLATE_URL: &str = "https://md.berlin.ccc.de/plenum-template/download"; | ||||
| pub const HEDGEDOC_SERVER_URL: &str = "https://md.berlin.ccc.de"; | ||||
| pub const HEDGEDOC_SERVER_URL: &str = "https://md.berlin.ccc.de"; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 murmeldin
							murmeldin