diff --git a/Cargo.lock b/Cargo.lock index 9b0142a..374923d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3281,6 +3281,7 @@ dependencies = [ "email_address", "hash", "id", + "serde", "thiserror", ] diff --git a/crates/database/queries/users/get_all.sql b/crates/database/queries/users/get_all.sql new file mode 100644 index 0000000..f2479ff --- /dev/null +++ b/crates/database/queries/users/get_all.sql @@ -0,0 +1,15 @@ +select id, + created_at as "created_at: DateTime", + updated_at as "updated_at: DateTime", + is_admin as "is_admin: bool", + username, + name, + email, + password, + password_recover, + paper_key, + is_archived as "is_archived: bool", + timezone +from users + +order by created_at desc diff --git a/crates/database/sqlx-data.json b/crates/database/sqlx-data.json index 400fdce..4c076ba 100644 --- a/crates/database/sqlx-data.json +++ b/crates/database/sqlx-data.json @@ -446,6 +446,90 @@ }, "query": "update users\n\nset paper_key = ?\n\nwhere id is ?" }, + "6a4a17c69175a677961779db048bff43d01e8773e7c4a6b25b9ee9b3c6fbacd5": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "created_at: DateTime", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "updated_at: DateTime", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "is_admin: bool", + "ordinal": 3, + "type_info": "Int64" + }, + { + "name": "username", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "name", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "email", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 7, + "type_info": "Text" + }, + { + "name": "password_recover", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "paper_key", + "ordinal": 9, + "type_info": "Text" + }, + { + "name": "is_archived: bool", + "ordinal": 10, + "type_info": "Int64" + }, + { + "name": "timezone", + "ordinal": 11, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false + ], + "parameters": { + "Right": 0 + } + }, + "query": "select id,\n created_at as \"created_at: DateTime\",\n updated_at as \"updated_at: DateTime\",\n is_admin as \"is_admin: bool\",\n username,\n name,\n email,\n password,\n password_recover,\n paper_key,\n is_archived as \"is_archived: bool\",\n timezone\nfrom users\n\norder by created_at desc\n" + }, "73f0d480c8dbef497a458070a32e65f0140f9a6e098ea082870a9c904629a97b": { "describe": { "columns": [ diff --git a/crates/database/src/tables/users.rs b/crates/database/src/tables/users.rs index 19a5421..0173cb3 100644 --- a/crates/database/src/tables/users.rs +++ b/crates/database/src/tables/users.rs @@ -97,6 +97,13 @@ impl Users { .map_err(handle_error) } + pub async fn get_all(conn: impl SqliteExecutor<'_>) -> Result, Error> { + sqlx::query_file_as!(Self, "queries/users/get_all.sql") + .fetch_all(conn) + .await + .map_err(handle_error) + } + pub async fn set_username( conn: impl SqliteExecutor<'_>, id: &str, diff --git a/crates/ezidam/src/icons.rs b/crates/ezidam/src/icons.rs index 7803e7f..e663003 100644 --- a/crates/ezidam/src/icons.rs +++ b/crates/ezidam/src/icons.rs @@ -40,7 +40,8 @@ impl Icon { "id-badge-2", IdBadge2, r#""#, "user", User, r#""#, "at", At, r#""#, - "paperclip-large", PaperclipLarge, r#""# + "paperclip-large", PaperclipLarge, r#""#, + "users", Users, r#""# } } @@ -62,6 +63,7 @@ pub fn icons_to_templates(tera: &mut Tera) { Icon::User, Icon::At, Icon::PaperclipLarge, + Icon::Users, ]; // For each icon, it will output: ("icons/name", "...") diff --git a/crates/ezidam/src/menu/items/admin.rs b/crates/ezidam/src/menu/items/admin.rs index a04cba8..d22c074 100644 --- a/crates/ezidam/src/menu/items/admin.rs +++ b/crates/ezidam/src/menu/items/admin.rs @@ -7,6 +7,7 @@ pub enum AdminMenu { Exit, Dashboard, Apps, + Users, Settings, } @@ -16,6 +17,7 @@ impl AdminMenu { AdminMenu::Exit => "exit", AdminMenu::Dashboard => "dashboard", AdminMenu::Apps => "apps", + AdminMenu::Users => "users", AdminMenu::Settings => "settings", } } @@ -42,6 +44,13 @@ impl AdminMenu { icon: Icon::Apps.svg, sub: None, }, + MainItem { + id: AdminMenu::Users.id(), + label: "Users", + link: uri!(routes::admin::users::admin_users_list).to_string(), + icon: Icon::Users.svg, + sub: None, + }, MainItem { id: AdminMenu::Settings.id(), label: "Server settings", diff --git a/crates/ezidam/src/page.rs b/crates/ezidam/src/page.rs index f1d67ab..47f25dc 100644 --- a/crates/ezidam/src/page.rs +++ b/crates/ezidam/src/page.rs @@ -24,6 +24,7 @@ pub enum Page { UserPersonalSettings(UserPersonalSettings), UserSecuritySettings(UserSecuritySettings), UserVisualSettings(UserVisualSettings), + AdminUsersList(AdminUsersList), } impl Page { @@ -44,6 +45,7 @@ impl Page { Page::UserPersonalSettings(_) => "pages/settings/personal", Page::UserSecuritySettings(_) => "pages/settings/security", Page::UserVisualSettings(_) => "pages/settings/visual", + Page::AdminUsersList(_) => "pages/admin/users/list", } } @@ -64,6 +66,7 @@ impl Page { Page::UserPersonalSettings(_) => "Personal settings", Page::UserSecuritySettings(_) => "Security settings", Page::UserVisualSettings(_) => "Visual settings", + Page::AdminUsersList(_) => "Users", } } @@ -86,6 +89,7 @@ impl Page { Page::UserPersonalSettings(_) => Some(UserMenu::Settings.into()), Page::UserSecuritySettings(_) => Some(UserMenu::Settings.into()), Page::UserVisualSettings(_) => Some(UserMenu::Settings.into()), + Page::AdminUsersList(_) => Some(AdminMenu::Users.into()), } } @@ -106,6 +110,7 @@ impl Page { Page::UserPersonalSettings(personal) => Box::new(personal), Page::UserSecuritySettings(security) => Box::new(security), Page::UserVisualSettings(visual) => Box::new(visual), + Page::AdminUsersList(list) => Box::new(list), } } } diff --git a/crates/ezidam/src/routes/admin.rs b/crates/ezidam/src/routes/admin.rs index d98eb56..ffadb91 100644 --- a/crates/ezidam/src/routes/admin.rs +++ b/crates/ezidam/src/routes/admin.rs @@ -1,11 +1,13 @@ use self::apps::*; use self::settings::*; +use self::users::*; use dashboard::*; use rocket::{routes, Route}; pub mod apps; pub mod dashboard; pub mod settings; +pub mod users; pub fn routes() -> Vec { routes![ @@ -21,6 +23,7 @@ pub fn routes() -> Vec { admin_apps_view_form, admin_apps_new_secret, admin_apps_archive, + admin_users_list, ] } @@ -28,6 +31,7 @@ pub mod content { use apps::App; use jwt::JwtClaims; use rocket::serde::Serialize; + use users::User; #[derive(Serialize)] #[serde(crate = "rocket::serde")] @@ -74,4 +78,12 @@ pub mod content { pub user: JwtClaims, pub app: App, } + + #[derive(Serialize)] + #[serde(crate = "rocket::serde")] + #[derive(Clone)] + pub struct AdminUsersList { + pub user: JwtClaims, + pub users: Vec, + } } diff --git a/crates/ezidam/src/routes/admin/users.rs b/crates/ezidam/src/routes/admin/users.rs new file mode 100644 index 0000000..ee33b55 --- /dev/null +++ b/crates/ezidam/src/routes/admin/users.rs @@ -0,0 +1,21 @@ +use crate::routes::prelude::*; +use rocket::get; +use users::User; + +#[get("/admin/users")] +pub async fn admin_users_list( + mut db: Connection, + admin: JwtAdmin, + flash: Option>, +) -> Result