From 8fc4766197491d91cf0854c859152dbec3af1e87 Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Sun, 21 Apr 2024 09:51:48 -0400 Subject: [PATCH] fix: remove duplicate options stored on the app struct --- src/app.rs | 127 ++++++------------------ src/request/curl.rs | 16 ++- src/screens/input/input_screen.rs | 14 +-- src/screens/input/request_body_input.rs | 22 ++-- src/screens/render.rs | 4 +- src/screens/request.rs | 6 +- 6 files changed, 66 insertions(+), 123 deletions(-) diff --git a/src/app.rs b/src/app.rs index 16babde..c261732 100644 --- a/src/app.rs +++ b/src/app.rs @@ -35,8 +35,6 @@ pub struct App<'a> { pub selected: Option, /// command (curl or wget) pub command: Curl, - /// vec of applicable options - pub opts: Vec, /// Input struct for tui_input dependency pub input: Input, /// vec for user input to push into @@ -64,7 +62,6 @@ impl<'a> Default for App<'a> { command: Curl::default(), input_mode: InputMode::Normal, messages: Vec::new(), - opts: Vec::new(), items: Screen::Home.get_opts(None), input: Input::default(), state: None, @@ -214,7 +211,7 @@ impl<'a> App<'a> { } pub fn get_request_body(&self) -> Option { - self.opts.iter().find_map(|opt| match opt { + self.command.opts.iter().find_map(|opt| match opt { AppOptions::RequestBody(body) => Some(body.clone()), _ => None, }) @@ -325,9 +322,7 @@ impl<'a> App<'a> { } pub fn execute_command(&mut self) -> Result<(), String> { - let opts = &self.opts; - self.command - .execute(Some(Box::new(self.db.deref_mut())), opts.as_slice()) + self.command.execute(Some(Box::new(self.db.deref_mut()))) } pub fn import_postman_collection( @@ -352,9 +347,8 @@ impl<'a> App<'a> { let mut command: Curl = serde_json::from_str(json) .map_err(|e| e.to_string()) .unwrap(); - let opts = &self.opts; - command.easy_from_opts(opts.as_slice()); - match command.execute(None, opts.as_slice()) { + command.easy_from_opts(); + match command.execute(None) { Ok(_) => self.set_response(&command.get_response().unwrap_or("".to_string())), Err(e) => self.set_response(&e), }; @@ -390,18 +384,20 @@ impl<'a> App<'a> { pub fn remove_app_option(&mut self, opt: &AppOptions) { self.command.remove_option(opt); - self.opts + self.command + .opts .retain(|x| mem::discriminant(x) != mem::discriminant(opt)); } pub fn clear_all_options(&mut self) { - self.opts.clear(); + self.command.opts.clear(); self.messages.clear(); self.response = None; } fn has_app_option(&self, opt: &AppOptions) -> bool { - self.opts + self.command + .opts .iter() .any(|x| mem::discriminant(x) == mem::discriminant(opt)) } @@ -425,7 +421,7 @@ impl<'a> App<'a> { return; } if opt.should_toggle() { - self.opts.push(opt.clone()); + self.command.opts.push(opt.clone()); self.command.add_option(&opt); } self.redraw(); @@ -437,87 +433,21 @@ impl<'a> App<'a> { return; } if self.should_add_option(&opt) { - self.opts.push(opt.clone()); + self.command.opts.push(opt.clone()); self.command.add_option(&opt); } else { - self.handle_replace(opt.clone()); + self.handle_replace(&opt); } self.selected = None; } - fn handle_replace(&mut self, mut opt: AppOptions) { - for option in self.opts.iter_mut() { - match option { - AppOptions::URL(_) => { - if let AppOptions::URL(ref url) = opt { - self.command.set_url(url); - option.replace_value(url.clone()); - } - } - AppOptions::Outfile(_) => { - if let AppOptions::Outfile(ref outfile) = opt { - option.replace_value(outfile.clone()); - self.command.set_outfile(outfile); - } - } - AppOptions::Response(_) => { - if let AppOptions::Response(ref response) = opt { - option.replace_value(opt.clone().get_value()); - self.command.set_response(response); - } - } - AppOptions::Auth(_) => {} // This is handled by the screen - AppOptions::UserAgent(_) => { - if let AppOptions::UserAgent(ref agent) = opt { - option.replace_value(String::from(agent)); - self.command.set_user_agent(agent); - } - } - AppOptions::Referrer(_) => { - if let AppOptions::Referrer(ref referrer) = opt { - option.replace_value(String::from(referrer)); - self.command.set_referrer(referrer); - } - } - AppOptions::CookiePath(_) => { - if let AppOptions::CookiePath(ref mut cookie) = opt { - option.replace_value(cookie.clone()); - self.command.add_cookie(cookie); - } - } - AppOptions::CookieJar(_) => { - if let AppOptions::CookieJar(ref mut cookie) = opt { - option.replace_value(cookie.clone()); - self.command.set_cookie_jar(cookie); - } - } - AppOptions::CaPath(_) => { - if let AppOptions::CaPath(ref ca_path) = opt { - option.replace_value(String::from(ca_path)); - self.command.set_ca_path(ca_path); - } - } - AppOptions::MaxRedirects(_) => { - if let AppOptions::MaxRedirects(ref max_redirects) = opt { - option.replace_value(max_redirects.to_string()); - self.command.set_max_redirects(*max_redirects); - } - } - AppOptions::UnixSocket(_) => { - if let AppOptions::UnixSocket(ref mut socket) = opt { - option.replace_value(socket.clone()); - self.command.set_unix_socket(socket); - } - } - AppOptions::RequestBody(_) => { - if let AppOptions::RequestBody(ref mut body) = opt { - option.replace_value(body.clone()); - self.command.set_request_body(body); - } - } - _ => {} - } - } + fn handle_replace(&mut self, opt: &AppOptions) { + self.command + .opts + .retain(|option| std::mem::discriminant(option) != std::mem::discriminant(opt)); + self.command.remove_option(opt); + self.command.add_option(opt); + self.command.opts.push(opt.clone()); } } #[cfg(test)] @@ -567,7 +497,7 @@ pub mod tests { "hello world".to_string(), )); app.add_app_option(crate::display::AppOptions::Headers( - "Content-Type: Application/json".to_string(), + "Content-Type: application/json".to_string(), )); app.command.set_request_body("hello world"); app.command.set_method(crate::request::curl::Method::Put); @@ -582,7 +512,8 @@ pub mod tests { .match_header("Content-Type", "application/json") .assert(); assert_eq!( - app.opts + app.command + .opts .iter() .find(|x| x == &&crate::display::AppOptions::ContentHeaders( @@ -590,7 +521,7 @@ pub mod tests { )) .unwrap() .get_curl_flag_value(), - "-H \"Content-Type: Application/json\"" + "-H \"Content-Type: application/json\"" ); } #[test] @@ -670,7 +601,8 @@ pub mod tests { token.to_string(), ))); assert_eq!( - app.opts + app.command + .opts .iter() .find(|x| x == &&crate::display::AppOptions::Auth(AuthKind::Bearer(token.to_string()))) @@ -689,7 +621,8 @@ pub mod tests { user, pass )))); assert_eq!( - app.opts + app.command + .opts .iter() .find(|x| x == &&crate::display::AppOptions::Auth(AuthKind::Basic(format!( @@ -711,7 +644,8 @@ pub mod tests { user, pass )))); assert_eq!( - app.opts + app.command + .opts .iter() .find(|x| x == &&crate::display::AppOptions::Auth(AuthKind::Digest(format!( @@ -728,7 +662,8 @@ pub mod tests { let mut app = App::default(); app.add_app_option(crate::display::AppOptions::Auth(AuthKind::Ntlm)); assert_eq!( - app.opts + app.command + .opts .iter() .find(|x| x == &&crate::display::AppOptions::Auth(AuthKind::Ntlm)) .unwrap() diff --git a/src/request/curl.rs b/src/request/curl.rs index 288a789..d14f7e5 100644 --- a/src/request/curl.rs +++ b/src/request/curl.rs @@ -45,7 +45,7 @@ pub struct Curl { headers: Option>, url: String, // Build this on the App struct and pass it here to store for serialization - opts: Vec, + pub opts: Vec, resp: Option, upload_file: Option, outfile: Option, @@ -308,9 +308,8 @@ impl Curl { } #[rustfmt::skip] - pub fn execute(&mut self, mut db: Option>, opts: &[AppOptions]) -> Result<(), String> { + pub fn execute(&mut self, mut db: Option>) -> Result<(), String> { let mut list = List::new(); - self.opts = opts.to_vec(); curl::init(); // we do this again because if it's a patch | put and there's a // body, it will default to post @@ -555,15 +554,12 @@ impl Curl { self.save.1 } - // This is a hack because when we deseialize json from the DB, we get a curl struct with no curl::Easy - // field, so we have to manually add, then set the options one at a time from the opts vector. - // ANY time we get a command from the database to run, we have to call this method first. - pub fn easy_from_opts(&mut self, opts: &[AppOptions]) { + pub fn easy_from_opts(&mut self) { self.build_command_string(); - let url = self.url.clone(); - self.set_url(&url); + self.curl.url(&self.url).unwrap(); self.apply_method(); - for opt in opts { + let opts = self.opts.clone(); + for opt in opts.iter() { self.add_option(opt); } } diff --git a/src/screens/input/input_screen.rs b/src/screens/input/input_screen.rs index 3858e83..676c02f 100644 --- a/src/screens/input/input_screen.rs +++ b/src/screens/input/input_screen.rs @@ -111,7 +111,7 @@ pub fn handle_default_input_screen(app: &mut App, frame: &mut Frame<'_>, opt: In String::from("Error: You have already entered a URL"), )))); } - let socket = app.opts.iter().find_map(|f| { + let socket = app.command.opts.iter().find_map(|f| { if let AppOptions::UnixSocket(s) = f { Some(s) } else { @@ -126,7 +126,7 @@ pub fn handle_default_input_screen(app: &mut App, frame: &mut Frame<'_>, opt: In } } InputOpt::CookiePath => { - if let Some(cookie) = app.opts.iter().find_map(|f| { + if let Some(cookie) = app.command.opts.iter().find_map(|f| { if let AppOptions::CookiePath(s) = f { Some(s) } else { @@ -142,7 +142,7 @@ pub fn handle_default_input_screen(app: &mut App, frame: &mut Frame<'_>, opt: In } } InputOpt::CookieJar => { - if let Some(cookie) = app.opts.iter().find_map(|f| { + if let Some(cookie) = app.command.opts.iter().find_map(|f| { if let AppOptions::CookieJar(s) = f { Some(s) } else { @@ -361,7 +361,7 @@ pub fn parse_input(message: String, opt: InputOpt, app: &mut App) { } } -pub fn render_input_with_prompt(frame: &mut Frame<'_>, prompt: Text) { +pub fn render_input_with_prompt<'a, T: Into>>(frame: &mut Frame<'_>, prompt: T) { // Render the input with the provided prompt let chunks = Layout::default() .direction(Direction::Vertical) @@ -397,9 +397,11 @@ fn parse_auth(auth: AuthKind, app: &mut App, message: &str) { _ => AuthKind::None, }); if app.command.has_auth() { - app.opts.retain(|x| !matches!(x, AppOptions::Auth(_))); + app.command + .opts + .retain(|x| !matches!(x, AppOptions::Auth(_))); } - app.opts.push(AppOptions::Auth(match auth { + app.command.opts.push(AppOptions::Auth(match auth { AuthKind::Basic(_) => AuthKind::Basic(String::from(message)), AuthKind::Bearer(_) => AuthKind::Bearer(String::from(message)), AuthKind::Digest(_) => AuthKind::Digest(String::from(message)), diff --git a/src/screens/input/request_body_input.rs b/src/screens/input/request_body_input.rs index b346b27..3bbf350 100644 --- a/src/screens/input/request_body_input.rs +++ b/src/screens/input/request_body_input.rs @@ -2,7 +2,8 @@ use crate::app::{App, InputMode}; use crate::display::inputopt::InputOpt; use crate::display::AppOptions; use crate::screens::{centered_rect, Screen, ScreenArea}; -use tui::text::{Line, Text}; +use tui::style::Styled; +use tui::text::Line; use tui::widgets::{Block, Borders, Paragraph}; use tui::{ prelude::{Constraint, Direction, Layout}, @@ -11,8 +12,6 @@ use tui::{ Frame, }; -use super::input_screen::render_input_with_prompt; - pub fn handle_req_body_input_screen(app: &mut App, frame: &mut Frame<'_>, _opt: InputOpt) { let chunks = Layout::default() .direction(Direction::Vertical) @@ -45,9 +44,15 @@ pub fn handle_req_body_input_screen(app: &mut App, frame: &mut Frame<'_>, _opt: Style::default(), ), }; - let prompt = Text::from( - "Enter your Request body,\nOr the file path to the body\na .json filepath will automatically add Content-Type Header\nthen press Enter to submit\n", - ); + let prompt = vec![ + Line::raw("Enter your Request body Or the path to a file containing the body."), + Line::raw(" "), + Line::raw("Example: {\"key\", \"value\"} (no outside quotes needed)\n"), + Line::raw(" "), + Line::raw("a .json filepath will automatically add Content-Type Header"), + Line::raw(" "), + Line::raw("then press Enter to submit"), + ]; if !app.command.method.needs_reset() { app.goto_screen(&Screen::RequestMenu(Some(InputOpt::RequestError( String::from("Error: Request Bodies are not allowed for this HTTP method"), @@ -55,9 +60,9 @@ pub fn handle_req_body_input_screen(app: &mut App, frame: &mut Frame<'_>, _opt: } let msg = Paragraph::new(Line::from(msg)); - let prompt = prompt.patch_style(style); + let prompt = Paragraph::new(prompt).set_style(style); frame.render_widget(msg, centered_rect(frame.size(), ScreenArea::Top)); - render_input_with_prompt(frame, prompt); + frame.render_widget(&prompt, chunks[0]); let width = chunks[0].width.max(3) - 3; let scroll = app.input.visual_scroll(width as usize); @@ -97,6 +102,7 @@ pub fn handle_req_body_input_screen(app: &mut App, frame: &mut Frame<'_>, _opt: )); app.goto_screen(&Screen::RequestMenu(None)); app.messages.clear(); + return; } app.add_app_option(AppOptions::RequestBody(app.messages[0].clone())); app.goto_screen(&Screen::RequestMenu(None)); diff --git a/src/screens/render.rs b/src/screens/render.rs index ca0231b..ecb23ea 100644 --- a/src/screens/render.rs +++ b/src/screens/render.rs @@ -45,8 +45,8 @@ pub fn render(app: &mut App, frame: &mut Frame<'_>) { frame.render_widget(logo, centered_rect(frame.size(), ScreenArea::Bottom)); } let area = centered_rect(frame.size(), ScreenArea::Bottom); - let opts = app.opts.clone(); - let display_opts = handle_display_options(&opts); + let opts = &app.command.opts; + let display_opts = handle_display_options(opts); frame.render_widget( Paragraph::new(display_opts) .block( diff --git a/src/screens/request.rs b/src/screens/request.rs index c1cc394..54ab3b6 100644 --- a/src/screens/request.rs +++ b/src/screens/request.rs @@ -49,7 +49,11 @@ pub fn handle_request_menu_screen(app: &mut App, frame: &mut Frame<'_>, opt: Opt // Execute command Some(9) => { if app.command.get_url().is_empty() - && !app.opts.iter().any(|x| *x == AppOptions::SaveCommand) + && !app + .command + .opts + .iter() + .any(|x| *x == AppOptions::SaveCommand) { app.goto_screen(&Screen::RequestMenu(Some(InputOpt::RequestError( String::from(VALID_COMMAND_ERROR),