Bulk delete, editable share links, gallery filter fix
ci / docker (push) Successful in 9s

- shift-click selects ranges in the gallery; selection bar gains
  'Delete N' with a single confirm (POST /api/photos/delete)
- PATCH /api/shares/{id}: allow_download and expiry editable in place,
  token and client feedback preserved
- Gallery: re-attach ResizeObserver via callback ref — after a filter
  with zero matches the gallery stayed blank at width 0
This commit is contained in:
2026-07-17 16:30:26 +02:00
parent 30d0b3064e
commit 5cb00f3ef0
7 changed files with 159 additions and 16 deletions
+29
View File
@@ -211,6 +211,35 @@ pub async fn delete(
Ok(Json(serde_json::json!({ "ok": true })))
}
#[derive(Deserialize)]
pub struct DeleteManyBody {
ids: Vec<Uuid>,
}
/// Bulk delete: photos vanish and their S3 cleanup jobs are enqueued in one
/// statement, same as album deletion.
pub async fn delete_many(
State(state): State<AppState>,
Json(body): Json<DeleteManyBody>,
) -> ApiResult<Json<serde_json::Value>> {
if body.ids.is_empty() {
return Err(ApiError::bad_request("ids must not be empty"));
}
let mut tx = state.db.begin().await?;
let jobs = sqlx::query(
"with deleted as (delete from photos where id = any($1) returning id)
insert into jobs (kind, payload)
select $2, jsonb_build_object('prefix', 'photos/' || id || '/')
from deleted",
)
.bind(&body.ids)
.bind(JobKind::DeleteS3Prefix.as_str())
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(Json(serde_json::json!({ "ok": true, "deleted": jobs.rows_affected() })))
}
pub async fn reprocess(
State(state): State<AppState>,
Path(photo_id): Path<Uuid>,