feat: implement configurable delete modes
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -25,6 +26,7 @@ type Server struct {
|
||||
WebDAVRoot string
|
||||
Allow string
|
||||
MultiRoot bool
|
||||
RemoveMode int
|
||||
}
|
||||
type fileInfo struct {
|
||||
Name string `json:"name"`
|
||||
@@ -156,6 +158,7 @@ func (s *Server) rename(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
func (s *Server) remove(w http.ResponseWriter, r *http.Request) {
|
||||
a := account(r, s)
|
||||
_ = r.ParseMultipartForm(16 << 20)
|
||||
_ = r.ParseForm()
|
||||
items := r.Form["filepath"]
|
||||
if len(items) == 0 {
|
||||
@@ -166,13 +169,38 @@ func (s *Server) remove(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "forbidden", 403)
|
||||
return
|
||||
}
|
||||
if e := s.Store.Remove(p); e != nil {
|
||||
if e := s.removePath(p); e != nil {
|
||||
http.Error(w, e.Error(), 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
writeJSON(w, map[string]any{"ok": true})
|
||||
}
|
||||
func (s *Server) removePath(p string) error {
|
||||
mode := s.RemoveMode
|
||||
if mode == 0 {
|
||||
mode = 1
|
||||
}
|
||||
t, ok := s.Store.(storage.Trashable)
|
||||
switch mode {
|
||||
case 1:
|
||||
if !ok {
|
||||
return fmt.Errorf("storage does not support system trash")
|
||||
}
|
||||
return t.Trash(p)
|
||||
case 2:
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.MoveToTrash(p, filepath.Join(home, ".chfs_trashbin"))
|
||||
case 3:
|
||||
return s.Store.Remove(p)
|
||||
default:
|
||||
return fmt.Errorf("invalid file.remove mode: %d", mode)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) exist(w http.ResponseWriter, r *http.Request) {
|
||||
p := strings.Trim(strings.ReplaceAll(r.URL.Query().Get("file"), "\\", "/"), "/")
|
||||
_, e := s.Store.Stat(p)
|
||||
|
||||
@@ -71,7 +71,7 @@ func ParseRules(values []string) (*Manager, error) {
|
||||
}
|
||||
}
|
||||
if m.Guest == nil {
|
||||
m.Guest = &Account{Mask: Read | Write}
|
||||
m.Guest = &Account{Mask: Read | Write | Delete}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@@ -91,6 +91,31 @@ func (m Multi) Remove(p string) error {
|
||||
}
|
||||
return r.Remove(rel)
|
||||
}
|
||||
|
||||
func (m Multi) Trash(p string) error {
|
||||
r, rel, ok := m.find(p)
|
||||
if !ok {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
return r.Trash(rel)
|
||||
}
|
||||
|
||||
func (m Multi) MoveToTrash(p, trashRoot string) error {
|
||||
r, rel, ok := m.find(p)
|
||||
if !ok {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
return r.MoveToTrash(rel, filepath.Join(trashRoot, m.RootName(r)))
|
||||
}
|
||||
|
||||
func (m Multi) RootName(r Local) string {
|
||||
for i := range m.Roots {
|
||||
if m.Roots[i].Root == r.Root {
|
||||
return m.Names[i]
|
||||
}
|
||||
}
|
||||
return "root"
|
||||
}
|
||||
func (m Multi) Rename(a, b string) error {
|
||||
ra, aa, oka := m.find(a)
|
||||
rb, bb, okb := m.find(b)
|
||||
|
||||
@@ -2,12 +2,20 @@ package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Bios-Marcel/wastebasket"
|
||||
)
|
||||
|
||||
type Trashable interface {
|
||||
Trash(path string) error
|
||||
MoveToTrash(path, trashRoot string) error
|
||||
}
|
||||
|
||||
type Storage interface {
|
||||
Stat(path string) (os.FileInfo, error)
|
||||
Open(path string) (*os.File, error)
|
||||
@@ -67,6 +75,33 @@ func (s Local) Remove(path string) error {
|
||||
}
|
||||
return os.RemoveAll(p)
|
||||
}
|
||||
|
||||
func (s Local) Trash(path string) error {
|
||||
p, e := s.real(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return wastebasket.Trash(p)
|
||||
}
|
||||
|
||||
func (s Local) MoveToTrash(path, trashRoot string) error {
|
||||
p, e := s.real(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
if e = os.MkdirAll(trashRoot, 0755); e != nil {
|
||||
return e
|
||||
}
|
||||
name := filepath.Base(p)
|
||||
target := filepath.Join(trashRoot, name)
|
||||
for i := 1; ; i++ {
|
||||
if _, e = os.Lstat(target); os.IsNotExist(e) {
|
||||
break
|
||||
}
|
||||
target = filepath.Join(trashRoot, fmt.Sprintf("%s.%d", name, i))
|
||||
}
|
||||
return os.Rename(p, target)
|
||||
}
|
||||
func (s Local) Rename(a, b string) error {
|
||||
pa, e := s.real(a)
|
||||
if e != nil {
|
||||
|
||||
Reference in New Issue
Block a user