client: print only json for show-db/show-user --json
All checks were successful
All checks were successful
This commit is contained in:
@@ -1,14 +1,16 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use clap_complete::ArgValueCompleter;
|
use clap_complete::ArgValueCompleter;
|
||||||
use futures_util::SinkExt;
|
use futures_util::SinkExt;
|
||||||
use prettytable::{Cell, Row, Table};
|
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::commands::erroneous_server_response,
|
client::commands::erroneous_server_response,
|
||||||
core::{
|
core::{
|
||||||
completion::mysql_database_completer,
|
completion::mysql_database_completer,
|
||||||
protocol::{ClientToServerMessageStream, Request, Response},
|
protocol::{
|
||||||
|
ClientToServerMessageStream, Request, Response, print_list_databases_output_status,
|
||||||
|
print_list_databases_output_status_json,
|
||||||
|
},
|
||||||
types::MySQLDatabase,
|
types::MySQLDatabase,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -40,25 +42,13 @@ pub async fn show_databases(
|
|||||||
|
|
||||||
server_connection.send(message).await?;
|
server_connection.send(message).await?;
|
||||||
|
|
||||||
// TODO: collect errors for json output.
|
let databases = match server_connection.next().await {
|
||||||
|
Some(Ok(Response::ListDatabases(databases))) => databases,
|
||||||
let mut contained_errors = false;
|
|
||||||
let database_list = match server_connection.next().await {
|
|
||||||
Some(Ok(Response::ListDatabases(databases))) => databases
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(database_name, result)| match result {
|
|
||||||
Ok(database_row) => Some(database_row),
|
|
||||||
Err(err) => {
|
|
||||||
contained_errors = true;
|
|
||||||
eprintln!("{}", err.to_error_message(&database_name));
|
|
||||||
eprintln!("Skipping...");
|
|
||||||
println!();
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
Some(Ok(Response::ListAllDatabases(database_list))) => match database_list {
|
Some(Ok(Response::ListAllDatabases(database_list))) => match database_list {
|
||||||
Ok(list) => list,
|
Ok(list) => list
|
||||||
|
.into_iter()
|
||||||
|
.map(|db| (db.database.clone(), Ok(db)))
|
||||||
|
.collect(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
server_connection.send(Request::Exit).await?;
|
server_connection.send(Request::Exit).await?;
|
||||||
return Err(
|
return Err(
|
||||||
@@ -72,19 +62,12 @@ pub async fn show_databases(
|
|||||||
server_connection.send(Request::Exit).await?;
|
server_connection.send(Request::Exit).await?;
|
||||||
|
|
||||||
if args.json {
|
if args.json {
|
||||||
println!("{}", serde_json::to_string_pretty(&database_list)?);
|
print_list_databases_output_status_json(&databases);
|
||||||
} else if database_list.is_empty() {
|
|
||||||
println!("No databases to show.");
|
|
||||||
} else {
|
} else {
|
||||||
let mut table = Table::new();
|
print_list_databases_output_status(&databases);
|
||||||
table.add_row(Row::new(vec![Cell::new("Database")]));
|
|
||||||
for db in database_list {
|
|
||||||
table.add_row(row![db.database]);
|
|
||||||
}
|
|
||||||
table.printstd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.fail && contained_errors {
|
if args.fail && databases.values().any(|res| res.is_err()) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use anyhow::Context;
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use clap_complete::ArgValueCompleter;
|
use clap_complete::ArgValueCompleter;
|
||||||
use futures_util::SinkExt;
|
use futures_util::SinkExt;
|
||||||
@@ -8,7 +7,10 @@ use crate::{
|
|||||||
client::commands::erroneous_server_response,
|
client::commands::erroneous_server_response,
|
||||||
core::{
|
core::{
|
||||||
completion::mysql_user_completer,
|
completion::mysql_user_completer,
|
||||||
protocol::{ClientToServerMessageStream, Request, Response},
|
protocol::{
|
||||||
|
ClientToServerMessageStream, Request, Response, print_list_users_output_status,
|
||||||
|
print_list_users_output_status_json,
|
||||||
|
},
|
||||||
types::MySQLUser,
|
types::MySQLUser,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -43,22 +45,13 @@ pub async fn show_users(
|
|||||||
anyhow::bail!(err);
|
anyhow::bail!(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut contained_errors = false;
|
|
||||||
let users = match server_connection.next().await {
|
let users = match server_connection.next().await {
|
||||||
Some(Ok(Response::ListUsers(users))) => users
|
Some(Ok(Response::ListUsers(users))) => users,
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(username, result)| match result {
|
|
||||||
Ok(user) => Some(user),
|
|
||||||
Err(err) => {
|
|
||||||
contained_errors = true;
|
|
||||||
eprintln!("{}", err.to_error_message(&username));
|
|
||||||
eprintln!("Skipping...");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
Some(Ok(Response::ListAllUsers(users))) => match users {
|
Some(Ok(Response::ListAllUsers(users))) => match users {
|
||||||
Ok(users) => users,
|
Ok(users) => users
|
||||||
|
.into_iter()
|
||||||
|
.map(|user| (user.user.clone(), Ok(user)))
|
||||||
|
.collect(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
server_connection.send(Request::Exit).await?;
|
server_connection.send(Request::Exit).await?;
|
||||||
return Err(
|
return Err(
|
||||||
@@ -72,32 +65,12 @@ pub async fn show_users(
|
|||||||
server_connection.send(Request::Exit).await?;
|
server_connection.send(Request::Exit).await?;
|
||||||
|
|
||||||
if args.json {
|
if args.json {
|
||||||
println!(
|
print_list_users_output_status_json(&users);
|
||||||
"{}",
|
|
||||||
serde_json::to_string_pretty(&users).context("Failed to serialize users to JSON")?
|
|
||||||
);
|
|
||||||
} else if users.is_empty() {
|
|
||||||
println!("No users to show.");
|
|
||||||
} else {
|
} else {
|
||||||
let mut table = prettytable::Table::new();
|
print_list_users_output_status(&users);
|
||||||
table.add_row(row![
|
|
||||||
"User",
|
|
||||||
"Password is set",
|
|
||||||
"Locked",
|
|
||||||
"Databases where user has privileges"
|
|
||||||
]);
|
|
||||||
for user in users {
|
|
||||||
table.add_row(row![
|
|
||||||
user.user,
|
|
||||||
user.has_password,
|
|
||||||
user.is_locked,
|
|
||||||
user.databases.join("\n")
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
table.printstd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.fail && contained_errors {
|
if args.fail && users.values().any(|result| result.is_err()) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use prettytable::{Cell, Row, Table};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{
|
core::{
|
||||||
@@ -22,6 +24,57 @@ pub enum ListDatabasesError {
|
|||||||
MySqlError(String),
|
MySqlError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_list_databases_output_status(output: &ListDatabasesResponse) {
|
||||||
|
let mut final_database_list: Vec<&DatabaseRow> = Vec::new();
|
||||||
|
for (db_name, db_result) in output {
|
||||||
|
match db_result {
|
||||||
|
Ok(db_row) => final_database_list.push(db_row),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("{}", err.to_error_message(db_name));
|
||||||
|
eprintln!("Skipping...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if final_database_list.is_empty() {
|
||||||
|
println!("No databases to show.");
|
||||||
|
} else {
|
||||||
|
let mut table = Table::new();
|
||||||
|
table.add_row(Row::new(vec![Cell::new("Database")]));
|
||||||
|
for db in final_database_list {
|
||||||
|
table.add_row(row![db.database]);
|
||||||
|
}
|
||||||
|
table.printstd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_list_databases_output_status_json(output: &ListDatabasesResponse) {
|
||||||
|
let value = output
|
||||||
|
.iter()
|
||||||
|
.map(|(name, result)| match result {
|
||||||
|
Ok(_row) => (
|
||||||
|
name.to_string(),
|
||||||
|
json!({
|
||||||
|
"status": "success",
|
||||||
|
// NOTE: there will likely be more data to include here in the future
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Err(err) => (
|
||||||
|
name.to_string(),
|
||||||
|
json!({
|
||||||
|
"status": "error",
|
||||||
|
"error": err.to_error_message(name),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.collect::<serde_json::Map<_, _>>();
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&value)
|
||||||
|
.unwrap_or("Failed to serialize result to JSON".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
impl ListDatabasesError {
|
impl ListDatabasesError {
|
||||||
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
|
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use prettytable::Table;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{
|
core::{
|
||||||
@@ -22,6 +24,72 @@ pub enum ListUsersError {
|
|||||||
MySqlError(String),
|
MySqlError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn print_list_users_output_status(output: &ListUsersResponse) {
|
||||||
|
let mut final_user_list: Vec<&DatabaseUser> = Vec::new();
|
||||||
|
for (db_name, db_result) in output {
|
||||||
|
match db_result {
|
||||||
|
Ok(db_row) => final_user_list.push(db_row),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("{}", err.to_error_message(db_name));
|
||||||
|
eprintln!("Skipping...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if final_user_list.is_empty() {
|
||||||
|
println!("No users to show.");
|
||||||
|
} else {
|
||||||
|
let mut table = Table::new();
|
||||||
|
table.add_row(row![
|
||||||
|
"User",
|
||||||
|
"Password is set",
|
||||||
|
"Locked",
|
||||||
|
"Databases where user has privileges"
|
||||||
|
]);
|
||||||
|
for user in final_user_list {
|
||||||
|
table.add_row(row![
|
||||||
|
user.user,
|
||||||
|
user.has_password,
|
||||||
|
user.is_locked,
|
||||||
|
user.databases.join("\n")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
table.printstd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_list_users_output_status_json(output: &ListUsersResponse) {
|
||||||
|
let value = output
|
||||||
|
.iter()
|
||||||
|
.map(|(name, result)| match result {
|
||||||
|
Ok(row) => (
|
||||||
|
name.to_string(),
|
||||||
|
json!({
|
||||||
|
"status": "success",
|
||||||
|
"value": {
|
||||||
|
"user": row.user,
|
||||||
|
"has_password": row.has_password,
|
||||||
|
"is_locked": row.is_locked,
|
||||||
|
"databases": row.databases,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Err(err) => (
|
||||||
|
name.to_string(),
|
||||||
|
json!({
|
||||||
|
"status": "error",
|
||||||
|
"error": err.to_error_message(name),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.collect::<serde_json::Map<_, _>>();
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&value)
|
||||||
|
.unwrap_or("Failed to serialize result to JSON".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
impl ListUsersError {
|
impl ListUsersError {
|
||||||
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
pub fn to_error_message(&self, username: &MySQLUser) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
Reference in New Issue
Block a user