diff --git a/messaging/commands/exporter.go b/messaging/commands/exporter.go new file mode 100644 index 000000000..6ed323b70 --- /dev/null +++ b/messaging/commands/exporter.go @@ -0,0 +1,135 @@ +package commands + +import ( + "context" + "strings" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" + + "github.com/cortezaproject/corteza-server/messaging/service" + "github.com/cortezaproject/corteza-server/pkg/auth" + "github.com/cortezaproject/corteza-server/pkg/cli" + "github.com/cortezaproject/corteza-server/pkg/permissions" + "github.com/cortezaproject/corteza-server/pkg/settings" + sysTypes "github.com/cortezaproject/corteza-server/system/types" +) + +func Exporter(ctx context.Context, c *cli.Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "export", + Short: "Export", + Long: `Export messaging resources`, + + Run: func(cmd *cobra.Command, args []string) { + + c.InitServices(ctx, c) + ctx = auth.SetSuperUserContext(ctx) + + var ( + sFlag = cmd.Flags().Lookup("settings").Changed + pFlag = cmd.Flags().Lookup("permissions").Changed + + out = &Messaging{ + Settings: yaml.MapSlice{}, + } + ) + + if !sFlag && !pFlag { + cli.HandleError(errors.New("Specify setting or permissions flag")) + } + + if pFlag { + permissionExporter(ctx, out) + } + + if sFlag { + settingExporter(ctx, out) + } + + y := yaml.NewEncoder(cmd.OutOrStdout()) + cli.HandleError(y.Encode(out)) + }, + } + + cmd.Flags().BoolP("settings", "s", false, "Export settings") + cmd.Flags().BoolP("permissions", "p", false, "Export permission") + + return cmd +} + +func permissionExporter(ctx context.Context, out *Messaging) { + roles = sysTypes.RoleSet{ + &sysTypes.Role{ID: permissions.EveryoneRoleID, Handle: "everyone"}, + &sysTypes.Role{ID: permissions.AdminsRoleID, Handle: "admins"}, + } + + out.Allow = expServicePermissions(permissions.Allow) + out.Deny = expServicePermissions(permissions.Deny) +} + +func settingExporter(ctx context.Context, out *Messaging) { + var ( + err error + ) + + ss, err := service.DefaultSettings.FindByPrefix("") + cli.HandleError(err) + + out.Settings = settings.Export(ss) +} + +// This is PoC for exporting messaging resources +// + +type ( + Messaging struct { + Settings yaml.MapSlice `yaml:",omitempty"` + + Allow map[string]map[string][]string `yaml:",omitempty"` + Deny map[string]map[string][]string `yaml:",omitempty"` + } +) + +var ( + roles sysTypes.RoleSet +) + +// @todo move to pkg/permissions +func expServicePermissions(access permissions.Access) map[string]map[string][]string { + var ( + has bool + res string + rules permissions.RuleSet + sp = make(map[string]map[string][]string) + ) + + for _, r := range roles { + rules = service.DefaultPermissions.FindRulesByRoleID(r.ID) + + if len(rules) == 0 { + continue + } + + for _, rule := range rules { + if rule.Resource.GetService() != rule.Resource && !rule.Resource.HasWildcard() { + continue + } + + res = strings.TrimRight(rule.Resource.String(), ":*") + + if _, has = sp[r.Handle]; !has { + sp[r.Handle] = map[string][]string{} + } + + if _, has = sp[r.Handle][res]; !has { + sp[r.Handle][res] = make([]string, 0) + } + + sp[r.Handle][res] = append(sp[r.Handle][res], rule.Operation.String()) + } + } + + return sp +} diff --git a/messaging/commands/importer.go b/messaging/commands/importer.go new file mode 100644 index 000000000..85d3d304e --- /dev/null +++ b/messaging/commands/importer.go @@ -0,0 +1,45 @@ +package commands + +import ( + "context" + "io" + "os" + + "github.com/spf13/cobra" + + "github.com/cortezaproject/corteza-server/messaging/importer" + "github.com/cortezaproject/corteza-server/pkg/auth" + "github.com/cortezaproject/corteza-server/pkg/cli" +) + +func Importer(ctx context.Context, c *cli.Config) *cobra.Command { + cmd := &cobra.Command{ + Use: "import", + Short: "Import", + + Run: func(cmd *cobra.Command, args []string) { + + c.InitServices(ctx, c) + + var ( + ff []io.Reader + err error + ) + + ctx = auth.SetSuperUserContext(ctx) + + if len(args) > 0 { + ff = make([]io.Reader, len(args)) + for a, arg := range args { + ff[a], err = os.Open(arg) + cli.HandleError(err) + } + cli.HandleError(importer.Import(ctx, ff...)) + } else { + cli.HandleError(importer.Import(ctx, os.Stdin)) + } + }, + } + + return cmd +} diff --git a/messaging/importer/default.go b/messaging/importer/default.go index eee35e209..ba7a5765f 100644 --- a/messaging/importer/default.go +++ b/messaging/importer/default.go @@ -9,6 +9,7 @@ import ( "github.com/cortezaproject/corteza-server/messaging/service" "github.com/cortezaproject/corteza-server/messaging/types" "github.com/cortezaproject/corteza-server/pkg/permissions" + "github.com/cortezaproject/corteza-server/pkg/settings" sysTypes "github.com/cortezaproject/corteza-server/system/types" ) @@ -28,6 +29,7 @@ func Import(ctx context.Context, ff ...io.Reader) (err error) { p = permissions.NewImporter(service.DefaultAccessControl.Whitelist()) imp = NewImporter( p, + settings.NewImporter(), NewChannelImport(p, cc), ) @@ -56,6 +58,7 @@ func Import(ctx context.Context, ff ...io.Reader) (err error) { ctx, service.DefaultChannel.With(ctx), service.DefaultAccessControl, + service.DefaultSettings, roles, ) } diff --git a/messaging/importer/importer.go b/messaging/importer/importer.go index 10e242dc9..c426137ea 100644 --- a/messaging/importer/importer.go +++ b/messaging/importer/importer.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/cortezaproject/corteza-server/pkg/settings" + "github.com/cortezaproject/corteza-server/messaging/types" "github.com/cortezaproject/corteza-server/pkg/deinterfacer" "github.com/cortezaproject/corteza-server/pkg/importer" @@ -15,6 +17,7 @@ type ( Importer struct { channels *Channel permissions importer.PermissionImporter + settings importer.SettingImporter } channelFinder interface { @@ -22,10 +25,11 @@ type ( } ) -func NewImporter(p importer.PermissionImporter, ci *Channel) *Importer { +func NewImporter(p importer.PermissionImporter, s importer.SettingImporter, ci *Channel) *Importer { return &Importer{ channels: ci, permissions: p, + settings: s, } } @@ -37,6 +41,9 @@ func (imp *Importer) Cast(in interface{}) (err error) { case "channel": return imp.channels.CastSet([]interface{}{val}) + case "settings": + return imp.settings.CastSet(val) + case "allow", "deny": return imp.permissions.CastResourcesSet(key, val) @@ -48,7 +55,7 @@ func (imp *Importer) Cast(in interface{}) (err error) { }) } -func (imp *Importer) Store(ctx context.Context, rk channelKeeper, pk permissions.ImportKeeper, roles sysTypes.RoleSet) (err error) { +func (imp *Importer) Store(ctx context.Context, rk channelKeeper, pk permissions.ImportKeeper, sk settings.ImportKeeper, roles sysTypes.RoleSet) (err error) { err = imp.channels.Store(ctx, rk) if err != nil { return @@ -65,5 +72,10 @@ func (imp *Importer) Store(ctx context.Context, rk channelKeeper, pk permissions return } + err = imp.settings.Store(ctx, sk) + if err != nil { + return + } + return nil } diff --git a/messaging/messaging.go b/messaging/messaging.go index 403be9c34..72f81a02d 100644 --- a/messaging/messaging.go +++ b/messaging/messaging.go @@ -8,6 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/titpetric/factory" + "github.com/cortezaproject/corteza-server/messaging/commands" migrate "github.com/cortezaproject/corteza-server/messaging/db" "github.com/cortezaproject/corteza-server/messaging/rest" "github.com/cortezaproject/corteza-server/messaging/service" @@ -79,6 +80,15 @@ func Configure() *cli.Config { func(r chi.Router) { ws.ApiServerRoutes(r) }, }, + AdtSubCommands: cli.CommandMakers{ + func(ctx context.Context, c *cli.Config) *cobra.Command { + return commands.Importer(ctx, c) + }, + func(ctx context.Context, c *cli.Config) *cobra.Command { + return commands.Exporter(ctx, c) + }, + }, + ProvisionMigrateDatabase: cli.Runners{ func(ctx context.Context, cmd *cobra.Command, c *cli.Config) error { var db, err = factory.Database.Get(messaging)