Skip to main content

max / makenotwork

2.0 KB · 71 lines History Blame Raw
1 use super::{DateTime, PgPool, Utc, Uuid};
2
3 #[derive(sqlx::FromRow)]
4 pub struct ImageRow {
5 pub id: Uuid,
6 pub community_id: Uuid,
7 pub s3_key: String,
8 pub content_type: String,
9 pub removed_at: Option<DateTime<Utc>>,
10 }
11
12 /// Fetch an image by ID (for serving). Carries `community_id` so the serve
13 /// handler can enforce the owning community's access policy.
14 #[tracing::instrument(skip_all)]
15 pub async fn get_image(pool: &PgPool, image_id: Uuid) -> Result<Option<ImageRow>, sqlx::Error> {
16 sqlx::query_as!(
17 ImageRow,
18 r#"SELECT id, community_id, s3_key, content_type,
19 removed_at AS "removed_at: chrono::DateTime<chrono::Utc>"
20 FROM images WHERE id = $1"#,
21 image_id,
22 )
23 .fetch_optional(pool)
24 .await
25 }
26
27 /// A removed image whose backing S3 object still needs to be purged.
28 #[derive(sqlx::FromRow)]
29 pub struct PendingPurgeImage {
30 pub id: Uuid,
31 pub s3_key: String,
32 }
33
34 /// List removed images whose S3 object has not been purged yet, oldest first.
35 /// Drives the background reconcile sweep; `limit` bounds one batch (S3's
36 /// batch-delete cap is 1000).
37 #[tracing::instrument(skip_all)]
38 pub async fn list_images_pending_s3_purge(
39 pool: &PgPool,
40 limit: i64,
41 ) -> Result<Vec<PendingPurgeImage>, sqlx::Error> {
42 sqlx::query_as!(
43 PendingPurgeImage,
44 "SELECT id, s3_key FROM images
45 WHERE removed_at IS NOT NULL AND s3_purged_at IS NULL
46 ORDER BY removed_at ASC
47 LIMIT $1",
48 limit,
49 )
50 .fetch_all(pool)
51 .await
52 }
53
54 /// Count images uploaded by a user in the last N seconds (rate limiting).
55 #[tracing::instrument(skip_all)]
56 pub async fn count_recent_uploads_by_user(
57 pool: &PgPool,
58 user_id: Uuid,
59 window_secs: i64,
60 ) -> Result<i64, sqlx::Error> {
61 sqlx::query_scalar!(
62 r#"SELECT COUNT(*) AS "count!" FROM images
63 WHERE uploader_id = $1
64 AND created_at > now() - make_interval(secs => $2::float8)"#,
65 user_id,
66 window_secs as f64,
67 )
68 .fetch_one(pool)
69 .await
70 }
71