feat: user details
This commit is contained in:
parent
c91ea9234a
commit
89a4c0756d
|
|
@ -17,3 +17,24 @@ pub struct Admin;
|
||||||
pub struct Users<'a> {
|
pub struct Users<'a> {
|
||||||
pub users: &'a [gotrue_entity::User],
|
pub users: &'a [gotrue_entity::User],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "user_details.html")]
|
||||||
|
pub struct UserDetails<'a> {
|
||||||
|
pub user: &'a gotrue_entity::User,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any filter defined in the module `filters` is accessible in your template.
|
||||||
|
mod filters {
|
||||||
|
pub fn default<T: std::fmt::Display>(
|
||||||
|
input: &Option<T>,
|
||||||
|
default_val: &str,
|
||||||
|
) -> ::askama::Result<String> {
|
||||||
|
Ok(
|
||||||
|
input
|
||||||
|
.as_ref()
|
||||||
|
.map(|i| i.to_string())
|
||||||
|
.unwrap_or_else(|| default_val.to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::access_token::WebAccessToken;
|
use crate::access_token::WebAccessToken;
|
||||||
use crate::error::RenderError;
|
use crate::error::RenderError;
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use axum::extract::State;
|
use axum::extract::{Path, State};
|
||||||
use axum::response::Result;
|
use axum::response::Result;
|
||||||
use axum::{response::Html, routing::get, Router};
|
use axum::{response::Html, routing::get, Router};
|
||||||
|
|
||||||
|
|
@ -14,14 +14,15 @@ pub fn router() -> Router<AppState> {
|
||||||
.route("/login", get(login_handler))
|
.route("/login", get(login_handler))
|
||||||
.route("/admin", get(admin_handler))
|
.route("/admin", get(admin_handler))
|
||||||
.route("/admin/users", get(admin_users_handler))
|
.route("/admin/users", get(admin_users_handler))
|
||||||
|
.route("/admin/users/:user_id", get(admin_user_details_handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn home_handler(access_token: WebAccessToken) -> Result<Html<String>, RenderError> {
|
pub async fn home_handler(_access_token: WebAccessToken) -> Result<Html<String>, RenderError> {
|
||||||
let s = templates::Home {}.render()?;
|
let s = templates::Home {}.render()?;
|
||||||
Ok(Html(s))
|
Ok(Html(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn admin_handler(access_token: WebAccessToken) -> Result<Html<String>, RenderError> {
|
pub async fn admin_handler(_access_token: WebAccessToken) -> Result<Html<String>, RenderError> {
|
||||||
let s = templates::Admin {}.render()?;
|
let s = templates::Admin {}.render()?;
|
||||||
Ok(Html(s))
|
Ok(Html(s))
|
||||||
}
|
}
|
||||||
|
|
@ -46,6 +47,22 @@ pub async fn admin_users_handler(
|
||||||
Ok(Html(s))
|
Ok(Html(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn admin_user_details_handler(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
access_token: WebAccessToken,
|
||||||
|
Path(user_id): Path<String>,
|
||||||
|
) -> Result<Html<String>, RenderError> {
|
||||||
|
println!("---------- user_id: {}", user_id);
|
||||||
|
// http://localhost:3000/admin/users/3c093675-c4e0-4329-bd92-c1e8345afdd2
|
||||||
|
let users = state
|
||||||
|
.gotrue_client
|
||||||
|
.admin_user_details(&access_token.0, &user_id)
|
||||||
|
.await
|
||||||
|
.unwrap(); // TODO: handle error
|
||||||
|
let s = templates::UserDetails { user: &users }.render()?;
|
||||||
|
Ok(Html(s))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn login_handler() -> Result<Html<String>, RenderError> {
|
pub async fn login_handler() -> Result<Html<String>, RenderError> {
|
||||||
let s = templates::Login {}.render()?;
|
let s = templates::Login {}.render()?;
|
||||||
Ok(Html(s))
|
Ok(Html(s))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>User Detail</title>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>User Detail</h1>
|
||||||
|
<h2>{{ user.email|escape }}</h2>
|
||||||
|
<p>Phone: {{ user.phone|escape }}</p>
|
||||||
|
<p>Email Confirmed At: {{ user.email_confirmed_at|default("-") }}</p>
|
||||||
|
<p>Phone Confirmed At: {{ user.phone_confirmed_at|default("-")|escape }}</p>
|
||||||
|
<p>Last Sign In At: {{ user.last_sign_in_at|default("-")|escape }}</p>
|
||||||
|
<p>Created At: {{ user.created_at|escape }}</p>
|
||||||
|
<p>Updated At: {{ user.updated_at|escape }}</p>
|
||||||
|
|
||||||
|
|
||||||
|
<a href="/web/admin/users">Back to User List</a>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
<th>Id</th>
|
<th>Id</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Created At</th>
|
<th>Created At</th>
|
||||||
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
|
|
@ -16,6 +17,7 @@
|
||||||
<td>{{ user.id|escape }}</td>
|
<td>{{ user.id|escape }}</td>
|
||||||
<td>{{ user.email|escape }}</td>
|
<td>{{ user.email|escape }}</td>
|
||||||
<td>{{ user.created_at|escape }}</td>
|
<td>{{ user.created_at|escape }}</td>
|
||||||
|
<td><a href="/web/admin/users/{{ user.id }}" class="btn">Go</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,20 @@ impl Client {
|
||||||
to_gotrue_result(resp).await
|
to_gotrue_result(resp).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn admin_user_details(
|
||||||
|
&self,
|
||||||
|
access_token: &str,
|
||||||
|
user_id: &str, // uuid
|
||||||
|
) -> Result<User, GoTrueError> {
|
||||||
|
let resp = self
|
||||||
|
.client
|
||||||
|
.get(format!("{}/admin/users/{}", self.base_url, user_id))
|
||||||
|
.header("Authorization", format!("Bearer {}", access_token))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
to_gotrue_result(resp).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn admin_add_user(
|
pub async fn admin_add_user(
|
||||||
&self,
|
&self,
|
||||||
access_token: &str,
|
access_token: &str,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue