[server][core] Empty trash

This commit is contained in:
Abhishek Shroff
2025-03-19 13:16:42 +05:30
parent d819d484ff
commit 2c92255805
8 changed files with 126 additions and 14 deletions

View File

@@ -21,9 +21,10 @@ func SetupCommand() *cobra.Command {
flags.StringP("user", "u", "phylum", "User")
cmd.AddCommand(
setupEmptyCommand(),
setupListCommand(),
setupSummaryCommand(),
setupRestoreCommand(),
setupSummaryCommand(),
)
return cmd

View File

@@ -0,0 +1,41 @@
package trash
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/shroff/phylum/server/internal/command/common"
"github.com/spf13/cobra"
)
func setupEmptyCommand() *cobra.Command {
cmd := cobra.Command{
Use: "empty",
Short: "Empty Trash",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
f := common.UserFileSystem(cmd)
printTrashSummary(f)
if noConfirm, err := cmd.Flags().GetBool("no-confirm"); err != nil {
fmt.Println("cannot read flag: " + err.Error())
os.Exit(1)
} else if !noConfirm {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Are you sure you want to continue (y/N)?: ")
text, _ := reader.ReadString('\n')
text = strings.TrimLeft(text, "\r\n\t ")
text = strings.TrimRight(text, "\r\n\t ")
if text != "Y" && text != "y" {
fmt.Println("Aborting")
os.Exit(0)
}
}
fmt.Println("Deleting")
f.TrashEmpty()
},
}
cmd.Flags().BoolP("no-confirm", "y", false, "Do not ask for confirmation")
return &cmd
}

View File

@@ -17,13 +17,17 @@ func setupRestoreCommand() *cobra.Command {
f := common.UserFileSystem(cmd)
for _, uuid := range args {
r, err := f.ResourceByPathOrUUID(uuid)
if err != nil {
fmt.Println("cannot restore'" + uuid + "': " + err.Error())
os.Exit(1)
}
if r.Dir() {
if recursive, err := cmd.Flags().GetBool("recursive"); err != nil || !recursive {
fmt.Println("cannot restore '" + uuid + "': Is a directory. Try again with '-r'")
os.Exit(1)
}
}
p, err := cmd.Flags().GetString("parent")
p, _ := cmd.Flags().GetString("parent")
name, _ := cmd.Flags().GetString("name")
autoRename, _ := cmd.Flags().GetBool("auto-rename")
r, items, size, err := r.Restore(p, name, autoRename)

View File

@@ -5,6 +5,7 @@ import (
"os"
"github.com/shroff/phylum/server/internal/command/common"
"github.com/shroff/phylum/server/internal/core/fs"
"github.com/spf13/cobra"
)
@@ -15,15 +16,19 @@ func setupSummaryCommand() *cobra.Command {
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
f := common.UserFileSystem(cmd)
items, size, err := f.TrashSummary()
if err != nil {
fmt.Println("cannot get trash summary: " + err.Error())
os.Exit(1)
}
fmt.Printf("Items in trash: %d\n", items)
fmt.Printf("Space occupied: %s\n", common.FormatSize(size))
printTrashSummary(f)
},
}
return &cmd
}
func printTrashSummary(f fs.FileSystem) {
items, size, err := f.TrashSummary()
if err != nil {
fmt.Println("cannot get trash summary: " + err.Error())
os.Exit(1)
}
fmt.Printf("Items in trash: %d\n", items)
fmt.Printf("Space occupied: %s\n", common.FormatSize(size))
}

View File

@@ -12,6 +12,40 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
const emptyTrash = `-- name: EmptyTrash :many
DELETE FROM resources
WHERE deleted IS NOT NULL
AND CASE
WHEN $1::TEXT IS NULL THEN TRUE
ELSE permissions[$1::TEXT]::integer & 32 <> 0 END
RETURNING id, dir
`
type EmptyTrashRow struct {
ID uuid.UUID
Dir bool
}
func (q *Queries) EmptyTrash(ctx context.Context, username pgtype.Text) ([]EmptyTrashRow, error) {
rows, err := q.db.Query(ctx, emptyTrash, username)
if err != nil {
return nil, err
}
defer rows.Close()
var items []EmptyTrashRow
for rows.Next() {
var i EmptyTrashRow
if err := rows.Scan(&i.ID, &i.Dir); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const hardDelete = `-- name: HardDelete :many
WITH RECURSIVE nodes(id, parent) AS (
SELECT r.id, r.parent
@@ -224,7 +258,7 @@ func (q *Queries) TrashList(ctx context.Context, arg TrashListParams) ([]Resourc
}
const trashSummary = `-- name: TrashSummary :one
SELECT SUM(content_length) AS size, COUNT(*) AS items
SELECT COALESCE(SUM(content_length), 0)::INTEGER AS size, COUNT(*) AS items
FROM resources
WHERE deleted IS NOT NULL
AND CASE
@@ -233,7 +267,7 @@ SELECT SUM(content_length) AS size, COUNT(*) AS items
`
type TrashSummaryRow struct {
Size int64
Size int32
Items int64
}

View File

@@ -37,6 +37,7 @@ type FileSystem interface {
// trash.go
TrashList(cursor string, n int) ([]Resource, string, error)
TrashSummary() (int, int, error)
TrashEmpty() (int, error)
}
func Open(ctx context.Context, username string, root uuid.UUID, fullAccess bool) FileSystem {

View File

@@ -174,3 +174,21 @@ func HardDeleteExpired(ctx context.Context, t time.Time) (int, error) {
storage.Get().DeleteAll(ids)
return len(rows), err
}
func (f filesystem) TrashEmpty() (int, error) {
var username pgtype.Text
if !f.fullAccess {
username.String = f.username
username.Valid = true
}
d := db.Get()
rows, err := d.EmptyTrash(f.ctx, username)
ids := make([]uuid.UUID, len(rows))
for _, d := range rows {
if !d.Dir {
ids = append(ids, d.ID)
}
}
storage.Get().DeleteAll(ids)
return len(rows), err
}

View File

@@ -76,9 +76,17 @@ SELECT * FROM resources
LIMIT @n::INTEGER;
-- name: TrashSummary :one
SELECT SUM(content_length) AS size, COUNT(*) AS items
SELECT COALESCE(SUM(content_length), 0)::INTEGER AS size, COUNT(*) AS items
FROM resources
WHERE deleted IS NOT NULL
AND CASE
WHEN sqlc.narg('username')::TEXT IS NULL THEN TRUE
ELSE permissions[@username::TEXT]::integer <> 0 END;
ELSE permissions[@username::TEXT]::integer <> 0 END;
-- name: EmptyTrash :many
DELETE FROM resources
WHERE deleted IS NOT NULL
AND CASE
WHEN sqlc.narg('username')::TEXT IS NULL THEN TRUE
ELSE permissions[@username::TEXT]::integer & 32 <> 0 END
RETURNING id, dir;