diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 515a85a41..ab009f526 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -27,7 +27,7 @@ jobs: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-go- - - run: make test.all + - run: make test.codegen test.all snapshot-docker: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index 785e3ff0d..f26d1378c 100644 --- a/Makefile +++ b/Makefile @@ -132,14 +132,29 @@ watch.test.%: $(FSWATCH) watch.test: watch.test.unit -# codegen: $(PROTOGEN) -codegen: $(CODEGEN) +# See codegen/README.md for details +codegen: $(CUE) $(JSONTPLEXEC) + $(CUE) eval codegen/*.cue --out json -e platform | $(JSONTPLEXEC) -v + +test.codegen: $(CUE) $(JSONTPLEXEC) + $(CUE) eval codegen/*.cue --out json -e platform + +cue.fmt: $(CUE) + $(CUE) fmt -v codegen/*.cue + $(CUE) fmt -v codegen/schema/*.cue + $(CUE) fmt -v app/*.cue + $(CUE) fmt system/*.cue + $(CUE) fmt compose/*.cue + # $(CUE) fmt automation/*.cue + # $(CUE) fmt federation/*.cue + +codegen-legacy: $(CODEGEN) @ $(CODEGEN) -v -watch.codegen: $(CODEGEN) +watch.codegen-legacy: $(CODEGEN) @ $(CODEGEN) -w -v -clean.codegen: +clean.codegen-legacy: rm -f $(CODEGEN) provision: diff --git a/Makefile.inc b/Makefile.inc index d4a3870a2..e6e536561 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -19,7 +19,9 @@ PROTOGEN_GRPC = $(GOPATH)/bin/protoc-gen-go-grpc GIN = $(GOPATH)/bin/gin STATIK = $(GOPATH)/bin/statik MODOUTDATED = $(GOPATH)/bin/go-mod-outdated +CUE = $(GOPATH)/bin/cue CODEGEN = build/codegen +JSONTPLEXEC = build/json-tpl-exec PROTOC = /usr/local/bin/protoc FSWATCH = /usr/local/bin/fswatch @@ -60,6 +62,13 @@ $(MODOUTDATED): $(CODEGEN): $(GO) build -o $@ cmd/codegen/main.go +$(CUE): + $(GOINSTALL) cuelang.org/go/cmd/cue@latest + +$(JSONTPLEXEC): + $(GO) build -o $@ ./codegen/tool clean-tools: rm -f $(BINS) + +# diff --git a/app/app.cue b/app/app.cue new file mode 100644 index 000000000..36765a6c9 --- /dev/null +++ b/app/app.cue @@ -0,0 +1,20 @@ +package app + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" + "github.com/cortezaproject/corteza-server/system" + "github.com/cortezaproject/corteza-server/compose" + "github.com/cortezaproject/corteza-server/automation" + "github.com/cortezaproject/corteza-server/federation" +) + +corteza: schema.#platform & { + ident: "corteza" + + components: [ + system.component, + compose.component, + automation.component, + federation.component, + ] +} diff --git a/automation/component.cue b/automation/component.cue new file mode 100644 index 000000000..02f2eb66a --- /dev/null +++ b/automation/component.cue @@ -0,0 +1,22 @@ +package automation + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +component: schema.#component & { + handle: "automation" + + resources: { + "workflow": workflow + } + + rbac: operations: { + "grant": description: "Manage automation permissions" + "workflow.create": description: "Create workflows" + "triggers.search": description: "List, search or filter triggers" + "sessions.search": description: "List, search or filter sessions" + "workflows.search": description: "List, search or filter workflows" + "resource-translations.manage": description: "List, search, create, or update resource translations" + } +} diff --git a/automation/service/access_control.gen.go b/automation/service/access_control.gen.go index a44b281da..b7c8eb411 100644 --- a/automation/service/access_control.gen.go +++ b/automation/service/access_control.gen.go @@ -6,10 +6,6 @@ package service // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - automation.workflow.yaml -// - automation.yaml - import ( "context" "fmt" @@ -249,42 +245,48 @@ func (svc accessControl) CanManageSessionsOnWorkflow(ctx context.Context, r *typ // // This function is auto-generated func (svc accessControl) CanGrant(ctx context.Context) bool { - return svc.can(ctx, "grant", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "grant", r) } // CanCreateWorkflow checks if current user can create workflows // // This function is auto-generated func (svc accessControl) CanCreateWorkflow(ctx context.Context) bool { - return svc.can(ctx, "workflow.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "workflow.create", r) } // CanSearchTriggers checks if current user can list, search or filter triggers // // This function is auto-generated func (svc accessControl) CanSearchTriggers(ctx context.Context) bool { - return svc.can(ctx, "triggers.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "triggers.search", r) } // CanSearchSessions checks if current user can list, search or filter sessions // // This function is auto-generated func (svc accessControl) CanSearchSessions(ctx context.Context) bool { - return svc.can(ctx, "sessions.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "sessions.search", r) } // CanSearchWorkflows checks if current user can list, search or filter workflows // // This function is auto-generated func (svc accessControl) CanSearchWorkflows(ctx context.Context) bool { - return svc.can(ctx, "workflows.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "workflows.search", r) } // CanManageResourceTranslations checks if current user can list, search, create, or update resource translations // // This function is auto-generated func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool { - return svc.can(ctx, "resource-translations.manage", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "resource-translations.manage", r) } // rbacResourceValidator validates known component's resource by routing it to the appropriate validator @@ -330,24 +332,24 @@ func rbacResourceOperations(r string) map[string]bool { return nil } -// rbacWorkflowResourceValidator checks validity of rbac resource and operations +// rbacWorkflowResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacWorkflowResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for automation Workflow resource", o) - } - } - if !strings.HasPrefix(r, types.WorkflowResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for workflow resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.WorkflowResourceType):], sep), sep) @@ -363,7 +365,7 @@ func rbacWorkflowResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Workflow", i) + return fmt.Errorf("invalid path wildcard level (%d) for workflow resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -374,23 +376,23 @@ func rbacWorkflowResourceValidator(r string, oo ...string) error { return nil } -// rbacComponentResourceValidator checks validity of rbac resource and operations +// rbacComponentResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacComponentResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for automation resource", o) - } - } - if !strings.HasPrefix(r, types.ComponentResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for automation component resource", o) + } + } + return nil } diff --git a/automation/types/rbac.gen.go b/automation/types/rbac.gen.go index 67b46ebcd..9dabe3f2c 100644 --- a/automation/types/rbac.gen.go +++ b/automation/types/rbac.gen.go @@ -6,10 +6,6 @@ package types // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - automation.workflow.yaml -// - automation.yaml - import ( "fmt" "strconv" @@ -22,6 +18,11 @@ type ( Component struct{} ) +var ( + _ = fmt.Printf + _ = strconv.FormatUint +) + const ( WorkflowResourceType = "corteza::automation:workflow" ComponentResourceType = "corteza::automation" @@ -53,7 +54,6 @@ func WorkflowRbacResource(id uint64) string { } -// @todo template func WorkflowRbacResourceTpl() string { return "%s/%s" } @@ -77,7 +77,6 @@ func ComponentRbacResource() string { } -// @todo template func ComponentRbacResourceTpl() string { return "%s" } diff --git a/automation/workflow.cue b/automation/workflow.cue new file mode 100644 index 000000000..b8dfd40cc --- /dev/null +++ b/automation/workflow.cue @@ -0,0 +1,19 @@ +package automation + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +workflow: schema.#resource & { + rbac: { + operations: { + "read": description: "Read workflow" + "update": description: "Update workflow" + "delete": description: "Delete workflow" + "undelete": description: "Undelete workflow" + "execute": description: "Execute workflow" + "triggers.manage": description: "Manage workflow triggers" + "sessions.manage": description: "Manage workflow sessions" + } + } +} diff --git a/codecov.cue b/codecov.cue new file mode 100644 index 000000000..4d3bb4e5a --- /dev/null +++ b/codecov.cue @@ -0,0 +1 @@ +ignore: ["vendor/.*"] diff --git a/codegen/README.md b/codegen/README.md new file mode 100644 index 000000000..d941d6cac --- /dev/null +++ b/codegen/README.md @@ -0,0 +1,81 @@ +# Corteza codegen tools and definitions + +## History + +See [old codegen](../pkh/codegen/README.md). + +## Plans + +Right now, Corteza is migrating its old YAML definitions to CUE. +We are also simplifying all templates by moving as much data manipulation to Cue as possible. + +## Intro + +Codegen tools are based on [cuelang](https://cuelang.org/docs/tutorials/) and golang templates. + +**What you can find here:** + - [codegen definitions in `codegen/`](./) + - [templates in `codegen/asset/templates`](./asset/templates) + - [schemas in `codegen/schema`](./schema) + - [template exec tool in `codegen/tool`](./tool) + +Platform, component and resource definitions (.cue files) can be found in: + - `app` + - `automation` @todo + - `system` + - `compose` + - `federation` @todo + +## Running code generator + +When a definitions or templates are changed all outputs need to be regenerated + +This can be done with the following command +``` +make codegen +``` +Please note that + + +## How does it work? + +### High-level overview + +See [Makefile's `codegen-cue` task](../Makefile) + +1. evaluate codegen instructions (see [platform.cue](./platform.cue)) +2. output instructions as JSON +3. pipe JSON into [template exec tool](./tool) +4. process instructions, load and execute templates and write to output files. + +### Definition structure + +#### Codegen instructions + +Collection of `#codegen` structs with template + payload + output instructions. Template exec tool iterates over collection and creates output from each one. + +#### Platform + +Main entry point that combines all components + + - @todo options + + - @todo REST endpoints (unrelated to specific component) + +#### Component + +Defines component, it's behaviour, RBAC operations and resources + + - @todo REST endpoints (unrelated to specific resources) + +#### Resource + +Defines resource, it's behaviour, types, RBAC operations, translatable keys + + - @todo events + - @todo actions + - @todo errors + - @todo automation functions + - @todo expression types + - @todo REST endpoints + diff --git a/codegen/assets/templates/gocode/envoy/rbac_references_$component.go.tpl b/codegen/assets/templates/gocode/envoy/rbac_references_$component.go.tpl new file mode 100644 index 000000000..a9e825edb --- /dev/null +++ b/codegen/assets/templates/gocode/envoy/rbac_references_$component.go.tpl @@ -0,0 +1,32 @@ +package {{ .package }} + +{{ template "gocode/header-gentext.tpl" }} + +import ( +{{- range .imports }} + {{ . }} +{{- end }} +) + +{{- range .resources }} +// {{ .rbacRefFunc }} generates RBAC references +// +// Resources with "envoy: false" are skipped +// +// This function is auto-generated +func {{ .rbacRefFunc }}({{- range .references }}{{ .param }} string, {{- end }}) (res *Ref, pp []*Ref, err error) { + {{- range .references }} + {{- if eq .refField "ID" }} + if {{ .param }} != "*" { + res = &Ref{ResourceType: types.{{ .expIdent }}ResourceType, Identifiers: MakeIdentifiers({{ .param }})} + } + {{- else }} + if {{ .param }} != "*" { + pp = append(pp, &Ref{ResourceType: types.{{ .expIdent }}ResourceType, Identifiers: MakeIdentifiers({{ .param }})}) + } + {{- end }} + {{- end }} + + return +} +{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-rbac_rules_parse.go.tpl b/codegen/assets/templates/gocode/envoy/rbac_rules_parse.go.tpl similarity index 56% rename from pkg/codegen-v3/assets/templates/gocode/envoy/resource-rbac_rules_parse.go.tpl rename to codegen/assets/templates/gocode/envoy/rbac_rules_parse.go.tpl index 97efa93c5..6746acdcb 100644 --- a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-rbac_rules_parse.go.tpl +++ b/codegen/assets/templates/gocode/envoy/rbac_rules_parse.go.tpl @@ -1,12 +1,11 @@ -package {{ .Package }} +package {{ .package }} -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} +{{ template "gocode/header-gentext.tpl" }} import ( "fmt" "strings" -{{- range .Imports }} +{{- range .imports }} {{ . }} {{- end }} ) @@ -45,23 +44,22 @@ func ParseRule(res string) (string, *Ref, []*Ref, error) { // make the resource provide the slice of parent resources we should nest under switch resourceType { - {{- range .Def }} - case {{ unexport .Component "types" }}.{{ export .Resource }}ResourceType: - if len(path) != {{ len .RBAC.Resource.References }} { - return "", nil, nil, fmt.Errorf("expecting {{ len .RBAC.Resource.References }} reference components in path, got %d", len(path)) + {{- range .resources }} + case {{ .typeConst }}: + if len(path) != {{ len .references }} { + return "", nil, nil, fmt.Errorf("expecting {{ len .references }} reference components in path, got %d", len(path)) } - {{- if gt (len .RBAC.Resource.References) 0 }} - ref, pp, err := {{ export .Component .Resource }}RbacReferences( - {{- range $i, $r := .RBAC.Resource.References }} - // {{ unexport $r.Resource }} + {{- if gt (len .references) 0 }} + ref, pp, err := {{ .rbacRefFunc }}( + {{- range $i, $r := .references }} path[{{ $i }}], - {{ end }} + {{- end }} ) - return {{ unexport .Component "types" }}.{{ export .Resource }}ResourceType, ref, pp, err + return resourceType, ref, pp, err {{ else }} // Component resource, no path - return {{ unexport .Component "types" }}.{{ export .Resource }}ResourceType, nil, nil, nil + return resourceType, nil, nil, nil {{- end }} {{- end}} } diff --git a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation.go.tpl b/codegen/assets/templates/gocode/envoy/resource_translation.go.tpl similarity index 50% rename from pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation.go.tpl rename to codegen/assets/templates/gocode/envoy/resource_translation.go.tpl index 580d1df0c..721d3462b 100644 --- a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation.go.tpl +++ b/codegen/assets/templates/gocode/envoy/resource_translation.go.tpl @@ -1,27 +1,20 @@ -package {{ .Package }} +package {{ .package }} -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} +{{ template "gocode/header-gentext.tpl" }} import ( systemTypes "github.com/cortezaproject/corteza-server/system/types" -{{- range .Imports }} - {{ . }} -{{- end }} ) -{{- range .Def }} -{{ $Component := .Component }} -{{ $Resource := .Resource }} -{{ $GoType := printf "types.%s" .Resource }} -func (r *{{if not (eq $Component "system")}}{{export $Component}}{{ end }}{{$Resource}}) EncodeTranslations() ([]*ResourceTranslation, error) { +{{- range .resources }} +func (r *{{ .expIdent }}) EncodeTranslations() ([]*ResourceTranslation, error) { out := make([]*ResourceTranslation, 0, 10) rr := r.Res.EncodeTranslations() rr.SetLanguage(defaultLanguage) res, ref, pp := r.ResourceTranslationParts() out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...)) -{{ if .Locale.Extended }} +{{ if .extended }} tmp, err := r.encodeTranslations() return append(out, tmp...), err {{ else }} @@ -29,3 +22,4 @@ func (r *{{if not (eq $Component "system")}}{{export $Component}}{{ end }}{{$Res {{- end }} } {{- end }} + diff --git a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation_parse.go.tpl b/codegen/assets/templates/gocode/envoy/resource_translation_parse.go.tpl similarity index 54% rename from pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation_parse.go.tpl rename to codegen/assets/templates/gocode/envoy/resource_translation_parse.go.tpl index a630a7aeb..a1c8b366c 100644 --- a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation_parse.go.tpl +++ b/codegen/assets/templates/gocode/envoy/resource_translation_parse.go.tpl @@ -1,18 +1,17 @@ -package {{ .Package }} +package {{ .package }} -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} +{{ template "gocode/header-gentext.tpl" }} import ( "fmt" "strings" -{{- range .Imports }} +{{- range .imports }} {{ . }} {{- end }} ) -// Parse generates resource setting logic for each resource +// ParseResourceTranslation generates resource setting logic for each resource // // Resources with "envoy: false" are skipped // @@ -47,25 +46,22 @@ func ParseResourceTranslation(res string) (string, *Ref, []*Ref, error) { // make the resource provide the slice of parent resources we should nest under switch resourceType { - {{- range .Def }} - case {{ unexport .Component "types" }}.{{ export .Resource }}ResourceTranslationType: - if len(path) != {{ len .Locale.Resource.References }} { - return "", nil, nil, fmt.Errorf("expecting {{ len .Locale.Resource.References }} reference components in path, got %d", len(path)) + {{- range .resources }} + case {{ .typeConst }}: + if len(path) != {{ len .references }} { + return "", nil, nil, fmt.Errorf("expecting {{ len .references }} reference components in path, got %d", len(path)) } - {{- if gt (len .Locale.Resource.References) 0 }} - ref, pp, err := {{ export .Component .Resource }}ResourceTranslationReferences( - {{- range $i, $r := .Locale.Resource.References }} - // {{ unexport $r.Resource }} + ref, pp, err := {{ .resTrRefFunc }}( + {{- range $i, $r := .references }} path[{{ $i }}], - {{ end }} + {{- end }} ) - return {{ unexport .Component "types" }}.{{ export .Resource }}ResourceTranslationType, ref, pp, err + return {{ .typeConst }}, ref, pp, err {{ else }} // Component resource, no path - return {{ unexport .Component "types" }}.{{ export .Resource }}ResourceTranslationType, nil, nil, nil + return {{ .typeConst }}, nil, nil, nil {{- end }} - {{- end}} } // return unhandled resource as-is diff --git a/codegen/assets/templates/gocode/envoy/resource_translation_references_$component.go.tpl b/codegen/assets/templates/gocode/envoy/resource_translation_references_$component.go.tpl new file mode 100644 index 000000000..c6e8cda79 --- /dev/null +++ b/codegen/assets/templates/gocode/envoy/resource_translation_references_$component.go.tpl @@ -0,0 +1,24 @@ +package {{ .package }} + +{{ template "gocode/header-gentext.tpl" }} + +import ( +{{- range .imports }} + {{ . }} +{{- end }} +) + +{{- range .resources }} +// {{ .resTrRefFunc }} generates Locale references +// +// This function is auto-generated +func {{ .resTrRefFunc }}({{- range .references }}{{ .param }} string, {{- end }} self string) (res *Ref, pp []*Ref, err error) { + res = &Ref{ResourceType: types.{{ .expIdent }}ResourceType, Identifiers: MakeIdentifiers(self)} + + {{- range .references }} + pp = append(pp, &Ref{ResourceType: types.{{ .expIdent }}ResourceType, Identifiers: MakeIdentifiers({{ .param }})}) + {{- end }} + + return +} +{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/header-gentext.tpl b/codegen/assets/templates/gocode/header-gentext.tpl similarity index 100% rename from pkg/codegen-v3/assets/templates/gocode/header-gentext.tpl rename to codegen/assets/templates/gocode/header-gentext.tpl diff --git a/pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl b/codegen/assets/templates/gocode/locale/$component_service.go.tpl similarity index 74% rename from pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl rename to codegen/assets/templates/gocode/locale/$component_service.go.tpl index 20366955b..f18b25cdd 100644 --- a/pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl +++ b/codegen/assets/templates/gocode/locale/$component_service.go.tpl @@ -1,12 +1,11 @@ -package {{ .Package }} +package {{ .package }} -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} +{{ template "gocode/header-gentext.tpl" }} import ( "context" -{{- range .Imports }} +{{- range .imports }} {{ . }} {{- end }} "github.com/cortezaproject/corteza-server/pkg/actionlog" @@ -36,8 +35,8 @@ type ( } ResourceTranslationsManagerService interface { -{{- range .Def }} - {{ .Resource }}(ctx context.Context, {{ if .Locale.Resource }}{{ range .Locale.Resource.References }}{{ .Field }} uint64, {{ end }}{{ end }}) (locale.ResourceTranslationSet, error) +{{- range .resources }} + {{ .expIdent }}(ctx context.Context, {{ range .references }}{{ . }} uint64, {{ end }}) (locale.ResourceTranslationSet, error) {{- end }} Upsert(context.Context, locale.ResourceTranslationSet) error @@ -103,7 +102,7 @@ func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.Res sysLocale = append(sysLocale, aux...) aux = current.Old(rr) - aux.Walk(func(cc *systemTypes.ResourceTranslation) error { + _ = aux.Walk(func(cc *systemTypes.ResourceTranslation) error { cc.UpdatedAt = now() cc.UpdatedBy = me.Identity() return nil @@ -127,50 +126,41 @@ func (svc resourceTranslationsManager) Locale() locale.Resource { return svc.locale } -{{- range .Def }} -{{ $Resource := .Resource }} -{{ $GoType := printf "types.%s" .Resource }} +{{- range .resources }} -func (svc resourceTranslationsManager) {{ .Resource }}(ctx context.Context, {{ if .Locale.Resource }}{{ range .Locale.Resource.References }}{{ .Field }} uint64, {{ end }}{{ end }}) (locale.ResourceTranslationSet, error) { +func (svc resourceTranslationsManager) {{ .expIdent }}(ctx context.Context, {{ range .references }}{{ . }} uint64, {{ end }}) (locale.ResourceTranslationSet, error) { var ( err error out locale.ResourceTranslationSet - res *{{ $GoType }} + res *types.{{ .expIdent }} k types.LocaleKey ) - res, err = svc.load{{$Resource}}(ctx, svc.store, {{ if .Locale.Resource }}{{ range .Locale.Resource.References }}{{ .Field }}, {{ end }}{{ end }}) + res, err = svc.load{{ .expIdent }}(ctx, svc.store, {{ range .references }}{{ . }}, {{ end }}) if err != nil { return nil, err } for _, tag := range svc.locale.Tags() { -{{- range .Locale.Keys}} - {{- if not .Custom }} - k = types.LocaleKey{{ $Resource }}{{coalesce (export .Name) (export .Path) }} - out = append(out, &locale.ResourceTranslation{ - Resource: res.ResourceTranslation(), - Lang: tag.String(), - Key: k.Path, - Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path), - }) - {{ end }} -{{- end}} - -{{- range .Locale.Keys}} - {{- if and .Custom .CustomHandler }} - auxResSet, err = svc.{{unexport $Resource}}{{export .CustomHandler}}Handler(ctx, tag, res, k.Path) + {{- range .keys}} + {{- if not .customHandler }} + k = types.{{ .struct }} + out = append(out, &locale.ResourceTranslation{ + Resource: res.ResourceTranslation(), + Lang: tag.String(), + Key: k.Path, + Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path), + }) + {{ end }} {{- end}} -{{- end}} } -{{- if .Locale.Extended }} - - tmp, err := svc.{{unexport $Resource}}Extended(ctx, res) - return append(out, tmp...), err - {{- else }} - return out, nil -{{- end }} + {{ if .extended }} + tmp, err := svc.{{ .ident }}Extended(ctx, res) + return append(out, tmp...), err + {{- else }} + return out, nil + {{- end }} } {{- end }} diff --git a/codegen/assets/templates/gocode/locale/$component_types.go.tpl b/codegen/assets/templates/gocode/locale/$component_types.go.tpl new file mode 100644 index 000000000..7bdbc0655 --- /dev/null +++ b/codegen/assets/templates/gocode/locale/$component_types.go.tpl @@ -0,0 +1,120 @@ +package {{ .package }} + +{{ template "gocode/header-gentext.tpl" }} + +import ( + "fmt" + "strconv" + "github.com/cortezaproject/corteza-server/pkg/locale" +) + +type ( + LocaleKey struct { + Name string + Resource string + Path string + CustomHandler string + } +) + +// Types and stuff +const ( +{{- range .resources }} + {{ .const }} = "{{ .type }}" +{{- end }} +) + +var ( + // @todo can we remove LocaleKey struct for string constant? +{{- range .resources }} +{{- range .keys }} + {{ .struct }} = LocaleKey{ Path: {{ printf "%q" .path }} } +{{- end }} +{{- end }} +) + +{{- range .resources }} + +// ResourceTranslation returns string representation of Locale resource for {{ .expIdent }} by calling {{ .expIdent }}ResourceTranslation fn +// +// Locale resource is in "{{ .type }}/..." format +// +// This function is auto-generated +func (r {{ .expIdent }}) ResourceTranslation() string { + return {{ .expIdent }}ResourceTranslation({{ range .references }}r.{{ .refField }},{{ end }}) +} + +// {{ .expIdent }}ResourceTranslation returns string representation of Locale resource for {{ .expIdent }} +// +// Locale resource is in the {{ .type }}/{{- if .references }}...{{ end }} format +// +// This function is auto-generated +func {{ .expIdent }}ResourceTranslation({{ range .references }}{{ .refField }} uint64,{{ end }}) string { + {{- if .references }} + cpts := []interface{{"{}"}}{ + {{ .expIdent }}ResourceTranslationType, + {{- range .references }} + strconv.FormatUint({{ .refField }}, 10), + {{- end }} + } + + return fmt.Sprintf({{ .expIdent }}ResourceTranslationTpl(), cpts...) + {{- end }} +} + +func {{ .expIdent }}ResourceTranslationTpl() string { + {{- if .references }} + return "%s + {{- range .references }}/%s{{- end }}" + + {{- else }} + return "%s" + {{- end }} +} + +func (r *{{ .expIdent }}) DecodeTranslations(tt locale.ResourceTranslationIndex) { + var aux *locale.ResourceTranslation + + {{- range .keys }} + {{ if .decodeFunc }} + {{ if not .extended }} + r.{{ .decodeFunc }}(tt) + {{- end}} + {{ else }} + if aux = tt.FindByKey({{ .struct }}.Path); aux != nil { + r.{{ .fieldPath }} = aux.Msg + } + {{- end}} + {{- end}} + + {{- if .extended }} + r.decodeTranslations(tt) + {{- end }} +} + +func (r *{{ .expIdent }}) EncodeTranslations() (out locale.ResourceTranslationSet) { + out = locale.ResourceTranslationSet{} + {{- range .keys }} + {{ if .encodeFunc }} + {{ if not .extended }} + out = append(out, r.{{ .encodeFunc }}()...) + {{- end}} + {{ else }} + if r.{{ .fieldPath }} != "" { + out = append(out, &locale.ResourceTranslation{ + Resource: r.ResourceTranslation(), + Key: {{ .struct }}.Path, + Msg: locale.SanitizeMessage(r.{{ .fieldPath }}), + }) + } + {{- end}} + {{- end}} + + {{- if .extended }} + out = append(out, r.encodeTranslations()...) + {{- end }} + + return out +} + +{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/rbac/access_control.go.tpl b/codegen/assets/templates/gocode/rbac/$component_access_control.go.tpl similarity index 61% rename from pkg/codegen-v3/assets/templates/gocode/rbac/access_control.go.tpl rename to codegen/assets/templates/gocode/rbac/$component_access_control.go.tpl index c05566008..907532aa1 100644 --- a/pkg/codegen-v3/assets/templates/gocode/rbac/access_control.go.tpl +++ b/codegen/assets/templates/gocode/rbac/$component_access_control.go.tpl @@ -1,7 +1,6 @@ -package {{ .Package }} +package {{ .package }} -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} +{{ template "gocode/header-gentext.tpl" }} import ( "fmt" @@ -10,7 +9,7 @@ import ( "context" "github.com/cortezaproject/corteza-server/pkg/rbac" "github.com/cortezaproject/corteza-server/pkg/actionlog" -{{- range .Imports }} +{{- range .imports }} {{ . }} {{- end }} ) @@ -26,7 +25,6 @@ type ( FindRulesByRoleID(roleID uint64) (rr rbac.RuleSet) CloneRulesByRoleID(ctx context.Context, fromRoleID uint64, toRoleID ...uint64) error } - } ) @@ -56,17 +54,13 @@ func (svc accessControl) Effective(ctx context.Context, rr ... rbac.Resource) (e func (svc accessControl) List() (out []map[string]string) { def := []map[string]string{ - {{- range .Def }} - {{- $Resource := .Resource }} - {{- $RbacResource := .RBAC.Resource }} - {{- range .RBAC.Operations }} + {{- range .operations }} { - "type": types.{{ coalesce $Resource }}ResourceType, - "any": types.{{ coalesce $Resource }}RbacResource({{ range $RbacResource.References }}0,{{ end }}), - "op": {{ printf "%q" .Operation }}, + "type": {{ .const }}, + "any": {{ .resFunc }}({{ range .references }}0,{{ end }}), + "op": {{ printf "%q" .op }}, }, {{- end }} - {{- end }} } func(svc interface{}) { @@ -143,42 +137,24 @@ func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...) } -{{- range .Def }} - {{ $GoType := printf "types.%s" (.Resource) }} - - {{ if .IsComponentResource }} - - {{- range .RBAC.Operations }} - // {{ export .CanFnName }} checks if current user can {{ lower .Description }} - // - // This function is auto-generated - func (svc accessControl) {{ export .CanFnName }}(ctx context.Context) bool { - return svc.can(ctx, {{ printf "%q" .Operation }}, &types.Component{}) - } - {{- end }} - - {{ else }} - {{- range .RBAC.Operations }} - // {{ export .CanFnName }} checks if current user can {{ lower .Description }} - // - // This function is auto-generated - func (svc accessControl) {{ export .CanFnName }}(ctx context.Context, r * {{ $GoType }}) bool { - return svc.can(ctx, {{ printf "%q" .Operation }}, r) - } - {{- end }} - -{{ end }} +{{- range .operations }} + // {{ .checkFuncName }} checks if current user can {{ lower .description }} + // + // This function is auto-generated + func (svc accessControl) {{ .checkFuncName }}(ctx context.Context{{ if not .component }}, r *{{ .goType }}{{ end }}) bool { + {{- if .component }}r := &{{ .goType }}{}{{ end }} + return svc.can(ctx, {{ printf "%q" .op }}, r) + } {{- end }} - // rbacResourceValidator validates known component's resource by routing it to the appropriate validator // // This function is auto-generated func rbacResourceValidator(r string, oo ...string) error { switch rbac.ResourceType(r) { - {{- range .Def }} - case types.{{ coalesce .Resource }}ResourceType: - return rbac{{ .Resource }}ResourceValidator(r, oo...) + {{- range .validation }} + case {{ .const }}: + return {{ .funcName }}(r, oo...) {{- end }} } @@ -190,11 +166,11 @@ func rbacResourceValidator(r string, oo ...string) error { // This function is auto-generated func rbacResourceOperations(r string) map[string]bool { switch rbac.ResourceType(r) { - {{- range .Def }} - case types.{{ coalesce .Resource }}ResourceType: + {{- range .validation }} + case {{ .const }}: return map[string]bool{ - {{- range .RBAC.Operations }} - {{ printf "%q" .Operation }}: true, + {{- range .operations }} + {{ printf "%q" . }}: true, {{- end }} } {{- end }} @@ -203,57 +179,53 @@ func rbacResourceOperations(r string) map[string]bool { return nil } -{{- range .Def }} +{{- range .validation }} -{{ $Resource := .Resource }} -{{ $GoType := printf "types.%s" (.Resource) }} - -// rbac{{ .Resource }}ResourceValidator checks validity of rbac resource and operations +// {{ .funcName }} checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated -func rbac{{ .Resource }}ResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for {{ .Component }}{{ if not .IsComponentResource }} {{ .Resource }}{{end }} resource", o) - } - } - - if !strings.HasPrefix(r, {{ $GoType }}ResourceType) { +func {{ .funcName }}(r string, oo ...string) error { + if !strings.HasPrefix(r, {{ .const }}) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for {{ .label }} resource", o) + } + } -{{ if .RBAC.Resource.References }} - const sep = "/" - var ( - pp = strings.Split(strings.Trim(r[len({{ $GoType }}ResourceType):], sep), sep) - prc = []string{ - {{- range .RBAC.Resource.References }} - {{ printf "%q" .Field }}, + {{ if .references }} + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len({{ .const }}):], sep), sep) + prc = []string{ + {{- range .references }} + {{ printf "%q" . }}, + {{- end }} + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for {{ .label }} resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } {{- end }} - } - ) - - if len(pp) != len(prc) { - return fmt.Errorf("invalid resource path structure") - } - - for i := 0; i < len(pp); i++ { - if pp[i] != "*" { - if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for {{ .Resource }}", i) - } - - if _, err := cast.ToUint64E(pp[i]); err != nil { - return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) - } - } - } -{{- end }} return nil } {{- end }} diff --git a/codegen/assets/templates/gocode/rbac/$component_types.go.tpl b/codegen/assets/templates/gocode/rbac/$component_types.go.tpl new file mode 100644 index 000000000..760f0c04b --- /dev/null +++ b/codegen/assets/templates/gocode/rbac/$component_types.go.tpl @@ -0,0 +1,78 @@ +package {{ .package }} + +{{ template "gocode/header-gentext.tpl" }} + +import ( + "fmt" + "strconv" +) + +type ( + // Component struct serves as a virtual resource type for the {{ .cmpIdent }} component + // + // This struct is auto-generated + Component struct {} +) + +var ( + {{/* + making sure that generated code does not break + when these packages are not used + */}} + _ = fmt.Printf + _ = strconv.FormatUint +) + +const ( +{{- range .types }} + {{ .const }} = {{ printf "%q" .type }} +{{- end }} +) + + +{{- range .types }} + +// RbacResource returns string representation of RBAC resource for {{ .goType }} by calling {{ .resFunc }} fn +// +// RBAC resource is in the {{ .type }}/... format +// +// This function is auto-generated +func (r {{ .goType }}) RbacResource() string { + return {{ .resFunc }}({{ if not .component }}{{ range .references }}r.{{ .refField }},{{ end }}{{ end }}) +} + +// {{ .resFunc }} returns string representation of RBAC resource for {{ .goType }} +// +// RBAC resource is in the {{ .type }}/{{- if .references }}...{{ end }} format +// +// This function is auto-generated +func {{ .resFunc }}({{ if not .component }}{{ range .references }}{{ .param }} uint64,{{ end }}{{ end }}) string { + {{- if .references }} + cpts := []interface{{"{}"}}{{"{"}}{{ .goType }}ResourceType{{"}"}} + {{- range .references }} + if {{ .param }} != 0 { + cpts = append(cpts, strconv.FormatUint({{ .param }}, 10)) + } else { + cpts = append(cpts, "*") + } + + {{ end }} + return fmt.Sprintf({{ .tplFunc }}(), cpts...) + {{- else }} + return {{ .goType }}ResourceType + "/" + {{- end }} + +} + +func {{ .tplFunc }}() string { + {{- if .references }} + return "%s + {{- range .references }}/%s{{- end }}" + + {{- else }} + return "%s" + {{- end }} +} + +{{- end }} + diff --git a/codegen/envoy-rbac.cue b/codegen/envoy-rbac.cue new file mode 100644 index 000000000..e90892400 --- /dev/null +++ b/codegen/envoy-rbac.cue @@ -0,0 +1,134 @@ +package codegen + +import ( + "github.com/cortezaproject/corteza-server/app" + "github.com/cortezaproject/corteza-server/codegen/schema" + // "strings" +) + +envoyRBAC: + [...schema.#codegen] & + [ + for cmp in app.corteza.components { + template: "gocode/envoy/rbac_references_$component.go.tpl" + output: "pkg/envoy/resource/rbac_references_\(cmp.ident).gen.go" + payload: { + package: "resource" + imports: [ + "\"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"", + ] + + resources: [ + for res in cmp.resources { + rbacRefFunc: "\(cmp.expIdent)\(res.expIdent)RbacReferences" + references: [ + for p in res.parents {p}, + {param: res.ident, refField: "ID", expIdent: res.expIdent}, + ] + }, + ] + } + }, + ]+ + [ + { + template: "gocode/envoy/rbac_rules_parse.go.tpl" + output: "pkg/envoy/resource/rbac_rules_parse.gen.go" + payload: { + package: "resource" + imports: [ + for cmp in app.corteza.components { + "\(cmp.ident)Types \"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"" + }, + ] + + resources: [ + for cmp in app.corteza.components for res in cmp.resources { + importAlias: "\(cmp.ident)Types" + expIdent: res.expIdent + + typeConst: "\(importAlias).\(expIdent)ResourceType" + rbacRefFunc: "\(cmp.expIdent)\(res.expIdent)RbacReferences" + references: [ + for p in res.parents {p}, + {param: res.ident, refField: "ID", expIdent: res.expIdent}, + ] + }, + + for cmp in app.corteza.components { + importAlias: "\(cmp.ident)Types" + expIdent: cmp.expIdent + + typeConst: "\(importAlias).ComponentResourceType" + references: [] + }, + ] + } + }, + ]+ + [ + { + template: "gocode/envoy/resource_translation.go.tpl" + output: "pkg/envoy/resource/resource_translation.gen.go" + payload: { + package: "resource" + resources: [ + for cmp in app.corteza.components for res in cmp.resources if res.locale != _|_ { + expIdent: "\(cmp.expIdent)\(res.expIdent)" + extended: res.locale.extended + }, + ] + } + }, + ]+ + [ + { + template: "gocode/envoy/resource_translation_parse.go.tpl" + output: "pkg/envoy/resource/resource_translation_parse.gen.go" + payload: { + package: "resource" + imports: [ + for cmp in app.corteza.components for res in cmp.resources if res.locale != _|_ { + "\(cmp.ident)Types \"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"" + }, + ] + + resources: [ + for cmp in app.corteza.components for res in cmp.resources if res.locale != _|_ { + importAlias: "\(cmp.ident)Types" + typeConst: "\(importAlias).\(res.expIdent)ResourceTranslationType" + resTrRefFunc: "\(cmp.expIdent)\(res.expIdent)ResourceTranslationReferences" + references: [ + for p in res.parents {p}, + {param: res.ident, refField: "ID", expIdent: res.expIdent}, + ] + }, + ] + } + }, + ]+ + [ + // wrapped with additional for loop to trim out templates with empty types list + for tpl in [ + for cmp in app.corteza.components { + template: "gocode/envoy/resource_translation_references_$component.go.tpl" + output: "pkg/envoy/resource/resource_translation_references_\(cmp.ident).gen.go" + payload: { + package: "resource" + imports: [ + "\"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"", + ] + + resources: [ + for res in cmp.resources if res.locale != _|_ { + resTrRefFunc: "\(cmp.expIdent)\(res.expIdent)ResourceTranslationReferences" + expIdent: res.expIdent + references: [ + for p in res.parents {p}, + ] + }, + ] + } + }, + ] if len(tpl.payload.resources) > 0 {tpl}]+ + [] diff --git a/codegen/locale-service.cue b/codegen/locale-service.cue new file mode 100644 index 000000000..8a25a331e --- /dev/null +++ b/codegen/locale-service.cue @@ -0,0 +1,43 @@ +package codegen + +import ( + "github.com/cortezaproject/corteza-server/app" + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +localeService: + [...schema.#codegen] & + [ + // wrapped with additional for loop to trim out templates with empty types list + for tpl in [ + for cmp in app.corteza.components { + template: "gocode/locale/$component_service.go.tpl" + output: "\(cmp.ident)/service/locale.gen.go" + payload: { + package: "service" + imports: [ + "\"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"", + ] + + resources: [ + for res in cmp.resources if (res.locale != _|_) if (!res.locale.skipSvc) { + expIdent: res.expIdent + ident: res.ident + + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] + + extended: res.locale.extended + + keys: [ for key in res.locale.keys if key.handlerFunc == _|_ { + struct: key.struct + + "extended": extended + customHandler: key.customHandler + if key.serviceFunc != _|_ {serviceFunc: key.serviceFunc} + }] + }, + ] + } + }, + // skip empty type lists + ] if len(tpl.payload.resources) > 0 {tpl}] diff --git a/codegen/locale-types.cue b/codegen/locale-types.cue new file mode 100644 index 000000000..a9e6b8e69 --- /dev/null +++ b/codegen/locale-types.cue @@ -0,0 +1,55 @@ +package codegen + +import ( + "github.com/cortezaproject/corteza-server/app" + "github.com/cortezaproject/corteza-server/codegen/schema" + "strings" +) + +localeTypes: + [...schema.#codegen] & + [ + // wrapped with additional for loop to trim out templates with empty types list + for tpl in [ + for cmp in app.corteza.components { + template: "gocode/locale/$component_types.go.tpl" + output: "\(cmp.ident)/types/locale.gen.go" + payload: { + package: "types" + + resources: [ + for res in cmp.resources if res.locale != _|_ { + expIdent: res.expIdent + const: res.locale.resource.const + type: res.locale.resource.type + + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] + + extended: res.locale.extended + + keys: [ for key in res.locale.keys if key.handlerFunc == _|_ { + struct: key.struct + field: strings.ToTitle(key.name) + + path: strings.Join([ for p in key.expandedPath { + if p.var {"{{\(p.part)}}"} + if !p.var {p.part} + }], ".") + + if !key.customHandler { + fieldPath: strings.Join([ for p in key.expandedPath { + strings.ToTitle(p.part) + }], ".") + } + + "extended": extended + if key.decodeFunc != _|_ {decodeFunc: key.decodeFunc} + if key.encodeFunc != _|_ {encodeFunc: key.encodeFunc} + + }] + }, + ] + } + }, + // skip empty type lists + ] if len(tpl.payload.resources) > 0 {tpl}] diff --git a/codegen/platform.cue b/codegen/platform.cue new file mode 100644 index 000000000..a08ad5b7e --- /dev/null +++ b/codegen/platform.cue @@ -0,0 +1,17 @@ +package codegen + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +// List of all codegen jobs for the entire platform +// +// How to run it? +// @todo when this gets into +// cue eval codegen/*.cue --out json -e platform | go run codegen/tool/*.go -v +platform: [...schema.#codegen] & + rbacAccessControl+ + rbacTypes+ + localeTypes+ + envoyRBAC+ + [] // placeholder diff --git a/codegen/rbac-access_control.cue b/codegen/rbac-access_control.cue new file mode 100644 index 000000000..5dd4f810e --- /dev/null +++ b/codegen/rbac-access_control.cue @@ -0,0 +1,62 @@ +package codegen + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" + "github.com/cortezaproject/corteza-server/app" +) + +rbacAccessControl: + [...schema.#codegen] & + [ + for cmp in app.corteza.components { + template: "gocode/rbac/$component_access_control.go.tpl" + output: "\(cmp.ident)/service/access_control.gen.go" + payload: { + package: "service" + imports: [ + "\"github.com/cortezaproject/corteza-server/\(cmp.ident)/types\"", + ] + + // All possible RBAC operations on component and resources + // flattened + operations: [ + for res in cmp.resources for op in res.rbac.operations { + "op": op.handle + const: "types.\(res.expIdent)ResourceType" + resFunc: "types.\(res.expIdent)RbacResource" + goType: "types.\(res.expIdent)" + description: op.description + checkFuncName: op.checkFuncName + + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] + }, + for op in cmp.rbac.operations { + "op": op.handle + const: "types.ComponentResourceType" + resFunc: "types.ComponentRbacResource" + goType: "types.Component" + description: op.description + checkFuncName: op.checkFuncName + component: true + }, + ] + + // Operation/resource validators, grouped by resource + validation: [ + for res in cmp.resources { + label: res.ident + const: "types.\(res.expIdent)ResourceType" + funcName: "rbac\(res.expIdent)ResourceValidator" + references: [ for p in res.parents {p.refField}, "ID"] + operations: [ for op in res.rbac.operations {op.handle}] + }, + { + label: "\(cmp.ident) component" + const: "types.ComponentResourceType" + funcName: "rbacComponentResourceValidator" + operations: [ for op in cmp.rbac.operations {op.handle}] + }, + ] + } + }, + ] diff --git a/codegen/rbac-types.cue b/codegen/rbac-types.cue new file mode 100644 index 000000000..a374e65df --- /dev/null +++ b/codegen/rbac-types.cue @@ -0,0 +1,42 @@ +package codegen + +import ( + "github.com/cortezaproject/corteza-server/app" + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +rbacTypes: + [...schema.#codegen] & + [ + for cmp in app.corteza.components { + template: "gocode/rbac/$component_types.go.tpl" + output: "\(cmp.ident)/types/rbac.gen.go" + payload: { + package: "types" + + cmpIdent: cmp.ident + // Operation/resource validators, grouped by resource + types: [ + for res in cmp.resources { + const: "\(res.expIdent)ResourceType" + type: res.fqrn + resFunc: "\(res.expIdent)RbacResource" + tplFunc: "\(res.expIdent)RbacResourceTpl" + attFunc: "\(res.expIdent)RbacAttributes" + goType: res.expIdent + + references: [ for p in res.parents {p}, {param: "id", refField: "ID"}] + }, + { + const: "ComponentResourceType" + type: cmp.fqrn + resFunc: "ComponentRbacResource" + tplFunc: "ComponentRbacResourceTpl" + attFunc: "ComponentRbacAttributes" + goType: "Component" + component: true + }, + ] + } + }, + ] diff --git a/codegen/schema/codegen.cue b/codegen/schema/codegen.cue new file mode 100644 index 000000000..36a9467fd --- /dev/null +++ b/codegen/schema/codegen.cue @@ -0,0 +1,13 @@ +package schema + +#codegen: { + template: string + output: string + + syntax: "go" + if output =~ "\\.adoc" { + syntax: "adoc" + } + + payload: _ +} diff --git a/codegen/schema/component.cue b/codegen/schema/component.cue new file mode 100644 index 000000000..6e85fe61f --- /dev/null +++ b/codegen/schema/component.cue @@ -0,0 +1,28 @@ +package schema + +import ( + "strings" +) + +#component: #_base & { + // copy field values from #_base + handle: handle, ident: ident, expIdent: expIdent + + label: strings.ToTitle(ident) + platform: #baseHandle + + resources: { + [key=_]: {"handle": key, "component": handle, "platform": platform} & #resource + } + + fqrn: platform + "::" + handle + + // All known RBAC operations for this component + rbac: #rbacComponent & { + operations: { + grant: { + description: "Manage \(handle) permissions" + } + } + } +} diff --git a/codegen/schema/locale.cue b/codegen/schema/locale.cue new file mode 100644 index 000000000..69261b822 --- /dev/null +++ b/codegen/schema/locale.cue @@ -0,0 +1,54 @@ +package schema + +import ( + "strings" + "list" +) + +#locale: { + resourceExpIdent: #expIdent + + // @todo we need a better name here! + skipSvc: bool | *false + + extended: bool | *false + + resource: { + type: string + const: string | *("\(resourceExpIdent)ResourceTranslationType") + } + + keys: { + [key=_]: #localeKey & { + name: key + _resourceExpIdent: resourceExpIdent + } + } +} + +#localeKey: { + name: #handle + _resourceExpIdent: #expIdent + + path: [...(#ident | {part: #ident, var: bool | *false})] | *([name]) + + expandedPath: [ for p in path { + if (p & {"p": #ident}) != _|_ {p, var: p.var} + if (p & string) != _|_ {"part": p, var: false} + }] + + _suffix: strings.Join([ for p in expandedPath {strings.ToTitle(p.part)}], "") + + struct: string | *("LocaleKey" + _resourceExpIdent + _suffix) + + // As soon as we use vars in the path, + // custom handler must be present + _hasVars: list.Contains([ for p in path {p.var | false}], true) + customHandler: bool | *_hasVars + + if customHandler { + decodeFunc: string | *("decodeTranslations" + _suffix) + encodeFunc: string | *("encodeTranslations" + _suffix) + serviceFunc: string | *("handle" + _resourceExpIdent + _suffix) + } +} diff --git a/codegen/schema/platform.cue b/codegen/schema/platform.cue new file mode 100644 index 000000000..f0901df4f --- /dev/null +++ b/codegen/schema/platform.cue @@ -0,0 +1,17 @@ +package schema + +#platform: { + ident: #baseHandle | *"corteza" + + components: [...{platform: ident} & #component] + + // env-var definitions + // options: {} + + // + + // automation: { + // types: .... + // function .... + // } +} diff --git a/codegen/schema/rbac.cue b/codegen/schema/rbac.cue new file mode 100644 index 000000000..712d007f8 --- /dev/null +++ b/codegen/schema/rbac.cue @@ -0,0 +1,61 @@ +package schema + +import ( + "strings" +) + +#rbacComponent: { + resource: { + type: string + } + + operations: { + [key=_]: #rbacOperation & { + handle: key + } + } +} + +#rbacResource: { + resourceExpIdent: #expIdent + + operations: { + [key=_]: #rbacOperation & { + handle: key + _resourceExpIdent: resourceExpIdent + } + } +} + +#rbacOperation: { + handle: #handle + description: string | *handle + _resourceExpIdent?: string + + // Some string manipulation that will result in + // more pronouncable access-control check function name + + // When check function name is not explicitly defined we try + // to use resource and operation name and generate easy-to-read name + // + // + => Can + // + => CanOn + + _operation: strings.Replace(strings.Replace(handle, "-", " ", -1), "_", " ", -1) + _opSplit: strings.Split(_operation, ".") + + _opFlip: [_opSplit[len(_opSplit)-1]] + _opSplit[0:len(_opSplit)-1] + _opFinal: strings.Replace(strings.ToTitle(strings.Join(_opFlip, " ")), " ", "", -1) + + if _resourceExpIdent == _|_ { + checkFuncName: #expIdent | *"Can\(_opFinal)" + } + + if len(_opSplit) > 1 && _resourceExpIdent != _|_ { + checkFuncName: #expIdent | *"Can\(_opFinal)On\(_resourceExpIdent)" + } + + if len(_opSplit) <= 1 && _resourceExpIdent != _|_ { + checkFuncName: #expIdent | *"Can\(_opFinal)\(_resourceExpIdent)" + } +} diff --git a/codegen/schema/resource.cue b/codegen/schema/resource.cue new file mode 100644 index 000000000..fb4dccd6f --- /dev/null +++ b/codegen/schema/resource.cue @@ -0,0 +1,98 @@ +package schema + +#resource: #_base & { + // copy field values from #_base + handle: handle, ident: ident, expIdent: expIdent + + component: #baseHandle | *"component" + platform: #baseHandle | *"corteza" + + // Fully qualified resource name + fqrn: string | *(platform + "::" + component + ":" + handle) + + // fields: #Fields + // operations: #Operations + + // All parent resources + parents: [... #_base & { + // copy field values from #_base + handle: handle, ident: ident, expIdent: expIdent + + refField: #expIdent | *(expIdent + "ID") + param: #ident | *(ident + "ID") + }] + + // All known RBAC operations for this resource + rbac: #rbacResource & { + resourceExpIdent: expIdent + } + + locale?: #locale & { + resourceExpIdent: expIdent + resource: { + // @todo can we merge this with RBAC type (FQRN?) + type: component + ":" + handle + } + } + + // List of known keys for resource translation + // locale?: { + // [Name=_]: { + // name: Name & #Handle + // path: string + // custom: bool | *false + // } + // } +} + +//#fields: { +// // Each field can be +// [key=_]: #fields | *({name: key} & #field) +//} +// +//#field: { +// name: #expIdent +// unique: bool | *false +// +// // Golang type (built-in or other) +// type: string | *"string" +// +// // System fields, +// system: bool | *false +// +// if name =~ "At$" { +// type: string | *"*time.Time" +// } +//} + +//#Operations: { +// [Operation=_]: {operation: Operation} & #Operation +//} + +//#Operation: { +// name: #ExpIdent +// description: string +// can: string | false | *"\(name)" +//} + +//idField: { +// // Expecting ID field to allways have name ID +// name: "ID" +// unique: true +// +// // Service fields, +// // @todo We might want to have a better name for this +// // service: true +// +// // @todo someday we'll replace this with the "ID" type +// type: "uint64" +//} +// +//handleField: { +// // Expecting ID field to allways have name ID +// name: "handle" +// unique: true +// +// // @todo someday we'll replace this with the "ID" type +// type: "string" & #handle +//} diff --git a/codegen/schema/shared.cue b/codegen/schema/shared.cue new file mode 100644 index 000000000..72b8a7a79 --- /dev/null +++ b/codegen/schema/shared.cue @@ -0,0 +1,32 @@ +package schema + +import ( + "strings" +) + +// Identifier +#ident: =~"^[a-z][a-zA-Z0-9_]*$" + +// Exported identifier +#expIdent: =~"^[A-Z][a-zA-Z0-9_]*$" + +// More liberal then identifier, allows underscores and dots +#handle: =~"^[A-Za-z][a-zA-Z0-9_\\-\\.]*[a-zA-Z0-9]+$" + +// More liberal then identifier, allows underscores and dots +#baseHandle: =~"^[a-z][a-z0-9-]*[a-z0-9]+$" + +#_base: { + // lowercase dash-separated words + // used to build ident and exported identifiers + handle: #baseHandle | *"base" + _words: strings.Replace(strings.Replace(strings.Replace(handle, "-", " ", -1), "_", " ", -1), ".", " ", -1) + + // lowercased (unexported, golang) identifier + ident: #ident | *strings.ToCamel(strings.Replace(strings.ToTitle(_words), " ", "", -1)) + + // upercased (exported, golang) identifier + expIdent: #expIdent | *strings.Replace(strings.ToTitle(_words), " ", "", -1) + + ... +} diff --git a/codegen/tool/main.go b/codegen/tool/main.go new file mode 100644 index 000000000..8141f7159 --- /dev/null +++ b/codegen/tool/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "text/template" + + "github.com/cortezaproject/corteza-server/pkg/cli" +) + +type ( + task struct { + Template string `json:"template"` + Output string `json:"output"` + Syntax string `json:"syntax"` + Payload interface{} `json:"payload"` + } +) + +var ( + verbose bool + showHelp bool + tplRootPath string +) + +func init() { + flag.BoolVar(&showHelp, "h", false, "show help") + flag.BoolVar(&verbose, "v", false, "be verbose") + flag.StringVar(&tplRootPath, "p", "codegen/assets/templates", "location of the template files") + flag.Parse() +} + +// Takes JSON input with codegen tasks and definitions and generates files +func main() { + if showHelp { + flag.PrintDefaults() + os.Exit(0) + } + + var ( + input = json.NewDecoder(os.Stdin) + tasks = make([]*task, 0) + tpl *template.Template + err error + ) + + print("Waiting for stdin ...\n") + if err = input.Decode(&tasks); err != nil { + cli.HandleError(fmt.Errorf("failed to decode input from standard input: %v", err)) + } + + if tpl, err = LoadTemplates(BaseTemplate(), tplRootPath); err != nil { + cli.HandleError(fmt.Errorf("failed to load templates: %v", err)) + } + + for _, j := range tasks { + switch j.Syntax { + case "go": + print(fmt.Sprintf("generating %s (from %s) ...", j.Output, j.Template)) + if err = GoTemplate(j.Output, tpl.Lookup(j.Template), j.Payload); err != nil { + cli.HandleError(fmt.Errorf("failed to write template: %v", err)) + } + print("done\n") + } + } +} + +func print(msg string) { + if verbose { + _, _ = fmt.Fprint(os.Stderr, msg) + } +} diff --git a/pkg/codegen-v3/internal/tpl/templating.go b/codegen/tool/templating.go similarity index 60% rename from pkg/codegen-v3/internal/tpl/templating.go rename to codegen/tool/templating.go index 119abe40b..62aa0277e 100644 --- a/pkg/codegen-v3/internal/tpl/templating.go +++ b/codegen/tool/templating.go @@ -1,4 +1,4 @@ -package tpl +package main import ( "bytes" @@ -8,63 +8,15 @@ import ( "io/ioutil" "os" "path/filepath" - "regexp" "strings" "text/template" "github.com/Masterminds/sprig" ) -type ( - Wrap struct { - Package string - - // will be set when grouping definitions by component - Component string - - Imports []string - Def interface{} - } -) - -var nonIdentChars = regexp.MustCompile(`[\s\\/\-.]+`) - -func Export(pp ...string) (out string) { - for _, p := range pp { - if len(p) > 1 { - p = strings.ToUpper(p[:1]) + p[1:] - } - - if ss := nonIdentChars.Split(p, -1); len(ss) > 1 { - p = Export(ss...) - } - - out = out + p - } - - return out -} - -func Unexport(pp ...string) (out string) { - out = Export(pp...) - if len(out) == 0 { - return - } - - if out == "ID" { - return "id" - } - - return strings.ToLower(out[:1]) + out[1:] -} - func BaseTemplate() *template.Template { return template.New(""). - Funcs(sprig.TxtFuncMap()). - Funcs(map[string]interface{}{ - "export": Export, - "unexport": Unexport, - }) + Funcs(sprig.TxtFuncMap()) } func LoadTemplates(rTpl *template.Template, rootDir string) (*template.Template, error) { @@ -72,6 +24,10 @@ func LoadTemplates(rTpl *template.Template, rootDir string) (*template.Template, pfx := len(cleanRoot) + 1 return rTpl, filepath.Walk(cleanRoot, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() || !strings.HasSuffix(path, ".tpl") || err != nil { return err } @@ -88,7 +44,7 @@ func LoadTemplates(rTpl *template.Template, rootDir string) (*template.Template, }) } -func GoTemplate(dst string, tpl *template.Template, payload Wrap) (err error) { +func GoTemplate(dst string, tpl *template.Template, payload interface{}) (err error) { var output io.WriteCloser buf := bytes.Buffer{} diff --git a/compose/chart.cue b/compose/chart.cue new file mode 100644 index 000000000..2169c6aaf --- /dev/null +++ b/compose/chart.cue @@ -0,0 +1,19 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +chart: schema.#resource & { + parents: [ + {handle: "namespace"}, + ] + + rbac: { + operations: { + "read": {} + "update": {} + "delete": {} + } + } +} diff --git a/compose/component.cue b/compose/component.cue new file mode 100644 index 000000000..beaad796a --- /dev/null +++ b/compose/component.cue @@ -0,0 +1,26 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +component: schema.#component & { + handle: "compose" + + resources: { + "chart": chart + "module": module + "module-field": moduleField + "namespace": namespace + "page": page + "record": record + } + + rbac: operations: { + "settings.read": description: "Read settings" + "settings.manage": description: "Manage settings" + "namespace.create": description: "Create namespace" + "namespaces.search": description: "List, search or filter namespaces" + "resource-translations.manage": description: "List, search, create, or update resource translations" + } +} diff --git a/compose/module-field.cue b/compose/module-field.cue new file mode 100644 index 000000000..46ef3b388 --- /dev/null +++ b/compose/module-field.cue @@ -0,0 +1,51 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +moduleField: schema.#resource & { + parents: [ + {handle: "namespace"}, + {handle: "module"}, + ] + + rbac: { + operations: { + "record.value.read": description: "Read field value on records" + "record.value.update": description: "Update field value on records" + } + } + + locale: { + skipSvc: true + + keys: { + label: {} + descriptionView: { + path: ["meta", "description", "view"] + customHandler: true + } + descriptionEdit: { + path: ["meta", "description", "edit"] + customHandler: true + } + hintView: { + path: ["meta", "hint", "view"] + customHandler: true + } + hintEdit: { + path: ["meta", "hint", "edit"] + customHandler: true + } + validatorError: { + path: ["expression", "validator", {part: "validatorID", var: true}, "error"] + customHandler: true + } + optionsOptionTexts: { + path: ["meta", "options", {part: "value", var: true}, "text"] + customHandler: true + } + } + } +} diff --git a/compose/module.cue b/compose/module.cue new file mode 100644 index 000000000..f628841d2 --- /dev/null +++ b/compose/module.cue @@ -0,0 +1,36 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +module: schema.#resource & { + handle: "module" + parents: [ + {handle: "namespace"}, + ] + + rbac: { + operations: { + "read": {} + "update": {} + "delete": {} + "record.create": description: "Create record" + "records.search": description: "List, search or filter records" + } + } + + locale: { + keys: { + "name": {} + } + } + + //locale: + // resource: + // references: [ namespace, ID ] + // + // extended: true + // keys: + // - name +} diff --git a/compose/namespace.cue b/compose/namespace.cue new file mode 100644 index 000000000..3a83c205a --- /dev/null +++ b/compose/namespace.cue @@ -0,0 +1,36 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +namespace: schema.#resource & { + rbac: { + operations: { + "read": {} + "update": {} + "delete": {} + "manage": description: "Access to namespace admin panel" + "module.create": description: "Create module on namespace" + "modules.search": description: "List, search or filter module on namespace" + "chart.create": description: "Create chart on namespace" + "charts.search": description: "List, search or filter chart on namespace" + "page.create": description: "Create page on namespace" + "pages.search": description: "List, search or filter pages on namespace" + } + } + + locale: { + resource: references: [ "ID"] + + keys: { + name: {} + metaSubtitle: { + path: ["meta", "subtitle"] + } + metaDescription: { + path: ["meta", "description"] + } + } + } +} diff --git a/compose/page.cue b/compose/page.cue new file mode 100644 index 000000000..21696d6ec --- /dev/null +++ b/compose/page.cue @@ -0,0 +1,40 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +page: schema.#resource & { + parents: [ + {handle: "namespace"}, + ] + + rbac: { + operations: { + "read": {} + "update": {} + "delete": {} + } + } + + locale: { + extended: true + + keys: { + title: {} + description: {} + blockTitle: { + path: ["pageBlock", {part: "blockID", var: true}, "title"] + customHandler: true + } + blockDescription: { + path: ["pageBlock", {part: "blockID", var: true}, "description"] + customHandler: true + } + blockAutomationButtonLabel: { + path: ["pageBlock", {part: "blockID", var: true}, "button", {part: "buttonID", var: true}, "label"] + customHandler: true + } + } + } +} diff --git a/compose/record.cue b/compose/record.cue new file mode 100644 index 000000000..0d34cc3a5 --- /dev/null +++ b/compose/record.cue @@ -0,0 +1,20 @@ +package compose + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +record: schema.#resource & { + parents: [ + {handle: "namespace"}, + {handle: "module"}, + ] + + rbac: { + operations: { + "read": {} + "update": {} + "delete": {} + } + } +} diff --git a/compose/rest/module.go b/compose/rest/module.go index d1d84d292..0499762c1 100644 --- a/compose/rest/module.go +++ b/compose/rest/module.go @@ -51,8 +51,8 @@ type ( CanCreateRecordOnModule(context.Context, *types.Module) bool CanReadRecord(context.Context, *types.Record) bool - CanReadRecordValue(context.Context, *types.ModuleField) bool - CanUpdateRecordValue(context.Context, *types.ModuleField) bool + CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool + CanUpdateRecordValueOnModuleField(context.Context, *types.ModuleField) bool } ) @@ -196,8 +196,8 @@ func (ctrl Module) makeFieldsPayload(ctx context.Context, m *types.Module) (out out[i] = &moduleFieldPayload{ ModuleField: f, - CanReadRecordValue: ctrl.ac.CanReadRecordValue(ctx, f), - CanUpdateRecordValue: ctrl.ac.CanUpdateRecordValue(ctx, f), + CanReadRecordValue: ctrl.ac.CanReadRecordValueOnModuleField(ctx, f), + CanUpdateRecordValue: ctrl.ac.CanUpdateRecordValueOnModuleField(ctx, f), } } diff --git a/compose/service/access_control.gen.go b/compose/service/access_control.gen.go index dc7b382e0..523a52e29 100644 --- a/compose/service/access_control.gen.go +++ b/compose/service/access_control.gen.go @@ -6,15 +6,6 @@ package service // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.chart.yaml -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml -// - compose.record.yaml -// - compose.yaml - import ( "context" "fmt" @@ -78,16 +69,6 @@ func (svc accessControl) List() (out []map[string]string) { "any": types.ChartRbacResource(0, 0), "op": "delete", }, - { - "type": types.ModuleFieldResourceType, - "any": types.ModuleFieldRbacResource(0, 0, 0), - "op": "record.value.read", - }, - { - "type": types.ModuleFieldResourceType, - "any": types.ModuleFieldRbacResource(0, 0, 0), - "op": "record.value.update", - }, { "type": types.ModuleResourceType, "any": types.ModuleRbacResource(0, 0), @@ -113,6 +94,16 @@ func (svc accessControl) List() (out []map[string]string) { "any": types.ModuleRbacResource(0, 0), "op": "records.search", }, + { + "type": types.ModuleFieldResourceType, + "any": types.ModuleFieldRbacResource(0, 0, 0), + "op": "record.value.read", + }, + { + "type": types.ModuleFieldResourceType, + "any": types.ModuleFieldRbacResource(0, 0, 0), + "op": "record.value.update", + }, { "type": types.NamespaceResourceType, "any": types.NamespaceRbacResource(0), @@ -296,56 +287,42 @@ func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...) } -// CanReadChart checks if current user can read chart +// CanReadChart checks if current user can read // // This function is auto-generated func (svc accessControl) CanReadChart(ctx context.Context, r *types.Chart) bool { return svc.can(ctx, "read", r) } -// CanUpdateChart checks if current user can update chart +// CanUpdateChart checks if current user can update // // This function is auto-generated func (svc accessControl) CanUpdateChart(ctx context.Context, r *types.Chart) bool { return svc.can(ctx, "update", r) } -// CanDeleteChart checks if current user can delete chart +// CanDeleteChart checks if current user can delete // // This function is auto-generated func (svc accessControl) CanDeleteChart(ctx context.Context, r *types.Chart) bool { return svc.can(ctx, "delete", r) } -// CanReadRecordValue checks if current user can read field value on records -// -// This function is auto-generated -func (svc accessControl) CanReadRecordValue(ctx context.Context, r *types.ModuleField) bool { - return svc.can(ctx, "record.value.read", r) -} - -// CanUpdateRecordValue checks if current user can update field value on records -// -// This function is auto-generated -func (svc accessControl) CanUpdateRecordValue(ctx context.Context, r *types.ModuleField) bool { - return svc.can(ctx, "record.value.update", r) -} - -// CanReadModule checks if current user can read module +// CanReadModule checks if current user can read // // This function is auto-generated func (svc accessControl) CanReadModule(ctx context.Context, r *types.Module) bool { return svc.can(ctx, "read", r) } -// CanUpdateModule checks if current user can update module +// CanUpdateModule checks if current user can update // // This function is auto-generated func (svc accessControl) CanUpdateModule(ctx context.Context, r *types.Module) bool { return svc.can(ctx, "update", r) } -// CanDeleteModule checks if current user can delete module +// CanDeleteModule checks if current user can delete // // This function is auto-generated func (svc accessControl) CanDeleteModule(ctx context.Context, r *types.Module) bool { @@ -366,21 +343,35 @@ func (svc accessControl) CanSearchRecordsOnModule(ctx context.Context, r *types. return svc.can(ctx, "records.search", r) } -// CanReadNamespace checks if current user can read namespace +// CanReadRecordValueOnModuleField checks if current user can read field value on records +// +// This function is auto-generated +func (svc accessControl) CanReadRecordValueOnModuleField(ctx context.Context, r *types.ModuleField) bool { + return svc.can(ctx, "record.value.read", r) +} + +// CanUpdateRecordValueOnModuleField checks if current user can update field value on records +// +// This function is auto-generated +func (svc accessControl) CanUpdateRecordValueOnModuleField(ctx context.Context, r *types.ModuleField) bool { + return svc.can(ctx, "record.value.update", r) +} + +// CanReadNamespace checks if current user can read // // This function is auto-generated func (svc accessControl) CanReadNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "read", r) } -// CanUpdateNamespace checks if current user can update namespace +// CanUpdateNamespace checks if current user can update // // This function is auto-generated func (svc accessControl) CanUpdateNamespace(ctx context.Context, r *types.Namespace) bool { return svc.can(ctx, "update", r) } -// CanDeleteNamespace checks if current user can delete namespace +// CanDeleteNamespace checks if current user can delete // // This function is auto-generated func (svc accessControl) CanDeleteNamespace(ctx context.Context, r *types.Namespace) bool { @@ -436,42 +427,42 @@ func (svc accessControl) CanSearchPagesOnNamespace(ctx context.Context, r *types return svc.can(ctx, "pages.search", r) } -// CanReadPage checks if current user can read page +// CanReadPage checks if current user can read // // This function is auto-generated func (svc accessControl) CanReadPage(ctx context.Context, r *types.Page) bool { return svc.can(ctx, "read", r) } -// CanUpdatePage checks if current user can update page +// CanUpdatePage checks if current user can update // // This function is auto-generated func (svc accessControl) CanUpdatePage(ctx context.Context, r *types.Page) bool { return svc.can(ctx, "update", r) } -// CanDeletePage checks if current user can delete page +// CanDeletePage checks if current user can delete // // This function is auto-generated func (svc accessControl) CanDeletePage(ctx context.Context, r *types.Page) bool { return svc.can(ctx, "delete", r) } -// CanReadRecord checks if current user can read record +// CanReadRecord checks if current user can read // // This function is auto-generated func (svc accessControl) CanReadRecord(ctx context.Context, r *types.Record) bool { return svc.can(ctx, "read", r) } -// CanUpdateRecord checks if current user can update record +// CanUpdateRecord checks if current user can update // // This function is auto-generated func (svc accessControl) CanUpdateRecord(ctx context.Context, r *types.Record) bool { return svc.can(ctx, "update", r) } -// CanDeleteRecord checks if current user can delete record +// CanDeleteRecord checks if current user can delete // // This function is auto-generated func (svc accessControl) CanDeleteRecord(ctx context.Context, r *types.Record) bool { @@ -482,42 +473,48 @@ func (svc accessControl) CanDeleteRecord(ctx context.Context, r *types.Record) b // // This function is auto-generated func (svc accessControl) CanGrant(ctx context.Context) bool { - return svc.can(ctx, "grant", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "grant", r) } // CanReadSettings checks if current user can read settings // // This function is auto-generated func (svc accessControl) CanReadSettings(ctx context.Context) bool { - return svc.can(ctx, "settings.read", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "settings.read", r) } // CanManageSettings checks if current user can manage settings // // This function is auto-generated func (svc accessControl) CanManageSettings(ctx context.Context) bool { - return svc.can(ctx, "settings.manage", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "settings.manage", r) } // CanCreateNamespace checks if current user can create namespace // // This function is auto-generated func (svc accessControl) CanCreateNamespace(ctx context.Context) bool { - return svc.can(ctx, "namespace.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "namespace.create", r) } // CanSearchNamespaces checks if current user can list, search or filter namespaces // // This function is auto-generated func (svc accessControl) CanSearchNamespaces(ctx context.Context) bool { - return svc.can(ctx, "namespaces.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "namespaces.search", r) } // CanManageResourceTranslations checks if current user can list, search, create, or update resource translations // // This function is auto-generated func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool { - return svc.can(ctx, "resource-translations.manage", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "resource-translations.manage", r) } // rbacResourceValidator validates known component's resource by routing it to the appropriate validator @@ -527,10 +524,10 @@ func rbacResourceValidator(r string, oo ...string) error { switch rbac.ResourceType(r) { case types.ChartResourceType: return rbacChartResourceValidator(r, oo...) - case types.ModuleFieldResourceType: - return rbacModuleFieldResourceValidator(r, oo...) case types.ModuleResourceType: return rbacModuleResourceValidator(r, oo...) + case types.ModuleFieldResourceType: + return rbacModuleFieldResourceValidator(r, oo...) case types.NamespaceResourceType: return rbacNamespaceResourceValidator(r, oo...) case types.PageResourceType: @@ -555,11 +552,6 @@ func rbacResourceOperations(r string) map[string]bool { "update": true, "delete": true, } - case types.ModuleFieldResourceType: - return map[string]bool{ - "record.value.read": true, - "record.value.update": true, - } case types.ModuleResourceType: return map[string]bool{ "read": true, @@ -568,6 +560,11 @@ func rbacResourceOperations(r string) map[string]bool { "record.create": true, "records.search": true, } + case types.ModuleFieldResourceType: + return map[string]bool{ + "record.value.read": true, + "record.value.update": true, + } case types.NamespaceResourceType: return map[string]bool{ "read": true, @@ -607,29 +604,29 @@ func rbacResourceOperations(r string) map[string]bool { return nil } -// rbacChartResourceValidator checks validity of rbac resource and operations +// rbacChartResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacChartResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose Chart resource", o) - } - } - if !strings.HasPrefix(r, types.ChartResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for chart resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.ChartResourceType):], sep), sep) prc = []string{ - "namespaceID", + "NamespaceID", "ID", } ) @@ -641,7 +638,7 @@ func rbacChartResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Chart", i) + return fmt.Errorf("invalid path wildcard level (%d) for chart resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -652,75 +649,29 @@ func rbacChartResourceValidator(r string, oo ...string) error { return nil } -// rbacModuleFieldResourceValidator checks validity of rbac resource and operations -// -// Can be called without operations to check for validity of resource string only -// -// This function is auto-generated -func rbacModuleFieldResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose ModuleField resource", o) - } - } - - if !strings.HasPrefix(r, types.ModuleFieldResourceType) { - // expecting resource to always include path - return fmt.Errorf("invalid resource type") - } - - const sep = "/" - var ( - pp = strings.Split(strings.Trim(r[len(types.ModuleFieldResourceType):], sep), sep) - prc = []string{ - "namespaceID", - "moduleID", - "ID", - } - ) - - if len(pp) != len(prc) { - return fmt.Errorf("invalid resource path structure") - } - - for i := 0; i < len(pp); i++ { - if pp[i] != "*" { - if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for ModuleField", i) - } - - if _, err := cast.ToUint64E(pp[i]); err != nil { - return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) - } - } - } - return nil -} - -// rbacModuleResourceValidator checks validity of rbac resource and operations +// rbacModuleResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacModuleResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose Module resource", o) - } - } - if !strings.HasPrefix(r, types.ModuleResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for module resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.ModuleResourceType):], sep), sep) prc = []string{ - "namespaceID", + "NamespaceID", "ID", } ) @@ -732,7 +683,7 @@ func rbacModuleResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Module", i) + return fmt.Errorf("invalid path wildcard level (%d) for module resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -743,24 +694,70 @@ func rbacModuleResourceValidator(r string, oo ...string) error { return nil } -// rbacNamespaceResourceValidator checks validity of rbac resource and operations +// rbacModuleFieldResourceValidator checks validity of RBAC resource and operations +// +// Can be called without operations to check for validity of resource string only +// +// This function is auto-generated +func rbacModuleFieldResourceValidator(r string, oo ...string) error { + if !strings.HasPrefix(r, types.ModuleFieldResourceType) { + // expecting resource to always include path + return fmt.Errorf("invalid resource type") + } + + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for moduleField resource", o) + } + } + + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.ModuleFieldResourceType):], sep), sep) + prc = []string{ + "NamespaceID", + "ModuleID", + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for moduleField resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } + return nil +} + +// rbacNamespaceResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacNamespaceResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose Namespace resource", o) - } - } - if !strings.HasPrefix(r, types.NamespaceResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for namespace resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.NamespaceResourceType):], sep), sep) @@ -776,7 +773,7 @@ func rbacNamespaceResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Namespace", i) + return fmt.Errorf("invalid path wildcard level (%d) for namespace resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -787,29 +784,29 @@ func rbacNamespaceResourceValidator(r string, oo ...string) error { return nil } -// rbacPageResourceValidator checks validity of rbac resource and operations +// rbacPageResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacPageResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose Page resource", o) - } - } - if !strings.HasPrefix(r, types.PageResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for page resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.PageResourceType):], sep), sep) prc = []string{ - "namespaceID", + "NamespaceID", "ID", } ) @@ -821,7 +818,7 @@ func rbacPageResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Page", i) + return fmt.Errorf("invalid path wildcard level (%d) for page resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -832,30 +829,30 @@ func rbacPageResourceValidator(r string, oo ...string) error { return nil } -// rbacRecordResourceValidator checks validity of rbac resource and operations +// rbacRecordResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacRecordResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose Record resource", o) - } - } - if !strings.HasPrefix(r, types.RecordResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for record resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.RecordResourceType):], sep), sep) prc = []string{ - "namespaceID", - "moduleID", + "NamespaceID", + "ModuleID", "ID", } ) @@ -867,7 +864,7 @@ func rbacRecordResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Record", i) + return fmt.Errorf("invalid path wildcard level (%d) for record resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -878,23 +875,23 @@ func rbacRecordResourceValidator(r string, oo ...string) error { return nil } -// rbacComponentResourceValidator checks validity of rbac resource and operations +// rbacComponentResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacComponentResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for compose resource", o) - } - } - if !strings.HasPrefix(r, types.ComponentResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for compose component resource", o) + } + } + return nil } diff --git a/compose/service/locale.gen.go b/compose/service/locale.gen.go index d2428001e..00e3a1936 100644 --- a/compose/service/locale.gen.go +++ b/compose/service/locale.gen.go @@ -6,11 +6,6 @@ package service // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml - import ( "context" "github.com/cortezaproject/corteza-server/compose/types" @@ -41,9 +36,9 @@ type ( } ResourceTranslationsManagerService interface { - Module(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) + Module(ctx context.Context, NamespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) Namespace(ctx context.Context, ID uint64) (locale.ResourceTranslationSet, error) - Page(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) + Page(ctx context.Context, NamespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) Upsert(context.Context, locale.ResourceTranslationSet) error Locale() locale.Resource @@ -108,7 +103,7 @@ func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.Res sysLocale = append(sysLocale, aux...) aux = current.Old(rr) - aux.Walk(func(cc *systemTypes.ResourceTranslation) error { + _ = aux.Walk(func(cc *systemTypes.ResourceTranslation) error { cc.UpdatedAt = now() cc.UpdatedBy = me.Identity() return nil @@ -132,7 +127,7 @@ func (svc resourceTranslationsManager) Locale() locale.Resource { return svc.locale } -func (svc resourceTranslationsManager) Module(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) { +func (svc resourceTranslationsManager) Module(ctx context.Context, NamespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) { var ( err error out locale.ResourceTranslationSet @@ -140,7 +135,7 @@ func (svc resourceTranslationsManager) Module(ctx context.Context, namespaceID u k types.LocaleKey ) - res, err = svc.loadModule(ctx, svc.store, namespaceID, ID) + res, err = svc.loadModule(ctx, svc.store, NamespaceID, ID) if err != nil { return nil, err } @@ -156,8 +151,7 @@ func (svc resourceTranslationsManager) Module(ctx context.Context, namespaceID u } - tmp, err := svc.moduleExtended(ctx, res) - return append(out, tmp...), err + return out, nil } func (svc resourceTranslationsManager) Namespace(ctx context.Context, ID uint64) (locale.ResourceTranslationSet, error) { @@ -182,7 +176,7 @@ func (svc resourceTranslationsManager) Namespace(ctx context.Context, ID uint64) Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path), }) - k = types.LocaleKeyNamespaceSubtitle + k = types.LocaleKeyNamespaceMetaSubtitle out = append(out, &locale.ResourceTranslation{ Resource: res.ResourceTranslation(), Lang: tag.String(), @@ -190,7 +184,7 @@ func (svc resourceTranslationsManager) Namespace(ctx context.Context, ID uint64) Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), k.Path), }) - k = types.LocaleKeyNamespaceDescription + k = types.LocaleKeyNamespaceMetaDescription out = append(out, &locale.ResourceTranslation{ Resource: res.ResourceTranslation(), Lang: tag.String(), @@ -199,10 +193,11 @@ func (svc resourceTranslationsManager) Namespace(ctx context.Context, ID uint64) }) } + return out, nil } -func (svc resourceTranslationsManager) Page(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) { +func (svc resourceTranslationsManager) Page(ctx context.Context, NamespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) { var ( err error out locale.ResourceTranslationSet @@ -210,7 +205,7 @@ func (svc resourceTranslationsManager) Page(ctx context.Context, namespaceID uin k types.LocaleKey ) - res, err = svc.loadPage(ctx, svc.store, namespaceID, ID) + res, err = svc.loadPage(ctx, svc.store, NamespaceID, ID) if err != nil { return nil, err } diff --git a/compose/service/locale.go b/compose/service/locale.go index 60a0c6364..d34c5bc9a 100644 --- a/compose/service/locale.go +++ b/compose/service/locale.go @@ -28,14 +28,14 @@ func (svc resourceTranslationsManager) moduleExtended(ctx context.Context, res * Msg: svc.locale.TResourceFor(tag, f.ResourceTranslation(), k.Path), }) - k = types.LocaleKeyModuleFieldDescriptionView + k = types.LocaleKeyModuleFieldMetaDescriptionView out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), Lang: tag.String(), Key: k.Path, Msg: svc.locale.TResourceFor(tag, f.ResourceTranslation(), k.Path), }) - k = types.LocaleKeyModuleFieldDescriptionEdit + k = types.LocaleKeyModuleFieldMetaDescriptionEdit out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), Lang: tag.String(), @@ -43,14 +43,14 @@ func (svc resourceTranslationsManager) moduleExtended(ctx context.Context, res * Msg: svc.locale.TResourceFor(tag, f.ResourceTranslation(), k.Path), }) - k = types.LocaleKeyModuleFieldHintView + k = types.LocaleKeyModuleFieldMetaHintView out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), Lang: tag.String(), Key: k.Path, Msg: svc.locale.TResourceFor(tag, f.ResourceTranslation(), k.Path), }) - k = types.LocaleKeyModuleFieldHintEdit + k = types.LocaleKeyModuleFieldMetaHintEdit out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), Lang: tag.String(), @@ -86,7 +86,7 @@ func (svc resourceTranslationsManager) moduleFieldExpressionsHandler(ctx context "{{validatorID}}", strconv.FormatUint(vContentID, 10), ) - tKey := rpl.Replace(types.LocaleKeyModuleFieldValidatorError.Path) + tKey := rpl.Replace(types.LocaleKeyModuleFieldExpressionValidatorValidatorIDError.Path) out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), @@ -128,7 +128,7 @@ func (svc resourceTranslationsManager) moduleFieldOptionsHandler(ctx context.Con } } - trKey := strings.NewReplacer("{{value}}", value).Replace(types.LocaleKeyModuleFieldOptionsOptionTexts.Path) + trKey := strings.NewReplacer("{{value}}", value).Replace(types.LocaleKeyModuleFieldMetaOptionsValueText.Path) out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), @@ -154,7 +154,7 @@ func (svc resourceTranslationsManager) pageExtended(ctx context.Context, res *ty ) // base stuff - k = types.LocaleKeyPageBlockTitle + k = types.LocaleKeyPagePageBlockBlockIDTitle out = append(out, &locale.ResourceTranslation{ Resource: res.ResourceTranslation(), Lang: tag.String(), @@ -162,7 +162,7 @@ func (svc resourceTranslationsManager) pageExtended(ctx context.Context, res *ty Msg: svc.locale.TResourceFor(tag, res.ResourceTranslation(), rpl.Replace(k.Path)), }) - k = types.LocaleKeyPageBlockDescription + k = types.LocaleKeyPagePageBlockBlockIDDescription out = append(out, &locale.ResourceTranslation{ Resource: res.ResourceTranslation(), Lang: tag.String(), diff --git a/compose/service/record.go b/compose/service/record.go index 2d2c0de81..cec0c5055 100644 --- a/compose/service/record.go +++ b/compose/service/record.go @@ -62,8 +62,8 @@ type ( } recordValueAccessController interface { - CanReadRecordValue(context.Context, *types.ModuleField) bool - CanUpdateRecordValue(context.Context, *types.ModuleField) bool + CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool + CanUpdateRecordValueOnModuleField(context.Context, *types.ModuleField) bool } recordAccessController interface { @@ -637,7 +637,7 @@ func RecordValueUpdateOpCheck(ctx context.Context, ac recordValueAccessControlle return nil } - if v.IsUpdated() && !ac.CanUpdateRecordValue(ctx, f) { + if v.IsUpdated() && !ac.CanUpdateRecordValueOnModuleField(ctx, f) { rve.Push(types.RecordValueError{Kind: "updateDenied", Meta: map[string]interface{}{"field": v.Name, "value": v.Value}}) } @@ -908,7 +908,7 @@ func (svc record) procUpdate(ctx context.Context, invokerID uint64, m *types.Mod upd = RecordUpdateOwner(invokerID, upd, old) upd.Values = old.Values.Merge(m.Fields, upd.Values, func(f *types.ModuleField) bool { - return svc.ac.CanUpdateRecordValue(ctx, m.Fields.FindByName(f.Name)) + return svc.ac.CanUpdateRecordValueOnModuleField(ctx, m.Fields.FindByName(f.Name)) }) if rve = RecordValueUpdateOpCheck(ctx, svc.ac, m, upd.Values); !rve.IsValid() { @@ -1095,7 +1095,7 @@ func (svc record) Organize(ctx context.Context, namespaceID, moduleID, recordID return fmt.Errorf("cannot reorder on multi-value field %q", posField) } - if !svc.ac.CanUpdateRecordValue(ctx, sf) { + if !svc.ac.CanUpdateRecordValueOnModuleField(ctx, sf) { return RecordErrNotAllowedToUpdate() } @@ -1119,7 +1119,7 @@ func (svc record) Organize(ctx context.Context, namespaceID, moduleID, recordID return fmt.Errorf("cannot update multi-value field %q", posField) } - if !svc.ac.CanUpdateRecordValue(ctx, vf) { + if !svc.ac.CanUpdateRecordValueOnModuleField(ctx, vf) { return RecordErrNotAllowedToUpdate() } @@ -1404,7 +1404,7 @@ func ComposeRecordFilterAC(ctx context.Context, ac recordValueAccessController, ) for _, f := range m.Fields { - readableFields[f.Name] = ac.CanReadRecordValue(ctx, f) + readableFields[f.Name] = ac.CanReadRecordValueOnModuleField(ctx, f) } for _, r := range rr { diff --git a/compose/types/locale.gen.go b/compose/types/locale.gen.go index c180e9788..97fa977f0 100644 --- a/compose/types/locale.gen.go +++ b/compose/types/locale.gen.go @@ -6,12 +6,6 @@ package types // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml - import ( "fmt" "github.com/cortezaproject/corteza-server/pkg/locale" @@ -29,160 +23,32 @@ type ( // Types and stuff const ( - ModuleFieldResourceTranslationType = "compose:module-field" ModuleResourceTranslationType = "compose:module" + ModuleFieldResourceTranslationType = "compose:module-field" NamespaceResourceTranslationType = "compose:namespace" PageResourceTranslationType = "compose:page" ) var ( - LocaleKeyModuleFieldLabel = LocaleKey{ - Name: "label", - Resource: ModuleFieldResourceTranslationType, - Path: "label", - } - LocaleKeyModuleFieldDescriptionView = LocaleKey{ - Name: "descriptionView", - Resource: ModuleFieldResourceTranslationType, - Path: "meta.description.view", - CustomHandler: "descriptionView", - } - LocaleKeyModuleFieldDescriptionEdit = LocaleKey{ - Name: "descriptionEdit", - Resource: ModuleFieldResourceTranslationType, - Path: "meta.description.edit", - CustomHandler: "descriptionEdit", - } - LocaleKeyModuleFieldHintView = LocaleKey{ - Name: "hintView", - Resource: ModuleFieldResourceTranslationType, - Path: "meta.hint.view", - CustomHandler: "hintView", - } - LocaleKeyModuleFieldHintEdit = LocaleKey{ - Name: "hintEdit", - Resource: ModuleFieldResourceTranslationType, - Path: "meta.hint.edit", - CustomHandler: "hintEdit", - } - LocaleKeyModuleFieldValidatorError = LocaleKey{ - Name: "validatorError", - Resource: ModuleFieldResourceTranslationType, - Path: "expression.validator.{{validatorID}}.error", - CustomHandler: "validatorError", - } - LocaleKeyModuleFieldOptionsOptionTexts = LocaleKey{ - Name: "optionsOptionTexts", - Resource: ModuleFieldResourceTranslationType, - Path: "meta.options.{{value}}.text", - CustomHandler: "optionsOptionTexts", - } - LocaleKeyModuleName = LocaleKey{ - Name: "name", - Resource: ModuleResourceTranslationType, - Path: "name", - } - LocaleKeyNamespaceName = LocaleKey{ - Name: "name", - Resource: NamespaceResourceTranslationType, - Path: "name", - } - LocaleKeyNamespaceSubtitle = LocaleKey{ - Name: "subtitle", - Resource: NamespaceResourceTranslationType, - Path: "subtitle", - } - LocaleKeyNamespaceDescription = LocaleKey{ - Name: "description", - Resource: NamespaceResourceTranslationType, - Path: "description", - } - LocaleKeyPageTitle = LocaleKey{ - Name: "title", - Resource: PageResourceTranslationType, - Path: "title", - } - LocaleKeyPageDescription = LocaleKey{ - Name: "description", - Resource: PageResourceTranslationType, - Path: "description", - } - LocaleKeyPageBlockTitle = LocaleKey{ - Name: "blockTitle", - Resource: PageResourceTranslationType, - Path: "pageBlock.{{blockID}}.title", - } - LocaleKeyPageBlockDescription = LocaleKey{ - Name: "blockDescription", - Resource: PageResourceTranslationType, - Path: "pageBlock.{{blockID}}.description", - } - LocaleKeyPageBlockAutomationButtonlabel = LocaleKey{ - Name: "blockAutomationButtonlabel", - Resource: PageResourceTranslationType, - Path: "pageBlock.{{blockID}}.button.{{buttonID}}.label", - } + // @todo can we remove LocaleKey struct for string constant? + LocaleKeyModuleName = LocaleKey{Path: "name"} + LocaleKeyModuleFieldLabel = LocaleKey{Path: "label"} + LocaleKeyModuleFieldMetaDescriptionView = LocaleKey{Path: "meta.description.view"} + LocaleKeyModuleFieldMetaDescriptionEdit = LocaleKey{Path: "meta.description.edit"} + LocaleKeyModuleFieldMetaHintView = LocaleKey{Path: "meta.hint.view"} + LocaleKeyModuleFieldMetaHintEdit = LocaleKey{Path: "meta.hint.edit"} + LocaleKeyModuleFieldExpressionValidatorValidatorIDError = LocaleKey{Path: "expression.validator.{{validatorID}}.error"} + LocaleKeyModuleFieldMetaOptionsValueText = LocaleKey{Path: "meta.options.{{value}}.text"} + LocaleKeyNamespaceName = LocaleKey{Path: "name"} + LocaleKeyNamespaceMetaSubtitle = LocaleKey{Path: "meta.subtitle"} + LocaleKeyNamespaceMetaDescription = LocaleKey{Path: "meta.description"} + LocaleKeyPageTitle = LocaleKey{Path: "title"} + LocaleKeyPageDescription = LocaleKey{Path: "description"} + LocaleKeyPagePageBlockBlockIDTitle = LocaleKey{Path: "pageBlock.{{blockID}}.title"} + LocaleKeyPagePageBlockBlockIDDescription = LocaleKey{Path: "pageBlock.{{blockID}}.description"} + LocaleKeyPagePageBlockBlockIDButtonButtonIDLabel = LocaleKey{Path: "pageBlock.{{blockID}}.button.{{buttonID}}.label"} ) -// ResourceTranslation returns string representation of Locale resource for ModuleField by calling ModuleFieldResourceTranslation fn -// -// Locale resource is in "compose:module-field/..." format -// -// This function is auto-generated -func (r ModuleField) ResourceTranslation() string { - return ModuleFieldResourceTranslation(r.NamespaceID, r.ModuleID, r.ID) -} - -// ModuleFieldResourceTranslation returns string representation of Locale resource for ModuleField -// -// Locale resource is in the compose:module-field/... format -// -// This function is auto-generated -func ModuleFieldResourceTranslation(namespaceID uint64, moduleID uint64, id uint64) string { - cpts := []interface{}{ModuleFieldResourceTranslationType} - cpts = append(cpts, strconv.FormatUint(namespaceID, 10), strconv.FormatUint(moduleID, 10), strconv.FormatUint(id, 10)) - - return fmt.Sprintf(ModuleFieldResourceTranslationTpl(), cpts...) -} - -// @todo template -func ModuleFieldResourceTranslationTpl() string { - return "%s/%s/%s/%s" -} - -func (r *ModuleField) DecodeTranslations(tt locale.ResourceTranslationIndex) { - var aux *locale.ResourceTranslation - if aux = tt.FindByKey(LocaleKeyModuleFieldLabel.Path); aux != nil { - r.Label = aux.Msg - } - r.decodeTranslationsDescriptionView(tt) - r.decodeTranslationsDescriptionEdit(tt) - r.decodeTranslationsHintView(tt) - r.decodeTranslationsHintEdit(tt) - r.decodeTranslationsValidatorError(tt) - r.decodeTranslationsOptionsOptionTexts(tt) -} - -func (r *ModuleField) EncodeTranslations() (out locale.ResourceTranslationSet) { - out = locale.ResourceTranslationSet{} - if r.Label != "" { - out = append(out, &locale.ResourceTranslation{ - Resource: r.ResourceTranslation(), - Key: LocaleKeyModuleFieldLabel.Path, - Msg: locale.SanitizeMessage(r.Label), - }) - } - - out = append(out, r.encodeTranslationsDescriptionView()...) - out = append(out, r.encodeTranslationsDescriptionEdit()...) - out = append(out, r.encodeTranslationsHintView()...) - out = append(out, r.encodeTranslationsHintEdit()...) - out = append(out, r.encodeTranslationsValidatorError()...) - out = append(out, r.encodeTranslationsOptionsOptionTexts()...) - - return out -} - // ResourceTranslation returns string representation of Locale resource for Module by calling ModuleResourceTranslation fn // // Locale resource is in "compose:module/..." format @@ -197,29 +63,31 @@ func (r Module) ResourceTranslation() string { // Locale resource is in the compose:module/... format // // This function is auto-generated -func ModuleResourceTranslation(namespaceID uint64, id uint64) string { - cpts := []interface{}{ModuleResourceTranslationType} - cpts = append(cpts, strconv.FormatUint(namespaceID, 10), strconv.FormatUint(id, 10)) +func ModuleResourceTranslation(NamespaceID uint64, ID uint64) string { + cpts := []interface{}{ + ModuleResourceTranslationType, + strconv.FormatUint(NamespaceID, 10), + strconv.FormatUint(ID, 10), + } return fmt.Sprintf(ModuleResourceTranslationTpl(), cpts...) } -// @todo template func ModuleResourceTranslationTpl() string { return "%s/%s/%s" } func (r *Module) DecodeTranslations(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation + if aux = tt.FindByKey(LocaleKeyModuleName.Path); aux != nil { r.Name = aux.Msg } - - r.decodeTranslations(tt) } func (r *Module) EncodeTranslations() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} + if r.Name != "" { out = append(out, &locale.ResourceTranslation{ Resource: r.ResourceTranslation(), @@ -228,7 +96,81 @@ func (r *Module) EncodeTranslations() (out locale.ResourceTranslationSet) { }) } - out = append(out, r.encodeTranslations()...) + return out +} + +// ResourceTranslation returns string representation of Locale resource for ModuleField by calling ModuleFieldResourceTranslation fn +// +// Locale resource is in "compose:module-field/..." format +// +// This function is auto-generated +func (r ModuleField) ResourceTranslation() string { + return ModuleFieldResourceTranslation(r.NamespaceID, r.ModuleID, r.ID) +} + +// ModuleFieldResourceTranslation returns string representation of Locale resource for ModuleField +// +// Locale resource is in the compose:module-field/... format +// +// This function is auto-generated +func ModuleFieldResourceTranslation(NamespaceID uint64, ModuleID uint64, ID uint64) string { + cpts := []interface{}{ + ModuleFieldResourceTranslationType, + strconv.FormatUint(NamespaceID, 10), + strconv.FormatUint(ModuleID, 10), + strconv.FormatUint(ID, 10), + } + + return fmt.Sprintf(ModuleFieldResourceTranslationTpl(), cpts...) +} + +func ModuleFieldResourceTranslationTpl() string { + return "%s/%s/%s/%s" +} + +func (r *ModuleField) DecodeTranslations(tt locale.ResourceTranslationIndex) { + var aux *locale.ResourceTranslation + + if aux = tt.FindByKey(LocaleKeyModuleFieldLabel.Path); aux != nil { + r.Label = aux.Msg + } + + r.decodeTranslationsMetaDescriptionView(tt) + + r.decodeTranslationsMetaDescriptionEdit(tt) + + r.decodeTranslationsMetaHintView(tt) + + r.decodeTranslationsMetaHintEdit(tt) + + r.decodeTranslationsExpressionValidatorValidatorIDError(tt) + + r.decodeTranslationsMetaOptionsValueText(tt) + +} + +func (r *ModuleField) EncodeTranslations() (out locale.ResourceTranslationSet) { + out = locale.ResourceTranslationSet{} + + if r.Label != "" { + out = append(out, &locale.ResourceTranslation{ + Resource: r.ResourceTranslation(), + Key: LocaleKeyModuleFieldLabel.Path, + Msg: locale.SanitizeMessage(r.Label), + }) + } + + out = append(out, r.encodeTranslationsMetaDescriptionView()...) + + out = append(out, r.encodeTranslationsMetaDescriptionEdit()...) + + out = append(out, r.encodeTranslationsMetaHintView()...) + + out = append(out, r.encodeTranslationsMetaHintEdit()...) + + out = append(out, r.encodeTranslationsExpressionValidatorValidatorIDError()...) + + out = append(out, r.encodeTranslationsMetaOptionsValueText()...) return out } @@ -247,33 +189,38 @@ func (r Namespace) ResourceTranslation() string { // Locale resource is in the compose:namespace/... format // // This function is auto-generated -func NamespaceResourceTranslation(id uint64) string { - cpts := []interface{}{NamespaceResourceTranslationType} - cpts = append(cpts, strconv.FormatUint(id, 10)) +func NamespaceResourceTranslation(ID uint64) string { + cpts := []interface{}{ + NamespaceResourceTranslationType, + strconv.FormatUint(ID, 10), + } return fmt.Sprintf(NamespaceResourceTranslationTpl(), cpts...) } -// @todo template func NamespaceResourceTranslationTpl() string { return "%s/%s" } func (r *Namespace) DecodeTranslations(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation + if aux = tt.FindByKey(LocaleKeyNamespaceName.Path); aux != nil { r.Name = aux.Msg } - if aux = tt.FindByKey(LocaleKeyNamespaceSubtitle.Path); aux != nil { + + if aux = tt.FindByKey(LocaleKeyNamespaceMetaSubtitle.Path); aux != nil { r.Meta.Subtitle = aux.Msg } - if aux = tt.FindByKey(LocaleKeyNamespaceDescription.Path); aux != nil { + + if aux = tt.FindByKey(LocaleKeyNamespaceMetaDescription.Path); aux != nil { r.Meta.Description = aux.Msg } } func (r *Namespace) EncodeTranslations() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} + if r.Name != "" { out = append(out, &locale.ResourceTranslation{ Resource: r.ResourceTranslation(), @@ -281,17 +228,19 @@ func (r *Namespace) EncodeTranslations() (out locale.ResourceTranslationSet) { Msg: locale.SanitizeMessage(r.Name), }) } + if r.Meta.Subtitle != "" { out = append(out, &locale.ResourceTranslation{ Resource: r.ResourceTranslation(), - Key: LocaleKeyNamespaceSubtitle.Path, + Key: LocaleKeyNamespaceMetaSubtitle.Path, Msg: locale.SanitizeMessage(r.Meta.Subtitle), }) } + if r.Meta.Description != "" { out = append(out, &locale.ResourceTranslation{ Resource: r.ResourceTranslation(), - Key: LocaleKeyNamespaceDescription.Path, + Key: LocaleKeyNamespaceMetaDescription.Path, Msg: locale.SanitizeMessage(r.Meta.Description), }) } @@ -313,23 +262,27 @@ func (r Page) ResourceTranslation() string { // Locale resource is in the compose:page/... format // // This function is auto-generated -func PageResourceTranslation(namespaceID uint64, id uint64) string { - cpts := []interface{}{PageResourceTranslationType} - cpts = append(cpts, strconv.FormatUint(namespaceID, 10), strconv.FormatUint(id, 10)) +func PageResourceTranslation(NamespaceID uint64, ID uint64) string { + cpts := []interface{}{ + PageResourceTranslationType, + strconv.FormatUint(NamespaceID, 10), + strconv.FormatUint(ID, 10), + } return fmt.Sprintf(PageResourceTranslationTpl(), cpts...) } -// @todo template func PageResourceTranslationTpl() string { return "%s/%s/%s" } func (r *Page) DecodeTranslations(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation + if aux = tt.FindByKey(LocaleKeyPageTitle.Path); aux != nil { r.Title = aux.Msg } + if aux = tt.FindByKey(LocaleKeyPageDescription.Path); aux != nil { r.Description = aux.Msg } @@ -339,6 +292,7 @@ func (r *Page) DecodeTranslations(tt locale.ResourceTranslationIndex) { func (r *Page) EncodeTranslations() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} + if r.Title != "" { out = append(out, &locale.ResourceTranslation{ Resource: r.ResourceTranslation(), @@ -346,6 +300,7 @@ func (r *Page) EncodeTranslations() (out locale.ResourceTranslationSet) { Msg: locale.SanitizeMessage(r.Title), }) } + if r.Description != "" { out = append(out, &locale.ResourceTranslation{ Resource: r.ResourceTranslation(), diff --git a/compose/types/module_field.go b/compose/types/module_field.go index cc3bc30d9..cfd5ef329 100644 --- a/compose/types/module_field.go +++ b/compose/types/module_field.go @@ -56,7 +56,7 @@ var ( _ sort.Interface = &ModuleFieldSet{} ) -func (f *ModuleField) decodeTranslationsValidatorError(tt locale.ResourceTranslationIndex) { +func (f *ModuleField) decodeTranslationsExpressionValidatorValidatorIDError(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation for i, e := range f.Expressions.Validators { @@ -65,40 +65,40 @@ func (f *ModuleField) decodeTranslationsValidatorError(tt locale.ResourceTransla "{{validatorID}}", strconv.FormatUint(validatorID, 10), ) - if aux = tt.FindByKey(rpl.Replace(LocaleKeyModuleFieldValidatorError.Path)); aux != nil { + if aux = tt.FindByKey(rpl.Replace(LocaleKeyModuleFieldExpressionValidatorValidatorIDError.Path)); aux != nil { f.Expressions.Validators[i].Error = aux.Msg } } } -func (f *ModuleField) decodeTranslationsDescriptionView(tt locale.ResourceTranslationIndex) { +func (f *ModuleField) decodeTranslationsMetaDescriptionView(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation - if aux = tt.FindByKey(LocaleKeyModuleFieldDescriptionView.Path); aux != nil { + if aux = tt.FindByKey(LocaleKeyModuleFieldMetaDescriptionView.Path); aux != nil { f.setOptionKey(aux.Msg, "description", "edit") } } -func (f *ModuleField) decodeTranslationsDescriptionEdit(tt locale.ResourceTranslationIndex) { +func (f *ModuleField) decodeTranslationsMetaDescriptionEdit(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation - if aux = tt.FindByKey(LocaleKeyModuleFieldDescriptionEdit.Path); aux != nil { + if aux = tt.FindByKey(LocaleKeyModuleFieldMetaDescriptionEdit.Path); aux != nil { f.setOptionKey(aux.Msg, "description", "view") } } -func (f *ModuleField) decodeTranslationsHintView(tt locale.ResourceTranslationIndex) { +func (f *ModuleField) decodeTranslationsMetaHintView(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation - if aux = tt.FindByKey(LocaleKeyModuleFieldHintView.Path); aux != nil { + if aux = tt.FindByKey(LocaleKeyModuleFieldMetaHintView.Path); aux != nil { f.setOptionKey(aux.Msg, "hint", "edit") } } -func (f *ModuleField) decodeTranslationsHintEdit(tt locale.ResourceTranslationIndex) { +func (f *ModuleField) decodeTranslationsMetaHintEdit(tt locale.ResourceTranslationIndex) { var aux *locale.ResourceTranslation - if aux = tt.FindByKey(LocaleKeyModuleFieldHintEdit.Path); aux != nil { + if aux = tt.FindByKey(LocaleKeyModuleFieldMetaHintEdit.Path); aux != nil { f.setOptionKey(aux.Msg, "hint", "view") } } @@ -106,7 +106,7 @@ func (f *ModuleField) decodeTranslationsHintEdit(tt locale.ResourceTranslationIn // Decodes translations and modifies options // // Why "options-option-texts"? Because we're translating option txts under options key-value -func (f *ModuleField) decodeTranslationsOptionsOptionTexts(tt locale.ResourceTranslationIndex) { +func (f *ModuleField) decodeTranslationsMetaOptionsValueText(tt locale.ResourceTranslationIndex) { var ( tr *locale.ResourceTranslation ) @@ -145,7 +145,7 @@ func (f *ModuleField) decodeTranslationsOptionsOptionTexts(tt locale.ResourceTra // find the translation for that value // and update the option (effectively overwriting // the original text value (in case of map option) - trKey := strings.NewReplacer("{{value}}", outOpt["value"]).Replace(LocaleKeyModuleFieldOptionsOptionTexts.Path) + trKey := strings.NewReplacer("{{value}}", outOpt["value"]).Replace(LocaleKeyModuleFieldMetaOptionsValueText.Path) if tr = tt.FindByKey(trKey); tr != nil { outOpt["text"] = tr.Msg } @@ -155,7 +155,7 @@ func (f *ModuleField) decodeTranslationsOptionsOptionTexts(tt locale.ResourceTra } } -func (m *ModuleField) encodeTranslationsValidatorError() (out locale.ResourceTranslationSet) { +func (m *ModuleField) encodeTranslationsExpressionValidatorValidatorIDError() (out locale.ResourceTranslationSet) { out = make(locale.ResourceTranslationSet, 0, 3) // Module field expressions @@ -167,7 +167,7 @@ func (m *ModuleField) encodeTranslationsValidatorError() (out locale.ResourceTra out = append(out, &locale.ResourceTranslation{ Resource: m.ResourceTranslation(), - Key: rpl.Replace(LocaleKeyModuleFieldValidatorError.Path), + Key: rpl.Replace(LocaleKeyModuleFieldExpressionValidatorValidatorIDError.Path), Msg: e.Error, }) } @@ -175,53 +175,53 @@ func (m *ModuleField) encodeTranslationsValidatorError() (out locale.ResourceTra return } -func (f *ModuleField) encodeTranslationsDescriptionView() (out locale.ResourceTranslationSet) { +func (f *ModuleField) encodeTranslationsMetaDescriptionView() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} if v := f.getOptionKey("description", "edit"); v != nil { aux := cast.ToString(v) out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), - Key: LocaleKeyModuleFieldDescriptionView.Path, + Key: LocaleKeyModuleFieldMetaDescriptionView.Path, Msg: aux, }) } return out } -func (f *ModuleField) encodeTranslationsDescriptionEdit() (out locale.ResourceTranslationSet) { +func (f *ModuleField) encodeTranslationsMetaDescriptionEdit() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} if v := f.getOptionKey("description", "view"); v != nil { aux := cast.ToString(v) out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), - Key: LocaleKeyModuleFieldDescriptionEdit.Path, + Key: LocaleKeyModuleFieldMetaDescriptionEdit.Path, Msg: aux, }) } return out } -func (f *ModuleField) encodeTranslationsHintView() (out locale.ResourceTranslationSet) { +func (f *ModuleField) encodeTranslationsMetaHintView() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} if v := f.getOptionKey("hint", "edit"); v != nil { aux := cast.ToString(v) out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), - Key: LocaleKeyModuleFieldHintView.Path, + Key: LocaleKeyModuleFieldMetaHintView.Path, Msg: aux, }) } return out } -func (f *ModuleField) encodeTranslationsHintEdit() (out locale.ResourceTranslationSet) { +func (f *ModuleField) encodeTranslationsMetaHintEdit() (out locale.ResourceTranslationSet) { out = locale.ResourceTranslationSet{} if v := f.getOptionKey("hint", "view"); v != nil { aux := cast.ToString(v) out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), - Key: LocaleKeyModuleFieldHintEdit.Path, + Key: LocaleKeyModuleFieldMetaHintEdit.Path, Msg: aux, }) } @@ -229,7 +229,7 @@ func (f *ModuleField) encodeTranslationsHintEdit() (out locale.ResourceTranslati } // extracts option texts and converts (encodes) them to translations -func (f *ModuleField) encodeTranslationsOptionsOptionTexts() (out locale.ResourceTranslationSet) { +func (f *ModuleField) encodeTranslationsMetaOptionsValueText() (out locale.ResourceTranslationSet) { out = make(locale.ResourceTranslationSet, 0, 3) optsUnknown, has := f.Options["options"] @@ -252,7 +252,7 @@ func (f *ModuleField) encodeTranslationsOptionsOptionTexts() (out locale.Resourc out = append(out, &locale.ResourceTranslation{ Resource: f.ResourceTranslation(), Key: strings.NewReplacer("{{value}}", value). - Replace(LocaleKeyModuleFieldOptionsOptionTexts.Path), + Replace(LocaleKeyModuleFieldMetaOptionsValueText.Path), Msg: text, }) } diff --git a/compose/types/module_field_test.go b/compose/types/module_field_test.go index 8746de13e..1ddc15af0 100644 --- a/compose/types/module_field_test.go +++ b/compose/types/module_field_test.go @@ -68,7 +68,7 @@ func TestModuleField_decodeTranslationsOptionsOptionTexts(t *testing.T) { f = &ModuleField{Options: tt.opts} ) - f.decodeTranslationsOptionsOptionTexts(rti) + f.decodeTranslationsMetaOptionsValueText(rti) if tt.out != nil { req.Equal(tt.out, f.Options["options"]) diff --git a/compose/types/namespace.go b/compose/types/namespace.go index 40a04f989..c27ac56ef 100644 --- a/compose/types/namespace.go +++ b/compose/types/namespace.go @@ -6,7 +6,6 @@ import ( "time" "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/pkg/errors" ) diff --git a/compose/types/page.go b/compose/types/page.go index 034effc1e..9808f955f 100644 --- a/compose/types/page.go +++ b/compose/types/page.go @@ -124,10 +124,10 @@ func (p *Page) decodeTranslations(tt locale.ResourceTranslationIndex) { ) // - generic page block stuff - if aux = tt.FindByKey(rpl.Replace(LocaleKeyPageBlockTitle.Path)); aux != nil { + if aux = tt.FindByKey(rpl.Replace(LocaleKeyPagePageBlockBlockIDTitle.Path)); aux != nil { p.Blocks[i].Title = aux.Msg } - if aux = tt.FindByKey(rpl.Replace(LocaleKeyPageBlockDescription.Path)); aux != nil { + if aux = tt.FindByKey(rpl.Replace(LocaleKeyPagePageBlockBlockIDDescription.Path)); aux != nil { p.Blocks[i].Description = aux.Msg } @@ -148,7 +148,7 @@ func (p *Page) decodeTranslations(tt locale.ResourceTranslationIndex) { "{{buttonID}}", strconv.FormatUint(buttonID, 10), ) - if aux = tt.FindByKey(rpl.Replace(LocaleKeyPageBlockAutomationButtonlabel.Path)); aux != nil { + if aux = tt.FindByKey(rpl.Replace(LocaleKeyPagePageBlockBlockIDButtonButtonIDLabel.Path)); aux != nil { btn["label"] = aux.Msg } } @@ -169,13 +169,13 @@ func (p *Page) encodeTranslations() (out locale.ResourceTranslationSet) { // - generic page block stuff out = append(out, &locale.ResourceTranslation{ Resource: p.ResourceTranslation(), - Key: rpl.Replace(LocaleKeyPageBlockTitle.Path), + Key: rpl.Replace(LocaleKeyPagePageBlockBlockIDTitle.Path), Msg: block.Title, }) out = append(out, &locale.ResourceTranslation{ Resource: p.ResourceTranslation(), - Key: rpl.Replace(LocaleKeyPageBlockDescription.Path), + Key: rpl.Replace(LocaleKeyPagePageBlockBlockIDDescription.Path), Msg: block.Description, }) @@ -202,7 +202,7 @@ func (p *Page) encodeTranslations() (out locale.ResourceTranslationSet) { out = append(out, &locale.ResourceTranslation{ Resource: p.ResourceTranslation(), - Key: rpl.Replace(LocaleKeyPageBlockAutomationButtonlabel.Path), + Key: rpl.Replace(LocaleKeyPagePageBlockBlockIDButtonButtonIDLabel.Path), Msg: btn["label"].(string), }) } diff --git a/compose/types/rbac.gen.go b/compose/types/rbac.gen.go index 6832ddc0b..4198023a2 100644 --- a/compose/types/rbac.gen.go +++ b/compose/types/rbac.gen.go @@ -6,15 +6,6 @@ package types // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.chart.yaml -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml -// - compose.record.yaml -// - compose.yaml - import ( "fmt" "strconv" @@ -27,10 +18,15 @@ type ( Component struct{} ) +var ( + _ = fmt.Printf + _ = strconv.FormatUint +) + const ( ChartResourceType = "corteza::compose:chart" - ModuleFieldResourceType = "corteza::compose:module-field" ModuleResourceType = "corteza::compose:module" + ModuleFieldResourceType = "corteza::compose:module-field" NamespaceResourceType = "corteza::compose:namespace" PageResourceType = "corteza::compose:page" RecordResourceType = "corteza::compose:record" @@ -69,11 +65,46 @@ func ChartRbacResource(namespaceID uint64, id uint64) string { } -// @todo template func ChartRbacResourceTpl() string { return "%s/%s/%s" } +// RbacResource returns string representation of RBAC resource for Module by calling ModuleRbacResource fn +// +// RBAC resource is in the corteza::compose:module/... format +// +// This function is auto-generated +func (r Module) RbacResource() string { + return ModuleRbacResource(r.NamespaceID, r.ID) +} + +// ModuleRbacResource returns string representation of RBAC resource for Module +// +// RBAC resource is in the corteza::compose:module/... format +// +// This function is auto-generated +func ModuleRbacResource(namespaceID uint64, id uint64) string { + cpts := []interface{}{ModuleResourceType} + if namespaceID != 0 { + cpts = append(cpts, strconv.FormatUint(namespaceID, 10)) + } else { + cpts = append(cpts, "*") + } + + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(ModuleRbacResourceTpl(), cpts...) + +} + +func ModuleRbacResourceTpl() string { + return "%s/%s/%s" +} + // RbacResource returns string representation of RBAC resource for ModuleField by calling ModuleFieldRbacResource fn // // RBAC resource is in the corteza::compose:module-field/... format @@ -112,48 +143,10 @@ func ModuleFieldRbacResource(namespaceID uint64, moduleID uint64, id uint64) str } -// @todo template func ModuleFieldRbacResourceTpl() string { return "%s/%s/%s/%s" } -// RbacResource returns string representation of RBAC resource for Module by calling ModuleRbacResource fn -// -// RBAC resource is in the corteza::compose:module/... format -// -// This function is auto-generated -func (r Module) RbacResource() string { - return ModuleRbacResource(r.NamespaceID, r.ID) -} - -// ModuleRbacResource returns string representation of RBAC resource for Module -// -// RBAC resource is in the corteza::compose:module/... format -// -// This function is auto-generated -func ModuleRbacResource(namespaceID uint64, id uint64) string { - cpts := []interface{}{ModuleResourceType} - if namespaceID != 0 { - cpts = append(cpts, strconv.FormatUint(namespaceID, 10)) - } else { - cpts = append(cpts, "*") - } - - if id != 0 { - cpts = append(cpts, strconv.FormatUint(id, 10)) - } else { - cpts = append(cpts, "*") - } - - return fmt.Sprintf(ModuleRbacResourceTpl(), cpts...) - -} - -// @todo template -func ModuleRbacResourceTpl() string { - return "%s/%s/%s" -} - // RbacResource returns string representation of RBAC resource for Namespace by calling NamespaceRbacResource fn // // RBAC resource is in the corteza::compose:namespace/... format @@ -180,7 +173,6 @@ func NamespaceRbacResource(id uint64) string { } -// @todo template func NamespaceRbacResourceTpl() string { return "%s/%s" } @@ -217,7 +209,6 @@ func PageRbacResource(namespaceID uint64, id uint64) string { } -// @todo template func PageRbacResourceTpl() string { return "%s/%s/%s" } @@ -260,7 +251,6 @@ func RecordRbacResource(namespaceID uint64, moduleID uint64, id uint64) string { } -// @todo template func RecordRbacResourceTpl() string { return "%s/%s/%s/%s" } @@ -284,7 +274,6 @@ func ComponentRbacResource() string { } -// @todo template func ComponentRbacResourceTpl() string { return "%s" } diff --git a/cue.mod/module.cue b/cue.mod/module.cue new file mode 100644 index 000000000..921718396 --- /dev/null +++ b/cue.mod/module.cue @@ -0,0 +1 @@ +module: "github.com/cortezaproject/corteza-server" diff --git a/cue.mods b/cue.mods new file mode 100644 index 000000000..e3e715219 --- /dev/null +++ b/cue.mods @@ -0,0 +1,3 @@ +module github.com/cortezaproject/corteza-server + +cue v0.4.0 diff --git a/cue.sums b/cue.sums new file mode 100644 index 000000000..e69de29bb diff --git a/def/README.md b/def/README.md deleted file mode 100644 index 1c63ca499..000000000 --- a/def/README.md +++ /dev/null @@ -1 +0,0 @@ -See `pkg/codegen-v3/README.md` diff --git a/def/automation.workflow.yaml b/def/automation.workflow.yaml deleted file mode 100644 index 83cb29328..000000000 --- a/def/automation.workflow.yaml +++ /dev/null @@ -1,23 +0,0 @@ -rbac: - operations: - read: - description: Read workflow - update: - description: Update workflow - delete: - description: Delete workflow - undelete: - description: Undelete workflow - execute: - description: Execute workflow - triggers.manage: - description: Manage workflow triggers - sessions.manage: - description: Manage workflow sessions - -# locale: -# resource: -# references: [ ID ] -# keys: -# - { path: name, field: "Meta.Name" } -# - { path: description, field: "Meta.Description" } diff --git a/def/automation.yaml b/def/automation.yaml deleted file mode 100644 index 94c8974b9..000000000 --- a/def/automation.yaml +++ /dev/null @@ -1,21 +0,0 @@ -rbac: - resource: { references: [] } - - operations: - grant: - description: Manage automation permissions - - workflow.create: - description: Create workflows - - triggers.search: - description: List, search or filter triggers - - sessions.search: - description: List, search or filter sessions - - workflows.search: - description: List, search or filter workflows - - resource-translations.manage: - description: List, search, create, or update resource translations diff --git a/def/compose.chart.yaml b/def/compose.chart.yaml deleted file mode 100644 index 19ec3882f..000000000 --- a/def/compose.chart.yaml +++ /dev/null @@ -1,17 +0,0 @@ -rbac: - resource: - references: [ namespace, ID ] - - operations: - read: - description: Read chart - update: - description: Update chart - delete: - description: Delete chart - -# locale: -# resource: -# references: [ namespace, ID ] -# keys: -# - name diff --git a/def/compose.module-field.yaml b/def/compose.module-field.yaml deleted file mode 100644 index b22fb9586..000000000 --- a/def/compose.module-field.yaml +++ /dev/null @@ -1,29 +0,0 @@ -rbac: - resource: - references: [ namespace, module, ID ] - - operations: - record.value.read: - canFnName: CanReadRecordValue - description: Read field value on records - record.value.update: - canFnName: CanUpdateRecordValue - description: Update field value on records - -locale: - resource: - references: [ namespace, module, ID ] - - skipSvc: true - keys: - - label - - { name: descriptionView, path: meta.description.view, custom: true, customHandler: descriptionView } - - { name: descriptionEdit, path: meta.description.edit, custom: true, customHandler: descriptionEdit } - - { name: hintView, path: meta.hint.view, custom: true, customHandler: hintView } - - { name: hintEdit, path: meta.hint.edit, custom: true, customHandler: hintEdit } - - { name: validatorError, path: "expression.validator.{{validatorID}}.error", custom: true, customHandler: validatorError } - - { name: optionsOptionTexts, - path: "meta.options.{{value}}.text", - custom: true, - customHandler: optionsOptionTexts - } diff --git a/def/compose.module.yaml b/def/compose.module.yaml deleted file mode 100644 index b3a8a7ffd..000000000 --- a/def/compose.module.yaml +++ /dev/null @@ -1,24 +0,0 @@ -rbac: - resource: - references: [ namespace, ID ] - - operations: - read: - description: Read module - update: - description: Update module - delete: - description: Delete module - - record.create: - description: Create record - records.search: - description: List, search or filter records - -locale: - resource: - references: [ namespace, ID ] - - extended: true - keys: - - name diff --git a/def/compose.namespace.yaml b/def/compose.namespace.yaml deleted file mode 100644 index fa0f355e8..000000000 --- a/def/compose.namespace.yaml +++ /dev/null @@ -1,31 +0,0 @@ -rbac: - operations: - read: - description: Read namespace - update: - description: Update namespace - delete: - description: Delete namespace - manage: - description: Access to namespace admin panel - - module.create: - description: Create module on namespace - modules.search: - description: List, search or filter module on namespace - - chart.create: - description: Create chart on namespace - charts.search: - description: List, search or filter chart on namespace - - page.create: - description: Create page on namespace - pages.search: - description: List, search or filter pages on namespace - -locale: - keys: - - name - - { path: subtitle, field: "Meta.Subtitle" } - - { path: description, field: "Meta.Description" } diff --git a/def/compose.page.yaml b/def/compose.page.yaml deleted file mode 100644 index 5affab111..000000000 --- a/def/compose.page.yaml +++ /dev/null @@ -1,23 +0,0 @@ -rbac: - resource: - references: [ namespace, ID ] - - operations: - read: - description: Read page - update: - description: Update page - delete: - description: Delete page - -locale: - resource: - references: [ namespace, ID ] - - extended: true - keys: - - title - - description - - { name: blockTitle, path: "pageBlock.{{blockID}}.title", custom: true } - - { name: blockDescription, path: "pageBlock.{{blockID}}.description", custom: true } - - { name: blockAutomationButtonlabel, path: "pageBlock.{{blockID}}.button.{{buttonID}}.label", custom: true } diff --git a/def/compose.record.yaml b/def/compose.record.yaml deleted file mode 100644 index a51137b0a..000000000 --- a/def/compose.record.yaml +++ /dev/null @@ -1,11 +0,0 @@ -rbac: - resource: - references: [ namespace, module, ID ] - - operations: - read: - description: Read record - update: - description: Update record - delete: - description: Delete record diff --git a/def/compose.yaml b/def/compose.yaml deleted file mode 100644 index 271a509f2..000000000 --- a/def/compose.yaml +++ /dev/null @@ -1,19 +0,0 @@ -rbac: - resource: { references: [] } - - operations: - grant: - description: Manage Compose permissions - - settings.read: - description: Read settings - settings.manage: - description: Manage settings - - namespace.create: - description: Create namespace - namespaces.search: - description: List, search or filter namespaces - - resource-translations.manage: - description: List, search, create, or update resource translations diff --git a/def/def-envoy.json b/def/def-envoy.json deleted file mode 100644 index ee59940d9..000000000 --- a/def/def-envoy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "boolean", - "enum": [ "false" ], - "title": "Disable envoy support", - "description": "Enabled by default" -} diff --git a/def/def-rbac.json b/def/def-rbac.json deleted file mode 100644 index a6b3ab977..000000000 --- a/def/def-rbac.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "resource": { - "additionalProperties": false, - "type": "object", - "description": "RBAC resource definition", - "properties": { - "prefix": { - "type": "string", - "description": "Resource name", - "pattern": "^[a-z]+:?[a-zA-Z]+(:[a-zA-Z]+)?$" - }, - "references": { - "type": "array", - "title": "Reference components", - "description": "When not explicitly defined it fallbacks to one item array with 'ID'", - "items": { - "oneOf": [ - { - "type": "object", - "properties": { - "field": { - "type": "string" - }, - "type": { - "type": "string" - } - } - }, - { - "type": "string" - } - ] - } - }, - "attributes": { - "anyOf": [ - { - "type": "boolean", - "enum": [ "true" ], - "title": "Custom implementation of resource attributes", - }, - { - "type": "array", - "title": "List of resource attributes", - "description": "Attributes are used for generating list of contextual roles" - } - ] - } - } - }, - "operations": { - "type": "object", - "additionalProperties": false, - "patternProperties": { - "^([a-z]+(-[a-z]+)*)(\\.[a-z]+)*$": { - "anyOf": [ - { "type": "boolean", "enum": [ "false" ] }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "canFnName": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - ] - } - } - } - } -} diff --git a/def/def.json b/def/def.json deleted file mode 100644 index 273fda9f0..000000000 --- a/def/def.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$id": "https://schemas.cortezaproject.org/def.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "imports": { - "type": "array", - "title": "List of go packages to be imported when generating files", - "description": "Attributes are used for generating list of contextual roles" - }, - - "component": { - "type": "string", - "title": "Component of the definition", - "description": "By default, component is taken from the filename of the definition: from start of the filename to the first dot" - }, - "resource": { - "type": "string", - "title": "Resource of the definition", - "description": "By default, resource is taken from the filename of the definition: from the first dot to the end of the filename without extension" - }, - "rbac": { "$ref": "def-rbac.json" }, - "envoy": { "$ref": "def-envoy.json" } - }, - "additionalProperties": false -} diff --git a/def/federation.exposed-module.yaml b/def/federation.exposed-module.yaml deleted file mode 100644 index 7dff05e90..000000000 --- a/def/federation.exposed-module.yaml +++ /dev/null @@ -1,9 +0,0 @@ -rbac: - resource: - references: [ node, ID ] - - operations: - manage: - description: Manage shared module - -envoy: false diff --git a/def/federation.node.yaml b/def/federation.node.yaml deleted file mode 100644 index bf46d9edc..000000000 --- a/def/federation.node.yaml +++ /dev/null @@ -1,8 +0,0 @@ -rbac: - operations: - manage: - description: Manage federation node - module.create: - description: Create shared module - -envoy: false diff --git a/def/federation.shared-module.yaml b/def/federation.shared-module.yaml deleted file mode 100644 index 9ecb0ad40..000000000 --- a/def/federation.shared-module.yaml +++ /dev/null @@ -1,9 +0,0 @@ -rbac: - resource: - references: [ node, ID ] - - operations: - map: - description: Map shared module - -envoy: false diff --git a/def/federation.yaml b/def/federation.yaml deleted file mode 100644 index 5064f5a5b..000000000 --- a/def/federation.yaml +++ /dev/null @@ -1,19 +0,0 @@ -rbac: - resource: { references: [] } - operations: - grant: - description: Manage federation permissions - pair: - description: Pair federation nodes - - settings.read: - description: Read settings - settings.manage: - description: Manage settings - - node.create: - description: Create new federation node - nodes.search: - description: List, search or filter federation nodes - -envoy: false diff --git a/def/system.apigw-route.yaml b/def/system.apigw-route.yaml deleted file mode 100644 index 873dd5973..000000000 --- a/def/system.apigw-route.yaml +++ /dev/null @@ -1,8 +0,0 @@ -rbac: - operations: - read: - description: Read API Gateway route - update: - description: Update API Gateway route - delete: - description: Delete API Gateway route diff --git a/def/system.application.yaml b/def/system.application.yaml deleted file mode 100644 index 9566786a5..000000000 --- a/def/system.application.yaml +++ /dev/null @@ -1,8 +0,0 @@ -rbac: - operations: - read: - description: Read application - update: - description: Update application - delete: - description: Delete application diff --git a/def/system.auth-client.yaml b/def/system.auth-client.yaml deleted file mode 100644 index b656cba51..000000000 --- a/def/system.auth-client.yaml +++ /dev/null @@ -1,10 +0,0 @@ -rbac: - operations: - read: - description: Read authorization client - update: - description: Update authorization client - delete: - description: Delete authorization client - authorize: - description: Authorize authorization client diff --git a/def/system.queue.yaml b/def/system.queue.yaml deleted file mode 100644 index fdd31bec3..000000000 --- a/def/system.queue.yaml +++ /dev/null @@ -1,12 +0,0 @@ -rbac: - operations: - read: - description: Read queue - update: - description: Update queue - delete: - description: Delete queue - queue.read: - description: Read from queue - queue.write: - description: Write to queue diff --git a/def/system.report.yaml b/def/system.report.yaml deleted file mode 100644 index af5accba6..000000000 --- a/def/system.report.yaml +++ /dev/null @@ -1,18 +0,0 @@ -rbac: - operations: - read: - description: Read report - update: - description: Update report - delete: - description: Delete report - run: - description: Run report - -# locale: -# extended: true -# keys: -# - { path: name, field: "Meta.Name" } -# - { path: description, field: "Meta.Description" } -# - { name: block title, path: "block.{{blockID}}.title", custom: true } -# - { name: block description, path: "block.{{blockID}}.description", custom: true } diff --git a/def/system.role.yaml b/def/system.role.yaml deleted file mode 100644 index f262d2f50..000000000 --- a/def/system.role.yaml +++ /dev/null @@ -1,10 +0,0 @@ -rbac: - operations: - read: - description: Read role - update: - description: Update role - delete: - description: Delete role - members.manage: - description: Manage members diff --git a/def/system.template.yaml b/def/system.template.yaml deleted file mode 100644 index 0e0f857f8..000000000 --- a/def/system.template.yaml +++ /dev/null @@ -1,10 +0,0 @@ -rbac: - operations: - read: - description: Read template - update: - description: Update template - delete: - description: Delete template - render: - description: Render template diff --git a/def/system.user.yaml b/def/system.user.yaml deleted file mode 100644 index 840fb1652..000000000 --- a/def/system.user.yaml +++ /dev/null @@ -1,18 +0,0 @@ -rbac: - operations: - read: - description: Read user - update: - description: Update user - delete: - description: Delete user - suspend: - description: Suspemd user - unsuspend: - description: Unsuspend user - email.unmask: - description: Unmask email - name.unmask: - description: Unmask name - impersonate: - description: Impersonate user diff --git a/def/system.yaml b/def/system.yaml deleted file mode 100644 index b757e5c36..000000000 --- a/def/system.yaml +++ /dev/null @@ -1,64 +0,0 @@ -rbac: - resource: { references: [] } - - operations: - grant: - description: Manage system permissions - - action-log.read: - description: Access to action log - - settings.read: - description: Read system settings - settings.manage: - description: Manage system settings - - auth-client.create: - description: Create auth clients - auth-clients.search: - description: List, search or filter auth clients - - role.create: - description: Create roles - roles.search: - description: List, search or filter roles - - user.create: - description: Create users - users.search: - description: List, search or filter users - - application.create: - description: Create applications - applications.search: - description: List, search or filter auth clients - application.flag.self: - description: Manage private flags for applications - application.flag.global: - description: Manage global flags for applications - - template.create: - description: Create template - templates.search: - description: List, search or filter templates - - report.create: - description: Create report - reports.search: - description: List, search or filter reports - - reminder.assign: - description: Assign reminders - - queue.create: - description: Create messagebus queues - queues.search: - description: List, search or filter messagebus queues - - apigw-route.create: - description: Create API gateway route - apigw-routes.search: - description: List search or filter API gateway routes - - resource-translations.manage: - description: List, search, create, or update resource translations diff --git a/federation/component.cue b/federation/component.cue new file mode 100644 index 000000000..c148788da --- /dev/null +++ b/federation/component.cue @@ -0,0 +1,24 @@ +package federation + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +component: schema.#component & { + handle: "federation" + + resources: { + "node": node + "exposed-module": exposedModule + "shared-module": sharedModule + } + + rbac: operations: { + "grant": description: "Manage federation permissions" + "pair": description: "Pair federation nodes" + "settings.read": description: "Read settings" + "settings.manage": description: "Manage settings" + "node.create": description: "Create new federation node" + "nodes.search": description: "List, search or filter federation nodes" + } +} diff --git a/federation/exposed-module.cue b/federation/exposed-module.cue new file mode 100644 index 000000000..07d0d3626 --- /dev/null +++ b/federation/exposed-module.cue @@ -0,0 +1,17 @@ +package federation + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +exposedModule: schema.#resource & { + parents: [ + {handle: "node"}, + ] + + rbac: { + operations: { + "manage": description: "Manage exposed module module" + } + } +} diff --git a/federation/node.cue b/federation/node.cue new file mode 100644 index 000000000..f82269b61 --- /dev/null +++ b/federation/node.cue @@ -0,0 +1,14 @@ +package federation + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +node: schema.#resource & { + rbac: { + operations: { + "manage": description: "Manage federation node" + "module.create": description: "Create shared module" + } + } +} diff --git a/federation/service/access_control.gen.go b/federation/service/access_control.gen.go index 761b11367..5b268c8a3 100644 --- a/federation/service/access_control.gen.go +++ b/federation/service/access_control.gen.go @@ -6,12 +6,6 @@ package service // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - federation.exposed-module.yaml -// - federation.node.yaml -// - federation.shared-module.yaml -// - federation.yaml - import ( "context" "fmt" @@ -60,11 +54,6 @@ func (svc accessControl) Effective(ctx context.Context, rr ...rbac.Resource) (ee func (svc accessControl) List() (out []map[string]string) { def := []map[string]string{ - { - "type": types.ExposedModuleResourceType, - "any": types.ExposedModuleRbacResource(0, 0), - "op": "manage", - }, { "type": types.NodeResourceType, "any": types.NodeRbacResource(0), @@ -75,6 +64,11 @@ func (svc accessControl) List() (out []map[string]string) { "any": types.NodeRbacResource(0), "op": "module.create", }, + { + "type": types.ExposedModuleResourceType, + "any": types.ExposedModuleRbacResource(0, 0), + "op": "manage", + }, { "type": types.SharedModuleResourceType, "any": types.SharedModuleRbacResource(0, 0), @@ -183,13 +177,6 @@ func (svc accessControl) CloneRulesByRoleID(ctx context.Context, fromRoleID uint return svc.rbac.CloneRulesByRoleID(ctx, fromRoleID, toRoleID...) } -// CanManageExposedModule checks if current user can manage shared module -// -// This function is auto-generated -func (svc accessControl) CanManageExposedModule(ctx context.Context, r *types.ExposedModule) bool { - return svc.can(ctx, "manage", r) -} - // CanManageNode checks if current user can manage federation node // // This function is auto-generated @@ -204,6 +191,13 @@ func (svc accessControl) CanCreateModuleOnNode(ctx context.Context, r *types.Nod return svc.can(ctx, "module.create", r) } +// CanManageExposedModule checks if current user can manage exposed module module +// +// This function is auto-generated +func (svc accessControl) CanManageExposedModule(ctx context.Context, r *types.ExposedModule) bool { + return svc.can(ctx, "manage", r) +} + // CanMapSharedModule checks if current user can map shared module // // This function is auto-generated @@ -215,42 +209,48 @@ func (svc accessControl) CanMapSharedModule(ctx context.Context, r *types.Shared // // This function is auto-generated func (svc accessControl) CanGrant(ctx context.Context) bool { - return svc.can(ctx, "grant", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "grant", r) } // CanPair checks if current user can pair federation nodes // // This function is auto-generated func (svc accessControl) CanPair(ctx context.Context) bool { - return svc.can(ctx, "pair", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "pair", r) } // CanReadSettings checks if current user can read settings // // This function is auto-generated func (svc accessControl) CanReadSettings(ctx context.Context) bool { - return svc.can(ctx, "settings.read", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "settings.read", r) } // CanManageSettings checks if current user can manage settings // // This function is auto-generated func (svc accessControl) CanManageSettings(ctx context.Context) bool { - return svc.can(ctx, "settings.manage", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "settings.manage", r) } // CanCreateNode checks if current user can create new federation node // // This function is auto-generated func (svc accessControl) CanCreateNode(ctx context.Context) bool { - return svc.can(ctx, "node.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "node.create", r) } // CanSearchNodes checks if current user can list, search or filter federation nodes // // This function is auto-generated func (svc accessControl) CanSearchNodes(ctx context.Context) bool { - return svc.can(ctx, "nodes.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "nodes.search", r) } // rbacResourceValidator validates known component's resource by routing it to the appropriate validator @@ -258,10 +258,10 @@ func (svc accessControl) CanSearchNodes(ctx context.Context) bool { // This function is auto-generated func rbacResourceValidator(r string, oo ...string) error { switch rbac.ResourceType(r) { - case types.ExposedModuleResourceType: - return rbacExposedModuleResourceValidator(r, oo...) case types.NodeResourceType: return rbacNodeResourceValidator(r, oo...) + case types.ExposedModuleResourceType: + return rbacExposedModuleResourceValidator(r, oo...) case types.SharedModuleResourceType: return rbacSharedModuleResourceValidator(r, oo...) case types.ComponentResourceType: @@ -276,15 +276,15 @@ func rbacResourceValidator(r string, oo ...string) error { // This function is auto-generated func rbacResourceOperations(r string) map[string]bool { switch rbac.ResourceType(r) { - case types.ExposedModuleResourceType: - return map[string]bool{ - "manage": true, - } case types.NodeResourceType: return map[string]bool{ "manage": true, "module.create": true, } + case types.ExposedModuleResourceType: + return map[string]bool{ + "manage": true, + } case types.SharedModuleResourceType: return map[string]bool{ "map": true, @@ -303,69 +303,24 @@ func rbacResourceOperations(r string) map[string]bool { return nil } -// rbacExposedModuleResourceValidator checks validity of rbac resource and operations -// -// Can be called without operations to check for validity of resource string only -// -// This function is auto-generated -func rbacExposedModuleResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for federation ExposedModule resource", o) - } - } - - if !strings.HasPrefix(r, types.ExposedModuleResourceType) { - // expecting resource to always include path - return fmt.Errorf("invalid resource type") - } - - const sep = "/" - var ( - pp = strings.Split(strings.Trim(r[len(types.ExposedModuleResourceType):], sep), sep) - prc = []string{ - "nodeID", - "ID", - } - ) - - if len(pp) != len(prc) { - return fmt.Errorf("invalid resource path structure") - } - - for i := 0; i < len(pp); i++ { - if pp[i] != "*" { - if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for ExposedModule", i) - } - - if _, err := cast.ToUint64E(pp[i]); err != nil { - return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) - } - } - } - return nil -} - -// rbacNodeResourceValidator checks validity of rbac resource and operations +// rbacNodeResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacNodeResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for federation Node resource", o) - } - } - if !strings.HasPrefix(r, types.NodeResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for node resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.NodeResourceType):], sep), sep) @@ -381,7 +336,7 @@ func rbacNodeResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Node", i) + return fmt.Errorf("invalid path wildcard level (%d) for node resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -392,29 +347,29 @@ func rbacNodeResourceValidator(r string, oo ...string) error { return nil } -// rbacSharedModuleResourceValidator checks validity of rbac resource and operations +// rbacExposedModuleResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated -func rbacSharedModuleResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for federation SharedModule resource", o) - } - } - - if !strings.HasPrefix(r, types.SharedModuleResourceType) { +func rbacExposedModuleResourceValidator(r string, oo ...string) error { + if !strings.HasPrefix(r, types.ExposedModuleResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for exposedModule resource", o) + } + } + const sep = "/" var ( - pp = strings.Split(strings.Trim(r[len(types.SharedModuleResourceType):], sep), sep) + pp = strings.Split(strings.Trim(r[len(types.ExposedModuleResourceType):], sep), sep) prc = []string{ - "nodeID", + "NodeID", "ID", } ) @@ -426,7 +381,7 @@ func rbacSharedModuleResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for SharedModule", i) + return fmt.Errorf("invalid path wildcard level (%d) for exposedModule resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -437,23 +392,68 @@ func rbacSharedModuleResourceValidator(r string, oo ...string) error { return nil } -// rbacComponentResourceValidator checks validity of rbac resource and operations +// rbacSharedModuleResourceValidator checks validity of RBAC resource and operations +// +// Can be called without operations to check for validity of resource string only +// +// This function is auto-generated +func rbacSharedModuleResourceValidator(r string, oo ...string) error { + if !strings.HasPrefix(r, types.SharedModuleResourceType) { + // expecting resource to always include path + return fmt.Errorf("invalid resource type") + } + + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for sharedModule resource", o) + } + } + + const sep = "/" + var ( + pp = strings.Split(strings.Trim(r[len(types.SharedModuleResourceType):], sep), sep) + prc = []string{ + "NodeID", + "ID", + } + ) + + if len(pp) != len(prc) { + return fmt.Errorf("invalid resource path structure") + } + + for i := 0; i < len(pp); i++ { + if pp[i] != "*" { + if i > 0 && pp[i-1] == "*" { + return fmt.Errorf("invalid path wildcard level (%d) for sharedModule resource", i) + } + + if _, err := cast.ToUint64E(pp[i]); err != nil { + return fmt.Errorf("invalid reference for %s: '%s'", prc[i], pp[i]) + } + } + } + return nil +} + +// rbacComponentResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacComponentResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for federation resource", o) - } - } - if !strings.HasPrefix(r, types.ComponentResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for federation component resource", o) + } + } + return nil } diff --git a/federation/shared-module.cue b/federation/shared-module.cue new file mode 100644 index 000000000..9509315b0 --- /dev/null +++ b/federation/shared-module.cue @@ -0,0 +1,17 @@ +package federation + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +sharedModule: schema.#resource & { + parents: [ + {handle: "node"}, + ] + + rbac: { + operations: { + "map": description: "Map shared module" + } + } +} diff --git a/federation/types/rbac.gen.go b/federation/types/rbac.gen.go index 7c59affe9..9e677c77c 100644 --- a/federation/types/rbac.gen.go +++ b/federation/types/rbac.gen.go @@ -6,12 +6,6 @@ package types // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - federation.exposed-module.yaml -// - federation.node.yaml -// - federation.shared-module.yaml -// - federation.yaml - import ( "fmt" "strconv" @@ -24,13 +18,48 @@ type ( Component struct{} ) +var ( + _ = fmt.Printf + _ = strconv.FormatUint +) + const ( - ExposedModuleResourceType = "corteza::federation:exposed-module" NodeResourceType = "corteza::federation:node" + ExposedModuleResourceType = "corteza::federation:exposed-module" SharedModuleResourceType = "corteza::federation:shared-module" ComponentResourceType = "corteza::federation" ) +// RbacResource returns string representation of RBAC resource for Node by calling NodeRbacResource fn +// +// RBAC resource is in the corteza::federation:node/... format +// +// This function is auto-generated +func (r Node) RbacResource() string { + return NodeRbacResource(r.ID) +} + +// NodeRbacResource returns string representation of RBAC resource for Node +// +// RBAC resource is in the corteza::federation:node/... format +// +// This function is auto-generated +func NodeRbacResource(id uint64) string { + cpts := []interface{}{NodeResourceType} + if id != 0 { + cpts = append(cpts, strconv.FormatUint(id, 10)) + } else { + cpts = append(cpts, "*") + } + + return fmt.Sprintf(NodeRbacResourceTpl(), cpts...) + +} + +func NodeRbacResourceTpl() string { + return "%s/%s" +} + // RbacResource returns string representation of RBAC resource for ExposedModule by calling ExposedModuleRbacResource fn // // RBAC resource is in the corteza::federation:exposed-module/... format @@ -63,42 +92,10 @@ func ExposedModuleRbacResource(nodeID uint64, id uint64) string { } -// @todo template func ExposedModuleRbacResourceTpl() string { return "%s/%s/%s" } -// RbacResource returns string representation of RBAC resource for Node by calling NodeRbacResource fn -// -// RBAC resource is in the corteza::federation:node/... format -// -// This function is auto-generated -func (r Node) RbacResource() string { - return NodeRbacResource(r.ID) -} - -// NodeRbacResource returns string representation of RBAC resource for Node -// -// RBAC resource is in the corteza::federation:node/... format -// -// This function is auto-generated -func NodeRbacResource(id uint64) string { - cpts := []interface{}{NodeResourceType} - if id != 0 { - cpts = append(cpts, strconv.FormatUint(id, 10)) - } else { - cpts = append(cpts, "*") - } - - return fmt.Sprintf(NodeRbacResourceTpl(), cpts...) - -} - -// @todo template -func NodeRbacResourceTpl() string { - return "%s/%s" -} - // RbacResource returns string representation of RBAC resource for SharedModule by calling SharedModuleRbacResource fn // // RBAC resource is in the corteza::federation:shared-module/... format @@ -131,7 +128,6 @@ func SharedModuleRbacResource(nodeID uint64, id uint64) string { } -// @todo template func SharedModuleRbacResourceTpl() string { return "%s/%s/%s" } @@ -155,7 +151,6 @@ func ComponentRbacResource() string { } -// @todo template func ComponentRbacResourceTpl() string { return "%s" } diff --git a/pkg/codegen-v3/README.md b/pkg/codegen-v3/README.md deleted file mode 100644 index a7d2c4b0c..000000000 --- a/pkg/codegen-v3/README.md +++ /dev/null @@ -1,12 +0,0 @@ -This is 3rd generation of corteza code generator -(1st was written in PHP, apologies 2nd is active and in use) - -Goal for the 3rd generation is: - - improved definition structure that addresses all elements that are used for code generation (types, store, rbac) - - unify most if not all definitions (stuff in YAML files) into what you can find in /def/... - - JSON schema validation for YAML files - -How to run it (temp): -``` -go run pkg/codegen-v3/*.go def -``` diff --git a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-rbac_references.go.tpl b/pkg/codegen-v3/assets/templates/gocode/envoy/resource-rbac_references.go.tpl deleted file mode 100644 index 37a4051ef..000000000 --- a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-rbac_references.go.tpl +++ /dev/null @@ -1,35 +0,0 @@ -package {{ .Package }} - -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} - -import ( -{{- range .Imports }} - {{ . }} -{{- end }} -) - -{{- range .Def }} -{{- if gt (len .RBAC.Resource.References) 0 }} -// {{ export .Component .Resource }}RbacReferences generates RBAC references -// -// Resources with "envoy: false" are skipped -// -// This function is auto-generated -func {{ export .Component .Resource }}RbacReferences({{- range .RBAC.Resource.References }}{{ unexport .Resource }} string, {{- end }}) (res *Ref, pp []*Ref, err error) { - {{- range .RBAC.Resource.References }} - {{- if eq .Field "ID" }} - if {{ unexport .Resource }} != "*" { - res = &Ref{ResourceType: types.{{ export .Resource }}ResourceType, Identifiers: MakeIdentifiers({{ unexport .Resource }})} - } - {{- else }} - if {{ unexport .Resource }} != "*" { - pp = append(pp, &Ref{ResourceType: types.{{ export .Resource }}ResourceType, Identifiers: MakeIdentifiers({{ unexport .Resource }})}) - } - {{- end }} - {{- end }} - - return -} -{{- end }} -{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation_references.go.tpl b/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation_references.go.tpl deleted file mode 100644 index 065516b5b..000000000 --- a/pkg/codegen-v3/assets/templates/gocode/envoy/resource-resource_translation_references.go.tpl +++ /dev/null @@ -1,33 +0,0 @@ -package {{ .Package }} - -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} - -import ( -{{- range .Imports }} - {{ . }} -{{- end }} -) - -{{- range .Def }} -{{- if .Locale }} -{{- if gt (len .Locale.Resource.References) 0 }} -// {{ export .Component .Resource }}ResourceTranslationReferences generates Locale references -// -// Resources with "envoy: false" are skipped -// -// This function is auto-generated -func {{ export .Component .Resource }}ResourceTranslationReferences({{- range .Locale.Resource.References }}{{ unexport .Resource }} string, {{- end }}) (res *Ref, pp []*Ref, err error) { - {{- range .Locale.Resource.References }} - {{- if eq .Field "ID" }} - res = &Ref{ResourceType: types.{{ export .Resource }}ResourceType, Identifiers: MakeIdentifiers({{ unexport .Resource }})} - {{- else }} - pp = append(pp, &Ref{ResourceType: types.{{ export .Resource }}ResourceType, Identifiers: MakeIdentifiers({{ unexport .Resource }})}) - {{- end }} - {{- end }} - - return -} -{{- end }} -{{- end }} -{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/header-definitions.tpl b/pkg/codegen-v3/assets/templates/gocode/header-definitions.tpl deleted file mode 100644 index 6ac55a5b7..000000000 --- a/pkg/codegen-v3/assets/templates/gocode/header-definitions.tpl +++ /dev/null @@ -1,4 +0,0 @@ -// Definitions file that controls how this file is generated: -{{- range .Def }} -// - {{ .Source }} -{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/locale/types.go.tpl b/pkg/codegen-v3/assets/templates/gocode/locale/types.go.tpl deleted file mode 100644 index 05be93e59..000000000 --- a/pkg/codegen-v3/assets/templates/gocode/locale/types.go.tpl +++ /dev/null @@ -1,135 +0,0 @@ -package {{ .Package }} - -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} - -import ( - "fmt" - "strconv" - "github.com/cortezaproject/corteza-server/pkg/locale" -) - -type ( - LocaleKey struct { - Name string - Resource string - Path string - CustomHandler string - } -) - -// Types and stuff -const ( -{{- range .Def }} - {{ .Resource }}ResourceTranslationType = "{{ .Locale.ResourceType }}" -{{- end }} -) - -var ( -{{- range .Def }} -{{- $Resource := .Resource }} - {{- range .Locale.Keys}} - LocaleKey{{ $Resource }}{{coalesce (export .Name) (export .Path) }} = LocaleKey{ - Name: "{{.Name}}", - Resource: {{ $Resource }}ResourceTranslationType, - Path: "{{.Path }}",{{ if .CustomHandler }} - CustomHandler: "{{ .CustomHandler }}", - {{- end }} - } - {{- end}} -{{- end }} -) - -{{- range .Def }} -{{ $Resource := .Resource }} -{{ $GoType := printf "types.%s" .Resource }} - - -// ResourceTranslation returns string representation of Locale resource for {{ .Resource }} by calling {{ .Resource }}ResourceTranslation fn -// -// Locale resource is in "{{ .Locale.ResourceType }}/..." format -// -// This function is auto-generated -func (r {{ .Resource }}) ResourceTranslation() string { - return {{ .Resource }}ResourceTranslation({{ if .Locale.Resource }}{{ range .Locale.Resource.References }}r.{{ export .Field }},{{ end }}{{ end }}) -} - -// {{ .Resource }}ResourceTranslation returns string representation of Locale resource for {{ .Resource }} -// -// Locale resource is in the {{ .Locale.ResourceType }}/{{- if .Locale.Resource.References }}...{{ end }} format -// -// This function is auto-generated -func {{ .Resource }}ResourceTranslation({{ if .Locale.Resource }}{{ range .Locale.Resource.References }}{{ unexport .Field }} uint64,{{ end }}{{ end }}) string { - {{- if .Locale.Resource.References }} - cpts := []interface{{"{}"}}{{"{"}}{{ .Resource }}ResourceTranslationType{{"}"}} - cpts = append(cpts, {{range .Locale.Resource.References -}} - strconv.FormatUint({{ unexport .Field }}, 10), - {{- end }}) - - return fmt.Sprintf({{ .Resource }}ResourceTranslationTpl(), cpts...) - {{- end }} -} - -// @todo template -func {{ .Resource }}ResourceTranslationTpl() string { - {{- if .Locale.Resource.References }} - return "%s - {{- range .Locale.Resource.References }}/%s{{- end }}" - - {{- else }} - return "%s" - {{- end }} -} - -func (r *{{ .Resource }}) DecodeTranslations(tt locale.ResourceTranslationIndex) { - var aux *locale.ResourceTranslation - -{{- range .Locale.Keys}} -{{- if not .Custom }} - if aux = tt.FindByKey(LocaleKey{{ $Resource }}{{coalesce (export .Name) (export .Path) }}.Path); aux != nil { - r.{{ .Field }} = aux.Msg - } -{{- end}} -{{- end}} - -{{- range .Locale.Keys}} -{{- if and .Custom .CustomHandler }} - r.decodeTranslations{{export .CustomHandler }}(tt) -{{- end}} -{{- end}} - -{{- if .Locale.Extended }} - - r.decodeTranslations(tt) -{{- end }} -} - -func (r *{{ .Resource }}) EncodeTranslations() (out locale.ResourceTranslationSet) { - out = locale.ResourceTranslationSet{} -{{- range .Locale.Keys}} -{{- if not .Custom }} - if r.{{ .Field }} != "" { - out = append(out, &locale.ResourceTranslation{ - Resource: r.ResourceTranslation(), - Key: LocaleKey{{ $Resource }}{{coalesce (export .Name) (export .Path) }}.Path, - Msg: locale.SanitizeMessage(r.{{ .Field }}), - }) - } - -{{- end}} -{{- end}} - -{{range .Locale.Keys}} -{{- if and .Custom .CustomHandler }} - out = append(out, r.encodeTranslations{{export .CustomHandler}}()...) -{{- end}} -{{- end}} - -{{- if .Locale.Extended }} - out = append(out, r.encodeTranslations()...) -{{- end }} - - return out -} - -{{- end }} diff --git a/pkg/codegen-v3/assets/templates/gocode/rbac/types.go.tpl b/pkg/codegen-v3/assets/templates/gocode/rbac/types.go.tpl deleted file mode 100644 index 5442cd6af..000000000 --- a/pkg/codegen-v3/assets/templates/gocode/rbac/types.go.tpl +++ /dev/null @@ -1,99 +0,0 @@ -package {{ .Package }} - -{{ template "header-gentext.tpl" }} -{{ template "header-definitions.tpl" . }} - -import ( - "fmt" - "strconv" -) - -type ( - // Component struct serves as a virtual resource type for the {{ .Component }} component - // - // This struct is auto-generated - Component struct {} -) - -const ( -{{- range .Def }} - {{ coalesce .Resource "Component" }}ResourceType = "{{ .RBAC.ResourceType }}" -{{- end }} -) - - -{{- range .Def }} -{{ $Resource := .Resource }} -{{ $GoType := printf "types.%s" .Resource }} - - -// RbacResource returns string representation of RBAC resource for {{ .Resource }} by calling {{ .Resource }}RbacResource fn -// -// RBAC resource is in the {{ .RBAC.ResourceType }}/... format -// -// This function is auto-generated -func (r {{ .Resource }}) RbacResource() string { - return {{ .Resource }}RbacResource({{ if .RBAC.Resource }}{{ range .RBAC.Resource.References }}r.{{ export .Field }},{{ end }}{{ end }}) -} - -// {{ .Resource }}RbacResource returns string representation of RBAC resource for {{ .Resource }} -// -// RBAC resource is in the {{ .RBAC.ResourceType }}/{{- if .RBAC.Resource.References }}...{{ end }} format -// -// This function is auto-generated -func {{ .Resource }}RbacResource({{ if .RBAC.Resource }}{{ range .RBAC.Resource.References }}{{ unexport .Field }} uint64,{{ end }}{{ end }}) string { - {{- if .RBAC.Resource.References }} - cpts := []interface{{"{}"}}{{"{"}}{{ .Resource }}ResourceType{{"}"}} - {{- range .RBAC.Resource.References }} - if {{ unexport .Field }} != 0 { - cpts = append(cpts, strconv.FormatUint({{ unexport .Field }}, 10)) - } else { - cpts = append(cpts, "*") - } - - {{ end }} - return fmt.Sprintf({{ .Resource }}RbacResourceTpl(), cpts...) - {{- else }} - return {{ .Resource }}ResourceType + "/" - {{- end }} - -} - -// @todo template -func {{ .Resource }}RbacResourceTpl() string { - {{- if .RBAC.Resource.References }} - return "%s - {{- range .RBAC.Resource.References }}/%s{{- end }}" - - {{- else }} - return "%s" - {{- end }} -} - -{{ if .RBAC.Resource.Attributes }} - // RbacAttributes returns resource attributes used for generating list of contextual roles - // - // This function is auto-generated - func (r {{ .Resource }}) RbacAttributes() map[string]interface{} { - return {{ unexport .Resource }}RbacAttributes(r) - } - - {{ if .RBAC.Resource.Attributes.Fields }} - // {{ .Resource }}RbacResource returns string representation of RBAC resource for {{ .Resource }} - // - // RBAC resource is in the {{ .RBAC.ResourceType }}/... format - // - // This function is auto-generated - func {{ unexport .Resource }}RbacAttributes(r {{ .Resource }}) map[string]interface{} { - return map[string]interface{}{ - {{- range .RBAC.Resource.Attributes.Fields }} - {{ printf "%q" . }}: r.{{ export . }}, - {{- end }} - } - } - {{- end }} -{{- end }} - - -{{- end }} - diff --git a/pkg/codegen-v3/internal/def/doc.go b/pkg/codegen-v3/internal/def/doc.go deleted file mode 100644 index b47b1058e..000000000 --- a/pkg/codegen-v3/internal/def/doc.go +++ /dev/null @@ -1,91 +0,0 @@ -package def - -import ( - "fmt" - "strings" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" - "github.com/cortezaproject/corteza-server/pkg/y7s" - "gopkg.in/yaml.v3" -) - -type ( - Document struct { - Skip bool `yaml:"(skip)"` - Imports []string - Component string - IsComponentResource bool `yaml:"-"` - Resource string - Source string - RBAC *rbac - Locale *locale - Envoy bool `yaml:"envoy"` - } -) - -func (set *rbacOperations) UnmarshalYAML(n *yaml.Node) error { - return y7s.Each(n, func(k *yaml.Node, v *yaml.Node) (err error) { - def := rbacOperation{} - if k != nil { - def.Operation = k.Value - } - - *set = append(*set, &def) - return v.Decode(&def) - }) -} - -// Preproc preprocesses the document and sets defaults -func (doc *Document) Proc(filename string) error { - doc.Source = filename - - // filename parts - fp := strings.Split(filename, ".") - // trim extension - fp = fp[:len(fp)-1] - if len(fp) > 0 && doc.Component == "" { - // set component from the 1st part - // component is system, compose, ... - doc.Component = fp[0] - } - - if len(fp) > 1 && doc.Resource == "" { - // if there are more parts, set resource - // resource is user, module, record, workflow, ... - doc.Resource = fp[1] - } - - if strings.ToLower(doc.Resource) == "component" { - return fmt.Errorf("can not use 'component' as a resource name, this is done automatically") - } else if doc.Resource == "" { - doc.Resource = "component" - doc.IsComponentResource = true - } - - doc.Imports = normalizeImport(doc.Imports...) - - if err := doc.RBAC.proc(doc.Component, doc.Resource); err != nil { - return err - } - - if err := doc.Locale.proc(doc.Component, doc.Resource); err != nil { - return err - } - - doc.Resource = tpl.Export(doc.Resource) - - return nil -} - -func normalizeImport(ii ...string) []string { - for i := range ii { - if strings.Contains(ii[i], " ") { - p := strings.SplitN(ii[i], " ", 2) - ii[i] = fmt.Sprintf(`%s "%s"`, p[0], strings.Trim(p[1], `"`)) - } else { - ii[i] = fmt.Sprintf(`"%s"`, strings.Trim(ii[i], `"'`+"`")) - } - } - - return ii -} diff --git a/pkg/codegen-v3/internal/def/locale.go b/pkg/codegen-v3/internal/def/locale.go deleted file mode 100644 index f173158c2..000000000 --- a/pkg/codegen-v3/internal/def/locale.go +++ /dev/null @@ -1,127 +0,0 @@ -package def - -import ( - "fmt" - "strings" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" - "github.com/cortezaproject/corteza-server/pkg/y7s" - "gopkg.in/yaml.v3" -) - -type ( - locale struct { - ResourceType string `yaml:"resourceType"` - Resource *resourceTranslation - Extended bool - SkipSvc bool `yaml:"skipSvc"` - Keys localeKeys - } - - resourceTranslation struct { - References []*resourceTranslationRef - } - - resourceTranslationRef struct { - Field string - ResourceType string - Resource string - Component string - - custom bool - } - - localeKeys []*localeKey - - localeKey struct { - Name string - Path string - Custom bool - CustomHandler string `yaml:"customHandler"` - Description string - Field string - } -) - -func (r *locale) proc(component, resource string) error { - if r == nil { - return nil - } - - if r.ResourceType == "" { - if strings.ToLower(resource) == "component" { - r.ResourceType = component - } else { - r.ResourceType = fmt.Sprintf("%s:%s", component, resource) - } - } - - if r.Resource == nil { - r.Resource = &resourceTranslation{References: []*resourceTranslationRef{{Field: "ID"}}} - } - - // check types of each referenced component - // and self-references (field==ID) with own resource type - for _, rc := range r.Resource.References { - if !rc.custom { - if rc.Field == "ID" { - rc.ResourceType = r.ResourceType - rc.Component = component - rc.Resource = resource - } else { - rc.ResourceType = fmt.Sprintf("%s:%s", component, rc.Field) - rc.Component = component - rc.Resource = rc.Field - rc.Field = rc.Field + "ID" - } - } - } - - // assure missing key field paths - for _, k := range r.Keys { - k.Custom = k.Custom || k.CustomHandler != "" - - // Guess the key path - if k.Field == "" { - k.Field = tpl.Export(k.Path) - } - - // Guess the name - if k.Name == "" { - k.Name = k.Path - } - } - - return nil -} - -func (op *localeKey) UnmarshalYAML(n *yaml.Node) error { - type auxType localeKey - - switch { - case y7s.IsKind(n, yaml.ScalarNode): - return y7s.DecodeScalar(n, "locale key", &op.Path) - - case y7s.IsKind(n, yaml.MappingNode): - var aux = (*auxType)(op) - return n.Decode(aux) - } - - return y7s.NodeErr(n, "unsupported formatting") -} - -func (op *resourceTranslationRef) UnmarshalYAML(n *yaml.Node) error { - if y7s.IsKind(n, yaml.ScalarNode) { - op.Field = n.Value - if n.Value != "ID" { - op.ResourceType = n.Value - } - - return nil - } - - type auxType resourceTranslationRef - var aux = (*auxType)(op) - aux.custom = true - return n.Decode(aux) -} diff --git a/pkg/codegen-v3/internal/def/rbac.go b/pkg/codegen-v3/internal/def/rbac.go deleted file mode 100644 index 245ecfa7f..000000000 --- a/pkg/codegen-v3/internal/def/rbac.go +++ /dev/null @@ -1,165 +0,0 @@ -package def - -import ( - "fmt" - "strings" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" - "github.com/cortezaproject/corteza-server/pkg/y7s" - "gopkg.in/yaml.v3" -) - -type ( - rbac struct { - // fully qualified resource name - ResourceType string `yaml:"resourceType"` - Resource *rbacResource - Operations rbacOperations - } - - rbacResource struct { - References []*rbacResourceRef - Attributes *rbacAttributes - } - - rbacResourceRef struct { - Field string - ResourceType string - Resource string - Component string - - custom bool - } - - rbacOperations []*rbacOperation - - rbacOperation struct { - Operation string - CanFnName string `yaml:"canFnName"` - Description string - } - - rbacAttributes struct { - Fields []string `yaml:"-"` - } -) - -func (r *rbac) proc(component, resource string) error { - const ( - defaultNS = "corteza" - nsDelimiter = "::" - ) - - if r.ResourceType == "" { - if strings.ToLower(resource) == "component" { - r.ResourceType = component - } else { - r.ResourceType = fmt.Sprintf("%s:%s", component, resource) - } - - r.ResourceType = defaultNS + nsDelimiter + r.ResourceType - } - - if !strings.Contains(r.ResourceType, nsDelimiter) { - return fmt.Errorf("no namespace prefix found (e.g.: 'corteza::') in resource type") - } - - for _, op := range r.Operations { - // Generate all check name - if op.CanFnName == "" { - op.CanFnName = RbacOperationCanFnName(resource, op.Operation) - } - } - - if r.Resource == nil { - r.Resource = &rbacResource{References: []*rbacResourceRef{{Field: "ID"}}} - } - - // check types of each referenced component - // and prefix non-custom components with corteza:: - // and self-references (field==ID) with own resource type - for _, rc := range r.Resource.References { - if !rc.custom { - if rc.Field == "ID" { - rc.ResourceType = r.ResourceType - rc.Component = component - rc.Resource = resource - } else { - rc.ResourceType = defaultNS + nsDelimiter + fmt.Sprintf("%s:%s", component, rc.Field) - rc.Component = component - rc.Resource = rc.Field - rc.Field = rc.Field + "ID" - } - } - } - - return nil -} - -func (op *rbacOperation) UnmarshalYAML(n *yaml.Node) error { - if y7s.IsKind(n, yaml.ScalarNode) { - // @todo handle disabled operations - // the idea is that when service operations are defined we implicitly define - // RBAC operations. Here, we'll be able to remove implicitly defined operation - return nil - } - - type auxType rbacOperation - var aux = (*auxType)(op) - return n.Decode(aux) -} - -func (op *rbacResourceRef) UnmarshalYAML(n *yaml.Node) error { - if y7s.IsKind(n, yaml.ScalarNode) { - op.Field = n.Value - if n.Value != "ID" { - op.ResourceType = n.Value - // @todo expand resource & component - } - - return nil - } - - type auxType rbacResourceRef - var aux = (*auxType)(op) - aux.custom = true - return n.Decode(aux) -} - -func (a *rbacAttributes) UnmarshalYAML(n *yaml.Node) error { - if y7s.IsKind(n, yaml.ScalarNode) { - return nil - } - - // if not scalar, assume we will get list of fields - a.Fields = make([]string, 0) - return n.Decode(&a.Fields) -} - -func RbacOperationCanFnName(res, op string) string { - // when check function name is not explicitly defined we try - // to use resource and operation name and generate easy-to-read name - // - // + => Can - // + => CanOn - - if strings.ToLower(res) == "component" { - res = "" - } - - if strings.Contains(op, ".") { - parts := strings.Split(op, ".") - l := len(parts) - - parts = append(parts[l-1:], parts[:l-1]...) - - if res != "" { - // Only append "on" if there is resource - parts = append(parts, "on") - } - - op = tpl.Export(parts...) - } - - return tpl.Export("can", op, res) -} diff --git a/pkg/codegen-v3/internal/gen/envoy.go b/pkg/codegen-v3/internal/gen/envoy.go deleted file mode 100644 index 48fa357e5..000000000 --- a/pkg/codegen-v3/internal/gen/envoy.go +++ /dev/null @@ -1,168 +0,0 @@ -package gen - -import ( - "fmt" - "text/template" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/def" - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" - "github.com/cortezaproject/corteza-server/pkg/slice" -) - -func Envoy(t *template.Template, dd []*def.Document) error { - return List{ - "resource rbac parse": envoyResourceRbacUnmarshal, - "resource rbac references": envoyResourceRbacReferences, - - "resource translation": envoyResourceTranslation, - "resource translation parse": envoyResourceTranslationUnmarshal, - "resource translation references": envoyResourceTranslationReferences, - }.Generate(t, dd) -} - -// EnvoyResourceRbacUnmarshal envoy rbac unmarshal -// /service/rbac.gen.go -// -// Contains all RBAC related definitions -func envoyResourceRbacUnmarshal(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "envoy/resource-rbac_rules_parse.go.tpl" - outputPathTpl = "pkg/envoy/resource/rbac_rules_parse.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Envoy }) - - // build list of component type imports - ctImports := make([]string, 0) - for _, d := range dd { - imp := d.Component + "Types " + cImport(d.Component, "types") - if !slice.HasString(ctImports, imp) { - ctImports = append(ctImports, imp) - } - } - - w := tpl.Wrap{ - Package: "resource", - Def: dd, - Imports: append(collectImports(dd...), ctImports...), - } - - err = tpl.GoTemplate(outputPathTpl, t.Lookup(templateName), w) - if err != nil { - return - } - - return -} - -// EnvoyResourceRbacReferences generates one rbac definition file per component -// /service/rbac.gen.go -// -// Contains all RBAC related definitions -func envoyResourceRbacReferences(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "envoy/resource-rbac_references.go.tpl" - outputPathTpl = "pkg/envoy/resource/rbac_references_%s.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Envoy }) - - for component, perComponent := range partByComponent(dd) { - - w := tpl.Wrap{ - Package: "resource", - Component: component, - Def: perComponent, - Imports: append(collectImports(perComponent...), cImport(component, "types")), - } - - err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w) - if err != nil { - return - } - } - - return -} - -func envoyResourceTranslation(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "envoy/resource-resource_translation.go.tpl" - outputPathTpl = "pkg/envoy/resource/resource_translation.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Envoy && d.Locale != nil }) - - // build list of component type imports - ctImports := make([]string, 0) - - w := tpl.Wrap{ - Package: "resource", - Def: dd, - Imports: append(collectImports(dd...), ctImports...), - } - - err = tpl.GoTemplate(outputPathTpl, t.Lookup(templateName), w) - if err != nil { - return - } - - return -} - -func envoyResourceTranslationUnmarshal(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "envoy/resource-resource_translation_parse.go.tpl" - outputPathTpl = "pkg/envoy/resource/resource_translation_parse.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Envoy && d.Locale != nil }) - - // build list of component type imports - ctImports := make([]string, 0) - for _, d := range dd { - imp := d.Component + "Types " + cImport(d.Component, "types") - if !slice.HasString(ctImports, imp) { - ctImports = append(ctImports, imp) - } - } - - w := tpl.Wrap{ - Package: "resource", - Def: dd, - Imports: append(collectImports(dd...), ctImports...), - } - - err = tpl.GoTemplate(outputPathTpl, t.Lookup(templateName), w) - if err != nil { - return - } - - return -} - -func envoyResourceTranslationReferences(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "envoy/resource-resource_translation_references.go.tpl" - outputPathTpl = "pkg/envoy/resource/resource_translation_references_%s.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Envoy && d.Locale != nil }) - - for component, perComponent := range partByComponent(dd) { - - w := tpl.Wrap{ - Package: "resource", - Component: component, - Def: perComponent, - Imports: append(collectImports(perComponent...), cImport(component, "types")), - } - - err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w) - if err != nil { - return - } - } - - return -} diff --git a/pkg/codegen-v3/internal/gen/gen.go b/pkg/codegen-v3/internal/gen/gen.go deleted file mode 100644 index 977b88f26..000000000 --- a/pkg/codegen-v3/internal/gen/gen.go +++ /dev/null @@ -1,67 +0,0 @@ -package gen - -import ( - "fmt" - "text/template" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/def" -) - -type ( - List map[string]func(*template.Template, []*def.Document) error -) - -func (gg List) Generate(tpls *template.Template, dd []*def.Document) (err error) { - for l, g := range gg { - if err = g(tpls, dd); err != nil { - return fmt.Errorf("codegen for %s failed: %w", l, err) - } - } - - return -} - -func filter(dd []*def.Document, check func(*def.Document) bool) []*def.Document { - aux := make([]*def.Document, 0, len(dd)) - for _, d := range dd { - if !check(d) { - continue - } - - aux = append(aux, d) - } - return aux -} - -func partByComponent(dd []*def.Document) map[string][]*def.Document { - var ( - parted = make(map[string][]*def.Document) - ) - - for _, d := range dd { - parted[d.Component] = append(parted[d.Component], d) - } - - return parted -} - -func collectImports(dd ...*def.Document) []string { - mm := make(map[string]bool) - for _, d := range dd { - for _, i := range d.Imports { - mm[i] = true - } - } - - ii := make([]string, 0, len(mm)) - for i := range mm { - ii = append(ii, i) - } - - return ii -} - -// component import -func cImport(c, s string) string { - return fmt.Sprintf(`"github.com/cortezaproject/corteza-server/%s/%s"`, c, s) -} diff --git a/pkg/codegen-v3/internal/gen/locale.go b/pkg/codegen-v3/internal/gen/locale.go deleted file mode 100644 index 2f52ba3fd..000000000 --- a/pkg/codegen-v3/internal/gen/locale.go +++ /dev/null @@ -1,70 +0,0 @@ -package gen - -import ( - "fmt" - "text/template" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/def" - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" -) - -func Locale(t *template.Template, dd []*def.Document) error { - return List{ - "types": localeTypes, - "services": localeServices, - }.Generate(t, dd) -} - -func localeTypes(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "locale/types.go.tpl" - outputPathTpl = "%s/types/locale.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Locale != nil }) - - for component, perComponent := range partByComponent(dd) { - w := tpl.Wrap{ - Package: "types", - Component: component, - Def: perComponent, - } - - err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w) - if err != nil { - return - } - } - - return -} - -func localeServices(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "locale/service.go.tpl" - outputPathTpl = "%s/service/locale.gen.go" - ) - - dd = filter(dd, func(d *def.Document) bool { return d.Locale != nil && !d.Locale.SkipSvc }) - - for component, perComponent := range partByComponent(dd) { - w := tpl.Wrap{ - Package: "service", - Component: component, - Def: perComponent, - Imports: append(collectImports(perComponent...), cImport(component, "types")), - } - - err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w) - if err != nil { - return - } - } - - for _, d := range dd { - if d.Locale != nil { - } - } - - return -} diff --git a/pkg/codegen-v3/internal/gen/rbac.go b/pkg/codegen-v3/internal/gen/rbac.go deleted file mode 100644 index f99a978e2..000000000 --- a/pkg/codegen-v3/internal/gen/rbac.go +++ /dev/null @@ -1,69 +0,0 @@ -package gen - -import ( - "fmt" - "text/template" - - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/def" - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" -) - -func RBAC(t *template.Template, dd []*def.Document) error { - return List{ - "type": rbacTypes, - "service access control": rbacAccessControlService, - }.Generate(t, dd) -} - -// RbacTypes generates rbac definitions (one per component) -// /service/rbac.gen.go -// -// Contains all RBAC related definitions -func rbacTypes(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "rbac/types.go.tpl" - outputPathTpl = "%s/types/rbac.gen.go" - ) - - for component, perComponent := range partByComponent(dd) { - w := tpl.Wrap{ - Package: "types", - Component: component, - Def: perComponent, - } - - err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w) - if err != nil { - return - } - } - - return -} - -// RbacAccessControlService generates access control functions (one file per component) -// /service/rbac.gen.go -// -// Contains all RBAC related definitions -func rbacAccessControlService(t *template.Template, dd []*def.Document) (err error) { - const ( - templateName = "rbac/access_control.go.tpl" - outputPathTpl = "%s/service/access_control.gen.go" - ) - - for component, perComponent := range partByComponent(dd) { - w := tpl.Wrap{ - Package: "service", - Component: component, - Def: perComponent, - Imports: append(collectImports(perComponent...), cImport(component, "types")), - } - - err = tpl.GoTemplate(fmt.Sprintf(outputPathTpl, component), t.Lookup(templateName), w) - if err != nil { - return - } - } - - return -} diff --git a/pkg/codegen-v3/loader.go b/pkg/codegen-v3/loader.go deleted file mode 100644 index 1dc8f46ed..000000000 --- a/pkg/codegen-v3/loader.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" - "path/filepath" - - "github.com/cortezaproject/corteza-server/pkg/cli" - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/def" - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/gen" - "github.com/cortezaproject/corteza-server/pkg/codegen-v3/internal/tpl" - "github.com/davecgh/go-spew/spew" - "gopkg.in/yaml.v3" -) - -var _ = spew.Dump - -func main() { - dd, err := loadDefinitions(os.Args[1]) - cli.HandleError(err) - - tpls, err := tpl.LoadTemplates(tpl.BaseTemplate(), "./pkg/codegen-v3/assets/templates/gocode") - if err != nil { - cli.HandleError(fmt.Errorf("could not load templates: %w", err)) - } - - cli.HandleError(gen.List{ - "RBAC": gen.RBAC, - "Envoy": gen.Envoy, - "Locale": gen.Locale, - }.Generate(tpls, dd)) -} - -func loadDefinition(r io.Reader) (*def.Document, error) { - doc := &def.Document{ - Envoy: true, - } - - return doc, yaml.NewDecoder(r).Decode(doc) -} - -func loadDefinitions(path string) (dd []*def.Document, err error) { - var ( - fh *os.File - doc *def.Document - files []string - ) - - files, err = filepath.Glob(path + "/*.yaml") - if err != nil { - return nil, fmt.Errorf("could not load ddefinitions form path '%s': %w", path, err) - } - - for _, file := range files { - fh, err = os.Open(file) - if err != nil { - return nil, fmt.Errorf("could not load definiton file '%s': %w", file, err) - } - - doc, err = loadDefinition(fh) - if err != nil { - return nil, fmt.Errorf("could not load definiton from '%s': %w", file, err) - } - - if doc.Skip { - continue - } - - if err = doc.Proc(filepath.Base(file)); err != nil { - return nil, fmt.Errorf("failed to preprocess definitions from '%s': %w", file, err) - } - - dd = append(dd, doc) - } - - return -} diff --git a/pkg/codegen/README.md b/pkg/codegen/README.md index 61f880733..4bc784076 100644 --- a/pkg/codegen/README.md +++ b/pkg/codegen/README.md @@ -1,5 +1,7 @@ # Code generation package +See [latest codegen version](../../codegen/README.md). + It consumes YAMLs from all known locations and provides them to templates diff --git a/pkg/envoy/resource/rbac_references_automation.gen.go b/pkg/envoy/resource/rbac_references_automation.gen.go index f3abc0b12..231c3fbe2 100644 --- a/pkg/envoy/resource/rbac_references_automation.gen.go +++ b/pkg/envoy/resource/rbac_references_automation.gen.go @@ -6,10 +6,6 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - automation.workflow.yaml -// - automation.yaml - import ( "github.com/cortezaproject/corteza-server/automation/types" ) diff --git a/pkg/envoy/resource/rbac_references_compose.gen.go b/pkg/envoy/resource/rbac_references_compose.gen.go index 9b72bfccc..34c706985 100644 --- a/pkg/envoy/resource/rbac_references_compose.gen.go +++ b/pkg/envoy/resource/rbac_references_compose.gen.go @@ -6,15 +6,6 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.chart.yaml -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml -// - compose.record.yaml -// - compose.yaml - import ( "github.com/cortezaproject/corteza-server/compose/types" ) @@ -24,9 +15,9 @@ import ( // Resources with "envoy: false" are skipped // // This function is auto-generated -func ComposeChartRbacReferences(namespace string, chart string) (res *Ref, pp []*Ref, err error) { - if namespace != "*" { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) +func ComposeChartRbacReferences(namespaceID string, chart string) (res *Ref, pp []*Ref, err error) { + if namespaceID != "*" { + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) } if chart != "*" { res = &Ref{ResourceType: types.ChartResourceType, Identifiers: MakeIdentifiers(chart)} @@ -35,33 +26,14 @@ func ComposeChartRbacReferences(namespace string, chart string) (res *Ref, pp [] return } -// ComposeModuleFieldRbacReferences generates RBAC references -// -// Resources with "envoy: false" are skipped -// -// This function is auto-generated -func ComposeModuleFieldRbacReferences(namespace string, module string, moduleField string) (res *Ref, pp []*Ref, err error) { - if namespace != "*" { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) - } - if module != "*" { - pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(module)}) - } - if moduleField != "*" { - res = &Ref{ResourceType: types.ModuleFieldResourceType, Identifiers: MakeIdentifiers(moduleField)} - } - - return -} - // ComposeModuleRbacReferences generates RBAC references // // Resources with "envoy: false" are skipped // // This function is auto-generated -func ComposeModuleRbacReferences(namespace string, module string) (res *Ref, pp []*Ref, err error) { - if namespace != "*" { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) +func ComposeModuleRbacReferences(namespaceID string, module string) (res *Ref, pp []*Ref, err error) { + if namespaceID != "*" { + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) } if module != "*" { res = &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(module)} @@ -70,6 +42,25 @@ func ComposeModuleRbacReferences(namespace string, module string) (res *Ref, pp return } +// ComposeModuleFieldRbacReferences generates RBAC references +// +// Resources with "envoy: false" are skipped +// +// This function is auto-generated +func ComposeModuleFieldRbacReferences(namespaceID string, moduleID string, moduleField string) (res *Ref, pp []*Ref, err error) { + if namespaceID != "*" { + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) + } + if moduleID != "*" { + pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(moduleID)}) + } + if moduleField != "*" { + res = &Ref{ResourceType: types.ModuleFieldResourceType, Identifiers: MakeIdentifiers(moduleField)} + } + + return +} + // ComposeNamespaceRbacReferences generates RBAC references // // Resources with "envoy: false" are skipped @@ -88,9 +79,9 @@ func ComposeNamespaceRbacReferences(namespace string) (res *Ref, pp []*Ref, err // Resources with "envoy: false" are skipped // // This function is auto-generated -func ComposePageRbacReferences(namespace string, page string) (res *Ref, pp []*Ref, err error) { - if namespace != "*" { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) +func ComposePageRbacReferences(namespaceID string, page string) (res *Ref, pp []*Ref, err error) { + if namespaceID != "*" { + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) } if page != "*" { res = &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(page)} @@ -104,12 +95,12 @@ func ComposePageRbacReferences(namespace string, page string) (res *Ref, pp []*R // Resources with "envoy: false" are skipped // // This function is auto-generated -func ComposeRecordRbacReferences(namespace string, module string, record string) (res *Ref, pp []*Ref, err error) { - if namespace != "*" { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) +func ComposeRecordRbacReferences(namespaceID string, moduleID string, record string) (res *Ref, pp []*Ref, err error) { + if namespaceID != "*" { + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) } - if module != "*" { - pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(module)}) + if moduleID != "*" { + pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(moduleID)}) } if record != "*" { res = &Ref{ResourceType: types.RecordResourceType, Identifiers: MakeIdentifiers(record)} diff --git a/pkg/envoy/resource/rbac_references_federation.gen.go b/pkg/envoy/resource/rbac_references_federation.gen.go new file mode 100644 index 000000000..5900fd1c3 --- /dev/null +++ b/pkg/envoy/resource/rbac_references_federation.gen.go @@ -0,0 +1,56 @@ +package resource + +// This file is auto-generated. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// + +import ( + "github.com/cortezaproject/corteza-server/federation/types" +) + +// FederationNodeRbacReferences generates RBAC references +// +// Resources with "envoy: false" are skipped +// +// This function is auto-generated +func FederationNodeRbacReferences(node string) (res *Ref, pp []*Ref, err error) { + if node != "*" { + res = &Ref{ResourceType: types.NodeResourceType, Identifiers: MakeIdentifiers(node)} + } + + return +} + +// FederationExposedModuleRbacReferences generates RBAC references +// +// Resources with "envoy: false" are skipped +// +// This function is auto-generated +func FederationExposedModuleRbacReferences(nodeID string, exposedModule string) (res *Ref, pp []*Ref, err error) { + if nodeID != "*" { + pp = append(pp, &Ref{ResourceType: types.NodeResourceType, Identifiers: MakeIdentifiers(nodeID)}) + } + if exposedModule != "*" { + res = &Ref{ResourceType: types.ExposedModuleResourceType, Identifiers: MakeIdentifiers(exposedModule)} + } + + return +} + +// FederationSharedModuleRbacReferences generates RBAC references +// +// Resources with "envoy: false" are skipped +// +// This function is auto-generated +func FederationSharedModuleRbacReferences(nodeID string, sharedModule string) (res *Ref, pp []*Ref, err error) { + if nodeID != "*" { + pp = append(pp, &Ref{ResourceType: types.NodeResourceType, Identifiers: MakeIdentifiers(nodeID)}) + } + if sharedModule != "*" { + res = &Ref{ResourceType: types.SharedModuleResourceType, Identifiers: MakeIdentifiers(sharedModule)} + } + + return +} diff --git a/pkg/envoy/resource/rbac_references_system.gen.go b/pkg/envoy/resource/rbac_references_system.gen.go index 4e953ee6d..4fb241d91 100644 --- a/pkg/envoy/resource/rbac_references_system.gen.go +++ b/pkg/envoy/resource/rbac_references_system.gen.go @@ -6,17 +6,6 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - system.apigw-route.yaml -// - system.application.yaml -// - system.auth-client.yaml -// - system.queue.yaml -// - system.report.yaml -// - system.role.yaml -// - system.template.yaml -// - system.user.yaml -// - system.yaml - import ( "github.com/cortezaproject/corteza-server/system/types" ) diff --git a/pkg/envoy/resource/rbac_rules_parse.gen.go b/pkg/envoy/resource/rbac_rules_parse.gen.go index 98423de17..58d30aae9 100644 --- a/pkg/envoy/resource/rbac_rules_parse.gen.go +++ b/pkg/envoy/resource/rbac_rules_parse.gen.go @@ -6,30 +6,11 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - automation.workflow.yaml -// - automation.yaml -// - compose.chart.yaml -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml -// - compose.record.yaml -// - compose.yaml -// - system.apigw-route.yaml -// - system.application.yaml -// - system.auth-client.yaml -// - system.queue.yaml -// - system.report.yaml -// - system.role.yaml -// - system.template.yaml -// - system.user.yaml -// - system.yaml - import ( "fmt" automationTypes "github.com/cortezaproject/corteza-server/automation/types" composeTypes "github.com/cortezaproject/corteza-server/compose/types" + federationTypes "github.com/cortezaproject/corteza-server/federation/types" systemTypes "github.com/cortezaproject/corteza-server/system/types" "strings" ) @@ -66,190 +47,176 @@ func ParseRule(res string) (string, *Ref, []*Ref, error) { // make the resource provide the slice of parent resources we should nest under switch resourceType { - case automationTypes.WorkflowResourceType: - if len(path) != 1 { - return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) - } - ref, pp, err := AutomationWorkflowRbacReferences( - // workflow - path[0], - ) - return automationTypes.WorkflowResourceType, ref, pp, err - - case automationTypes.ComponentResourceType: - if len(path) != 0 { - return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path)) - } - - // Component resource, no path - return automationTypes.ComponentResourceType, nil, nil, nil - case composeTypes.ChartResourceType: - if len(path) != 2 { - return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposeChartRbacReferences( - // namespace - path[0], - - // chart - path[1], - ) - return composeTypes.ChartResourceType, ref, pp, err - - case composeTypes.ModuleFieldResourceType: - if len(path) != 3 { - return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposeModuleFieldRbacReferences( - // namespace - path[0], - - // module - path[1], - - // moduleField - path[2], - ) - return composeTypes.ModuleFieldResourceType, ref, pp, err - - case composeTypes.ModuleResourceType: - if len(path) != 2 { - return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposeModuleRbacReferences( - // namespace - path[0], - - // module - path[1], - ) - return composeTypes.ModuleResourceType, ref, pp, err - - case composeTypes.NamespaceResourceType: - if len(path) != 1 { - return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposeNamespaceRbacReferences( - // namespace - path[0], - ) - return composeTypes.NamespaceResourceType, ref, pp, err - - case composeTypes.PageResourceType: - if len(path) != 2 { - return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposePageRbacReferences( - // namespace - path[0], - - // page - path[1], - ) - return composeTypes.PageResourceType, ref, pp, err - - case composeTypes.RecordResourceType: - if len(path) != 3 { - return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposeRecordRbacReferences( - // namespace - path[0], - - // module - path[1], - - // record - path[2], - ) - return composeTypes.RecordResourceType, ref, pp, err - - case composeTypes.ComponentResourceType: - if len(path) != 0 { - return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path)) - } - - // Component resource, no path - return composeTypes.ComponentResourceType, nil, nil, nil case systemTypes.ApigwRouteResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemApigwRouteRbacReferences( - // apigwRoute path[0], ) - return systemTypes.ApigwRouteResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.ApplicationResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemApplicationRbacReferences( - // application path[0], ) - return systemTypes.ApplicationResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.AuthClientResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemAuthClientRbacReferences( - // authClient path[0], ) - return systemTypes.AuthClientResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.QueueResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemQueueRbacReferences( - // queue path[0], ) - return systemTypes.QueueResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.ReportResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemReportRbacReferences( - // report path[0], ) - return systemTypes.ReportResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.RoleResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemRoleRbacReferences( - // role path[0], ) - return systemTypes.RoleResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.TemplateResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemTemplateRbacReferences( - // template path[0], ) - return systemTypes.TemplateResourceType, ref, pp, err + return resourceType, ref, pp, err case systemTypes.UserResourceType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := SystemUserRbacReferences( - // user path[0], ) - return systemTypes.UserResourceType, ref, pp, err + return resourceType, ref, pp, err + + case composeTypes.ChartResourceType: + if len(path) != 2 { + return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposeChartRbacReferences( + path[0], + path[1], + ) + return resourceType, ref, pp, err + + case composeTypes.ModuleResourceType: + if len(path) != 2 { + return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposeModuleRbacReferences( + path[0], + path[1], + ) + return resourceType, ref, pp, err + + case composeTypes.ModuleFieldResourceType: + if len(path) != 3 { + return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposeModuleFieldRbacReferences( + path[0], + path[1], + path[2], + ) + return resourceType, ref, pp, err + + case composeTypes.NamespaceResourceType: + if len(path) != 1 { + return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposeNamespaceRbacReferences( + path[0], + ) + return resourceType, ref, pp, err + + case composeTypes.PageResourceType: + if len(path) != 2 { + return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposePageRbacReferences( + path[0], + path[1], + ) + return resourceType, ref, pp, err + + case composeTypes.RecordResourceType: + if len(path) != 3 { + return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposeRecordRbacReferences( + path[0], + path[1], + path[2], + ) + return resourceType, ref, pp, err + + case automationTypes.WorkflowResourceType: + if len(path) != 1 { + return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) + } + ref, pp, err := AutomationWorkflowRbacReferences( + path[0], + ) + return resourceType, ref, pp, err + + case federationTypes.NodeResourceType: + if len(path) != 1 { + return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) + } + ref, pp, err := FederationNodeRbacReferences( + path[0], + ) + return resourceType, ref, pp, err + + case federationTypes.ExposedModuleResourceType: + if len(path) != 2 { + return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) + } + ref, pp, err := FederationExposedModuleRbacReferences( + path[0], + path[1], + ) + return resourceType, ref, pp, err + + case federationTypes.SharedModuleResourceType: + if len(path) != 2 { + return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) + } + ref, pp, err := FederationSharedModuleRbacReferences( + path[0], + path[1], + ) + return resourceType, ref, pp, err case systemTypes.ComponentResourceType: if len(path) != 0 { @@ -257,7 +224,28 @@ func ParseRule(res string) (string, *Ref, []*Ref, error) { } // Component resource, no path - return systemTypes.ComponentResourceType, nil, nil, nil + return resourceType, nil, nil, nil + case composeTypes.ComponentResourceType: + if len(path) != 0 { + return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path)) + } + + // Component resource, no path + return resourceType, nil, nil, nil + case automationTypes.ComponentResourceType: + if len(path) != 0 { + return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path)) + } + + // Component resource, no path + return resourceType, nil, nil, nil + case federationTypes.ComponentResourceType: + if len(path) != 0 { + return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path)) + } + + // Component resource, no path + return resourceType, nil, nil, nil } // return unhandled resource as-is diff --git a/pkg/envoy/resource/resource_translation.gen.go b/pkg/envoy/resource/resource_translation.gen.go index b206aae87..0613308f2 100644 --- a/pkg/envoy/resource/resource_translation.gen.go +++ b/pkg/envoy/resource/resource_translation.gen.go @@ -6,16 +6,20 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml - import ( systemTypes "github.com/cortezaproject/corteza-server/system/types" ) +func (r *ComposeModule) EncodeTranslations() ([]*ResourceTranslation, error) { + out := make([]*ResourceTranslation, 0, 10) + + rr := r.Res.EncodeTranslations() + rr.SetLanguage(defaultLanguage) + res, ref, pp := r.ResourceTranslationParts() + out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...)) + + return out, nil +} func (r *ComposeModuleField) EncodeTranslations() ([]*ResourceTranslation, error) { out := make([]*ResourceTranslation, 0, 10) @@ -26,20 +30,6 @@ func (r *ComposeModuleField) EncodeTranslations() ([]*ResourceTranslation, error return out, nil } - -func (r *ComposeModule) EncodeTranslations() ([]*ResourceTranslation, error) { - out := make([]*ResourceTranslation, 0, 10) - - rr := r.Res.EncodeTranslations() - rr.SetLanguage(defaultLanguage) - res, ref, pp := r.ResourceTranslationParts() - out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...)) - - tmp, err := r.encodeTranslations() - return append(out, tmp...), err - -} - func (r *ComposeNamespace) EncodeTranslations() ([]*ResourceTranslation, error) { out := make([]*ResourceTranslation, 0, 10) @@ -50,7 +40,6 @@ func (r *ComposeNamespace) EncodeTranslations() ([]*ResourceTranslation, error) return out, nil } - func (r *ComposePage) EncodeTranslations() ([]*ResourceTranslation, error) { out := make([]*ResourceTranslation, 0, 10) diff --git a/pkg/envoy/resource/resource_translation_parse.gen.go b/pkg/envoy/resource/resource_translation_parse.gen.go index 522786c4a..12bd1f611 100644 --- a/pkg/envoy/resource/resource_translation_parse.gen.go +++ b/pkg/envoy/resource/resource_translation_parse.gen.go @@ -6,19 +6,13 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml - import ( "fmt" composeTypes "github.com/cortezaproject/corteza-server/compose/types" "strings" ) -// Parse generates resource setting logic for each resource +// ParseResourceTranslation generates resource setting logic for each resource // // Resources with "envoy: false" are skipped // @@ -53,41 +47,32 @@ func ParseResourceTranslation(res string) (string, *Ref, []*Ref, error) { // make the resource provide the slice of parent resources we should nest under switch resourceType { - case composeTypes.ModuleFieldResourceTranslationType: - if len(path) != 3 { - return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path)) - } - ref, pp, err := ComposeModuleFieldResourceTranslationReferences( - // namespace - path[0], - - // module - path[1], - - // moduleField - path[2], - ) - return composeTypes.ModuleFieldResourceTranslationType, ref, pp, err - case composeTypes.ModuleResourceTranslationType: if len(path) != 2 { return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) } ref, pp, err := ComposeModuleResourceTranslationReferences( - // namespace path[0], - - // module path[1], ) return composeTypes.ModuleResourceTranslationType, ref, pp, err + case composeTypes.ModuleFieldResourceTranslationType: + if len(path) != 3 { + return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path)) + } + ref, pp, err := ComposeModuleFieldResourceTranslationReferences( + path[0], + path[1], + path[2], + ) + return composeTypes.ModuleFieldResourceTranslationType, ref, pp, err + case composeTypes.NamespaceResourceTranslationType: if len(path) != 1 { return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path)) } ref, pp, err := ComposeNamespaceResourceTranslationReferences( - // namespace path[0], ) return composeTypes.NamespaceResourceTranslationType, ref, pp, err @@ -97,10 +82,7 @@ func ParseResourceTranslation(res string) (string, *Ref, []*Ref, error) { return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path)) } ref, pp, err := ComposePageResourceTranslationReferences( - // namespace path[0], - - // page path[1], ) return composeTypes.PageResourceTranslationType, ref, pp, err diff --git a/pkg/envoy/resource/resource_translation_references_compose.gen.go b/pkg/envoy/resource/resource_translation_references_compose.gen.go index d5361607e..1df89c42e 100644 --- a/pkg/envoy/resource/resource_translation_references_compose.gen.go +++ b/pkg/envoy/resource/resource_translation_references_compose.gen.go @@ -6,60 +6,46 @@ package resource // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - compose.module-field.yaml -// - compose.module.yaml -// - compose.namespace.yaml -// - compose.page.yaml - import ( "github.com/cortezaproject/corteza-server/compose/types" ) -// ComposeModuleFieldResourceTranslationReferences generates Locale references -// -// Resources with "envoy: false" are skipped +// ComposeModuleResourceTranslationReferences generates Locale references // // This function is auto-generated -func ComposeModuleFieldResourceTranslationReferences(namespace string, module string, moduleField string) (res *Ref, pp []*Ref, err error) { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) - pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(module)}) - res = &Ref{ResourceType: types.ModuleFieldResourceType, Identifiers: MakeIdentifiers(moduleField)} +func ComposeModuleResourceTranslationReferences(namespaceID string, self string) (res *Ref, pp []*Ref, err error) { + res = &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(self)} + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) return } -// ComposeModuleResourceTranslationReferences generates Locale references -// -// Resources with "envoy: false" are skipped +// ComposeModuleFieldResourceTranslationReferences generates Locale references // // This function is auto-generated -func ComposeModuleResourceTranslationReferences(namespace string, module string) (res *Ref, pp []*Ref, err error) { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) - res = &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(module)} +func ComposeModuleFieldResourceTranslationReferences(namespaceID string, moduleID string, self string) (res *Ref, pp []*Ref, err error) { + res = &Ref{ResourceType: types.ModuleFieldResourceType, Identifiers: MakeIdentifiers(self)} + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) + pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(moduleID)}) return } // ComposeNamespaceResourceTranslationReferences generates Locale references // -// Resources with "envoy: false" are skipped -// // This function is auto-generated -func ComposeNamespaceResourceTranslationReferences(namespace string) (res *Ref, pp []*Ref, err error) { - res = &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)} +func ComposeNamespaceResourceTranslationReferences(self string) (res *Ref, pp []*Ref, err error) { + res = &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(self)} return } // ComposePageResourceTranslationReferences generates Locale references // -// Resources with "envoy: false" are skipped -// // This function is auto-generated -func ComposePageResourceTranslationReferences(namespace string, page string) (res *Ref, pp []*Ref, err error) { - pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}) - res = &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(page)} +func ComposePageResourceTranslationReferences(namespaceID string, self string) (res *Ref, pp []*Ref, err error) { + res = &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(self)} + pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)}) return } diff --git a/pkg/envoy/resource/resource_translation_references_system.gen.go b/pkg/envoy/resource/resource_translation_references_system.gen.go deleted file mode 100644 index c781bd5ed..000000000 --- a/pkg/envoy/resource/resource_translation_references_system.gen.go +++ /dev/null @@ -1,25 +0,0 @@ -package resource - -// This file is auto-generated. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// - -// Definitions file that controls how this file is generated: -// - system.report.yaml - -import ( - "github.com/cortezaproject/corteza-server/system/types" -) - -// SystemReportResourceTranslationReferences generates Locale references -// -// Resources with "envoy: false" are skipped -// -// This function is auto-generated -func SystemReportResourceTranslationReferences(report string) (res *Ref, pp []*Ref, err error) { - res = &Ref{ResourceType: types.ReportResourceType, Identifiers: MakeIdentifiers(report)} - - return -} diff --git a/pkg/envoy/store/encoder.go b/pkg/envoy/store/encoder.go index 344c41249..299f31a88 100644 --- a/pkg/envoy/store/encoder.go +++ b/pkg/envoy/store/encoder.go @@ -49,8 +49,8 @@ type ( composeRecordAccessController } composeRecordValueAccessController interface { - CanReadRecordValue(context.Context, *types.ModuleField) bool - CanUpdateRecordValue(context.Context, *types.ModuleField) bool + CanReadRecordValueOnModuleField(context.Context, *types.ModuleField) bool + CanUpdateRecordValueOnModuleField(context.Context, *types.ModuleField) bool } composeRecordAccessController interface { diff --git a/system/apigw-route.cue b/system/apigw-route.cue new file mode 100644 index 000000000..14f14edb4 --- /dev/null +++ b/system/apigw-route.cue @@ -0,0 +1,15 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +apigwRoute: schema.#resource & { + rbac: { + operations: { + read: description: "Read API Gateway route" + update: description: "Update API Gateway route" + delete: description: "Delete API Gateway route" + } + } +} diff --git a/system/application.cue b/system/application.cue new file mode 100644 index 000000000..8c5196cc5 --- /dev/null +++ b/system/application.cue @@ -0,0 +1,18 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +application: schema.#resource & { + rbac: { + operations: { + read: + description: "Read application" + update: + description: "Update application" + delete: + description: "Delete application" + } + } +} diff --git a/system/auth-client.cue b/system/auth-client.cue new file mode 100644 index 000000000..eaa2853d0 --- /dev/null +++ b/system/auth-client.cue @@ -0,0 +1,16 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +authClient: schema.#resource & { + rbac: { + operations: { + read: description: "Read authorization client" + update: description: "Update authorization client" + delete: description: "Delete authorization client" + authorize: description: "Authorize authorization client" + } + } +} diff --git a/system/component.cue b/system/component.cue new file mode 100644 index 000000000..ac462a7d8 --- /dev/null +++ b/system/component.cue @@ -0,0 +1,56 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +component: schema.#component & { + handle: "system" + + resources: { + "apigw-route": apigwRoute + "application": application + "auth-client": authClient + "queue": queue + "report": report + "role": role + "template": template + "user": user + } + + rbac: operations: { + "action-log.read": description: "Access to action log" + + "settings.read": description: "Read system settings" + "settings.manage": description: "Manage system settings" + "auth-client.create": description: "Create auth clients" + "auth-clients.search": description: "List, search or filter auth clients" + + "role.create": description: "Create roles" + "roles.search": description: "List, search or filter roles" + + "user.create": description: "Create users" + "users.search": description: "List, search or filter users" + + "application.create": description: "Create applications" + "applications.search": description: "List, search or filter auth clients" + "application.flag.self": description: "Manage private flags for applications" + "application.flag.global": description: "Manage global flags for applications" + + "template.create": description: "Create template" + "templates.search": description: "List, search or filter templates" + + "report.create": description: "Create report" + "reports.search": description: "List, search or filter reports" + + "reminder.assign": description: " Assign reminders" + + "queue.create": description: "Create messagebus queues" + "queues.search": description: "List, search or filter messagebus queues" + + "apigw-route.create": description: "Create API gateway route" + "apigw-routes.search": description: "List search or filter API gateway routes" + + "resource-translations.manage": description: "List, search, create, or update resource translations" + } +} diff --git a/system/queue.cue b/system/queue.cue new file mode 100644 index 000000000..f85aaf2c1 --- /dev/null +++ b/system/queue.cue @@ -0,0 +1,18 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +queue: schema.#resource & { + rbac: { + operations: { + "render": description: "Render template" + "read": description: "Read queue" + "update": description: "Update queue" + "delete": description: "Delete queue" + "queue.read": description: "Read from queue" + "queue.write": description: "Write to queue" + } + } +} diff --git a/system/report.cue b/system/report.cue new file mode 100644 index 000000000..53fbbad8f --- /dev/null +++ b/system/report.cue @@ -0,0 +1,23 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +report: schema.#resource & { + rbac: { + operations: { + read: description: "Read report" + update: description: "Update report" + delete: description: "Delete report" + run: description: "Run report" + } + } + // locale: + // extended: true + // keys: + // - { path: name, field: "Meta.Name" } + // - { path: description, field: "Meta.Description" } + // - { name: block title, path: "block.{{blockID}}.title", custom: true } + // - { name: block description, path: "block.{{blockID}}.description", custom: true } +} diff --git a/system/role.cue b/system/role.cue new file mode 100644 index 000000000..f2d8de63c --- /dev/null +++ b/system/role.cue @@ -0,0 +1,14 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +role: schema.#resource & { + rbac: { + operations: { + read: description: "Read role" + update: description: "Update role" + delete: description: "Delete role" + "members.manage": description: "Manage members" + }}} diff --git a/system/service/access_control.gen.go b/system/service/access_control.gen.go index 01b4925e0..6978d8e3f 100644 --- a/system/service/access_control.gen.go +++ b/system/service/access_control.gen.go @@ -6,17 +6,6 @@ package service // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - system.apigw-route.yaml -// - system.application.yaml -// - system.auth-client.yaml -// - system.queue.yaml -// - system.report.yaml -// - system.role.yaml -// - system.template.yaml -// - system.user.yaml -// - system.yaml - import ( "context" "fmt" @@ -115,6 +104,11 @@ func (svc accessControl) List() (out []map[string]string) { "any": types.AuthClientRbacResource(0), "op": "authorize", }, + { + "type": types.QueueResourceType, + "any": types.QueueRbacResource(0), + "op": "render", + }, { "type": types.QueueResourceType, "any": types.QueueRbacResource(0), @@ -503,6 +497,13 @@ func (svc accessControl) CanAuthorizeAuthClient(ctx context.Context, r *types.Au return svc.can(ctx, "authorize", r) } +// CanRenderQueue checks if current user can render template +// +// This function is auto-generated +func (svc accessControl) CanRenderQueue(ctx context.Context, r *types.Queue) bool { + return svc.can(ctx, "render", r) +} + // CanReadQueue checks if current user can read queue // // This function is auto-generated @@ -643,7 +644,7 @@ func (svc accessControl) CanDeleteUser(ctx context.Context, r *types.User) bool return svc.can(ctx, "delete", r) } -// CanSuspendUser checks if current user can suspemd user +// CanSuspendUser checks if current user can suspend user // // This function is auto-generated func (svc accessControl) CanSuspendUser(ctx context.Context, r *types.User) bool { @@ -682,168 +683,192 @@ func (svc accessControl) CanImpersonateUser(ctx context.Context, r *types.User) // // This function is auto-generated func (svc accessControl) CanGrant(ctx context.Context) bool { - return svc.can(ctx, "grant", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "grant", r) } // CanReadActionLog checks if current user can access to action log // // This function is auto-generated func (svc accessControl) CanReadActionLog(ctx context.Context) bool { - return svc.can(ctx, "action-log.read", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "action-log.read", r) } // CanReadSettings checks if current user can read system settings // // This function is auto-generated func (svc accessControl) CanReadSettings(ctx context.Context) bool { - return svc.can(ctx, "settings.read", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "settings.read", r) } // CanManageSettings checks if current user can manage system settings // // This function is auto-generated func (svc accessControl) CanManageSettings(ctx context.Context) bool { - return svc.can(ctx, "settings.manage", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "settings.manage", r) } // CanCreateAuthClient checks if current user can create auth clients // // This function is auto-generated func (svc accessControl) CanCreateAuthClient(ctx context.Context) bool { - return svc.can(ctx, "auth-client.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "auth-client.create", r) } // CanSearchAuthClients checks if current user can list, search or filter auth clients // // This function is auto-generated func (svc accessControl) CanSearchAuthClients(ctx context.Context) bool { - return svc.can(ctx, "auth-clients.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "auth-clients.search", r) } // CanCreateRole checks if current user can create roles // // This function is auto-generated func (svc accessControl) CanCreateRole(ctx context.Context) bool { - return svc.can(ctx, "role.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "role.create", r) } // CanSearchRoles checks if current user can list, search or filter roles // // This function is auto-generated func (svc accessControl) CanSearchRoles(ctx context.Context) bool { - return svc.can(ctx, "roles.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "roles.search", r) } // CanCreateUser checks if current user can create users // // This function is auto-generated func (svc accessControl) CanCreateUser(ctx context.Context) bool { - return svc.can(ctx, "user.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "user.create", r) } // CanSearchUsers checks if current user can list, search or filter users // // This function is auto-generated func (svc accessControl) CanSearchUsers(ctx context.Context) bool { - return svc.can(ctx, "users.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "users.search", r) } // CanCreateApplication checks if current user can create applications // // This function is auto-generated func (svc accessControl) CanCreateApplication(ctx context.Context) bool { - return svc.can(ctx, "application.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "application.create", r) } // CanSearchApplications checks if current user can list, search or filter auth clients // // This function is auto-generated func (svc accessControl) CanSearchApplications(ctx context.Context) bool { - return svc.can(ctx, "applications.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "applications.search", r) } // CanSelfApplicationFlag checks if current user can manage private flags for applications // // This function is auto-generated func (svc accessControl) CanSelfApplicationFlag(ctx context.Context) bool { - return svc.can(ctx, "application.flag.self", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "application.flag.self", r) } // CanGlobalApplicationFlag checks if current user can manage global flags for applications // // This function is auto-generated func (svc accessControl) CanGlobalApplicationFlag(ctx context.Context) bool { - return svc.can(ctx, "application.flag.global", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "application.flag.global", r) } // CanCreateTemplate checks if current user can create template // // This function is auto-generated func (svc accessControl) CanCreateTemplate(ctx context.Context) bool { - return svc.can(ctx, "template.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "template.create", r) } // CanSearchTemplates checks if current user can list, search or filter templates // // This function is auto-generated func (svc accessControl) CanSearchTemplates(ctx context.Context) bool { - return svc.can(ctx, "templates.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "templates.search", r) } // CanCreateReport checks if current user can create report // // This function is auto-generated func (svc accessControl) CanCreateReport(ctx context.Context) bool { - return svc.can(ctx, "report.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "report.create", r) } // CanSearchReports checks if current user can list, search or filter reports // // This function is auto-generated func (svc accessControl) CanSearchReports(ctx context.Context) bool { - return svc.can(ctx, "reports.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "reports.search", r) } -// CanAssignReminder checks if current user can assign reminders +// CanAssignReminder checks if current user can assign reminders // // This function is auto-generated func (svc accessControl) CanAssignReminder(ctx context.Context) bool { - return svc.can(ctx, "reminder.assign", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "reminder.assign", r) } // CanCreateQueue checks if current user can create messagebus queues // // This function is auto-generated func (svc accessControl) CanCreateQueue(ctx context.Context) bool { - return svc.can(ctx, "queue.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "queue.create", r) } // CanSearchQueues checks if current user can list, search or filter messagebus queues // // This function is auto-generated func (svc accessControl) CanSearchQueues(ctx context.Context) bool { - return svc.can(ctx, "queues.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "queues.search", r) } // CanCreateApigwRoute checks if current user can create api gateway route // // This function is auto-generated func (svc accessControl) CanCreateApigwRoute(ctx context.Context) bool { - return svc.can(ctx, "apigw-route.create", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "apigw-route.create", r) } // CanSearchApigwRoutes checks if current user can list search or filter api gateway routes // // This function is auto-generated func (svc accessControl) CanSearchApigwRoutes(ctx context.Context) bool { - return svc.can(ctx, "apigw-routes.search", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "apigw-routes.search", r) } // CanManageResourceTranslations checks if current user can list, search, create, or update resource translations // // This function is auto-generated func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool { - return svc.can(ctx, "resource-translations.manage", &types.Component{}) + r := &types.Component{} + return svc.can(ctx, "resource-translations.manage", r) } // rbacResourceValidator validates known component's resource by routing it to the appropriate validator @@ -900,6 +925,7 @@ func rbacResourceOperations(r string) map[string]bool { } case types.QueueResourceType: return map[string]bool{ + "render": true, "read": true, "update": true, "delete": true, @@ -970,24 +996,24 @@ func rbacResourceOperations(r string) map[string]bool { return nil } -// rbacApigwRouteResourceValidator checks validity of rbac resource and operations +// rbacApigwRouteResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacApigwRouteResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system ApigwRoute resource", o) - } - } - if !strings.HasPrefix(r, types.ApigwRouteResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for apigwRoute resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.ApigwRouteResourceType):], sep), sep) @@ -1003,7 +1029,7 @@ func rbacApigwRouteResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for ApigwRoute", i) + return fmt.Errorf("invalid path wildcard level (%d) for apigwRoute resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1014,24 +1040,24 @@ func rbacApigwRouteResourceValidator(r string, oo ...string) error { return nil } -// rbacApplicationResourceValidator checks validity of rbac resource and operations +// rbacApplicationResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacApplicationResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system Application resource", o) - } - } - if !strings.HasPrefix(r, types.ApplicationResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for application resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.ApplicationResourceType):], sep), sep) @@ -1047,7 +1073,7 @@ func rbacApplicationResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Application", i) + return fmt.Errorf("invalid path wildcard level (%d) for application resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1058,24 +1084,24 @@ func rbacApplicationResourceValidator(r string, oo ...string) error { return nil } -// rbacAuthClientResourceValidator checks validity of rbac resource and operations +// rbacAuthClientResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacAuthClientResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system AuthClient resource", o) - } - } - if !strings.HasPrefix(r, types.AuthClientResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for authClient resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.AuthClientResourceType):], sep), sep) @@ -1091,7 +1117,7 @@ func rbacAuthClientResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for AuthClient", i) + return fmt.Errorf("invalid path wildcard level (%d) for authClient resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1102,24 +1128,24 @@ func rbacAuthClientResourceValidator(r string, oo ...string) error { return nil } -// rbacQueueResourceValidator checks validity of rbac resource and operations +// rbacQueueResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacQueueResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system Queue resource", o) - } - } - if !strings.HasPrefix(r, types.QueueResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for queue resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.QueueResourceType):], sep), sep) @@ -1135,7 +1161,7 @@ func rbacQueueResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Queue", i) + return fmt.Errorf("invalid path wildcard level (%d) for queue resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1146,24 +1172,24 @@ func rbacQueueResourceValidator(r string, oo ...string) error { return nil } -// rbacReportResourceValidator checks validity of rbac resource and operations +// rbacReportResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacReportResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system Report resource", o) - } - } - if !strings.HasPrefix(r, types.ReportResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for report resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.ReportResourceType):], sep), sep) @@ -1179,7 +1205,7 @@ func rbacReportResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Report", i) + return fmt.Errorf("invalid path wildcard level (%d) for report resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1190,24 +1216,24 @@ func rbacReportResourceValidator(r string, oo ...string) error { return nil } -// rbacRoleResourceValidator checks validity of rbac resource and operations +// rbacRoleResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacRoleResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system Role resource", o) - } - } - if !strings.HasPrefix(r, types.RoleResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for role resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.RoleResourceType):], sep), sep) @@ -1223,7 +1249,7 @@ func rbacRoleResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Role", i) + return fmt.Errorf("invalid path wildcard level (%d) for role resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1234,24 +1260,24 @@ func rbacRoleResourceValidator(r string, oo ...string) error { return nil } -// rbacTemplateResourceValidator checks validity of rbac resource and operations +// rbacTemplateResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacTemplateResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system Template resource", o) - } - } - if !strings.HasPrefix(r, types.TemplateResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for template resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.TemplateResourceType):], sep), sep) @@ -1267,7 +1293,7 @@ func rbacTemplateResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for Template", i) + return fmt.Errorf("invalid path wildcard level (%d) for template resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1278,24 +1304,24 @@ func rbacTemplateResourceValidator(r string, oo ...string) error { return nil } -// rbacUserResourceValidator checks validity of rbac resource and operations +// rbacUserResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacUserResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system User resource", o) - } - } - if !strings.HasPrefix(r, types.UserResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for user resource", o) + } + } + const sep = "/" var ( pp = strings.Split(strings.Trim(r[len(types.UserResourceType):], sep), sep) @@ -1311,7 +1337,7 @@ func rbacUserResourceValidator(r string, oo ...string) error { for i := 0; i < len(pp); i++ { if pp[i] != "*" { if i > 0 && pp[i-1] == "*" { - return fmt.Errorf("invalid resource path wildcard level (%d) for User", i) + return fmt.Errorf("invalid path wildcard level (%d) for user resource", i) } if _, err := cast.ToUint64E(pp[i]); err != nil { @@ -1322,23 +1348,23 @@ func rbacUserResourceValidator(r string, oo ...string) error { return nil } -// rbacComponentResourceValidator checks validity of rbac resource and operations +// rbacComponentResourceValidator checks validity of RBAC resource and operations // // Can be called without operations to check for validity of resource string only // // This function is auto-generated func rbacComponentResourceValidator(r string, oo ...string) error { - defOps := rbacResourceOperations(r) - for _, o := range oo { - if !defOps[o] { - return fmt.Errorf("invalid operation '%s' for system resource", o) - } - } - if !strings.HasPrefix(r, types.ComponentResourceType) { // expecting resource to always include path return fmt.Errorf("invalid resource type") } + defOps := rbacResourceOperations(r) + for _, o := range oo { + if !defOps[o] { + return fmt.Errorf("invalid operation '%s' for system component resource", o) + } + } + return nil } diff --git a/system/template.cue b/system/template.cue new file mode 100644 index 000000000..c6f0e460b --- /dev/null +++ b/system/template.cue @@ -0,0 +1,16 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +template: schema.#resource & { + rbac: { + operations: { + read: description: "Read template" + update: description: "Update template" + delete: description: "Delete template" + render: description: "Render template" + } + } +} diff --git a/system/types/rbac.gen.go b/system/types/rbac.gen.go index ea32860c6..e6a57df1e 100644 --- a/system/types/rbac.gen.go +++ b/system/types/rbac.gen.go @@ -6,17 +6,6 @@ package types // the code is regenerated. // -// Definitions file that controls how this file is generated: -// - system.apigw-route.yaml -// - system.application.yaml -// - system.auth-client.yaml -// - system.queue.yaml -// - system.report.yaml -// - system.role.yaml -// - system.template.yaml -// - system.user.yaml -// - system.yaml - import ( "fmt" "strconv" @@ -29,6 +18,11 @@ type ( Component struct{} ) +var ( + _ = fmt.Printf + _ = strconv.FormatUint +) + const ( ApigwRouteResourceType = "corteza::system:apigw-route" ApplicationResourceType = "corteza::system:application" @@ -67,7 +61,6 @@ func ApigwRouteRbacResource(id uint64) string { } -// @todo template func ApigwRouteRbacResourceTpl() string { return "%s/%s" } @@ -98,7 +91,6 @@ func ApplicationRbacResource(id uint64) string { } -// @todo template func ApplicationRbacResourceTpl() string { return "%s/%s" } @@ -129,7 +121,6 @@ func AuthClientRbacResource(id uint64) string { } -// @todo template func AuthClientRbacResourceTpl() string { return "%s/%s" } @@ -160,7 +151,6 @@ func QueueRbacResource(id uint64) string { } -// @todo template func QueueRbacResourceTpl() string { return "%s/%s" } @@ -191,7 +181,6 @@ func ReportRbacResource(id uint64) string { } -// @todo template func ReportRbacResourceTpl() string { return "%s/%s" } @@ -222,7 +211,6 @@ func RoleRbacResource(id uint64) string { } -// @todo template func RoleRbacResourceTpl() string { return "%s/%s" } @@ -253,7 +241,6 @@ func TemplateRbacResource(id uint64) string { } -// @todo template func TemplateRbacResourceTpl() string { return "%s/%s" } @@ -284,7 +271,6 @@ func UserRbacResource(id uint64) string { } -// @todo template func UserRbacResourceTpl() string { return "%s/%s" } @@ -308,7 +294,6 @@ func ComponentRbacResource() string { } -// @todo template func ComponentRbacResourceTpl() string { return "%s" } diff --git a/system/user.cue b/system/user.cue new file mode 100644 index 000000000..4614eb4c0 --- /dev/null +++ b/system/user.cue @@ -0,0 +1,33 @@ +package system + +import ( + "github.com/cortezaproject/corteza-server/codegen/schema" +) + +user: schema.#resource & { + // fields: { + // ID: schema.IdField + // handle: schema.HandleField + // email: { unique: true } + // kind: {} + // meta: { + // note: type: string + // sub: { + // sub: { "non-unique-string-named-sub": {} } + // } + // } + // } + + rbac: { + operations: { + "read": description: "Read user" + "update": description: "Update user" + "delete": description: "Delete user" + "suspend": description: "Suspend user" + "unsuspend": description: "Unsuspend user" + "email.unmask": description: "Unmask email" + "name.unmask": description: "Unmask name" + "impersonate": description: "Impersonate user" + } + } +}