Base envoy codegen
This commit is contained in:
+256
@@ -0,0 +1,256 @@
|
||||
package envoy
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
)
|
||||
|
||||
type (
|
||||
// StoreDecoder is responsible for fetching already stored Corteza resources
|
||||
// which are then managed by envoy and imported via an encoder.
|
||||
StoreDecoder struct{}
|
||||
)
|
||||
|
||||
// Decode returns a set of envoy nodes based on the provided params
|
||||
//
|
||||
// StoreDecoder expects the DecodeParam of `storer` and `dal` which conform
|
||||
// to the store.Storer and dal.FullService interfaces.
|
||||
func (d StoreDecoder) Decode(ctx context.Context, p envoyx.DecodeParams) (out envoyx.NodeSet, err error) {
|
||||
var (
|
||||
s store.Storer
|
||||
dl dal.FullService
|
||||
)
|
||||
|
||||
// @todo we can optionally not require them based on what we're doing
|
||||
if auxS, ok := p.Params["storer"]; ok {
|
||||
s = auxS.(store.Storer)
|
||||
}
|
||||
if auxDl, ok := p.Params["dal"]; ok {
|
||||
dl = auxDl.(dal.FullService)
|
||||
}
|
||||
|
||||
return d.decode(ctx, s, dl, p)
|
||||
}
|
||||
|
||||
func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullService, p envoyx.DecodeParams) (out envoyx.NodeSet, err error) {
|
||||
// Transform passed filters into an ordered structure
|
||||
type (
|
||||
filterWrap struct {
|
||||
rt string
|
||||
f envoyx.ResourceFilter
|
||||
}
|
||||
)
|
||||
wrappedFilters := make([]filterWrap, 0, len(p.Filter))
|
||||
for rt, f := range p.Filter {
|
||||
wrappedFilters = append(wrappedFilters, filterWrap{rt: rt, f: f})
|
||||
}
|
||||
|
||||
// Get all requested scopes
|
||||
scopedNodes := make(envoyx.NodeSet, len(p.Filter))
|
||||
|
||||
// @note skipping scope logic since it's currently only supported within
|
||||
// Compose resources.
|
||||
|
||||
// Get all requested references
|
||||
//
|
||||
// Keep an index for the Node and one for the reference to make our
|
||||
// lives easier.
|
||||
refNodes := make([]map[string]*envoyx.Node, len(p.Filter))
|
||||
refRefs := make([]map[string]envoyx.Ref, len(p.Filter))
|
||||
for i, a := range wrappedFilters {
|
||||
if len(a.f.Refs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
auxr := make(map[string]*envoyx.Node, len(a.f.Refs))
|
||||
auxa := make(map[string]envoyx.Ref)
|
||||
for field, ref := range a.f.Refs {
|
||||
f := ref.ResourceFilter()
|
||||
aux, err := d.decode(ctx, s, dl, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Filter: f,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(aux) == 0 {
|
||||
return nil, fmt.Errorf("invalid reference %v", ref)
|
||||
}
|
||||
if len(aux) > 1 {
|
||||
return nil, fmt.Errorf("ambiguous reference: too many resources returned %v", a.f)
|
||||
}
|
||||
|
||||
auxr[field] = aux[0]
|
||||
auxa[field] = aux[0].ToRef()
|
||||
}
|
||||
|
||||
refNodes[i] = auxr
|
||||
refRefs[i] = auxa
|
||||
}
|
||||
|
||||
var aux envoyx.NodeSet
|
||||
for i, wf := range wrappedFilters {
|
||||
switch wf.rt {
|
||||
case types.WorkflowResourceType:
|
||||
aux, err = d.decodeWorkflow(ctx, s, dl, d.makeWorkflowFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
case types.TriggerResourceType:
|
||||
aux, err = d.decodeTrigger(ctx, s, dl, d.makeTriggerFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
} // // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource workflow
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodeWorkflow(ctx context.Context, s store.Storer, dl dal.FullService, f types.WorkflowFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchAutomationWorkflows(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.Handle,
|
||||
r.ID,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{
|
||||
// Handle references
|
||||
"CreatedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.CreatedBy),
|
||||
},
|
||||
// Handle references
|
||||
"DeletedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.DeletedBy),
|
||||
},
|
||||
// Handle references
|
||||
"OwnedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.OwnedBy),
|
||||
},
|
||||
// Handle references
|
||||
"RunAs": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.RunAs),
|
||||
},
|
||||
// Handle references
|
||||
"UpdatedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy),
|
||||
},
|
||||
}
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.WorkflowResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Resource should define a custom filter builder
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource trigger
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodeTrigger(ctx context.Context, s store.Storer, dl dal.FullService, f types.TriggerFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchAutomationTriggers(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.ID,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{
|
||||
// Handle references
|
||||
"CreatedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.CreatedBy),
|
||||
},
|
||||
// Handle references
|
||||
"DeletedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.DeletedBy),
|
||||
},
|
||||
// Handle references
|
||||
"OwnedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.OwnedBy),
|
||||
},
|
||||
// Handle references
|
||||
"UpdatedBy": envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.UpdatedBy),
|
||||
},
|
||||
// Handle references
|
||||
"WorkflowID": envoyx.Ref{
|
||||
ResourceType: "corteza::automation:workflow",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.WorkflowID),
|
||||
},
|
||||
}
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.TriggerResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Resource should define a custom filter builder
|
||||
@@ -0,0 +1,34 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
)
|
||||
|
||||
func (d StoreDecoder) makeWorkflowFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.WorkflowFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.IdentsAsStrings()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
out.WorkflowID = ids
|
||||
|
||||
if len(hh) > 0 {
|
||||
out.Handle = hh[0]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) makeTriggerFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.TriggerFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.Idents()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
out.TriggerID = ids
|
||||
|
||||
return
|
||||
}
|
||||
+465
@@ -0,0 +1,465 @@
|
||||
package envoy
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/id"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
)
|
||||
|
||||
type (
|
||||
// StoreEncoder is responsible for encoding Corteza resources into the
|
||||
// database via the Storer or the DAL interface
|
||||
//
|
||||
// @todo consider having a different encoder for the DAL resources
|
||||
StoreEncoder struct{}
|
||||
)
|
||||
|
||||
// Prepare performs some initial processing on the resource before it can be encoded
|
||||
//
|
||||
// Preparation runs validation, default value initialization, matching with
|
||||
// already existing instances, ...
|
||||
//
|
||||
// The prepare function receives a set of nodes grouped by the resource type.
|
||||
// This enables some batching optimization and simplifications when it comes to
|
||||
// matching with existing resources.
|
||||
//
|
||||
// Prepare does not receive any placeholder nodes which are used solely
|
||||
// for dependency resolution.
|
||||
func (e StoreEncoder) Prepare(ctx context.Context, p envoyx.EncodeParams, rt string, nn envoyx.NodeSet) (err error) {
|
||||
s, err := e.grabStorer(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch rt {
|
||||
case types.WorkflowResourceType:
|
||||
return e.prepareWorkflow(ctx, p, s, nn)
|
||||
|
||||
case types.TriggerResourceType:
|
||||
return e.prepareTrigger(ctx, p, s, nn)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Encode encodes the given Corteza resources into the primary store
|
||||
//
|
||||
// Encoding should not do any additional processing apart from matching with
|
||||
// dependencies and runtime validation
|
||||
//
|
||||
// The Encode function is called for every resource type where the resource
|
||||
// appears at the root of the dependency tree.
|
||||
// All of the root-level resources for that resource type are passed into the function.
|
||||
// The encoding function must traverse the branches to encode all of the dependencies.
|
||||
//
|
||||
// This flow is used to simplify the flow of how resources are encoded into YAML
|
||||
// (and other documents) as well as to simplify batching.
|
||||
//
|
||||
// Encode does not receive any placeholder nodes which are used solely
|
||||
// for dependency resolution.
|
||||
func (e StoreEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt string, nodes envoyx.NodeSet, tree envoyx.Traverser) (err error) {
|
||||
s, err := e.grabStorer(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch rt {
|
||||
case types.WorkflowResourceType:
|
||||
return e.encodeWorkflows(ctx, p, s, nodes, tree)
|
||||
|
||||
case types.TriggerResourceType:
|
||||
return e.encodeTriggers(ctx, p, s, nodes, tree)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource workflow
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
// prepareWorkflow prepares the resources of the given type for encoding
|
||||
func (e StoreEncoder) prepareWorkflow(ctx context.Context, p envoyx.EncodeParams, s store.Storer, nn envoyx.NodeSet) (err error) {
|
||||
// Grab an index of already existing resources of this type
|
||||
// @note since these resources should be fairly low-volume and existing for
|
||||
// a short time (and because we batch by resource type); fetching them all
|
||||
// into memory shouldn't hurt too much.
|
||||
// @todo do some benchmarks and potentially implement some smarter check such as
|
||||
// a bloom filter or something similar.
|
||||
|
||||
// Initializing the index here (and using a hashmap) so it's not escaped to the heap
|
||||
existing := make(map[int]types.Workflow, len(nn))
|
||||
err = e.matchupWorkflows(ctx, s, existing, nn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, n := range nn {
|
||||
if n.Resource == nil {
|
||||
panic("unexpected state: cannot call prepareWorkflow with nodes without a defined Resource")
|
||||
}
|
||||
|
||||
res, ok := n.Resource.(*types.Workflow)
|
||||
if !ok {
|
||||
panic("unexpected resource type: node expecting type of workflow")
|
||||
}
|
||||
|
||||
existing, hasExisting := existing[i]
|
||||
|
||||
if hasExisting {
|
||||
// On existing, we don't need to re-do identifiers and references; simply
|
||||
// changing up the internal resource is enough.
|
||||
//
|
||||
// In the future, we can pass down the tree and re-do the deps like that
|
||||
switch p.Config.OnExisting {
|
||||
case envoyx.OnConflictPanic:
|
||||
err = fmt.Errorf("resource already exists")
|
||||
return
|
||||
|
||||
case envoyx.OnConflictReplace:
|
||||
// Replace; simple ID change should do the trick
|
||||
res.ID = existing.ID
|
||||
|
||||
case envoyx.OnConflictSkip:
|
||||
// Replace the node's resource with the fetched one
|
||||
res = &existing
|
||||
|
||||
// @todo merging
|
||||
}
|
||||
} else {
|
||||
// @todo actually a bottleneck. As per sonyflake docs, it can at most
|
||||
// generate up to 2**8 (256) IDs per 10ms in a single thread.
|
||||
// How can we improve this?
|
||||
res.ID = id.Next()
|
||||
}
|
||||
|
||||
// We can skip validation/defaults when the resource is overwritten by
|
||||
// the one already stored (the panic one errors out anyway) since it
|
||||
// should already be ok.
|
||||
if !hasExisting || p.Config.OnExisting != envoyx.OnConflictSkip {
|
||||
err = e.setWorkflowDefaults(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = e.validateWorkflow(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
n.Resource = res
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeWorkflows encodes a set of resource into the database
|
||||
func (e StoreEncoder) encodeWorkflows(ctx context.Context, p envoyx.EncodeParams, s store.Storer, nn envoyx.NodeSet, tree envoyx.Traverser) (err error) {
|
||||
for _, n := range nn {
|
||||
err = e.encodeWorkflow(ctx, p, s, n, tree)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeWorkflow encodes the resource into the database
|
||||
func (e StoreEncoder) encodeWorkflow(ctx context.Context, p envoyx.EncodeParams, s store.Storer, n *envoyx.Node, tree envoyx.Traverser) (err error) {
|
||||
// Grab dependency references
|
||||
var auxID uint64
|
||||
for fieldLabel, ref := range n.References {
|
||||
rn := tree.ParentForRef(n, ref)
|
||||
if rn == nil {
|
||||
err = fmt.Errorf("missing node for ref %v", ref)
|
||||
return
|
||||
}
|
||||
|
||||
auxID = rn.Resource.GetID()
|
||||
if auxID == 0 {
|
||||
err = fmt.Errorf("related resource doesn't provide an ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = n.Resource.SetValue(fieldLabel, 0, auxID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Flush to the DB
|
||||
err = store.UpsertAutomationWorkflow(ctx, s, n.Resource.(*types.Workflow))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle resources nested under it
|
||||
//
|
||||
// @todo how can we remove the OmitPlaceholderNodes call the same way we did for
|
||||
// the root function calls?
|
||||
|
||||
for rt, nn := range envoyx.NodesByResourceType(tree.Children(n)...) {
|
||||
nn = envoyx.OmitPlaceholderNodes(nn...)
|
||||
|
||||
switch rt {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// matchupWorkflows returns an index with indicates what resources already exist
|
||||
func (e StoreEncoder) matchupWorkflows(ctx context.Context, s store.Storer, uu map[int]types.Workflow, nn envoyx.NodeSet) (err error) {
|
||||
// @todo might need to do it smarter then this.
|
||||
// Most resources won't really be that vast so this should be acceptable for now.
|
||||
aa, _, err := store.SearchAutomationWorkflows(ctx, s, types.WorkflowFilter{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
idMap := make(map[uint64]*types.Workflow, len(aa))
|
||||
strMap := make(map[string]*types.Workflow, len(aa))
|
||||
|
||||
for _, a := range aa {
|
||||
strMap[a.Handle] = a
|
||||
idMap[a.ID] = a
|
||||
|
||||
}
|
||||
|
||||
var aux *types.Workflow
|
||||
var ok bool
|
||||
for i, n := range nn {
|
||||
for _, idf := range n.Identifiers.Slice {
|
||||
if id, err := strconv.ParseUint(idf, 10, 64); err == nil {
|
||||
aux, ok = idMap[id]
|
||||
if ok {
|
||||
uu[i] = *aux
|
||||
// When any identifier matches we can end it
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
aux, ok = strMap[idf]
|
||||
if ok {
|
||||
uu[i] = *aux
|
||||
// When any identifier matches we can end it
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource trigger
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
// prepareTrigger prepares the resources of the given type for encoding
|
||||
func (e StoreEncoder) prepareTrigger(ctx context.Context, p envoyx.EncodeParams, s store.Storer, nn envoyx.NodeSet) (err error) {
|
||||
// Grab an index of already existing resources of this type
|
||||
// @note since these resources should be fairly low-volume and existing for
|
||||
// a short time (and because we batch by resource type); fetching them all
|
||||
// into memory shouldn't hurt too much.
|
||||
// @todo do some benchmarks and potentially implement some smarter check such as
|
||||
// a bloom filter or something similar.
|
||||
|
||||
// Initializing the index here (and using a hashmap) so it's not escaped to the heap
|
||||
existing := make(map[int]types.Trigger, len(nn))
|
||||
err = e.matchupTriggers(ctx, s, existing, nn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, n := range nn {
|
||||
if n.Resource == nil {
|
||||
panic("unexpected state: cannot call prepareTrigger with nodes without a defined Resource")
|
||||
}
|
||||
|
||||
res, ok := n.Resource.(*types.Trigger)
|
||||
if !ok {
|
||||
panic("unexpected resource type: node expecting type of trigger")
|
||||
}
|
||||
|
||||
existing, hasExisting := existing[i]
|
||||
|
||||
if hasExisting {
|
||||
// On existing, we don't need to re-do identifiers and references; simply
|
||||
// changing up the internal resource is enough.
|
||||
//
|
||||
// In the future, we can pass down the tree and re-do the deps like that
|
||||
switch p.Config.OnExisting {
|
||||
case envoyx.OnConflictPanic:
|
||||
err = fmt.Errorf("resource already exists")
|
||||
return
|
||||
|
||||
case envoyx.OnConflictReplace:
|
||||
// Replace; simple ID change should do the trick
|
||||
res.ID = existing.ID
|
||||
|
||||
case envoyx.OnConflictSkip:
|
||||
// Replace the node's resource with the fetched one
|
||||
res = &existing
|
||||
|
||||
// @todo merging
|
||||
}
|
||||
} else {
|
||||
// @todo actually a bottleneck. As per sonyflake docs, it can at most
|
||||
// generate up to 2**8 (256) IDs per 10ms in a single thread.
|
||||
// How can we improve this?
|
||||
res.ID = id.Next()
|
||||
}
|
||||
|
||||
// We can skip validation/defaults when the resource is overwritten by
|
||||
// the one already stored (the panic one errors out anyway) since it
|
||||
// should already be ok.
|
||||
if !hasExisting || p.Config.OnExisting != envoyx.OnConflictSkip {
|
||||
err = e.setTriggerDefaults(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = e.validateTrigger(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
n.Resource = res
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeTriggers encodes a set of resource into the database
|
||||
func (e StoreEncoder) encodeTriggers(ctx context.Context, p envoyx.EncodeParams, s store.Storer, nn envoyx.NodeSet, tree envoyx.Traverser) (err error) {
|
||||
for _, n := range nn {
|
||||
err = e.encodeTrigger(ctx, p, s, n, tree)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeTrigger encodes the resource into the database
|
||||
func (e StoreEncoder) encodeTrigger(ctx context.Context, p envoyx.EncodeParams, s store.Storer, n *envoyx.Node, tree envoyx.Traverser) (err error) {
|
||||
// Grab dependency references
|
||||
var auxID uint64
|
||||
for fieldLabel, ref := range n.References {
|
||||
rn := tree.ParentForRef(n, ref)
|
||||
if rn == nil {
|
||||
err = fmt.Errorf("missing node for ref %v", ref)
|
||||
return
|
||||
}
|
||||
|
||||
auxID = rn.Resource.GetID()
|
||||
if auxID == 0 {
|
||||
err = fmt.Errorf("related resource doesn't provide an ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = n.Resource.SetValue(fieldLabel, 0, auxID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Flush to the DB
|
||||
err = store.UpsertAutomationTrigger(ctx, s, n.Resource.(*types.Trigger))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle resources nested under it
|
||||
//
|
||||
// @todo how can we remove the OmitPlaceholderNodes call the same way we did for
|
||||
// the root function calls?
|
||||
|
||||
for rt, nn := range envoyx.NodesByResourceType(tree.Children(n)...) {
|
||||
nn = envoyx.OmitPlaceholderNodes(nn...)
|
||||
|
||||
switch rt {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// matchupTriggers returns an index with indicates what resources already exist
|
||||
func (e StoreEncoder) matchupTriggers(ctx context.Context, s store.Storer, uu map[int]types.Trigger, nn envoyx.NodeSet) (err error) {
|
||||
// @todo might need to do it smarter then this.
|
||||
// Most resources won't really be that vast so this should be acceptable for now.
|
||||
aa, _, err := store.SearchAutomationTriggers(ctx, s, types.TriggerFilter{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
idMap := make(map[uint64]*types.Trigger, len(aa))
|
||||
strMap := make(map[string]*types.Trigger, len(aa))
|
||||
|
||||
for _, a := range aa {
|
||||
idMap[a.ID] = a
|
||||
|
||||
}
|
||||
|
||||
var aux *types.Trigger
|
||||
var ok bool
|
||||
for i, n := range nn {
|
||||
for _, idf := range n.Identifiers.Slice {
|
||||
if id, err := strconv.ParseUint(idf, 10, 64); err == nil {
|
||||
aux, ok = idMap[id]
|
||||
if ok {
|
||||
uu[i] = *aux
|
||||
// When any identifier matches we can end it
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
aux, ok = strMap[idf]
|
||||
if ok {
|
||||
uu[i] = *aux
|
||||
// When any identifier matches we can end it
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Utility functions
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e *StoreEncoder) grabStorer(p envoyx.EncodeParams) (s store.Storer, err error) {
|
||||
auxs, ok := p.Params["storer"]
|
||||
if !ok {
|
||||
err = fmt.Errorf("storer not defined")
|
||||
return
|
||||
}
|
||||
|
||||
s, ok = auxs.(store.Storer)
|
||||
if !ok {
|
||||
err = fmt.Errorf("invalid storer provided")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package envoy
|
||||
|
||||
import "github.com/cortezaproject/corteza/server/automation/types"
|
||||
|
||||
func (e StoreEncoder) setWorkflowDefaults(res *types.Workflow) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateWorkflow(res *types.Workflow) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setTriggerDefaults(res *types.Trigger) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateTrigger(res *types.Trigger) (err error) {
|
||||
return
|
||||
}
|
||||
+804
@@ -0,0 +1,804 @@
|
||||
package envoy
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/pkg/y7s"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"golang.org/x/text/language"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type (
|
||||
// YamlDecoder is responsible for decoding YAML documents into Corteza resources
|
||||
// which are then managed by envoy and imported via an encoder.
|
||||
YamlDecoder struct{}
|
||||
documentContext struct {
|
||||
references map[string]string
|
||||
}
|
||||
auxYamlDoc struct {
|
||||
nodes envoyx.NodeSet
|
||||
}
|
||||
)
|
||||
|
||||
// Decode returns a set of envoy nodes based on the provided params
|
||||
//
|
||||
// YamlDecoder expects the DecodeParam of `stream` which conforms
|
||||
// to the io.Reader interface.
|
||||
func (d YamlDecoder) Decode(ctx context.Context, p envoyx.DecodeParams) (out envoyx.NodeSet, err error) {
|
||||
// Get the reader
|
||||
r, err := d.getReader(ctx, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Offload decoding to the aux document
|
||||
doc := &auxYamlDoc{}
|
||||
err = yaml.NewDecoder(r).Decode(doc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return doc.nodes, nil
|
||||
}
|
||||
|
||||
func (d *auxYamlDoc) UnmarshalYAML(n *yaml.Node) (err error) {
|
||||
// Get the document context from the root level
|
||||
dctx, err := d.getDocumentContext(n)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var aux envoyx.NodeSet
|
||||
return y7s.EachMap(n, func(k, v *yaml.Node) error {
|
||||
kv := strings.ToLower(k.Value)
|
||||
|
||||
switch kv {
|
||||
case "workflow", "workflows":
|
||||
if y7s.IsMapping(v) {
|
||||
aux, err = d.unmarshalWorkflowMap(dctx, v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
return err
|
||||
}
|
||||
if y7s.IsSeq(v) {
|
||||
aux, err = d.unmarshalWorkflowSeq(dctx, v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
}
|
||||
return err
|
||||
|
||||
case "trigger":
|
||||
if y7s.IsSeq(v) {
|
||||
aux, err = d.unmarshalTriggerSeq(dctx, v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
}
|
||||
return err
|
||||
|
||||
// Access control nodes
|
||||
case "allow":
|
||||
aux, err = unmarshalAllowNode(v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case "deny":
|
||||
aux, err = unmarshalDenyNode(v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Resource translation nodes
|
||||
case "locale", "translation", "translations", "i18n":
|
||||
aux, err = unmarshalLocaleNode(v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Offload to custom handlers
|
||||
default:
|
||||
aux, err = d.unmarshalYAML(kv, v)
|
||||
d.nodes = append(d.nodes, aux...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource workflow
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
// unmarshalWorkflowSeq unmarshals Workflow when provided as a sequence node
|
||||
func (d *auxYamlDoc) unmarshalWorkflowSeq(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachSeq(n, func(n *yaml.Node) error {
|
||||
aux, err = d.unmarshalWorkflowNode(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalWorkflowMap unmarshals Workflow when provided as a mapping node
|
||||
//
|
||||
// When map encoded, the map key is used as a preset identifier.
|
||||
// The identifier is passed to the node function as a meta node
|
||||
func (d *auxYamlDoc) unmarshalWorkflowMap(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
aux, err = d.unmarshalWorkflowNode(dctx, n, k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalTriggersExtendedSeq unmarshals Triggers when provided as a sequence node
|
||||
func (d *auxYamlDoc) unmarshalExtendedTriggersSeq(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachSeq(n, func(n *yaml.Node) error {
|
||||
aux, err = d.unmarshalTriggersExtendedNode(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalTriggersExtendedMap unmarshals Triggers when provided as a mapping node
|
||||
//
|
||||
// When map encoded, the map key is used as a preset identifier.
|
||||
// The identifier is passed to the node function as a meta node
|
||||
func (d *auxYamlDoc) unmarshalExtendedTriggersMap(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
aux, err = d.unmarshalTriggersExtendedNode(dctx, n, k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalWorkflowNode is a cookie-cutter function to unmarshal
|
||||
// the yaml node into the corresponding Corteza type & Node
|
||||
func (d *auxYamlDoc) unmarshalWorkflowNode(dctx documentContext, n *yaml.Node, meta ...*yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var r *types.Workflow
|
||||
|
||||
// @todo we're omitting errors because there will be a bunch due to invalid
|
||||
// resource field types. This might be a bit unstable as other errors may
|
||||
// also get ignored.
|
||||
//
|
||||
// A potential fix would be to firstly unmarshal into an any, check errors
|
||||
// and then unmarshal into the resource while omitting errors.
|
||||
n.Decode(&r)
|
||||
|
||||
// Identifiers are determined manually when iterating the yaml node.
|
||||
// This is to help assure there are no duplicates and everything
|
||||
// was accounted for especially when working with aliases such as
|
||||
// user_name instead of userName.
|
||||
ii := envoyx.Identifiers{}
|
||||
|
||||
// When a resource supports mapped input, the key is passed as meta which
|
||||
// needs to be registered as an identifier (since it is)
|
||||
if len(meta) > 0 {
|
||||
y7s.DecodeScalar(meta[0], "Handle", &r.Handle)
|
||||
ii = ii.Add(r.Handle)
|
||||
}
|
||||
|
||||
var (
|
||||
refs = make(map[string]envoyx.Ref)
|
||||
auxOut envoyx.NodeSet
|
||||
nestedNodes envoyx.NodeSet
|
||||
scope envoyx.Scope
|
||||
rbacNodes envoyx.NodeSet
|
||||
)
|
||||
_ = auxOut
|
||||
_ = refs
|
||||
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
var auxNodeValue any
|
||||
_ = auxNodeValue
|
||||
|
||||
switch strings.ToLower(k.Value) {
|
||||
|
||||
case "createdby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "createdBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["CreatedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "deletedby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "deletedBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["DeletedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "handle":
|
||||
// Handle identifiers
|
||||
err = y7s.DecodeScalar(n, "handle", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ii = ii.Add(auxNodeValue)
|
||||
|
||||
break
|
||||
|
||||
case "id":
|
||||
// Handle identifiers
|
||||
err = y7s.DecodeScalar(n, "id", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ii = ii.Add(auxNodeValue)
|
||||
|
||||
break
|
||||
|
||||
case "ownedby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "ownedBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["OwnedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "runas":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "runAs", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["RunAs"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "updatedby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "updatedBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["UpdatedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
// Handle RBAC rules
|
||||
case "allow":
|
||||
auxOut, err = unmarshalAllowNode(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rbacNodes = append(rbacNodes, auxOut...)
|
||||
auxOut = nil
|
||||
|
||||
case "deny":
|
||||
auxOut, err = unmarshalDenyNode(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rbacNodes = append(rbacNodes, auxOut...)
|
||||
auxOut = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Apply the scope to all of the references of the same type
|
||||
for k, ref := range refs {
|
||||
if ref.ResourceType != scope.ResourceType {
|
||||
continue
|
||||
}
|
||||
ref.Scope = scope
|
||||
refs[k] = ref
|
||||
}
|
||||
|
||||
// Handle any resources that could be inserted under workflow such as a module inside a namespace
|
||||
//
|
||||
// This operation is done in the second pass of the document so we have
|
||||
// the complete context of the current resource; such as the identifier,
|
||||
// references, and scope.
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
nestedNodes = nil
|
||||
|
||||
switch strings.ToLower(k.Value) {
|
||||
|
||||
case "triggers":
|
||||
default:
|
||||
if y7s.IsSeq(n) {
|
||||
nestedNodes, err = d.unmarshalExtendedTriggersSeq(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Iterate nested nodes and update their reference to the current resource
|
||||
//
|
||||
// Any reference to the parent resource from the child resource is overwritten
|
||||
// to avoid potential user-error edge cases.
|
||||
for _, a := range nestedNodes {
|
||||
// @note all nested resources fall under the same component and the same scope.
|
||||
// Simply assign the same scope to all -- if it shouldn't be scoped
|
||||
// the parent won't have it (saving CPU ticks :)
|
||||
a.Scope = scope
|
||||
|
||||
if a.References == nil {
|
||||
a.References = make(map[string]envoyx.Ref)
|
||||
}
|
||||
|
||||
a.References["WorkflowID"] = envoyx.Ref{
|
||||
ResourceType: types.WorkflowResourceType,
|
||||
Identifiers: ii,
|
||||
Scope: scope,
|
||||
}
|
||||
|
||||
for f, ref := range refs {
|
||||
a.References[f] = ref
|
||||
}
|
||||
}
|
||||
auxOut = append(auxOut, nestedNodes...)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
a := &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.WorkflowResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
}
|
||||
// Update RBAC resource nodes with references regarding the resource
|
||||
for _, rn := range rbacNodes {
|
||||
// Since the rule belongs to the resource, it will have the same
|
||||
// subset of references as the parent resource.
|
||||
rn.References = envoyx.MergeRefs(rn.References, a.References)
|
||||
|
||||
// The RBAC rule's most specific identifier is the resource itself.
|
||||
// Using this we can hardcode it to point to the location after the parent resource.
|
||||
//
|
||||
// @todo consider using a more descriptive identifier for the position
|
||||
// such as `index-%d`.
|
||||
rn.References["0"] = envoyx.Ref{
|
||||
ResourceType: a.ResourceType,
|
||||
Identifiers: a.Identifiers,
|
||||
Scope: scope,
|
||||
}
|
||||
}
|
||||
|
||||
// Put it all together...
|
||||
out = append(out, a)
|
||||
out = append(out, auxOut...)
|
||||
out = append(out, rbacNodes...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource trigger
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
// unmarshalTriggerSeq unmarshals Trigger when provided as a sequence node
|
||||
func (d *auxYamlDoc) unmarshalTriggerSeq(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachSeq(n, func(n *yaml.Node) error {
|
||||
aux, err = d.unmarshalTriggerNode(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalTriggerMap unmarshals Trigger when provided as a mapping node
|
||||
//
|
||||
// When map encoded, the map key is used as a preset identifier.
|
||||
// The identifier is passed to the node function as a meta node
|
||||
// @note this resource does not support map encoding.
|
||||
// Refer to the corresponding definition files to adjust if needed.
|
||||
|
||||
// unmarshalTriggerNode is a cookie-cutter function to unmarshal
|
||||
// the yaml node into the corresponding Corteza type & Node
|
||||
func (d *auxYamlDoc) unmarshalTriggerNode(dctx documentContext, n *yaml.Node, meta ...*yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var r *types.Trigger
|
||||
|
||||
// @todo we're omitting errors because there will be a bunch due to invalid
|
||||
// resource field types. This might be a bit unstable as other errors may
|
||||
// also get ignored.
|
||||
//
|
||||
// A potential fix would be to firstly unmarshal into an any, check errors
|
||||
// and then unmarshal into the resource while omitting errors.
|
||||
n.Decode(&r)
|
||||
|
||||
// Identifiers are determined manually when iterating the yaml node.
|
||||
// This is to help assure there are no duplicates and everything
|
||||
// was accounted for especially when working with aliases such as
|
||||
// user_name instead of userName.
|
||||
ii := envoyx.Identifiers{}
|
||||
|
||||
var (
|
||||
refs = make(map[string]envoyx.Ref)
|
||||
auxOut envoyx.NodeSet
|
||||
nestedNodes envoyx.NodeSet
|
||||
scope envoyx.Scope
|
||||
)
|
||||
_ = auxOut
|
||||
_ = refs
|
||||
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
var auxNodeValue any
|
||||
_ = auxNodeValue
|
||||
|
||||
switch strings.ToLower(k.Value) {
|
||||
|
||||
case "createdby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "createdBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["CreatedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "deletedby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "deletedBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["DeletedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "id":
|
||||
// Handle identifiers
|
||||
err = y7s.DecodeScalar(n, "id", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ii = ii.Add(auxNodeValue)
|
||||
|
||||
break
|
||||
|
||||
case "ownedby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "ownedBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["OwnedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "updatedby":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "updatedBy", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["UpdatedBy"] = envoyx.Ref{
|
||||
ResourceType: "corteza::system:user",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case "workflowid":
|
||||
// Handle references
|
||||
err = y7s.DecodeScalar(n, "workflowID", &auxNodeValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs["WorkflowID"] = envoyx.Ref{
|
||||
ResourceType: "corteza::automation:workflow",
|
||||
Identifiers: envoyx.MakeIdentifiers(auxNodeValue),
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Apply the scope to all of the references of the same type
|
||||
for k, ref := range refs {
|
||||
if ref.ResourceType != scope.ResourceType {
|
||||
continue
|
||||
}
|
||||
ref.Scope = scope
|
||||
refs[k] = ref
|
||||
}
|
||||
|
||||
// Handle any resources that could be inserted under trigger such as a module inside a namespace
|
||||
//
|
||||
// This operation is done in the second pass of the document so we have
|
||||
// the complete context of the current resource; such as the identifier,
|
||||
// references, and scope.
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
nestedNodes = nil
|
||||
|
||||
switch strings.ToLower(k.Value) {
|
||||
|
||||
}
|
||||
|
||||
// Iterate nested nodes and update their reference to the current resource
|
||||
//
|
||||
// Any reference to the parent resource from the child resource is overwritten
|
||||
// to avoid potential user-error edge cases.
|
||||
for _, a := range nestedNodes {
|
||||
// @note all nested resources fall under the same component and the same scope.
|
||||
// Simply assign the same scope to all -- if it shouldn't be scoped
|
||||
// the parent won't have it (saving CPU ticks :)
|
||||
a.Scope = scope
|
||||
|
||||
if a.References == nil {
|
||||
a.References = make(map[string]envoyx.Ref)
|
||||
}
|
||||
|
||||
a.References["TriggerID"] = envoyx.Ref{
|
||||
ResourceType: types.TriggerResourceType,
|
||||
Identifiers: ii,
|
||||
Scope: scope,
|
||||
}
|
||||
|
||||
for f, ref := range refs {
|
||||
a.References[f] = ref
|
||||
}
|
||||
}
|
||||
auxOut = append(auxOut, nestedNodes...)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
a := &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.TriggerResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
}
|
||||
|
||||
// Put it all together...
|
||||
out = append(out, a)
|
||||
out = append(out, auxOut...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// RBAC unmarshal logic
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func unmarshalAllowNode(n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return unmarshalRBACNode(n, rbac.Allow)
|
||||
}
|
||||
|
||||
func unmarshalDenyNode(n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return unmarshalRBACNode(n, rbac.Deny)
|
||||
}
|
||||
|
||||
func unmarshalRBACNode(n *yaml.Node, acc rbac.Access) (out envoyx.NodeSet, err error) {
|
||||
if y7s.IsMapping(n.Content[1]) {
|
||||
return unmarshalNestedRBACNode(n, acc)
|
||||
}
|
||||
|
||||
return unmarshalFlatRBACNode(n, acc)
|
||||
}
|
||||
|
||||
// unmarshalNestedRBACNode handles RBAC rules when they are nested inside a resource
|
||||
//
|
||||
// The edge-case exists since the node doesn't explicitly specify the resource
|
||||
// it belongs to.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// modules:
|
||||
// module1:
|
||||
// name: "module 1"
|
||||
// fields: ...
|
||||
// allow:
|
||||
// role1:
|
||||
// - read
|
||||
// - delete
|
||||
func unmarshalNestedRBACNode(n *yaml.Node, acc rbac.Access) (out envoyx.NodeSet, err error) {
|
||||
// Handles role
|
||||
return out, y7s.EachMap(n, func(role, perm *yaml.Node) error {
|
||||
// Handles operation
|
||||
return y7s.EachMap(perm, func(res, op *yaml.Node) error {
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: &rbac.Rule{
|
||||
Resource: res.Value,
|
||||
Operation: op.Value,
|
||||
Access: acc,
|
||||
},
|
||||
ResourceType: rbac.RuleResourceType,
|
||||
References: envoyx.MergeRefs(
|
||||
map[string]envoyx.Ref{"RoleID": {
|
||||
// Providing resource type as plain text to reduce cross component references
|
||||
ResourceType: "corteza::system:role",
|
||||
Identifiers: envoyx.MakeIdentifiers(role.Value),
|
||||
}},
|
||||
envoyx.SplitResourceIdentifier(res.Value),
|
||||
),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// unmarshalFlatRBACNode handles RBAC rules when they are provided on the root level
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// allow:
|
||||
// role1:
|
||||
// corteza::system/:
|
||||
// - users.search
|
||||
// - users.create
|
||||
func unmarshalFlatRBACNode(n *yaml.Node, acc rbac.Access) (out envoyx.NodeSet, err error) {
|
||||
return out, y7s.EachMap(n, func(role, op *yaml.Node) error {
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: &rbac.Rule{
|
||||
Operation: op.Value,
|
||||
Access: acc,
|
||||
},
|
||||
ResourceType: rbac.RuleResourceType,
|
||||
References: map[string]envoyx.Ref{
|
||||
"RoleID": {
|
||||
// Providing resource type as plain text to reduce cross component references
|
||||
ResourceType: "corteza::system:role",
|
||||
Identifiers: envoyx.MakeIdentifiers(role.Value),
|
||||
},
|
||||
},
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// i18n unmarshal logic
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func unmarshalLocaleNode(n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return out, y7s.EachMap(n, func(lang, loc *yaml.Node) error {
|
||||
langTag := systemTypes.Lang{Tag: language.Make(lang.Value)}
|
||||
|
||||
return y7s.EachMap(loc, func(res, kv *yaml.Node) error {
|
||||
return y7s.EachMap(kv, func(k, msg *yaml.Node) error {
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: &systemTypes.ResourceTranslation{
|
||||
Lang: langTag,
|
||||
K: k.Value,
|
||||
Message: msg.Value,
|
||||
},
|
||||
// Providing resource type as plain text to reduce cross component references
|
||||
ResourceType: "corteza::system:resource-translation",
|
||||
References: envoyx.SplitResourceIdentifier(res.Value),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Utilities
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d YamlDecoder) getReader(ctx context.Context, p envoyx.DecodeParams) (r io.Reader, err error) {
|
||||
aux, ok := p.Params["stream"]
|
||||
if ok {
|
||||
r, ok = aux.(io.Reader)
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// @todo consider adding support for managing files from a location
|
||||
err = fmt.Errorf("YAML decoder expects a stream conforming to io.Reader interface")
|
||||
return
|
||||
}
|
||||
|
||||
func (d *auxYamlDoc) getDocumentContext(n *yaml.Node) (dctx documentContext, err error) {
|
||||
dctx = documentContext{
|
||||
references: make(map[string]string),
|
||||
}
|
||||
|
||||
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
|
||||
// @todo expand when needed. The previous implementation only supported
|
||||
// namespaces on the root of the document.
|
||||
|
||||
if y7s.IsKind(v, yaml.ScalarNode) {
|
||||
dctx.references[k.Value] = v.Value
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func (d *auxYamlDoc) unmarshalYAML(k string, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (d *auxYamlDoc) unmarshalTriggersExtendedNode(dctx documentContext, n *yaml.Node, meta ...*yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return d.unmarshalTriggerNode(dctx, n, meta...)
|
||||
}
|
||||
+327
@@ -0,0 +1,327 @@
|
||||
package envoy
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/y7s"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type (
|
||||
// YamlEncoder is responsible for encoding Corteza resources into
|
||||
// a YAML supported format
|
||||
YamlEncoder struct{}
|
||||
)
|
||||
|
||||
// Encode encodes the given Corteza resources into some YAML supported format
|
||||
//
|
||||
// Encoding should not do any additional processing apart from matching with
|
||||
// dependencies and runtime validation
|
||||
//
|
||||
// Preparation runs validation, default value initialization, matching with
|
||||
// already existing instances, ...
|
||||
//
|
||||
// The prepare function receives a set of nodes grouped by the resource type.
|
||||
// This enables some batching optimization and simplifications when it comes to
|
||||
// matching with existing resources.
|
||||
//
|
||||
// Prepare does not receive any placeholder nodes which are used solely
|
||||
// for dependency resolution.
|
||||
func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt string, nodes envoyx.NodeSet, tt envoyx.Traverser) (err error) {
|
||||
var (
|
||||
out *yaml.Node
|
||||
aux *yaml.Node
|
||||
)
|
||||
_ = aux
|
||||
|
||||
w, err := e.getWriter(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch rt {
|
||||
case types.WorkflowResourceType:
|
||||
aux, err = e.encodeWorkflows(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "workflow", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
case types.TriggerResourceType:
|
||||
aux, err = e.encodeTriggers(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "trigger", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return yaml.NewEncoder(w).Encode(out)
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource workflow
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeWorkflows(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodeWorkflow(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeWorkflow focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodeWorkflow(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.Workflow)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxCreatedBy, err := e.encodeRef(p, res.CreatedBy, "CreatedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedBy, err := e.encodeRef(p, res.DeletedBy, "DeletedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxOwnedBy, err := e.encodeRef(p, res.OwnedBy, "OwnedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxRunAs, err := e.encodeRef(p, res.RunAs, "RunAs", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxUpdatedBy, err := e.encodeRef(p, res.UpdatedBy, "UpdatedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"createdAt", auxCreatedAt,
|
||||
"createdBy", auxCreatedBy,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"deletedBy", auxDeletedBy,
|
||||
"enabled", res.Enabled,
|
||||
"handle", res.Handle,
|
||||
"id", res.ID,
|
||||
"issues", res.Issues,
|
||||
"keepSessions", res.KeepSessions,
|
||||
"meta", res.Meta,
|
||||
"ownedBy", auxOwnedBy,
|
||||
"paths", res.Paths,
|
||||
"runAs", auxRunAs,
|
||||
"scope", res.Scope,
|
||||
"steps", res.Steps,
|
||||
"trace", res.Trace,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
"updatedBy", auxUpdatedBy,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource trigger
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeTriggers(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodeTrigger(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeTrigger focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodeTrigger(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.Trigger)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxCreatedBy, err := e.encodeRef(p, res.CreatedBy, "CreatedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedBy, err := e.encodeRef(p, res.DeletedBy, "DeletedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxOwnedBy, err := e.encodeRef(p, res.OwnedBy, "OwnedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxUpdatedBy, err := e.encodeRef(p, res.UpdatedBy, "UpdatedBy", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxWorkflowID, err := e.encodeRef(p, res.WorkflowID, "WorkflowID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"constraints", res.Constraints,
|
||||
"createdAt", auxCreatedAt,
|
||||
"createdBy", auxCreatedBy,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"deletedBy", auxDeletedBy,
|
||||
"enabled", res.Enabled,
|
||||
"eventType", res.EventType,
|
||||
"id", res.ID,
|
||||
"input", res.Input,
|
||||
"meta", res.Meta,
|
||||
"ownedBy", auxOwnedBy,
|
||||
"resourceType", res.ResourceType,
|
||||
"stepID", res.StepID,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
"updatedBy", auxUpdatedBy,
|
||||
"workflowID", auxWorkflowID,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Encoding utils
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, error) {
|
||||
if t.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tz := p.Config.PreferredTimezone
|
||||
if tz != "" {
|
||||
tzL, err := time.LoadLocation(tz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t = t.In(tzL)
|
||||
}
|
||||
|
||||
ly := p.Config.PreferredTimeLayout
|
||||
if ly == "" {
|
||||
ly = time.RFC3339
|
||||
}
|
||||
|
||||
return t.Format(ly), nil
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeTimestampNil(p envoyx.EncodeParams, t *time.Time) (any, error) {
|
||||
if t == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// @todo timestamp encoding format
|
||||
return e.encodeTimestamp(p, *t)
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRef(p envoyx.EncodeParams, id uint64, field string, node *envoyx.Node, tt envoyx.Traverser) (any, error) {
|
||||
parent := tt.ParentForRef(node, node.References[field])
|
||||
|
||||
// @todo should we panic instead?
|
||||
// for now gracefully fallback to the ID
|
||||
if parent == nil {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
return node.Identifiers.FriendlyIdentifier(), nil
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Utility functions
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) getWriter(p envoyx.EncodeParams) (out io.Writer, err error) {
|
||||
aux, ok := p.Params["writer"]
|
||||
if ok {
|
||||
out, ok = aux.(io.Writer)
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// @todo consider adding support for managing files from a location
|
||||
err = fmt.Errorf("YAML encoder expects a writer conforming to io.Writer interface")
|
||||
return
|
||||
}
|
||||
@@ -80,6 +80,10 @@ session: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
session_id: { goType: "[]uint64", storeIdent: "id", ident: "sessionID" }
|
||||
|
||||
@@ -70,6 +70,16 @@ trigger: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: false
|
||||
identKeyAlias: []
|
||||
}
|
||||
store: {
|
||||
customFilterBuilder: true
|
||||
}
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
deleted: { goType: "filter.State", storeIdent: "deleted_at" }
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/expr"
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
)
|
||||
@@ -48,6 +49,8 @@ type (
|
||||
WorkflowFilter struct {
|
||||
WorkflowID []string `json:"workflowID"`
|
||||
|
||||
Handle string `json:"handle"`
|
||||
|
||||
Query string `json:"query"`
|
||||
|
||||
Deleted filter.State `json:"deleted"`
|
||||
|
||||
@@ -70,16 +70,34 @@ workflow: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["workflows"]
|
||||
extendedResourceDecoders: [{
|
||||
ident: "triggers"
|
||||
expIdent: "Triggers"
|
||||
supportMappedInput: false
|
||||
identKeys: ["triggers"]
|
||||
}]
|
||||
}
|
||||
store: {
|
||||
customFilterBuilder: true
|
||||
}
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
workflow_id: { goType: "[]string", ident: "workflowID", storeIdent: "id" }
|
||||
handle: { goType: "string" }
|
||||
sub_workflow: { goType: "filter.State" }
|
||||
deleted: { goType: "filter.State", storeIdent: "deleted_at" }
|
||||
disabled: { goType: "filter.State", storeIdent: "enabled" }
|
||||
}
|
||||
|
||||
query: ["handle"]
|
||||
byValue: ["workflow_id"]
|
||||
byValue: ["workflow_id", "handle"]
|
||||
byNilState: ["deleted"]
|
||||
byFalseState: ["disabled"]
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullSer
|
||||
|
||||
// Get all requested scopes
|
||||
scopedNodes := make(envoyx.NodeSet, len(p.Filter))
|
||||
{{ if eq .componentIdent "compose" }}
|
||||
for i, a := range wrappedFilters {
|
||||
if a.f.Scope.ResourceType == "" {
|
||||
continue
|
||||
@@ -64,7 +65,7 @@ func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullSer
|
||||
|
||||
// For now the scope can only point to namespace so this will do
|
||||
var nn envoyx.NodeSet
|
||||
nn, err = d.decodeNamespace(ctx, s, dl, d.identToNamespaceFilter(a.f.Scope.Identifiers))
|
||||
nn, err = d.decodeNamespace(ctx, s, dl, d.makeNamespaceFilter(nil, nil, envoyx.ResourceFilter{Identifiers: a.f.Scope.Identifiers}))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -79,6 +80,10 @@ func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullSer
|
||||
|
||||
scopedNodes[i] = nn[0]
|
||||
}
|
||||
{{ else }}
|
||||
// @note skipping scope logic since it's currently only supported within
|
||||
// Compose resources.
|
||||
{{ end }}
|
||||
|
||||
// Get all requested references
|
||||
//
|
||||
@@ -121,7 +126,7 @@ func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullSer
|
||||
for i, wf := range wrappedFilters {
|
||||
switch wf.rt {
|
||||
{{- range .resources -}}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}{{continue}}{{ end -}}
|
||||
{{- if .envoy.omit}}{{continue}}{{ end -}}
|
||||
|
||||
case types.{{.expIdent}}ResourceType:
|
||||
aux, err = d.decode{{.expIdent}}(ctx, s, dl, d.make{{.expIdent}}Filter(scopedNodes[i], refNodes[i], wf.f))
|
||||
@@ -142,7 +147,7 @@ func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullSer
|
||||
}
|
||||
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}
|
||||
{{- if .envoy.omit}}
|
||||
{{continue}}
|
||||
{{ end -}}
|
||||
|
||||
@@ -248,6 +253,7 @@ func (d StoreDecoder) make{{.expIdent}}Filter(scope *envoyx.Node, refs map[strin
|
||||
_ = ar
|
||||
_ = ok
|
||||
{{ range .model.attributes }}
|
||||
{{- if .envoy.store.omitRefFilter }}{{continue}}{{ end }}
|
||||
{{ if eq .dal.type "Ref" }}
|
||||
ar, ok = refs["{{ .expIdent }}"]
|
||||
if ok {
|
||||
|
||||
@@ -46,7 +46,7 @@ func (e StoreEncoder) Prepare(ctx context.Context, p envoyx.EncodeParams, rt str
|
||||
|
||||
switch rt {
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}
|
||||
{{- if .envoy.omit}}
|
||||
{{continue}}
|
||||
{{end -}}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (e StoreEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt stri
|
||||
|
||||
switch rt {
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use) -}}
|
||||
{{- if .envoy.omit -}}
|
||||
{{continue}}
|
||||
{{end}}
|
||||
case types.{{.expIdent}}ResourceType:
|
||||
@@ -93,7 +93,7 @@ func (e StoreEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt stri
|
||||
}
|
||||
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}
|
||||
{{- if .envoy.omit}}
|
||||
{{continue}}
|
||||
{{end}}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ func (d *auxYamlDoc) UnmarshalYAML(n *yaml.Node) (err error) {
|
||||
|
||||
switch kv {
|
||||
{{- range .resources -}}
|
||||
{{- if or .envoy.omit (not .envoy.use) -}}
|
||||
{{- if .envoy.omit -}}
|
||||
{{continue}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (d *auxYamlDoc) UnmarshalYAML(n *yaml.Node) (err error) {
|
||||
|
||||
{{ $rootRes := .resources }}
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}
|
||||
{{- if .envoy.omit}}
|
||||
{{continue}}
|
||||
{{ end -}}
|
||||
|
||||
@@ -175,6 +175,43 @@ func (d *auxYamlDoc) unmarshal{{ .expIdent }}Map(dctx documentContext, n *yaml.N
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{ range .envoy.yaml.extendedResourceDecoders -}}
|
||||
// unmarshal{{.expIdent}}ExtendedSeq unmarshals {{.expIdent}} when provided as a sequence node
|
||||
func (d *auxYamlDoc) unmarshalExtended{{.expIdent}}Seq(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachSeq(n, func(n *yaml.Node) error {
|
||||
aux, err = d.unmarshal{{ .expIdent }}ExtendedNode(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshal{{.expIdent}}ExtendedMap unmarshals {{.expIdent}} when provided as a mapping node
|
||||
//
|
||||
// When map encoded, the map key is used as a preset identifier.
|
||||
// The identifier is passed to the node function as a meta node
|
||||
func (d *auxYamlDoc) unmarshalExtended{{ .expIdent }}Map(dctx documentContext, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
var aux envoyx.NodeSet
|
||||
err = y7s.EachMap(n, func(k, n *yaml.Node) error {
|
||||
aux, err = d.unmarshal{{ .expIdent }}ExtendedNode(dctx, n, k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
// unmarshal{{ .expIdent }}Node is a cookie-cutter function to unmarshal
|
||||
// the yaml node into the corresponding Corteza type & Node
|
||||
func (d *auxYamlDoc) unmarshal{{ .expIdent }}Node(dctx documentContext, n *yaml.Node, meta ...*yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
@@ -425,6 +462,26 @@ func (d *auxYamlDoc) unmarshal{{ .expIdent }}Node(dctx documentContext, n *yaml.
|
||||
{{break}}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{- range .envoy.yaml.extendedResourceDecoders }}
|
||||
{{ $identKeys := .identKeys }}
|
||||
case {{ range $i, $l := $identKeys -}}
|
||||
"{{ $l }}"{{if not (eq $i (sub (len $identKeys) 1))}},{{end}}
|
||||
{{- end}}:
|
||||
default:
|
||||
if y7s.IsSeq(n) {
|
||||
nestedNodes, err = d.unmarshalExtended{{.expIdent}}Seq(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} {{- if .supportMappedInput }} else {
|
||||
nestedNodes, err = d.unmarshalExtended{{.expIdent}}Map(dctx, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}{{ end }}
|
||||
break
|
||||
{{ end -}}
|
||||
}
|
||||
|
||||
// Iterate nested nodes and update their reference to the current resource
|
||||
|
||||
@@ -51,7 +51,7 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin
|
||||
|
||||
switch rt {
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}
|
||||
{{- if .envoy.omit}}
|
||||
{{continue}}
|
||||
{{ end -}}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt strin
|
||||
{{ $rootRes := .resources }}
|
||||
|
||||
{{- range .resources }}
|
||||
{{- if or .envoy.omit (not .envoy.use)}}
|
||||
{{- if .envoy.omit}}
|
||||
{{continue}}
|
||||
{{ end -}}
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ import (
|
||||
// defines a custom field identifier when constructing
|
||||
// resource filters and assigning reference constraints
|
||||
filterRefField: string | *""
|
||||
|
||||
omitRefFilter: bool | *false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +226,11 @@ HandleField: {
|
||||
AttributeUserRef: {
|
||||
goType: "uint64"
|
||||
dal: { type: "Ref", refModelResType: "corteza::system:user", default: 0 }
|
||||
envoy: {
|
||||
store: {
|
||||
omitRefFilter: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SortableTimestampField: {
|
||||
|
||||
@@ -90,10 +90,7 @@ import (
|
||||
}
|
||||
|
||||
envoy?: #resourceEnvoy & {
|
||||
// @todo temporary; easier development on less resources
|
||||
use: bool | *false
|
||||
omit: bool | *false
|
||||
|
||||
$resourceIdent: ident
|
||||
}
|
||||
|
||||
@@ -147,8 +144,6 @@ import (
|
||||
#resourceEnvoy: {
|
||||
$resourceIdent: string
|
||||
|
||||
// @todo remove use, temporary for now
|
||||
use: bool
|
||||
omit: bool
|
||||
|
||||
// Scoped resources prioritize matching with resources in the same scope.
|
||||
@@ -174,13 +169,22 @@ import (
|
||||
supportMappedInput: bool | *true
|
||||
// mappedField controls what identifier the map key represents
|
||||
// @todo this can probably be inferred so consider removing it.
|
||||
mappedField: string
|
||||
mappedField: string | *""
|
||||
|
||||
identKeyLabel: string | *strings.ToLower($resourceIdent)
|
||||
identKeyAlias: [...string] | *[]
|
||||
// identKeys defines all of the identifiers that can be used when
|
||||
// referencing this resource
|
||||
identKeys: [...string] | *([identKeyLabel]+identKeyAlias)
|
||||
|
||||
extendedResourceDecoders: [...{
|
||||
ident: string
|
||||
expIdent: string
|
||||
identKeys: [...string]
|
||||
|
||||
supportMappedInput: bool | *true
|
||||
mappedField: string | *""
|
||||
}] | *[]
|
||||
}
|
||||
|
||||
// store decode/encode configs
|
||||
|
||||
@@ -70,6 +70,10 @@ attachment: {
|
||||
byValue: ["kind", "namespace_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
ident: "composeAttachment"
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ chart: {
|
||||
goType: "uint64",
|
||||
storeIdent: "rel_namespace"
|
||||
dal: { type: "Ref", refModelResType: "corteza::compose:namespace" }
|
||||
envoy: {
|
||||
yaml: {
|
||||
identKeyAlias: ["namespace", "namespace_id", "ns"]
|
||||
}
|
||||
}
|
||||
}
|
||||
name: {
|
||||
sortable: true
|
||||
@@ -29,6 +34,11 @@ chart: {
|
||||
dal: {}
|
||||
omitSetter: true
|
||||
omitGetter: true
|
||||
envoy: {
|
||||
yaml: {
|
||||
customDecoder: true
|
||||
}
|
||||
}
|
||||
}
|
||||
created_at: schema.SortableTimestampNowField
|
||||
updated_at: schema.SortableTimestampNilField
|
||||
@@ -63,6 +73,18 @@ chart: {
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["charts", "chrt"]
|
||||
}
|
||||
store: {
|
||||
extendedRefDecoder: true
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": {}
|
||||
|
||||
Generated
+573
@@ -0,0 +1,573 @@
|
||||
package envoy
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
)
|
||||
|
||||
type (
|
||||
// StoreDecoder is responsible for fetching already stored Corteza resources
|
||||
// which are then managed by envoy and imported via an encoder.
|
||||
StoreDecoder struct{}
|
||||
)
|
||||
|
||||
// Decode returns a set of envoy nodes based on the provided params
|
||||
//
|
||||
// StoreDecoder expects the DecodeParam of `storer` and `dal` which conform
|
||||
// to the store.Storer and dal.FullService interfaces.
|
||||
func (d StoreDecoder) Decode(ctx context.Context, p envoyx.DecodeParams) (out envoyx.NodeSet, err error) {
|
||||
var (
|
||||
s store.Storer
|
||||
dl dal.FullService
|
||||
)
|
||||
|
||||
// @todo we can optionally not require them based on what we're doing
|
||||
if auxS, ok := p.Params["storer"]; ok {
|
||||
s = auxS.(store.Storer)
|
||||
}
|
||||
if auxDl, ok := p.Params["dal"]; ok {
|
||||
dl = auxDl.(dal.FullService)
|
||||
}
|
||||
|
||||
return d.decode(ctx, s, dl, p)
|
||||
}
|
||||
|
||||
func (d StoreDecoder) decode(ctx context.Context, s store.Storer, dl dal.FullService, p envoyx.DecodeParams) (out envoyx.NodeSet, err error) {
|
||||
// Transform passed filters into an ordered structure
|
||||
type (
|
||||
filterWrap struct {
|
||||
rt string
|
||||
f envoyx.ResourceFilter
|
||||
}
|
||||
)
|
||||
wrappedFilters := make([]filterWrap, 0, len(p.Filter))
|
||||
for rt, f := range p.Filter {
|
||||
wrappedFilters = append(wrappedFilters, filterWrap{rt: rt, f: f})
|
||||
}
|
||||
|
||||
// Get all requested scopes
|
||||
scopedNodes := make(envoyx.NodeSet, len(p.Filter))
|
||||
|
||||
for i, a := range wrappedFilters {
|
||||
if a.f.Scope.ResourceType == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// For now the scope can only point to namespace so this will do
|
||||
var nn envoyx.NodeSet
|
||||
nn, err = d.decodeNamespace(ctx, s, dl, d.makeNamespaceFilter(nil, nil, envoyx.ResourceFilter{Identifiers: a.f.Scope.Identifiers}))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(nn) > 1 {
|
||||
err = fmt.Errorf("ambiguous scope %v", a.f.Scope)
|
||||
return
|
||||
}
|
||||
if len(nn) == 0 {
|
||||
err = fmt.Errorf("invalid scope: resource not found %v", a.f)
|
||||
return
|
||||
}
|
||||
|
||||
scopedNodes[i] = nn[0]
|
||||
}
|
||||
|
||||
// Get all requested references
|
||||
//
|
||||
// Keep an index for the Node and one for the reference to make our
|
||||
// lives easier.
|
||||
refNodes := make([]map[string]*envoyx.Node, len(p.Filter))
|
||||
refRefs := make([]map[string]envoyx.Ref, len(p.Filter))
|
||||
for i, a := range wrappedFilters {
|
||||
if len(a.f.Refs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
auxr := make(map[string]*envoyx.Node, len(a.f.Refs))
|
||||
auxa := make(map[string]envoyx.Ref)
|
||||
for field, ref := range a.f.Refs {
|
||||
f := ref.ResourceFilter()
|
||||
aux, err := d.decode(ctx, s, dl, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Filter: f,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(aux) == 0 {
|
||||
return nil, fmt.Errorf("invalid reference %v", ref)
|
||||
}
|
||||
if len(aux) > 1 {
|
||||
return nil, fmt.Errorf("ambiguous reference: too many resources returned %v", a.f)
|
||||
}
|
||||
|
||||
auxr[field] = aux[0]
|
||||
auxa[field] = aux[0].ToRef()
|
||||
}
|
||||
|
||||
refNodes[i] = auxr
|
||||
refRefs[i] = auxa
|
||||
}
|
||||
|
||||
var aux envoyx.NodeSet
|
||||
for i, wf := range wrappedFilters {
|
||||
switch wf.rt {
|
||||
case types.ChartResourceType:
|
||||
aux, err = d.decodeChart(ctx, s, dl, d.makeChartFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
case types.ModuleResourceType:
|
||||
aux, err = d.decodeModule(ctx, s, dl, d.makeModuleFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
case types.ModuleFieldResourceType:
|
||||
aux, err = d.decodeModuleField(ctx, s, dl, d.makeModuleFieldFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
case types.NamespaceResourceType:
|
||||
aux, err = d.decodeNamespace(ctx, s, dl, d.makeNamespaceFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
case types.PageResourceType:
|
||||
aux, err = d.decodePage(ctx, s, dl, d.makePageFilter(scopedNodes[i], refNodes[i], wf.f))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, a := range aux {
|
||||
a.Identifiers = a.Identifiers.Merge(wf.f.Identifiers)
|
||||
a.References = envoyx.MergeRefs(a.References, refRefs[i])
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource chart
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodeChart(ctx context.Context, s store.Storer, dl dal.FullService, f types.ChartFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchComposeCharts(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.Handle,
|
||||
r.ID,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{
|
||||
// Handle references
|
||||
"NamespaceID": envoyx.Ref{
|
||||
ResourceType: "corteza::compose:namespace",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.NamespaceID),
|
||||
},
|
||||
}
|
||||
|
||||
refs = envoyx.MergeRefs(refs, d.decodeChartRefs(r))
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
scope = envoyx.Scope{
|
||||
ResourceType: refs["NamespaceID"].ResourceType,
|
||||
Identifiers: refs["NamespaceID"].Identifiers,
|
||||
}
|
||||
for k, ref := range refs {
|
||||
ref.Scope = scope
|
||||
refs[k] = ref
|
||||
}
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.ChartResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) makeChartFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.ChartFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.Idents()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
out.ChartID = ids
|
||||
|
||||
if len(hh) > 0 {
|
||||
out.Handle = hh[0]
|
||||
}
|
||||
|
||||
// Refs
|
||||
var (
|
||||
ar *envoyx.Node
|
||||
ok bool
|
||||
)
|
||||
_ = ar
|
||||
_ = ok
|
||||
|
||||
ar, ok = refs["NamespaceID"]
|
||||
if ok {
|
||||
out.NamespaceID = ar.Resource.GetID()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource module
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodeModule(ctx context.Context, s store.Storer, dl dal.FullService, f types.ModuleFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchComposeModules(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.Handle,
|
||||
r.ID,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{
|
||||
// Handle references
|
||||
"NamespaceID": envoyx.Ref{
|
||||
ResourceType: "corteza::compose:namespace",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.NamespaceID),
|
||||
},
|
||||
}
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
scope = envoyx.Scope{
|
||||
ResourceType: refs["NamespaceID"].ResourceType,
|
||||
Identifiers: refs["NamespaceID"].Identifiers,
|
||||
}
|
||||
for k, ref := range refs {
|
||||
ref.Scope = scope
|
||||
refs[k] = ref
|
||||
}
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.ModuleResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
aux, err := d.extendedModuleDecoder(ctx, s, dl, f, out)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
out = append(out, aux...)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) makeModuleFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.ModuleFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.Idents()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
out.ModuleID = ids
|
||||
|
||||
if len(hh) > 0 {
|
||||
out.Handle = hh[0]
|
||||
}
|
||||
|
||||
// Refs
|
||||
var (
|
||||
ar *envoyx.Node
|
||||
ok bool
|
||||
)
|
||||
_ = ar
|
||||
_ = ok
|
||||
|
||||
ar, ok = refs["NamespaceID"]
|
||||
if ok {
|
||||
out.NamespaceID = ar.Resource.GetID()
|
||||
}
|
||||
|
||||
out = d.extendModuleFilter(scope, refs, auxf, out)
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource moduleField
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodeModuleField(ctx context.Context, s store.Storer, dl dal.FullService, f types.ModuleFieldFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchComposeModuleFields(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.ID,
|
||||
r.Name,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{
|
||||
// Handle references
|
||||
"ModuleID": envoyx.Ref{
|
||||
ResourceType: "corteza::compose:module",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.ModuleID),
|
||||
},
|
||||
}
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
scope = envoyx.Scope{
|
||||
ResourceType: refs["NamespaceID"].ResourceType,
|
||||
Identifiers: refs["NamespaceID"].Identifiers,
|
||||
}
|
||||
for k, ref := range refs {
|
||||
ref.Scope = scope
|
||||
refs[k] = ref
|
||||
}
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.ModuleFieldResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Resource should define a custom filter builder
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource namespace
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodeNamespace(ctx context.Context, s store.Storer, dl dal.FullService, f types.NamespaceFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchComposeNamespaces(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.ID,
|
||||
r.Slug,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{}
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
scope = envoyx.Scope{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: ii,
|
||||
}
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) makeNamespaceFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.NamespaceFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.Idents()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
out.NamespaceID = ids
|
||||
|
||||
if len(hh) > 0 {
|
||||
out.Slug = hh[0]
|
||||
}
|
||||
|
||||
// Refs
|
||||
var (
|
||||
ar *envoyx.Node
|
||||
ok bool
|
||||
)
|
||||
_ = ar
|
||||
_ = ok
|
||||
|
||||
out = d.extendNamespaceFilter(scope, refs, auxf, out)
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource page
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (d StoreDecoder) decodePage(ctx context.Context, s store.Storer, dl dal.FullService, f types.PageFilter) (out envoyx.NodeSet, err error) {
|
||||
// @todo this might need to be improved.
|
||||
// Currently, no resource is vast enough to pose a problem.
|
||||
rr, _, err := store.SearchComposePages(ctx, s, f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range rr {
|
||||
// Identifiers
|
||||
ii := envoyx.MakeIdentifiers(
|
||||
r.Handle,
|
||||
r.ID,
|
||||
)
|
||||
|
||||
refs := map[string]envoyx.Ref{
|
||||
// Handle references
|
||||
"ModuleID": envoyx.Ref{
|
||||
ResourceType: "corteza::compose:module",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.ModuleID),
|
||||
},
|
||||
// Handle references
|
||||
"NamespaceID": envoyx.Ref{
|
||||
ResourceType: "corteza::compose:namespace",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.NamespaceID),
|
||||
},
|
||||
// Handle references
|
||||
"SelfID": envoyx.Ref{
|
||||
ResourceType: "corteza::compose:page",
|
||||
Identifiers: envoyx.MakeIdentifiers(r.SelfID),
|
||||
},
|
||||
}
|
||||
|
||||
var scope envoyx.Scope
|
||||
|
||||
scope = envoyx.Scope{
|
||||
ResourceType: refs["NamespaceID"].ResourceType,
|
||||
Identifiers: refs["NamespaceID"].Identifiers,
|
||||
}
|
||||
for k, ref := range refs {
|
||||
ref.Scope = scope
|
||||
refs[k] = ref
|
||||
}
|
||||
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: r,
|
||||
|
||||
ResourceType: types.PageResourceType,
|
||||
Identifiers: ii,
|
||||
References: refs,
|
||||
Scope: scope,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) makePageFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.PageFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.Idents()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
out.PageID = ids
|
||||
|
||||
if len(hh) > 0 {
|
||||
out.Handle = hh[0]
|
||||
}
|
||||
|
||||
// Refs
|
||||
var (
|
||||
ar *envoyx.Node
|
||||
ok bool
|
||||
)
|
||||
_ = ar
|
||||
_ = ok
|
||||
|
||||
ar, ok = refs["ModuleID"]
|
||||
if ok {
|
||||
out.ModuleID = ar.Resource.GetID()
|
||||
}
|
||||
|
||||
ar, ok = refs["NamespaceID"]
|
||||
if ok {
|
||||
out.NamespaceID = ar.Resource.GetID()
|
||||
}
|
||||
|
||||
ar, ok = refs["SelfID"]
|
||||
if ok {
|
||||
out.ParentID = ar.Resource.GetID()
|
||||
}
|
||||
|
||||
out = d.extendPageFilter(scope, refs, auxf, out)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
)
|
||||
|
||||
func (d StoreDecoder) extendNamespaceFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter, base types.NamespaceFilter) (out types.NamespaceFilter) {
|
||||
out = base
|
||||
|
||||
if scope == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if scope.ResourceType == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Overwrite it
|
||||
out.NamespaceID = []uint64{scope.Resource.GetID()}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) extendModuleFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter, base types.ModuleFilter) (out types.ModuleFilter) {
|
||||
out = base
|
||||
|
||||
if scope == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if scope.ResourceType == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Overwrite it
|
||||
out.NamespaceID = scope.Resource.GetID()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) extendPageFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter, base types.PageFilter) (out types.PageFilter) {
|
||||
out = base
|
||||
|
||||
if scope == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if scope.ResourceType == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// Overwrite it
|
||||
out.NamespaceID = scope.Resource.GetID()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) makeModuleFieldFilter(scope *envoyx.Node, refs map[string]*envoyx.Node, auxf envoyx.ResourceFilter) (out types.ModuleFieldFilter) {
|
||||
out.Limit = auxf.Limit
|
||||
|
||||
ids, hh := auxf.Identifiers.Idents()
|
||||
_ = ids
|
||||
_ = hh
|
||||
|
||||
// Refs
|
||||
var (
|
||||
ar *envoyx.Node
|
||||
ok bool
|
||||
)
|
||||
_ = ar
|
||||
_ = ok
|
||||
|
||||
// ar, ok = refs["ModuleID"]
|
||||
// if ok {
|
||||
// out.ModuleID = ar.Resource.GetID()
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) extendedModuleDecoder(ctx context.Context, s store.Storer, dl dal.FullService, f types.ModuleFilter, base envoyx.NodeSet) (out envoyx.NodeSet, err error) {
|
||||
var ff types.ModuleFieldSet
|
||||
|
||||
for _, b := range base {
|
||||
ff, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{b.Resource.GetID()}})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// No need to assign them under the module since we're working with nodes now
|
||||
for _, f := range ff {
|
||||
out = append(out, &envoyx.Node{
|
||||
Resource: f,
|
||||
|
||||
ResourceType: types.ModuleFieldResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers(f.ID, f.Name),
|
||||
References: envoyx.MergeRefs(b.References, map[string]envoyx.Ref{
|
||||
"ModuleID": b.ToRef(),
|
||||
}),
|
||||
Scope: b.Scope,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d StoreDecoder) decodeChartRefs(c *types.Chart) (refs map[string]envoyx.Ref) {
|
||||
|
||||
// @todo
|
||||
return
|
||||
}
|
||||
Generated
+1021
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
func (e StoreEncoder) setChartDefaults(res *types.Chart) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateChart(*types.Chart) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setModuleDefaults(res *types.Module) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateModule(*types.Module) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setModuleFieldDefaults(res *types.ModuleField) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateModuleField(*types.ModuleField) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setNamespaceDefaults(res *types.Namespace) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateNamespace(*types.Namespace) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setPageDefaults(res *types.Page) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validatePage(*types.Page) (err error) {
|
||||
return
|
||||
}
|
||||
Generated
+1596
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/y7s"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func unmarshalChartConfigNode(r *types.Chart, n *yaml.Node) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
|
||||
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
|
||||
if k.Value != "reports" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if y7s.IsSeq(v) {
|
||||
var (
|
||||
auxRefs = make(map[string]envoyx.Ref)
|
||||
auxIdents envoyx.Identifiers
|
||||
i = -1
|
||||
)
|
||||
err = y7s.EachSeq(v, func(c *yaml.Node) error {
|
||||
i++
|
||||
|
||||
auxRefs, auxIdents, err = unmarshalChartConfigReportNode(r, c, i)
|
||||
refs = envoyx.MergeRefs(refs, auxRefs)
|
||||
idents = idents.Merge(auxIdents)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
refs, idents, err = unmarshalChartConfigReportNode(r, v, 0)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func unmarshalChartConfigReportNode(r *types.Chart, n *yaml.Node, index int) (refs map[string]envoyx.Ref, idents envoyx.Identifiers, err error) {
|
||||
err = y7s.EachMap(n, func(k, v *yaml.Node) error {
|
||||
switch strings.ToLower(k.Value) {
|
||||
case "module", "mod", "moduleid", "module_id":
|
||||
var auxi any
|
||||
y7s.DecodeScalar(v, "moduleID", &auxi)
|
||||
refs = map[string]envoyx.Ref{
|
||||
fmt.Sprintf("Config.Reports.%d.ModuleID", index): {
|
||||
ResourceType: types.ModuleResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers(auxi),
|
||||
},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (d *auxYamlDoc) unmarshalYAML(k string, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return
|
||||
}
|
||||
Generated
+525
@@ -0,0 +1,525 @@
|
||||
package envoy
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/y7s"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type (
|
||||
// YamlEncoder is responsible for encoding Corteza resources into
|
||||
// a YAML supported format
|
||||
YamlEncoder struct{}
|
||||
)
|
||||
|
||||
// Encode encodes the given Corteza resources into some YAML supported format
|
||||
//
|
||||
// Encoding should not do any additional processing apart from matching with
|
||||
// dependencies and runtime validation
|
||||
//
|
||||
// Preparation runs validation, default value initialization, matching with
|
||||
// already existing instances, ...
|
||||
//
|
||||
// The prepare function receives a set of nodes grouped by the resource type.
|
||||
// This enables some batching optimization and simplifications when it comes to
|
||||
// matching with existing resources.
|
||||
//
|
||||
// Prepare does not receive any placeholder nodes which are used solely
|
||||
// for dependency resolution.
|
||||
func (e YamlEncoder) Encode(ctx context.Context, p envoyx.EncodeParams, rt string, nodes envoyx.NodeSet, tt envoyx.Traverser) (err error) {
|
||||
var (
|
||||
out *yaml.Node
|
||||
aux *yaml.Node
|
||||
)
|
||||
_ = aux
|
||||
|
||||
w, err := e.getWriter(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch rt {
|
||||
case types.ChartResourceType:
|
||||
aux, err = e.encodeCharts(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "chart", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case types.ModuleResourceType:
|
||||
aux, err = e.encodeModules(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "module", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case types.ModuleFieldResourceType:
|
||||
aux, err = e.encodeModuleFields(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "moduleField", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case types.NamespaceResourceType:
|
||||
aux, err = e.encodeNamespaces(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "namespace", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case types.PageResourceType:
|
||||
aux, err = e.encodePages(ctx, p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Root level resources are always encoded as a map
|
||||
out, err = y7s.AddMap(out, "page", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return yaml.NewEncoder(w).Encode(out)
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource chart
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeCharts(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodeChart(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeChart focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodeChart(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.Chart)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxNamespaceID, err := e.encodeRef(p, res.NamespaceID, "NamespaceID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"config", res.Config,
|
||||
"createdAt", auxCreatedAt,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"handle", res.Handle,
|
||||
"id", res.ID,
|
||||
"name", res.Name,
|
||||
"namespaceID", auxNamespaceID,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource module
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeModules(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodeModule(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeModule focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodeModule(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.Module)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxNamespaceID, err := e.encodeRef(p, res.NamespaceID, "NamespaceID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"config", e.encodeModuleConfig(p, res.Config),
|
||||
"createdAt", auxCreatedAt,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"fields", res.Fields,
|
||||
"handle", res.Handle,
|
||||
"id", res.ID,
|
||||
"meta", res.Meta,
|
||||
"name", res.Name,
|
||||
"namespaceID", auxNamespaceID,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource moduleField
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeModuleFields(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodeModuleField(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeModuleField focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodeModuleField(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.ModuleField)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxModuleID, err := e.encodeRef(p, res.ModuleID, "ModuleID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"config", res.Config,
|
||||
"createdAt", auxCreatedAt,
|
||||
"defaultValue", res.DefaultValue,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"expressions", res.Expressions,
|
||||
"id", res.ID,
|
||||
"kind", res.Kind,
|
||||
"label", res.Label,
|
||||
"moduleID", auxModuleID,
|
||||
"multi", res.Multi,
|
||||
"name", res.Name,
|
||||
"options", res.Options,
|
||||
"place", res.Place,
|
||||
"required", res.Required,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource namespace
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeNamespaces(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodeNamespace(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodeNamespace focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodeNamespace(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.Namespace)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"createdAt", auxCreatedAt,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"enabled", res.Enabled,
|
||||
"id", res.ID,
|
||||
"meta", res.Meta,
|
||||
"name", res.Name,
|
||||
"slug", res.Slug,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Functions for resource page
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodePages(ctx context.Context, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
var aux *yaml.Node
|
||||
for _, n := range nodes {
|
||||
aux, err = e.encodePage(ctx, p, n, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddSeq(out, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// encodePage focuses on the specific resource invoked by the Encode method
|
||||
func (e YamlEncoder) encodePage(ctx context.Context, p envoyx.EncodeParams, node *envoyx.Node, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
res := node.Resource.(*types.Page)
|
||||
|
||||
// Pre-compute some map values so we can omit error checking when encoding yaml nodes
|
||||
|
||||
auxCreatedAt, err := e.encodeTimestamp(p, res.CreatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxDeletedAt, err := e.encodeTimestampNil(p, res.DeletedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxModuleID, err := e.encodeRef(p, res.ModuleID, "ModuleID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxNamespaceID, err := e.encodeRef(p, res.NamespaceID, "NamespaceID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auxSelfID, err := e.encodeRef(p, res.SelfID, "SelfID", node, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
auxUpdatedAt, err := e.encodeTimestampNil(p, res.UpdatedAt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
"blocks", res.Blocks,
|
||||
"children", res.Children,
|
||||
"config", res.Config,
|
||||
"createdAt", auxCreatedAt,
|
||||
"deletedAt", auxDeletedAt,
|
||||
"description", res.Description,
|
||||
"handle", res.Handle,
|
||||
"id", res.ID,
|
||||
"moduleID", auxModuleID,
|
||||
"namespaceID", auxNamespaceID,
|
||||
"selfID", auxSelfID,
|
||||
"title", res.Title,
|
||||
"updatedAt", auxUpdatedAt,
|
||||
"visible", res.Visible,
|
||||
"weight", res.Weight,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle nested resources
|
||||
var aux *yaml.Node
|
||||
_ = aux
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Encoding utils
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) encodeTimestamp(p envoyx.EncodeParams, t time.Time) (any, error) {
|
||||
if t.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
tz := p.Config.PreferredTimezone
|
||||
if tz != "" {
|
||||
tzL, err := time.LoadLocation(tz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t = t.In(tzL)
|
||||
}
|
||||
|
||||
ly := p.Config.PreferredTimeLayout
|
||||
if ly == "" {
|
||||
ly = time.RFC3339
|
||||
}
|
||||
|
||||
return t.Format(ly), nil
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeTimestampNil(p envoyx.EncodeParams, t *time.Time) (any, error) {
|
||||
if t == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// @todo timestamp encoding format
|
||||
return e.encodeTimestamp(p, *t)
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRef(p envoyx.EncodeParams, id uint64, field string, node *envoyx.Node, tt envoyx.Traverser) (any, error) {
|
||||
parent := tt.ParentForRef(node, node.References[field])
|
||||
|
||||
// @todo should we panic instead?
|
||||
// for now gracefully fallback to the ID
|
||||
if parent == nil {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
return node.Identifiers.FriendlyIdentifier(), nil
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
// Utility functions
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
func (e YamlEncoder) getWriter(p envoyx.EncodeParams) (out io.Writer, err error) {
|
||||
aux, ok := p.Params["writer"]
|
||||
if ok {
|
||||
out, ok = aux.(io.Writer)
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// @todo consider adding support for managing files from a location
|
||||
err = fmt.Errorf("YAML encoder expects a writer conforming to io.Writer interface")
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
)
|
||||
|
||||
func (e YamlEncoder) encodeModuleConfig(p envoyx.EncodeParams, cfg types.ModuleConfig) any {
|
||||
|
||||
// @todo...
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -19,6 +19,12 @@ module: {
|
||||
goType: "uint64",
|
||||
storeIdent: "rel_namespace"
|
||||
dal: { type: "Ref", refModelResType: "corteza::compose:namespace" }
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
identKeyAlias: ["namespace", "namespace_id", "ns", "ns_id"]
|
||||
}
|
||||
}
|
||||
}
|
||||
handle: schema.HandleField
|
||||
name: {
|
||||
@@ -36,6 +42,11 @@ module: {
|
||||
dal: { type: "JSON", defaultEmptyObject: true }
|
||||
omitSetter: true
|
||||
omitGetter: true
|
||||
envoy: {
|
||||
yaml: {
|
||||
customEncoder: true
|
||||
}
|
||||
}
|
||||
}
|
||||
fields: {
|
||||
goType: "types.ModuleFieldSet",
|
||||
@@ -72,6 +83,19 @@ module: {
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["modules", "mod"]
|
||||
}
|
||||
store: {
|
||||
extendedFilterBuilder: true
|
||||
extendedDecoder: true
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": {}
|
||||
|
||||
@@ -13,7 +13,11 @@ moduleField: {
|
||||
model: {
|
||||
ident: "compose_module_field"
|
||||
attributes: {
|
||||
id: schema.IdField
|
||||
id: schema.IdField & {
|
||||
envoy: {
|
||||
identifier: true
|
||||
}
|
||||
}
|
||||
module_id: {
|
||||
ident: "moduleID",
|
||||
goType: "uint64",
|
||||
@@ -39,6 +43,10 @@ moduleField: {
|
||||
name: {
|
||||
sortable: true
|
||||
dal: {}
|
||||
} & {
|
||||
envoy: {
|
||||
identifier: true
|
||||
}
|
||||
}
|
||||
label: {
|
||||
sortable: true
|
||||
@@ -104,6 +112,19 @@ moduleField: {
|
||||
checkFn: false
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Name"
|
||||
identKeyAlias: ["module_fields", "modulefields", "fields"]
|
||||
}
|
||||
store: {
|
||||
handleField: ""
|
||||
customFilterBuilder: true
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"record.value.read": description: "Read field value on records"
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace: {
|
||||
sortable: true,
|
||||
goType: "string"
|
||||
dal: {}
|
||||
envoy: {
|
||||
identifier: true
|
||||
}
|
||||
}
|
||||
enabled: {
|
||||
goType: "bool"
|
||||
@@ -45,7 +48,7 @@ namespace: {
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
namespace_id: { goType: "[]uint64", ident: "namespaceID" }
|
||||
namespace_id: { goType: "[]uint64", ident: "namespaceID", storeIdent: "id" }
|
||||
slug: { goType: "string" }
|
||||
name: { goType: "string" }
|
||||
deleted: { goType: "filter.State", storeIdent: "deleted_at" }
|
||||
@@ -56,6 +59,19 @@ namespace: {
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Slug"
|
||||
identKeyAlias: ["namespaces", "ns"]
|
||||
}
|
||||
store: {
|
||||
handleField: "Slug"
|
||||
extendedFilterBuilder: true
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": {}
|
||||
|
||||
+19
-1
@@ -24,6 +24,11 @@ page: {
|
||||
goType: "uint64",
|
||||
dal: { type: "Ref", refModelResType: "corteza::compose:page" }
|
||||
sortable: true
|
||||
envoy: {
|
||||
store: {
|
||||
filterRefField: "ParentID"
|
||||
}
|
||||
}
|
||||
}
|
||||
module_id: {
|
||||
ident: "moduleID",
|
||||
@@ -87,6 +92,7 @@ page: {
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
page_id: { goType: "uint64", ident: "pageID", storeIdent: "id" }
|
||||
namespace_id: { goType: "uint64", ident: "namespaceID", storeIdent: "rel_namespace" }
|
||||
parent_id: { goType: "uint64", ident: "parentID" }
|
||||
module_id: { goType: "uint64", ident: "moduleID", storeIdent: "rel_module" }
|
||||
@@ -97,10 +103,22 @@ page: {
|
||||
}
|
||||
|
||||
query: ["handle", "title", "description"]
|
||||
byValue: ["handle", "namespace_id", "module_id"]
|
||||
byValue: ["page_id", "handle", "namespace_id", "module_id"]
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["pages", "pg"]
|
||||
}
|
||||
store: {
|
||||
extendedFilterBuilder: true
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": {}
|
||||
|
||||
@@ -66,6 +66,11 @@ record: {
|
||||
}
|
||||
}
|
||||
|
||||
// @todo tmp
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
defaultGetter: true
|
||||
defaultSetter: true
|
||||
|
||||
|
||||
@@ -38,4 +38,8 @@ record_revision: {
|
||||
"primary": { attribute: "id" }
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,13 +143,14 @@ type (
|
||||
}
|
||||
|
||||
PageFilter struct {
|
||||
NamespaceID uint64 `json:"namespaceID,string"`
|
||||
ParentID uint64 `json:"parentID,string,omitempty"`
|
||||
ModuleID uint64 `json:"moduleID,string,omitempty"`
|
||||
Root bool `json:"root,omitempty"`
|
||||
Handle string `json:"handle"`
|
||||
Title string `json:"title"`
|
||||
Query string `json:"query"`
|
||||
PageID []uint64 `json:"pageID,string"`
|
||||
NamespaceID uint64 `json:"namespaceID,string"`
|
||||
ParentID uint64 `json:"parentID,string,omitempty"`
|
||||
ModuleID uint64 `json:"moduleID,string,omitempty"`
|
||||
Root bool `json:"root,omitempty"`
|
||||
Handle string `json:"handle"`
|
||||
Title string `json:"title"`
|
||||
Query string `json:"query"`
|
||||
|
||||
LabeledIDs []uint64 `json:"-"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
@@ -71,6 +71,9 @@ exposedModule: {
|
||||
byValue: ["compose_module_id", "compose_namespace_id", "node_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
|
||||
@@ -54,6 +54,10 @@ moduleMapping: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
compose_module_id: { goType: "uint64", ident: "composeModuleID", storeIdent: "rel_compose_module" }
|
||||
|
||||
@@ -57,6 +57,10 @@ node: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
name: { goType: "string" }
|
||||
|
||||
@@ -53,6 +53,10 @@ nodeSync: {
|
||||
byValue: ["node_id", "module_id", "sync_status", "sync_type"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
ident: "federationNodeSync"
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ sharedModule: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
node_id: { goType: "uint64", ident: "nodeID", storeIdent: "rel_node" }
|
||||
|
||||
@@ -222,6 +222,16 @@ func (ii Identifiers) Add(vv ...any) (out Identifiers) {
|
||||
return ii
|
||||
}
|
||||
|
||||
func (ii Identifiers) IdentsAsStrings() (ids, rest []string) {
|
||||
aux, rest := ii.Idents()
|
||||
|
||||
for _, a := range aux {
|
||||
ids = append(ids, strconv.FormatUint(a, 10))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Idents returns a slice of numeric and text identifiers
|
||||
func (ii Identifiers) Idents() (ints []uint64, rest []string) {
|
||||
var aux uint64
|
||||
|
||||
Generated
+36
@@ -0,0 +1,36 @@
|
||||
package envoyx
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import ()
|
||||
|
||||
var (
|
||||
// needyResources is a list of resources that require a parent resource
|
||||
//
|
||||
// This list is primarily used when figuring out what nodes the dep. graph
|
||||
// should return when traversing.
|
||||
needyResources = map[string]bool{
|
||||
|
||||
"corteza::compose:chart": true,
|
||||
"corteza::compose:module": true,
|
||||
"corteza::compose:module-field": true,
|
||||
|
||||
"corteza::compose:page": true,
|
||||
"corteza::compose:record": true,
|
||||
|
||||
"corteza::federation:exposed-module": true,
|
||||
"corteza::federation:module-mapping": true,
|
||||
|
||||
"corteza::federation:shared-module": true,
|
||||
}
|
||||
|
||||
// superNeedyResources is the second level of filtering in case the first
|
||||
// pass removes everything
|
||||
superNeedyResources = map[string]bool{
|
||||
"corteza::compose:module-field": true,
|
||||
}
|
||||
)
|
||||
+25
-1
@@ -203,6 +203,10 @@ func ApigwFilterFilter(d drivers.Dialect, f systemType.ApigwFilterFilter) (ee []
|
||||
ee = append(ee, expr)
|
||||
}
|
||||
|
||||
if f.ApigwFilterID > 0 {
|
||||
ee = append(ee, goqu.C("id").Eq(f.ApigwFilterID))
|
||||
}
|
||||
|
||||
if f.RouteID > 0 {
|
||||
ee = append(ee, goqu.C("rel_route").Eq(f.RouteID))
|
||||
}
|
||||
@@ -227,6 +231,10 @@ func ApigwRouteFilter(d drivers.Dialect, f systemType.ApigwRouteFilter) (ee []go
|
||||
ee = append(ee, expr)
|
||||
}
|
||||
|
||||
if len(f.ApigwrouteID) > 0 {
|
||||
ee = append(ee, goqu.C("id").In(f.ApigwrouteID))
|
||||
}
|
||||
|
||||
if val := strings.TrimSpace(f.Route); len(val) > 0 {
|
||||
ee = append(ee, goqu.C("id").Eq(f.Route))
|
||||
}
|
||||
@@ -456,6 +464,10 @@ func AutomationWorkflowFilter(d drivers.Dialect, f automationType.WorkflowFilter
|
||||
ee = append(ee, goqu.C("id").In(ss))
|
||||
}
|
||||
|
||||
if val := strings.TrimSpace(f.Handle); len(val) > 0 {
|
||||
ee = append(ee, goqu.C("handle").Eq(f.Handle))
|
||||
}
|
||||
|
||||
if len(f.LabeledIDs) > 0 {
|
||||
ee = append(ee, goqu.I("id").In(f.LabeledIDs))
|
||||
}
|
||||
@@ -601,7 +613,7 @@ func ComposeNamespaceFilter(d drivers.Dialect, f composeType.NamespaceFilter) (e
|
||||
}
|
||||
|
||||
if len(f.NamespaceID) > 0 {
|
||||
ee = append(ee, goqu.C("namespace_id").In(f.NamespaceID))
|
||||
ee = append(ee, goqu.C("id").In(f.NamespaceID))
|
||||
}
|
||||
|
||||
if val := strings.TrimSpace(f.Name); len(val) > 0 {
|
||||
@@ -639,6 +651,10 @@ func ComposePageFilter(d drivers.Dialect, f composeType.PageFilter) (ee []goqu.E
|
||||
ee = append(ee, expr)
|
||||
}
|
||||
|
||||
if f.PageID > 0 {
|
||||
ee = append(ee, goqu.C("id").Eq(f.PageID))
|
||||
}
|
||||
|
||||
if val := strings.TrimSpace(f.Handle); len(val) > 0 {
|
||||
ee = append(ee, goqu.C("handle").Eq(f.Handle))
|
||||
}
|
||||
@@ -739,6 +755,10 @@ func DalSensitivityLevelFilter(d drivers.Dialect, f systemType.DalSensitivityLev
|
||||
ee = append(ee, goqu.C("id").In(f.SensitivityLevelID))
|
||||
}
|
||||
|
||||
if val := strings.TrimSpace(f.Handle); len(val) > 0 {
|
||||
ee = append(ee, goqu.C("handle").Eq(f.Handle))
|
||||
}
|
||||
|
||||
return ee, f, err
|
||||
}
|
||||
|
||||
@@ -982,6 +1002,10 @@ func QueueFilter(d drivers.Dialect, f systemType.QueueFilter) (ee []goqu.Express
|
||||
ee = append(ee, expr)
|
||||
}
|
||||
|
||||
if f.QueueID > 0 {
|
||||
ee = append(ee, goqu.C("id").Eq(f.QueueID))
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
ee = append(ee, goqu.Or(
|
||||
goqu.C("queue").ILike("%"+f.Query+"%"),
|
||||
|
||||
@@ -15,6 +15,11 @@ apigw_filter: {
|
||||
route: {
|
||||
sortable: true, goType: "uint64", storeIdent: "rel_route"
|
||||
dal: { type: "Ref", refModelResType: "corteza::system:apigw-route" }
|
||||
envoy: {
|
||||
store: {
|
||||
omitRefFilter: true
|
||||
}
|
||||
}
|
||||
}
|
||||
weight: {
|
||||
sortable: true,
|
||||
@@ -53,14 +58,24 @@ apigw_filter: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: false
|
||||
}
|
||||
store: {
|
||||
handleField: ""
|
||||
}
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
apigw_filter_id: {goType: "uint64", ident: "apigwFilterID", storeIdent: "id"}
|
||||
route_id: {goType: "uint64", ident: "routeID", storeIdent: "rel_route"}
|
||||
deleted: {goType: "filter.State", storeIdent: "deleted_at"}
|
||||
disabled: {goType: "filter.State", storeIdent: "enabled"}
|
||||
}
|
||||
|
||||
byValue: ["route_id"]
|
||||
byValue: ["apigw_filter_id", "route_id"]
|
||||
byNilState: ["deleted"]
|
||||
byFalseState: ["disabled"]
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ apigw_route: {
|
||||
// @todo what does this do?
|
||||
refModelResType: "corteza::system:apigw-group"
|
||||
}
|
||||
envoy: {
|
||||
store: {
|
||||
omitRefFilter: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
created_at: schema.SortableTimestampNowField
|
||||
@@ -55,8 +60,20 @@ apigw_route: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Endpoint"
|
||||
identKeyAlias: ["endpoints"]
|
||||
}
|
||||
store: {
|
||||
handleField: "Endpoint"
|
||||
}
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
apigw_route_id: { goType: "[]uint64", ident: "apigwrouteID", storeIdent: "id" }
|
||||
route: {goType: "string", storeIdent: "id"}
|
||||
endpoint: {goType: "string"}
|
||||
method: {goType: "string"}
|
||||
@@ -65,7 +82,7 @@ apigw_route: {
|
||||
disabled: {goType: "filter.State", storeIdent: "enabled"}
|
||||
}
|
||||
|
||||
byValue: ["route", "method"]
|
||||
byValue: ["apigw_route_id", "route", "method"]
|
||||
byNilState: ["deleted"]
|
||||
byFalseState: ["disabled"]
|
||||
}
|
||||
|
||||
@@ -32,6 +32,11 @@ application: {
|
||||
schema.AttributeUserRef,
|
||||
storeIdent: "rel_owner",
|
||||
ident: "ownerID"
|
||||
envoy: {
|
||||
store: {
|
||||
omitRefFilter: true
|
||||
}
|
||||
}
|
||||
}
|
||||
created_at: schema.SortableTimestampNowField
|
||||
updated_at: schema.SortableTimestampNilField
|
||||
@@ -62,6 +67,18 @@ application: {
|
||||
flags: true
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Name"
|
||||
identKeyAlias: ["apps"]
|
||||
}
|
||||
store: {
|
||||
extendedRefDecoder: true
|
||||
handleField: "Name"
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
read:
|
||||
|
||||
@@ -47,6 +47,10 @@ attachment: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
kind: {}
|
||||
|
||||
@@ -6,14 +6,14 @@ import (
|
||||
|
||||
auth_client: {
|
||||
model: {
|
||||
omitGetterSetter: true
|
||||
|
||||
attributes: {
|
||||
id: schema.IdField
|
||||
handle: schema.HandleField
|
||||
meta: {
|
||||
goType: "*types.AuthClientMeta"
|
||||
dal: { type: "JSON", defaultEmptyObject: true }
|
||||
omitSetter: true
|
||||
omitGetter: true
|
||||
}
|
||||
secret: {
|
||||
goType: "string"
|
||||
@@ -47,6 +47,8 @@ auth_client: {
|
||||
security: {
|
||||
goType: "*types.AuthClientSecurity"
|
||||
dal: { type: "JSON", defaultEmptyObject: true }
|
||||
omitSetter: true
|
||||
omitGetter: true
|
||||
}
|
||||
owned_by: schema.AttributeUserRef
|
||||
created_at: schema.SortableTimestampNowField
|
||||
@@ -83,6 +85,16 @@ auth_client: {
|
||||
user_id: {goType: "uint64"}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["authclients"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
read: description: "Read authorization client"
|
||||
|
||||
@@ -44,6 +44,10 @@ auth_confirmed_client: {
|
||||
byValue: ["user_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
|
||||
store: {
|
||||
api: {
|
||||
|
||||
@@ -68,6 +68,10 @@ auth_oa2token: {
|
||||
byValue: ["user_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
lookups: [
|
||||
|
||||
@@ -55,6 +55,10 @@ auth_session: {
|
||||
byValue: ["user_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
lookups: [
|
||||
|
||||
@@ -60,6 +60,10 @@ credential: {
|
||||
checkFn: false
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
lookups: [
|
||||
|
||||
@@ -42,14 +42,14 @@ dal_connection: {
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
connection_id: {goType: "[]uint64", ident: "connectionID", storeIdent: "id"}
|
||||
dal_connection_id: {goType: "[]uint64", ident: "connectionID", storeIdent: "id"}
|
||||
handle: {goType: "string"}
|
||||
type: {goType: "string"}
|
||||
|
||||
deleted: {goType: "filter.State", storeIdent: "deleted_at"}
|
||||
}
|
||||
|
||||
byValue: ["connection_id", "handle", "type"]
|
||||
byValue: ["dal_connection_id", "handle", "type"]
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
@@ -57,6 +57,15 @@ dal_connection: {
|
||||
labels: false
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["connection", "connections"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": description: "Read connection"
|
||||
|
||||
@@ -36,15 +36,25 @@ dal_sensitivity_level: {
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
sensitivity_level_id: {goType: "[]uint64", ident: "sensitivityLevelID", storeIdent: "id"}
|
||||
dal_sensitivity_level_id: {goType: "[]uint64", ident: "sensitivityLevelID", storeIdent: "id"}
|
||||
handle: { goType: "string" }
|
||||
|
||||
deleted: {goType: "filter.State", storeIdent: "deleted_at"}
|
||||
}
|
||||
|
||||
byValue: ["sensitivity_level_id"]
|
||||
byValue: ["dal_sensitivity_level_id", "handle"]
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["sensitivity_level"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
features: {
|
||||
labels: false
|
||||
}
|
||||
|
||||
@@ -77,6 +77,10 @@ data_privacy_request: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
lookups: [
|
||||
|
||||
@@ -45,6 +45,10 @@ data_privacy_request_comment: {
|
||||
byValue: ["request_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
functions: []
|
||||
|
||||
Generated
+1035
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
func (d StoreDecoder) decodeApplicationRefs(c *types.Application) (refs map[string]envoyx.Ref) {
|
||||
|
||||
// @todo
|
||||
return
|
||||
}
|
||||
Generated
+2131
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
package envoy
|
||||
|
||||
import "github.com/cortezaproject/corteza/server/system/types"
|
||||
|
||||
func (e StoreEncoder) setApplicationDefaults(res *types.Application) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateApplication(res *types.Application) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setApigwRouteDefaults(res *types.ApigwRoute) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateApigwRoute(res *types.ApigwRoute) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setApigwFilterDefaults(res *types.ApigwFilter) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateApigwFilter(res *types.ApigwFilter) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setAuthClientDefaults(res *types.AuthClient) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateAuthClient(res *types.AuthClient) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setQueueDefaults(res *types.Queue) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateQueue(res *types.Queue) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setReportDefaults(res *types.Report) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateReport(res *types.Report) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setRoleDefaults(res *types.Role) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateRole(res *types.Role) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setTemplateDefaults(res *types.Template) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateTemplate(res *types.Template) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setUserDefaults(res *types.User) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateUser(res *types.User) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setDalConnectionDefaults(res *types.DalConnection) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateDalConnection(res *types.DalConnection) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) setDalSensitivityLevelDefaults(res *types.DalSensitivityLevel) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (e StoreEncoder) validateDalSensitivityLevel(res *types.DalSensitivityLevel) (err error) {
|
||||
return
|
||||
}
|
||||
Generated
+2946
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func (d *auxYamlDoc) unmarshalYAML(k string, n *yaml.Node) (out envoyx.NodeSet, err error) {
|
||||
return
|
||||
}
|
||||
Generated
+1086
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,9 @@ queue: {
|
||||
sortable: true,
|
||||
goType: "string"
|
||||
dal: {}
|
||||
envoy: {
|
||||
identifier: true
|
||||
}
|
||||
}
|
||||
meta: {
|
||||
goType: "types.QueueMeta"
|
||||
@@ -45,14 +48,28 @@ queue: {
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
queue_id: {goType: "uint64", ident: "queueID", storeIdent: "id"}
|
||||
query: {goType: "string"}
|
||||
deleted: {goType: "filter.State", storeIdent: "deleted_at"}
|
||||
}
|
||||
|
||||
query: ["queue", "consumer"]
|
||||
byValue: ["queue_id"]
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
scoped: true
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Queue"
|
||||
identKeyAlias: []
|
||||
}
|
||||
store: {
|
||||
handleField: ""
|
||||
}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": description: "Read queue"
|
||||
|
||||
@@ -32,6 +32,10 @@ queue_message: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
queue: {}
|
||||
|
||||
@@ -44,6 +44,10 @@ reminder: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
reminder_id: {goType: "[]uint64", ident: "reminderID", storeIdent: "id"}
|
||||
|
||||
@@ -48,6 +48,15 @@ report: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["reports"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
report_id: {goType: "[]uint64", storeIdent: "id", ident: "reportID" }
|
||||
|
||||
@@ -52,6 +52,11 @@ resource_translation: {
|
||||
}
|
||||
}
|
||||
|
||||
envoy: {
|
||||
// Special handling for i18n
|
||||
omit: true
|
||||
}
|
||||
|
||||
filter: {
|
||||
struct: {
|
||||
translation_id: {goType: "[]uint64", ident: "translationID" }
|
||||
|
||||
@@ -77,9 +77,9 @@ func (ctrl DalConnection) List(ctx context.Context, r *request.DalConnectionList
|
||||
dalConnections types.DalConnectionSet
|
||||
|
||||
f = types.DalConnectionFilter{
|
||||
ConnectionID: payload.ParseUint64s(r.ConnectionID),
|
||||
Handle: r.Handle,
|
||||
Type: r.Type,
|
||||
DalConnectionID: payload.ParseUint64s(r.ConnectionID),
|
||||
Handle: r.Handle,
|
||||
Type: r.Type,
|
||||
|
||||
Deleted: filter.State(r.Deleted),
|
||||
}
|
||||
@@ -243,8 +243,8 @@ func (ctrl DalConnection) filterConnections(baseConnections types.DalConnectionS
|
||||
for _, conn := range baseConnections {
|
||||
include := true
|
||||
|
||||
if len(f.ConnectionID) > 0 {
|
||||
include = include && ctrl.inIDSet(f.ConnectionID, conn.ID)
|
||||
if len(f.DalConnectionID) > 0 {
|
||||
include = include && ctrl.inIDSet(f.DalConnectionID, conn.ID)
|
||||
}
|
||||
|
||||
if f.Handle != "" {
|
||||
|
||||
@@ -39,9 +39,9 @@ func (ctrl DataPrivacy) ConnectionList(ctx context.Context, r *request.DataPriva
|
||||
set types.PrivacyDalConnectionSet
|
||||
|
||||
f = types.DalConnectionFilter{
|
||||
ConnectionID: payload.ParseUint64s(r.ConnectionID),
|
||||
Handle: r.Handle,
|
||||
Type: r.Type,
|
||||
DalConnectionID: payload.ParseUint64s(r.ConnectionID),
|
||||
Handle: r.Handle,
|
||||
Type: r.Type,
|
||||
|
||||
Deleted: r.Deleted,
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func (ctrl SensitivityLevel) List(ctx context.Context, r *request.DalSensitivity
|
||||
set types.DalSensitivityLevelSet
|
||||
|
||||
f = types.DalSensitivityLevelFilter{
|
||||
SensitivityLevelID: payload.ParseUint64s(r.SensitivityLevelID),
|
||||
DalSensitivityLevelID: payload.ParseUint64s(r.SensitivityLevelID),
|
||||
|
||||
Deleted: filter.State(r.Deleted),
|
||||
}
|
||||
|
||||
@@ -47,6 +47,15 @@ role: {
|
||||
byNilState: ["deleted", "archived"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["roles"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
read: description: "Read role"
|
||||
|
||||
@@ -38,6 +38,10 @@ role_member: {
|
||||
byValue: [ "user_id", "role_id"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
lookups: []
|
||||
|
||||
@@ -58,6 +58,10 @@ settings: {
|
||||
byValue: [ "owned_by" ]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
omit: true
|
||||
}
|
||||
|
||||
store: {
|
||||
api: {
|
||||
lookups: [
|
||||
|
||||
@@ -77,6 +77,15 @@ template: {
|
||||
byNilState: ["deleted"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["templates"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
read: description: "Read template"
|
||||
|
||||
@@ -31,7 +31,8 @@ type (
|
||||
}
|
||||
|
||||
ApigwFilterFilter struct {
|
||||
RouteID uint64 `json:"routeID,string"`
|
||||
ApigwFilterID []uint64 `json:"apigwFilterID"`
|
||||
RouteID uint64 `json:"routeID,string"`
|
||||
|
||||
Deleted filter.State `json:"deleted"`
|
||||
Disabled filter.State `json:"disabled"`
|
||||
|
||||
@@ -34,9 +34,10 @@ type (
|
||||
}
|
||||
|
||||
ApigwRouteFilter struct {
|
||||
Route string `json:"route"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Method string `json:"method"`
|
||||
ApigwRouteID []uint64 `json:"apigwRouteID"`
|
||||
Route string `json:"route"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Method string `json:"method"`
|
||||
|
||||
Deleted filter.State `json:"deleted"`
|
||||
Disabled filter.State `json:"disabled"`
|
||||
|
||||
@@ -3,9 +3,10 @@ package types
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
)
|
||||
|
||||
@@ -42,8 +43,9 @@ type (
|
||||
}
|
||||
|
||||
ApplicationFilter struct {
|
||||
Name string `json:"name"`
|
||||
Query string `json:"query"`
|
||||
ApplicationID []uint64 `json:"applicationID"`
|
||||
Name string `json:"name"`
|
||||
Query string `json:"query"`
|
||||
|
||||
LabeledIDs []uint64 `json:"-"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
)
|
||||
|
||||
@@ -84,7 +85,7 @@ type (
|
||||
}
|
||||
|
||||
AuthClientFilter struct {
|
||||
ClientID []uint64 `json:"authClientID"`
|
||||
AuthClientID []uint64 `json:"authClientID"`
|
||||
|
||||
Handle string `json:"handle"`
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ type (
|
||||
// ........................................................................
|
||||
|
||||
DalConnectionFilter struct {
|
||||
ConnectionID []uint64 `json:"connectionID,string"`
|
||||
Handle string `json:"handle"`
|
||||
Type string `json:"type"`
|
||||
DalConnectionID []uint64 `json:"connectionID,string"`
|
||||
Handle string `json:"handle"`
|
||||
Type string `json:"type"`
|
||||
|
||||
Deleted filter.State `json:"deleted"`
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ package types
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
)
|
||||
|
||||
@@ -33,7 +34,8 @@ type (
|
||||
}
|
||||
|
||||
DalSensitivityLevelFilter struct {
|
||||
SensitivityLevelID []uint64 `json:"sensitivityLevelID,string"`
|
||||
DalSensitivityLevelID []uint64 `json:"sensitivityLevelID,string"`
|
||||
Handle string `json:"handle"`
|
||||
|
||||
Deleted filter.State `json:"deleted"`
|
||||
|
||||
|
||||
+84
@@ -234,6 +234,90 @@ func (r *ApigwFilter) SetValue(name string, pos uint, value any) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r AuthClient) GetID() uint64 { return r.ID }
|
||||
|
||||
func (r *AuthClient) GetValue(name string, pos uint) (any, error) {
|
||||
switch name {
|
||||
case "createdAt", "CreatedAt":
|
||||
return r.CreatedAt, nil
|
||||
case "createdBy", "CreatedBy":
|
||||
return r.CreatedBy, nil
|
||||
case "deletedAt", "DeletedAt":
|
||||
return r.DeletedAt, nil
|
||||
case "deletedBy", "DeletedBy":
|
||||
return r.DeletedBy, nil
|
||||
case "enabled", "Enabled":
|
||||
return r.Enabled, nil
|
||||
case "expiresAt", "ExpiresAt":
|
||||
return r.ExpiresAt, nil
|
||||
case "handle", "Handle":
|
||||
return r.Handle, nil
|
||||
case "id", "ID":
|
||||
return r.ID, nil
|
||||
case "ownedBy", "OwnedBy":
|
||||
return r.OwnedBy, nil
|
||||
case "redirectURI", "RedirectURI":
|
||||
return r.RedirectURI, nil
|
||||
case "scope", "Scope":
|
||||
return r.Scope, nil
|
||||
case "secret", "Secret":
|
||||
return r.Secret, nil
|
||||
case "trusted", "Trusted":
|
||||
return r.Trusted, nil
|
||||
case "updatedAt", "UpdatedAt":
|
||||
return r.UpdatedAt, nil
|
||||
case "updatedBy", "UpdatedBy":
|
||||
return r.UpdatedBy, nil
|
||||
case "validFrom", "ValidFrom":
|
||||
return r.ValidFrom, nil
|
||||
case "validGrant", "ValidGrant":
|
||||
return r.ValidGrant, nil
|
||||
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *AuthClient) SetValue(name string, pos uint, value any) (err error) {
|
||||
switch name {
|
||||
case "createdAt", "CreatedAt":
|
||||
return cast2.Time(value, &r.CreatedAt)
|
||||
case "createdBy", "CreatedBy":
|
||||
return cast2.Uint64(value, &r.CreatedBy)
|
||||
case "deletedAt", "DeletedAt":
|
||||
return cast2.TimePtr(value, &r.DeletedAt)
|
||||
case "deletedBy", "DeletedBy":
|
||||
return cast2.Uint64(value, &r.DeletedBy)
|
||||
case "enabled", "Enabled":
|
||||
return cast2.Bool(value, &r.Enabled)
|
||||
case "expiresAt", "ExpiresAt":
|
||||
return cast2.TimePtr(value, &r.ExpiresAt)
|
||||
case "handle", "Handle":
|
||||
return cast2.String(value, &r.Handle)
|
||||
case "id", "ID":
|
||||
return cast2.Uint64(value, &r.ID)
|
||||
case "ownedBy", "OwnedBy":
|
||||
return cast2.Uint64(value, &r.OwnedBy)
|
||||
case "redirectURI", "RedirectURI":
|
||||
return cast2.String(value, &r.RedirectURI)
|
||||
case "scope", "Scope":
|
||||
return cast2.String(value, &r.Scope)
|
||||
case "secret", "Secret":
|
||||
return cast2.String(value, &r.Secret)
|
||||
case "trusted", "Trusted":
|
||||
return cast2.Bool(value, &r.Trusted)
|
||||
case "updatedAt", "UpdatedAt":
|
||||
return cast2.TimePtr(value, &r.UpdatedAt)
|
||||
case "updatedBy", "UpdatedBy":
|
||||
return cast2.Uint64(value, &r.UpdatedBy)
|
||||
case "validFrom", "ValidFrom":
|
||||
return cast2.TimePtr(value, &r.ValidFrom)
|
||||
case "validGrant", "ValidGrant":
|
||||
return cast2.String(value, &r.ValidGrant)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r DataPrivacyRequestComment) GetID() uint64 { return r.ID }
|
||||
|
||||
func (r *DataPrivacyRequestComment) GetValue(name string, pos uint) (any, error) {
|
||||
|
||||
@@ -3,9 +3,10 @@ package types
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
@@ -26,6 +27,7 @@ type (
|
||||
}
|
||||
|
||||
QueueFilter struct {
|
||||
QueueID []uint64 `json:"queueID"`
|
||||
Query string `json:"query"`
|
||||
Deleted filter.State `json:"deleted"`
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ package types
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/sql"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
)
|
||||
|
||||
@@ -117,9 +117,9 @@ const (
|
||||
SystemUser UserKind = "sys"
|
||||
)
|
||||
|
||||
func (u User) String() string {
|
||||
return fmt.Sprintf("%d", u.ID)
|
||||
}
|
||||
// func (u User) String() string {
|
||||
// return fmt.Sprintf("%d", u.ID)
|
||||
// }
|
||||
|
||||
func (u *User) Valid() bool {
|
||||
return u.ID > 0 && u.SuspendedAt == nil && u.DeletedAt == nil
|
||||
|
||||
@@ -23,7 +23,6 @@ user: {
|
||||
unique: true,
|
||||
ignoreCase: true
|
||||
dal: {}
|
||||
|
||||
}
|
||||
name: {
|
||||
sortable: true
|
||||
@@ -86,6 +85,15 @@ user: {
|
||||
byNilState: ["deleted", "suspended"]
|
||||
}
|
||||
|
||||
envoy: {
|
||||
yaml: {
|
||||
supportMappedInput: true
|
||||
mappedField: "Handle"
|
||||
identKeyAlias: ["users", "usr"]
|
||||
}
|
||||
store: {}
|
||||
}
|
||||
|
||||
rbac: {
|
||||
operations: {
|
||||
"read": description: "Read user"
|
||||
|
||||
Reference in New Issue
Block a user