ux: More style (bulma / fork-awesome) for logged in users
This commit is contained in:
parent
1d09019875
commit
a60434e662
14 changed files with 275 additions and 62 deletions
3
assets/css/bulma.min.css
vendored
Normal file
3
assets/css/bulma.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
assets/css/fork-awesome.min.css
vendored
Executable file
12
assets/css/fork-awesome.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
BIN
assets/fonts/forkawesome-webfont.woff2
Executable file
BIN
assets/fonts/forkawesome-webfont.woff2
Executable file
Binary file not shown.
|
|
@ -7,6 +7,29 @@ use serde::Deserialize;
|
||||||
use crate::db::{DatabaseInterface, Operation};
|
use crate::db::{DatabaseInterface, Operation};
|
||||||
use crate::http::{HttpSession, HttpState};
|
use crate::http::{HttpSession, HttpState};
|
||||||
|
|
||||||
|
pub async fn list_domains(State(state): State<HttpState>, session: HttpSession) -> Response {
|
||||||
|
let domains = match state.db.domains_user_can_see(&session.user).await {
|
||||||
|
Ok(domains) => domains,
|
||||||
|
Err(e) => {
|
||||||
|
return format!("Database error: {e}").into_response();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctx = context! {
|
||||||
|
domains,
|
||||||
|
user => session.user,
|
||||||
|
can_create_domain => session.user.can_create_domain(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let page = state
|
||||||
|
.templates
|
||||||
|
.get_template("domains.html")
|
||||||
|
.unwrap()
|
||||||
|
.render(ctx)
|
||||||
|
.unwrap();
|
||||||
|
(StatusCode::OK, Html(page)).into_response()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_domain(
|
pub async fn get_domain(
|
||||||
State(state): State<HttpState>,
|
State(state): State<HttpState>,
|
||||||
session: HttpSession,
|
session: HttpSession,
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ pub async fn http_listen(listener: Listener, db: Database) {
|
||||||
.route("/login", post(login::post_login))
|
.route("/login", post(login::post_login))
|
||||||
.route("/logout", get(logout::logout))
|
.route("/logout", get(logout::logout))
|
||||||
.route("/domain/{domain}", get(domain::get_domain))
|
.route("/domain/{domain}", get(domain::get_domain))
|
||||||
|
.route("/domain", get(domain::list_domains))
|
||||||
.route("/domain", post(domain::create_domain))
|
.route("/domain", post(domain::create_domain))
|
||||||
.route("/user", post(user::create_user))
|
.route("/user", post(user::create_user))
|
||||||
.with_state(HttpState::new(db));
|
.with_state(HttpState::new(db));
|
||||||
|
|
|
||||||
58
templates/app.html
Normal file
58
templates/app.html
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block header %}
|
||||||
|
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="/"><img src="/assets/img/logo.png"></a>
|
||||||
|
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navMenu">
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="navMenu" class="navbar-menu">
|
||||||
|
<div class="navbar-start">
|
||||||
|
<a href="/domain" class="navbar-item">
|
||||||
|
<i class="fa fa-university" aria-hidden="true"></i>
|
||||||
|
Domains
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="navbar-end">
|
||||||
|
<div class="navbar-item">
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="/logout" class="button is-danger">
|
||||||
|
<strong>Logout</strong>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% endblock header %}
|
||||||
|
{% block js %}
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
|
// Get all "navbar-burger" elements
|
||||||
|
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
|
||||||
|
|
||||||
|
// Add a click event on each of them
|
||||||
|
$navbarBurgers.forEach( el => {
|
||||||
|
el.addEventListener('click', () => {
|
||||||
|
|
||||||
|
// Get the target from the "data-target" attribute
|
||||||
|
const target = el.dataset.target;
|
||||||
|
const $target = document.getElementById(target);
|
||||||
|
|
||||||
|
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
||||||
|
el.classList.toggle('is-active');
|
||||||
|
$target.classList.toggle('is-active');
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock js %}
|
||||||
|
|
@ -1,11 +1,22 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>LLLDAP</title>
|
<title>LLLDAP</title>
|
||||||
|
{% block stylesheets %}
|
||||||
|
<link rel="stylesheet" href="/assets/css/bulma.min.css">
|
||||||
|
<link rel="stylesheet" href="/assets/css/fork-awesome.min.css">
|
||||||
<link rel="stylesheet" href="/assets/css/main.css">
|
<link rel="stylesheet" href="/assets/css/main.css">
|
||||||
|
{% endblock stylesheets %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block main %}
|
{% block header %}
|
||||||
{% endblock %}
|
{% endblock header %}
|
||||||
|
{% block main %}
|
||||||
|
{% endblock main %}
|
||||||
|
{% block js %}
|
||||||
|
{% endblock js %}
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,48 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'app.html' %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<main id="center">
|
<main>
|
||||||
<img src="/assets/img/logo.png" id="logo">
|
<section class="section">
|
||||||
<p style="text-align: center;">You are logged in as {{ user.username }}</p>
|
<div class="container is-widescreen mt-5">
|
||||||
<div id="login-line">
|
<div class="card">
|
||||||
<a href="/logout" id="submit-login" value="Logout">Logout</a>
|
<header class="card-header">
|
||||||
</div>
|
<p class="card-header-title">{{ domain.name }}</p>
|
||||||
{% if can_create_user %}
|
</header>
|
||||||
<div>
|
<div class="card-content">
|
||||||
<h2>Create user</h2>
|
<div class="content">
|
||||||
<form action="/user" method="POST">
|
<p><i class="fa fa-user mr-3" aria-hidden="true"></i>{{ users|length() }} users</p>
|
||||||
<input type="hidden" name="domain" value="{{ domain.name }}">
|
</div>
|
||||||
<input type="text" name="username" placeholder="username">
|
</div>
|
||||||
<input type="password" name="password" placeholder="password">
|
</div>
|
||||||
<button type="submit" class="button is-info">Create</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% if can_create_user %}
|
||||||
<div>
|
{% include 'partials/create_user_form.html' %}
|
||||||
<h2>Users on {{ domain.name }}</h2>
|
{% endif %}
|
||||||
<ul>
|
<div class="container is-widescreen mt-5">
|
||||||
{% for user in users %}
|
<article class="message is-info">
|
||||||
<li>{{ user.mail }}</li>
|
<header class="message-header">
|
||||||
{% endfor %}
|
<p class="card-header-title">List of all users on this domain</p>
|
||||||
</ul>
|
</header>
|
||||||
</div>
|
<div class="message-body">
|
||||||
|
<table class="table is-fullwidth is-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Role</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user in users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ user.username }}</td>
|
||||||
|
<td>{{ user.role }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
||||||
38
templates/domains.html
Normal file
38
templates/domains.html
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{% extends 'app.html' %}
|
||||||
|
{% block main %}
|
||||||
|
<main>
|
||||||
|
<section class="section">
|
||||||
|
{% if can_create_domain %}
|
||||||
|
{% include 'partials/create_domain_form.html' %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="container is-widescreen mt-5">
|
||||||
|
<article class="message is-info">
|
||||||
|
<header class="message-header">
|
||||||
|
{% if can_create_domain %}
|
||||||
|
<p class="card-header-title">List of all domains on this server</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="card-header-title">List of your domains</p>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
<div class="message-body">
|
||||||
|
<table class="table is-fullwidth is-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Domain</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for domain in domains %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="/domain/{{ domain.name }}">{{ domain.name }}</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
@ -1,38 +1,14 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'app.html' %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<main id="center">
|
<main>
|
||||||
<img src="/assets/img/logo.png" id="logo">
|
<section class="section">
|
||||||
<p style="text-align: center;">You are logged in as {{ user.username }}</p>
|
<h1 class="title has-text-centered">Welcome to llldap, {{ user.username }}</h1>
|
||||||
<div id="login-line">
|
{% if can_create_domain %}
|
||||||
<a href="/logout" id="submit-login" value="Logout">Logout</a>
|
{% include 'partials/create_domain_form.html' %}
|
||||||
</div>
|
{% endif %}
|
||||||
{% if can_create_domain %}
|
{% if domains|length() > 1 %}
|
||||||
<div>
|
{% include 'partials/create_user_form.html' %}
|
||||||
<h2>Create domain</h2>
|
{% endif %}
|
||||||
<form action="/domain" method="POST">
|
</section>
|
||||||
<input type="text" name="domainname" placeholder="example.com">
|
|
||||||
<button type="submit" class="button is-info">Create</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div>
|
|
||||||
<h2>Active domains you can see</h2>
|
|
||||||
<ul>
|
|
||||||
{% for domain in domains %}
|
|
||||||
<li><a href="/domain/{{ domain.name }}">{{ domain.name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% if other_users %}
|
|
||||||
<div>
|
|
||||||
<h2>Other users you have permission to see on your own domain</h2>
|
|
||||||
<ul>
|
|
||||||
{% for user in other_users %}
|
|
||||||
<li>{{ user.mail }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
{% block stylesheets %}
|
||||||
|
<link rel="stylesheet" href="/assets/css/login.css">
|
||||||
|
{% endblock stylesheets %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<main id="login-screen">
|
<main id="login-screen">
|
||||||
<img src="/assets/img/logo.png" id="logo">
|
<img src="/assets/img/logo.png" id="logo">
|
||||||
|
|
|
||||||
19
templates/partials/create_domain_form.html
Normal file
19
templates/partials/create_domain_form.html
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="container is-widescreen mt-5">
|
||||||
|
<article class="message is-info">
|
||||||
|
<div class="message-header">
|
||||||
|
<p><i class="fa fa-university mr-3" aria-hidden="true"></i>Create domain</p>
|
||||||
|
</div>
|
||||||
|
<div class="message-body">
|
||||||
|
<form action="/domain" method="POST">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Domain name</label>
|
||||||
|
<div class="control">
|
||||||
|
<input name="domainname" class="input" type="text" placeholder="example.com">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="button is-info is-link">Create</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
51
templates/partials/create_user_form.html
Normal file
51
templates/partials/create_user_form.html
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<div class="container is-widescreen mt-5">
|
||||||
|
<article class="message is-info">
|
||||||
|
<div class="message-header">
|
||||||
|
<p><i class="fa fa-user mr-3" aria-hidden="true"></i>Create user</p>
|
||||||
|
</div>
|
||||||
|
<div class="message-body">
|
||||||
|
<form action="/user" method="POST">
|
||||||
|
{% if domain %}
|
||||||
|
<input name="domain" type="hidden" value="{{ domain.name }}">
|
||||||
|
{% else %}
|
||||||
|
<div class="field is-horizontal">
|
||||||
|
<div class="field-label is-flex-grow-0 is-align-content-center">
|
||||||
|
<label class="label">Domain</label>
|
||||||
|
</div>
|
||||||
|
<div class="field-body">
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<div class="select">
|
||||||
|
<select name="domain" autocomplete="{{ domains|map(attribute = 'name')|join(' ') }}">
|
||||||
|
{% for domain in domains %}
|
||||||
|
<option>{{ domain.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="field">
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input name="username" class="input" type="text" placeholder="myuser">
|
||||||
|
<span class="icon is-small is-left">
|
||||||
|
<i class="fa fa-user"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control has-icons-left">
|
||||||
|
<input name="password" class="input" type="password" placeholder="password">
|
||||||
|
<span class="icon is-small is-left">
|
||||||
|
<i class="fa fa-lock"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="button is-info is-link">Create</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
Loading…
Reference in a new issue