Session data to change views

This commit is contained in:
Daniel Flanagan 2023-11-21 14:41:52 -06:00
parent 6579332013
commit 3f0fa57695
Signed by: lytedev
GPG key ID: 5B2020A0F9921EF4
4 changed files with 56 additions and 33 deletions

View file

@ -2,7 +2,10 @@
// feather icons // feather icons
pub const FEATHER_ICON_USER_PLUS: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user-plus"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><line x1="20" y1="8" x2="20" y2="14"></line><line x1="23" y1="11" x2="17" y2="11"></line></svg>"#; pub const FEATHER_ICON_USER_PLUS: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user-plus"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><line x1="20" y1="8" x2="20" y2="14"></line><line x1="23" y1="11" x2="17" y2="11"></line></svg>"#;
#[allow(dead_code)]
pub const FEATHER_ICON_LAYOUT: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layout"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line></svg>"#; pub const FEATHER_ICON_LAYOUT: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layout"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line></svg>"#;
pub const FEATHER_ICON_LOGIN: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-in"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>"#; pub const FEATHER_ICON_LOGIN: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-log-in"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>"#;
pub const FEATHER_ICON_USER: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>"#;
// pub const FEATHER_ICON_: &str = r#""#;

View file

@ -1,8 +1,10 @@
use axum_login::AuthSession;
use maud::{html, Markup, PreEscaped, DOCTYPE}; use maud::{html, Markup, PreEscaped, DOCTYPE};
use crate::feather_icons; use crate::{feather_icons, state};
pub fn header() -> Markup { pub fn header(sess: &AuthSession<state::State>) -> Markup {
let is_logged_in = sess.user.is_some();
html! { html! {
(DOCTYPE) (DOCTYPE)
head { head {
@ -27,13 +29,24 @@ pub fn header() -> Markup {
// (PreEscaped(FEATHER_ICON_LAYOUT)) // (PreEscaped(FEATHER_ICON_LAYOUT))
// "Dashboard" // "Dashboard"
// } // }
a href="/register" preload="" { @if is_logged_in {
(PreEscaped(feather_icons::FEATHER_ICON_USER_PLUS)) a href="/account" preload="" {
"Register" (PreEscaped(feather_icons::FEATHER_ICON_USER))
} "Account"
a href="/login" preload="" { }
(PreEscaped(feather_icons::FEATHER_ICON_LOGIN)) a href="/app" preload="" {
"Login" (PreEscaped(feather_icons::FEATHER_ICON_LAYOUT))
"Dashboard"
}
} @else {
a href="/register" preload="" {
(PreEscaped(feather_icons::FEATHER_ICON_USER_PLUS))
"Register"
}
a href="/login" preload="" {
(PreEscaped(feather_icons::FEATHER_ICON_LOGIN))
"Login"
}
} }
} }
} }

View file

@ -114,7 +114,7 @@ where
{ {
let password_bytes = password.as_ref().as_bytes(); let password_bytes = password.as_ref().as_bytes();
let current = PasswordHash::new(current_digest.as_ref())?; let current = PasswordHash::new(current_digest.as_ref())?;
Ok(Argon2::default().verify_password(password_bytes, &current)?) Argon2::default().verify_password(password_bytes, &current)
} }
impl user::ActiveModel {} impl user::ActiveModel {}
@ -170,18 +170,16 @@ impl AuthnBackend for state::State {
type Error = AppError; type Error = AppError;
async fn authenticate(&self, l: Self::Credentials) -> Result<Option<Self::User>, Self::Error> { async fn authenticate(&self, l: Self::Credentials) -> Result<Option<Self::User>, Self::Error> {
match User::find() Ok(User::find()
.filter(user::Column::Username.eq(l.username)) .filter(user::Column::Username.eq(l.username))
// TODO: will this have index problems since I'm searching over the password digest? // TODO: will this have index problems since I'm searching over the password digest?
.one(&self.db) .one(&self.db)
.await? .await?
{ .filter(|u| {
Some(user) => match password_verify(&l.password, &user.password_digest) { password_verify(&l.password, &u.password_digest)
Ok(()) => Ok(Some(user)), .ok()
Err(e) => Err(e.into()), .is_some()
}, }))
None => Ok(None),
}
} }
async fn get_user(&self, user_id: &UserId<Self>) -> Result<Option<Self::User>, Self::Error> { async fn get_user(&self, user_id: &UserId<Self>) -> Result<Option<Self::User>, Self::Error> {

View file

@ -10,6 +10,7 @@ use axum::{
response::{Html, IntoResponse}, response::{Html, IntoResponse},
}; };
use axum_csrf::CsrfToken; use axum_csrf::CsrfToken;
use axum_login::AuthSession;
use maud::html; use maud::html;
use sea_orm::EntityTrait; use sea_orm::EntityTrait;
use tracing::instrument; use tracing::instrument;
@ -24,11 +25,15 @@ where
type AppRes = Result<(StatusCode, Html<String>), AppError>; type AppRes = Result<(StatusCode, Html<String>), AppError>;
#[instrument] pub async fn index(sess: AuthSession<state::State>) -> Html<String> {
pub async fn index() -> Html<String> { let is_logged_in = sess.user.is_some();
// let username = sess
// .user
// .map(|u| u.username)
// .unwrap_or_else(|| "N/A".to_owned());
Html( Html(
html! { html! {
(header()) (header(&sess))
main class="prose" { main class="prose" {
h1 { "Manage live lyrics and music displays" } h1 { "Manage live lyrics and music displays" }
p { "Stop struggling to share the same messy set of PowerPoint files or Google Presentations. Make editing and controlling your live lyrics and music displays easy and simple." } p { "Stop struggling to share the same messy set of PowerPoint files or Google Presentations. Make editing and controlling your live lyrics and music displays easy and simple." }
@ -41,8 +46,12 @@ pub async fn index() -> Html<String> {
li { "Lightweight and fast" } li { "Lightweight and fast" }
} }
section class="flex gap" { section class="flex gap" {
a href="/register" class="button bg-primary" { "Try now" } @if is_logged_in {
a class="button" href="/login" { "Login" } a href="/app" class="button bg-primary" { "Open app" }
} @else {
a href="/register" class="button bg-primary" { "Try now" }
a class="button" href="/login" { "Login" }
}
} }
} }
(footer()) (footer())
@ -51,11 +60,11 @@ pub async fn index() -> Html<String> {
) )
} }
pub async fn register(t: CsrfToken) -> impl IntoResponse { pub async fn register(sess: AuthSession<state::State>, t: CsrfToken) -> impl IntoResponse {
csrf(t, |token| { csrf(t, move |token| {
Html( Html(
html! { html! {
(header()) (header(&sess))
main class="prose" { main class="prose" {
h1 { "Register an account" } h1 { "Register an account" }
form method="post" { form method="post" {
@ -79,11 +88,11 @@ pub async fn register(t: CsrfToken) -> impl IntoResponse {
.await .await
} }
pub async fn login(t: CsrfToken) -> impl IntoResponse { pub async fn login(sess: AuthSession<state::State>, t: CsrfToken) -> impl IntoResponse {
csrf(t, |token| { csrf(t, move |token| {
Html( Html(
html! { html! {
(header()) (header(&sess))
main class="prose" { main class="prose" {
h1 { "Login" } h1 { "Login" }
form method="post" { form method="post" {
@ -107,20 +116,20 @@ pub async fn login(t: CsrfToken) -> impl IntoResponse {
.await .await
} }
pub async fn all_users(State(s): State<state::State>) -> AppRes { pub async fn all_users(sess: AuthSession<state::State>, State(s): State<state::State>) -> AppRes {
let users: Vec<user::Model> = User::find().all(&s.db).await?; let users: Vec<user::Model> = User::find().all(&s.db).await?;
Ok(( Ok((
StatusCode::OK, StatusCode::OK,
Html( Html(
html! { html! {
(header()) (header(&sess))
main class="prose" { main class="prose" {
h1 { "Users" } h1 { "Users" }
ul { ul {
@if users.is_empty() { @if users.is_empty() {
li { "It looks like there are no users yet!" } li { "It looks like there are no users yet!" }
} else { } @else {
@for u in users { @for u in users {
li { li {
(u.username) (u.username)