feat: add shadcn admin workspace

This commit is contained in:
2026-03-28 17:56:36 +08:00
parent ec96d91548
commit 178434d63e
41 changed files with 6153 additions and 16 deletions

View File

@@ -19,6 +19,8 @@ use crate::services::{ai, content};
static ADMIN_LOGGED_IN: AtomicBool = AtomicBool::new(false);
const FRONTEND_BASE_URL: &str = "http://localhost:4321";
const DEFAULT_ADMIN_USERNAME: &str = "admin";
const DEFAULT_ADMIN_PASSWORD: &str = "admin123";
#[derive(Deserialize)]
pub struct LoginForm {
@@ -397,15 +399,35 @@ fn render_admin(
format::view(&view_engine.0, template, Value::Object(context))
}
pub(crate) fn admin_username() -> String {
std::env::var("TERMI_ADMIN_USERNAME").unwrap_or_else(|_| DEFAULT_ADMIN_USERNAME.to_string())
}
pub(crate) fn admin_password() -> String {
std::env::var("TERMI_ADMIN_PASSWORD").unwrap_or_else(|_| DEFAULT_ADMIN_PASSWORD.to_string())
}
pub(crate) fn is_admin_logged_in() -> bool {
ADMIN_LOGGED_IN.load(Ordering::SeqCst)
}
pub(crate) fn set_admin_logged_in(value: bool) {
ADMIN_LOGGED_IN.store(value, Ordering::SeqCst);
}
pub(crate) fn validate_admin_credentials(username: &str, password: &str) -> bool {
username == admin_username() && password == admin_password()
}
pub(crate) fn check_auth() -> Result<()> {
if !ADMIN_LOGGED_IN.load(Ordering::SeqCst) {
if !is_admin_logged_in() {
return Err(Error::Unauthorized("Not logged in".to_string()));
}
Ok(())
}
pub async fn root() -> Result<impl IntoResponse> {
if ADMIN_LOGGED_IN.load(Ordering::SeqCst) {
if is_admin_logged_in() {
Ok(format::redirect("/admin"))
} else {
Ok(format::redirect("/admin/login"))
@@ -428,15 +450,15 @@ pub async fn login_page(
}
pub async fn login_submit(Form(form): Form<LoginForm>) -> Result<impl IntoResponse> {
if form.username == "admin" && form.password == "admin123" {
ADMIN_LOGGED_IN.store(true, Ordering::SeqCst);
if validate_admin_credentials(&form.username, &form.password) {
set_admin_logged_in(true);
return Ok(format::redirect("/admin"));
}
Ok(format::redirect("/admin/login?error=1"))
}
pub async fn logout() -> Result<impl IntoResponse> {
ADMIN_LOGGED_IN.store(false, Ordering::SeqCst);
set_admin_logged_in(false);
Ok(format::redirect("/admin/login"))
}