pub mod attachment; pub mod bug; pub mod comment; pub mod user; use crate::bugzilla::bug::*; // use crate::bugzilla::user::*; mod schema; use rusqlite::Connection; use serde::Deserialize; use serde::Serialize; use serde_json::Value; use std::collections::HashMap; use std::time::Duration; use ureq::Agent; // use ulid::Ulid; use crate::util::*; use std::io::Write; #[derive(Debug, Deserialize, Serialize)] pub struct BugsList { pub bugs: Vec, } #[derive(Debug)] pub struct BugzillaClient { token: String, client: ureq::Agent, } impl BugzillaClient { pub fn new(login: &str, password: &str) -> Result { let login_endpoint = "https://bugs.freebsd.org/bugzilla/rest/login"; let client: Agent = ureq::AgentBuilder::new() .timeout_read(Duration::from_secs(5)) .timeout_write(Duration::from_secs(5)) .build(); let mut params = HashMap::new(); params.insert("login", login); params.insert("password", password); let response: serde_json::Value = client .get(login_endpoint) .query_pairs(params) .call()? .into_json()?; match response { Value::Object(fields) => Ok(Self { token: fields["token"] .as_str() .expect("no token in login response") .to_string(), client, }), _ => Err("Bugzilla login failed".into()), } } /// Reads all bugs from bugzilla API and stores them in the sqlite database pub fn get_all_bugs(&self, sqlite: &Connection) { let bugs_endpoint = "https://bugs.freebsd.org/bugzilla/rest/bug"; let batch_size = 1000; let mut offset = 0; let mut total = 0; loop { // add this to only get open bugs - open bugs have no resolution // .query("f1", "resolution") // .query("o1", "isempty") let bugs: BugsList = self .client .get(bugs_endpoint) .query("token", &self.token) .query("limit", &batch_size.to_string()) .query("offset", &offset.to_string()) .set("Content-Type", "application/json") .set("Accept", "application/json") .call() .expect("search bugs API call failed") .into_json() .expect("invalid json was received from API"); let len = bugs.bugs.len(); sqlite.execute("BEGIN TRANSACTION", []).unwrap(); for bug in bugs.bugs.into_iter() { bug.insert(sqlite); } total += len; sqlite.execute("COMMIT TRANSACTION", []).unwrap(); print!("\rGetting bugzilla bugs: {}", total); std::io::stdout().flush().unwrap(); if len < batch_size { break; } else { offset += batch_size; } } println!(); } // pub fn get_bug_comments(&self, ids: Vec) -> HashMap> { // if let Ok(comments) = Self::get_comments_from_file("comments.json") { // println!("Read {} bugs from comments.json", comments.len()); // return comments; // } // let comment_endpoint = format!("https://bugs.freebsd.org/bugzilla/rest/bug/{}/comment", ids[0]); // let mut result:HashMap> = HashMap::new(); // let mut builder = self.client // .get(&comment_endpoint) // .query("token", self.token.as_str()) // .set("Content-Type", "application/json") // .set("Accept", "application/json"); // for id in ids.iter() { // builder = builder.query("ids", &id.to_string()); // } // let response: serde_json::Value = builder.call() // .expect("search bugs API call failed") // .into_json().expect("invalid json was received from API"); // // "bugs" : { // // "261732" : { // // "comments" : [ // let comment_map = response.get("bugs") // .unwrap() // .as_object() // .unwrap(); // for (strid, value) in comment_map.iter() { // let bug_id: u32 = strid.clone().parse::().unwrap(); // assert!(ids.contains(&bug_id)); // let mut comments: Vec = vec![]; // value.get("comments") // .unwrap() // .as_array().unwrap() // .into_iter() // .for_each(|v| { // let c: Comment = serde_json::from_value(v.clone()).unwrap(); // comments.push(c); // }); // result.insert(bug_id, comments); // } // result // } }