From e600405f224f0aaf30d2b4cbcc9923391ef6370b Mon Sep 17 00:00:00 2001
From: Philippe Loctaux
Date: Wed, 3 May 2023 21:49:25 +0200
Subject: [PATCH] admin/users: view user, archive + restore
---
crates/ezidam/src/icons.rs | 8 +-
crates/ezidam/src/id.rs | 12 +-
crates/ezidam/src/page.rs | 5 +
crates/ezidam/src/routes/admin.rs | 11 +
crates/ezidam/src/routes/admin/users.rs | 119 +++++-
.../pages/admin/users/view.html.tera | 341 ++++++++++++++++++
6 files changed, 492 insertions(+), 4 deletions(-)
create mode 100644 crates/ezidam/templates/pages/admin/users/view.html.tera
diff --git a/crates/ezidam/src/icons.rs b/crates/ezidam/src/icons.rs
index 7834370..f331ef4 100644
--- a/crates/ezidam/src/icons.rs
+++ b/crates/ezidam/src/icons.rs
@@ -45,7 +45,10 @@ impl Icon {
"users", Users, r#""#,
"mail", Mail, r#""#,
"password", Password, r#""#,
- "2fa-large", TwoFaLarge, r#""#
+ "2fa-large", TwoFaLarge, r#""#,
+ "check", Check, r#""#,
+ "x", X, r#""#,
+ "progress", Progress, r#""#
}
}
@@ -72,6 +75,9 @@ pub fn icons_to_templates(tera: &mut Tera) {
Icon::Mail,
Icon::Password,
Icon::TwoFaLarge,
+ Icon::Check,
+ Icon::X,
+ Icon::Progress,
];
// For each icon, it will output: ("icons/name", "")
diff --git a/crates/ezidam/src/id.rs b/crates/ezidam/src/id.rs
index 7fdab7c..15d3be3 100644
--- a/crates/ezidam/src/id.rs
+++ b/crates/ezidam/src/id.rs
@@ -6,7 +6,7 @@ use rocket::serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
-#[derive(Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
pub struct RocketUserID(pub UserID);
@@ -18,7 +18,15 @@ impl<'r> FromParam<'r> for RocketUserID {
}
}
-#[derive(Serialize, Deserialize)]
+impl UriDisplay for RocketUserID {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ UriDisplay::fmt(&self.0 .0, f)
+ }
+}
+
+impl_from_uri_param_identity!([Path] RocketUserID);
+
+#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
pub struct RocketAppID(pub AppID);
diff --git a/crates/ezidam/src/page.rs b/crates/ezidam/src/page.rs
index 1fec61b..700d4e0 100644
--- a/crates/ezidam/src/page.rs
+++ b/crates/ezidam/src/page.rs
@@ -29,6 +29,7 @@ pub enum Page {
ResetPassword(ResetPassword),
UserSecurityTotp(UserSecurityTotp),
AuthorizeTotp(AuthorizeTotp),
+ AdminUsersView(AdminUsersView),
}
impl Page {
@@ -54,6 +55,7 @@ impl Page {
Page::ResetPassword(_) => "pages/reset-password",
Page::UserSecurityTotp(_) => "pages/settings/totp",
Page::AuthorizeTotp(_) => "pages/oauth/totp",
+ Page::AdminUsersView(_) => "pages/admin/users/view",
}
}
@@ -79,6 +81,7 @@ impl Page {
Page::ResetPassword(_) => "Reset password",
Page::UserSecurityTotp(_) => "Enable One-time password",
Page::AuthorizeTotp(_) => "Verifying your account",
+ Page::AdminUsersView(_) => "User info",
}
}
@@ -106,6 +109,7 @@ impl Page {
Page::ResetPassword(_) => None,
Page::UserSecurityTotp(_) => Some(UserMenu::Settings.into()),
Page::AuthorizeTotp(_) => None,
+ Page::AdminUsersView(_) => Some(AdminMenu::Users.into()),
}
}
@@ -131,6 +135,7 @@ impl Page {
Page::ResetPassword(reset) => Box::new(reset),
Page::UserSecurityTotp(totp) => Box::new(totp),
Page::AuthorizeTotp(totp) => Box::new(totp),
+ Page::AdminUsersView(view) => Box::new(view),
}
}
}
diff --git a/crates/ezidam/src/routes/admin.rs b/crates/ezidam/src/routes/admin.rs
index ffadb91..5fc13f8 100644
--- a/crates/ezidam/src/routes/admin.rs
+++ b/crates/ezidam/src/routes/admin.rs
@@ -24,6 +24,8 @@ pub fn routes() -> Vec {
admin_apps_new_secret,
admin_apps_archive,
admin_users_list,
+ admin_users_view,
+ admin_users_archive,
]
}
@@ -86,4 +88,13 @@ pub mod content {
pub user: JwtClaims,
pub users: Vec,
}
+
+ #[derive(Serialize)]
+ #[serde(crate = "rocket::serde")]
+ #[derive(Clone)]
+ pub struct AdminUsersView {
+ pub user: JwtClaims,
+ pub jwt_duration: i64,
+ pub local: User,
+ }
}
diff --git a/crates/ezidam/src/routes/admin/users.rs b/crates/ezidam/src/routes/admin/users.rs
index ee33b55..c1c79c9 100644
--- a/crates/ezidam/src/routes/admin/users.rs
+++ b/crates/ezidam/src/routes/admin/users.rs
@@ -1,5 +1,9 @@
use crate::routes::prelude::*;
-use rocket::get;
+use crate::tokens::JWT_DURATION_MINUTES;
+use authorization_codes::AuthorizationCode;
+use rocket::{get, post};
+use settings::Settings;
+use users::totp_login_request::TotpLoginRequest;
use users::User;
#[get("/admin/users")]
@@ -19,3 +23,116 @@ pub async fn admin_users_list(
.map(|flash| Page::with_flash(page.clone(), flash))
.unwrap_or_else(|| page.into()))
}
+
+#[get("/admin/users/")]
+pub async fn admin_users_view(
+ admin_not_current: JwtAdminNotCurrent,
+ mut db: Connection,
+ id: RocketUserID,
+ flash: Option>,
+) -> Result {
+ let user_id = id.0;
+ let user = User::get_by_id(&mut *db, &user_id)
+ .await?
+ .ok_or_else(|| Error::not_found(user_id.to_string()))?;
+
+ let page = Page::AdminUsersView(super::content::AdminUsersView {
+ user: admin_not_current.0,
+ jwt_duration: JWT_DURATION_MINUTES,
+ local: user,
+ });
+
+ Ok(flash
+ .map(|flash| Page::with_flash(page.clone(), flash))
+ .unwrap_or_else(|| page.into()))
+}
+
+#[derive(Debug, FromForm)]
+pub struct ArchiveUserForm {
+ pub archive: Option,
+ pub restore: Option,
+}
+
+#[post("/admin/users//archive", data = "