feat: implement gallery feed with social features and SSE
- Cursor-based feed endpoint using v_feed view with hashtag filtering - Like toggle (INSERT ON CONFLICT), comments CRUD - Feed delta endpoint for SSE-driven incremental updates - SSE client with Page Visibility API (pause/reconnect) - Responsive photo/video grid with infinite scroll - Hashtag filter chips, lightbox modal with comments - Media file serving via tower-http ServeDir Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
72
backend/src/models/comment.rs
Normal file
72
backend/src/models/comment.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::Serialize;
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
pub struct Comment {
|
||||
pub id: Uuid,
|
||||
pub upload_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub body: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub deleted_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, sqlx::FromRow)]
|
||||
pub struct CommentDto {
|
||||
pub id: Uuid,
|
||||
pub upload_id: Uuid,
|
||||
pub user_id: Uuid,
|
||||
pub uploader_name: String,
|
||||
pub body: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl Comment {
|
||||
pub async fn create(
|
||||
pool: &PgPool,
|
||||
upload_id: Uuid,
|
||||
user_id: Uuid,
|
||||
body: &str,
|
||||
) -> Result<Self, sqlx::Error> {
|
||||
sqlx::query_as::<_, Self>(
|
||||
"INSERT INTO comment (upload_id, user_id, body) VALUES ($1, $2, $3) RETURNING *",
|
||||
)
|
||||
.bind(upload_id)
|
||||
.bind(user_id)
|
||||
.bind(body)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_for_upload(pool: &PgPool, upload_id: Uuid) -> Result<Vec<CommentDto>, sqlx::Error> {
|
||||
sqlx::query_as::<_, CommentDto>(
|
||||
"SELECT c.id, c.upload_id, c.user_id, u.display_name AS uploader_name, c.body, c.created_at
|
||||
FROM comment c
|
||||
JOIN \"user\" u ON u.id = c.user_id
|
||||
WHERE c.upload_id = $1 AND c.deleted_at IS NULL
|
||||
ORDER BY c.created_at ASC",
|
||||
)
|
||||
.bind(upload_id)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn find_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as::<_, Self>(
|
||||
"SELECT * FROM comment WHERE id = $1 AND deleted_at IS NULL",
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn soft_delete(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
|
||||
sqlx::query("UPDATE comment SET deleted_at = NOW() WHERE id = $1")
|
||||
.bind(id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user