snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
99
server/pkg/envoy/resource/api_gateway.go
Normal file
99
server/pkg/envoy/resource/api_gateway.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
APIGateway struct {
|
||||
*base
|
||||
Res *types.ApigwRoute
|
||||
|
||||
Filters []*APIGatewayFilter
|
||||
}
|
||||
|
||||
APIGatewayFilter struct {
|
||||
*base
|
||||
Res *types.ApigwFilter
|
||||
}
|
||||
)
|
||||
|
||||
func NewAPIGateway(res *types.ApigwRoute) *APIGateway {
|
||||
// @todo we could use method + path combo to uniquely identify them also
|
||||
r := &APIGateway{
|
||||
base: &base{},
|
||||
}
|
||||
r.SetResourceType(types.ApigwRouteResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.ID)...)
|
||||
|
||||
// Initial stamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
us := MakeUserstampsCUDO(res.CreatedBy, res.UpdatedBy, res.DeletedBy, 0)
|
||||
r.SetUserstamps(us)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *APIGateway) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *APIGateway) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.ApigwRouteRbacResourceTpl(), types.ApigwRouteResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *APIGateway) AddGatewayFilter(res *types.ApigwFilter) *APIGatewayFilter {
|
||||
f := &APIGatewayFilter{
|
||||
base: &base{},
|
||||
}
|
||||
|
||||
f.Res = res
|
||||
|
||||
// Initial stamps
|
||||
f.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
f.SetUserstamps(MakeUserstampsCUDO(res.CreatedBy, res.UpdatedBy, res.DeletedBy, 0))
|
||||
|
||||
r.Filters = append(r.Filters, f)
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (r *APIGateway) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
// FindAPIGateway looks for the ApigwRoute in the resource set
|
||||
func FindAPIGateway(rr InterfaceSet, ii Identifiers) (ns *types.ApigwRoute) {
|
||||
var wfRes *APIGateway
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
wr, ok := r.(*APIGateway)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if wr.Identifiers().HasAny(ii) {
|
||||
wfRes = wr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if wfRes != nil {
|
||||
return wfRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func APIGatewayErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("automation apu gateway unresolved %v", ii.StringSlice())
|
||||
}
|
||||
80
server/pkg/envoy/resource/application.go
Normal file
80
server/pkg/envoy/resource/application.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// Application represents a Application
|
||||
Application struct {
|
||||
*base
|
||||
Res *types.Application
|
||||
}
|
||||
)
|
||||
|
||||
func NewApplication(res *types.Application) *Application {
|
||||
r := &Application{base: &base{}}
|
||||
r.SetResourceType(types.ApplicationResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.Name, res.ID)...)
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
// Initial userstamps
|
||||
if res.OwnerID > 0 {
|
||||
r.SetUserstamps(&Userstamps{
|
||||
OwnedBy: &Userstamp{UserID: res.OwnerID},
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Application) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *Application) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Application) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.ApplicationRbacResourceTpl(), types.ApplicationResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10)))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindApplication looks for the app in the resource set
|
||||
func FindApplication(rr InterfaceSet, ii Identifiers) (ap *types.Application) {
|
||||
var apRes *Application
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
ar, ok := r.(*Application)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ar.Identifiers().HasAny(ii) {
|
||||
apRes = ar
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if apRes != nil {
|
||||
return apRes.Res
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ApplicationErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("application unresolved %v", ii.StringSlice())
|
||||
}
|
||||
155
server/pkg/envoy/resource/automation_workflow.go
Normal file
155
server/pkg/envoy/resource/automation_workflow.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
)
|
||||
|
||||
type (
|
||||
AutomationWorkflow struct {
|
||||
*base
|
||||
Res *types.Workflow
|
||||
|
||||
Triggers []*AutomationTrigger
|
||||
Steps []*AutomationWorkflowStep
|
||||
Paths []*AutomationWorkflowPath
|
||||
}
|
||||
|
||||
AutomationTrigger struct {
|
||||
*base
|
||||
Res *types.Trigger
|
||||
}
|
||||
|
||||
AutomationWorkflowStep struct {
|
||||
*base
|
||||
Res *types.WorkflowStep
|
||||
}
|
||||
|
||||
AutomationWorkflowPath struct {
|
||||
*base
|
||||
Res *types.WorkflowPath
|
||||
|
||||
ParentStep Identifiers
|
||||
ChildStep Identifiers
|
||||
}
|
||||
)
|
||||
|
||||
func NewAutomationWorkflow(res *types.Workflow) *AutomationWorkflow {
|
||||
r := &AutomationWorkflow{
|
||||
base: &base{},
|
||||
}
|
||||
r.SetResourceType(types.WorkflowResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.Handle, res.Meta.Name, res.ID)...)
|
||||
|
||||
// Initial stamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
us := MakeUserstampsCUDO(res.CreatedBy, res.UpdatedBy, res.DeletedBy, res.OwnedBy)
|
||||
us.RunAs = MakeUserstampFromID(res.RunAs)
|
||||
r.SetUserstamps(us)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) AddAutomationTrigger(res *types.Trigger) *AutomationTrigger {
|
||||
t := &AutomationTrigger{
|
||||
base: &base{},
|
||||
}
|
||||
|
||||
t.Res = res
|
||||
|
||||
// Initial stamps
|
||||
t.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
t.SetUserstamps(MakeUserstampsCUDO(res.CreatedBy, res.UpdatedBy, res.DeletedBy, res.OwnedBy))
|
||||
|
||||
if r.Triggers == nil {
|
||||
r.Triggers = make([]*AutomationTrigger, 0, 2)
|
||||
}
|
||||
r.Triggers = append(r.Triggers, t)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.WorkflowRbacResourceTpl(), types.WorkflowResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.WorkflowResourceTranslationTpl(), types.WorkflowResourceTranslationType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) AddAutomationWorkflowStep(res *types.WorkflowStep) *AutomationWorkflowStep {
|
||||
s := &AutomationWorkflowStep{
|
||||
base: &base{},
|
||||
}
|
||||
|
||||
s.Res = res
|
||||
|
||||
if r.Steps == nil {
|
||||
r.Steps = make([]*AutomationWorkflowStep, 0, 100)
|
||||
}
|
||||
r.Steps = append(r.Steps, s)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) AddAutomationWorkflowPath(res *types.WorkflowPath) *AutomationWorkflowPath {
|
||||
p := &AutomationWorkflowPath{
|
||||
base: &base{},
|
||||
}
|
||||
|
||||
p.Res = res
|
||||
|
||||
if r.Paths == nil {
|
||||
r.Paths = make([]*AutomationWorkflowPath, 0, 100)
|
||||
}
|
||||
r.Paths = append(r.Paths, p)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *AutomationWorkflow) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
// FindAutomationWorkflow looks for the workflow in the resource set
|
||||
func FindAutomationWorkflow(rr InterfaceSet, ii Identifiers) (ns *types.Workflow) {
|
||||
var wfRes *AutomationWorkflow
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
wr, ok := r.(*AutomationWorkflow)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if wr.Identifiers().HasAny(ii) {
|
||||
wfRes = wr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if wfRes != nil {
|
||||
return wfRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AutomationWorkflowErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("automation workflow unresolved %v", ii.StringSlice())
|
||||
}
|
||||
114
server/pkg/envoy/resource/compose_chart.go
Normal file
114
server/pkg/envoy/resource/compose_chart.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// ComposeChart represents a ComposeChart
|
||||
ComposeChart struct {
|
||||
*base
|
||||
Res *types.Chart
|
||||
|
||||
// Might keep track of related namespace
|
||||
RefNs *Ref
|
||||
RefMods RefSet
|
||||
}
|
||||
)
|
||||
|
||||
func NewComposeChart(res *types.Chart, nsRef *Ref, mmRef RefSet) *ComposeChart {
|
||||
r := &ComposeChart{
|
||||
base: &base{},
|
||||
RefMods: make(RefSet, len(mmRef)),
|
||||
}
|
||||
r.SetResourceType(types.ChartResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.Handle, res.Name, res.ID)...)
|
||||
|
||||
r.RefNs = r.addRef(nsRef)
|
||||
for i, mRef := range mmRef {
|
||||
r.RefMods[i] = r.addRef(mRef).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeChart) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *ComposeChart) ReRef(old RefSet, new RefSet) {
|
||||
r.base.ReRef(old, new)
|
||||
|
||||
// Additional references
|
||||
for _, n := range new {
|
||||
if n.ResourceType == types.NamespaceResourceType {
|
||||
r.RefNs = MakeRef(types.NamespaceResourceType, n.Identifiers)
|
||||
}
|
||||
}
|
||||
|
||||
for i, o := range old {
|
||||
if o.ResourceType == types.ModuleResourceType {
|
||||
r.RefMods = r.RefMods.replaceRef(o, new[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ComposeChart) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposeChart) resourceParts(tpl string) (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref().Constraint(r.RefNs)
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.ChartRbacResourceTpl(), types.ChartResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeChart) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ChartRbacResourceTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeChart) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ChartResourceTranslationTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeChart) encodeTranslations() ([]*ResourceTranslation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FindComposeChart looks for the chart in the resources
|
||||
func FindComposeChart(rr InterfaceSet, ii Identifiers) (ch *types.Chart) {
|
||||
var chRes *ComposeChart
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
cr, ok := r.(*ComposeChart)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cr.Identifiers().HasAny(ii) {
|
||||
chRes = cr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if chRes != nil {
|
||||
return chRes.Res
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ComposeChartErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose chart unresolved %v", ii.StringSlice())
|
||||
}
|
||||
220
server/pkg/envoy/resource/compose_layout.go
Normal file
220
server/pkg/envoy/resource/compose_layout.go
Normal file
@@ -0,0 +1,220 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
automationTypes "github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// ComposePageLayout represents a ComposePageLayout
|
||||
ComposePageLayout struct {
|
||||
*base
|
||||
Res *types.PageLayout
|
||||
|
||||
RefNs *Ref
|
||||
RefMod *Ref
|
||||
RefParent *Ref
|
||||
|
||||
WfRefs RefSet
|
||||
ModRefs RefSet
|
||||
RefCharts RefSet
|
||||
|
||||
BlockRefs map[int]RefSet
|
||||
}
|
||||
)
|
||||
|
||||
func NewComposePageLayout(pg *types.PageLayout, nsRef, modRef, parentRef *Ref) *ComposePageLayout {
|
||||
r := &ComposePageLayout{
|
||||
base: &base{},
|
||||
WfRefs: make(RefSet, 0, 10),
|
||||
ModRefs: make(RefSet, 0, 10),
|
||||
RefCharts: make(RefSet, 0, 10),
|
||||
BlockRefs: make(map[int]RefSet),
|
||||
}
|
||||
r.SetResourceType(types.PageLayoutResourceType)
|
||||
r.Res = pg
|
||||
|
||||
r.AddIdentifier(identifiers(pg.Handle, pg.Meta.Title, pg.ID)...)
|
||||
|
||||
r.RefNs = r.addRef(nsRef)
|
||||
if modRef != nil {
|
||||
r.RefMod = r.addRef(modRef).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
if parentRef != nil {
|
||||
r.RefParent = r.addRef(parentRef).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&pg.CreatedAt, pg.UpdatedAt, pg.DeletedAt, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func UnpackComposePageLayout(p *types.PageLayout) (*types.PageLayout, *Ref, *Ref) {
|
||||
var modRef *Ref
|
||||
var parentRef *Ref
|
||||
|
||||
return p, modRef, parentRef
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) ReRef(old RefSet, new RefSet) {
|
||||
r.base.ReRef(old, new)
|
||||
|
||||
for _, n := range new {
|
||||
switch n.ResourceType {
|
||||
case types.NamespaceResourceType:
|
||||
r.RefNs = MakeRef(types.NamespaceResourceType, n.Identifiers)
|
||||
case types.ModuleResourceType:
|
||||
r.RefMod = MakeRef(types.ModuleResourceType, n.Identifiers)
|
||||
case types.PageLayoutResourceType:
|
||||
r.RefParent = MakeRef(types.PageLayoutResourceType, n.Identifiers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) Prune(ref *Ref) {
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) resourceParts(tpl string) (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref().Constraint(r.RefNs)
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.PageLayoutRbacResourceTpl(), types.PageLayoutResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.PageLayoutRbacResourceTpl())
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.PageLayoutResourceTranslationTpl())
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) encodeTranslations() ([]*ResourceTranslation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FindComposePageLayout looks for the page in the resources
|
||||
func FindComposePageLayout(rr InterfaceSet, ii Identifiers) (pg *types.PageLayout) {
|
||||
var pgRes *ComposePageLayout
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
pr, ok := r.(*ComposePageLayout)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pr.Identifiers().HasAny(ii) {
|
||||
pgRes = pr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if pgRes != nil {
|
||||
return pgRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ComposePageLayoutErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose page unresolved %v", ii.StringSlice())
|
||||
}
|
||||
|
||||
// PageLayout block utilities
|
||||
func (r *ComposePageLayout) removeBlock(i int) {
|
||||
// do the swap remove thing
|
||||
r.Res.Blocks[i] = r.Res.Blocks[len(r.Res.Blocks)-1]
|
||||
r.Res.Blocks = r.Res.Blocks[:len(r.Res.Blocks)-1]
|
||||
|
||||
// correct block refs.
|
||||
// +1 here because it's already cut
|
||||
r.BlockRefs[i] = r.BlockRefs[len(r.Res.Blocks)]
|
||||
delete(r.BlockRefs, len(r.Res.Blocks))
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) optString(opt map[string]interface{}, kk ...string) string {
|
||||
for _, k := range kk {
|
||||
if vr, has := opt[k]; has {
|
||||
v, _ := vr.(string)
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbRecordList(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbComment(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbAutomation(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "workflow", "workflowID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(automationTypes.WorkflowResourceType, MakeIdentifiers(id))
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbRecordOrganizer(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbChart(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "chart", "chartID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ChartResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbCalendar(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePageLayout) pbMetric(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
308
server/pkg/envoy/resource/compose_module.go
Normal file
308
server/pkg/envoy/resource/compose_module.go
Normal file
@@ -0,0 +1,308 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/modern-go/reflect2"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type (
|
||||
ComposeModuleField struct {
|
||||
*base
|
||||
Res *types.ModuleField
|
||||
|
||||
RefNs *Ref
|
||||
RefMod *Ref
|
||||
}
|
||||
|
||||
ComposeModule struct {
|
||||
*base
|
||||
Res *types.Module
|
||||
ResFields []*ComposeModuleField
|
||||
|
||||
// Might keep track of related NS
|
||||
RefNs *Ref
|
||||
RefMods RefSet
|
||||
RefRoles RefSet
|
||||
}
|
||||
)
|
||||
|
||||
func NewComposeModule(res *types.Module, nsRef *Ref) *ComposeModule {
|
||||
r := &ComposeModule{
|
||||
base: &base{},
|
||||
RefMods: make(RefSet, 0, len(res.Fields)),
|
||||
}
|
||||
r.SetResourceType(types.ModuleResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.Handle, res.Name, res.ID)...)
|
||||
|
||||
r.RefNs = r.addRef(nsRef)
|
||||
|
||||
// Field deps
|
||||
for _, f := range res.Fields {
|
||||
switch f.Kind {
|
||||
case "Record":
|
||||
refMod := f.Options.String("module")
|
||||
if refMod == "" {
|
||||
refMod = f.Options.String("moduleID")
|
||||
}
|
||||
if refMod != "" && refMod != "0" {
|
||||
r.RefMods = append(r.RefMods, r.AddRef(types.ModuleResourceType, refMod).Constraint(r.RefNs))
|
||||
}
|
||||
|
||||
case "User":
|
||||
refRoles := ComposeModuleFieldExtractUserFieldRoles(f.Options["roles"])
|
||||
if len(refRoles) == 0 {
|
||||
refRoles = ComposeModuleFieldExtractUserFieldRoles(f.Options["role"])
|
||||
}
|
||||
if len(refRoles) == 0 {
|
||||
refRoles = ComposeModuleFieldExtractUserFieldRoles(f.Options["roleID"])
|
||||
}
|
||||
|
||||
for _, refRole := range refRoles {
|
||||
r.RefRoles = append(r.RefRoles, r.AddRef(systemTypes.RoleResourceType, refRole))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeModule) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *ComposeModule) ReRef(old RefSet, new RefSet) {
|
||||
r.base.ReRef(old, new)
|
||||
|
||||
// Additional references
|
||||
for _, n := range new {
|
||||
if n.ResourceType == types.NamespaceResourceType {
|
||||
r.RefNs = MakeRef(types.NamespaceResourceType, n.Identifiers)
|
||||
}
|
||||
}
|
||||
|
||||
for i, o := range old {
|
||||
if o.ResourceType == types.ModuleResourceType {
|
||||
r.RefMods = r.RefMods.replaceRef(o, new[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ComposeModule) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposeModule) resourceParts(tpl string) (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref().Constraint(r.RefNs)
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(tpl, types.ModuleResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeModule) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ModuleRbacResourceTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeModule) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ModuleResourceTranslationTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeModule) encodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, len(r.ResFields))
|
||||
|
||||
for _, f := range r.ResFields {
|
||||
rr := f.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := f.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// FindComposeModule looks for the module in the resource set
|
||||
func FindComposeModule(rr InterfaceSet, ii Identifiers) (ns *types.Module) {
|
||||
var modRes *ComposeModule
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
mr, ok := r.(*ComposeModule)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if mr.Identifiers().HasAny(ii) {
|
||||
modRes = mr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if modRes != nil {
|
||||
return modRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ComposeModule) AddField(f *ComposeModuleField) {
|
||||
r.ResFields = append(r.ResFields, f)
|
||||
}
|
||||
|
||||
// FindComposeModule looks for the module in the resource set
|
||||
func FindComposeModuleField(rr InterfaceSet, mod, ii Identifiers) (field *types.ModuleField) {
|
||||
var fieldRes *ComposeModuleField
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
mr, ok := r.(*ComposeModule)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !mr.Identifiers().HasAny(mod) {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, rf := range mr.ResFields {
|
||||
if rf.Identifiers().HasAny(ii) {
|
||||
fieldRes = rf
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if fieldRes != nil {
|
||||
return fieldRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ComposeModuleField) resourceParts(tpl string) (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref().Constraint(r.RefNs).Constraint(r.RefMod)
|
||||
path = []*Ref{r.RefNs, r.RefMod}
|
||||
resource = fmt.Sprintf(types.ModuleFieldResourceTranslationTpl(), types.ModuleFieldResourceTranslationType, r.RefNs.Identifiers.First(), r.RefMod.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Name))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeModuleField) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ModuleFieldRbacResourceTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeModuleField) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.ModuleFieldResourceTranslationTpl())
|
||||
}
|
||||
|
||||
func (r *ComposeModuleField) ResourceTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func ComposeModuleErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose module unresolved %v", ii.StringSlice())
|
||||
}
|
||||
|
||||
func ComposeModuleFieldErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose module field unresolved %v", ii.StringSlice())
|
||||
}
|
||||
|
||||
func NewComposeModuleField(res *types.ModuleField, nsRef, modRef *Ref) *ComposeModuleField {
|
||||
r := &ComposeModuleField{
|
||||
base: &base{},
|
||||
}
|
||||
r.SetResourceType(types.ModuleFieldResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.Name, res.ID)...)
|
||||
|
||||
r.RefNs = r.addRef(nsRef)
|
||||
r.RefMod = r.addRef(modRef).Constraint(r.RefNs)
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeModuleField) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
// ComposeModuleFieldExtractUserFieldRoles is a helper to extract roles
|
||||
// from the given filer options.
|
||||
func ComposeModuleFieldExtractUserFieldRoles(i interface{}) []string {
|
||||
if reflect2.IsNil(i) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make([]string, 0, 1)
|
||||
|
||||
isOk := func(v string) bool {
|
||||
return v != "" && v != "0"
|
||||
}
|
||||
|
||||
switch v := i.(type) {
|
||||
case uint64:
|
||||
aux := strconv.FormatUint(v, 10)
|
||||
if !isOk(aux) {
|
||||
return nil
|
||||
}
|
||||
return []string{aux}
|
||||
case []uint64:
|
||||
for _, i := range v {
|
||||
aux := strconv.FormatUint(i, 10)
|
||||
if !isOk(aux) {
|
||||
continue
|
||||
}
|
||||
out = append(out, aux)
|
||||
}
|
||||
return out
|
||||
|
||||
case string:
|
||||
if !isOk(v) {
|
||||
return nil
|
||||
}
|
||||
return []string{v}
|
||||
case []string:
|
||||
for _, aux := range v {
|
||||
if !isOk(aux) {
|
||||
continue
|
||||
}
|
||||
out = append(out, aux)
|
||||
}
|
||||
return out
|
||||
|
||||
case []interface{}:
|
||||
for _, i := range v {
|
||||
aux := cast.ToString(i)
|
||||
if !isOk(aux) {
|
||||
continue
|
||||
}
|
||||
out = append(out, aux)
|
||||
}
|
||||
return out
|
||||
case interface{}:
|
||||
aux := cast.ToString(v)
|
||||
if !isOk(aux) {
|
||||
return nil
|
||||
}
|
||||
return []string{aux}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
80
server/pkg/envoy/resource/compose_namespace.go
Normal file
80
server/pkg/envoy/resource/compose_namespace.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
type (
|
||||
ComposeNamespace struct {
|
||||
*base
|
||||
Res *types.Namespace
|
||||
}
|
||||
)
|
||||
|
||||
func NewComposeNamespace(ns *types.Namespace) *ComposeNamespace {
|
||||
r := &ComposeNamespace{base: &base{}}
|
||||
r.SetResourceType(types.NamespaceResourceType)
|
||||
r.Res = ns
|
||||
|
||||
r.AddIdentifier(identifiers(ns.Slug, ns.Name, ns.ID)...)
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&ns.CreatedAt, ns.UpdatedAt, ns.DeletedAt, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeNamespace) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *ComposeNamespace) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.NamespaceRbacResourceTpl(), types.NamespaceResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Slug))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeNamespace) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.NamespaceResourceTranslationTpl(), types.NamespaceResourceTranslationType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Slug))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposeNamespace) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
// FindComposeNamespace looks for the namespace in the resource set
|
||||
func FindComposeNamespace(rr InterfaceSet, ii Identifiers) (ns *types.Namespace) {
|
||||
var nsRes *ComposeNamespace
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
nr, ok := r.(*ComposeNamespace)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if nr.Identifiers().HasAny(ii) {
|
||||
nsRes = nr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if nsRes != nil {
|
||||
return nsRes.Res
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ComposeNamespaceErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose namespace unresolved %v", ii.StringSlice())
|
||||
}
|
||||
340
server/pkg/envoy/resource/compose_page.go
Normal file
340
server/pkg/envoy/resource/compose_page.go
Normal file
@@ -0,0 +1,340 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
automationTypes "github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// ComposePage represents a ComposePage
|
||||
ComposePage struct {
|
||||
*base
|
||||
Res *types.Page
|
||||
|
||||
RefNs *Ref
|
||||
RefMod *Ref
|
||||
RefParent *Ref
|
||||
|
||||
WfRefs RefSet
|
||||
ModRefs RefSet
|
||||
RefCharts RefSet
|
||||
|
||||
BlockRefs map[int]RefSet
|
||||
}
|
||||
)
|
||||
|
||||
func NewComposePage(pg *types.Page, nsRef, modRef, parentRef *Ref) *ComposePage {
|
||||
r := &ComposePage{
|
||||
base: &base{},
|
||||
WfRefs: make(RefSet, 0, 10),
|
||||
ModRefs: make(RefSet, 0, 10),
|
||||
RefCharts: make(RefSet, 0, 10),
|
||||
BlockRefs: make(map[int]RefSet),
|
||||
}
|
||||
r.SetResourceType(types.PageResourceType)
|
||||
r.Res = pg
|
||||
|
||||
r.AddIdentifier(identifiers(pg.Handle, pg.Title, pg.ID)...)
|
||||
|
||||
r.RefNs = r.addRef(nsRef)
|
||||
if modRef != nil {
|
||||
r.RefMod = r.addRef(modRef).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
if parentRef != nil {
|
||||
r.RefParent = r.addRef(parentRef).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
var ref *Ref
|
||||
for i, b := range pg.Blocks {
|
||||
switch b.Kind {
|
||||
case "RecordList":
|
||||
ref = r.pbRecordList(b.Options)
|
||||
if ref != nil {
|
||||
r.addRef(ref)
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.ModRefs = append(r.ModRefs, ref)
|
||||
}
|
||||
|
||||
case "Automation":
|
||||
bb, _ := b.Options["buttons"].([]interface{})
|
||||
for _, b := range bb {
|
||||
button, _ := b.(map[string]interface{})
|
||||
ref = r.pbAutomation(button)
|
||||
if ref != nil {
|
||||
r.addRef(ref)
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.WfRefs = append(r.WfRefs, ref)
|
||||
}
|
||||
}
|
||||
|
||||
case "RecordOrganizer":
|
||||
ref = r.pbRecordList(b.Options)
|
||||
if ref != nil {
|
||||
r.addRef(ref)
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.ModRefs = append(r.ModRefs, ref)
|
||||
}
|
||||
|
||||
case "Chart":
|
||||
ref = r.pbChart(b.Options)
|
||||
if ref != nil {
|
||||
r.addRef(ref)
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.RefCharts = append(r.RefCharts, ref)
|
||||
}
|
||||
|
||||
case "Calendar":
|
||||
ff, _ := b.Options["feeds"].([]interface{})
|
||||
for _, f := range ff {
|
||||
feed, _ := f.(map[string]interface{})
|
||||
fOpts, _ := (feed["options"]).(map[string]interface{})
|
||||
|
||||
ref = r.pbCalendar(fOpts)
|
||||
if ref != nil {
|
||||
r.addRef(ref)
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.ModRefs = append(r.ModRefs, ref)
|
||||
}
|
||||
}
|
||||
|
||||
case "Metric":
|
||||
mm, _ := b.Options["metrics"].([]interface{})
|
||||
for _, m := range mm {
|
||||
mops, _ := m.(map[string]interface{})
|
||||
ref = r.pbMetric(mops)
|
||||
if ref != nil {
|
||||
r.addRef(ref)
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.ModRefs = append(r.ModRefs, ref)
|
||||
}
|
||||
}
|
||||
|
||||
case "Comment":
|
||||
ref = r.pbComment(b.Options)
|
||||
if ref != nil {
|
||||
r.addRef(ref.Constraint(r.RefNs))
|
||||
r.BlockRefs[i] = append(r.BlockRefs[i], ref)
|
||||
r.ModRefs = append(r.ModRefs, ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&pg.CreatedAt, pg.UpdatedAt, pg.DeletedAt, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func UnpackComposePage(p *types.Page) (*types.Page, *Ref, *Ref) {
|
||||
var modRef *Ref
|
||||
var parentRef *Ref
|
||||
|
||||
if p.ModuleID != 0 {
|
||||
modRef = MakeModuleRef(p.ModuleID, "", "")
|
||||
}
|
||||
if p.SelfID != 0 {
|
||||
parentRef = MakePageRef(p.SelfID, "", "")
|
||||
}
|
||||
|
||||
return p, modRef, parentRef
|
||||
}
|
||||
|
||||
func (r *ComposePage) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *ComposePage) ReRef(old RefSet, new RefSet) {
|
||||
r.base.ReRef(old, new)
|
||||
|
||||
for _, n := range new {
|
||||
switch n.ResourceType {
|
||||
case types.NamespaceResourceType:
|
||||
r.RefNs = MakeRef(types.NamespaceResourceType, n.Identifiers)
|
||||
case types.ModuleResourceType:
|
||||
r.RefMod = MakeRef(types.ModuleResourceType, n.Identifiers)
|
||||
case types.PageResourceType:
|
||||
r.RefParent = MakeRef(types.PageResourceType, n.Identifiers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ComposePage) Prune(ref *Ref) {
|
||||
var auxRef *Ref
|
||||
|
||||
outer:
|
||||
for i := len(r.Res.Blocks) - 1; i >= 0; i-- {
|
||||
b := r.Res.Blocks[i]
|
||||
|
||||
switch b.Kind {
|
||||
// Implement the rest when support is needed
|
||||
case "Automation":
|
||||
if b.Options["buttons"] == nil {
|
||||
// In case the block isn't connected to a workflow (placeholder, script)
|
||||
if auxRef == nil {
|
||||
r.removeBlock(i)
|
||||
continue outer
|
||||
}
|
||||
} else {
|
||||
bb, _ := b.Options["buttons"].([]interface{})
|
||||
for _, b := range bb {
|
||||
button, _ := b.(map[string]interface{})
|
||||
auxRef = r.pbAutomation(button)
|
||||
|
||||
// In case the block isn't connected to a workflow (placeholder, script)
|
||||
if auxRef == nil {
|
||||
r.removeBlock(i)
|
||||
continue outer
|
||||
}
|
||||
|
||||
// In case we are removing it
|
||||
if auxRef.equals(ref) {
|
||||
r.ReplaceRef(ref, nil)
|
||||
r.WfRefs = r.WfRefs.replaceRef(ref, nil)
|
||||
r.removeBlock(i)
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ComposePage) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *ComposePage) resourceParts(tpl string) (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref().Constraint(r.RefNs)
|
||||
path = []*Ref{r.RefNs}
|
||||
resource = fmt.Sprintf(types.PageRbacResourceTpl(), types.PageResourceType, r.RefNs.Identifiers.First(), firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ComposePage) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.PageRbacResourceTpl())
|
||||
}
|
||||
|
||||
func (r *ComposePage) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
return r.resourceParts(types.PageResourceTranslationTpl())
|
||||
}
|
||||
|
||||
func (r *ComposePage) encodeTranslations() ([]*ResourceTranslation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FindComposePage looks for the page in the resources
|
||||
func FindComposePage(rr InterfaceSet, ii Identifiers) (pg *types.Page) {
|
||||
var pgRes *ComposePage
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
pr, ok := r.(*ComposePage)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pr.Identifiers().HasAny(ii) {
|
||||
pgRes = pr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if pgRes != nil {
|
||||
return pgRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ComposePageErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose page unresolved %v", ii.StringSlice())
|
||||
}
|
||||
|
||||
// Page block utilities
|
||||
func (r *ComposePage) removeBlock(i int) {
|
||||
// do the swap remove thing
|
||||
r.Res.Blocks[i] = r.Res.Blocks[len(r.Res.Blocks)-1]
|
||||
r.Res.Blocks = r.Res.Blocks[:len(r.Res.Blocks)-1]
|
||||
|
||||
// correct block refs.
|
||||
// +1 here because it's already cut
|
||||
r.BlockRefs[i] = r.BlockRefs[len(r.Res.Blocks)]
|
||||
delete(r.BlockRefs, len(r.Res.Blocks))
|
||||
}
|
||||
|
||||
func (r *ComposePage) optString(opt map[string]interface{}, kk ...string) string {
|
||||
for _, k := range kk {
|
||||
if vr, has := opt[k]; has {
|
||||
v, _ := vr.(string)
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbRecordList(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbComment(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbAutomation(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "workflow", "workflowID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(automationTypes.WorkflowResourceType, MakeIdentifiers(id))
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbRecordOrganizer(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbChart(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "chart", "chartID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ChartResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbCalendar(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
|
||||
func (r *ComposePage) pbMetric(opt map[string]interface{}) (out *Ref) {
|
||||
id := r.optString(opt, "module", "moduleID")
|
||||
if id == "" || id == "0" {
|
||||
return
|
||||
}
|
||||
|
||||
return MakeRef(types.ModuleResourceType, MakeIdentifiers(id)).Constraint(r.RefNs)
|
||||
}
|
||||
115
server/pkg/envoy/resource/compose_record.go
Normal file
115
server/pkg/envoy/resource/compose_record.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
composeTypes "github.com/cortezaproject/corteza/server/compose/types"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
rawSysValues struct {
|
||||
OwnedBy string
|
||||
CreatedAt string
|
||||
CreatedBy string
|
||||
UpdatedAt string
|
||||
UpdatedBy string
|
||||
DeletedAt string
|
||||
DeletedBy string
|
||||
}
|
||||
|
||||
ComposeRecordRaw struct {
|
||||
ID string
|
||||
Values map[string]ComposeRecordRawValue
|
||||
|
||||
Ts *Timestamps
|
||||
Us *Userstamps
|
||||
|
||||
Config *EnvoyConfig
|
||||
}
|
||||
ComposeRecordRawSet []*ComposeRecordRaw
|
||||
|
||||
ComposeRecordRawValue struct {
|
||||
Name string
|
||||
IsMulti bool
|
||||
|
||||
Value string
|
||||
Values []string
|
||||
}
|
||||
|
||||
CrsWalker func(f func(r *ComposeRecordRaw) error) error
|
||||
|
||||
ComposeRecord struct {
|
||||
*base
|
||||
|
||||
Walker CrsWalker
|
||||
|
||||
RefNs *Ref
|
||||
|
||||
RefMod *Ref
|
||||
RelMod *composeTypes.Module
|
||||
|
||||
IDMap map[string]uint64
|
||||
// UserFlakes help the system by predefining a set of potential sys user references.
|
||||
// This should make the operation cheaper for larger datasets.
|
||||
UserFlakes UserstampIndex
|
||||
}
|
||||
)
|
||||
|
||||
func NewComposeRecordSet(w CrsWalker, nsRef, modRef string) *ComposeRecord {
|
||||
r := &ComposeRecord{
|
||||
base: &base{},
|
||||
IDMap: make(map[string]uint64),
|
||||
}
|
||||
|
||||
r.SetResourceType(composeTypes.RecordResourceType)
|
||||
r.Walker = w
|
||||
|
||||
r.AddIdentifier(identifiers(modRef)...)
|
||||
|
||||
r.RefNs = r.AddRef(composeTypes.NamespaceResourceType, nsRef)
|
||||
r.RefMod = r.AddRef(composeTypes.ModuleResourceType, modRef).Constraint(r.RefNs)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeRecord) Resource() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ComposeRecord) SetUserFlakes(uu UserstampIndex) {
|
||||
r.UserFlakes = uu
|
||||
|
||||
// Set user refs as wildflag, indicating it refers to any user resource
|
||||
r.AddRef(systemTypes.UserResourceType, "*")
|
||||
}
|
||||
|
||||
func (r *ComposeRecord) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = []*Ref{r.RefNs, r.RefMod}
|
||||
// @todo specific records
|
||||
resource = fmt.Sprintf(types.RecordRbacResourceTpl(), types.RecordResourceType, r.RefNs.Identifiers.First(), r.RefMod.Identifiers.First(), "*")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func FindComposeRecordResource(rr InterfaceSet, ii Identifiers) (rec *ComposeRecord) {
|
||||
rr.Walk(func(r Interface) error {
|
||||
crr, ok := r.(*ComposeRecord)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if crr.Identifiers().HasAny(ii) {
|
||||
rec = crr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return rec
|
||||
}
|
||||
|
||||
func ComposeRecordErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("compose record unresolved %v", ii.StringSlice())
|
||||
}
|
||||
205
server/pkg/envoy/resource/compose_record_shaper.go
Normal file
205
server/pkg/envoy/resource/compose_record_shaper.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// A simple wrapper struct for related resources
|
||||
composeRecordShaper struct{}
|
||||
)
|
||||
|
||||
// ComposeRecordShaper initializes and returns a new compose record resource shaper
|
||||
func ComposeRecordShaper() shaper {
|
||||
return &composeRecordShaper{}
|
||||
}
|
||||
|
||||
// Shape shapes ResourceDatasets based on the related compose template
|
||||
//
|
||||
// The first step finds the matching pair;
|
||||
// The second step creates an actual resource based on the two.
|
||||
func (crt *composeRecordShaper) Shape(rr []Interface) ([]Interface, error) {
|
||||
// This will do for most cases
|
||||
ii := make([]Interface, 0, int(len(rr)/2)+1)
|
||||
|
||||
for _, r := range rr {
|
||||
rt, ok := r.(*ComposeRecordTemplate)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
rd := findResourceDataset(rr, rt.Identifiers())
|
||||
if rd == nil {
|
||||
return nil, genericSourceErrUnresolved(rt.Identifiers())
|
||||
}
|
||||
|
||||
ii = append(ii, crt.toResource(rt, rd))
|
||||
}
|
||||
|
||||
return ii, nil
|
||||
}
|
||||
|
||||
func (r *composeRecordShaper) Resource() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (crt *composeRecordShaper) toResource(def *ComposeRecordTemplate, dt *ResourceDataset) Interface {
|
||||
w := func(f func(r *ComposeRecordRaw) error) error {
|
||||
if err := dt.P.Reset(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
mr, err := dt.P.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if mr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the bits in order
|
||||
vv := crt.mapValues(mr, def.FieldMap, def.Defaultable)
|
||||
auxVals := make(map[string]ComposeRecordRawValue)
|
||||
|
||||
for k, v := range vv {
|
||||
auxVals[k] = ComposeRecordRawValue{
|
||||
Name: k,
|
||||
Value: v,
|
||||
}
|
||||
}
|
||||
|
||||
rRaw := &ComposeRecordRaw{
|
||||
ID: crt.getKey(mr, def.Key),
|
||||
Values: auxVals,
|
||||
}
|
||||
|
||||
crt.getTimestamps(rRaw)
|
||||
crt.getUserstamps(rRaw)
|
||||
|
||||
// Process it
|
||||
err = f(rRaw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NewComposeRecordSet(w, def.NsRef.Identifiers.First(), def.ModRef.Identifiers.First())
|
||||
}
|
||||
|
||||
// mapValues maps original values based on the provided mapping
|
||||
func (crt *composeRecordShaper) mapValues(ov map[string]string, fm MappingTplSet, defaultable bool) map[string]string {
|
||||
nv := make(map[string]string)
|
||||
|
||||
// Mappings are provided as a slice since we'll want to do some additional conditional mappings.
|
||||
// We'll make an index for a nicer lookup for now.
|
||||
mx := make(map[string]*MappingTpl)
|
||||
for _, m := range fm {
|
||||
mx[m.Cell] = m
|
||||
}
|
||||
|
||||
if defaultable {
|
||||
for k, v := range ov {
|
||||
if m, has := mx[k]; has {
|
||||
if !m.IsIgnored() {
|
||||
nv[m.Field] = v
|
||||
}
|
||||
} else {
|
||||
nv[k] = v
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(mx) > 0 {
|
||||
for k, v := range ov {
|
||||
if m, has := mx[k]; has && !m.IsIgnored() {
|
||||
nv[m.Field] = v
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for k, v := range ov {
|
||||
nv[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nv
|
||||
}
|
||||
|
||||
func (crt *composeRecordShaper) getTimestamps(r *ComposeRecordRaw) {
|
||||
ts := &Timestamps{}
|
||||
// Provided values are already mapped
|
||||
for k, v := range crt.cloneValues(r) {
|
||||
switch strings.ToLower(k) {
|
||||
case "createdat",
|
||||
"created_at":
|
||||
ts.CreatedAt = MakeTimestamp(v.Value)
|
||||
delete(r.Values, k)
|
||||
|
||||
case "updatedat",
|
||||
"updated_at":
|
||||
ts.UpdatedAt = MakeTimestamp(v.Value)
|
||||
delete(r.Values, k)
|
||||
|
||||
case "deletedat",
|
||||
"deleted_at":
|
||||
ts.DeletedAt = MakeTimestamp(v.Value)
|
||||
delete(r.Values, k)
|
||||
}
|
||||
}
|
||||
|
||||
r.Ts = ts
|
||||
}
|
||||
|
||||
func (crt *composeRecordShaper) getUserstamps(r *ComposeRecordRaw) {
|
||||
us := &Userstamps{}
|
||||
// Provided values are already mapped
|
||||
for k, v := range crt.cloneValues(r) {
|
||||
switch strings.ToLower(k) {
|
||||
case "createdby",
|
||||
"creatorid",
|
||||
"creator":
|
||||
us.CreatedBy = MakeUserstampFromRef(v.Value)
|
||||
delete(r.Values, k)
|
||||
|
||||
case "updatedby":
|
||||
us.UpdatedBy = MakeUserstampFromRef(v.Value)
|
||||
delete(r.Values, k)
|
||||
|
||||
case "deletedby":
|
||||
us.DeletedBy = MakeUserstampFromRef(v.Value)
|
||||
delete(r.Values, k)
|
||||
|
||||
case "ownedby",
|
||||
"ownerid",
|
||||
"owner":
|
||||
us.OwnedBy = MakeUserstampFromRef(v.Value)
|
||||
delete(r.Values, k)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
r.Us = us
|
||||
}
|
||||
|
||||
func (crt *composeRecordShaper) cloneValues(r *ComposeRecordRaw) map[string]ComposeRecordRawValue {
|
||||
rr := make(map[string]ComposeRecordRawValue)
|
||||
for k, v := range r.Values {
|
||||
rr[k] = ComposeRecordRawValue{
|
||||
Name: v.Name,
|
||||
Value: v.Value,
|
||||
}
|
||||
}
|
||||
return rr
|
||||
}
|
||||
|
||||
func (crt *composeRecordShaper) getKey(vv map[string]string, kk []string) (rtr string) {
|
||||
if len(kk) <= 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, k := range kk {
|
||||
rtr += k + "."
|
||||
}
|
||||
// Remove the trailing dot
|
||||
return vv[rtr[0:len(rtr)-1]]
|
||||
}
|
||||
77
server/pkg/envoy/resource/compose_record_template.go
Normal file
77
server/pkg/envoy/resource/compose_record_template.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
type (
|
||||
MappingTpl struct {
|
||||
// Index is like Cell, but the index
|
||||
Index uint
|
||||
Cell string
|
||||
Field string
|
||||
|
||||
// If specifies when the field should be mapped
|
||||
// @todo
|
||||
If string
|
||||
|
||||
// Expr specifies how to aditionally manipulate the value
|
||||
// @todo
|
||||
Expr string
|
||||
}
|
||||
MappingTplSet []*MappingTpl
|
||||
|
||||
ComposeRecordTemplate struct {
|
||||
// We'll do this so it conforms to the resource.Interface
|
||||
*base
|
||||
|
||||
ModRef *Ref
|
||||
NsRef *Ref
|
||||
|
||||
// Name is the source name; topically file name
|
||||
Name string
|
||||
// Key determines what defines an identifier
|
||||
Key []string
|
||||
FieldMap MappingTplSet
|
||||
Defaultable bool
|
||||
}
|
||||
)
|
||||
|
||||
// NewComposeRecordTemplate returns a record template based on the provided parameters.
|
||||
//
|
||||
// The template is only valid up until the resource shaping; it is not allowed after the fact.
|
||||
func NewComposeRecordTemplate(modRef, nsRef, name string, defaultable bool, fieldMap MappingTplSet, key ...string) *ComposeRecordTemplate {
|
||||
r := &ComposeRecordTemplate{base: &base{}}
|
||||
r.Name = name
|
||||
r.Key = key
|
||||
r.FieldMap = fieldMap
|
||||
r.Defaultable = defaultable
|
||||
|
||||
r.NsRef = r.AddRef(types.NamespaceResourceType, nsRef)
|
||||
r.ModRef = r.AddRef(types.ModuleResourceType, modRef).Constraint(r.NsRef)
|
||||
|
||||
r.SetResourceType(DataSourceResourceType)
|
||||
r.AddIdentifier(identifiers(name)...)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ComposeRecordTemplate) Resource() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MapToMappingTplSet converts the given string map to a propper MappingTplSet
|
||||
func MapToMappingTplSet(b map[string]string) MappingTplSet {
|
||||
mp := make(MappingTplSet, 0, len(b))
|
||||
for c, f := range b {
|
||||
mp = append(mp, &MappingTpl{
|
||||
Cell: c,
|
||||
Field: f,
|
||||
})
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
func (t *MappingTpl) IsIgnored() bool {
|
||||
// @todo expand this?
|
||||
return t.Field == "/"
|
||||
}
|
||||
30
server/pkg/envoy/resource/dataset.go
Normal file
30
server/pkg/envoy/resource/dataset.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package resource
|
||||
|
||||
type (
|
||||
provider interface {
|
||||
Fields() []string
|
||||
Count() uint64
|
||||
Reset() error
|
||||
Next() (map[string]string, error)
|
||||
}
|
||||
|
||||
ResourceDataset struct {
|
||||
*base
|
||||
|
||||
P provider
|
||||
}
|
||||
)
|
||||
|
||||
func NewResourceDataset(name string, p provider) *ResourceDataset {
|
||||
r := &ResourceDataset{base: &base{}}
|
||||
r.P = p
|
||||
|
||||
r.SetResourceType(DataSourceResourceType)
|
||||
r.AddIdentifier(identifiers(name)...)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ResourceDataset) Resource() interface{} {
|
||||
return nil
|
||||
}
|
||||
24
server/pkg/envoy/resource/rbac_references_automation.gen.go
generated
Normal file
24
server/pkg/envoy/resource/rbac_references_automation.gen.go
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
)
|
||||
|
||||
// AutomationWorkflowRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func AutomationWorkflowRbacReferences(workflow string) (res *Ref, pp []*Ref, err error) {
|
||||
if workflow != "*" {
|
||||
res = &Ref{ResourceType: types.WorkflowResourceType, Identifiers: MakeIdentifiers(workflow)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
129
server/pkg/envoy/resource/rbac_references_compose.gen.go
generated
Normal file
129
server/pkg/envoy/resource/rbac_references_compose.gen.go
generated
Normal file
@@ -0,0 +1,129 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
// ComposeChartRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeChartRbacReferences(namespaceID string, chart string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespaceID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
}
|
||||
if chart != "*" {
|
||||
res = &Ref{ResourceType: types.ChartResourceType, Identifiers: MakeIdentifiers(chart)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeModuleRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeModuleRbacReferences(namespaceID string, module string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespaceID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
}
|
||||
if module != "*" {
|
||||
res = &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(module)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeModuleFieldRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeModuleFieldRbacReferences(namespaceID string, moduleID string, moduleField string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespaceID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
}
|
||||
if moduleID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(moduleID)})
|
||||
}
|
||||
if moduleField != "*" {
|
||||
res = &Ref{ResourceType: types.ModuleFieldResourceType, Identifiers: MakeIdentifiers(moduleField)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeNamespaceRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeNamespaceRbacReferences(namespace string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespace != "*" {
|
||||
res = &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespace)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposePageRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposePageRbacReferences(namespaceID string, page string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespaceID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
}
|
||||
if page != "*" {
|
||||
res = &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(page)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposePageLayoutRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposePageLayoutRbacReferences(namespaceID string, pageID string, pageLayout string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespaceID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
}
|
||||
if pageID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(pageID)})
|
||||
}
|
||||
if pageLayout != "*" {
|
||||
res = &Ref{ResourceType: types.PageLayoutResourceType, Identifiers: MakeIdentifiers(pageLayout)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeRecordRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeRecordRbacReferences(namespaceID string, moduleID string, record string) (res *Ref, pp []*Ref, err error) {
|
||||
if namespaceID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
}
|
||||
if moduleID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(moduleID)})
|
||||
}
|
||||
if record != "*" {
|
||||
res = &Ref{ResourceType: types.RecordResourceType, Identifiers: MakeIdentifiers(record)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
56
server/pkg/envoy/resource/rbac_references_federation.gen.go
generated
Normal file
56
server/pkg/envoy/resource/rbac_references_federation.gen.go
generated
Normal file
@@ -0,0 +1,56 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/federation/types"
|
||||
)
|
||||
|
||||
// FederationNodeRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func FederationNodeRbacReferences(node string) (res *Ref, pp []*Ref, err error) {
|
||||
if node != "*" {
|
||||
res = &Ref{ResourceType: types.NodeResourceType, Identifiers: MakeIdentifiers(node)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FederationExposedModuleRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func FederationExposedModuleRbacReferences(nodeID string, exposedModule string) (res *Ref, pp []*Ref, err error) {
|
||||
if nodeID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NodeResourceType, Identifiers: MakeIdentifiers(nodeID)})
|
||||
}
|
||||
if exposedModule != "*" {
|
||||
res = &Ref{ResourceType: types.ExposedModuleResourceType, Identifiers: MakeIdentifiers(exposedModule)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FederationSharedModuleRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func FederationSharedModuleRbacReferences(nodeID string, sharedModule string) (res *Ref, pp []*Ref, err error) {
|
||||
if nodeID != "*" {
|
||||
pp = append(pp, &Ref{ResourceType: types.NodeResourceType, Identifiers: MakeIdentifiers(nodeID)})
|
||||
}
|
||||
if sharedModule != "*" {
|
||||
res = &Ref{ResourceType: types.SharedModuleResourceType, Identifiers: MakeIdentifiers(sharedModule)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
141
server/pkg/envoy/resource/rbac_references_system.gen.go
generated
Normal file
141
server/pkg/envoy/resource/rbac_references_system.gen.go
generated
Normal file
@@ -0,0 +1,141 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
// SystemApplicationRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemApplicationRbacReferences(application string) (res *Ref, pp []*Ref, err error) {
|
||||
if application != "*" {
|
||||
res = &Ref{ResourceType: types.ApplicationResourceType, Identifiers: MakeIdentifiers(application)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemApigwRouteRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemApigwRouteRbacReferences(apigwRoute string) (res *Ref, pp []*Ref, err error) {
|
||||
if apigwRoute != "*" {
|
||||
res = &Ref{ResourceType: types.ApigwRouteResourceType, Identifiers: MakeIdentifiers(apigwRoute)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemAuthClientRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemAuthClientRbacReferences(authClient string) (res *Ref, pp []*Ref, err error) {
|
||||
if authClient != "*" {
|
||||
res = &Ref{ResourceType: types.AuthClientResourceType, Identifiers: MakeIdentifiers(authClient)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemDataPrivacyRequestRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemDataPrivacyRequestRbacReferences(dataPrivacyRequest string) (res *Ref, pp []*Ref, err error) {
|
||||
if dataPrivacyRequest != "*" {
|
||||
res = &Ref{ResourceType: types.DataPrivacyRequestResourceType, Identifiers: MakeIdentifiers(dataPrivacyRequest)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemQueueRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemQueueRbacReferences(queue string) (res *Ref, pp []*Ref, err error) {
|
||||
if queue != "*" {
|
||||
res = &Ref{ResourceType: types.QueueResourceType, Identifiers: MakeIdentifiers(queue)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemReportRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemReportRbacReferences(report string) (res *Ref, pp []*Ref, err error) {
|
||||
if report != "*" {
|
||||
res = &Ref{ResourceType: types.ReportResourceType, Identifiers: MakeIdentifiers(report)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemRoleRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemRoleRbacReferences(role string) (res *Ref, pp []*Ref, err error) {
|
||||
if role != "*" {
|
||||
res = &Ref{ResourceType: types.RoleResourceType, Identifiers: MakeIdentifiers(role)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemTemplateRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemTemplateRbacReferences(template string) (res *Ref, pp []*Ref, err error) {
|
||||
if template != "*" {
|
||||
res = &Ref{ResourceType: types.TemplateResourceType, Identifiers: MakeIdentifiers(template)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemUserRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemUserRbacReferences(user string) (res *Ref, pp []*Ref, err error) {
|
||||
if user != "*" {
|
||||
res = &Ref{ResourceType: types.UserResourceType, Identifiers: MakeIdentifiers(user)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SystemDalConnectionRbacReferences generates RBAC references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func SystemDalConnectionRbacReferences(dalConnection string) (res *Ref, pp []*Ref, err error) {
|
||||
if dalConnection != "*" {
|
||||
res = &Ref{ResourceType: types.DalConnectionResourceType, Identifiers: MakeIdentifiers(dalConnection)}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
122
server/pkg/envoy/resource/rbac_rule.go
Normal file
122
server/pkg/envoy/resource/rbac_rule.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
composeTypes "github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
)
|
||||
|
||||
type (
|
||||
RbacRule struct {
|
||||
*base
|
||||
Res *rbac.Rule
|
||||
|
||||
RefResource string
|
||||
RefRes *Ref
|
||||
RefRole *Ref
|
||||
RefPath []*Ref
|
||||
}
|
||||
)
|
||||
|
||||
func NewRbacRule(res *rbac.Rule, refRole, refRes *Ref, refResource string, refPath ...*Ref) *RbacRule {
|
||||
r := &RbacRule{base: &base{}}
|
||||
r.SetResourceType(RbacResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.RefRole = r.addRef(refRole)
|
||||
|
||||
r.RefResource = refResource
|
||||
if refRes != nil {
|
||||
r.RefRes = r.addRef(refRes)
|
||||
}
|
||||
|
||||
// any additional constraints
|
||||
for i, rp := range refPath {
|
||||
ref := MakeRef(rp.ResourceType, rp.Identifiers)
|
||||
|
||||
if r.RefRes != nil {
|
||||
r.RefRes.Constraint(ref)
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
for j := i - 1; j < i; j++ {
|
||||
aux := refPath[j]
|
||||
ref = ref.Constraint(MakeRef(aux.ResourceType, aux.Identifiers))
|
||||
}
|
||||
}
|
||||
|
||||
r.RefPath = append(r.RefPath, r.addRef(ref))
|
||||
}
|
||||
|
||||
// Handle cases for nested resources
|
||||
if refRes != nil {
|
||||
switch refRes.ResourceType {
|
||||
case composeTypes.RecordResourceType:
|
||||
r.handleComposeRecord(res, refPath)
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
r.handleComposeModuleField(res, refPath)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *RbacRule) WrapError(act string, err error) error {
|
||||
return fmt.Errorf("%s %s %v: %s",
|
||||
act,
|
||||
r.ResourceType(),
|
||||
fmt.Sprintf("{ role: %s, resource: %s, operation: %s, access: %s }", r.RefRole.Identifiers.First(), r.RefResource, r.Res.Operation, r.Res.Access),
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
func (r *RbacRule) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *RbacRule) ReRef(old RefSet, new RefSet) {
|
||||
r.base.ReRef(old, new)
|
||||
|
||||
// Care for wildcards
|
||||
if r.RefRes != nil {
|
||||
for i, o := range old {
|
||||
if o.equals(r.RefRes) {
|
||||
r.RefRes = new[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i, o := range old {
|
||||
if RefSet(r.RefPath).findRef(o) > -1 {
|
||||
r.RefPath = RefSet(r.RefPath).replaceRef(o, new[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RbacRule) handleComposeRecord(res *rbac.Rule, refPath []*Ref) {
|
||||
|
||||
// records are grouped under module
|
||||
|
||||
if len(refPath) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
r.AddRef(composeTypes.RecordResourceType, refPath[1].Identifiers.StringSlice()...)
|
||||
}
|
||||
|
||||
func (r *RbacRule) handleComposeModuleField(res *rbac.Rule, refPath []*Ref) {
|
||||
|
||||
// module fields are grouped under module
|
||||
|
||||
if len(refPath) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
r.AddRef(composeTypes.ModuleFieldResourceTranslationType, refPath[1].Identifiers.StringSlice()...)
|
||||
}
|
||||
|
||||
func RbacResourceErrNotFound(ii Identifiers) error {
|
||||
return fmt.Errorf("rbac resource not found %v", ii.StringSlice())
|
||||
}
|
||||
282
server/pkg/envoy/resource/rbac_rules_parse.gen.go
generated
Normal file
282
server/pkg/envoy/resource/rbac_rules_parse.gen.go
generated
Normal file
@@ -0,0 +1,282 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
automationTypes "github.com/cortezaproject/corteza/server/automation/types"
|
||||
composeTypes "github.com/cortezaproject/corteza/server/compose/types"
|
||||
federationTypes "github.com/cortezaproject/corteza/server/federation/types"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Parse generates resource setting logic for each resource
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ParseRule(res string) (string, *Ref, []*Ref, error) {
|
||||
if res == "" {
|
||||
return "", nil, nil, fmt.Errorf("empty resource")
|
||||
}
|
||||
|
||||
sp := "/"
|
||||
|
||||
res = strings.TrimSpace(res)
|
||||
res = strings.TrimRight(res, sp)
|
||||
rr := strings.Split(res, sp)
|
||||
|
||||
// only service defined (corteza::system, corteza::compose, ...)
|
||||
if len(rr) == 1 {
|
||||
return res, nil, nil, nil
|
||||
}
|
||||
|
||||
// full thing
|
||||
resourceType, path := rr[0], rr[1:]
|
||||
|
||||
for p := 1; p < len(path); p++ {
|
||||
if path[p] != "*" && path[p-1] == "*" {
|
||||
return "", nil, nil, fmt.Errorf("invalid path wildcard combination for '%s'", res)
|
||||
}
|
||||
}
|
||||
|
||||
// make the resource provide the slice of parent resources we should nest under
|
||||
switch resourceType {
|
||||
case systemTypes.ApplicationResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemApplicationRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.ApigwRouteResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemApigwRouteRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.AuthClientResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemAuthClientRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.DataPrivacyRequestResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemDataPrivacyRequestRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.QueueResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemQueueRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.ReportResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemReportRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.RoleResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemRoleRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.TemplateResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemTemplateRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.UserResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemUserRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.DalConnectionResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := SystemDalConnectionRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.ChartResourceType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeChartRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.ModuleResourceType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeModuleRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.ModuleFieldResourceType:
|
||||
if len(path) != 3 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeModuleFieldRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
path[2],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.NamespaceResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeNamespaceRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.PageResourceType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposePageRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.PageLayoutResourceType:
|
||||
if len(path) != 3 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposePageLayoutRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
path[2],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case composeTypes.RecordResourceType:
|
||||
if len(path) != 3 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeRecordRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
path[2],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case automationTypes.WorkflowResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := AutomationWorkflowRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case federationTypes.NodeResourceType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := FederationNodeRbacReferences(
|
||||
path[0],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case federationTypes.ExposedModuleResourceType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := FederationExposedModuleRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case federationTypes.SharedModuleResourceType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := FederationSharedModuleRbacReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return resourceType, ref, pp, err
|
||||
|
||||
case systemTypes.ComponentResourceType:
|
||||
if len(path) != 0 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path))
|
||||
}
|
||||
|
||||
// Component resource, no path
|
||||
return resourceType, nil, nil, nil
|
||||
case composeTypes.ComponentResourceType:
|
||||
if len(path) != 0 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path))
|
||||
}
|
||||
|
||||
// Component resource, no path
|
||||
return resourceType, nil, nil, nil
|
||||
case automationTypes.ComponentResourceType:
|
||||
if len(path) != 0 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path))
|
||||
}
|
||||
|
||||
// Component resource, no path
|
||||
return resourceType, nil, nil, nil
|
||||
case federationTypes.ComponentResourceType:
|
||||
if len(path) != 0 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 0 reference components in path, got %d", len(path))
|
||||
}
|
||||
|
||||
// Component resource, no path
|
||||
return resourceType, nil, nil, nil
|
||||
}
|
||||
|
||||
// return unhandled resource as-is
|
||||
return resourceType, nil, nil, nil
|
||||
}
|
||||
121
server/pkg/envoy/resource/report.go
Normal file
121
server/pkg/envoy/resource/report.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Report struct {
|
||||
*base
|
||||
Res *types.Report
|
||||
|
||||
Sources []*ReportSource
|
||||
Blocks []*ReportBlock
|
||||
}
|
||||
|
||||
ReportSource struct {
|
||||
*base
|
||||
Res *types.ReportDataSource
|
||||
}
|
||||
|
||||
ReportBlock struct {
|
||||
*base
|
||||
Res *types.ReportBlock
|
||||
}
|
||||
)
|
||||
|
||||
func NewReport(res *types.Report) *Report {
|
||||
r := &Report{
|
||||
base: &base{},
|
||||
}
|
||||
r.SetResourceType(types.ReportResourceType)
|
||||
r.Res = res
|
||||
|
||||
r.AddIdentifier(identifiers(res.Handle, res.ID)...)
|
||||
|
||||
// Initial stamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&res.CreatedAt, res.UpdatedAt, res.DeletedAt, nil))
|
||||
r.SetUserstamps(MakeUserstampsCUDO(res.CreatedBy, res.UpdatedBy, res.DeletedBy, res.OwnedBy))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Report) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *Report) AddReportSource(res *types.ReportDataSource) *ReportSource {
|
||||
s := &ReportSource{
|
||||
base: &base{},
|
||||
}
|
||||
|
||||
s.Res = res
|
||||
r.Sources = append(r.Sources, s)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Report) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.ReportRbacResourceTpl(), types.ReportResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// func (r *Report) ResourceTranslationParts() (resource string, ref *Ref, path []*Ref) {
|
||||
// ref = r.Ref()
|
||||
// path = nil
|
||||
// resource = fmt.Sprintf(types.ReportResourceTranslationTpl(), types.ReportResourceTranslationType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
// return
|
||||
// }
|
||||
|
||||
func (r *Report) AddReportBlock(res *types.ReportBlock) *ReportBlock {
|
||||
p := &ReportBlock{
|
||||
base: &base{},
|
||||
}
|
||||
|
||||
p.Res = res
|
||||
r.Blocks = append(r.Blocks, p)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *Report) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Report) encodeTranslations() ([]*ResourceTranslation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// FindReport looks for the workflow in the resource set
|
||||
func FindReport(rr InterfaceSet, ii Identifiers) (ns *types.Report) {
|
||||
var wfRes *Report
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
wr, ok := r.(*Report)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if wr.Identifiers().HasAny(ii) {
|
||||
wfRes = wr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if wfRes != nil {
|
||||
return wfRes.Res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReportErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("report unresolved %v", ii.StringSlice())
|
||||
}
|
||||
232
server/pkg/envoy/resource/resource.go
Normal file
232
server/pkg/envoy/resource/resource.go
Normal file
@@ -0,0 +1,232 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
composeTypes "github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
base struct {
|
||||
rt string
|
||||
ii Identifiers
|
||||
rr RefSet
|
||||
ph bool
|
||||
|
||||
ts *Timestamps
|
||||
us *Userstamps
|
||||
cfg *EnvoyConfig
|
||||
urefs RefSet
|
||||
}
|
||||
|
||||
EnvoyConfig struct {
|
||||
// SkipIf determines when the encoding should be skipped for this resource
|
||||
SkipIf string
|
||||
OnExisting MergeAlg
|
||||
}
|
||||
|
||||
MergeAlg int
|
||||
)
|
||||
|
||||
const (
|
||||
// Default takes the operation defined default
|
||||
Default MergeAlg = iota
|
||||
// Skip skips the existing resource
|
||||
Skip
|
||||
// Replace replaces the existing resource
|
||||
Replace
|
||||
// MergeLeft updates the existing resource, giving priority to the existing data
|
||||
MergeLeft
|
||||
// MergeRight updates the existing resource, giving priority to the new data
|
||||
MergeRight
|
||||
)
|
||||
|
||||
// fn converts identifier values (string, fmt.Stringer, uint64) to string slice
|
||||
//
|
||||
// Each value is checked and should not be empty or zero
|
||||
func identifiers(ii ...interface{}) []string {
|
||||
ss := make([]string, 0, len(ii))
|
||||
|
||||
for _, i := range ii {
|
||||
switch c := i.(type) {
|
||||
case uint64:
|
||||
if c == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
ss = append(ss, strconv.FormatUint(c, 10))
|
||||
|
||||
case fmt.Stringer:
|
||||
if c.String() == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
ss = append(ss, c.String())
|
||||
|
||||
case string:
|
||||
if c == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
ss = append(ss, c)
|
||||
}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// Check checks if the identifier c is in the set of identifiers ii
|
||||
func Check(a string, ii ...interface{}) bool {
|
||||
for _, i := range ii {
|
||||
switch pi := i.(type) {
|
||||
case string:
|
||||
if a == pi {
|
||||
return true
|
||||
}
|
||||
case uint64:
|
||||
if pi > 0 && strconv.FormatUint(pi, 10) == i {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AddIdentifier adds a set of identifiers to the current resource
|
||||
func (t *base) AddIdentifier(ss ...string) {
|
||||
t.ii = t.ii.Add(ss...)
|
||||
}
|
||||
|
||||
// SetIdentifier sets the identifiers to whatever was provided
|
||||
func (t *base) SetIdentifier(ii Identifiers) {
|
||||
t.ii = ii
|
||||
}
|
||||
|
||||
// AddRef adds a new reference to the current resource
|
||||
func (t *base) AddRef(rt string, ii ...string) *Ref {
|
||||
iiC := make([]string, 0, len(ii))
|
||||
for _, i := range ii {
|
||||
if i != "" {
|
||||
iiC = append(iiC, i)
|
||||
}
|
||||
}
|
||||
|
||||
return t.addRef(&Ref{ResourceType: rt, Identifiers: Identifiers{}.Add(iiC...)})
|
||||
}
|
||||
|
||||
func (t *base) addRef(r *Ref) *Ref {
|
||||
t.rr = append(t.rr, r)
|
||||
return r
|
||||
}
|
||||
|
||||
// ReplaceRef replaces the given ref with the new one.
|
||||
// The new ref is added regardles if the old one exists or not.
|
||||
func (t *base) ReplaceRef(old, new *Ref) {
|
||||
t.rr = t.rr.replaceRef(old, new)
|
||||
}
|
||||
|
||||
// SetResourceType sets the resource type of the current resource struct
|
||||
func (t *base) SetResourceType(rt string) {
|
||||
t.rt = rt
|
||||
}
|
||||
|
||||
func (t *base) SetTimestamps(ts *Timestamps) {
|
||||
t.ts = ts
|
||||
}
|
||||
|
||||
func (t *base) Timestamps() *Timestamps {
|
||||
return t.ts
|
||||
}
|
||||
|
||||
func (t *base) SetUserstamps(us *Userstamps) {
|
||||
t.us = us
|
||||
|
||||
if us != nil {
|
||||
uu := []*Userstamp{us.CreatedBy, us.UpdatedBy, us.DeletedBy, us.OwnedBy, us.RunAs}
|
||||
t.SetUserRefs(uu)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *base) Userstamps() *Userstamps {
|
||||
return t.us
|
||||
}
|
||||
|
||||
func (t *base) SetConfig(cfg *EnvoyConfig) {
|
||||
t.cfg = cfg
|
||||
}
|
||||
|
||||
func (t *base) Config() *EnvoyConfig {
|
||||
return t.cfg
|
||||
}
|
||||
|
||||
func (t *base) SetUserRefs(uu []*Userstamp) {
|
||||
if t.urefs == nil {
|
||||
t.urefs = make(RefSet, 0, 4)
|
||||
}
|
||||
|
||||
for _, u := range uu {
|
||||
if u == nil {
|
||||
continue
|
||||
}
|
||||
if u.UserID > 0 {
|
||||
t.urefs = append(t.urefs, t.AddRef(types.UserResourceType, strconv.FormatUint(u.UserID, 10)))
|
||||
} else if u.Ref != "" {
|
||||
t.urefs = append(t.urefs, t.AddRef(types.UserResourceType, u.Ref))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *base) UserRefs() RefSet {
|
||||
return t.urefs
|
||||
}
|
||||
|
||||
func (t *base) Identifiers() Identifiers {
|
||||
return t.ii
|
||||
}
|
||||
|
||||
func (t *base) ResourceType() string {
|
||||
return t.rt
|
||||
}
|
||||
|
||||
func (t *base) Refs() RefSet {
|
||||
return t.rr
|
||||
}
|
||||
|
||||
func (t *base) Ref() *Ref {
|
||||
return &Ref{ResourceType: t.rt, Identifiers: t.ii}
|
||||
}
|
||||
|
||||
func (t *base) HasRefs() bool {
|
||||
return t.rr == nil || len(t.rr) == 0
|
||||
}
|
||||
|
||||
// MarkPlaceholder denotes that the given resource should be treated as a placeholder
|
||||
//
|
||||
// Placeholder resources should not be encoded but should only provide additional
|
||||
// context to resources that depend on it
|
||||
func (t *base) MarkPlaceholder() {
|
||||
t.ph = true
|
||||
}
|
||||
|
||||
// Placeholder resources should not be encoded but should only provide additional
|
||||
// context to resources that depend on it
|
||||
func (t *base) Placeholder() bool {
|
||||
return t.ph
|
||||
}
|
||||
|
||||
func IgnoreDepResolution(ref *Ref) bool {
|
||||
return ref.ResourceType == composeTypes.ModuleFieldResourceType
|
||||
}
|
||||
|
||||
func (t *base) ReID(ii Identifiers) {
|
||||
t.SetIdentifier(ii)
|
||||
}
|
||||
|
||||
func (t *base) ReRef(old RefSet, new RefSet) {
|
||||
for i, o := range old {
|
||||
t.ReplaceRef(o, new[i])
|
||||
}
|
||||
}
|
||||
80
server/pkg/envoy/resource/resource_translation.gen.go
generated
Normal file
80
server/pkg/envoy/resource/resource_translation.gen.go
generated
Normal file
@@ -0,0 +1,80 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
func (r *ComposeChart) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
tmp, err := r.encodeTranslations()
|
||||
return append(out, tmp...), err
|
||||
|
||||
}
|
||||
func (r *ComposeModule) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
tmp, err := r.encodeTranslations()
|
||||
return append(out, tmp...), err
|
||||
|
||||
}
|
||||
func (r *ComposeModuleField) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
return out, nil
|
||||
}
|
||||
func (r *ComposeNamespace) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
return out, nil
|
||||
}
|
||||
func (r *ComposePage) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
tmp, err := r.encodeTranslations()
|
||||
return append(out, tmp...), err
|
||||
|
||||
}
|
||||
func (r *ComposePageLayout) EncodeTranslations() ([]*ResourceTranslation, error) {
|
||||
out := make([]*ResourceTranslation, 0, 10)
|
||||
|
||||
rr := r.Res.EncodeTranslations()
|
||||
rr.SetLanguage(defaultLanguage)
|
||||
res, ref, pp := r.ResourceTranslationParts()
|
||||
out = append(out, NewResourceTranslation(systemTypes.FromLocale(rr), res, ref, pp...))
|
||||
|
||||
tmp, err := r.encodeTranslations()
|
||||
return append(out, tmp...), err
|
||||
|
||||
}
|
||||
92
server/pkg/envoy/resource/resource_translation.go
Normal file
92
server/pkg/envoy/resource/resource_translation.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type (
|
||||
ResourceTranslation struct {
|
||||
*base
|
||||
Res types.ResourceTranslationSet
|
||||
|
||||
RefResource string
|
||||
RefRes *Ref
|
||||
RefPath []*Ref
|
||||
|
||||
Priority int
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
defaultLanguage = language.English
|
||||
)
|
||||
|
||||
func NewResourceTranslation(res types.ResourceTranslationSet, refResource string, refRes *Ref, refPath ...*Ref) *ResourceTranslation {
|
||||
r := &ResourceTranslation{base: &base{}}
|
||||
r.SetResourceType(ResourceTranslationType)
|
||||
r.Res = res
|
||||
|
||||
r.RefResource = refResource
|
||||
r.RefRes = r.addRef(refRes)
|
||||
|
||||
// any additional constraints
|
||||
for i, rp := range refPath {
|
||||
ref := MakeRef(rp.ResourceType, rp.Identifiers)
|
||||
|
||||
r.RefRes.Constraint(ref)
|
||||
if i > 0 {
|
||||
for j := i - 1; j < i; j++ {
|
||||
aux := refPath[j]
|
||||
ref = ref.Constraint(MakeRef(aux.ResourceType, aux.Identifiers))
|
||||
}
|
||||
}
|
||||
|
||||
r.RefPath = append(r.RefPath, r.addRef(ref))
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *ResourceTranslation) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *ResourceTranslation) ReRef(old RefSet, new RefSet) {
|
||||
r.base.ReRef(old, new)
|
||||
|
||||
for i, o := range old {
|
||||
if o.equals(r.RefRes) {
|
||||
r.RefRes = new[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for i, o := range old {
|
||||
if RefSet(r.RefPath).findRef(o) > -1 {
|
||||
r.RefPath = RefSet(r.RefPath).replaceRef(o, new[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ResourceTranslation) MarkDefault() {
|
||||
l.Priority = 1
|
||||
}
|
||||
|
||||
func (l *ResourceTranslation) IsDefault() bool {
|
||||
return l.Priority == 1
|
||||
}
|
||||
|
||||
func (l *ResourceTranslation) MarkGeneric() {
|
||||
l.Priority = 0
|
||||
}
|
||||
|
||||
func (l *ResourceTranslation) IsGeneric() bool {
|
||||
return l.Priority == 0
|
||||
}
|
||||
|
||||
func ResourceTranslationErrNotFound(ii Identifiers) error {
|
||||
return fmt.Errorf("resource translation not found %v", ii.StringSlice())
|
||||
}
|
||||
115
server/pkg/envoy/resource/resource_translation_parse.gen.go
generated
Normal file
115
server/pkg/envoy/resource/resource_translation_parse.gen.go
generated
Normal file
@@ -0,0 +1,115 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
composeTypes "github.com/cortezaproject/corteza/server/compose/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseResourceTranslation generates resource setting logic for each resource
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ParseResourceTranslation(res string) (string, *Ref, []*Ref, error) {
|
||||
if res == "" {
|
||||
return "", nil, nil, fmt.Errorf("empty resource")
|
||||
}
|
||||
|
||||
sp := "/"
|
||||
|
||||
if strings.Index(res, "corteza::") == 0 {
|
||||
res = res[9:]
|
||||
}
|
||||
|
||||
res = strings.TrimSpace(res)
|
||||
res = strings.TrimRight(res, sp)
|
||||
rr := strings.Split(res, sp)
|
||||
|
||||
// only service defined (corteza::system, corteza::compose, ...)
|
||||
if len(rr) == 1 {
|
||||
return "", nil, nil, fmt.Errorf("only service defined: %s", res)
|
||||
}
|
||||
|
||||
// full thing
|
||||
resourceType, path := rr[0], rr[1:]
|
||||
for p := 1; p < len(path); p++ {
|
||||
if path[p] == "*" {
|
||||
return "", nil, nil, fmt.Errorf("path wildcard not allowed for locale resources: '%s'", res)
|
||||
}
|
||||
}
|
||||
|
||||
// make the resource provide the slice of parent resources we should nest under
|
||||
switch resourceType {
|
||||
case composeTypes.ChartResourceTranslationType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeChartResourceTranslationReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return composeTypes.ChartResourceTranslationType, ref, pp, err
|
||||
|
||||
case composeTypes.ModuleResourceTranslationType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeModuleResourceTranslationReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return composeTypes.ModuleResourceTranslationType, ref, pp, err
|
||||
|
||||
case composeTypes.ModuleFieldResourceTranslationType:
|
||||
if len(path) != 3 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeModuleFieldResourceTranslationReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
path[2],
|
||||
)
|
||||
return composeTypes.ModuleFieldResourceTranslationType, ref, pp, err
|
||||
|
||||
case composeTypes.NamespaceResourceTranslationType:
|
||||
if len(path) != 1 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 1 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposeNamespaceResourceTranslationReferences(
|
||||
path[0],
|
||||
)
|
||||
return composeTypes.NamespaceResourceTranslationType, ref, pp, err
|
||||
|
||||
case composeTypes.PageResourceTranslationType:
|
||||
if len(path) != 2 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 2 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposePageResourceTranslationReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
)
|
||||
return composeTypes.PageResourceTranslationType, ref, pp, err
|
||||
|
||||
case composeTypes.PageLayoutResourceTranslationType:
|
||||
if len(path) != 3 {
|
||||
return "", nil, nil, fmt.Errorf("expecting 3 reference components in path, got %d", len(path))
|
||||
}
|
||||
ref, pp, err := ComposePageLayoutResourceTranslationReferences(
|
||||
path[0],
|
||||
path[1],
|
||||
path[2],
|
||||
)
|
||||
return composeTypes.PageLayoutResourceTranslationType, ref, pp, err
|
||||
|
||||
}
|
||||
|
||||
// return unhandled resource as-is
|
||||
return resourceType, nil, nil, nil
|
||||
}
|
||||
25
server/pkg/envoy/resource/resource_translation_references_automation.gen.go
generated
Normal file
25
server/pkg/envoy/resource/resource_translation_references_automation.gen.go
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
// Definitions file that controls how this file is generated:
|
||||
// - automation.workflow.yaml
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/automation/types"
|
||||
)
|
||||
|
||||
// AutomationWorkflowResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// Resources with "envoy: false" are skipped
|
||||
//
|
||||
// This function is auto-generated
|
||||
func AutomationWorkflowResourceTranslationReferences(workflow string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.WorkflowResourceType, Identifiers: MakeIdentifiers(workflow)}
|
||||
|
||||
return
|
||||
}
|
||||
72
server/pkg/envoy/resource/resource_translation_references_compose.gen.go
generated
Normal file
72
server/pkg/envoy/resource/resource_translation_references_compose.gen.go
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
package resource
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
//
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
)
|
||||
|
||||
// ComposeChartResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeChartResourceTranslationReferences(namespaceID string, self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.ChartResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeModuleResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeModuleResourceTranslationReferences(namespaceID string, self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeModuleFieldResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeModuleFieldResourceTranslationReferences(namespaceID string, moduleID string, self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.ModuleFieldResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
pp = append(pp, &Ref{ResourceType: types.ModuleResourceType, Identifiers: MakeIdentifiers(moduleID)})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposeNamespaceResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposeNamespaceResourceTranslationReferences(self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposePageResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposePageResourceTranslationReferences(namespaceID string, self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ComposePageLayoutResourceTranslationReferences generates Locale references
|
||||
//
|
||||
// This function is auto-generated
|
||||
func ComposePageLayoutResourceTranslationReferences(namespaceID string, pageID string, self string) (res *Ref, pp []*Ref, err error) {
|
||||
res = &Ref{ResourceType: types.PageLayoutResourceType, Identifiers: MakeIdentifiers(self)}
|
||||
pp = append(pp, &Ref{ResourceType: types.NamespaceResourceType, Identifiers: MakeIdentifiers(namespaceID)})
|
||||
pp = append(pp, &Ref{ResourceType: types.PageResourceType, Identifiers: MakeIdentifiers(pageID)})
|
||||
|
||||
return
|
||||
}
|
||||
73
server/pkg/envoy/resource/role.go
Normal file
73
server/pkg/envoy/resource/role.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// Role represents a Role
|
||||
Role struct {
|
||||
*base
|
||||
Res *types.Role
|
||||
}
|
||||
)
|
||||
|
||||
func NewRole(rl *types.Role) *Role {
|
||||
r := &Role{base: &base{}}
|
||||
r.SetResourceType(types.RoleResourceType)
|
||||
r.Res = rl
|
||||
|
||||
r.AddIdentifier(identifiers(rl.Handle, rl.Name, rl.ID)...)
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(&rl.CreatedAt, rl.UpdatedAt, rl.DeletedAt, rl.ArchivedAt))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Role) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *Role) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Role) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.RoleRbacResourceTpl(), types.RoleResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindRole looks for the role in the resources
|
||||
func FindRole(rr InterfaceSet, ii Identifiers) (rl *types.Role) {
|
||||
var rlRes *Role
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
rr, ok := r.(*Role)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rr.Identifiers().HasAny(ii) {
|
||||
rlRes = rr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if rlRes != nil {
|
||||
return rlRes.Res
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RoleErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("role unresolved %v", ii.StringSlice())
|
||||
}
|
||||
57
server/pkg/envoy/resource/settings.go
Normal file
57
server/pkg/envoy/resource/settings.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Settings struct {
|
||||
*base
|
||||
Res types.SettingValueSet
|
||||
}
|
||||
|
||||
Setting struct {
|
||||
*base
|
||||
Res types.SettingValue
|
||||
}
|
||||
)
|
||||
|
||||
func NewSettings(vv map[string]interface{}) *Settings {
|
||||
r := &Settings{base: &base{}}
|
||||
r.SetResourceType(SettingsResourceType)
|
||||
|
||||
r.Res = make(types.SettingValueSet, 0, len(vv))
|
||||
for k, v := range vv {
|
||||
sv := &types.SettingValue{
|
||||
Name: k,
|
||||
}
|
||||
sv.SetSetting(v)
|
||||
r.Res = append(r.Res, sv)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func NewSetting(s *types.SettingValue) *Setting {
|
||||
r := &Setting{base: &base{}}
|
||||
r.SetResourceType(SettingsResourceType)
|
||||
r.Res = *s
|
||||
|
||||
r.AddIdentifier(identifiers(s.Name)...)
|
||||
|
||||
// Set initial stamps
|
||||
r.SetTimestamps(MakeTimestampsCUDA(nil, &s.UpdatedAt, nil, nil))
|
||||
r.SetUserstamps(&Userstamps{
|
||||
UpdatedBy: &Userstamp{UserID: s.UpdatedBy},
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Setting) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *Settings) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
64
server/pkg/envoy/resource/shaper.go
Normal file
64
server/pkg/envoy/resource/shaper.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package resource
|
||||
|
||||
import "fmt"
|
||||
|
||||
type (
|
||||
shaper interface {
|
||||
Shape([]Interface) ([]Interface, error)
|
||||
}
|
||||
)
|
||||
|
||||
// Shape shapes ResourceDatasets based on their correlated Template
|
||||
//
|
||||
// During the shaping step, no data is removed, nor added to the original resource slice.
|
||||
// The shapers are ran in the same order they were provided.
|
||||
func Shape(rr []Interface, ss ...shaper) ([]Interface, error) {
|
||||
ii := make([]Interface, 0, int(len(rr)/2))
|
||||
|
||||
// Firstly handle any resource shaping
|
||||
for _, s := range ss {
|
||||
sdd, err := s.Shape(rr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ii = append(ii, sdd...)
|
||||
}
|
||||
|
||||
// Cleanup the final shaped resource slice.
|
||||
// @todo make this cleaner!!1!'
|
||||
//
|
||||
// After this point, all of the data should be ready for further processing.
|
||||
for _, r := range rr {
|
||||
if _, ok := r.(*ComposeRecordTemplate); ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := r.(*ResourceDataset); ok {
|
||||
continue
|
||||
}
|
||||
|
||||
ii = append(ii, r)
|
||||
}
|
||||
|
||||
return ii, nil
|
||||
}
|
||||
|
||||
// findResourceDataset finds and returns the first dataset that matches the
|
||||
// provided identifiers.
|
||||
func findResourceDataset(rr []Interface, ii Identifiers) *ResourceDataset {
|
||||
for _, r := range rr {
|
||||
genR, ok := r.(*ResourceDataset)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if !genR.Identifiers().HasAny(ii) {
|
||||
continue
|
||||
}
|
||||
|
||||
return genR
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func genericSourceErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("generic source unresolved %v", ii.StringSlice())
|
||||
}
|
||||
73
server/pkg/envoy/resource/template.go
Normal file
73
server/pkg/envoy/resource/template.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// Template represents a Template
|
||||
Template struct {
|
||||
*base
|
||||
Res *types.Template
|
||||
}
|
||||
)
|
||||
|
||||
func NewTemplate(t *types.Template) *Template {
|
||||
r := &Template{base: &base{}}
|
||||
r.SetResourceType(types.TemplateResourceType)
|
||||
r.Res = t
|
||||
|
||||
r.AddIdentifier(identifiers(t.Handle, t.Meta.Short, t.ID)...)
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDAS(&t.CreatedAt, t.UpdatedAt, t.DeletedAt, nil, nil))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Template) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *Template) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *Template) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.TemplateRbacResourceTpl(), types.TemplateResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindTemplate looks for the template in the resources
|
||||
func FindTemplate(rr InterfaceSet, ii Identifiers) (u *types.Template) {
|
||||
var tRes *Template
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
tr, ok := r.(*Template)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if tr.Identifiers().HasAny(ii) {
|
||||
tRes = tr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if tRes != nil {
|
||||
return tRes.Res
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TemplateErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("template unresolved %v", ii.StringSlice())
|
||||
}
|
||||
119
server/pkg/envoy/resource/timestamps.go
Normal file
119
server/pkg/envoy/resource/timestamps.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
Timestamp struct {
|
||||
// S is a stringified representation of the timestamp
|
||||
S string
|
||||
// T is a time representation of the timestamp
|
||||
T *time.Time
|
||||
// Tz is the timezone the timestamp will be encoded into
|
||||
Tz string
|
||||
// Tpl is the template the timestamp will be encoded into
|
||||
Tpl string
|
||||
}
|
||||
Timestamps struct {
|
||||
CreatedAt *Timestamp
|
||||
UpdatedAt *Timestamp
|
||||
DeletedAt *Timestamp
|
||||
ArchivedAt *Timestamp
|
||||
SuspendedAt *Timestamp
|
||||
}
|
||||
)
|
||||
|
||||
func (ts *Timestamp) MarshalYAML() (interface{}, error) {
|
||||
return ts.S, nil
|
||||
}
|
||||
|
||||
func (ts *Timestamp) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(ts.S)
|
||||
}
|
||||
|
||||
// MakeTimestamp initializes a Timestamp from the passed timestamp
|
||||
func MakeTimestamp(ts string) *Timestamp {
|
||||
t := toTime(ts)
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Timestamp{
|
||||
S: ts,
|
||||
T: t,
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTimestampsCUDA initializes timestamps for createdAt, updatedAt, deletedAt and archivedAt
|
||||
func MakeTimestampsCUDA(c, u, d, a *time.Time) *Timestamps {
|
||||
t := &Timestamps{}
|
||||
|
||||
if c != nil && !c.IsZero() {
|
||||
t.CreatedAt = &Timestamp{T: c}
|
||||
}
|
||||
if u != nil && !u.IsZero() {
|
||||
t.UpdatedAt = &Timestamp{T: u}
|
||||
}
|
||||
if d != nil && !d.IsZero() {
|
||||
t.DeletedAt = &Timestamp{T: d}
|
||||
}
|
||||
if a != nil && !a.IsZero() {
|
||||
t.ArchivedAt = &Timestamp{T: a}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// MakeTimestampsCUDAS initializes timestamps for createdAt, updatedAt, deletedAt, archivedAt and suspendedAt
|
||||
func MakeTimestampsCUDAS(c, u, d, a, s *time.Time) *Timestamps {
|
||||
t := MakeTimestampsCUDA(c, u, d, a)
|
||||
|
||||
if s != nil && !s.IsZero() {
|
||||
t.SuspendedAt = &Timestamp{T: s}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// Model stringifies the timestamps based on the passed template and timezone
|
||||
func (tt *Timestamps) Model(tpl string, tz string) (*Timestamps, error) {
|
||||
var err error
|
||||
if tt.CreatedAt != nil {
|
||||
tt.CreatedAt, err = tt.CreatedAt.Model(tpl, tz)
|
||||
}
|
||||
if tt.UpdatedAt != nil {
|
||||
tt.UpdatedAt, err = tt.UpdatedAt.Model(tpl, tz)
|
||||
}
|
||||
if tt.DeletedAt != nil {
|
||||
tt.DeletedAt, err = tt.DeletedAt.Model(tpl, tz)
|
||||
}
|
||||
if tt.ArchivedAt != nil {
|
||||
tt.ArchivedAt, err = tt.ArchivedAt.Model(tpl, tz)
|
||||
}
|
||||
if tt.SuspendedAt != nil {
|
||||
tt.SuspendedAt, err = tt.SuspendedAt.Model(tpl, tz)
|
||||
}
|
||||
|
||||
return tt, err
|
||||
}
|
||||
|
||||
// Model stringifies the timestamp based on the passed template and timezone
|
||||
func (ts *Timestamp) Model(tpl string, tz string) (*Timestamp, error) {
|
||||
if tz != "" {
|
||||
tzL, err := time.LoadLocation(tz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := ts.T.In(tzL)
|
||||
ts.T = &t
|
||||
}
|
||||
|
||||
if tpl == "" {
|
||||
tpl = time.RFC3339
|
||||
}
|
||||
|
||||
ts.S = ts.T.Format(tpl)
|
||||
return ts, nil
|
||||
}
|
||||
343
server/pkg/envoy/resource/types.go
Normal file
343
server/pkg/envoy/resource/types.go
Normal file
@@ -0,0 +1,343 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type (
|
||||
Interface interface {
|
||||
Identifiers() Identifiers
|
||||
ResourceType() string
|
||||
Resource() interface{}
|
||||
Refs() RefSet
|
||||
MarkPlaceholder()
|
||||
Placeholder() bool
|
||||
ReID(Identifiers)
|
||||
ReRef(old RefSet, new RefSet)
|
||||
}
|
||||
|
||||
ErrorWrapper interface {
|
||||
WrapError(act string, err error) error
|
||||
}
|
||||
|
||||
InterfaceSet []Interface
|
||||
|
||||
IdentifiableInterface interface {
|
||||
Interface
|
||||
|
||||
SysID() uint64
|
||||
}
|
||||
|
||||
RefableInterface interface {
|
||||
Interface
|
||||
|
||||
Ref() string
|
||||
}
|
||||
|
||||
RBACInterface interface {
|
||||
Interface
|
||||
|
||||
RBACParts() (string, *Ref, []*Ref)
|
||||
}
|
||||
|
||||
LocaleInterface interface {
|
||||
Interface
|
||||
|
||||
ResourceTranslationParts() (string, *Ref, []*Ref)
|
||||
EncodeTranslations() ([]*ResourceTranslation, error)
|
||||
}
|
||||
|
||||
PrunableInterface interface {
|
||||
Interface
|
||||
|
||||
Prune(*Ref)
|
||||
}
|
||||
|
||||
RefSet []*Ref
|
||||
Ref struct {
|
||||
// @todo check with Denis regarding strings here (the cdocs comment)
|
||||
// @todo should this become node type instead?
|
||||
ResourceType string
|
||||
Identifiers Identifiers
|
||||
Constraints RefSet
|
||||
}
|
||||
|
||||
Identifiers []string
|
||||
)
|
||||
|
||||
var (
|
||||
DataSourceResourceType = "data:raw"
|
||||
SettingsResourceType = "setting"
|
||||
RbacResourceType = "rbac-rule"
|
||||
ResourceTranslationType = "resource-translation"
|
||||
)
|
||||
|
||||
func MakeRef(rt string, ii Identifiers) *Ref {
|
||||
return &Ref{ResourceType: rt, Identifiers: ii}
|
||||
}
|
||||
|
||||
func MakeWildRef(rt string) *Ref {
|
||||
return &Ref{ResourceType: rt, Identifiers: MakeIdentifiers("*")}
|
||||
}
|
||||
|
||||
func MakeIdentifiers(ss ...string) Identifiers {
|
||||
ii := make(Identifiers, 0, len(ss))
|
||||
ii = ii.Add(ss...)
|
||||
return ii
|
||||
}
|
||||
|
||||
func (ri Identifiers) Add(ii ...string) Identifiers {
|
||||
for _, i := range ii {
|
||||
if len(i) > 0 {
|
||||
ri = append(ri, i)
|
||||
}
|
||||
}
|
||||
|
||||
return ri
|
||||
}
|
||||
|
||||
func (ri Identifiers) Clone() Identifiers {
|
||||
out := make(Identifiers, 0, len(ri))
|
||||
out = append(out, ri...)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (ri Identifiers) HasAny(check Identifiers) bool {
|
||||
// The size of these will be tiny so no need for hashmaps
|
||||
for _, i := range ri {
|
||||
for _, j := range check {
|
||||
if i == j {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (ri Identifiers) StringSlice() []string {
|
||||
return ri
|
||||
}
|
||||
|
||||
func (ri Identifiers) First() string {
|
||||
if len(ri) == 0 {
|
||||
return ""
|
||||
}
|
||||
return ri[0]
|
||||
}
|
||||
|
||||
func (ri Identifiers) FirstID() uint64 {
|
||||
if len(ri) <= 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
for _, s := range ri {
|
||||
if v, err := strconv.ParseUint(s, 10, 64); err != nil {
|
||||
continue
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rr InterfaceSet) Walk(f func(r Interface) error) (err error) {
|
||||
for _, r := range rr {
|
||||
err = f(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SearchForIdentifiers returns the resources where the provided identifiers exist
|
||||
//
|
||||
// The Resource is matching if at least one identifier matches.
|
||||
func (rr InterfaceSet) SearchForIdentifiers(resource string, ii Identifiers) (out InterfaceSet) {
|
||||
out = make(InterfaceSet, 0, len(rr)/2)
|
||||
|
||||
for _, r := range rr {
|
||||
if r.ResourceType() != resource {
|
||||
continue
|
||||
}
|
||||
|
||||
if r.Identifiers().HasAny(ii) {
|
||||
out = append(out, r)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SearchForReferences returns the resources where the provided references exist
|
||||
//
|
||||
// The Resource is matching if at least one reference matches.
|
||||
func (rr InterfaceSet) SearchForReferences(ref *Ref) (out InterfaceSet) {
|
||||
out = make(InterfaceSet, 0, len(rr)/2)
|
||||
|
||||
for _, r := range rr {
|
||||
if r.Refs().HasRef(ref) {
|
||||
out = append(out, r)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Constraint returns the current reference with added constraint
|
||||
func (r *Ref) Constraint(c *Ref) *Ref {
|
||||
if r.Constraints == nil {
|
||||
r.Constraints = make(RefSet, 0, 1)
|
||||
}
|
||||
|
||||
r.Constraints = append(r.Constraints, &Ref{
|
||||
ResourceType: c.ResourceType,
|
||||
Identifiers: MakeIdentifiers(c.Identifiers.StringSlice()...),
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// IsWildcard checks if this Ref points to all resources of a specific resource type
|
||||
func (r *Ref) IsWildcard() bool {
|
||||
if len(r.Identifiers) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, i := range r.Identifiers {
|
||||
if i == "*" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *Ref) equals(b *Ref) bool {
|
||||
if a == nil && a == b {
|
||||
return true
|
||||
}
|
||||
|
||||
if a == nil && a != b {
|
||||
return false
|
||||
}
|
||||
|
||||
if a.ResourceType != b.ResourceType {
|
||||
return false
|
||||
}
|
||||
|
||||
if !b.IsWildcard() && !a.Identifiers.HasAny(b.Identifiers) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, c := range b.Constraints {
|
||||
if !a.Constraints.HasRef(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (rr RefSet) findRef(ref *Ref) int {
|
||||
for i, r := range rr {
|
||||
if r.equals(ref) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// replaceRef replaces the reference both on the ref level and on the
|
||||
// constraint level.
|
||||
func (rr RefSet) replaceRef(old, new *Ref) RefSet {
|
||||
found := false
|
||||
|
||||
for x := len(rr) - 1; x >= 0; x-- {
|
||||
r := rr[x]
|
||||
|
||||
if r.equals(old) {
|
||||
found = true
|
||||
if new == nil {
|
||||
rr[x] = rr[len(rr)-1]
|
||||
return rr[:len(rr)-1]
|
||||
} else {
|
||||
rr[x] = new
|
||||
}
|
||||
} else {
|
||||
if len(r.Constraints) > 0 {
|
||||
r.Constraints = r.Constraints.replaceRef(old, new)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found && new != nil {
|
||||
return append(rr, new)
|
||||
}
|
||||
|
||||
return rr
|
||||
}
|
||||
|
||||
func (rr RefSet) HasRef(ref *Ref) bool {
|
||||
return rr.findRef(ref) > -1
|
||||
}
|
||||
|
||||
// IsSbubset checks if aa is subset of bb
|
||||
//
|
||||
// Order is important; primary use is RBAC and res. tr. path checking.
|
||||
func (aa RefSet) IsSubset(bb RefSet) bool {
|
||||
if len(bb) > len(aa) {
|
||||
return false
|
||||
}
|
||||
|
||||
return aa[0:len(bb)].Equals(bb)
|
||||
}
|
||||
|
||||
// Equals checks if two RefSets match
|
||||
//
|
||||
// They match if everything matches, even constraints (important)
|
||||
func (aa RefSet) Equals(bb RefSet) bool {
|
||||
if len(aa) != len(bb) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, a := range aa {
|
||||
if !a.equals(bb[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Unique returns only unique references
|
||||
//
|
||||
// Uniqueness is defined as "two references may not define
|
||||
// the same resource type and identifier" combinations.
|
||||
func (rr RefSet) Unique() RefSet {
|
||||
out := make(RefSet, 0, len(rr))
|
||||
seen := make(map[string]Identifiers)
|
||||
|
||||
for _, r := range rr {
|
||||
ii, ok := seen[r.ResourceType]
|
||||
|
||||
// type not seen at all, unique
|
||||
if !ok {
|
||||
out = append(out, r)
|
||||
seen[r.ResourceType] = r.Identifiers.Clone()
|
||||
continue
|
||||
}
|
||||
|
||||
// not yet seen
|
||||
if !ii.HasAny(r.Identifiers) {
|
||||
out = append(out, r)
|
||||
seen[r.ResourceType] = seen[r.ResourceType].Add(r.Identifiers...)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
96
server/pkg/envoy/resource/user.go
Normal file
96
server/pkg/envoy/resource/user.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// User represents a User
|
||||
User struct {
|
||||
*base
|
||||
Res *types.User
|
||||
|
||||
RoleMembership []Identifiers
|
||||
RefRoles RefSet
|
||||
}
|
||||
)
|
||||
|
||||
func NewUser(u *types.User, roles ...string) *User {
|
||||
r := &User{base: &base{}}
|
||||
r.SetResourceType(types.UserResourceType)
|
||||
r.Res = u
|
||||
|
||||
r.AddIdentifier(identifiers(u.Handle, u.Email, u.Name, u.ID)...)
|
||||
|
||||
// Role membership
|
||||
for _, role := range roles {
|
||||
rid := MakeIdentifiers(role)
|
||||
r.RoleMembership = append(r.RoleMembership, rid)
|
||||
|
||||
r.RefRoles = append(r.RefRoles, r.AddRef(types.RoleResourceType, role))
|
||||
}
|
||||
|
||||
// Initial timestamps
|
||||
r.SetTimestamps(MakeTimestampsCUDAS(&u.CreatedAt, u.UpdatedAt, u.DeletedAt, nil, u.SuspendedAt))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (u *User) AddRoles(roles ...*types.Role) *User {
|
||||
for _, r := range roles {
|
||||
idf := firstOkString(r.Handle, strconv.FormatUint(r.ID, 10))
|
||||
rid := MakeIdentifiers(idf)
|
||||
u.RoleMembership = append(u.RoleMembership, rid)
|
||||
|
||||
u.RefRoles = append(u.RefRoles, u.AddRef(types.RoleResourceType, idf))
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func (r *User) Resource() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r *User) SysID() uint64 {
|
||||
return r.Res.ID
|
||||
}
|
||||
|
||||
func (r *User) RBACParts() (resource string, ref *Ref, path []*Ref) {
|
||||
ref = r.Ref()
|
||||
path = nil
|
||||
resource = fmt.Sprintf(types.UserRbacResourceTpl(), types.UserResourceType, firstOkString(strconv.FormatUint(r.Res.ID, 10), r.Res.Handle, r.Res.Username))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindUser looks for the user in the resources
|
||||
func FindUser(rr InterfaceSet, ii Identifiers) (u *types.User) {
|
||||
var uRes *User
|
||||
|
||||
rr.Walk(func(r Interface) error {
|
||||
ur, ok := r.(*User)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ur.Identifiers().HasAny(ii) {
|
||||
uRes = ur
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Found it
|
||||
if uRes != nil {
|
||||
return uRes.Res
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UserErrUnresolved(ii Identifiers) error {
|
||||
return fmt.Errorf("user unresolved %v", ii.StringSlice())
|
||||
}
|
||||
242
server/pkg/envoy/resource/userstamps.go
Normal file
242
server/pkg/envoy/resource/userstamps.go
Normal file
@@ -0,0 +1,242 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Userstamp struct {
|
||||
UserID uint64
|
||||
Ref string
|
||||
U *types.User
|
||||
// S is the stringified user representation
|
||||
S string
|
||||
}
|
||||
|
||||
Userstamps struct {
|
||||
CreatedBy *Userstamp
|
||||
UpdatedBy *Userstamp
|
||||
DeletedBy *Userstamp
|
||||
OwnedBy *Userstamp
|
||||
RunAs *Userstamp
|
||||
}
|
||||
UserstampIndex map[string]*Userstamp
|
||||
)
|
||||
|
||||
func (us *Userstamp) MarshalYAML() (interface{}, error) {
|
||||
if us == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if us.U != nil {
|
||||
if us.U.Handle != "" {
|
||||
return us.U.Handle, nil
|
||||
}
|
||||
if us.U.Username != "" {
|
||||
return us.U.Username, nil
|
||||
}
|
||||
if us.U.Email != "" {
|
||||
return us.U.Email, nil
|
||||
}
|
||||
if us.U.Name != "" {
|
||||
return us.U.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
if us.Ref != "" {
|
||||
return us.Ref, nil
|
||||
}
|
||||
|
||||
if us.UserID > 0 {
|
||||
return us.UserID, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid userstamp")
|
||||
}
|
||||
|
||||
func (us *Userstamp) MarshalJSON() ([]byte, error) {
|
||||
if us == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
l := ""
|
||||
|
||||
if us.U != nil {
|
||||
if us.U.Handle != "" {
|
||||
l = us.U.Handle
|
||||
}
|
||||
if us.U.Username != "" {
|
||||
l = us.U.Username
|
||||
}
|
||||
if us.U.Email != "" {
|
||||
l = us.U.Email
|
||||
}
|
||||
if us.U.Name != "" {
|
||||
l = us.U.Name
|
||||
}
|
||||
} else {
|
||||
if us.Ref != "" {
|
||||
l = us.Ref
|
||||
}
|
||||
|
||||
if us.UserID > 0 {
|
||||
l = strconv.FormatUint(us.UserID, 10)
|
||||
}
|
||||
}
|
||||
|
||||
if l == "" {
|
||||
return nil, fmt.Errorf("invalid userstamp")
|
||||
}
|
||||
|
||||
return json.Marshal(l)
|
||||
}
|
||||
|
||||
// MakeUserstamp initializes a userstamp from the passed user struct
|
||||
func MakeUserstamp(u *types.User) *Userstamp {
|
||||
sID := strconv.FormatUint(u.ID, 10)
|
||||
return &Userstamp{
|
||||
UserID: u.ID,
|
||||
U: u,
|
||||
Ref: firstOkString(u.Handle, u.Email, u.Username, sID),
|
||||
}
|
||||
}
|
||||
|
||||
// MakeUserstampFromRef initializes a userstamp from the passed reference
|
||||
//
|
||||
// If possible, the function determines the userID
|
||||
func MakeUserstampFromRef(ref string) *Userstamp {
|
||||
id, err := strconv.ParseUint(ref, 10, 64)
|
||||
|
||||
us := &Userstamp{}
|
||||
|
||||
if err == nil && id != 0 {
|
||||
us.UserID = id
|
||||
us.U = &types.User{ID: id}
|
||||
}
|
||||
us.Ref = ref
|
||||
|
||||
return us
|
||||
}
|
||||
|
||||
// MakeUserstampFromRef initializes a userstamp from the passed userID
|
||||
func MakeUserstampFromID(ID uint64) *Userstamp {
|
||||
if ID == 0 {
|
||||
return nil
|
||||
}
|
||||
return MakeUserstampFromRef(strconv.FormatUint(ID, 10))
|
||||
}
|
||||
|
||||
// MakeUserstampsCUDO initializes userstamps for createdAt, updatedAt, deletedAt and ownedBy
|
||||
func MakeUserstampsCUDO(c, u, d, o uint64) *Userstamps {
|
||||
us := &Userstamps{}
|
||||
|
||||
if c > 0 {
|
||||
us.CreatedBy = &Userstamp{
|
||||
UserID: c,
|
||||
Ref: strconv.FormatUint(c, 10),
|
||||
}
|
||||
}
|
||||
if u > 0 {
|
||||
us.UpdatedBy = &Userstamp{
|
||||
UserID: u,
|
||||
Ref: strconv.FormatUint(u, 10),
|
||||
}
|
||||
}
|
||||
if d > 0 {
|
||||
us.DeletedBy = &Userstamp{
|
||||
UserID: d,
|
||||
Ref: strconv.FormatUint(d, 10),
|
||||
}
|
||||
}
|
||||
if o > 0 {
|
||||
us.OwnedBy = &Userstamp{
|
||||
UserID: o,
|
||||
Ref: strconv.FormatUint(o, 10),
|
||||
}
|
||||
}
|
||||
|
||||
return us
|
||||
}
|
||||
|
||||
// Model stringifies the userstamp
|
||||
//
|
||||
// @todo make this configurable
|
||||
func (us *Userstamp) Model() (string, error) {
|
||||
if us == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if us.U != nil {
|
||||
if us.U.Handle != "" {
|
||||
return us.U.Handle, nil
|
||||
}
|
||||
if us.U.Username != "" {
|
||||
return us.U.Username, nil
|
||||
}
|
||||
if us.U.Email != "" {
|
||||
return us.U.Email, nil
|
||||
}
|
||||
if us.U.Name != "" {
|
||||
return us.U.Name, nil
|
||||
}
|
||||
}
|
||||
|
||||
if us.Ref != "" {
|
||||
return us.Ref, nil
|
||||
}
|
||||
|
||||
if us.UserID > 0 {
|
||||
return strconv.FormatUint(us.UserID, 10), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("invalid userstamp")
|
||||
}
|
||||
|
||||
func (ux UserstampIndex) Add(uu ...*types.User) {
|
||||
for _, u := range uu {
|
||||
sID := strconv.FormatUint(u.ID, 10)
|
||||
s := MakeUserstamp(u)
|
||||
|
||||
ux[sID] = s
|
||||
ux[u.Email] = s
|
||||
if u.Handle != "" {
|
||||
ux[u.Handle] = s
|
||||
}
|
||||
if u.Username != "" {
|
||||
ux[u.Username] = s
|
||||
}
|
||||
if u.Name != "" {
|
||||
ux[u.Name+" "+u.Email] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ux UserstampIndex) GetByKey(kr interface{}) *Userstamp {
|
||||
if k, ok := kr.(string); ok {
|
||||
return ux[k]
|
||||
} else if k, ok := kr.(uint64); ok {
|
||||
return ux[strconv.FormatUint(k, 10)]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ux UserstampIndex) GetByStamp(s *Userstamp) *Userstamp {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.Ref != "" {
|
||||
return ux.GetByKey(s.Ref)
|
||||
}
|
||||
if s.UserID > 0 {
|
||||
return ux.GetByKey(s.UserID)
|
||||
}
|
||||
if s.U != nil && s.U.ID > 0 {
|
||||
return ux.GetByKey(s.U.ID)
|
||||
}
|
||||
return s
|
||||
}
|
||||
80
server/pkg/envoy/resource/util.go
Normal file
80
server/pkg/envoy/resource/util.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
)
|
||||
|
||||
func firstOkString(ss ...string) string {
|
||||
for _, s := range ss {
|
||||
if s != "" && s != "0" {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Taken (and modified) from compose/service/values/sanitizer.go
|
||||
func toTime(v string) *time.Time {
|
||||
ff := []string{
|
||||
time.RFC3339,
|
||||
time.RFC1123Z,
|
||||
time.RFC1123,
|
||||
time.RFC850,
|
||||
time.RFC822Z,
|
||||
time.RFC822,
|
||||
time.RubyDate,
|
||||
time.UnixDate,
|
||||
time.ANSIC,
|
||||
"2006/_1/_2 15:04:05",
|
||||
"2006/_1/_2 15:04",
|
||||
}
|
||||
|
||||
for _, f := range ff {
|
||||
parsed, err := time.Parse(f, v)
|
||||
if err == nil {
|
||||
return &parsed
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ref builders
|
||||
|
||||
func MakeNamespaceRef(id uint64, handle, name string) *Ref {
|
||||
return makeGenericRef(types.NamespaceResourceType, id, handle, name)
|
||||
}
|
||||
|
||||
func MakeModuleRef(id uint64, handle, name string) *Ref {
|
||||
return makeGenericRef(types.ModuleResourceType, id, handle, name)
|
||||
}
|
||||
|
||||
func MakePageRef(id uint64, handle, title string) *Ref {
|
||||
return makeGenericRef(types.PageResourceType, id, handle, title)
|
||||
}
|
||||
|
||||
func MakeRoleRef(id uint64, handle, name string) *Ref {
|
||||
return makeGenericRef(systemTypes.RoleResourceType, id, handle, name)
|
||||
}
|
||||
|
||||
func makeGenericRef(t string, id uint64, ii ...string) *Ref {
|
||||
args := make([]interface{}, len(ii)+1)
|
||||
args[0] = id
|
||||
for i := range ii {
|
||||
args[i+1] = ii[i]
|
||||
}
|
||||
|
||||
aux := &Ref{
|
||||
ResourceType: t,
|
||||
Identifiers: identifiers(args...),
|
||||
}
|
||||
|
||||
if t == "" || len(aux.Identifiers) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return aux
|
||||
}
|
||||
Reference in New Issue
Block a user