diff --git a/CHANGELOG.md b/CHANGELOG.md index acc2c0a9..ecd7de54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ - Added `expiry` field to the OAuth2 user response containing the _optional_ expiration time of the OAuth2 access token ([#3617](https://github.com/pocketbase/pocketbase/discussions/3617)). +- Added new `filesystem.Copy(src, dest)` method to copy existing files from one location to another. + _This is usually useful when duplicating records with file fields programmatically._ + ## v0.20.0-rc3 diff --git a/tools/filesystem/filesystem.go b/tools/filesystem/filesystem.go index b36d61fa..af2f3c1a 100644 --- a/tools/filesystem/filesystem.go +++ b/tools/filesystem/filesystem.go @@ -117,6 +117,13 @@ func (s *System) GetFile(fileKey string) (*blob.Reader, error) { return br, nil } +// Copy copies the file stored at srcKey to dstKey. +// +// If dstKey file already exists, it is overwritten. +func (s *System) Copy(srcKey, dstKey string) error { + return s.bucket.Copy(s.ctx, dstKey, srcKey, nil) +} + // List returns a flat list with info for all files under the specified prefix. func (s *System) List(prefix string) ([]*blob.ListObject, error) { files := []*blob.ListObject{} diff --git a/tools/filesystem/filesystem_test.go b/tools/filesystem/filesystem_test.go index 3667aee0..7b57b549 100644 --- a/tools/filesystem/filesystem_test.go +++ b/tools/filesystem/filesystem_test.go @@ -429,6 +429,38 @@ func TestFileSystemGetFile(t *testing.T) { } } +func TestFileSystemCopy(t *testing.T) { + dir := createTestDir(t) + defer os.RemoveAll(dir) + + fs, err := filesystem.NewLocal(dir) + if err != nil { + t.Fatal(err) + } + defer fs.Close() + + src := "image.png" + dst := "image.png_copy" + + // copy missing file + if err := fs.Copy(dst, src); err == nil { + t.Fatalf("Expected to fail copying %q to %q, got nil", dst, src) + } + + // copy existing file + if err := fs.Copy(src, dst); err != nil { + t.Fatalf("Failed to copy %q to %q: %v", src, dst, err) + } + f, err := fs.GetFile(dst) + defer f.Close() + if err != nil { + t.Fatalf("Missing copied file %q: %v", dst, err) + } + if f.Size() != 73 { + t.Fatalf("Expected file size %d, got %d", 73, f.Size()) + } +} + func TestFileSystemList(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir)