1use crate::config::Config;
2use crate::connection::{DbConnection, UserDatabaseRole, UserSchemaRole, UserTableRole};
3use anyhow::{anyhow, Result};
4use ascii_table::AsciiTable;
5use indoc::indoc;
6use log::info;
7
8pub fn inspect(config: &Config) -> Result<()> {
9 let mut conn = DbConnection::new(config)?;
10
11 let users_in_db = conn.get_users()?;
12 let current_db_name = conn
13 .get_current_database()
14 .map(|s| s.to_string())
15 .ok_or_else(|| anyhow!("Could not determine current database"))?;
16
17 let user_database_privileges = conn
18 .get_user_database_privileges()?
19 .into_iter()
20 .filter(|p| p.database_name == current_db_name)
21 .collect::<Vec<_>>();
22 let user_schema_privileges = conn.get_user_schema_privileges()?;
23 let user_table_privileges = conn.get_user_table_privileges()?;
24
25 let mut users = users_in_db
26 .iter()
27 .map(|u| {
28 vec![
29 u.name.clone(),
30 u.user_super.to_string(),
31 get_user_database_privileges(&user_database_privileges, &u.name).unwrap(),
32 get_user_schema_privileges(&user_schema_privileges, &u.name).unwrap(),
33 get_user_table_privileges(&user_table_privileges, &u.name).unwrap(),
34 ]
35 })
36 .collect::<Vec<_>>();
37
38 users.insert(
39 0,
40 vec![
41 "User".to_string(),
42 "Super".to_string(),
43 "Current Database".to_string(),
44 "Schemas".to_string(),
45 "Tables".to_string(),
46 ],
47 );
48 users.insert(
49 1,
50 vec![
51 "---".to_string(),
52 "---".to_string(),
53 "---".to_string(),
54 "---".to_string(),
55 ],
56 );
57
58 let term_width = term_size::dimensions().map(|(w, _)| w).unwrap_or(120) - 5;
60
61 let mut table = AsciiTable::default();
63 table.set_max_width(term_width);
64
65 info!(
66 "Current users in {}:\n{}",
67 config.connection.url,
68 table.format(users)
69 );
70
71 info!(indoc! { r#"
72 == Legend ==
73
74 Database:
75 A = ALL Privileges
76 C = CREATE
77 T = TEMP
78
79 Schema:
80 A = ALL Privileges
81 C = CREATE
82 U = USAGE
83
84 Table:
85 A = ALL Privileges
86 S = SELECT
87 U = UPDATE
88 I = INSERT
89 D = DELETE
90 R = REFERENCES
91 "#});
92
93 Ok(())
94}
95
96fn get_user_database_privileges(privileges: &[UserDatabaseRole], user: &str) -> Result<String> {
98 let privileges = privileges
99 .iter()
100 .filter(|p| p.name == *user) .filter(|p| p.has_create || p.has_temp) .map(|p| p.perm_to_string(true))
103 .collect::<Vec<_>>()
104 .join(", ");
105
106 Ok(privileges)
107}
108
109fn get_user_schema_privileges(privileges: &[UserSchemaRole], user: &str) -> Result<String> {
111 let privileges = privileges
112 .iter()
113 .filter(|p| p.name == *user)
114 .filter(|p| p.has_create || p.has_usage)
115 .map(|p| p.perm_to_string(true))
116 .collect::<Vec<_>>()
117 .join(", ");
118
119 Ok(privileges)
120}
121
122fn get_user_table_privileges(privileges: &[UserTableRole], user: &str) -> Result<String> {
124 let privileges = privileges
125 .iter()
126 .filter(|p| p.name == *user) .filter(|p| {
128 p.has_select || p.has_insert || p.has_update || p.has_delete || p.has_references
129 }) .map(|p| p.perm_to_string(true))
131 .collect::<Vec<_>>()
132 .join(", ");
133
134 Ok(privileges)
135}