diff --git a/src/db/interface.rs b/src/db/interface.rs index baccc60..ca84fd9 100644 --- a/src/db/interface.rs +++ b/src/db/interface.rs @@ -67,12 +67,11 @@ pub trait DatabaseInterface: Clone + Send + Sync + 'static { &mut self, user: User, ) -> Result, BoxedError>; - #[expect(unused)] - async fn try_create_user( + fn try_create_user( &mut self, new_user: User, current_user: &User, - ) -> Result, BoxedError>; + ) -> impl Future, BoxedError>> + Send; fn list_all_domains(&self) -> impl Future, BoxedError>> + Send; #[expect(unused)] diff --git a/src/db/memory.rs b/src/db/memory.rs index 83c3178..e170db0 100644 --- a/src/db/memory.rs +++ b/src/db/memory.rs @@ -91,7 +91,6 @@ impl DatabaseInterface for MemoryDatabase { // // TODO: for now we don't allow creating service users manually // so we assume there's a domain provided - // TODO: restrict user creation on non-declared domains let Some(new_user_domain) = &new_user.domain else { return Ok(Err(UserCreationError::Permissions)); }; diff --git a/src/http/mod.rs b/src/http/mod.rs index 9cd0a94..def0f22 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -19,6 +19,7 @@ mod login; mod logout; mod session; use session::HttpSessionManager; +mod user; impl AxumListener for Listener { type Io = AbstractStreamKind; @@ -102,6 +103,7 @@ pub async fn http_listen(listener: Listener, db: Database< .route("/logout", get(logout::logout)) .route("/domain/{domain}", get(domain::get_domain)) .route("/domain", post(domain::create_domain)) + .route("/user", post(user::create_user)) .with_state(HttpState::new(db)); axum::serve(listener, app).await.unwrap(); diff --git a/src/http/user.rs b/src/http/user.rs new file mode 100644 index 0000000..d6eb054 --- /dev/null +++ b/src/http/user.rs @@ -0,0 +1,49 @@ +use axum::extract::{Form, State}; +use axum::response::{IntoResponse, Redirect, Response}; +use axum_extra::extract::cookie::CookieJar; +use serde::Deserialize; + +use crate::db::{DatabaseInterface, Role, User}; +use crate::http::HttpState; +use crate::http::login::login_page; + +#[derive(Clone, Debug, Deserialize)] +pub struct UserCreationForm { + pub username: String, + pub domain: String, + pub password: String, +} + +pub async fn create_user( + State(mut state): State>, + cookies: CookieJar, + Form(form): Form, +) -> Response { + let Some(session) = state.sessions.get_session(&cookies) else { + return login_page(State(state), None).await.into_response(); + }; + + // let domain = form.domain; + // let op = Operation::CreateUser(domain.clone()); + // if !session.user.can_perform(&op) { + // return format!("Not authorized to create a new user on domain {domain}").into_response() + // } + + let new_user = User { + mail: format!("{}@{}", form.username, form.domain), + username: form.username.clone(), + domain: Some(form.domain.clone()), + password: form.password, + role: Role::User, + }; + + match state.db.try_create_user(new_user, &session.user).await { + Ok(Ok(())) => Redirect::to(&format!("/domain/{}", form.domain)).into_response(), + Ok(Err(e)) => format!( + "Failed to create user {} on domain {}: {}", + form.username, form.domain, e + ) + .into_response(), + Err(e) => format!("Database error: {e}").into_response(), + } +} diff --git a/templates/domain.html b/templates/domain.html index a5c46a4..758ad65 100644 --- a/templates/domain.html +++ b/templates/domain.html @@ -10,7 +10,7 @@

Create user

- +