Edit posts
Use fix routes for user profile edit handles to make it easier when user decides to change his username
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use crate::routes::{COMMENTS_PER_PAGE, get_max_page};
|
||||
use crate::templates::PostsPageDashboardTemplate;
|
||||
use crate::authentication::AuthenticatedUser;
|
||||
use crate::routes::{COMMENTS_PER_PAGE, Query, get_max_page};
|
||||
use crate::session_state::TypedSession;
|
||||
use crate::templates::{ErrorTemplate, MessageTemplate, PostsPageDashboardTemplate};
|
||||
use crate::{
|
||||
domain::PostEntry,
|
||||
routes::{
|
||||
AppError, Path, Query, get_comments_count_for_post, get_comments_page_for_post,
|
||||
not_found_html,
|
||||
AppError, Path, get_comments_count_for_post, get_comments_page_for_post, not_found_html,
|
||||
},
|
||||
startup::AppState,
|
||||
templates::{HtmlTemplate, PostListTemplate, PostTemplate, PostsTemplate},
|
||||
@@ -12,6 +13,7 @@ use crate::{
|
||||
use anyhow::Context;
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
Extension, Form,
|
||||
extract::State,
|
||||
response::{Html, IntoResponse, Redirect, Response},
|
||||
};
|
||||
@@ -118,17 +120,65 @@ pub async fn get_posts_count(connection_pool: &PgPool) -> Result<i64, sqlx::Erro
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct PostParams {
|
||||
pub struct EditPostForm {
|
||||
pub title: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Editing post", skip_all, fields(post_id = %post_id))]
|
||||
pub async fn update_post(
|
||||
State(AppState {
|
||||
connection_pool, ..
|
||||
}): State<AppState>,
|
||||
Extension(AuthenticatedUser { user_id, .. }): Extension<AuthenticatedUser>,
|
||||
Path(post_id): Path<Uuid>,
|
||||
Form(form): Form<EditPostForm>,
|
||||
) -> Result<Response, AppError> {
|
||||
let record = sqlx::query!("SELECT author_id FROM posts WHERE post_id = $1", post_id)
|
||||
.fetch_optional(&connection_pool)
|
||||
.await
|
||||
.context("Could not fetch post author.")?;
|
||||
match record {
|
||||
None => Ok(HtmlTemplate(ErrorTemplate::NotFound).into_response()),
|
||||
Some(record) if record.author_id == user_id => {
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE posts
|
||||
SET title = $1, content = $2 WHERE post_id = $3
|
||||
",
|
||||
form.title,
|
||||
form.content,
|
||||
post_id
|
||||
)
|
||||
.execute(&connection_pool)
|
||||
.await
|
||||
.context("Could not update post")?;
|
||||
Ok(HtmlTemplate(MessageTemplate::success(
|
||||
"Your changes have been saved.".into(),
|
||||
))
|
||||
.into_response())
|
||||
}
|
||||
_ => Ok(HtmlTemplate(ErrorTemplate::Forbidden).into_response()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct OriginQueryParam {
|
||||
origin: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Fetching post from database", skip(connection_pool, origin))]
|
||||
#[tracing::instrument(
|
||||
name = "Fetching post from database",
|
||||
skip(connection_pool, origin, session)
|
||||
)]
|
||||
|
||||
pub async fn see_post(
|
||||
session: TypedSession,
|
||||
State(AppState {
|
||||
connection_pool, ..
|
||||
}): State<AppState>,
|
||||
Path(post_id): Path<Uuid>,
|
||||
Query(PostParams { origin }): Query<PostParams>,
|
||||
Query(OriginQueryParam { origin }): Query<OriginQueryParam>,
|
||||
) -> Result<Response, AppError> {
|
||||
if let Some(origin) = origin {
|
||||
mark_email_as_opened(&connection_pool, origin).await?;
|
||||
@@ -140,7 +190,7 @@ pub async fn see_post(
|
||||
.context(format!("Failed to fetch post #{}", post_id))
|
||||
.map_err(AppError::unexpected_page)?
|
||||
{
|
||||
let post = post
|
||||
let post_html = post
|
||||
.to_html()
|
||||
.context("Could not render markdown with extension.")?;
|
||||
let current_page = 1;
|
||||
@@ -152,13 +202,19 @@ pub async fn see_post(
|
||||
.await
|
||||
.context("Failed to fetch latest comments")?;
|
||||
let idempotency_key = Uuid::new_v4().to_string();
|
||||
let session_username = session
|
||||
.get_username()
|
||||
.await
|
||||
.context("Could not check for session username")?;
|
||||
let template = HtmlTemplate(PostTemplate {
|
||||
post,
|
||||
post_html,
|
||||
comments,
|
||||
idempotency_key,
|
||||
current_page,
|
||||
max_page,
|
||||
comments_count,
|
||||
session_username,
|
||||
});
|
||||
Ok(template.into_response())
|
||||
} else {
|
||||
|
||||
@@ -19,21 +19,12 @@ 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>,
|
||||
pub async fn user_edit_form(
|
||||
Extension(AuthenticatedUser { user_id, .. }): 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#"
|
||||
@@ -52,25 +43,26 @@ pub async fn get_user_edit(
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct EditProfileForm {
|
||||
user_id: Uuid,
|
||||
username: String,
|
||||
full_name: String,
|
||||
bio: String,
|
||||
}
|
||||
|
||||
pub async fn put_user_edit(
|
||||
#[tracing::instrument(name = "Updating user profile", skip_all, fields(user_id = %form.user_id))]
|
||||
pub async fn update_user(
|
||||
State(AppState {
|
||||
connection_pool, ..
|
||||
}): State<AppState>,
|
||||
session: TypedSession,
|
||||
Extension(AuthenticatedUser {
|
||||
user_id,
|
||||
user_id: session_user_id,
|
||||
username: session_username,
|
||||
..
|
||||
}): Extension<AuthenticatedUser>,
|
||||
Path(username): Path<String>,
|
||||
Form(form): Form<EditProfileForm>,
|
||||
) -> Result<Response, AppError> {
|
||||
if username != session_username {
|
||||
if form.user_id != session_user_id {
|
||||
let template = HtmlTemplate(ErrorTemplate::Forbidden);
|
||||
return Ok(template.into_response());
|
||||
}
|
||||
@@ -101,7 +93,7 @@ pub async fn put_user_edit(
|
||||
updated_username,
|
||||
updated_full_name,
|
||||
bio,
|
||||
user_id
|
||||
form.user_id
|
||||
)
|
||||
.execute(&connection_pool)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user