Merge branch '2022.3.x-feature-cuelang' into 2022.3.x

This commit is contained in:
Denis Arh
2022-01-26 17:20:22 +01:00
124 changed files with 2765 additions and 2965 deletions
+1 -1
View File
@@ -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
+19 -4
View File
@@ -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:
+9
View File
@@ -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)
#
+20
View File
@@ -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,
]
}
+22
View File
@@ -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"
}
}
+29 -27
View File
@@ -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
}
+5 -6
View File
@@ -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"
}
+19
View File
@@ -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"
}
}
}
+1
View File
@@ -0,0 +1 @@
ignore: ["vendor/.*"]
+81
View File
@@ -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
@@ -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 }}
@@ -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}}
}
@@ -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 }}
@@ -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
@@ -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 }}
@@ -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 }}
@@ -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 }}
@@ -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 }}
@@ -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 }}
+134
View File
@@ -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}]+
[]
+43
View File
@@ -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}]
+55
View File
@@ -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}]
+17
View File
@@ -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
+62
View File
@@ -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}]
},
]
}
},
]
+42
View File
@@ -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
},
]
}
},
]
+13
View File
@@ -0,0 +1,13 @@
package schema
#codegen: {
template: string
output: string
syntax: "go"
if output =~ "\\.adoc" {
syntax: "adoc"
}
payload: _
}
+28
View File
@@ -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"
}
}
}
}
+54
View File
@@ -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)
}
}
+17
View File
@@ -0,0 +1,17 @@
package schema
#platform: {
ident: #baseHandle | *"corteza"
components: [...{platform: ident} & #component]
// env-var definitions
// options: {}
//
// automation: {
// types: ....
// function ....
// }
}
+61
View File
@@ -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
//
// <res> + <op> => Can<Op><Res>
// <res> + <op:foo.bar.verb> => Can<Verb><Foo><Bar>On<Res>
_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)"
}
}
+98
View File
@@ -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
//}
+32
View File
@@ -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)
...
}
+74
View File
@@ -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)
}
}
@@ -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{}
+19
View File
@@ -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": {}
}
}
}
+26
View File
@@ -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"
}
}
+51
View File
@@ -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
}
}
}
}
+36
View File
@@ -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
}
+36
View File
@@ -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"]
}
}
}
}
+40
View File
@@ -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
}
}
}
}
+20
View File
@@ -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": {}
}
}
}
+4 -4
View File
@@ -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),
}
}
+162 -165
View File
@@ -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
}
+11 -16
View File
@@ -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
}
+8 -8
View File
@@ -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(),
+7 -7
View File
@@ -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 {
+126 -171
View File
@@ -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(),
+24 -24
View File
@@ -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,
})
}
+1 -1
View File
@@ -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"])
-1
View File
@@ -6,7 +6,6 @@ import (
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/pkg/errors"
)
+6 -6
View File
@@ -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),
})
}
+42 -53
View File
@@ -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"
}
+1
View File
@@ -0,0 +1 @@
module: "github.com/cortezaproject/corteza-server"
+3
View File
@@ -0,0 +1,3 @@
module github.com/cortezaproject/corteza-server
cue v0.4.0
View File
-1
View File
@@ -1 +0,0 @@
See `pkg/codegen-v3/README.md`
-23
View File
@@ -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" }
-21
View File
@@ -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
-17
View File
@@ -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
-29
View File
@@ -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
}
-24
View File
@@ -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
-31
View File
@@ -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" }
-23
View File
@@ -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 }
-11
View File
@@ -1,11 +0,0 @@
rbac:
resource:
references: [ namespace, module, ID ]
operations:
read:
description: Read record
update:
description: Update record
delete:
description: Delete record
-19
View File
@@ -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
-7
View File
@@ -1,7 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "boolean",
"enum": [ "false" ],
"title": "Disable envoy support",
"description": "Enabled by default"
}
-78
View File
@@ -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"
}
}
}
]
}
}
}
}
}
-26
View File
@@ -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
}
-9
View File
@@ -1,9 +0,0 @@
rbac:
resource:
references: [ node, ID ]
operations:
manage:
description: Manage shared module
envoy: false
-8
View File
@@ -1,8 +0,0 @@
rbac:
operations:
manage:
description: Manage federation node
module.create:
description: Create shared module
envoy: false
-9
View File
@@ -1,9 +0,0 @@
rbac:
resource:
references: [ node, ID ]
operations:
map:
description: Map shared module
envoy: false
-19
View File
@@ -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
-8
View File
@@ -1,8 +0,0 @@
rbac:
operations:
read:
description: Read API Gateway route
update:
description: Update API Gateway route
delete:
description: Delete API Gateway route
-8
View File
@@ -1,8 +0,0 @@
rbac:
operations:
read:
description: Read application
update:
description: Update application
delete:
description: Delete application
-10
View File
@@ -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
-12
View File
@@ -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
-18
View File
@@ -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 }
-10
View File
@@ -1,10 +0,0 @@
rbac:
operations:
read:
description: Read role
update:
description: Update role
delete:
description: Delete role
members.manage:
description: Manage members
-10
View File
@@ -1,10 +0,0 @@
rbac:
operations:
read:
description: Read template
update:
description: Update template
delete:
description: Delete template
render:
description: Render template
-18
View File
@@ -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
-64
View File
@@ -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
+24
View File
@@ -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"
}
}
+17
View File
@@ -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"
}
}
}
+14
View File
@@ -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"
}
}
}
+105 -105
View File
@@ -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
}
+17
View File
@@ -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"
}
}
}
+36 -41
View File
@@ -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"
}
-12
View File
@@ -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
```
@@ -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 }}
@@ -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 }}
@@ -1,4 +0,0 @@
// Definitions file that controls how this file is generated:
{{- range .Def }}
// - {{ .Source }}
{{- end }}
@@ -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 }}
@@ -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 }}
-91
View File
@@ -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
}
-127
View File
@@ -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)
}
-165
View File
@@ -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::<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 = 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
//
// <res> + <op> => Can<Op><Res>
// <res> + <op:foo.bar.verb> => Can<Verb><Foo><Bar>On<Res>
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)
}
-168
View File
@@ -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>/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>/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
}
-67
View File
@@ -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)
}
-70
View File
@@ -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
}

Some files were not shown because too many files have changed in this diff Show More