mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-05 11:10:47 -06:00
[server][core] Empty trash
This commit is contained in:
@@ -21,9 +21,10 @@ func SetupCommand() *cobra.Command {
|
||||
flags.StringP("user", "u", "phylum", "User")
|
||||
|
||||
cmd.AddCommand(
|
||||
setupEmptyCommand(),
|
||||
setupListCommand(),
|
||||
setupSummaryCommand(),
|
||||
setupRestoreCommand(),
|
||||
setupSummaryCommand(),
|
||||
)
|
||||
|
||||
return cmd
|
||||
|
||||
41
server/internal/command/trash/empty.go
Normal file
41
server/internal/command/trash/empty.go
Normal 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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user