feat: Basic domain admin page
This commit is contained in:
parent
38700ee4cb
commit
ae5d466e99
5 changed files with 92 additions and 2 deletions
|
|
@ -54,7 +54,10 @@ pub trait DatabaseInterface: Clone + Send + Sync + 'static {
|
|||
&mut self,
|
||||
domain: &str,
|
||||
) -> impl Future<Output = Result<Result<(), DomainCreationError>, BoxedError>>;
|
||||
fn get_domain(&self, domain: &str) -> impl Future<Output = Result<Option<Domain>, BoxedError>>;
|
||||
fn get_domain(
|
||||
&self,
|
||||
domain: &str,
|
||||
) -> impl Future<Output = Result<Option<Domain>, BoxedError>> + Send;
|
||||
|
||||
fn get_user(
|
||||
&self,
|
||||
|
|
|
|||
54
src/http/domain.rs
Normal file
54
src/http/domain.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use axum::extract::{Path, State};
|
||||
use axum::response::{Html, IntoResponse, Response};
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use http::StatusCode;
|
||||
use minijinja::context;
|
||||
|
||||
use crate::db::{DatabaseInterface, Operation};
|
||||
use crate::http::HttpState;
|
||||
use crate::http::login::login_page;
|
||||
|
||||
pub async fn get_domain<D: DatabaseInterface>(
|
||||
State(state): State<HttpState<D>>,
|
||||
cookies: CookieJar,
|
||||
Path(domain): Path<String>,
|
||||
) -> Response {
|
||||
let Some(session) = state.sessions.get_session(&cookies) else {
|
||||
return login_page(State(state), None).await.into_response();
|
||||
};
|
||||
|
||||
let domain = match state.db.get_domain(&domain).await {
|
||||
Ok(Some(domain)) => domain,
|
||||
Ok(None) => return format!("Domain not found: {domain}").into_response(),
|
||||
Err(e) => {
|
||||
return format!("Database error: {e}").into_response();
|
||||
}
|
||||
};
|
||||
|
||||
let domain_users = match state.db.list_domain_users(Some(domain.name.clone())).await {
|
||||
Ok(users) => users,
|
||||
Err(e) => {
|
||||
return format!("Database error: {e}").into_response();
|
||||
}
|
||||
};
|
||||
|
||||
// Redundant because someone who can see the domain admin page for the moment
|
||||
// always can create accounts.
|
||||
let op = Operation::CreateUser(domain.name.clone());
|
||||
let can_create_user = session.user.can_perform(&op);
|
||||
|
||||
let ctx = context! {
|
||||
can_create_user,
|
||||
domain,
|
||||
user => session.user,
|
||||
users => domain_users,
|
||||
};
|
||||
|
||||
let page = state
|
||||
.templates
|
||||
.get_template("domain.html")
|
||||
.unwrap()
|
||||
.render(ctx)
|
||||
.unwrap();
|
||||
(StatusCode::OK, Html(page)).into_response()
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ use crate::db::{Database, DatabaseInterface};
|
|||
use crate::listener::{Listener, ListenerKind};
|
||||
use crate::stream::{AbstractSocketAddr, AbstractStreamKind};
|
||||
|
||||
mod domain;
|
||||
mod home;
|
||||
mod login;
|
||||
mod logout;
|
||||
|
|
@ -99,6 +100,8 @@ pub async fn http_listen<D: DatabaseInterface>(listener: Listener, db: Database<
|
|||
.route("/login", get(home::home))
|
||||
.route("/login", post(login::post_login))
|
||||
.route("/logout", get(logout::logout))
|
||||
.route("/domain/{domain}", get(domain::get_domain))
|
||||
//.route("/domain", post(domain::create_domain))
|
||||
.with_state(HttpState::new(db));
|
||||
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
|
|
|
|||
30
templates/domain.html
Normal file
30
templates/domain.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block main %}
|
||||
<main id="center">
|
||||
<img src="/assets/img/logo.png" id="logo">
|
||||
<p style="text-align: center;">You are logged in as {{ user.username }}</p>
|
||||
<div id="login-line">
|
||||
<a href="/logout" id="submit-login" value="Logout">Logout</a>
|
||||
</div>
|
||||
{% if can_create_user %}
|
||||
<div>
|
||||
<h2>Create user</h2>
|
||||
<form action="/user" method="POST">
|
||||
<input type="hidden" name="domainname" value="{{ domain.name }}">
|
||||
<input type="text" name="username" placeholder="username">
|
||||
<input type="password" name="password" placeholder="password">
|
||||
<button type="submit" class="button is-info">Create</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<h2>Users on {{ domain.name }}</h2>
|
||||
<ul>
|
||||
{% for user in users %}
|
||||
<li>{{ user.mail }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
{% if can_create_domain %}
|
||||
<div>
|
||||
<h2>Create domain</h2>
|
||||
<form action="/domains" method="POST">
|
||||
<form action="/domain" method="POST">
|
||||
<input type="text" name="domainname" placeholder="example.com">
|
||||
<button type="submit" class="button is-info">Create</button>
|
||||
</form>
|
||||
|
|
|
|||
Loading…
Reference in a new issue