User comments
All checks were successful
Rust / Test (push) Successful in 6m17s
Rust / Rustfmt (push) Successful in 21s
Rust / Clippy (push) Successful in 1m37s
Rust / Code coverage (push) Successful in 5m5s

This commit is contained in:
Alphonse Paix
2025-10-08 14:23:43 +02:00
parent 8a5605812c
commit ef9f860da2
21 changed files with 316 additions and 2961 deletions

View File

@@ -2,6 +2,8 @@ use chrono::{DateTime, Utc};
use uuid::Uuid;
pub struct CommentEntry {
pub user_id: Option<Uuid>,
pub username: Option<String>,
pub comment_id: Uuid,
pub post_id: Uuid,
pub author: Option<String>,

View File

@@ -3,6 +3,7 @@ use uuid::Uuid;
pub struct PostEntry {
pub post_id: Uuid,
pub author_id: Uuid,
pub author: String,
pub title: String,
pub content: String,

View File

@@ -27,6 +27,7 @@ pub struct CommentForm {
pub author: Option<String>,
pub content: String,
pub idempotency_key: String,
pub user_id: Option<Uuid>,
}
#[tracing::instrument(name = "Posting new comment", skip_all, fields(post_id = %post_id))]
@@ -51,9 +52,15 @@ pub async fn post_comment(
}
};
insert_comment(&mut transaction, post_id, form.author, form.content)
.await
.context("Could not insert comment into database.")?;
insert_comment(
&mut transaction,
post_id,
form.author,
form.user_id,
form.content,
)
.await
.context("Could not insert comment into database.")?;
let template = HtmlTemplate(MessageTemplate::success(
"Your comment has been posted.".into(),
@@ -75,20 +82,25 @@ async fn insert_comment(
transaction: &mut Transaction<'static, Postgres>,
post_id: Uuid,
author: Option<String>,
user_id: Option<Uuid>,
content: String,
) -> Result<Uuid, sqlx::Error> {
let author = author
.filter(|s| !s.trim().is_empty())
.map(|s| s.trim().to_string());
let author = if user_id.is_some() {
None
} else {
author
.filter(|s| !s.trim().is_empty())
.map(|s| s.trim().to_string())
};
let content = content.trim();
let comment_id = Uuid::new_v4();
tracing::Span::current().record("comment_id", comment_id.to_string());
let query = sqlx::query!(
"
INSERT INTO comments (comment_id, post_id, author, content)
VALUES ($1, $2, $3, $4)
INSERT INTO comments (user_id, comment_id, post_id, author, content)
VALUES ($1, $2, $3, $4, $5)
",
user_id,
comment_id,
post_id,
author,
@@ -177,22 +189,35 @@ pub async fn get_comments_page_for_post(
page: i64,
) -> Result<Vec<CommentEntry>, sqlx::Error> {
let offset = (page - 1) * COMMENTS_PER_PAGE;
let comments = sqlx::query_as!(
let mut comments = sqlx::query_as!(
CommentEntry,
"
SELECT comment_id, post_id, author, content, published_at
FROM comments
WHERE post_id = $1
ORDER BY published_at DESC
r#"
SELECT c.user_id as "user_id?", u.username as "username?", c.comment_id, c.post_id, c.author, c.content, c.published_at
FROM comments c
LEFT JOIN users u ON c.user_id = u.user_id AND c.user_id IS NOT NULL
WHERE c.post_id = $1
ORDER BY c.published_at DESC
LIMIT $2
OFFSET $3
",
"#,
post_id,
COMMENTS_PER_PAGE,
offset
)
.fetch_all(connection_pool)
.await?;
for comment in comments.iter_mut() {
if let Some(user_id) = comment.user_id {
let record = sqlx::query!(
"SELECT username, full_name FROM users WHERE user_id = $1",
user_id
)
.fetch_one(connection_pool)
.await?;
let author = record.full_name.unwrap_or(record.username);
comment.author = Some(author);
}
}
Ok(comments)
}
@@ -214,13 +239,14 @@ pub async fn get_comments_page(
let offset = (page - 1) * COMMENTS_PER_PAGE;
let comments = sqlx::query_as!(
CommentEntry,
"
SELECT comment_id, post_id, author, content, published_at
FROM comments
r#"
SELECT c.user_id as "user_id?", u.username as "username?", c.comment_id, c.post_id, c.author, c.content, c.published_at
FROM comments c
LEFT JOIN users u ON c.user_id = u.user_id AND c.user_id IS NOT NULL
ORDER BY published_at DESC
LIMIT $1
OFFSET $2
",
"#,
COMMENTS_PER_PAGE,
offset
)

View File

@@ -77,7 +77,7 @@ async fn get_posts(
sqlx::query_as!(
PostEntry,
r#"
SELECT p.post_id, u.username AS author, p.title, p.content, p.published_at
SELECT p.post_id, p.author_id, u.username AS author, p.title, p.content, p.published_at
FROM posts p
LEFT JOIN users u ON p.author_id = u.user_id
ORDER BY p.published_at DESC
@@ -99,7 +99,7 @@ pub async fn get_posts_page(
sqlx::query_as!(
PostEntry,
r#"
SELECT p.post_id, u.username AS author, p.title, p.content, p.published_at
SELECT p.post_id, p.author_id, u.username AS author, p.title, p.content, p.published_at
FROM posts p
LEFT JOIN users u ON p.author_id = u.user_id
ORDER BY p.published_at DESC
@@ -197,7 +197,7 @@ pub async fn see_post(
if let Some(post) = get_post_data(&connection_pool, post_id)
.await
.context(format!("Failed to fetch post #{}", post_id))
.context(format!("Failed to fetch post #{}.", post_id))
.map_err(AppError::unexpected_page)?
{
let post_html = post
@@ -206,16 +206,20 @@ pub async fn see_post(
let current_page = 1;
let comments_count = get_comments_count_for_post(&connection_pool, post_id)
.await
.context("Could not fetch comment count")?;
.context("Could not fetch comment count.")?;
let max_page = get_max_page(comments_count, COMMENTS_PER_PAGE);
let comments = get_comments_page_for_post(&connection_pool, post_id, 1)
.await
.context("Failed to fetch latest comments")?;
.context("Failed to fetch latest comments.")?;
let idempotency_key = Uuid::new_v4().to_string();
let session_user_id = session
.get_user_id()
.await
.context("Could not check for session user id.")?;
let session_username = session
.get_username()
.await
.context("Could not check for session username")?;
.context("Could not check for session username.")?;
let template = HtmlTemplate(PostTemplate {
post,
post_html,
@@ -224,6 +228,7 @@ pub async fn see_post(
current_page,
max_page,
comments_count,
session_user_id,
session_username,
});
Ok(template.into_response())
@@ -252,7 +257,7 @@ async fn get_post_data(
sqlx::query_as!(
PostEntry,
r#"
SELECT p.post_id, u.username AS author, p.title, p.content, p.published_at
SELECT p.post_id, p.author_id, u.username AS author, p.title, p.content, p.published_at
FROM posts p
LEFT JOIN users u ON p.author_id = u.user_id
WHERE p.post_id = $1

View File

@@ -299,7 +299,7 @@ async fn fetch_user_posts(
sqlx::query_as!(
PostEntry,
r#"
SELECT u.username as author, p.post_id, p.title, p.content, p.published_at
SELECT p.author_id, u.username as author, p.post_id, p.title, p.content, p.published_at
FROM posts p
INNER JOIN users u ON p.author_id = u.user_id
WHERE p.author_id = $1

View File

@@ -127,6 +127,7 @@ pub struct PostTemplate {
pub current_page: i64,
pub max_page: i64,
pub comments_count: i64,
pub session_user_id: Option<Uuid>,
pub session_username: Option<String>,
}