The book detail page exposed server internals and unusable controls to everyday users: it now computes and renders the book's absolute on-disk location, and gates all of it behind the admin role. - The page handler resolves library folder + relative path (verified with os.Stat; falls back to the relative path when the file is not found on disk) into the new MediaDetail.FileLocation field - only for admins, so the absolute path never leaves the server for regular users. This also makes it possible to locate sparse entries whose metadata rows are largely blank. - The Metadata grid gains a full-width, monospace, click-selectable Location row (admins only). - The Edit button and the MetadataEditorModal markup render only for admins. The modal drives admin-only endpoints (metadata PUT, rescan, reset), so non-admins previously saw a button and a form that could only ever fail with 403s.
30 lines
1.1 KiB
Go
30 lines
1.1 KiB
Go
package handlers
|
|
|
|
import "bookhoard/internal/database"
|
|
|
|
// MediaDetail embeds database.MediaItems for complete book metadata
|
|
// No field duplication - template gets direct access to all database fields
|
|
type MediaDetail struct {
|
|
database.MediaItems // Embedded - ALL book fields available
|
|
|
|
// Absolute on-disk location (library folder + relative path), resolved by
|
|
// the page handler so the UI can show where the file lives.
|
|
FileLocation string `json:"file_location"`
|
|
|
|
// User-specific data
|
|
Rating *database.MediaRatings `json:"rating,omitempty"`
|
|
Collections []database.Collections `json:"collections"`
|
|
ReadingProgress *database.ReadingProgress `json:"reading_progress,omitempty"`
|
|
|
|
// Conflict data (if exists)
|
|
ActiveConflict *ConflictDetailResponse `json:"active_conflict,omitempty"`
|
|
|
|
// Computed counts
|
|
NotesCount int `json:"notes_count"`
|
|
HighlightsCount int `json:"highlights_count"`
|
|
|
|
// Deleted-annotation history (tombstoned rows, newest first) — the book
|
|
// page's "recently deleted" list with restore/permanent-delete actions.
|
|
DeletedAnnotations []DeletedAnnotationResponse `json:"deleted_annotations"`
|
|
}
|