bug(blog): media removal is a placeholder — no backend endpoint, viewer button does nothing #747

Closed
opened 2026-07-20 19:58:26 +00:00 by spikerj · 1 comment
Owner

Follow-up from #745. The blog viewer's media "Confirm Removal" flow (now correctly owner-gated) ends in BlogEntryComponent.removeMedia(), which is a placeholder snackbar ("Media removed (placeholder)") — no backend call exists, and the backend has no endpoint to remove a single media item from a post (the only path is PUT posts/{id} replacing the whole media array, which regenerates ids and drops thumbnails/paths/comments).

Fix

Backend (spikersoft-backend):

  • New DELETE api/blog/posts/{postId}/media/{mediaId}[Authorize], owner-or-staff (same pattern as DeleteBlogPost/#745), soft delete: set the existing BlogMedia.IsDeleted/DeletedAt flags (file retention stays with the purger, matching the post-level retention model). Idempotent on repeat calls.
  • Filter IsDeleted media out of MapToResponseDto (alongside the existing quarantine filter).

Frontend (spikersoft-angular):

  • BlogService.removeMediaFromPost(postId, mediaId) + wire removeMedia() to it with real success/error snackbars; drop the placeholder string.

Repos: spikersoft-backend, spikersoft-angular

Follow-up from #745. The blog viewer's media "Confirm Removal" flow (now correctly owner-gated) ends in `BlogEntryComponent.removeMedia()`, which is a placeholder snackbar ("Media removed (placeholder)") — no backend call exists, and the backend has no endpoint to remove a single media item from a post (the only path is `PUT posts/{id}` replacing the whole media array, which regenerates ids and drops thumbnails/paths/comments). ## Fix Backend (spikersoft-backend): - New `DELETE api/blog/posts/{postId}/media/{mediaId}` — `[Authorize]`, owner-or-staff (same pattern as DeleteBlogPost/#745), **soft delete**: set the existing `BlogMedia.IsDeleted`/`DeletedAt` flags (file retention stays with the purger, matching the post-level retention model). Idempotent on repeat calls. - Filter `IsDeleted` media out of `MapToResponseDto` (alongside the existing quarantine filter). Frontend (spikersoft-angular): - `BlogService.removeMediaFromPost(postId, mediaId)` + wire `removeMedia()` to it with real success/error snackbars; drop the placeholder string. Repos: spikersoft-backend, spikersoft-angular
Author
Owner

Resolved and merged:

  • spikersoft-backend PR #437 (merged to master, 5139211a): new DELETE api/blog/posts/{postId}/media/{mediaId}[Authorize], owner-or-staff, idempotent soft delete via the existing BlogMedia.IsDeleted/DeletedAt flags (file retention stays with the purger, matching the post-level model). Soft-removed media is filtered from all responses, rejects new comments, and stops serving photograph-info.
  • spikersoft-angular PR #477 (merged to master, 0d1f269b): removeMedia() now calls the endpoint via BlogService.removeMediaFromPost with real success/error snackbars and a busy flag; the placeholder string is gone.

Closing.

Resolved and merged: - **spikersoft-backend PR #437** (merged to master, `5139211a`): new `DELETE api/blog/posts/{postId}/media/{mediaId}` — `[Authorize]`, owner-or-staff, idempotent **soft delete** via the existing `BlogMedia.IsDeleted`/`DeletedAt` flags (file retention stays with the purger, matching the post-level model). Soft-removed media is filtered from all responses, rejects new comments, and stops serving photograph-info. - **spikersoft-angular PR #477** (merged to master, `0d1f269b`): `removeMedia()` now calls the endpoint via `BlogService.removeMediaFromPost` with real success/error snackbars and a busy flag; the placeholder string is gone. Closing.
Sign in to join this conversation.