diff --git a/Cargo.lock b/Cargo.lock index c7f84a05..7d84b00c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -344,6 +344,7 @@ dependencies = [ "tower-http", "tower-service", "tracing", + "tracing-subscriber", "uuid", ] diff --git a/admin_frontend/Cargo.toml b/admin_frontend/Cargo.toml index a35b6efc..cc8a44c3 100644 --- a/admin_frontend/Cargo.toml +++ b/admin_frontend/Cargo.toml @@ -25,3 +25,4 @@ tower-service = "0.3.2" tower-http = { version = "0.4.4", features = ["cors"] } tower = "0.4.13" tracing = "0.1.37" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } diff --git a/admin_frontend/dev.env b/admin_frontend/dev.env index 4e6f3d37..496e5b62 100644 --- a/admin_frontend/dev.env +++ b/admin_frontend/dev.env @@ -1,2 +1,3 @@ GOTRUE_URL=http://localhost:9998 REDIS_URL=redis://localhost:6380 +RUST_LOG=trace diff --git a/admin_frontend/src/main.rs b/admin_frontend/src/main.rs index beb1269c..5948eee9 100644 --- a/admin_frontend/src/main.rs +++ b/admin_frontend/src/main.rs @@ -16,6 +16,11 @@ async fn main() { // load from .env dotenv::dotenv().ok(); + // set up tracing + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .init(); + let gotrue_client = gotrue::api::Client::new( reqwest::Client::new(), &std::env::var("GOTRUE_URL").unwrap_or("http://gotrue:9999".to_string()), diff --git a/admin_frontend/src/models.rs b/admin_frontend/src/models.rs index 5c7ae5d4..87ae3743 100644 --- a/admin_frontend/src/models.rs +++ b/admin_frontend/src/models.rs @@ -6,6 +6,11 @@ pub struct LoginRequest { pub password: String, } +#[derive(Deserialize)] +pub struct AddUserRequest { + pub email: String, +} + #[derive(Serialize)] pub struct LoginResponse { pub access_token: String, diff --git a/admin_frontend/src/response.rs b/admin_frontend/src/response.rs index f09f480f..6bb32622 100644 --- a/admin_frontend/src/response.rs +++ b/admin_frontend/src/response.rs @@ -31,3 +31,12 @@ where Json(self).into_response() } } + +impl From for WebApiResponse +where + T: serde::Serialize, +{ + fn from(data: T) -> Self { + Self::new(data) + } +} diff --git a/admin_frontend/src/web_api.rs b/admin_frontend/src/web_api.rs index f5f95ea5..50c49c45 100644 --- a/admin_frontend/src/web_api.rs +++ b/admin_frontend/src/web_api.rs @@ -1,5 +1,7 @@ use crate::error::WebApiError; -use crate::session; +use crate::models::AddUserRequest; +use crate::response::WebApiResponse; +use crate::session::{self, UserSession}; use crate::{models::LoginRequest, AppState}; use axum::http::status; use axum::response::Result; @@ -7,12 +9,31 @@ use axum::Json; use axum::{extract::State, routing::post, Router}; use axum_extra::extract::cookie::Cookie; use axum_extra::extract::CookieJar; +use gotrue::params::AdminUserParams; +use gotrue_entity::User; pub fn router() -> Router { Router::new() // TODO .route("/login", post(login_handler)) .route("/logout", post(logout_handler)) + .route("/add_user", post(add_user_handler)) +} + +pub async fn add_user_handler( + State(state): State, + session: UserSession, + Json(param): Json, +) -> Result, WebApiError<'static>> { + let add_user_params = AdminUserParams { + email: param.email.to_owned(), + ..Default::default() + }; + let user = state + .gotrue_client + .admin_add_user(&session.access_token, &add_user_params) + .await?; + Ok(user.into()) } // TODO: Support OAuth2 login diff --git a/admin_frontend/templates/users.html b/admin_frontend/templates/users.html index c0039666..6d678ae9 100644 --- a/admin_frontend/templates/users.html +++ b/admin_frontend/templates/users.html @@ -29,26 +29,32 @@ document.getElementById('createUserBtn').addEventListener('click', function() { // Get the email from the user const email = prompt('Please enter the new user email:'); - - // TODO: Validate the email, if valid, send to server and update UI if (email) { - // Assuming you will use fetch API or another method to send the data to the server - // Example: - // fetch('/createUser', { - // method: 'POST', - // body: JSON.stringify({ email: email }), - // headers: { - // 'Content-Type': 'application/json', - // } - // }) - // .then(response => response.json()) - // .then(data => { - // // Update the UI as needed, e.g., add a new row to the table - // console.log('User created:', data); - // }) - // .catch((error) => { - // console.error('Error:', error); - // }); + fetch("/web-api/add_user", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email: email, + }), + }) + .then((response) => { + if (!response.ok) { + throw new Error('Network response was not ok' + response.statusText); + } + return response.json(); + }) + .then((data) => { + if (data.code === 0) { + window.location.href = "/web/admin/users/" + data.data.id; + } else { + throw new Error('Error creating user: ' + data.message); + } + }) + .catch((error) => { + console.error("Error:", error); + }); } }); diff --git a/libs/gotrue/src/params.rs b/libs/gotrue/src/params.rs index fb20bd34..2bc86b61 100644 --- a/libs/gotrue/src/params.rs +++ b/libs/gotrue/src/params.rs @@ -3,7 +3,7 @@ use std::collections::btree_map::BTreeMap; use gotrue_entity::{Factor, Identity}; use serde::{Deserialize, Serialize}; -#[derive(Default, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize)] pub struct AdminUserParams { pub aud: String, pub role: String,