Display account details
This commit is contained in:
parent
a4de6a01af
commit
e1eb64f27c
14
assets/css/base_settings_page.css
Normal file
14
assets/css/base_settings_page.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
html {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page_body {
|
||||||
|
padding: 3rem;
|
||||||
|
}
|
2
assets/css/bootstrap.css
vendored
2
assets/css/bootstrap.css
vendored
@ -12,7 +12,7 @@
|
|||||||
* Copyright 2011-2021 Twitter, Inc.
|
* Copyright 2011-2021 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||||
*/
|
*/
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap");
|
@import url("../robotfont/font.css");
|
||||||
:root {
|
:root {
|
||||||
--bs-blue: #2a9fd6;
|
--bs-blue: #2a9fd6;
|
||||||
--bs-indigo: #6610f2;
|
--bs-indigo: #6610f2;
|
||||||
|
BIN
assets/img/account.png
Normal file
BIN
assets/img/account.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 675 B |
7
assets/js/bootstrap.bundle.min.js
vendored
Normal file
7
assets/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
assets/robotfont/KFOlCnqEu92Fr1MmWUlvAw.ttf
Normal file
BIN
assets/robotfont/KFOlCnqEu92Fr1MmWUlvAw.ttf
Normal file
Binary file not shown.
BIN
assets/robotfont/KFOmCnqEu92Fr1Me5Q.ttf
Normal file
BIN
assets/robotfont/KFOmCnqEu92Fr1Me5Q.ttf
Normal file
Binary file not shown.
14
assets/robotfont/font.css
Normal file
14
assets/robotfont/font.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./KFOmCnqEu92Fr1Me5Q.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(./KFOlCnqEu92Fr1MmWUlvAw.ttf) format('truetype');
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use actix::{Actor, Context, Handler, Message, MessageResult};
|
use actix::{Actor, Context, Handler, Message, MessageResult};
|
||||||
|
|
||||||
use crate::data::entity_manager::EntityManager;
|
use crate::data::entity_manager::EntityManager;
|
||||||
use crate::data::user::{verify_password, User, UserID};
|
use crate::data::user::{User, UserID, verify_password};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoginResult {
|
pub enum LoginResult {
|
||||||
@ -21,6 +21,13 @@ pub struct LoginRequest {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ChangePasswordResult(pub bool);
|
pub struct ChangePasswordResult(pub bool);
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(GetUserResult)]
|
||||||
|
pub struct GetUserRequest(pub UserID);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GetUserResult(pub Option<User>);
|
||||||
|
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
#[rtype(ChangePasswordResult)]
|
#[rtype(ChangePasswordResult)]
|
||||||
pub struct ChangePasswordRequest {
|
pub struct ChangePasswordRequest {
|
||||||
@ -75,3 +82,11 @@ impl Handler<ChangePasswordRequest> for UsersActor {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Handler<GetUserRequest> for UsersActor {
|
||||||
|
type Result = MessageResult<GetUserRequest>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: GetUserRequest, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
MessageResult(GetUserResult(self.manager.find_by_user_id(&msg.0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod assets_controller;
|
pub mod assets_controller;
|
||||||
pub mod base_controller;
|
pub mod base_controller;
|
||||||
pub mod login_controller;
|
pub mod login_controller;
|
||||||
|
pub mod settings_controller;
|
62
src/controllers/settings_controller.rs
Normal file
62
src/controllers/settings_controller.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use actix::Addr;
|
||||||
|
use actix_identity::Identity;
|
||||||
|
use actix_web::{HttpResponse, Responder, web};
|
||||||
|
use askama::Template;
|
||||||
|
|
||||||
|
use crate::actors::users_actor;
|
||||||
|
use crate::actors::users_actor::UsersActor;
|
||||||
|
use crate::constants::APP_NAME;
|
||||||
|
use crate::data::session_identity::SessionIdentity;
|
||||||
|
use crate::data::user::User;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "settings/base_settings_page.html")]
|
||||||
|
struct BaseSettingsPage {
|
||||||
|
danger_message: Option<String>,
|
||||||
|
success_message: Option<String>,
|
||||||
|
page_title: &'static str,
|
||||||
|
app_name: &'static str,
|
||||||
|
is_admin: bool,
|
||||||
|
user_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BaseSettingsPage {
|
||||||
|
async fn get(user: &User) -> BaseSettingsPage {
|
||||||
|
Self {
|
||||||
|
danger_message: None,
|
||||||
|
success_message: None,
|
||||||
|
page_title: "Account details",
|
||||||
|
app_name: APP_NAME,
|
||||||
|
is_admin: user.admin,
|
||||||
|
user_name: user.username.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "settings/account_details.html")]
|
||||||
|
struct AccountDetailsPage {
|
||||||
|
_parent: BaseSettingsPage,
|
||||||
|
user_id: String,
|
||||||
|
first_name: String,
|
||||||
|
last_name: String,
|
||||||
|
username: String,
|
||||||
|
email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Account details page
|
||||||
|
pub async fn account_settings_details_route(id: Identity, user_actor: web::Data<Addr<UsersActor>>) -> impl Responder {
|
||||||
|
let user: User = user_actor.send(
|
||||||
|
users_actor::GetUserRequest(SessionIdentity(&id).user_id())
|
||||||
|
).await.unwrap().0.unwrap();
|
||||||
|
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.body(AccountDetailsPage {
|
||||||
|
_parent: BaseSettingsPage::get(&user).await,
|
||||||
|
user_id: user.uid,
|
||||||
|
first_name: user.first_name,
|
||||||
|
last_name: user.last_last,
|
||||||
|
username: user.username,
|
||||||
|
email: user.email,
|
||||||
|
}.render().unwrap())
|
||||||
|
}
|
@ -86,6 +86,10 @@ impl<'a> SessionIdentity<'a> {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_admin(&self) -> bool {
|
||||||
|
self.get_session_data().unwrap_or_default().is_admin
|
||||||
|
}
|
||||||
|
|
||||||
pub fn user_id(&self) -> UserID {
|
pub fn user_id(&self) -> UserID {
|
||||||
self.get_session_data().unwrap_or_default().id
|
self.get_session_data().unwrap_or_default().id
|
||||||
}
|
}
|
||||||
|
11
src/main.rs
11
src/main.rs
@ -14,6 +14,7 @@ use basic_oidc::constants::{
|
|||||||
};
|
};
|
||||||
use basic_oidc::controllers::assets_controller::assets_route;
|
use basic_oidc::controllers::assets_controller::assets_route;
|
||||||
use basic_oidc::controllers::login_controller::{login_route, logout_route};
|
use basic_oidc::controllers::login_controller::{login_route, logout_route};
|
||||||
|
use basic_oidc::controllers::settings_controller;
|
||||||
use basic_oidc::data::app_config::AppConfig;
|
use basic_oidc::data::app_config::AppConfig;
|
||||||
use basic_oidc::data::entity_manager::EntityManager;
|
use basic_oidc::data::entity_manager::EntityManager;
|
||||||
use basic_oidc::data::user::{hash_password, User};
|
use basic_oidc::data::user::{hash_password, User};
|
||||||
@ -81,18 +82,26 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.app_data(web::Data::new(users_actor.clone()))
|
.app_data(web::Data::new(users_actor.clone()))
|
||||||
.app_data(web::Data::new(bruteforce_actor.clone()))
|
.app_data(web::Data::new(bruteforce_actor.clone()))
|
||||||
.app_data(web::Data::new(config.clone()))
|
.app_data(web::Data::new(config.clone()))
|
||||||
|
|
||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
.wrap(AuthMiddleware {})
|
.wrap(AuthMiddleware {})
|
||||||
.wrap(IdentityService::new(policy))
|
.wrap(IdentityService::new(policy))
|
||||||
// /health route
|
|
||||||
|
// health route
|
||||||
.service(health)
|
.service(health)
|
||||||
|
|
||||||
// Assets serving
|
// Assets serving
|
||||||
.route("/assets/{path:.*}", web::get().to(assets_route))
|
.route("/assets/{path:.*}", web::get().to(assets_route))
|
||||||
|
|
||||||
// Login page
|
// Login page
|
||||||
.route("/login", web::get().to(login_route))
|
.route("/login", web::get().to(login_route))
|
||||||
.route("/login", web::post().to(login_route))
|
.route("/login", web::post().to(login_route))
|
||||||
|
|
||||||
// Logout page
|
// Logout page
|
||||||
.route("/logout", web::get().to(logout_route))
|
.route("/logout", web::get().to(logout_route))
|
||||||
|
|
||||||
|
// Settings routes
|
||||||
|
.route("/settings", web::get().to(settings_controller::account_settings_details_route))
|
||||||
})
|
})
|
||||||
.bind(listen_address)?
|
.bind(listen_address)?
|
||||||
.run()
|
.run()
|
||||||
|
33
templates/settings/account_details.html
Normal file
33
templates/settings/account_details.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{% extends "base_settings_page.html" %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<table class="table table-hover" style="max-width: 600px;" aria-describedby="Account details">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">User ID</th>
|
||||||
|
<td>{{ user_id }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">First name</th>
|
||||||
|
<td>{{ first_name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Last name</th>
|
||||||
|
<td>{{ last_name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Username</th>
|
||||||
|
<td>{{ username }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Email</th>
|
||||||
|
<td>{{ email }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Account type</th>
|
||||||
|
<td>{% if is_admin %}Admin{% else %}Regular account{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock content %}
|
69
templates/settings/base_settings_page.html
Normal file
69
templates/settings/base_settings_page.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>{{ page_title }} - {{ app_name }}</title>
|
||||||
|
|
||||||
|
<!-- Bootstrap core CSS -->
|
||||||
|
<link href="/assets/css/bootstrap.css" rel="stylesheet" crossorigin="anonymous"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/assets/css/base_settings_page.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="d-flex flex-column flex-shrink-0 p-3 bg-light" style="width: 280px;">
|
||||||
|
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-dark text-decoration-none">
|
||||||
|
<span class="fs-4">{{ app_name }}</span>
|
||||||
|
</a>
|
||||||
|
<hr>
|
||||||
|
<ul class="nav nav-pills flex-column mb-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="/settings" class="nav-link active" aria-current="page">
|
||||||
|
Account details
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/settings/change_password" class="nav-link link-dark">
|
||||||
|
Change password
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
{% if is_admin %}
|
||||||
|
<li>
|
||||||
|
<a href="/admin/apps" class="nav-link link-dark">
|
||||||
|
Applications
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/users" class="nav-link link-dark">
|
||||||
|
Users
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<hr>
|
||||||
|
<div class="dropdown">
|
||||||
|
<a href="#" class="d-flex align-items-center link-dark text-decoration-none dropdown-toggle" id="dropdownUser" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<img src="/assets/img/account.png" alt="" width="32" height="32" class="rounded-circle me-2">
|
||||||
|
<strong>{{ user_name }}</strong>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu text-small shadow" aria-labelledby="dropdownUser">
|
||||||
|
<li><a class="dropdown-item" href="/logout">Sign out</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page_body" style="flex: 1">
|
||||||
|
{% if let Some(msg) = danger_message %}<div class="alert alert-danger">{{ msg }}</div>{% endif %}
|
||||||
|
{% if let Some(msg) = success_message %}<div class="alert alert-success">{{ msg }}</div>{% endif %}
|
||||||
|
|
||||||
|
<h2 class="bd-title mt-0" style="margin-bottom: 40px;">{{ page_title }}</h2>
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
TO_REPLACE
|
||||||
|
{% endblock content %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user