major improvements to plenum pad logic
- a lot of new comments for better doc - removed unnecessary functions - main plenum pad logic still in progress - one additional comment in main
This commit is contained in:
		
							parent
							
								
									aca180d6ba
								
							
						
					
					
						commit
						bbd9b2c29e
					
				
					 2 changed files with 96 additions and 54 deletions
				
			
		|  | @ -94,6 +94,8 @@ fn today() -> NaiveDate { | |||
| } | ||||
| /// Gets either the state from the config or overrides it with the state from
 | ||||
| /// the environment variable `STATE_OVERRIDE` (for testing purposes.)
 | ||||
| /// 
 | ||||
| /// For example, `STATE_OVERRIDE=Waiting` can be used to debug mediawiki.
 | ||||
| fn state(config: &KeyValueStore) -> ProgramState { | ||||
|     match env::var("STATE_OVERRIDE") { | ||||
|         Ok(val) => ProgramState::parse(&val), | ||||
|  |  | |||
							
								
								
									
										148
									
								
								src/mediawiki.rs
									
										
									
									
									
								
							
							
						
						
									
										148
									
								
								src/mediawiki.rs
									
										
									
									
									
								
							|  | @ -1,10 +1,10 @@ | |||
| use std::cell::OnceCell; | ||||
| use std::error::Error; | ||||
| 
 | ||||
| use chrono::{Datelike, Utc}; | ||||
| use colored::Colorize; | ||||
| use reqwest::blocking::Client; | ||||
| use serde::Deserialize; | ||||
| use serde_json::json; | ||||
| 
 | ||||
| use crate::{trace_var, verboseln}; | ||||
| use crate::config_spec::{CfgField, CfgGroup}; | ||||
|  | @ -149,11 +149,13 @@ impl Mediawiki { | |||
|                         .send() | ||||
|                 } | ||||
|                 ValidRequestTypes::Post | ValidRequestTypes::PostForEditing => { | ||||
|                     // convert the params into a HashMap for JSON
 | ||||
|                     let params_map: std::collections::HashMap<_, _> = params.iter().cloned().collect(); | ||||
|                     self | ||||
|                         .client | ||||
|                         .post(url) | ||||
|                         //.basic_auth(&self.http_user, Some(&self.http_password)) ZU TESTZWECKEN ENTFERNT
 | ||||
|                         .form(¶ms) | ||||
|                         .json(¶ms_map) | ||||
|                         .send() | ||||
|                 } | ||||
|             } | ||||
|  | @ -179,8 +181,9 @@ impl Mediawiki { | |||
|         }; | ||||
|         resp | ||||
|     } | ||||
| 
 | ||||
|     /// Creates a completely new wiki page with page_content and page_title as inputs
 | ||||
|     pub fn new_wiki_page (&self, page_title: &str, page_content: &str) -> Result<String, Box<dyn Error>> { | ||||
|     pub fn new_wiki_page (&self, page_title: &str, page_content: &str, update_main_page: bool) -> Result<String, Box<dyn Error>> { | ||||
|         // action=edit&format=json&title=Wikipedia:Sandbox&appendtext=Hello&token=sampleCsrfToken123+\
 | ||||
|         let url = | ||||
|             format!("{}/api.php?", self.server_url); | ||||
|  | @ -192,28 +195,72 @@ impl Mediawiki { | |||
|             ("token", self.csrf_token.get().unwrap()), // A "csrf" token retrieved from action=query&meta=tokens
 | ||||
|             ("bot", "true"), // Mark this edit as a bot edit.
 | ||||
|         ]); | ||||
| 
 | ||||
|         println!("Making request to {} with params: {:?}", url, params); | ||||
|         
 | ||||
|         let request_result = self.make_request(url, params, ValidRequestTypes::Post); | ||||
|         
 | ||||
|         self.update_plenum_page(page_title)?; | ||||
|         
 | ||||
| 
 | ||||
|         if update_main_page { | ||||
|             self.update_plenum_page(page_title)?; | ||||
|         } | ||||
|         request_result | ||||
|     } | ||||
|     /// Downloads the main Plenum Page from Mediawiki, inserts the Link to the new Page and replaces the content of the mediawiki-
 | ||||
|     /// This function is responsible for updating the main plenum page:
 | ||||
|     ///
 | ||||
|     /// It downloads the main plenum page from Mediawiki, inserts the
 | ||||
|     /// new Link to the newly uploaded plenum pad and uploads the
 | ||||
|     /// page back to mediawiki. 
 | ||||
|     pub fn update_plenum_page (&self, new_page_title_to_link_to: &str) -> Result<(), Box<dyn Error>> { | ||||
|         // 1. Download Plenum page content
 | ||||
|         // 1. Get the current year:
 | ||||
|         let current_year = Utc::now().year().to_string(); | ||||
|         let year_pattern = format!("=== {} ===", current_year); | ||||
| 
 | ||||
|         // 2. Download Plenum page content
 | ||||
|         let page_content = self.get_page_content(&self.plenum_main_page_name)?; | ||||
|         trace_var!(page_content); | ||||
|         let current_year = "2024"; // TODO: Datumslogik einbauen
 | ||||
|         let year_section = format!("=== {} ===\n", current_year); | ||||
|         if page_content.contains(&year_section) { | ||||
|             let mut content_split: Vec<&str> = page_content.split(&year_section).collect(); | ||||
|             println!("Length: {}", content_split.len()); | ||||
|             let rest_of_content = content_split.pop().unwrap_or_default(); | ||||
|             let updated_section = format!("{}{}\n* {}", content_split.join(&year_section), year_section, new_page_title_to_link_to); | ||||
|             //format!("{}{}", updated_section, rest_of_content)
 | ||||
|         //trace_var!(page_content);
 | ||||
| 
 | ||||
|         // 3. Check if the current year exists
 | ||||
|         let mut updated_section = String::new(); | ||||
|         if page_content.contains(&year_pattern) { | ||||
|             // 4. Year Heading exists, inserting new link below
 | ||||
|             let mut content_split: Vec<&str> = page_content.split(&year_pattern).collect(); | ||||
|             let site_content_below_year_heading = content_split.pop().unwrap_or_default(); | ||||
|             let site_content_above_year_heading = content_split.pop().unwrap_or_default(); | ||||
|             updated_section = format!( | ||||
|                 "{}{}\n* [[{}]]{}", | ||||
|                 site_content_above_year_heading, | ||||
|                 year_pattern, | ||||
|                 new_page_title_to_link_to, | ||||
|                 site_content_below_year_heading); | ||||
|                 verboseln!("updated page: {}", updated_section) | ||||
|         } else { | ||||
|             // Scenario: New year: Generating new heading for the current year
 | ||||
|             // 4. First checking if the last year exists:
 | ||||
|             let last_year = current_year.parse::<i32>()? - 1; // returns e.g. 2023 when given 2024
 | ||||
|             let last_year_pattern = format!("=== {} ===", last_year); | ||||
|             if page_content.contains(&last_year_pattern) { | ||||
|                 // 2. Secondly, generate a new heading for this year above last year's
 | ||||
|                 verboseln!("new year, adding this year's heading"); | ||||
|                 let mut content_split: Vec<&str> = page_content.split(&last_year_pattern).collect(); | ||||
|                 let site_content_below_year_heading = content_split.pop().unwrap_or_default(); | ||||
|                 let site_content_above_year_heading = content_split.pop().unwrap_or_default(); | ||||
|                 updated_section = format!( | ||||
|                     "{}{}\n* [[{}]]\n\n{}{}", | ||||
|                     site_content_above_year_heading, | ||||
|                     year_pattern, | ||||
|                     new_page_title_to_link_to, | ||||
|                     last_year_pattern, | ||||
|                     site_content_below_year_heading); | ||||
|             } else { | ||||
|                 println!("There is neither a {}, nor a {} heading on the main plenum Page!", current_year, last_year); | ||||
|                 panic!("The Plenum Main Page seems seriously damaged, aborting...") | ||||
|             } | ||||
|         } | ||||
|         // uploading the pad again
 | ||||
|         self.new_wiki_page(&self.plenum_main_page_name, &updated_section, false)?; // nicht auf true setzen, sonst entsteht eine Endlosschleife
 | ||||
|         Ok(()) | ||||
|     } | ||||
|     /// This function downloads and returns the contents of a wiki page when given the page's title (e.g. `page_title = Plenum/13._August_2024`)
 | ||||
|     pub fn get_page_content (&self, page_title: &str) -> Result<String, Box<dyn Error>> { | ||||
|         let url = | ||||
|             format!("{}/api.php?", self.server_url); | ||||
|  | @ -225,41 +272,20 @@ impl Mediawiki { | |||
|             ("formatversion", "2"), | ||||
|         ]); | ||||
|         let resp = self.make_request(url, params, ValidRequestTypes::Get)?; | ||||
|         let resp = json!(resp); | ||||
|         Ok(resp["parse"]["wikitext"].to_string()) | ||||
|     } | ||||
|     pub fn get_page_section_title (&self, page_title: &str, section_number: &str) -> Result<String, Box<dyn Error>> { | ||||
|         let url = | ||||
|             format!("{}/api.php?", self.server_url); | ||||
|         let params: Box<[(&str, &str)]> = Box::from([ | ||||
|             ("action", "parse"), // Create and edit pages.
 | ||||
|             ("contentmodel", "wikitext"), | ||||
|             ("format", "json"), | ||||
|             ("page", page_title), | ||||
|         ]); | ||||
|         let resp = self.make_request(url, params, ValidRequestTypes::Get)?; | ||||
|         todo!() | ||||
|         //let response_deserialized = serde_json::from_str(&resp)?;
 | ||||
|         //Ok(response_deserialized["parse"])
 | ||||
|     } | ||||
|     pub fn edit_section (&self, page_title: &str, text_to_prepend: &str, section_number: &str) -> Result<String, Box<dyn Error>> { | ||||
|         let url = | ||||
|             format!("{}/api.php?", self.server_url); | ||||
|         let params: Box<[(&str, &str)]> = Box::from([ | ||||
|             ("action", "edit"), // Create and edit pages.
 | ||||
|             ("format", "json"), | ||||
|             ("title", page_title), // Title of the page to edit. Cannot be used together with pageid.
 | ||||
|             ("section", section_number), // Section identifier. 0 for the top section, new for a new section. Often a positive integer, but can also be non-numeric
 | ||||
|             ("prependtext", text_to_prepend), // Add this text to the end of the page or section. Overrides text.
 | ||||
|             ("token", self.csrf_token.get().unwrap()), // A "csrf" token retrieved from action=query&meta=tokens
 | ||||
|             ("bot", "true"), // Mark this edit as a bot edit.
 | ||||
|         ]); | ||||
|         let request_result = self.make_request(url, params, ValidRequestTypes::Post); | ||||
|         let response_deserialized: serde_json::Value = serde_json::from_str(&resp)?; | ||||
| 
 | ||||
|         request_result | ||||
|         let resp = response_deserialized | ||||
|             .get("parse") | ||||
|             .and_then(|parse | parse.get("wikitext")) | ||||
|             .ok_or("Expected field `wikitext` not found, likely no access to main plenum page")?; | ||||
|         Ok(resp.to_string()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// This function runs at the end of do_protocol() and is responsible for
 | ||||
| /// logging in to mediawiki, retrieving the necessary tokens, creating a
 | ||||
| /// new wiki page for the current plenum protocol, and for linking the new
 | ||||
| /// page to the main plenum overview page.
 | ||||
| pub fn pad_ins_wiki(old_pad_content: String, wiki: &Mediawiki) -> Result<(), Box<dyn Error>> { | ||||
|     // Login to Wiki and get required tokens for logging in and writing
 | ||||
|     wiki.get_login_token()?; | ||||
|  | @ -273,14 +299,25 @@ pub fn pad_ins_wiki(old_pad_content: String, wiki: &Mediawiki) -> Result<(), Box | |||
|     // Convert to mediawiki and make new page
 | ||||
|     let pad_converted = pandoc_convert(old_pad_content)?; | ||||
|     trace_var!(pad_converted); | ||||
|     let page_title = "Page Test 5"; | ||||
|     let page_title = format!("{}/{}", wiki.plenum_main_page_name, page_title); // Example: Plenum/13._August_2024
 | ||||
|     wiki.new_wiki_page(&page_title, &pad_converted)?; | ||||
|     
 | ||||
|     // Create a new wiki page plenum_main_page_name/page_title, e.g. under Plenum/13._August_2024
 | ||||
|     // and past the converted pad there
 | ||||
|     verboseln!("wiki: uploading converted pad"); | ||||
|     // let page_title = "14._August_2024";
 | ||||
|     let page_title = "14._AUGUST_2024"; | ||||
|     let page_title = format!("{}/{}", wiki.plenum_main_page_name, page_title); | ||||
|     wiki.new_wiki_page(&page_title, &pad_converted, true)?; | ||||
| 
 | ||||
|     // Download the main plenum page and insert the new page_title as a link
 | ||||
|     verboseln!("wiki: updating main plenum page"); | ||||
| 
 | ||||
|     wiki.update_plenum_page(&page_title)?; | ||||
|     verboseln!("Finished successfully with wiki"); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| /// Takes a String in the Markdown format and returns a String in the mediawiki Format
 | ||||
| /// Takes a String in the Markdown format, converts it and returns it in
 | ||||
| /// the Mediawiki format
 | ||||
| fn pandoc_convert(markdown: String) -> Result<String, Box<dyn Error>> { | ||||
|     let (output, errors, status) = crate::pipe( | ||||
|         "pandoc", | ||||
|  | @ -288,6 +325,7 @@ fn pandoc_convert(markdown: String) -> Result<String, Box<dyn Error>> { | |||
|         markdown, | ||||
|     )?; | ||||
|     if status.success() { | ||||
|         println!("Resultat von Pandoc: {}", output); | ||||
|         Ok(output) | ||||
|     } else { | ||||
|         Err(format!("Pandoc error, exit code {:?}\n{}", status, errors).into()) | ||||
|  | @ -302,8 +340,10 @@ fn create_title (nächster_plenumstermin: String) { | |||
| 
 | ||||
|  */ | ||||
| 
 | ||||
| // This has to be defined that way, because both in the login and csrf token,
 | ||||
| // the response contains two \\ characters which break the usual deserialization  
 | ||||
| /// Deserialization must be done this way because the response contains
 | ||||
| /// two `\\` characters in both the login and csrf tokens, which breaks the
 | ||||
| /// usual deserialization
 | ||||
| 
 | ||||
| #[derive(Deserialize)] | ||||
| struct QueryResponseLogin { | ||||
|     #[allow(dead_code)] | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 murmeldin
						murmeldin