diff --git a/changelog/unreleased/public-shares-cli.md b/changelog/unreleased/public-shares-cli.md new file mode 100644 index 0000000000..f85cf5766b --- /dev/null +++ b/changelog/unreleased/public-shares-cli.md @@ -0,0 +1,3 @@ +Enhancement: Add CLI commands for public shares + +https://github.com/cs3org/reva/pull/1328 diff --git a/cmd/reva/completer.go b/cmd/reva/completer.go index b1814f34ee..22aa591315 100644 --- a/cmd/reva/completer.go +++ b/cmd/reva/completer.go @@ -106,7 +106,7 @@ func (c *Completer) argumentCompleter(args ...string) []prompt.Suggest { return prompt.FilterHasPrefix(c.lsArgumentCompleter(false), args[2], true) } - case "rm", "stat", "share-create", "ocm-share-create", "open-file-in-app-provider", "download": + case "rm", "stat", "share-create", "ocm-share-create", "public-share-create", "open-file-in-app-provider", "download": if len(args) == 2 { return prompt.FilterHasPrefix(c.lsArgumentCompleter(false), args[1], true) } diff --git a/cmd/reva/main.go b/cmd/reva/main.go index e726959fd2..6e5a1135d3 100644 --- a/cmd/reva/main.go +++ b/cmd/reva/main.go @@ -63,6 +63,10 @@ var ( ocmShareUpdateReceivedCommand(), preferencesCommand(), genCommand(), + publicShareCreateCommand(), + publicShareListCommand(), + publicShareRemoveCommand(), + publicShareUpdateCommand(), recycleListCommand(), recycleRestoreCommand(), recyclePurgeCommand(), diff --git a/cmd/reva/public-share-create.go b/cmd/reva/public-share-create.go new file mode 100644 index 0000000000..99a2586576 --- /dev/null +++ b/cmd/reva/public-share-create.go @@ -0,0 +1,107 @@ +// Copyright 2018-2020 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package main + +import ( + "io" + "os" + "time" + + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/jedib0t/go-pretty/table" + "github.com/pkg/errors" +) + +func publicShareCreateCommand() *command { + cmd := newCommand("public-share-create") + cmd.Description = func() string { return "create a public share" } + cmd.Usage = func() string { return "Usage: public-share-create [-flags] " } + rol := cmd.String("rol", "viewer", "the permission for the share (viewer or editor)") + + cmd.ResetFlags = func() { + *rol = "viewer" + } + + cmd.Action = func(w ...io.Writer) error { + if cmd.NArg() < 1 { + return errors.New("Invalid arguments: " + cmd.Usage()) + } + + fn := cmd.Args()[0] + + ctx := getAuthContext() + client, err := getClient() + if err != nil { + return err + } + + ref := &provider.Reference{ + Spec: &provider.Reference_Path{Path: fn}, + } + + req := &provider.StatRequest{Ref: ref} + res, err := client.Stat(ctx, req) + if err != nil { + return err + } + + if res.Status.Code != rpc.Code_CODE_OK { + return formatError(res.Status) + } + + perm, err := getSharePerm(*rol) + if err != nil { + return err + } + + grant := &link.Grant{ + Permissions: &link.PublicSharePermissions{ + Permissions: perm, + }, + } + shareRequest := &link.CreatePublicShareRequest{ + ResourceInfo: res.Info, + Grant: grant, + } + + shareRes, err := client.CreatePublicShare(ctx, shareRequest) + if err != nil { + return err + } + + if shareRes.Status.Code != rpc.Code_CODE_OK { + return formatError(shareRes.Status) + } + + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.AppendHeader(table.Row{"#", "Owner.Idp", "Owner.OpaqueId", "ResourceId", "Permissions", "Token", "Expiration", "Created", "Updated"}) + + s := shareRes.Share + t.AppendRows([]table.Row{ + {s.Id.OpaqueId, s.Owner.Idp, s.Owner.OpaqueId, s.ResourceId.String(), s.Permissions.String(), s.Token, s.Expiration.String(), time.Unix(int64(s.Ctime.Seconds), 0), time.Unix(int64(s.Mtime.Seconds), 0)}, + }) + t.Render() + + return nil + } + return cmd +} diff --git a/cmd/reva/public-share-list.go b/cmd/reva/public-share-list.go new file mode 100644 index 0000000000..318aa7b6ff --- /dev/null +++ b/cmd/reva/public-share-list.go @@ -0,0 +1,102 @@ +// Copyright 2018-2020 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package main + +import ( + "encoding/gob" + "fmt" + "io" + "os" + "strings" + "time" + + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/jedib0t/go-pretty/table" +) + +func publicShareListCommand() *command { + cmd := newCommand("public-share-list") + cmd.Description = func() string { return "list public shares created by the user" } + cmd.Usage = func() string { return "Usage: public-share-list [-flags]" } + resID := cmd.String("by-resource-id", "", "filter by resource id (storage_id:opaque_id)") + + cmd.ResetFlags = func() { + *resID = "" + } + + cmd.Action = func(w ...io.Writer) error { + ctx := getAuthContext() + shareClient, err := getClient() + if err != nil { + return err + } + + shareRequest := &link.ListPublicSharesRequest{} + if *resID != "" { + // check split by colon (:) + tokens := strings.Split(*resID, ":") + if len(tokens) != 2 { + return fmt.Errorf("resource id invalid") + } + id := &provider.ResourceId{ + StorageId: tokens[0], + OpaqueId: tokens[1], + } + shareRequest.Filters = []*link.ListPublicSharesRequest_Filter{ + &link.ListPublicSharesRequest_Filter{ + Type: link.ListPublicSharesRequest_Filter_TYPE_RESOURCE_ID, + Term: &link.ListPublicSharesRequest_Filter_ResourceId{ + ResourceId: id, + }, + }, + } + } + + shareRes, err := shareClient.ListPublicShares(ctx, shareRequest) + if err != nil { + return err + } + + if shareRes.Status.Code != rpc.Code_CODE_OK { + return formatError(shareRes.Status) + } + + if len(w) == 0 { + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.AppendHeader(table.Row{"#", "Owner.Idp", "Owner.OpaqueId", "ResourceId", "Permissions", "Token", "Expiration", "Created", "Updated"}) + + for _, s := range shareRes.Share { + t.AppendRows([]table.Row{ + {s.Id.OpaqueId, s.Owner.Idp, s.Owner.OpaqueId, s.ResourceId.String(), s.Permissions.String(), s.Token, s.Expiration.String(), time.Unix(int64(s.Ctime.Seconds), 0), time.Unix(int64(s.Mtime.Seconds), 0)}, + }) + } + t.Render() + } else { + enc := gob.NewEncoder(w[0]) + if err := enc.Encode(shareRes.Share); err != nil { + return err + } + } + return nil + } + return cmd +} diff --git a/cmd/reva/public-share-remove.go b/cmd/reva/public-share-remove.go new file mode 100644 index 0000000000..472135a142 --- /dev/null +++ b/cmd/reva/public-share-remove.go @@ -0,0 +1,70 @@ +// Copyright 2018-2020 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package main + +import ( + "fmt" + "io" + + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" + "github.com/pkg/errors" +) + +func publicShareRemoveCommand() *command { + cmd := newCommand("public-share-remove") + cmd.Description = func() string { return "remove a public share" } + cmd.Usage = func() string { return "Usage: public-share-remove [-flags] " } + cmd.Action = func(w ...io.Writer) error { + if cmd.NArg() < 1 { + return errors.New("Invalid arguments: " + cmd.Usage()) + } + + id := cmd.Args()[0] + + ctx := getAuthContext() + shareClient, err := getClient() + if err != nil { + return err + } + + shareRequest := &link.RemovePublicShareRequest{ + Ref: &link.PublicShareReference{ + Spec: &link.PublicShareReference_Id{ + Id: &link.PublicShareId{ + OpaqueId: id, + }, + }, + }, + } + + shareRes, err := shareClient.RemovePublicShare(ctx, shareRequest) + if err != nil { + return err + } + + if shareRes.Status.Code != rpc.Code_CODE_OK { + return formatError(shareRes.Status) + } + + fmt.Println("OK") + return nil + } + return cmd +} diff --git a/cmd/reva/public-share-update.go b/cmd/reva/public-share-update.go new file mode 100644 index 0000000000..5926e5fea3 --- /dev/null +++ b/cmd/reva/public-share-update.go @@ -0,0 +1,93 @@ +// Copyright 2018-2020 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package main + +import ( + "fmt" + "io" + + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" + "github.com/pkg/errors" +) + +func publicShareUpdateCommand() *command { + cmd := newCommand("public-share-update") + cmd.Description = func() string { return "update a public share" } + cmd.Usage = func() string { return "Usage: public-share-update [-flags] " } + rol := cmd.String("rol", "viewer", "the permission for the share (viewer or editor)") + + cmd.ResetFlags = func() { + *rol = "viewer" + } + cmd.Action = func(w ...io.Writer) error { + if cmd.NArg() < 1 { + return errors.New("Invalid arguments: " + cmd.Usage()) + } + + // validate flags + if *rol != viewerPermission && *rol != editorPermission { + return errors.New("Invalid rol: rol must be viewer or editor\n" + cmd.Usage()) + } + + id := cmd.Args()[0] + + ctx := getAuthContext() + shareClient, err := getClient() + if err != nil { + return err + } + + perm, err := getSharePerm(*rol) + if err != nil { + return err + } + + shareRequest := &link.UpdatePublicShareRequest{ + Ref: &link.PublicShareReference{ + Spec: &link.PublicShareReference_Id{ + Id: &link.PublicShareId{ + OpaqueId: id, + }, + }, + }, + Update: &link.UpdatePublicShareRequest_Update{ + Type: link.UpdatePublicShareRequest_Update_TYPE_PERMISSIONS, + Grant: &link.Grant{ + Permissions: &link.PublicSharePermissions{ + Permissions: perm, + }, + }, + }, + } + + shareRes, err := shareClient.UpdatePublicShare(ctx, shareRequest) + if err != nil { + return err + } + + if shareRes.Status.Code != rpc.Code_CODE_OK { + return formatError(shareRes.Status) + } + + fmt.Println("OK") + return nil + } + return cmd +} diff --git a/cmd/reva/share-create.go b/cmd/reva/share-create.go index af7000a6eb..5d32392652 100644 --- a/cmd/reva/share-create.go +++ b/cmd/reva/share-create.go @@ -84,7 +84,9 @@ func shareCreateCommand() *command { gt := getGrantType(*grantType) grant := &collaboration.ShareGrant{ - Permissions: perm, + Permissions: &collaboration.SharePermissions{ + Permissions: perm, + }, Grantee: &provider.Grantee{ Type: gt, Id: &userpb.UserId{ @@ -133,31 +135,27 @@ func getGrantType(t string) provider.GranteeType { } } -func getSharePerm(p string) (*collaboration.SharePermissions, error) { +func getSharePerm(p string) (*provider.ResourcePermissions, error) { if p == viewerPermission { - return &collaboration.SharePermissions{ - Permissions: &provider.ResourcePermissions{ - GetPath: true, - InitiateFileDownload: true, - ListFileVersions: true, - ListContainer: true, - Stat: true, - }, + return &provider.ResourcePermissions{ + GetPath: true, + InitiateFileDownload: true, + ListFileVersions: true, + ListContainer: true, + Stat: true, }, nil } else if p == editorPermission { - return &collaboration.SharePermissions{ - Permissions: &provider.ResourcePermissions{ - GetPath: true, - InitiateFileDownload: true, - ListFileVersions: true, - ListContainer: true, - Stat: true, - CreateContainer: true, - Delete: true, - InitiateFileUpload: true, - RestoreFileVersion: true, - Move: true, - }, + return &provider.ResourcePermissions{ + GetPath: true, + InitiateFileDownload: true, + ListFileVersions: true, + ListContainer: true, + Stat: true, + CreateContainer: true, + Delete: true, + InitiateFileUpload: true, + RestoreFileVersion: true, + Move: true, }, nil } return nil, errors.New("invalid rol: " + p) diff --git a/cmd/reva/share-update.go b/cmd/reva/share-update.go index 96a8be81bc..6887d92848 100644 --- a/cmd/reva/share-update.go +++ b/cmd/reva/share-update.go @@ -69,7 +69,9 @@ func shareUpdateCommand() *command { }, Field: &collaboration.UpdateShareRequest_UpdateField{ Field: &collaboration.UpdateShareRequest_UpdateField_Permissions{ - Permissions: perm, + Permissions: &collaboration.SharePermissions{ + Permissions: perm, + }, }, }, }