Edit profile and templates update
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use crate::authentication::AuthenticatedUser;
|
||||
use crate::routes::verify_password;
|
||||
use crate::templates::MessageTemplate;
|
||||
use crate::session_state::TypedSession;
|
||||
use crate::templates::{ErrorTemplate, MessageTemplate, UserEditTemplate};
|
||||
use crate::{
|
||||
authentication::Role,
|
||||
domain::{PostEntry, UserEntry},
|
||||
@@ -9,7 +11,7 @@ use crate::{
|
||||
};
|
||||
use anyhow::Context;
|
||||
use axum::{
|
||||
Form,
|
||||
Extension, Form,
|
||||
extract::{Path, State},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
@@ -17,9 +19,102 @@ use secrecy::{ExposeSecret, SecretString};
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn get_user_edit(
|
||||
Path(username): Path<String>,
|
||||
Extension(AuthenticatedUser {
|
||||
user_id,
|
||||
username: session_username,
|
||||
..
|
||||
}): Extension<AuthenticatedUser>,
|
||||
State(AppState {
|
||||
connection_pool, ..
|
||||
}): State<AppState>,
|
||||
) -> Result<Response, AppError> {
|
||||
if username != session_username {
|
||||
let template = HtmlTemplate(ErrorTemplate::Forbidden);
|
||||
return Ok(template.into_response());
|
||||
}
|
||||
let user = sqlx::query_as!(
|
||||
UserEntry,
|
||||
r#"
|
||||
SELECT user_id, username, role as "role: Role", full_name, bio, member_since
|
||||
FROM users
|
||||
WHERE user_id = $1
|
||||
"#,
|
||||
user_id
|
||||
)
|
||||
.fetch_one(&connection_pool)
|
||||
.await
|
||||
.context("Could not fetch user in database.")?;
|
||||
let template = HtmlTemplate(UserEditTemplate { user });
|
||||
Ok(template.into_response())
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct ProfilePath {
|
||||
pub struct EditProfileForm {
|
||||
username: String,
|
||||
full_name: String,
|
||||
bio: String,
|
||||
}
|
||||
|
||||
pub async fn put_user_edit(
|
||||
State(AppState {
|
||||
connection_pool, ..
|
||||
}): State<AppState>,
|
||||
session: TypedSession,
|
||||
Extension(AuthenticatedUser {
|
||||
user_id,
|
||||
username: session_username,
|
||||
..
|
||||
}): Extension<AuthenticatedUser>,
|
||||
Path(username): Path<String>,
|
||||
Form(form): Form<EditProfileForm>,
|
||||
) -> Result<Response, AppError> {
|
||||
if username != session_username {
|
||||
let template = HtmlTemplate(ErrorTemplate::Forbidden);
|
||||
return Ok(template.into_response());
|
||||
}
|
||||
let updated_username = form.username.trim();
|
||||
if updated_username != session_username
|
||||
&& sqlx::query!(
|
||||
"SELECT user_id FROM users WHERE username = $1",
|
||||
updated_username
|
||||
)
|
||||
.fetch_optional(&connection_pool)
|
||||
.await
|
||||
.context("Could not fetch users table.")?
|
||||
.is_some()
|
||||
{
|
||||
let template = HtmlTemplate(MessageTemplate::error(
|
||||
"The username is already taken.".into(),
|
||||
));
|
||||
return Ok(template.into_response());
|
||||
}
|
||||
let updated_full_name = form.full_name.trim();
|
||||
let bio = form.bio.trim();
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE users
|
||||
SET username = $1, full_name = $2, bio = $3
|
||||
WHERE user_id = $4
|
||||
",
|
||||
updated_username,
|
||||
updated_full_name,
|
||||
bio,
|
||||
user_id
|
||||
)
|
||||
.execute(&connection_pool)
|
||||
.await
|
||||
.context("Failed to apply changes.")
|
||||
.map_err(AppError::FormError)?;
|
||||
session
|
||||
.insert_username(updated_username.to_owned())
|
||||
.await
|
||||
.context("Could not update session username.")?;
|
||||
let template = HtmlTemplate(MessageTemplate::success(
|
||||
"Your profile has been updated.".into(),
|
||||
));
|
||||
Ok(template.into_response())
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Get users from database", skip(connection_pool))]
|
||||
@@ -144,12 +239,13 @@ pub async fn delete_user(
|
||||
Ok(template.into_response())
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Fetching user data", skip(connection_pool))]
|
||||
#[tracing::instrument(name = "Fetching user data", skip(connection_pool, session))]
|
||||
pub async fn user_profile(
|
||||
session: TypedSession,
|
||||
State(AppState {
|
||||
connection_pool, ..
|
||||
}): State<AppState>,
|
||||
Path(ProfilePath { username }): Path<ProfilePath>,
|
||||
Path(username): Path<String>,
|
||||
) -> Result<Response, AppError> {
|
||||
match fetch_user_data(&connection_pool, &username)
|
||||
.await
|
||||
@@ -159,7 +255,15 @@ pub async fn user_profile(
|
||||
let posts = fetch_user_posts(&connection_pool, &user.user_id)
|
||||
.await
|
||||
.context("Could not fetch user posts.")?;
|
||||
let template = HtmlTemplate(UserTemplate { user, posts });
|
||||
let session_username = session
|
||||
.get_username()
|
||||
.await
|
||||
.context("Could not fetch session username.")?;
|
||||
let template = HtmlTemplate(UserTemplate {
|
||||
user,
|
||||
session_username,
|
||||
posts,
|
||||
});
|
||||
Ok(template.into_response())
|
||||
}
|
||||
None => {
|
||||
|
||||
Reference in New Issue
Block a user