ezidam: user settings: show personal info
This commit is contained in:
parent
71643f6e37
commit
29fbcb6428
8 changed files with 181 additions and 9 deletions
|
|
@ -36,7 +36,10 @@ impl Icon {
|
|||
"moon", Moon, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-moon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path></svg>"#,
|
||||
"sun", Sun, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"></path><path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7"></path></svg>"#,
|
||||
"arrow-left", ArrowLeft, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrow-left" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 12l14 0"></path><path d="M5 12l6 6"></path><path d="M5 12l6 -6"></path></svg>"#,
|
||||
"alert-triangle-large", AlertTriangleLarge, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-lg icon-tabler icon-tabler-alert-triangle" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M10.24 3.957l-8.422 14.06a1.989 1.989 0 0 0 1.7 2.983h16.845a1.989 1.989 0 0 0 1.7 -2.983l-8.423 -14.06a1.989 1.989 0 0 0 -3.4 0z"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg>"#
|
||||
"alert-triangle-large", AlertTriangleLarge, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-lg icon-tabler icon-tabler-alert-triangle" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M10.24 3.957l-8.422 14.06a1.989 1.989 0 0 0 1.7 2.983h16.845a1.989 1.989 0 0 0 1.7 -2.983l-8.423 -14.06a1.989 1.989 0 0 0 -3.4 0z"></path><path d="M12 9v4"></path><path d="M12 17h.01"></path></svg>"#,
|
||||
"id-badge-2", IdBadge2, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-id-badge-2" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 12h3v4h-3z"></path><path d="M10 6h-6a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h16a1 1 0 0 0 1 -1v-12a1 1 0 0 0 -1 -1h-6"></path><path d="M10 3m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v3a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z"></path><path d="M14 16h2"></path><path d="M14 12h4"></path></svg>"#,
|
||||
"user", User, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-user" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0"></path><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"></path></svg>"#,
|
||||
"at", At, r#"<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-at" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"></path><path d="M16 12v1.5a2.5 2.5 0 0 0 5 0v-1.5a9 9 0 1 0 -5.5 8.28"></path></svg>"#
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +57,9 @@ pub fn icons_to_templates(tera: &mut Tera) {
|
|||
Icon::Sun,
|
||||
Icon::ArrowLeft,
|
||||
Icon::AlertTriangleLarge,
|
||||
Icon::IdBadge2,
|
||||
Icon::User,
|
||||
Icon::At,
|
||||
];
|
||||
|
||||
// For each icon, it will output: ("icons/name", "<svg>...</svg>")
|
||||
|
|
|
|||
|
|
@ -1,25 +1,39 @@
|
|||
use crate::icons::Icon;
|
||||
use crate::menu::MainItem;
|
||||
use crate::menu::{MainItem, SubItem};
|
||||
use crate::routes;
|
||||
use rocket::uri;
|
||||
|
||||
pub enum UserMenu {
|
||||
Home,
|
||||
Settings,
|
||||
}
|
||||
|
||||
impl UserMenu {
|
||||
pub fn id(&self) -> &'static str {
|
||||
match self {
|
||||
UserMenu::Home => "home",
|
||||
UserMenu::Settings => "settings",
|
||||
}
|
||||
}
|
||||
pub fn list() -> Vec<MainItem> {
|
||||
vec![MainItem {
|
||||
vec![
|
||||
MainItem {
|
||||
id: UserMenu::Home.id(),
|
||||
label: "Home",
|
||||
link: uri!(routes::root::home::homepage).to_string(),
|
||||
icon: Icon::Home.svg,
|
||||
sub: None,
|
||||
}]
|
||||
},
|
||||
MainItem {
|
||||
id: UserMenu::Settings.id(),
|
||||
label: "Settings",
|
||||
link: uri!(routes::settings::user_settings).to_string(),
|
||||
icon: Icon::Settings.svg,
|
||||
sub: Some(vec![SubItem {
|
||||
label: "Personal",
|
||||
link: uri!(routes::settings::user_settings_personal).to_string(),
|
||||
}]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ pub enum Page {
|
|||
AdminAppsList(AdminAppsList),
|
||||
AdminAppsNew(AdminAppsNew),
|
||||
AdminAppsView(AdminAppsView),
|
||||
UserPersonalSettings(UserPersonalSettings),
|
||||
}
|
||||
|
||||
impl Page {
|
||||
|
|
@ -38,6 +39,7 @@ impl Page {
|
|||
Page::AdminAppsList(_) => "pages/admin/apps/list",
|
||||
Page::AdminAppsNew(_) => "pages/admin/apps/new",
|
||||
Page::AdminAppsView(_) => "pages/admin/apps/view",
|
||||
Page::UserPersonalSettings(_) => "pages/settings/personal",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +57,7 @@ impl Page {
|
|||
Page::AdminAppsList(_) => "Applications",
|
||||
Page::AdminAppsNew(_) => "New application",
|
||||
Page::AdminAppsView(_) => "Application info",
|
||||
Page::UserPersonalSettings(_) => "Personal settings",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +77,7 @@ impl Page {
|
|||
Page::AdminAppsList(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::AdminAppsNew(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::AdminAppsView(_) => Some(AdminMenu::Apps.into()),
|
||||
Page::UserPersonalSettings(_) => Some(UserMenu::Settings.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +95,7 @@ impl Page {
|
|||
Page::AdminAppsList(list) => Box::new(list),
|
||||
Page::AdminAppsNew(new) => Box::new(new),
|
||||
Page::AdminAppsView(view) => Box::new(view),
|
||||
Page::UserPersonalSettings(personal) => Box::new(personal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ pub use crate::error::content::*;
|
|||
pub use crate::routes::admin::content::*;
|
||||
pub use crate::routes::oauth::content::*;
|
||||
pub use crate::routes::root::content::*;
|
||||
pub use crate::routes::settings::content::*;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rocket::{Build, Rocket};
|
|||
pub mod admin;
|
||||
pub mod oauth;
|
||||
pub mod root;
|
||||
pub mod settings;
|
||||
pub mod setup;
|
||||
pub mod well_known;
|
||||
|
||||
|
|
@ -42,4 +43,6 @@ pub fn routes(rocket_builder: Rocket<Build>) -> Rocket<Build> {
|
|||
.mount("/", well_known::routes())
|
||||
// Admin
|
||||
.mount("/", admin::routes())
|
||||
// Settings
|
||||
.mount("/", settings::routes())
|
||||
}
|
||||
|
|
|
|||
29
crates/ezidam/src/routes/settings.rs
Normal file
29
crates/ezidam/src/routes/settings.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use super::prelude::*;
|
||||
pub use personal::*;
|
||||
use rocket::get;
|
||||
|
||||
pub mod personal;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![user_settings, user_settings_personal]
|
||||
}
|
||||
|
||||
#[get("/settings")]
|
||||
pub async fn user_settings(_user: JwtUser) -> Redirect {
|
||||
Redirect::to(uri!(user_settings_personal))
|
||||
}
|
||||
|
||||
pub mod content {
|
||||
use jwt::JwtClaims;
|
||||
use rocket::serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
#[derive(Clone)]
|
||||
pub struct UserPersonalSettings {
|
||||
pub user: JwtClaims,
|
||||
pub username: String,
|
||||
pub name: Option<String>,
|
||||
pub email: Option<String>,
|
||||
}
|
||||
}
|
||||
25
crates/ezidam/src/routes/settings/personal.rs
Normal file
25
crates/ezidam/src/routes/settings/personal.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use crate::routes::prelude::*;
|
||||
use rocket::get;
|
||||
use users::User;
|
||||
|
||||
#[get("/settings/personal")]
|
||||
pub async fn user_settings_personal(
|
||||
mut db: Connection<Database>,
|
||||
jwt_user: JwtUser,
|
||||
flash: Option<FlashMessage<'_>>,
|
||||
) -> Result<Template> {
|
||||
let user = User::get_by_login(&mut *db, &jwt_user.0.subject)
|
||||
.await?
|
||||
.ok_or_else(|| Error::not_found(jwt_user.0.subject.to_string()))?;
|
||||
|
||||
let page = Page::UserPersonalSettings(super::content::UserPersonalSettings {
|
||||
user: jwt_user.0,
|
||||
username: user.username().into(),
|
||||
name: user.name().map(String::from),
|
||||
email: user.email().map(String::from),
|
||||
});
|
||||
|
||||
Ok(flash
|
||||
.map(|flash| Page::with_flash(page.clone(), flash))
|
||||
.unwrap_or_else(|| page.into()))
|
||||
}
|
||||
89
crates/ezidam/templates/pages/settings/personal.html.tera
Normal file
89
crates/ezidam/templates/pages/settings/personal.html.tera
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
{% extends "shell" %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">
|
||||
Settings
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
|
||||
{% if flash %}
|
||||
<div class="alert alert-{{flash.0}}" role="alert">
|
||||
<h4 class="alert-title">{{ flash.1 | safe }}</h4>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<div class="row g-0">
|
||||
<div class="col-3 d-none d-md-block border-end">
|
||||
<div class="card-body">
|
||||
<div class="list-group list-group-transparent">
|
||||
<a href="./personal"
|
||||
class="list-group-item list-group-item-action d-flex align-items-center active">Personal</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col d-flex flex-column">
|
||||
<form action="" method="post" >
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">My Profile</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<!-- Username -->
|
||||
<label class="form-label required" for="username">Username</label>
|
||||
<div class="input-icon mb-3">
|
||||
<span class="input-icon-addon">
|
||||
{% include "icons/id-badge-2" %}
|
||||
</span>
|
||||
<input name="username" id="username" value="{{ username }}" type="text"
|
||||
placeholder="Enter a username"
|
||||
class="form-control"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<!-- Name -->
|
||||
<label class="form-label" for="name">Full Name</label>
|
||||
<div class="input-icon mb-3">
|
||||
<span class="input-icon-addon">
|
||||
{% include "icons/user" %}
|
||||
</span>
|
||||
<input name="name" id="name" value="{{ name }}" type="text"
|
||||
placeholder="Napoleon Bonaparte"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<label class="form-label" for="email">Email address</label>
|
||||
<div class="input-icon mb-3">
|
||||
<span class="input-icon-addon">
|
||||
{% include "icons/at" %}
|
||||
</span>
|
||||
<input name="email" id="email" value="{{ email }}" type="email"
|
||||
placeholder="napoleon@bonaparte.fr"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-end">
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue