feat: context menus, unified photo panel, tags, album trash and counters
- backend: deleting an album moves its photos to the trash without losing files (photos.album_id nullable, FK ON DELETE SET NULL, migration 000006; dropped S3 prefix delete); restore accepts an album target (album_required when the album is gone); user-scoped tags (000007) with GET /tags, POST/DELETE /photos/:id/tags, tags included in photo responses; GET /trash/count - frontend: right-click context menus for photos (grid + viewer) and albums (rail + overview); single shared PhotoPanel reused in viewer and gallery selection (not a copy); viewer download/delete moved to the panel 'Действия'; transparent compact viewer top bar; trash entry as last rail item with per-album photo counts and trash count; album rename/delete dialogs - openspec: sync lightroom-workspace-ui artifacts (specs photos/ui-workspace, design #24-30, tasks 9.17-9.24)
This commit is contained in:
@@ -150,11 +150,11 @@ func (s *Service) Delete(ctx context.Context, albumID, userID string) error {
|
||||
if role != roles.Owner {
|
||||
return httpx.Forbidden("forbidden", "only the owner can delete the album")
|
||||
}
|
||||
if err := s.store.Delete(ctx, a.ID); err != nil {
|
||||
if err := s.store.TrashPhotosByAlbum(ctx, a.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
if s.storage != nil {
|
||||
_ = s.storage.DeletePrefix(ctx, "albums/"+a.ID+"/")
|
||||
if err := s.store.Delete(ctx, a.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
s.hub.Publish(albumID, "album.deleted", map[string]string{"id": a.ID})
|
||||
return nil
|
||||
|
||||
@@ -107,3 +107,11 @@ func (s *Store) Delete(ctx context.Context, id string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TrashPhotosByAlbum soft-deletes all photos of an album so they can be restored
|
||||
// or permanently removed from the trash after the album is gone.
|
||||
func (s *Store) TrashPhotosByAlbum(ctx context.Context, albumID string) error {
|
||||
_, err := s.pool.Exec(ctx,
|
||||
`UPDATE photos SET deleted_at = now() WHERE album_id = $1 AND deleted_at IS NULL`, albumID)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user