Skip to content
This repository has been archived by the owner on Oct 8, 2024. It is now read-only.

Commit

Permalink
feat: implement postman collections importation
Browse files Browse the repository at this point in the history
  • Loading branch information
PThorpe92 committed Mar 27, 2024
1 parent d14fbba commit 1bd55b8
Show file tree
Hide file tree
Showing 25 changed files with 670 additions and 889 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/target
.vs
testapi.txt
/postman
*.json
101 changes: 69 additions & 32 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::database::db::{SavedCommand, SavedKey, DB};
use crate::database::db::{SavedCollection, SavedCommand, SavedKey, DB};
use crate::display::menuopts::OPTION_PADDING_MID;
use crate::display::{AppOptions, HeaderKind};
use crate::request::command::{Cmd, CMD};
use crate::request::curl::{AuthKind, Curl};
use crate::screens::screen::Screen;
use crate::Config;
use arboard::Clipboard;
use std::io::Write;
use std::ops::DerefMut;
use std::{error, mem};
use tui::widgets::{ListItem, ListState};
Expand Down Expand Up @@ -33,7 +33,7 @@ pub struct App<'a> {
/// index of selected item
pub selected: Option<usize>,
/// command (curl or wget)
pub command: Box<Cmd<'a>>,
pub command: Curl<'a>,
/// vec of applicable options
pub opts: Vec<AppOptions>,
/// Input struct for tui_input dependency
Expand All @@ -60,7 +60,7 @@ impl<'a> Default for App<'a> {
cursor: 0,
screen_stack: vec![Screen::Home],
selected: None,
command: Box::<Cmd<'a>>::default(),
command: Curl::default(),
input_mode: InputMode::Normal,
messages: Vec::new(),
opts: Vec::new(),
Expand All @@ -78,7 +78,7 @@ impl<'a> App<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn set_command(&mut self, command: Box<Cmd<'a>>) {
pub fn set_command(&mut self, command: Curl<'a>) {
self.command = command;
}
pub fn set_config(&mut self, config: Config) {
Expand Down Expand Up @@ -147,9 +147,9 @@ impl<'a> App<'a> {
self.selected = None;
return;
}
Screen::SavedCommands => {
Screen::SavedCommands(col_name) => {
self.items = self
.get_saved_commands()
.get_saved_commands(col_name)
.unwrap_or_default()
.iter()
.map(|cmd| {
Expand All @@ -159,6 +159,14 @@ impl<'a> App<'a> {
self.selected = None;
return;
}
Screen::ViewSavedCollections => {
self.items = self
.get_collections()
.unwrap_or_default()
.iter()
.map(|col| ListItem::new(format!("{}{}", col.name, OPTION_PADDING_MID)))
.collect();
}
_ => {
self.items = screen.get_opts(None);
}
Expand All @@ -169,31 +177,32 @@ impl<'a> App<'a> {
pub fn go_back_screen(&mut self) {
let last = self.screen_stack.pop().unwrap_or_default(); // current screen
match self.screen_stack.last() {
Some(Screen::InputMenu(_) | Screen::CmdMenu(_) | Screen::KeysMenu(_)) => {
self.go_back_screen()
}
Some(Screen::RequestBodyInput) => self.goto_screen(Screen::Method),
// is that recursion in prod????? o_0
Some(screen) if screen == &last => self.go_back_screen(),
Some(
Screen::InputMenu(_)
| Screen::CmdMenu(_)
| Screen::ColMenu(_)
| Screen::KeysMenu(_),
) => self.go_back_screen(),
Some(Screen::RequestBodyInput) => self.goto_screen(Screen::Method),
Some(Screen::RequestMenu(_)) => {
// This is to remove errors from the stack
self.goto_screen(Screen::RequestMenu(String::new()));
}
Some(screen) => {
self.goto_screen(screen.clone());
}
None => self.goto_screen(Screen::Home),
_ => self.goto_screen(Screen::Home),
}
}

pub fn quit(&mut self) {
if let Some(resp) = self.response.as_ref() {
let _ = std::process::Command::new("echo")
.arg(resp)
.spawn()
.map_err(|e| e.to_string())
.unwrap();
}
std::io::stdout()
.write_all(self.get_response().as_bytes())
.unwrap();
// make sure the response is flushed to stdout
std::io::stdout().flush().unwrap();
self.running = false;
}

Expand Down Expand Up @@ -245,20 +254,45 @@ impl<'a> App<'a> {
self.db.as_ref().get_keys()
}

pub fn get_collections(&self) -> Result<Vec<SavedCollection>, rusqlite::Error> {
self.db.get_collections()
}

pub fn add_saved_key(&mut self, key: String) -> Result<(), rusqlite::Error> {
match self.db.as_ref().add_key(&key) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}

pub fn get_saved_commands(&self) -> Result<Vec<SavedCommand>, rusqlite::Error> {
self.db.as_ref().get_commands()
pub fn get_saved_commands(
&self,
col_name: Option<i32>,
) -> Result<Vec<SavedCommand>, rusqlite::Error> {
self.db.as_ref().get_commands(col_name)
}

pub fn create_postman_collection(&mut self, name: &str) -> Result<(), rusqlite::Error> {
self.db.create_collection(name)
}

#[rustfmt::skip]
pub fn import_postman_collection(&mut self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
let file = std::fs::File::open(path)?;
let collection: Result<crate::database::postman::PostmanCollection, String> =
serde_json::from_reader(file).map_err(|e| e.to_string());
if let Ok(collection) = collection {
let name = collection.info.name.clone();
let cmds: Vec<SavedCommand> = collection.into();
self.db.add_collection(&name, cmds.as_slice())
} else {
Err("Failed to import collection".into())
}
}

// Takes an array index of the selected item
pub fn execute_saved_command(&mut self, index: usize) {
if let Ok(saved_commands) = self.get_saved_commands() {
if let Ok(saved_commands) = self.get_saved_commands(None) {
match saved_commands.get(index) {
Some(cmd) => {
let mut command: Curl = serde_json::from_str(cmd.get_curl_json())
Expand Down Expand Up @@ -310,7 +344,7 @@ impl<'a> App<'a> {

pub fn delete_saved_command(&mut self, ind: i32) -> Result<(), rusqlite::Error> {
self.db.delete_command(ind)?;
self.goto_screen(Screen::SavedCommands);
self.goto_screen(Screen::SavedCommands(None));
Ok(())
}

Expand All @@ -332,6 +366,18 @@ impl<'a> App<'a> {
Ok(())
}

pub fn delete_collection(&mut self, id: i32) -> Result<(), rusqlite::Error> {
self.db.delete_collection(id)?;
self.goto_screen(Screen::SavedCommands(None));
Ok(())
}

pub fn rename_collection(&mut self, id: i32, name: &str) -> Result<(), rusqlite::Error> {
self.db.rename_collection(id, name)?;
self.goto_screen(Screen::SavedCollections);
Ok(())
}

pub fn delete_item(&mut self, ind: i32) -> Result<(), rusqlite::Error> {
match self.current_screen {
Screen::CmdMenu(_) => self.delete_saved_command(ind),
Expand Down Expand Up @@ -365,7 +411,6 @@ impl<'a> App<'a> {
AppOptions::MaxRedirects(_) => self.command.set_max_redirects(0),
AppOptions::UserAgent(_) => self.command.set_user_agent(""),
AppOptions::Referrer(_) => self.command.set_referrer(""),
AppOptions::RecDownload(_) => self.command.set_rec_download_level(0),
AppOptions::RequestBody(_) => self.command.set_request_body(""),
AppOptions::Cookie(_) => self.command.remove_headers(&opt.get_value()),
AppOptions::Headers(_) => self.command.remove_headers(&opt.get_value()),
Expand Down Expand Up @@ -487,8 +532,6 @@ impl<'a> App<'a> {

AppOptions::Cookie(cookie) => self.command.add_cookie(&cookie),

AppOptions::RecDownload(i) => self.command.set_rec_download_level(i),

AppOptions::Response(resp) => self.command.set_response(&resp),

AppOptions::Referrer(referrer) => self.command.set_referrer(&referrer),
Expand Down Expand Up @@ -531,12 +574,6 @@ impl<'a> App<'a> {
self.command.set_response(response);
}
}
AppOptions::RecDownload(_) => {
if let AppOptions::RecDownload(level) = opt {
option.replace_value(level.to_string());
self.command.set_rec_download_level(level);
}
}
AppOptions::Auth(_) => {} // This is handled by the screen
AppOptions::UserAgent(_) => {
if let AppOptions::UserAgent(ref agent) = opt {
Expand Down
Loading

0 comments on commit 1bd55b8

Please sign in to comment.