proper layout
This commit is contained in:
@@ -63,7 +63,14 @@
|
|||||||
<a href="/" class="btn btn-ghost btn-sm">Home</a>
|
<a href="/" class="btn btn-ghost btn-sm">Home</a>
|
||||||
<a href="/about" class="btn btn-ghost btn-sm">About</a>
|
<a href="/about" class="btn btn-ghost btn-sm">About</a>
|
||||||
<a href="/blog" class="btn btn-ghost btn-sm">Blog</a>
|
<a href="/blog" class="btn btn-ghost btn-sm">Blog</a>
|
||||||
|
{% if logged_in_admin %}
|
||||||
|
<a href="/admin/dashboard" class="btn btn-ghost btn-sm">Dashboard</a>
|
||||||
|
<form method="post" action="/admin/logout">
|
||||||
|
<button type="submit" class="btn btn-ghost btn-sm">Logout</button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
<a href="/admin/login" class="btn btn-ghost btn-sm">Admin</a>
|
<a href="/admin/login" class="btn btn-ghost btn-sm">Admin</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<div class="dropdown dropdown-end md:hidden">
|
<div class="dropdown dropdown-end md:hidden">
|
||||||
@@ -78,7 +85,14 @@
|
|||||||
<a href="/" class="btn btn-ghost btn-sm justify-start">Home</a>
|
<a href="/" class="btn btn-ghost btn-sm justify-start">Home</a>
|
||||||
<a href="/about" class="btn btn-ghost btn-sm justify-start">About</a>
|
<a href="/about" class="btn btn-ghost btn-sm justify-start">About</a>
|
||||||
<a href="/blog" class="btn btn-ghost btn-sm justify-start">Blog</a>
|
<a href="/blog" class="btn btn-ghost btn-sm justify-start">Blog</a>
|
||||||
|
{% if logged_in_admin %}
|
||||||
|
<a href="/admin/dashboard" class="btn btn-ghost btn-sm justify-start">Dashboard</a>
|
||||||
|
<form method="post" action="/admin/logout">
|
||||||
|
<button type="submit" class="btn btn-ghost btn-sm w-full justify-start">Logout</button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
<a href="/admin/login" class="btn btn-ghost btn-sm justify-start">Admin</a>
|
<a href="/admin/login" class="btn btn-ghost btn-sm justify-start">Admin</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown dropdown-end">
|
<div class="dropdown dropdown-end">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use std::sync::OnceLock;
|
|||||||
use time::Duration as TimeDuration;
|
use time::Duration as TimeDuration;
|
||||||
|
|
||||||
pub static EMAIL_DOMAIN_RE: OnceLock<Regex> = OnceLock::new();
|
pub static EMAIL_DOMAIN_RE: OnceLock<Regex> = OnceLock::new();
|
||||||
const AUTH_COOKIE: &str = "auth_token";
|
pub(crate) const AUTH_COOKIE: &str = "auth_token";
|
||||||
|
|
||||||
fn get_allow_email_domain_re() -> &'static Regex {
|
fn get_allow_email_domain_re() -> &'static Regex {
|
||||||
EMAIL_DOMAIN_RE.get_or_init(|| {
|
EMAIL_DOMAIN_RE.get_or_init(|| {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::{
|
|||||||
users::{self, LoginParams},
|
users::{self, LoginParams},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use axum_extra::extract::cookie::CookieJar;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use loco_rs::prelude::*;
|
use loco_rs::prelude::*;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
@@ -87,8 +88,27 @@ async fn article_by_id(ctx: &AppContext, id: Uuid) -> Result<blog_articles::Mode
|
|||||||
.ok_or_else(|| Error::NotFound)
|
.ok_or_else(|| Error::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn logged_in_admin(ctx: &AppContext, jar: &CookieJar) -> bool {
|
||||||
|
let Some(cookie) = jar.get(auth_controller::AUTH_COOKIE) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Ok(jwt_config) = ctx.config.get_jwt_config() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Ok(claims) = loco_rs::auth::jwt::JWT::new(&jwt_config.secret).validate(cookie.value())
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Ok(user) = users::Model::find_by_pid(&ctx.db, &claims.claims.pid).await else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
admin::is_admin(ctx, &user)
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn home(
|
async fn home(
|
||||||
|
jar: CookieJar,
|
||||||
ViewEngine(v): ViewEngine<TeraView>,
|
ViewEngine(v): ViewEngine<TeraView>,
|
||||||
State(ctx): State<AppContext>,
|
State(ctx): State<AppContext>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
@@ -99,19 +119,32 @@ async fn home(
|
|||||||
.all(&ctx.db)
|
.all(&ctx.db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
format::view(&v, "home/index.html", json!({ "articles": articles }))
|
format::view(
|
||||||
|
&v,
|
||||||
|
"home/index.html",
|
||||||
|
json!({ "articles": articles, "logged_in_admin": logged_in_admin(&ctx, &jar).await }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn about(
|
async fn about(
|
||||||
|
jar: CookieJar,
|
||||||
ViewEngine(v): ViewEngine<TeraView>,
|
ViewEngine(v): ViewEngine<TeraView>,
|
||||||
State(ctx): State<AppContext>,
|
State(ctx): State<AppContext>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
format::view(&v, "pages/about.html", json!({ "page": about_page(&ctx).await? }))
|
format::view(
|
||||||
|
&v,
|
||||||
|
"pages/about.html",
|
||||||
|
json!({
|
||||||
|
"page": about_page(&ctx).await?,
|
||||||
|
"logged_in_admin": logged_in_admin(&ctx, &jar).await,
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn blog_index(
|
async fn blog_index(
|
||||||
|
jar: CookieJar,
|
||||||
ViewEngine(v): ViewEngine<TeraView>,
|
ViewEngine(v): ViewEngine<TeraView>,
|
||||||
State(ctx): State<AppContext>,
|
State(ctx): State<AppContext>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
@@ -121,11 +154,16 @@ async fn blog_index(
|
|||||||
.all(&ctx.db)
|
.all(&ctx.db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
format::view(&v, "blog/index.html", json!({ "articles": articles }))
|
format::view(
|
||||||
|
&v,
|
||||||
|
"blog/index.html",
|
||||||
|
json!({ "articles": articles, "logged_in_admin": logged_in_admin(&ctx, &jar).await }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn blog_show(
|
async fn blog_show(
|
||||||
|
jar: CookieJar,
|
||||||
ViewEngine(v): ViewEngine<TeraView>,
|
ViewEngine(v): ViewEngine<TeraView>,
|
||||||
Path(slug): Path<String>,
|
Path(slug): Path<String>,
|
||||||
State(ctx): State<AppContext>,
|
State(ctx): State<AppContext>,
|
||||||
@@ -142,12 +180,28 @@ async fn blog_show(
|
|||||||
active.view_count = Set(next_count);
|
active.view_count = Set(next_count);
|
||||||
let article = active.update(&ctx.db).await?;
|
let article = active.update(&ctx.db).await?;
|
||||||
|
|
||||||
format::view(&v, "blog/show.html", json!({ "article": article }))
|
format::view(
|
||||||
|
&v,
|
||||||
|
"blog/show.html",
|
||||||
|
json!({ "article": article, "logged_in_admin": logged_in_admin(&ctx, &jar).await }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn admin_login_page(ViewEngine(v): ViewEngine<TeraView>) -> Result<Response> {
|
async fn admin_login_page(
|
||||||
format::view(&v, "admin/login.html", json!({ "error": null }))
|
jar: CookieJar,
|
||||||
|
ViewEngine(v): ViewEngine<TeraView>,
|
||||||
|
State(ctx): State<AppContext>,
|
||||||
|
) -> Result<Response> {
|
||||||
|
if logged_in_admin(&ctx, &jar).await {
|
||||||
|
return format::redirect("/admin/dashboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
format::view(
|
||||||
|
&v,
|
||||||
|
"admin/login.html",
|
||||||
|
json!({ "error": null, "logged_in_admin": false }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
@@ -157,11 +211,19 @@ async fn admin_login(
|
|||||||
Form(params): Form<LoginParams>,
|
Form(params): Form<LoginParams>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
let Ok(user) = users::Model::find_by_email(&ctx.db, ¶ms.email).await else {
|
let Ok(user) = users::Model::find_by_email(&ctx.db, ¶ms.email).await else {
|
||||||
return format::view(&v, "admin/login.html", json!({ "error": "Invalid credentials" }));
|
return format::view(
|
||||||
|
&v,
|
||||||
|
"admin/login.html",
|
||||||
|
json!({ "error": "Invalid credentials", "logged_in_admin": false }),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if !user.verify_password(¶ms.password) || !admin::is_admin(&ctx, &user) {
|
if !user.verify_password(¶ms.password) || !admin::is_admin(&ctx, &user) {
|
||||||
return format::view(&v, "admin/login.html", json!({ "error": "Invalid credentials" }));
|
return format::view(
|
||||||
|
&v,
|
||||||
|
"admin/login.html",
|
||||||
|
json!({ "error": "Invalid credentials", "logged_in_admin": false }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let jwt_secret = ctx.config.get_jwt_config()?;
|
let jwt_secret = ctx.config.get_jwt_config()?;
|
||||||
|
|||||||
Reference in New Issue
Block a user