Refactored configuration provisioning
This commit is contained in:
+7
-11
@@ -120,14 +120,10 @@ function database {
|
||||
}
|
||||
|
||||
|
||||
function files {
|
||||
yellow "> files"
|
||||
FOLDERS=$(find . -type d -wholename '*/data')
|
||||
for FOLDER in $FOLDERS; do
|
||||
FOLDER=$(dirname $FOLDER)
|
||||
FOLDER=${FOLDER:2}
|
||||
echo $FOLDER
|
||||
cd $FOLDER && $GOPATH/bin/statik -p files -m -Z -f -src=data && cd $_PWD
|
||||
function provision {
|
||||
yellow "> provision files"
|
||||
for FOLDER in system compose messaging; do
|
||||
$GOPATH/bin/statik -p $FOLDER -m -Z -f -src="./provision/$FOLDER/src" -dest "./provision"
|
||||
done
|
||||
green "OK"
|
||||
}
|
||||
@@ -200,8 +196,8 @@ case ${1:-"all"} in
|
||||
database)
|
||||
database
|
||||
;;
|
||||
files)
|
||||
files
|
||||
provision)
|
||||
provision
|
||||
;;
|
||||
specs)
|
||||
specs
|
||||
@@ -212,7 +208,7 @@ case ${1:-"all"} in
|
||||
all)
|
||||
types
|
||||
database
|
||||
files
|
||||
provision
|
||||
specs
|
||||
proto
|
||||
esac
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
)
|
||||
|
||||
func accessControlSetup(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
// Calling grant directly on internal permissions service to avoid AC check for "grant"
|
||||
var p = service.DefaultPermissions
|
||||
var ac = service.DefaultAccessControl
|
||||
return p.Grant(ctx, ac.Whitelist(), ac.DefaultRules()...)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
sqlTypes "github.com/jmoiron/sqlx/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
@@ -47,6 +48,10 @@ func Exporter(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
nsOut = Namespace{}
|
||||
)
|
||||
|
||||
if nsFlag == "" {
|
||||
cli.HandleError(errors.New("Specify namespace to export from"))
|
||||
}
|
||||
|
||||
if namespaceID, _ := strconv.ParseUint(nsFlag, 10, 64); namespaceID > 0 {
|
||||
ns, err = service.DefaultNamespace.FindByID(namespaceID)
|
||||
if err != repository.ErrNamespaceNotFound {
|
||||
@@ -65,8 +70,8 @@ func Exporter(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
//
|
||||
// Roles are use for resolving access control
|
||||
roles = sysTypes.RoleSet{
|
||||
&sysTypes.Role{ID: 1, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: 2, Handle: "admins"},
|
||||
&sysTypes.Role{ID: permissions.EveryoneRoleID, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: permissions.AdminRoleID, Handle: "admins"},
|
||||
}
|
||||
|
||||
modules, _, err := service.DefaultModule.Find(types.ModuleFilter{NamespaceID: ns.ID})
|
||||
@@ -90,13 +95,13 @@ func Exporter(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
|
||||
y := yaml.NewEncoder(cmd.OutOrStdout())
|
||||
|
||||
nsOut.Name = ns.Name
|
||||
nsOut.Handle = ns.Slug
|
||||
nsOut.Enabled = ns.Enabled
|
||||
nsOut.Meta = ns.Meta
|
||||
|
||||
nsOut.Allow = expResourcePermissions(permissions.Allow, ns.PermissionResource())
|
||||
nsOut.Deny = expResourcePermissions(permissions.Deny, ns.PermissionResource())
|
||||
// nsOut.Name = ns.Name
|
||||
// nsOut.Handle = ns.Slug
|
||||
// nsOut.Enabled = ns.Enabled
|
||||
// nsOut.Meta = ns.Meta
|
||||
//
|
||||
// nsOut.Allow = expResourcePermissions(permissions.Allow, ns.PermissionResource())
|
||||
// nsOut.Deny = expResourcePermissions(permissions.Deny, ns.PermissionResource())
|
||||
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
@@ -114,14 +119,15 @@ func Exporter(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
out.Namespaces[ns.Slug] = nsOut
|
||||
// out.Namespaces[ns.Slug] = nsOut
|
||||
nsOut.Namespace = ns.Slug
|
||||
|
||||
_, _ = y, out
|
||||
cli.HandleError(y.Encode(out))
|
||||
cli.HandleError(y.Encode(nsOut))
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String("namespace", "crm", "Export namespace resources (by ID or string)")
|
||||
cmd.Flags().String("namespace", "", "Export namespace resources (by ID or string)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -138,13 +144,16 @@ type (
|
||||
}
|
||||
|
||||
Namespace struct {
|
||||
// This is used when exporting one single namespace
|
||||
Namespace string `yaml:",omitempty"`
|
||||
|
||||
Name string `yaml:",omitempty"`
|
||||
Handle string `yaml:",omitempty"`
|
||||
Enabled bool `yaml:",omitempty"`
|
||||
Meta types.NamespaceMeta `yaml:",omitempty"`
|
||||
|
||||
Modules map[string]Module `yaml:",omitempty"`
|
||||
Pages map[string]Page `yaml:",omitempty"`
|
||||
Pages yaml.MapSlice `yaml:",omitempty"`
|
||||
Charts map[string]Chart `yaml:",omitempty"`
|
||||
Scripts map[string]Script `yaml:",omitempty"`
|
||||
|
||||
@@ -155,7 +164,7 @@ type (
|
||||
Module struct {
|
||||
Name string
|
||||
Meta string `yaml:"meta,omitempty"`
|
||||
Fields map[string]Field
|
||||
Fields yaml.MapSlice
|
||||
|
||||
Allow map[string][]string `yaml:",omitempty"`
|
||||
Deny map[string][]string `yaml:",omitempty"`
|
||||
@@ -184,7 +193,7 @@ type (
|
||||
|
||||
Blocks types.PageBlocks `yaml:",omitempty"`
|
||||
|
||||
Pages map[string]Page `yaml:",omitempty"`
|
||||
Pages yaml.MapSlice `yaml:",omitempty"`
|
||||
|
||||
Visible bool
|
||||
|
||||
@@ -275,21 +284,24 @@ func expModuleMetaCleanup(meta sqlTypes.JSONText) string {
|
||||
return meta.String()
|
||||
}
|
||||
|
||||
func expModuleFields(ff types.ModuleFieldSet, modules types.ModuleSet) (o map[string]Field) {
|
||||
o = make(map[string]Field)
|
||||
func expModuleFields(ff types.ModuleFieldSet, modules types.ModuleSet) (o yaml.MapSlice) {
|
||||
o = make(yaml.MapSlice, len(ff))
|
||||
|
||||
for _, f := range ff {
|
||||
o[f.Name] = Field{
|
||||
Label: f.Label,
|
||||
Kind: f.Kind,
|
||||
Options: expModuleFieldOptions(f, modules),
|
||||
Private: f.Private,
|
||||
Required: f.Required,
|
||||
Visible: f.Visible,
|
||||
Multi: f.Multi,
|
||||
for i, f := range ff {
|
||||
o[i] = yaml.MapItem{
|
||||
Key: f.Name,
|
||||
Value: Field{
|
||||
Label: f.Label,
|
||||
Kind: f.Kind,
|
||||
Options: expModuleFieldOptions(f, modules),
|
||||
Private: f.Private,
|
||||
Required: f.Required,
|
||||
Visible: f.Visible,
|
||||
Multi: f.Multi,
|
||||
|
||||
Allow: expResourcePermissions(permissions.Allow, types.ModuleFieldPermissionResource),
|
||||
Deny: expResourcePermissions(permissions.Deny, types.ModuleFieldPermissionResource),
|
||||
Allow: expResourcePermissions(permissions.Allow, types.ModuleFieldPermissionResource),
|
||||
Deny: expResourcePermissions(permissions.Deny, types.ModuleFieldPermissionResource),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,12 +364,12 @@ func expModuleFieldOptions(f *types.ModuleField, modules types.ModuleSet) types.
|
||||
return out
|
||||
}
|
||||
|
||||
func expPages(parentID uint64, pages types.PageSet, modules types.ModuleSet, charts types.ChartSet, scripts automation.ScriptSet) (o map[string]Page) {
|
||||
func expPages(parentID uint64, pages types.PageSet, modules types.ModuleSet, charts types.ChartSet, scripts automation.ScriptSet) (o yaml.MapSlice) {
|
||||
var (
|
||||
children = pages.FindByParent(parentID)
|
||||
handle string
|
||||
)
|
||||
o = map[string]Page{}
|
||||
o = yaml.MapSlice{}
|
||||
|
||||
for _, child := range children {
|
||||
page := Page{
|
||||
@@ -388,7 +400,10 @@ func expPages(parentID uint64, pages types.PageSet, modules types.ModuleSet, cha
|
||||
|
||||
pagesHandles[handle] = true
|
||||
|
||||
o[handle] = page
|
||||
o = append(o, yaml.MapItem{
|
||||
Key: handle,
|
||||
Value: page,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
@@ -698,7 +713,7 @@ func makeHandleFromName(name, currentHandle, def string, id uint64) string {
|
||||
return currentHandle
|
||||
}
|
||||
|
||||
newHandle := strings.ReplaceAll(name, " ", "_")
|
||||
newHandle := strings.ReplaceAll(strings.Title(name), " ", "")
|
||||
newHandle = regexp.MustCompile(`[^0-9A-Za-z_\-.]+`).ReplaceAllString(newHandle, "")
|
||||
if handle.IsValid(newHandle) {
|
||||
return newHandle
|
||||
|
||||
+4
-4
@@ -51,8 +51,8 @@ func Configure() *cli.Config {
|
||||
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
if c.ProvisionOpt.AutoSetup {
|
||||
cli.HandleError(accessControlSetup(ctx, cmd, c))
|
||||
if c.ProvisionOpt.Configuration {
|
||||
cli.HandleError(provisionConfig(ctx, cmd, c))
|
||||
}
|
||||
|
||||
go service.Watchers(ctx)
|
||||
@@ -86,8 +86,8 @@ func Configure() *cli.Config {
|
||||
},
|
||||
},
|
||||
|
||||
ProvisionAccessControl: cli.Runners{
|
||||
accessControlSetup,
|
||||
ProvisionConfig: cli.Runners{
|
||||
provisionConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,11 @@ func (asImp *AutomationScript) Store(ctx context.Context, k automationScriptKeep
|
||||
func (asImp *AutomationScript) resolveRefs() error {
|
||||
for _, ref := range asImp.modRefs {
|
||||
s := asImp.set.FindByName(ref.as, asImp.namespace.ID)
|
||||
if s == nil {
|
||||
// try to find it in no-mans land
|
||||
s = asImp.set.FindByName(ref.as, 0)
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
return errors.Errorf("invalid reference, unknown automation script (%v)", ref)
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ func Import(ctx context.Context, ns *types.Namespace, ff ...io.Reader) (err erro
|
||||
//
|
||||
// Roles are use for resolving access control
|
||||
roles = sysTypes.RoleSet{
|
||||
&sysTypes.Role{ID: 1, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: 2, Handle: "admins"},
|
||||
&sysTypes.Role{ID: permissions.EveryoneRoleID, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: permissions.AdminRoleID, Handle: "admins"},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -147,27 +147,7 @@ func (mImp *Module) Cast(handle string, def interface{}) (err error) {
|
||||
|
||||
func (mImp *Module) castFields(module *types.Module, def interface{}) (err error) {
|
||||
return deinterfacer.Each(def, func(_ int, fieldName string, val interface{}) (err error) {
|
||||
if fieldKind, ok := val.(string); ok && fieldName != "" {
|
||||
// Not much more to do here
|
||||
field := module.Fields.FindByName(fieldName)
|
||||
if field == nil {
|
||||
module.Fields = append(module.Fields, &types.ModuleField{
|
||||
Kind: fieldKind,
|
||||
Name: fieldName,
|
||||
Label: fieldName,
|
||||
})
|
||||
} else {
|
||||
field.Kind = fieldKind
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !deinterfacer.IsMap(def) {
|
||||
return errors.New("expecting map of values for module field")
|
||||
}
|
||||
|
||||
deinterfacer.KVsetString(&fieldName, "name", def)
|
||||
deinterfacer.KVsetString(&fieldName, "name", val)
|
||||
field := module.Fields.FindByName(fieldName)
|
||||
|
||||
if field == nil {
|
||||
@@ -182,21 +162,27 @@ func (mImp *Module) castFields(module *types.Module, def interface{}) (err error
|
||||
|
||||
return deinterfacer.Each(val, func(_ int, key string, val interface{}) (err error) {
|
||||
switch key {
|
||||
case "name":
|
||||
// already handled
|
||||
|
||||
case "label":
|
||||
field.Label = deinterfacer.ToString(val)
|
||||
|
||||
case "kind", "type":
|
||||
field.Kind = deinterfacer.ToString(val)
|
||||
|
||||
case "options":
|
||||
// @todo ModuleField.Options
|
||||
return mImp.castFieldOptions(field, val)
|
||||
|
||||
case "private":
|
||||
field.Private = deinterfacer.ToBool(val)
|
||||
|
||||
case "required":
|
||||
field.Required = deinterfacer.ToBool(val)
|
||||
|
||||
case "visible":
|
||||
field.Visible = deinterfacer.ToBool(val)
|
||||
|
||||
case "multi":
|
||||
field.Multi = deinterfacer.ToBool(val)
|
||||
|
||||
|
||||
@@ -9,32 +9,35 @@ import (
|
||||
)
|
||||
|
||||
func TestModuleImport_CastSet(t *testing.T) {
|
||||
impFixTester(t, "module_full", func(t *testing.T, module *Module) {
|
||||
stdFieldsAsTest := func(t *testing.T, module *Module) {
|
||||
// map definition's sort order is unreliable
|
||||
req := require.New(t)
|
||||
|
||||
req.Len(module.set, 1)
|
||||
|
||||
tc := module.set.FindByHandle("mod1")
|
||||
req.Equal(tc.Name, "Module with fields")
|
||||
req.Equal(tc.Fields, types.ModuleFieldSet{
|
||||
{
|
||||
Name: "f1",
|
||||
Kind: "Number",
|
||||
Label: "f1",
|
||||
},
|
||||
{
|
||||
req.Len(tc.Fields, 2)
|
||||
req.Equal(tc.Fields.FindByName("f1"), &types.ModuleField{
|
||||
Name: "f1",
|
||||
Kind: "Number",
|
||||
Label: "f1",
|
||||
})
|
||||
|
||||
Name: "f2",
|
||||
Kind: "String",
|
||||
Label: "F2",
|
||||
Place: 1,
|
||||
Required: true,
|
||||
Options: map[string]interface{}{
|
||||
"multiLine": true,
|
||||
"useRichTextEditor": true,
|
||||
"multiDelimiter": "\n",
|
||||
},
|
||||
req.Equal(tc.Fields.FindByName("f2"), &types.ModuleField{
|
||||
Name: "f2",
|
||||
Kind: "String",
|
||||
Label: "F2",
|
||||
Place: 1,
|
||||
Required: true,
|
||||
Options: map[string]interface{}{
|
||||
"multiLine": true,
|
||||
"useRichTextEditor": true,
|
||||
"multiDelimiter": "\n",
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
impFixTester(t, "module_fields_as_slice", stdFieldsAsTest)
|
||||
impFixTester(t, "module_fields_as_map", stdFieldsAsTest)
|
||||
}
|
||||
|
||||
@@ -247,14 +247,18 @@ func (nsImp *Namespace) Store(ctx context.Context, nsk namespaceKeeper, mk modul
|
||||
if err = nsImp.modules[handle].Store(ctx, mk); err != nil {
|
||||
return errors.Wrap(err, "could not import modules")
|
||||
}
|
||||
|
||||
nsImp.scripts[handle].namespace = namespace
|
||||
if err = nsImp.scripts[handle].Store(ctx, sk); err != nil {
|
||||
return errors.Wrap(err, "could not import automation scripts")
|
||||
}
|
||||
|
||||
nsImp.charts[handle].namespace = namespace
|
||||
if err = nsImp.charts[handle].Store(ctx, ck); err != nil {
|
||||
return errors.Wrap(err, "could not import charts")
|
||||
}
|
||||
|
||||
nsImp.pages[handle].namespace = namespace
|
||||
if err = nsImp.pages[handle].Store(ctx, pk); err != nil {
|
||||
return errors.Wrap(err, "could not import pages")
|
||||
}
|
||||
|
||||
+135
-94
@@ -3,7 +3,6 @@ package importer
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -131,9 +130,6 @@ func (pImp *Page) cast(parent, handle string, def interface{}) (err error) {
|
||||
|
||||
pImp.tree[parent] = append(pImp.tree[parent], handle)
|
||||
|
||||
// Make pages are always sorted
|
||||
sort.Strings(pImp.tree[parent])
|
||||
|
||||
if title, ok := def.(string); ok && title != "" {
|
||||
page.Title = title
|
||||
return nil
|
||||
@@ -280,17 +276,29 @@ func (pImp *Page) storeChildren(ctx context.Context, parent string, k pageKeeper
|
||||
return nil
|
||||
}
|
||||
|
||||
var parentPage *types.Page
|
||||
if parent != "" {
|
||||
parentPage, err = pImp.Get(parent)
|
||||
if err != nil {
|
||||
return
|
||||
} else if parentPage == nil {
|
||||
return errors.Errorf("could not load parent %q", parent)
|
||||
}
|
||||
}
|
||||
|
||||
var page *types.Page
|
||||
|
||||
for _, child := range children {
|
||||
for w, child := range children {
|
||||
if page, err = pImp.Get(child); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = pImp.resolveRefs(page); err != nil {
|
||||
return
|
||||
if parentPage != nil {
|
||||
page.SelfID = parentPage.ID
|
||||
}
|
||||
|
||||
page.Weight = w
|
||||
|
||||
if page.ID == 0 {
|
||||
page.NamespaceID = pImp.namespace.ID
|
||||
page, err = k.Create(page)
|
||||
@@ -314,127 +322,160 @@ func (pImp *Page) storeChildren(ctx context.Context, parent string, k pageKeeper
|
||||
}
|
||||
}
|
||||
|
||||
// We do that at the end - and save all pages with resolved references
|
||||
//
|
||||
// Many because internal page referencing from page blocks
|
||||
var refs uint
|
||||
for _, child := range children {
|
||||
if page, err = pImp.Get(child); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if refs, err = pImp.resolveRefs(page); err != nil {
|
||||
return
|
||||
} else if refs > 0 {
|
||||
// make sure we do not get stale-data error
|
||||
page.UpdatedAt = nil
|
||||
if _, err = k.Update(page); err != nil {
|
||||
return errors.Wrap(err, "could not update resolved refs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve all refs for this page (page module, inside block)
|
||||
func (pImp *Page) resolveRefs(page *types.Page) error {
|
||||
if moduleHandle, ok := pImp.modules[page.Handle]; ok {
|
||||
if module, err := pImp.getModule(moduleHandle); err != nil {
|
||||
return err
|
||||
} else if module == nil {
|
||||
return errors.Wrapf(err, "could not load module %q for page %q",
|
||||
moduleHandle, page.Handle)
|
||||
} else {
|
||||
page.ModuleID = module.ID
|
||||
}
|
||||
}
|
||||
//
|
||||
// It counts number of resolved refs so that caller can know
|
||||
// if there is anything to save
|
||||
func (pImp *Page) resolveRefs(page *types.Page) (uint, error) {
|
||||
var refs uint
|
||||
|
||||
for i, b := range page.Blocks {
|
||||
if b.Options == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if h, ok := b.Options["module"]; ok {
|
||||
if refm, err := pImp.getModule(deinterfacer.ToString(h)); err != nil || refm == nil {
|
||||
return errors.Errorf("could not load module %q for page %q block #%d (%v)",
|
||||
h, page.Handle, i+1, err)
|
||||
return refs, func() error {
|
||||
if moduleHandle, ok := pImp.modules[page.Handle]; ok {
|
||||
if module, err := pImp.getModule(moduleHandle); err != nil {
|
||||
return err
|
||||
} else if module == nil {
|
||||
return errors.Wrapf(err, "could not load module %q for page %q",
|
||||
moduleHandle, page.Handle)
|
||||
} else {
|
||||
b.Options["moduleID"] = strconv.FormatUint(refm.ID, 10)
|
||||
delete(b.Options, "module")
|
||||
page.ModuleID = module.ID
|
||||
refs++
|
||||
}
|
||||
}
|
||||
|
||||
if h, ok := b.Options["page"]; ok {
|
||||
if refp, err := pImp.Get(deinterfacer.ToString(h)); err != nil || refp == nil {
|
||||
return errors.Errorf("could not load page %q for page %q block #%d (%v)",
|
||||
h, page.Handle, i+1, err)
|
||||
} else {
|
||||
b.Options["pageID"] = strconv.FormatUint(refp.ID, 10)
|
||||
delete(b.Options, "page")
|
||||
for i, b := range page.Blocks {
|
||||
if b.Options == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if h, ok := b.Options["chart"]; ok {
|
||||
if refc, err := pImp.getChart(deinterfacer.ToString(h)); err != nil || refc == nil {
|
||||
return errors.Errorf("could not load chart %q for page %q block #%d (%v)",
|
||||
h, page.Handle, i+1, err)
|
||||
} else {
|
||||
b.Options["chartID"] = strconv.FormatUint(refc.ID, 10)
|
||||
delete(b.Options, "chart")
|
||||
if h, ok := b.Options["module"]; ok {
|
||||
if refm, err := pImp.getModule(deinterfacer.ToString(h)); err != nil || refm == nil {
|
||||
return errors.Errorf("could not load module %q for page %q block #%d (%v)",
|
||||
h, page.Handle, i+1, err)
|
||||
} else {
|
||||
b.Options["moduleID"] = strconv.FormatUint(refm.ID, 10)
|
||||
delete(b.Options, "module")
|
||||
refs++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if b.Kind == "Automation" {
|
||||
bb := make([]interface{}, 0)
|
||||
err := deinterfacer.Each(b.Options["buttons"], func(_ int, _ string, btn interface{}) (err error) {
|
||||
button := map[string]interface{}{}
|
||||
if h, ok := b.Options["page"]; ok {
|
||||
if refp, err := pImp.Get(deinterfacer.ToString(h)); err != nil || refp == nil {
|
||||
return errors.Errorf("could not load page %q for page %q block #%d (%v)",
|
||||
h, page.Handle, i+1, err)
|
||||
} else {
|
||||
b.Options["pageID"] = strconv.FormatUint(refp.ID, 10)
|
||||
delete(b.Options, "page")
|
||||
refs++
|
||||
}
|
||||
}
|
||||
|
||||
err = deinterfacer.Each(btn, func(_ int, k string, v interface{}) error {
|
||||
switch k {
|
||||
case "script":
|
||||
if s, err := pImp.getScript(deinterfacer.ToString(v)); err != nil || s == nil {
|
||||
return errors.Errorf("could not load script %q for page %q block #%d (%v)",
|
||||
v, page.Handle, i+1, err)
|
||||
} else {
|
||||
button["scriptID"] = s.ID
|
||||
if h, ok := b.Options["chart"]; ok {
|
||||
if refc, err := pImp.getChart(deinterfacer.ToString(h)); err != nil || refc == nil {
|
||||
return errors.Errorf("could not load chart %q for page %q block #%d (%v)",
|
||||
h, page.Handle, i+1, err)
|
||||
} else {
|
||||
b.Options["chartID"] = strconv.FormatUint(refc.ID, 10)
|
||||
delete(b.Options, "chart")
|
||||
refs++
|
||||
}
|
||||
}
|
||||
|
||||
if b.Kind == "Automation" {
|
||||
bb := make([]interface{}, 0)
|
||||
err := deinterfacer.Each(b.Options["buttons"], func(_ int, _ string, btn interface{}) (err error) {
|
||||
button := map[string]interface{}{}
|
||||
|
||||
err = deinterfacer.Each(btn, func(_ int, k string, v interface{}) error {
|
||||
switch k {
|
||||
case "script":
|
||||
if s, err := pImp.getScript(deinterfacer.ToString(v)); err != nil || s == nil {
|
||||
return errors.Errorf("could not load script %q for page %q block #%d (%v)",
|
||||
v, page.Handle, i+1, err)
|
||||
} else {
|
||||
button["scriptID"] = s.ID
|
||||
refs++
|
||||
}
|
||||
default:
|
||||
button[k] = v
|
||||
}
|
||||
default:
|
||||
button[k] = v
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bb = append(bb, button)
|
||||
return nil
|
||||
})
|
||||
|
||||
b.Options["buttons"] = bb
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if b.Kind == "Calendar" {
|
||||
ff := make([]interface{}, 0)
|
||||
err := deinterfacer.Each(b.Options["feeds"], func(_ int, _ string, def interface{}) (err error) {
|
||||
feed := map[string]interface{}{}
|
||||
|
||||
bb = append(bb, button)
|
||||
return nil
|
||||
})
|
||||
|
||||
b.Options["buttons"] = bb
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if b.Kind == "Calendar" {
|
||||
ff := make([]interface{}, 0)
|
||||
err := deinterfacer.Each(b.Options["feeds"], func(_ int, _ string, def interface{}) (err error) {
|
||||
feed := map[string]interface{}{}
|
||||
|
||||
err = deinterfacer.Each(def, func(_ int, k string, v interface{}) error {
|
||||
switch k {
|
||||
case "module":
|
||||
if m, err := pImp.getModule(deinterfacer.ToString(v)); err != nil || m == nil {
|
||||
return errors.Errorf("could not load module %q for page %q block #%d (%v)",
|
||||
v, page.Handle, i+1, err)
|
||||
} else {
|
||||
feed["moduleID"] = m.ID
|
||||
err = deinterfacer.Each(def, func(_ int, k string, v interface{}) error {
|
||||
switch k {
|
||||
case "module":
|
||||
if m, err := pImp.getModule(deinterfacer.ToString(v)); err != nil || m == nil {
|
||||
return errors.Errorf("could not load module %q for page %q block #%d (%v)",
|
||||
v, page.Handle, i+1, err)
|
||||
} else {
|
||||
feed["moduleID"] = m.ID
|
||||
refs++
|
||||
}
|
||||
default:
|
||||
feed[k] = v
|
||||
}
|
||||
default:
|
||||
feed[k] = v
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ff = append(ff, feed)
|
||||
return nil
|
||||
})
|
||||
|
||||
b.Options["feeds"] = ff
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ff = append(ff, feed)
|
||||
return nil
|
||||
})
|
||||
|
||||
b.Options["feeds"] = ff
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}()
|
||||
}
|
||||
|
||||
Vendored
+3
-2
@@ -2,13 +2,14 @@ modules:
|
||||
mod1:
|
||||
name: Module with fields
|
||||
fields:
|
||||
f1: Number
|
||||
f1:
|
||||
kind: Number
|
||||
f2:
|
||||
kind: String
|
||||
label: F2
|
||||
required: true
|
||||
options:
|
||||
multiLine: true
|
||||
useRichTextEditor: true
|
||||
multiDelimiter: |2+
|
||||
|
||||
useRichTextEditor: true
|
||||
@@ -0,0 +1,15 @@
|
||||
modules:
|
||||
mod1:
|
||||
name: Module with fields
|
||||
fields:
|
||||
- name: f1
|
||||
type: Number
|
||||
- name: f2
|
||||
kind: String
|
||||
label: F2
|
||||
required: true
|
||||
options:
|
||||
multiLine: true
|
||||
multiDelimiter: |2+
|
||||
|
||||
useRichTextEditor: true
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
pages:
|
||||
root:
|
||||
- handle: root
|
||||
title: Root page
|
||||
pages:
|
||||
sub1:
|
||||
- handle: sub1
|
||||
title: Sub page 1
|
||||
blocks:
|
||||
- title: B1
|
||||
@@ -12,8 +12,8 @@ pages:
|
||||
- title: B2
|
||||
xywh: [ 11, 12, 13, 14 ]
|
||||
kind: TheTestingKind
|
||||
sub2:
|
||||
- handle: sub2
|
||||
title: Sub page 2
|
||||
pages:
|
||||
sub21:
|
||||
- handle: sub21
|
||||
title: Sub-sub page 2.1
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package compose
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/importer"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
impAux "github.com/cortezaproject/corteza-server/pkg/importer"
|
||||
provision "github.com/cortezaproject/corteza-server/provision/compose"
|
||||
)
|
||||
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
c.Log.Debug("running configuration provision")
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
// Make sure we have all full access for provisioning
|
||||
ctx = auth.SetSuperUserContext(ctx)
|
||||
|
||||
if provisioned, err := isProvisioned(ctx); err != nil {
|
||||
return err
|
||||
} else if provisioned {
|
||||
c.Log.Debug("configuration already provisioned")
|
||||
return nil
|
||||
}
|
||||
|
||||
readers, err := impAux.ReadStatic(provision.Asset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Wrap(
|
||||
importer.Import(ctx, nil, readers...),
|
||||
"could not provision configuration for compose service",
|
||||
)
|
||||
}
|
||||
|
||||
// Provision only where there are no namespaces
|
||||
func isProvisioned(ctx context.Context) (bool, error) {
|
||||
_, f, err := service.DefaultNamespace.With(ctx).Find(types.NamespaceFilter{})
|
||||
return f.Count > 0, err
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package messaging
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/messaging/repository"
|
||||
"github.com/cortezaproject/corteza-server/messaging/service"
|
||||
"github.com/cortezaproject/corteza-server/messaging/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
)
|
||||
|
||||
func accessControlSetup(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
// Calling grant directly on internal permissions service to avoid AC check for "grant"
|
||||
var p = service.DefaultPermissions
|
||||
var ac = service.DefaultAccessControl
|
||||
return p.Grant(ctx, ac.Whitelist(), ac.DefaultRules()...)
|
||||
}
|
||||
|
||||
// Add default channels when there are none
|
||||
func makeDefaultChannels(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
db, err := factory.Database.Get(messaging)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repo := repository.Channel(ctx, db)
|
||||
|
||||
cc, err := repo.Find(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(cc) == 0 {
|
||||
cc = types.ChannelSet{
|
||||
&types.Channel{Name: "General"},
|
||||
&types.Channel{Name: "Random"},
|
||||
}
|
||||
|
||||
err = cc.Walk(func(c *types.Channel) error {
|
||||
_, err := repo.Create(c)
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/messaging/service"
|
||||
"github.com/cortezaproject/corteza-server/messaging/types"
|
||||
sysTypes "github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
// Import performs standard import procedure with default services
|
||||
func Import(ctx context.Context, ff ...io.Reader) (err error) {
|
||||
var (
|
||||
cc types.ChannelSet
|
||||
aux interface{}
|
||||
)
|
||||
|
||||
cc, err = service.DefaultChannel.With(ctx).Find(&types.ChannelFilter{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
p = permissions.NewImporter(service.DefaultAccessControl.Whitelist())
|
||||
imp = NewImporter(
|
||||
p,
|
||||
NewChannelImport(p, cc),
|
||||
)
|
||||
|
||||
// At the moment, we can not load roles from system service
|
||||
// so we'll just use static set of known roles
|
||||
//
|
||||
// Roles are use for resolving access control
|
||||
roles = sysTypes.RoleSet{
|
||||
&sysTypes.Role{ID: permissions.EveryoneRoleID, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: permissions.AdminRoleID, Handle: "admins"},
|
||||
}
|
||||
)
|
||||
|
||||
for _, f := range ff {
|
||||
if err = yaml.NewDecoder(f).Decode(&aux); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = imp.Cast(aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Store all imported
|
||||
return imp.Store(
|
||||
ctx,
|
||||
service.DefaultChannel.With(ctx),
|
||||
service.DefaultAccessControl,
|
||||
roles,
|
||||
)
|
||||
}
|
||||
@@ -54,6 +54,10 @@ func Configure() *cli.Config {
|
||||
cli.HandleError(c.ProvisionMigrateDatabase.Run(ctx, cmd, c))
|
||||
}
|
||||
|
||||
if c.ProvisionOpt.Configuration {
|
||||
cli.HandleError(provisionConfig(ctx, cmd, c))
|
||||
}
|
||||
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
var websocketOpt = options.Websocket(messaging)
|
||||
@@ -64,11 +68,6 @@ func Configure() *cli.Config {
|
||||
PingPeriod: websocketOpt.PingPeriod,
|
||||
})
|
||||
|
||||
if c.ProvisionOpt.AutoSetup {
|
||||
cli.HandleError(accessControlSetup(ctx, cmd, c))
|
||||
cli.HandleError(makeDefaultChannels(ctx, cmd, c))
|
||||
}
|
||||
|
||||
go service.Watchers(ctx)
|
||||
return nil
|
||||
},
|
||||
@@ -93,8 +92,8 @@ func Configure() *cli.Config {
|
||||
},
|
||||
},
|
||||
|
||||
ProvisionAccessControl: cli.Runners{
|
||||
accessControlSetup,
|
||||
ProvisionConfig: cli.Runners{
|
||||
provisionConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package messaging
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/messaging/importer"
|
||||
"github.com/cortezaproject/corteza-server/messaging/service"
|
||||
"github.com/cortezaproject/corteza-server/messaging/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
impAux "github.com/cortezaproject/corteza-server/pkg/importer"
|
||||
provision "github.com/cortezaproject/corteza-server/provision/messaging"
|
||||
)
|
||||
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
c.Log.Debug("running configuration provision")
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
// Make sure we have all full access for provisioning
|
||||
ctx = auth.SetSuperUserContext(ctx)
|
||||
|
||||
if provisioned, err := isProvisioned(ctx); err != nil {
|
||||
return err
|
||||
} else if provisioned {
|
||||
c.Log.Debug("configuration already provisioned")
|
||||
return nil
|
||||
}
|
||||
|
||||
readers, err := impAux.ReadStatic(provision.Asset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Wrap(
|
||||
importer.Import(ctx, readers...),
|
||||
"could not provision configuration for messaging service",
|
||||
)
|
||||
}
|
||||
|
||||
// Provision ONLY when there are no channels (even if we find delete channels we abort provisioning
|
||||
func isProvisioned(ctx context.Context) (bool, error) {
|
||||
cc, err := service.DefaultChannel.With(ctx).Find(&types.ChannelFilter{IncludeDeleted: true})
|
||||
return len(cc) > 0, err
|
||||
}
|
||||
@@ -111,11 +111,11 @@ func Configure() *cli.Config {
|
||||
},
|
||||
},
|
||||
|
||||
ProvisionAccessControl: cli.Runners{
|
||||
ProvisionConfig: cli.Runners{
|
||||
func(ctx context.Context, cmd *cobra.Command, c *cli.Config) (err error) {
|
||||
cli.HandleError(cmp.ProvisionAccessControl.Run(ctx, cmd, cmp))
|
||||
cli.HandleError(msg.ProvisionAccessControl.Run(ctx, cmd, msg))
|
||||
cli.HandleError(sys.ProvisionAccessControl.Run(ctx, cmd, sys))
|
||||
cli.HandleError(cmp.ProvisionConfig.Run(ctx, cmd, cmp))
|
||||
cli.HandleError(msg.ProvisionConfig.Run(ctx, cmd, msg))
|
||||
cli.HandleError(sys.ProvisionConfig.Run(ctx, cmd, sys))
|
||||
return
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,14 +3,14 @@ package options
|
||||
type (
|
||||
ProvisionOpt struct {
|
||||
MigrateDatabase bool `env:"PROVISION_MIGRATE_DATABASE"`
|
||||
AutoSetup bool `env:"PROVISION_AUTO_SETUP"`
|
||||
Configuration bool `env:"PROVISION_CONFIGURATION"`
|
||||
}
|
||||
)
|
||||
|
||||
func Provision(pfix string) (o *ProvisionOpt) {
|
||||
o = &ProvisionOpt{
|
||||
MigrateDatabase: true,
|
||||
AutoSetup: true,
|
||||
Configuration: true,
|
||||
}
|
||||
|
||||
fill(o, pfix)
|
||||
|
||||
+6
-6
@@ -95,7 +95,7 @@ type (
|
||||
|
||||
// Access control initial setup
|
||||
// Reapplies default access control rules for roles "everyone" [1] and "admin" [2]
|
||||
ProvisionAccessControl Runners
|
||||
ProvisionConfig Runners
|
||||
|
||||
// ******************************************************************
|
||||
|
||||
@@ -264,7 +264,7 @@ func (c *Config) MakeCLI(ctx context.Context) (cmd *cobra.Command) {
|
||||
|
||||
cmd.AddCommand(serveApiCmd)
|
||||
|
||||
if len(c.ProvisionMigrateDatabase) > 0 || len(c.ProvisionAccessControl) > 0 {
|
||||
if len(c.ProvisionMigrateDatabase) > 0 || len(c.ProvisionConfig) > 0 {
|
||||
var (
|
||||
provisionCmd = &cobra.Command{
|
||||
Use: "provision",
|
||||
@@ -275,17 +275,17 @@ func (c *Config) MakeCLI(ctx context.Context) (cmd *cobra.Command) {
|
||||
// Add only commands with defined callbacks
|
||||
if len(c.ProvisionMigrateDatabase) > 0 {
|
||||
provisionCmd.AddCommand(&cobra.Command{
|
||||
Use: "access-control-rules",
|
||||
Short: "Reset access control rules & roles",
|
||||
Use: "configuration",
|
||||
Short: "Create permissions & resources",
|
||||
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return c.ProvisionAccessControl.Run(ctx, nil, c)
|
||||
return c.ProvisionConfig.Run(ctx, nil, c)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Add only commands with defined callbacks
|
||||
if len(c.ProvisionAccessControl) > 0 {
|
||||
if len(c.ProvisionConfig) > 0 {
|
||||
provisionCmd.AddCommand(&cobra.Command{
|
||||
Use: "migrate-database",
|
||||
Short: "Run database migration scripts",
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/goware/statik/fs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ReadStatic reads static FS and returns slice of io.Readers
|
||||
func ReadStatic(data string) ([]io.Reader, error) {
|
||||
var (
|
||||
files = make([]string, 0)
|
||||
|
||||
yamlFilter = func(filename string, info os.FileInfo, err error) error {
|
||||
if err == nil && !info.IsDir() {
|
||||
if matched, err := filepath.Match("/*.yaml", filename); matched && err == nil {
|
||||
files = append(files, filename)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
sfs, err = fs.New(data)
|
||||
|
||||
readers []io.Reader
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read static filesystem")
|
||||
}
|
||||
|
||||
if err = fs.Walk(sfs, "/", yamlFilter); err != nil {
|
||||
return nil, errors.Wrap(err, "could not filter files")
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sort.Strings(files)
|
||||
|
||||
for _, file := range files {
|
||||
if bb, err := fs.ReadFile(sfs, file); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not read %s", file)
|
||||
} else {
|
||||
readers = append(readers, bytes.NewBuffer(bb))
|
||||
}
|
||||
}
|
||||
|
||||
return readers, nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
allow:
|
||||
everyone:
|
||||
compose:
|
||||
- access
|
||||
|
||||
admins:
|
||||
compose:
|
||||
- access
|
||||
- grant
|
||||
- namespace.create
|
||||
|
||||
compose:namespace:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
- manage
|
||||
- page.create
|
||||
- module.create
|
||||
- chart.create
|
||||
|
||||
compose:module:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
- record.create
|
||||
- record.read
|
||||
- record.update
|
||||
- record.delete
|
||||
|
||||
compose:chart:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
|
||||
compose:page:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
|
||||
compose:automation-script:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
@@ -0,0 +1,10 @@
|
||||
namespaces:
|
||||
crm:
|
||||
name: CRM
|
||||
allow:
|
||||
everyone:
|
||||
- module.create
|
||||
- read
|
||||
deny:
|
||||
everyone:
|
||||
- delete
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
||||
namespace: crm
|
||||
charts:
|
||||
LeadsByCountry:
|
||||
name: Leads by country
|
||||
config:
|
||||
reports:
|
||||
- metrics:
|
||||
- backgroundColor: '#e5a83b'
|
||||
beginAtZero: true
|
||||
field: count
|
||||
fixTooltips: true
|
||||
label: Number of leads
|
||||
type: bar
|
||||
dimensions:
|
||||
- conditions: {}
|
||||
field: Country
|
||||
modifier: (no grouping / buckets)
|
||||
module: Lead
|
||||
LeadsBySource:
|
||||
name: Leads by source
|
||||
config:
|
||||
reports:
|
||||
- metrics:
|
||||
- backgroundColor: '#36d436'
|
||||
beginAtZero: true
|
||||
field: count
|
||||
label: Number of leads
|
||||
type: bar
|
||||
dimensions:
|
||||
- conditions: {}
|
||||
field: LeadSource
|
||||
modifier: (no grouping / buckets)
|
||||
module: Lead
|
||||
LeadsByType:
|
||||
name: Leads by type
|
||||
config:
|
||||
reports:
|
||||
- metrics:
|
||||
- backgroundColor: '#63da1a'
|
||||
beginAtZero: true
|
||||
field: count
|
||||
label: Number of leads
|
||||
type: bar
|
||||
dimensions:
|
||||
- conditions: {}
|
||||
field: Status
|
||||
modifier: (no grouping / buckets)
|
||||
module: Lead
|
||||
LeadsPerDay:
|
||||
name: Leads per day
|
||||
config:
|
||||
reports:
|
||||
- metrics:
|
||||
- aggregate: SUM
|
||||
axisType: linear
|
||||
backgroundColor: '#fc7507'
|
||||
beginAtZero: true
|
||||
field: count
|
||||
fill: false
|
||||
label: Leads per day
|
||||
type: line
|
||||
dimensions:
|
||||
- conditions: {}
|
||||
field: created_at
|
||||
modifier: DATE
|
||||
module: Lead
|
||||
OpportunitiesByValue:
|
||||
name: Opportunities by value
|
||||
config:
|
||||
reports:
|
||||
- metrics:
|
||||
- aggregate: SUM
|
||||
backgroundColor: '#5977ff'
|
||||
beginAtZero: true
|
||||
field: Amount
|
||||
label: Total value
|
||||
type: bar
|
||||
dimensions:
|
||||
- conditions: {}
|
||||
field: StageName
|
||||
modifier: (no grouping / buckets)
|
||||
module: Opportunity
|
||||
QuarterlyPerformance:
|
||||
name: Quarterly performance
|
||||
config:
|
||||
reports:
|
||||
- filter: Amount > 0
|
||||
metrics:
|
||||
- aggregate: SUM
|
||||
axisPosition: left
|
||||
axisType: linear
|
||||
backgroundColor: '#009eff'
|
||||
beginAtZero: true
|
||||
field: Amount
|
||||
fill: true
|
||||
label: Amount
|
||||
type: line
|
||||
dimensions:
|
||||
- autoSkip: true
|
||||
conditions: {}
|
||||
field: CloseDate
|
||||
modifier: QUARTER
|
||||
module: Opportunity
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
||||
allow:
|
||||
everyone:
|
||||
messaging:
|
||||
- access
|
||||
|
||||
admins:
|
||||
messaging:
|
||||
- access
|
||||
- grant
|
||||
- channel.public.create
|
||||
- channel.private.create
|
||||
- channel.group.create
|
||||
|
||||
messaging:channel:
|
||||
- update
|
||||
- leave
|
||||
- read
|
||||
- join
|
||||
- delete
|
||||
- undelete
|
||||
- archive
|
||||
- unarchive
|
||||
- members.manage
|
||||
- attachments.manage
|
||||
- message.attach
|
||||
- message.update.all
|
||||
- message.update.own
|
||||
- message.delete.all
|
||||
- message.delete.own
|
||||
- message.embed
|
||||
- message.send
|
||||
- message.reply
|
||||
- message.react
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
channels:
|
||||
- name: General
|
||||
type: public
|
||||
- name: Random
|
||||
type: public
|
||||
@@ -0,0 +1,6 @@
|
||||
// Code generated by statik. DO NOT EDIT.
|
||||
|
||||
// Package contains static assets.
|
||||
package messaging
|
||||
|
||||
var Asset = "PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x000000_access_control.yamlUT\x05\x00\x01\x80Cm8allow:\n everyone:\n messaging:\n - access\n\n admins:\n messaging:\n - access\n - grant\n - channel.public.create\n - channel.private.create\n - channel.group.create\n\n messaging:channel:\n - update\n - leave\n - read\n - join\n - delete\n - undelete\n - archive\n - unarchive\n - members.manage\n - attachments.manage\n - message.attach\n - message.update.all\n - message.update.own\n - message.delete.all\n - message.delete.own\n - message.embed\n - message.send\n - message.reply\n - message.react\n\nPK\x07\x08\xa5\xf4PT`\x02\x00\x00`\x02\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00 \x001000_channels.yamlUT\x05\x00\x01\x80Cm8channels:\n - name: General\n type: public\n - name: Random\n type: public\nPK\x07\x08\xe8\x83F\xf8O\x00\x00\x00O\x00\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xa5\xf4PT`\x02\x00\x00`\x02\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x000000_access_control.yamlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xe8\x83F\xf8O\x00\x00\x00O\x00\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xaf\x02\x00\x001000_channels.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x98\x00\x00\x00G\x03\x00\x00\x00\x00"
|
||||
@@ -0,0 +1,38 @@
|
||||
roles:
|
||||
admins: Administrators
|
||||
|
||||
allow:
|
||||
admins:
|
||||
system:
|
||||
- access
|
||||
- grant
|
||||
- settings.read
|
||||
- settings.manage
|
||||
- organisation.create
|
||||
- application.create
|
||||
- user.create
|
||||
- role.create
|
||||
- automation-script.create
|
||||
|
||||
system:application:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
|
||||
system:user:
|
||||
- read
|
||||
- update
|
||||
- suspend
|
||||
- unsuspend
|
||||
- delete
|
||||
|
||||
system:role:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
- members.manage
|
||||
|
||||
system:automation-script:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
@@ -0,0 +1,6 @@
|
||||
// Code generated by statik. DO NOT EDIT.
|
||||
|
||||
// Package contains static assets.
|
||||
package system
|
||||
|
||||
var Asset = "PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x000000_access_control.yamlUT\x05\x00\x01\x80Cm8roles:\n admins: Administrators\n\nallow:\n admins:\n system:\n - access\n - grant\n - settings.read\n - settings.manage\n - organisation.create\n - application.create\n - user.create\n - role.create\n - automation-script.create\n\n system:application:\n - read\n - update\n - delete\n\n system:user:\n - read\n - update\n - suspend\n - unsuspend\n - delete\n\n system:role:\n - read\n - update\n - delete\n - members.manage\n\n system:automation-script:\n - read\n - update\n - delete\nPK\x07\x08\xe5T\x99\x88J\x02\x00\x00J\x02\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xe5T\x99\x88J\x02\x00\x00J\x02\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x000000_access_control.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00O\x00\x00\x00\x99\x02\x00\x00\x00\x00"
|
||||
+3
-19
@@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
function download {
|
||||
SRC="https://raw.githubusercontent.com/cortezaproject/corteza-configs/master/${1}"
|
||||
@@ -13,26 +14,9 @@ function getCrmConfig {
|
||||
NAMES="1000_namespace 1100_modules 1200_charts 1300_scripts 1400_pages"
|
||||
|
||||
for NAME in $NAMES; do
|
||||
download "crm/${NAME}.yaml" "./compose/${NAME}.yaml"
|
||||
download "crm/${NAME}.yaml" "./compose/src/${NAME}.yaml"
|
||||
done
|
||||
}
|
||||
|
||||
function get {
|
||||
getCrmConfig
|
||||
}
|
||||
getCrmConfig
|
||||
|
||||
function gen {
|
||||
echo "generating..."
|
||||
}
|
||||
|
||||
case ${1:-"all"} in
|
||||
gen)
|
||||
gen
|
||||
;;
|
||||
get)
|
||||
get
|
||||
;;
|
||||
all)
|
||||
get
|
||||
gen
|
||||
esac
|
||||
|
||||
Vendored
+1
-1
@@ -115,7 +115,7 @@ func RegisterOidcProvider(ctx context.Context, name, providerUrl string, force,
|
||||
}
|
||||
|
||||
if as.ExternalRedirectUrl == "" {
|
||||
return nil, errors.New("refusing to register oidc privider withoit redirect url")
|
||||
return nil, errors.New("refusing to register OIDC provider without redirect url")
|
||||
}
|
||||
|
||||
p, err := parseExternalProviderUrl(providerUrl)
|
||||
|
||||
@@ -6,14 +6,10 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza-server/system/importer"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
@@ -26,7 +22,6 @@ func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
var (
|
||||
aux interface{}
|
||||
ff []io.Reader
|
||||
err error
|
||||
)
|
||||
@@ -39,33 +34,10 @@ func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
ff[a], err = os.Open(arg)
|
||||
cli.HandleError(err)
|
||||
}
|
||||
cli.HandleError(importer.Import(ctx, ff...))
|
||||
} else {
|
||||
args = []string{"STDIN"}
|
||||
ff = []io.Reader{os.Stdin}
|
||||
cli.HandleError(importer.Import(ctx, os.Stdin))
|
||||
}
|
||||
|
||||
roles, err := service.DefaultRole.With(ctx).Find(&types.RoleFilter{})
|
||||
cli.HandleError(err)
|
||||
|
||||
perm := permissions.NewImporter(service.DefaultAccessControl.Whitelist())
|
||||
|
||||
imp := importer.NewImporter(perm,
|
||||
importer.NewRoleImport(perm, roles),
|
||||
)
|
||||
|
||||
for i, f := range ff {
|
||||
cmd.Printf("Importing from %s\n", args[i])
|
||||
cli.HandleError(yaml.NewDecoder(f).Decode(&aux))
|
||||
|
||||
cli.HandleError(imp.Cast(aux))
|
||||
}
|
||||
|
||||
cli.HandleError(imp.Store(
|
||||
ctx,
|
||||
service.DefaultRole.With(ctx),
|
||||
service.DefaultAccessControl,
|
||||
roles,
|
||||
))
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+27
-10
@@ -16,6 +16,10 @@ import (
|
||||
)
|
||||
|
||||
func Users(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
var (
|
||||
flagNoPassword bool
|
||||
)
|
||||
|
||||
// User management commands.
|
||||
cmd := &cobra.Command{
|
||||
Use: "users",
|
||||
@@ -82,28 +86,41 @@ func Users(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
password []byte
|
||||
)
|
||||
|
||||
if existing, _ := userRepo.FindByEmail(user.Email); existing != nil && existing.ID > 0 {
|
||||
cmd.Printf("User already exists [%d].\n", existing.ID)
|
||||
return
|
||||
}
|
||||
|
||||
if user, err = userRepo.Create(user); err != nil {
|
||||
cli.HandleError(err)
|
||||
}
|
||||
|
||||
cmd.Printf("User created [%d].\n", user.ID)
|
||||
|
||||
cmd.Print("Set password: ")
|
||||
if password, err = terminal.ReadPassword(syscall.Stdin); err != nil {
|
||||
cli.HandleError(err)
|
||||
}
|
||||
if !flagNoPassword {
|
||||
cmd.Print("Set password: ")
|
||||
if password, err = terminal.ReadPassword(syscall.Stdin); err != nil {
|
||||
cli.HandleError(err)
|
||||
}
|
||||
|
||||
if len(password) == 0 {
|
||||
// Password not set, that's ok too.
|
||||
return
|
||||
}
|
||||
if len(password) == 0 {
|
||||
// Password not set, that's ok too.
|
||||
return
|
||||
}
|
||||
|
||||
if err = authSvc.SetPassword(user.ID, string(password)); err != nil {
|
||||
cli.HandleError(err)
|
||||
if err = authSvc.SetPassword(user.ID, string(password)); err != nil {
|
||||
cli.HandleError(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
addCmd.Flags().BoolVar(
|
||||
&flagNoPassword,
|
||||
"no-password",
|
||||
false,
|
||||
"Create user without password")
|
||||
|
||||
pwdCmd := &cobra.Command{
|
||||
Use: "password [email]",
|
||||
Short: "Change password for user",
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
// Import performs standard import procedure with default services
|
||||
func Import(ctx context.Context, ff ...io.Reader) (err error) {
|
||||
var (
|
||||
roles types.RoleSet
|
||||
aux interface{}
|
||||
)
|
||||
|
||||
roles, err = service.DefaultRole.With(ctx).Find(&types.RoleFilter{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pi := permissions.NewImporter(service.DefaultAccessControl.Whitelist())
|
||||
imp := NewImporter(
|
||||
pi,
|
||||
NewRoleImport(pi, roles),
|
||||
)
|
||||
|
||||
for _, f := range ff {
|
||||
if err = yaml.NewDecoder(f).Decode(&aux); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = imp.Cast(aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Get roles across the system
|
||||
// roles, err := service.DefaultSystemRole.Find(ctx)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// Store all imported
|
||||
return imp.Store(
|
||||
ctx,
|
||||
service.DefaultRole.With(ctx),
|
||||
service.DefaultAccessControl,
|
||||
roles,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
impAux "github.com/cortezaproject/corteza-server/pkg/importer"
|
||||
provision "github.com/cortezaproject/corteza-server/provision/system"
|
||||
"github.com/cortezaproject/corteza-server/system/importer"
|
||||
"github.com/cortezaproject/corteza-server/system/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
c.Log.Debug("running configuration provision")
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
// Make sure we have all full access for provisioning
|
||||
ctx = auth.SetSuperUserContext(ctx)
|
||||
|
||||
if provisioned, err := isProvisioned(ctx); err != nil {
|
||||
return err
|
||||
} else if provisioned {
|
||||
c.Log.Debug("configuration already provisioned")
|
||||
return nil
|
||||
}
|
||||
|
||||
readers, err := impAux.ReadStatic(provision.Asset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Wrap(
|
||||
importer.Import(ctx, readers...),
|
||||
"could not provision configuration for system service",
|
||||
)
|
||||
}
|
||||
|
||||
// Provision ONLY when there are no roles
|
||||
func isProvisioned(ctx context.Context) (bool, error) {
|
||||
rr, err := service.DefaultRole.With(ctx).Find(&types.RoleFilter{})
|
||||
return len(rr) > 0, err
|
||||
}
|
||||
|
||||
func makeDefaultApplications(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
db, err := factory.Database.Get(system)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repo := repository.Application(ctx, db)
|
||||
|
||||
aa, err := repo.Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// List of apps to create.
|
||||
//
|
||||
// We use Unify.Url field for matching,
|
||||
// so make sure it's always present!
|
||||
defApps := types.ApplicationSet{
|
||||
&types.Application{
|
||||
Name: "CRM",
|
||||
Enabled: true,
|
||||
Unify: &types.ApplicationUnify{
|
||||
Name: "CRM",
|
||||
Listed: true,
|
||||
Icon: "/applications/crust_favicon.png",
|
||||
Logo: "/applications/crust.jpg",
|
||||
Url: "/compose/ns/crm/pages",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return defApps.Walk(func(defApp *types.Application) error {
|
||||
for _, a := range aa {
|
||||
if a.Unify != nil && a.Unify.Url == defApp.Unify.Url {
|
||||
// App already added.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
defApp, err = repo.Create(defApp)
|
||||
c.Log.Info(
|
||||
"creating default application",
|
||||
zap.String("name", defApp.Name),
|
||||
zap.Uint64("name", defApp.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -2,86 +2,18 @@ package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli/options"
|
||||
"github.com/cortezaproject/corteza-server/system/auth/external"
|
||||
"github.com/cortezaproject/corteza-server/system/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
func accessControlSetup(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
// Calling grant directly on internal permissions service to avoid AC check for "grant"
|
||||
var p = service.DefaultPermissions
|
||||
var ac = service.DefaultAccessControl
|
||||
return p.Grant(ctx, ac.Whitelist(), ac.DefaultRules()...)
|
||||
}
|
||||
|
||||
func makeDefaultApplications(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
db, err := factory.Database.Get(system)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repo := repository.Application(ctx, db)
|
||||
|
||||
aa, err := repo.Find()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// List of apps to create.
|
||||
//
|
||||
// We use Unify.Url field for matching,
|
||||
// so make sure it's always present!
|
||||
defApps := types.ApplicationSet{
|
||||
&types.Application{
|
||||
Name: "CRM",
|
||||
Enabled: true,
|
||||
Unify: &types.ApplicationUnify{
|
||||
Name: "CRM",
|
||||
Listed: true,
|
||||
Icon: "/applications/crust_favicon.png",
|
||||
Logo: "/applications/crust.jpg",
|
||||
Url: "/compose/ns/crm/pages",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return defApps.Walk(func(defApp *types.Application) error {
|
||||
for _, a := range aa {
|
||||
if a.Unify != nil && a.Unify.Url == defApp.Unify.Url {
|
||||
// App already added.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
defApp, err = repo.Create(defApp)
|
||||
c.Log.Info(
|
||||
"creating default application",
|
||||
zap.String("name", defApp.Name),
|
||||
zap.Uint64("name", defApp.ID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func discoverSettings(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
return service.DefaultSettings.With(ctx).AutoDiscovery()
|
||||
}
|
||||
|
||||
func oidcAutoDiscovery(ctx context.Context, cmd *cobra.Command, c *cli.Config) (err error) {
|
||||
var provider = strings.TrimSpace(options.EnvString("", "PROVISION_OIDC_PROVIDER", ""))
|
||||
|
||||
@@ -117,7 +49,7 @@ func oidcAutoDiscovery(ctx context.Context, cmd *cobra.Command, c *cli.Config) (
|
||||
|
||||
if err != nil {
|
||||
c.Log.Error(
|
||||
"could not register oidc provider",
|
||||
"could not register OIDC provider",
|
||||
zap.String("url", purl),
|
||||
zap.String("name", name),
|
||||
zap.Error(err))
|
||||
@@ -126,7 +58,7 @@ func oidcAutoDiscovery(ctx context.Context, cmd *cobra.Command, c *cli.Config) (
|
||||
c.Log.Info("provider already exists",
|
||||
zap.String("name", name))
|
||||
} else {
|
||||
c.Log.Info("provider successfuly registered",
|
||||
c.Log.Info("provider successfully registered",
|
||||
zap.String("url", purl),
|
||||
zap.String("key", eap.Key),
|
||||
zap.String("name", name))
|
||||
@@ -0,0 +1,14 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
)
|
||||
|
||||
func settingsAutoDiscovery(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
return service.DefaultSettings.With(ctx).AutoDiscovery()
|
||||
}
|
||||
+5
-5
@@ -57,11 +57,11 @@ func Configure() *cli.Config {
|
||||
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
if c.ProvisionOpt.AutoSetup {
|
||||
cli.HandleError(accessControlSetup(ctx, cmd, c))
|
||||
if c.ProvisionOpt.Configuration {
|
||||
cli.HandleError(provisionConfig(ctx, cmd, c))
|
||||
cli.HandleError(makeDefaultApplications(ctx, cmd, c))
|
||||
|
||||
cli.HandleError(discoverSettings(ctx, cmd, c))
|
||||
cli.HandleError(settingsAutoDiscovery(ctx, cmd, c))
|
||||
|
||||
// Reload auto-configured settings
|
||||
// adding externals and oidc auto discovery depends on redirect-url setting
|
||||
@@ -154,8 +154,8 @@ func Configure() *cli.Config {
|
||||
},
|
||||
},
|
||||
|
||||
ProvisionAccessControl: cli.Runners{
|
||||
accessControlSetup,
|
||||
ProvisionConfig: cli.Runners{
|
||||
provisionConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ func TestProvisioning(t *testing.T) {
|
||||
aux interface{}
|
||||
|
||||
roles = sysTypes.RoleSet{
|
||||
&sysTypes.Role{ID: 1, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: 2, Handle: "admins"},
|
||||
&sysTypes.Role{ID: permissions.EveryoneRoleID, Handle: "everyone"},
|
||||
&sysTypes.Role{ID: permissions.AdminRoleID, Handle: "admins"},
|
||||
}
|
||||
|
||||
ctx = h.secCtx()
|
||||
|
||||
@@ -19,8 +19,8 @@ func TestProvisioning(t *testing.T) {
|
||||
aux interface{}
|
||||
|
||||
roles = types.RoleSet{
|
||||
&types.Role{ID: 1, Handle: "everyone"},
|
||||
&types.Role{ID: 2, Handle: "admins"},
|
||||
&types.Role{ID: permissions.EveryoneRoleID, Handle: "everyone"},
|
||||
&types.Role{ID: permissions.AdminRoleID, Handle: "admins"},
|
||||
}
|
||||
|
||||
ctx = h.secCtx()
|
||||
|
||||
Reference in New Issue
Block a user