eventmanager: auto-create destination folder for renames

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2023-01-03 18:13:01 +01:00
parent 51f0ded222
commit f0dedbfabf
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
8 changed files with 17 additions and 37 deletions

View file

@ -117,19 +117,13 @@ Create an action named `move to recycle` with the settings you can see in the fo
![Recycle move action](./img/recycle-move-action.png) ![Recycle move action](./img/recycle-move-action.png)
Add another action, named `create move folder`, to create the parent directory for the move destination.
![Recycle create move folder action](./img/recycle-move-folder-action.png)
Now select `Event rules` and create a rule named `Recycle rule`, select `Filesystem events` as trigger, `pre-delete` as filesystem event and exclude the `/recycle` path. Now select `Event rules` and create a rule named `Recycle rule`, select `Filesystem events` as trigger, `pre-delete` as filesystem event and exclude the `/recycle` path.
![Recycle rule](./img/recycle-rule.png) ![Recycle rule](./img/recycle-rule.png)
![Recycle rule exclude path](./img/recycle-rule-path.png) ![Recycle rule exclude path](./img/recycle-rule-path.png)
As actions, select `create move folder` and `move to recycle` and for both set `Execute sync`. As actions, select `move to recycle` and set `Execute sync`.
![Recycle rule actions](./img/recycle-rule-actions.png)
Done! Try deleting a file, it will be moved to the Recycle Bin. Done! Try deleting a file, it will be moved to the Recycle Bin.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

4
go.mod
View file

@ -34,10 +34,10 @@ require (
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/hashicorp/go-hclog v1.4.0 github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-plugin v1.4.8 github.com/hashicorp/go-plugin v1.4.8
github.com/hashicorp/go-retryablehttp v0.7.1 github.com/hashicorp/go-retryablehttp v0.7.2
github.com/jackc/pgx/v5 v5.2.0 github.com/jackc/pgx/v5 v5.2.0
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126 github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
github.com/klauspost/compress v1.15.13 github.com/klauspost/compress v1.15.14
github.com/lestrrat-go/jwx/v2 v2.0.8 github.com/lestrrat-go/jwx/v2 v2.0.8
github.com/lithammer/shortuuid/v3 v3.0.7 github.com/lithammer/shortuuid/v3 v3.0.7
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16

7
go.sum
View file

@ -930,8 +930,9 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM=
github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@ -1066,8 +1067,8 @@ github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0= github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc=
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=

View file

@ -676,6 +676,10 @@ func (c *BaseConnection) Copy(virtualSourcePath, virtualTargetPath string) error
// Rename renames (moves) virtualSourcePath to virtualTargetPath // Rename renames (moves) virtualSourcePath to virtualTargetPath
func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) error { func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) error {
return c.renameInternal(virtualSourcePath, virtualTargetPath, false)
}
func (c *BaseConnection) renameInternal(virtualSourcePath, virtualTargetPath string, checkParentDestination bool) error {
if virtualSourcePath == virtualTargetPath { if virtualSourcePath == virtualTargetPath {
return fmt.Errorf("the rename source and target cannot be the same: %w", c.GetOpUnsupportedError()) return fmt.Errorf("the rename source and target cannot be the same: %w", c.GetOpUnsupportedError())
} }
@ -696,6 +700,7 @@ func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) err
} }
initialSize := int64(-1) initialSize := int64(-1)
if dstInfo, err := fsDst.Lstat(fsTargetPath); err == nil { if dstInfo, err := fsDst.Lstat(fsTargetPath); err == nil {
checkParentDestination = false
if dstInfo.IsDir() { if dstInfo.IsDir() {
c.Log(logger.LevelWarn, "attempted to rename %q overwriting an existing directory %q", c.Log(logger.LevelWarn, "attempted to rename %q overwriting an existing directory %q",
fsSourcePath, fsTargetPath) fsSourcePath, fsTargetPath)
@ -720,6 +725,9 @@ func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) err
c.Log(logger.LevelInfo, "denying cross rename due to space limit") c.Log(logger.LevelInfo, "denying cross rename due to space limit")
return c.GetGenericError(ErrQuotaExceeded) return c.GetGenericError(ErrQuotaExceeded)
} }
if checkParentDestination {
c.CheckParentDirs(path.Dir(virtualTargetPath)) //nolint:errcheck
}
if err := fsDst.Rename(fsSourcePath, fsTargetPath); err != nil { if err := fsDst.Rename(fsSourcePath, fsTargetPath); err != nil {
c.Log(logger.LevelError, "failed to rename %q -> %q: %+v", fsSourcePath, fsTargetPath, err) c.Log(logger.LevelError, "failed to rename %q -> %q: %+v", fsSourcePath, fsTargetPath, err)
return c.GetFsError(fsSrc, err) return c.GetFsError(fsSrc, err)

View file

@ -1477,7 +1477,7 @@ func executeRenameFsActionForUser(renames []dataprovider.KeyValue, replacer *str
for _, item := range renames { for _, item := range renames {
source := util.CleanPath(replaceWithReplacer(item.Key, replacer)) source := util.CleanPath(replaceWithReplacer(item.Key, replacer))
target := util.CleanPath(replaceWithReplacer(item.Value, replacer)) target := util.CleanPath(replaceWithReplacer(item.Value, replacer))
if err = conn.Rename(source, target); err != nil { if err = conn.renameInternal(source, target, true); err != nil {
return fmt.Errorf("unable to rename %q->%q, user %q: %w", source, target, user.Username, err) return fmt.Errorf("unable to rename %q->%q, user %q: %w", source, target, user.Username, err)
} }
eventManagerLog(logger.LevelDebug, "rename %q->%q ok, user %q", source, target, user.Username) eventManagerLog(logger.LevelDebug, "rename %q->%q ok, user %q", source, target, user.Username)

View file

@ -4200,18 +4200,6 @@ func TestEventRulePreDelete(t *testing.T) {
a1 := dataprovider.BaseEventAction{ a1 := dataprovider.BaseEventAction{
Name: "a1", Name: "a1",
Type: dataprovider.ActionTypeFilesystem, Type: dataprovider.ActionTypeFilesystem,
Options: dataprovider.BaseEventActionOptions{
FsConfig: dataprovider.EventActionFilesystemConfig{
Type: dataprovider.FilesystemActionMkdirs,
MkDirs: []string{fmt.Sprintf("/%s/{{VirtualDirPath}}", movePath)},
},
},
}
action1, resp, err := httpdtest.AddEventAction(a1, http.StatusCreated)
assert.NoError(t, err, string(resp))
a2 := dataprovider.BaseEventAction{
Name: "a2",
Type: dataprovider.ActionTypeFilesystem,
Options: dataprovider.BaseEventActionOptions{ Options: dataprovider.BaseEventActionOptions{
FsConfig: dataprovider.EventActionFilesystemConfig{ FsConfig: dataprovider.EventActionFilesystemConfig{
Type: dataprovider.FilesystemActionRename, Type: dataprovider.FilesystemActionRename,
@ -4224,7 +4212,7 @@ func TestEventRulePreDelete(t *testing.T) {
}, },
}, },
} }
action2, resp, err := httpdtest.AddEventAction(a2, http.StatusCreated) action1, resp, err := httpdtest.AddEventAction(a1, http.StatusCreated)
assert.NoError(t, err, string(resp)) assert.NoError(t, err, string(resp))
r1 := dataprovider.EventRule{ r1 := dataprovider.EventRule{
Name: "rule1", Name: "rule1",
@ -4250,15 +4238,6 @@ func TestEventRulePreDelete(t *testing.T) {
ExecuteSync: true, ExecuteSync: true,
}, },
}, },
{
BaseEventAction: dataprovider.BaseEventAction{
Name: action2.Name,
},
Order: 2,
Options: dataprovider.EventActionOptions{
ExecuteSync: true,
},
},
}, },
} }
rule1, _, err := httpdtest.AddEventRule(r1, http.StatusCreated) rule1, _, err := httpdtest.AddEventRule(r1, http.StatusCreated)
@ -4325,8 +4304,6 @@ func TestEventRulePreDelete(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
_, err = httpdtest.RemoveEventAction(action1, http.StatusOK) _, err = httpdtest.RemoveEventAction(action1, http.StatusOK)
assert.NoError(t, err) assert.NoError(t, err)
_, err = httpdtest.RemoveEventAction(action2, http.StatusOK)
assert.NoError(t, err)
_, err = httpdtest.RemoveUser(user, http.StatusOK) _, err = httpdtest.RemoveUser(user, http.StatusOK)
assert.NoError(t, err) assert.NoError(t, err)
err = os.RemoveAll(user.GetHomeDir()) err = os.RemoveAll(user.GetHomeDir())