fix: trash integrity for TypeFile nodes — file record soft-delete, correct preview/restore
This commit is contained in:
@@ -200,12 +200,25 @@ func (s *Service) Get(id string) (*Record, error) {
|
||||
return scanRecord(row)
|
||||
}
|
||||
|
||||
// ListByNode returns all files linked to a node.
|
||||
// ListByNode returns all active (non-trashed) files linked to a node.
|
||||
func (s *Service) ListByNode(nodeID string) ([]Record, error) {
|
||||
rows, err := s.db.Query(
|
||||
`SELECT id,node_id,filename,path,storage_mode,size,sha256,mime,
|
||||
created_at,updated_at,last_seen_at,missing
|
||||
FROM files WHERE node_id = ? ORDER BY created_at`, nodeID)
|
||||
FROM files WHERE node_id = ? AND missing != 1 ORDER BY created_at`, nodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
return scanRecords(rows)
|
||||
}
|
||||
|
||||
// ListTrashedByNode returns file records with missing=1 for a given node.
|
||||
func (s *Service) ListTrashedByNode(nodeID string) ([]Record, error) {
|
||||
rows, err := s.db.Query(
|
||||
`SELECT id,node_id,filename,path,storage_mode,size,sha256,mime,
|
||||
created_at,updated_at,last_seen_at,missing
|
||||
FROM files WHERE node_id = ? AND missing = 1 ORDER BY created_at`, nodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -545,6 +558,32 @@ func (s *Service) DeleteNodeAndChildren(nodeID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// trashRecord moves a file record's physical file to .verstak/trash/ and
|
||||
// marks the record as missing=1 so it can be restored later.
|
||||
func (s *Service) trashRecord(r Record) error {
|
||||
if r.StorageMode == "vault" {
|
||||
src, err := s.vaultPath(r.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
trashDir := filepath.Join(s.vaultRoot, ".verstak", "trash")
|
||||
if err := os.MkdirAll(trashDir, 0o750); err != nil {
|
||||
return err
|
||||
}
|
||||
dest := filepath.Join(trashDir, r.ID+"_"+r.Filename)
|
||||
if _, err := s.vaultPath(filepath.Join(".verstak", "trash", r.ID+"_"+r.Filename)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, statErr := os.Stat(src); os.IsNotExist(statErr) {
|
||||
// File already gone — keep the DB record as-is.
|
||||
} else if err := os.Rename(src, dest); err != nil {
|
||||
return fmt.Errorf("move to trash: %w", err)
|
||||
}
|
||||
}
|
||||
_, err := s.db.Exec("UPDATE files SET missing=1, updated_at=? WHERE id=?", now(), r.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Service) deleteFileRecords(nodeID string) error {
|
||||
records, err := s.ListByNode(nodeID)
|
||||
if err != nil {
|
||||
@@ -552,7 +591,7 @@ func (s *Service) deleteFileRecords(nodeID string) error {
|
||||
}
|
||||
var errs []string
|
||||
for _, r := range records {
|
||||
if err := s.DeleteToTrash(r.ID); err != nil {
|
||||
if err := s.trashRecord(r); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("file %s: %v", r.ID, err))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user