KOReader push (processBookAnnotations) accepts deleted_highlights and deleted_bookmarks arrays of dedup keys and tombstones the matching rows, after the upserts so a key present in both lists resolves to 'deleted' (the newer intent). Deletions remain soft: rows stay restorable from the history and echo to other devices as tombstones on their next pull. A stale device replay of the annotation cannot resurrect the tombstone — device pushes carry no modification timestamp, so the save loses to the delete. Absence from these arrays is never a delete, keeping category toggles safe. New annotation-history endpoints (annotation_history.go, media.go): GET /api/media-items/:id/annotations/deleted POST /api/media-items/:id/annotations/:annotationId/restore DELETE /api/media-items/:id/annotations/:annotationId All scoped to the authenticated user and the route's book; the DELETE is the permanent purge (annotation_type required in query or body). MediaDetail gains DeletedAnnotations, populated by the book page route via the shared DeletedAnnotationsForBook builder, so the server-rendered history ships with the page instead of requiring a client round-trip. Binding tests cover the plugin's exact wire shape and the legacy plugin case (arrays omitted -> empty).
26 lines
971 B
Go
26 lines
971 B
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
|
|
|
|
// 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"`
|
|
}
|