feat(podcasts): edit segregation — feed metadata is fetcher-owned (task 1.8)
D9/D10: users never edit podcast episode metadata. Three gates: - Generic edit endpoint (UpdateMediaItem) rejects source= 'podcast_episode' items with 400 — the next fetch refresh would clobber any edit anyway, and the fetcher is the sole metadata writer. - Write-to-file (MetadataWriter.WriteMetadataToFile) refuses podcast episodes for the same reason (tag write-back for downloaded episodes is a named Phase-4 item needing its own iTunes-tag mapping). - The book-detail page hides the admin Edit affordance for podcasts-type items (direct-URL visits), and the metadata-editor modal's field list has no podcast fields by construction (fixed templ field list) — episodes render read-only via /podcasts surfaces.
This commit is contained in:
1 parent
45b1152a15
commit
54d7d6e7a1
4 files changed
+17
-2
No files matched your search
@@ -1542,6 +1542,13 @@ func (mh *MediaHandler) UpdateMediaItem(c *echo.Context) error {
|
||||
return c.JSON(http.StatusNotFound, map[string]string{"error": "media item not found"})
|
||||
}
|
||||
|
||||
// Edit segregation (plan D10, task 1.8): podcast episodes are
|
||||
// fetcher-owned (D9 — the sole writer); the generic edit box would
|
||||
// clobber feed metadata that the next refresh overwrites anyway.
|
||||
if existing.Source == "podcast_episode" {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "podcast episodes are managed by their feed and cannot be edited here"})
|
||||
}
|
||||
|
||||
coverPath := existing.CoverImagePath.String
|
||||
coverUploaded := false
|
||||
|
||||
|
||||
@@ -110,6 +110,14 @@ func (w *MetadataWriter) WriteMetadataToFile(ctx context.Context, itemID uuid.UU
|
||||
return nil, fmt.Errorf("media item not found: %w", err)
|
||||
}
|
||||
|
||||
// Edit segregation (plan D10/D9, task 1.8): podcast episodes are
|
||||
// feed-managed; writing their metadata into the file would be
|
||||
// clobbered by the next download/refresh and violates the
|
||||
// fetcher's sole-writer rule.
|
||||
if item.Source == "podcast_episode" {
|
||||
return nil, fmt.Errorf("podcast episodes are managed by their feed; metadata write-to-file is not available")
|
||||
}
|
||||
|
||||
absPath, err := w.libraries.ResolveMediaPath(ctx, item.LibraryID, item.FilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot resolve library folder: %w", err)
|
||||
|
||||
@@ -176,7 +176,7 @@ templ BookDetail(user User, book handlers.MediaDetail, errorMessage string, tomb
|
||||
<span class="badge ml-1" style="background-color: var(--accent-muted); color: var(--accent);">{ book.NotesCount + book.HighlightsCount }</span>
|
||||
}
|
||||
</button>
|
||||
if user.Role == "admin" {
|
||||
if user.Role == "admin" && book.LibraryTypeName != "podcasts" {
|
||||
<button @click="showMetadataEditor()" class="btn btn-secondary px-5 py-2.5">
|
||||
@Icon("edit", "h-4 w-4")
|
||||
<span>Edit</span>
|
||||
|
||||
@@ -566,7 +566,7 @@ func BookDetail(user User, book handlers.MediaDetail, errorMessage string, tombs
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if user.Role == "admin" {
|
||||
if user.Role == "admin" && book.LibraryTypeName != "podcasts" {
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "<button @click=\"showMetadataEditor()\" class=\"btn btn-secondary px-5 py-2.5\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
|
||||
Reference in new issue
Block a user