Refactore exposed module, rename sync_structure, added service methods to exposed, shared module
This commit is contained in:
@@ -25,6 +25,11 @@ $ docker exec -i corteza-server_pg_1 psql -U docker corteza < federation/migrati
|
||||
|
||||
=== Structure sync
|
||||
|
||||
.TODO
|
||||
* [ ] Finish endpoints below
|
||||
* [ ] Add structure sync service (the syncing process)
|
||||
* [ ] Handle acl
|
||||
|
||||
.List of endpoints
|
||||
* [x] Show exposed module
|
||||
* [x] Remove exposed module
|
||||
@@ -57,8 +62,8 @@ $ curl -X GET "$BASE_URL/federation/nodes/$NODE_ID/modules/$MODULE_ID/shared"
|
||||
List of shared/exposed modules::
|
||||
[source,bash]
|
||||
----
|
||||
$ curl -X GET "$BASE_URL/federation/nodes/$NODE_ID/modules?exposed"
|
||||
$ curl -X GET "$BASE_URL/federation/nodes/$NODE_ID/modules?shared"
|
||||
$ curl -X GET "$BASE_URL/federation/nodes/$NODE_ID/modules?exposed=1"
|
||||
$ curl -X GET "$BASE_URL/federation/nodes/$NODE_ID/modules?shared=1"
|
||||
----
|
||||
|
||||
Add module as exposed (with mappings)::
|
||||
|
||||
@@ -79,16 +79,16 @@ endpoints:
|
||||
required: true
|
||||
title: Auth token of the origin node
|
||||
|
||||
- title: Federation sync structure
|
||||
description: Federation structure sync
|
||||
entrypoint: syncStructure
|
||||
path: "/nodes/{nodeID}/modules/{moduleID}"
|
||||
- title: Manage structure
|
||||
description: Manage structure
|
||||
entrypoint: manageStructure
|
||||
path: "/nodes/{nodeID}"
|
||||
authentication: []
|
||||
apis:
|
||||
- name: readExposed
|
||||
method: GET
|
||||
title: Exposed settings for module
|
||||
path: "/exposed"
|
||||
path: "/modules/{moduleID}/exposed"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
@@ -99,10 +99,33 @@ endpoints:
|
||||
name: moduleID
|
||||
required: true
|
||||
title: Module ID
|
||||
- name: createExposed
|
||||
method: PUT
|
||||
title: Add exposed settings for module
|
||||
path: "/modules/{moduleID}/exposed"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
name: nodeID
|
||||
required: true
|
||||
title: Node ID
|
||||
- type: uint64
|
||||
name: moduleID
|
||||
required: true
|
||||
title: Module ID
|
||||
post:
|
||||
- type: uint64
|
||||
name: composeModuleID
|
||||
required: true
|
||||
title: Compose module id
|
||||
- type: types.ModuleFieldMappingList
|
||||
name: fields
|
||||
required: true
|
||||
title: Exposed module fields
|
||||
- name: remove
|
||||
method: DELETE
|
||||
title: Remove from federation
|
||||
path: "/exposed"
|
||||
path: "/modules/{moduleID}/exposed"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
@@ -113,3 +136,36 @@ endpoints:
|
||||
name: moduleID
|
||||
required: true
|
||||
title: Module ID
|
||||
- name: readShared
|
||||
method: GET
|
||||
title: Shared settings for module
|
||||
path: "/modules/{moduleID}/shared"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
name: nodeID
|
||||
required: true
|
||||
title: Node ID
|
||||
- type: uint64
|
||||
name: moduleID
|
||||
required: true
|
||||
title: Module ID
|
||||
- name: listAll
|
||||
method: GET
|
||||
title: List of shared/exposed modules
|
||||
path: "/modules"
|
||||
parameters:
|
||||
path:
|
||||
- type: uint64
|
||||
name: nodeID
|
||||
required: true
|
||||
title: Node ID
|
||||
get:
|
||||
- name: shared
|
||||
type: bool
|
||||
required: false
|
||||
title: List shared modules
|
||||
- name: exposed
|
||||
type: bool
|
||||
required: false
|
||||
title: List exposed modules
|
||||
|
||||
155
federation/rest/handlers/manageStructure.go
Normal file
155
federation/rest/handlers/manageStructure.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package handlers
|
||||
|
||||
// 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:
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
ManageStructureAPI interface {
|
||||
ReadExposed(context.Context, *request.ManageStructureReadExposed) (interface{}, error)
|
||||
CreateExposed(context.Context, *request.ManageStructureCreateExposed) (interface{}, error)
|
||||
Remove(context.Context, *request.ManageStructureRemove) (interface{}, error)
|
||||
ReadShared(context.Context, *request.ManageStructureReadShared) (interface{}, error)
|
||||
ListAll(context.Context, *request.ManageStructureListAll) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
ManageStructure struct {
|
||||
ReadExposed func(http.ResponseWriter, *http.Request)
|
||||
CreateExposed func(http.ResponseWriter, *http.Request)
|
||||
Remove func(http.ResponseWriter, *http.Request)
|
||||
ReadShared func(http.ResponseWriter, *http.Request)
|
||||
ListAll func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewManageStructure(h ManageStructureAPI) *ManageStructure {
|
||||
return &ManageStructure{
|
||||
ReadExposed: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewManageStructureReadExposed()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("ManageStructure.ReadExposed", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ReadExposed(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("ManageStructure.ReadExposed", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("ManageStructure.ReadExposed", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
CreateExposed: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewManageStructureCreateExposed()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("ManageStructure.CreateExposed", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.CreateExposed(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("ManageStructure.CreateExposed", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("ManageStructure.CreateExposed", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
Remove: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewManageStructureRemove()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("ManageStructure.Remove", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Remove(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("ManageStructure.Remove", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("ManageStructure.Remove", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
ReadShared: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewManageStructureReadShared()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("ManageStructure.ReadShared", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ReadShared(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("ManageStructure.ReadShared", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("ManageStructure.ReadShared", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
ListAll: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewManageStructureListAll()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("ManageStructure.ListAll", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ListAll(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("ManageStructure.ListAll", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("ManageStructure.ListAll", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h ManageStructure) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Get("/nodes/{nodeID}/modules/{moduleID}/exposed", h.ReadExposed)
|
||||
r.Put("/nodes/{nodeID}/modules/{moduleID}/exposed", h.CreateExposed)
|
||||
r.Delete("/nodes/{nodeID}/modules/{moduleID}/exposed", h.Remove)
|
||||
r.Get("/nodes/{nodeID}/modules/{moduleID}/shared", h.ReadShared)
|
||||
r.Get("/nodes/{nodeID}/modules", h.ListAll)
|
||||
})
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package handlers
|
||||
|
||||
// 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:
|
||||
//
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
SyncStructureAPI interface {
|
||||
ReadExposed(context.Context, *request.SyncStructureReadExposed) (interface{}, error)
|
||||
Remove(context.Context, *request.SyncStructureRemove) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
SyncStructure struct {
|
||||
ReadExposed func(http.ResponseWriter, *http.Request)
|
||||
Remove func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewSyncStructure(h SyncStructureAPI) *SyncStructure {
|
||||
return &SyncStructure{
|
||||
ReadExposed: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewSyncStructureReadExposed()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("SyncStructure.ReadExposed", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ReadExposed(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("SyncStructure.ReadExposed", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("SyncStructure.ReadExposed", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
Remove: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewSyncStructureRemove()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("SyncStructure.Remove", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Remove(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("SyncStructure.Remove", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("SyncStructure.Remove", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h SyncStructure) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Get("/nodes/{nodeID}/modules/{moduleID}/exposed", h.ReadExposed)
|
||||
r.Delete("/nodes/{nodeID}/modules/{moduleID}/exposed", h.Remove)
|
||||
})
|
||||
}
|
||||
76
federation/rest/manage_structure.go
Normal file
76
federation/rest/manage_structure.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/federation/service"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type (
|
||||
ManageStructure struct{}
|
||||
)
|
||||
|
||||
func (ManageStructure) New() *ManageStructure {
|
||||
return &ManageStructure{}
|
||||
}
|
||||
|
||||
func (ctrl ManageStructure) Remove(ctx context.Context, r *request.ManageStructureRemove) (interface{}, error) {
|
||||
return nil, (service.ExposedModule()).DeleteByID(ctx, r.NodeID, r.ModuleID)
|
||||
}
|
||||
|
||||
func (ctrl ManageStructure) ReadExposed(ctx context.Context, r *request.ManageStructureReadExposed) (interface{}, error) {
|
||||
return (service.ExposedModule()).FindByID(context.Background(), r.GetNodeID(), r.GetModuleID())
|
||||
}
|
||||
|
||||
func (ctrl ManageStructure) CreateExposed(ctx context.Context, r *request.ManageStructureCreateExposed) (interface{}, error) {
|
||||
spew.Dump("RECEIVED", r)
|
||||
// create new type, add to Create()
|
||||
// return (service.ExposedModule()).Create(context.Background(), r.GetNodeID(), r.GetModuleID())
|
||||
var (
|
||||
err error
|
||||
mod = &types.ExposedModule{
|
||||
NodeID: r.NodeID,
|
||||
ComposeModuleID: r.ComposeModuleID,
|
||||
Fields: r.Fields,
|
||||
}
|
||||
)
|
||||
|
||||
spew.Dump("MOD", mod)
|
||||
|
||||
mod, err = (service.ExposedModule()).Create(context.Background(), mod)
|
||||
spew.Dump(mod, err)
|
||||
// return ctrl.makePayload(ctx, mod, err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (ctrl ManageStructure) ReadShared(ctx context.Context, r *request.ManageStructureReadShared) (interface{}, error) {
|
||||
return (service.SharedModule()).FindByID(context.Background(), r.GetNodeID(), r.GetModuleID())
|
||||
}
|
||||
|
||||
func (ctrl ManageStructure) ListAll(ctx context.Context, r *request.ManageStructureListAll) (interface{}, error) {
|
||||
var (
|
||||
list interface{}
|
||||
err error
|
||||
)
|
||||
|
||||
switch true {
|
||||
case r.Exposed:
|
||||
list, _, err = (service.ExposedModule()).Find(context.Background(), types.ExposedModuleFilter{
|
||||
NodeID: r.NodeID,
|
||||
})
|
||||
break
|
||||
case r.Shared:
|
||||
list, _, err = (service.SharedModule()).Find(context.Background(), types.SharedModuleFilter{
|
||||
NodeID: r.NodeID,
|
||||
})
|
||||
break
|
||||
default:
|
||||
return nil, errors.New("TODO - http 400 bad request - either use ?exposed or ?shared")
|
||||
}
|
||||
|
||||
return list, err
|
||||
}
|
||||
445
federation/rest/request/manageStructure.go
Normal file
445
federation/rest/request/manageStructure.go
Normal file
@@ -0,0 +1,445 @@
|
||||
package request
|
||||
|
||||
// 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:
|
||||
//
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
ManageStructureReadExposed struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// ModuleID PATH parameter
|
||||
//
|
||||
// Module ID
|
||||
ModuleID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
ManageStructureCreateExposed struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// ModuleID PATH parameter
|
||||
//
|
||||
// Module ID
|
||||
ModuleID uint64 `json:",string"`
|
||||
|
||||
// ComposeModuleID POST parameter
|
||||
//
|
||||
// Compose module id
|
||||
ComposeModuleID uint64 `json:",string"`
|
||||
|
||||
// Fields POST parameter
|
||||
//
|
||||
// Exposed module fields
|
||||
Fields types.ModuleFieldMappingList
|
||||
}
|
||||
|
||||
ManageStructureRemove struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// ModuleID PATH parameter
|
||||
//
|
||||
// Module ID
|
||||
ModuleID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
ManageStructureReadShared struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// ModuleID PATH parameter
|
||||
//
|
||||
// Module ID
|
||||
ModuleID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
ManageStructureListAll struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// Shared GET parameter
|
||||
//
|
||||
// List shared modules
|
||||
Shared bool
|
||||
|
||||
// Exposed GET parameter
|
||||
//
|
||||
// List exposed modules
|
||||
Exposed bool
|
||||
}
|
||||
)
|
||||
|
||||
// NewManageStructureReadExposed request
|
||||
func NewManageStructureReadExposed() *ManageStructureReadExposed {
|
||||
return &ManageStructureReadExposed{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureReadExposed) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"moduleID": r.ModuleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureReadExposed) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureReadExposed) GetModuleID() uint64 {
|
||||
return r.ModuleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ManageStructureReadExposed) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "moduleID")
|
||||
r.ModuleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewManageStructureCreateExposed request
|
||||
func NewManageStructureCreateExposed() *ManageStructureCreateExposed {
|
||||
return &ManageStructureCreateExposed{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureCreateExposed) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"moduleID": r.ModuleID,
|
||||
"composeModuleID": r.ComposeModuleID,
|
||||
"fields": r.Fields,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureCreateExposed) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureCreateExposed) GetModuleID() uint64 {
|
||||
return r.ModuleID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureCreateExposed) GetComposeModuleID() uint64 {
|
||||
return r.ComposeModuleID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureCreateExposed) GetFields() types.ModuleFieldMappingList {
|
||||
return r.Fields
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ManageStructureCreateExposed) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// POST params
|
||||
|
||||
if val, ok := req.Form["composeModuleID"]; ok && len(val) > 0 {
|
||||
r.ComposeModuleID, err = payload.ParseUint64(val[0]), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if val, ok := req.Form["fields"]; ok && len(val) > 0 {
|
||||
// r.Fields, err = types.ModuleFieldMappingList(val[0]), nil
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "moduleID")
|
||||
r.ModuleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewManageStructureRemove request
|
||||
func NewManageStructureRemove() *ManageStructureRemove {
|
||||
return &ManageStructureRemove{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureRemove) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"moduleID": r.ModuleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureRemove) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureRemove) GetModuleID() uint64 {
|
||||
return r.ModuleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ManageStructureRemove) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "moduleID")
|
||||
r.ModuleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewManageStructureReadShared request
|
||||
func NewManageStructureReadShared() *ManageStructureReadShared {
|
||||
return &ManageStructureReadShared{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureReadShared) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"moduleID": r.ModuleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureReadShared) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureReadShared) GetModuleID() uint64 {
|
||||
return r.ModuleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ManageStructureReadShared) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "moduleID")
|
||||
r.ModuleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewManageStructureListAll request
|
||||
func NewManageStructureListAll() *ManageStructureListAll {
|
||||
return &ManageStructureListAll{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureListAll) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"shared": r.Shared,
|
||||
"exposed": r.Exposed,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureListAll) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureListAll) GetShared() bool {
|
||||
return r.Shared
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r ManageStructureListAll) GetExposed() bool {
|
||||
return r.Exposed
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *ManageStructureListAll) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// GET params
|
||||
tmp := req.URL.Query()
|
||||
|
||||
if val, ok := tmp["shared"]; ok && len(val) > 0 {
|
||||
r.Shared, err = payload.ParseBool(val[0]), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := tmp["exposed"]; ok && len(val) > 0 {
|
||||
r.Exposed, err = payload.ParseBool(val[0]), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package request
|
||||
|
||||
// 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:
|
||||
//
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
SyncStructureReadExposed struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// ModuleID PATH parameter
|
||||
//
|
||||
// Module ID
|
||||
ModuleID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
SyncStructureRemove struct {
|
||||
// NodeID PATH parameter
|
||||
//
|
||||
// Node ID
|
||||
NodeID uint64 `json:",string"`
|
||||
|
||||
// ModuleID PATH parameter
|
||||
//
|
||||
// Module ID
|
||||
ModuleID uint64 `json:",string"`
|
||||
}
|
||||
)
|
||||
|
||||
// NewSyncStructureReadExposed request
|
||||
func NewSyncStructureReadExposed() *SyncStructureReadExposed {
|
||||
return &SyncStructureReadExposed{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r SyncStructureReadExposed) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"moduleID": r.ModuleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r SyncStructureReadExposed) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r SyncStructureReadExposed) GetModuleID() uint64 {
|
||||
return r.ModuleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *SyncStructureReadExposed) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "moduleID")
|
||||
r.ModuleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewSyncStructureRemove request
|
||||
func NewSyncStructureRemove() *SyncStructureRemove {
|
||||
return &SyncStructureRemove{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r SyncStructureRemove) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"nodeID": r.NodeID,
|
||||
"moduleID": r.ModuleID,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r SyncStructureRemove) GetNodeID() uint64 {
|
||||
return r.NodeID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r SyncStructureRemove) GetModuleID() uint64 {
|
||||
return r.ModuleID
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *SyncStructureRemove) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("error parsing http request body: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var val string
|
||||
// path params
|
||||
|
||||
val = chi.URLParam(req, "nodeID")
|
||||
r.NodeID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val = chi.URLParam(req, "moduleID")
|
||||
r.ModuleID, err = payload.ParseUint64(val), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -13,7 +13,7 @@ func MountRoutes(r chi.Router) {
|
||||
|
||||
// temporary because of acl
|
||||
handlers.NewModule((Module{}.New())).MountRoutes(r)
|
||||
handlers.NewSyncStructure((SyncStructure{}.New())).MountRoutes(r)
|
||||
handlers.NewManageStructure((ManageStructure{}.New())).MountRoutes(r)
|
||||
})
|
||||
|
||||
// Protect all _private_ routes
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/federation/service"
|
||||
)
|
||||
|
||||
type (
|
||||
SyncStructure struct{}
|
||||
)
|
||||
|
||||
func (SyncStructure) New() *SyncStructure {
|
||||
return &SyncStructure{}
|
||||
}
|
||||
|
||||
func (ctrl SyncStructure) Remove(ctx context.Context, r *request.SyncStructureRemove) (interface{}, error) {
|
||||
return nil, (service.ExposedModule()).DeleteByID(ctx, r.NodeID, r.ModuleID)
|
||||
}
|
||||
|
||||
func (ctrl SyncStructure) ReadExposed(ctx context.Context, r *request.SyncStructureReadExposed) (interface{}, error) {
|
||||
return (service.ExposedModule()).FindByID(context.Background(), r.GetNodeID(), r.GetModuleID())
|
||||
}
|
||||
199
federation/service/exposed_module.go
Normal file
199
federation/service/exposed_module.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
composeService "github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type (
|
||||
exposedModule struct {
|
||||
ctx context.Context
|
||||
compose composeService.ModuleService
|
||||
store store.Storer
|
||||
actionlog actionlog.Recorder
|
||||
}
|
||||
|
||||
ExposedModuleService interface {
|
||||
Find(ctx context.Context, filter types.ExposedModuleFilter) (types.ExposedModuleSet, types.ExposedModuleFilter, error)
|
||||
FindByID(ctx context.Context, nodeID uint64, moduleID uint64) (*types.ExposedModule, error)
|
||||
FindByAny(ctx context.Context, nodeID uint64, identifier interface{}) (*types.ExposedModule, error)
|
||||
DeleteByID(ctx context.Context, nodeID, moduleID uint64) error
|
||||
Create(ctx context.Context, new *types.ExposedModule) (*types.ExposedModule, error)
|
||||
// Remove(ctx context.Context, filter types.ExposedModuleFilter) (err error)
|
||||
}
|
||||
|
||||
moduleUpdateHandler func(ctx context.Context, ns *types.Node, c *types.ExposedModule) (bool, bool, error)
|
||||
)
|
||||
|
||||
func ExposedModule() ExposedModuleService {
|
||||
return &exposedModule{
|
||||
ctx: context.Background(),
|
||||
compose: composeService.Module(),
|
||||
store: DefaultStore,
|
||||
actionlog: DefaultActionlog,
|
||||
}
|
||||
}
|
||||
|
||||
// FindByAny tries to find module in a particular namespace by id, handle or name
|
||||
func (svc exposedModule) FindByAny(ctx context.Context, nodeID uint64, identifier interface{}) (m *types.ExposedModule, err error) {
|
||||
if ID, ok := identifier.(uint64); ok {
|
||||
m, err = svc.FindByID(ctx, nodeID, ID)
|
||||
} else if strIdentifier, ok := identifier.(string); ok {
|
||||
if ID, _ := strconv.ParseUint(strIdentifier, 10, 64); ID > 0 {
|
||||
m, err = svc.FindByID(ctx, nodeID, ID)
|
||||
}
|
||||
} else {
|
||||
// force invalid ID error
|
||||
// we do that to wrap error with lookup action context
|
||||
_, err = svc.FindByID(ctx, nodeID, 0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (svc exposedModule) FindByID(ctx context.Context, nodeID uint64, moduleID uint64) (module *types.ExposedModule, err error) {
|
||||
err = func() error {
|
||||
if module, err = store.LookupFederationExposedModuleByID(svc.ctx, svc.store, moduleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return module, err
|
||||
}
|
||||
|
||||
func (svc exposedModule) DeleteByID(ctx context.Context, nodeID, moduleID uint64) error {
|
||||
return trim1st(svc.updater(ctx, nodeID, moduleID, ExposedModuleActionDelete, svc.handleDelete))
|
||||
}
|
||||
|
||||
func (svc exposedModule) updater(ctx context.Context, nodeID, moduleID uint64, action func(...*exposedModuleActionProps) *exposedModuleAction, fn moduleUpdateHandler) (*types.ExposedModule, error) {
|
||||
var (
|
||||
moduleChanged, fieldsChanged bool
|
||||
|
||||
n *types.Node
|
||||
m *types.ExposedModule
|
||||
// m, old *types.ExposedModule
|
||||
aProps = &exposedModuleActionProps{module: &types.ExposedModule{ID: moduleID, NodeID: nodeID}}
|
||||
err error
|
||||
)
|
||||
|
||||
spew.Dump("before handle delete", fn, n, m)
|
||||
|
||||
err = store.Tx(ctx, svc.store, func(ctx context.Context, s store.Storer) (err error) {
|
||||
if m, err = svc.store.LookupFederationExposedModuleByID(ctx, moduleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO - handle node id also
|
||||
if moduleChanged, fieldsChanged, err = fn(ctx, n, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return m, svc.recordAction(ctx, aProps, action, err)
|
||||
}
|
||||
|
||||
func (svc exposedModule) handleDelete(ctx context.Context, n *types.Node, m *types.ExposedModule) (bool, bool, error) {
|
||||
if err := store.DeleteFederationExposedModuleByID(ctx, svc.store, m.ID); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
func (svc exposedModule) Find(ctx context.Context, filter types.ExposedModuleFilter) (set types.ExposedModuleSet, f types.ExposedModuleFilter, err error) {
|
||||
err = func() error {
|
||||
if set, f, err = store.SearchFederationExposedModules(svc.ctx, svc.store, filter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return set, f, err
|
||||
}
|
||||
|
||||
func (svc exposedModule) Create(ctx context.Context, new *types.ExposedModule) (*types.ExposedModule, error) {
|
||||
var (
|
||||
aProps = &exposedModuleActionProps{changed: new}
|
||||
)
|
||||
|
||||
err := store.Tx(ctx, svc.store, func(ctx context.Context, s store.Storer) (err error) {
|
||||
// TODO
|
||||
// if !svc.ac.CanCreateFederationExposedModule(ctx, ns) {
|
||||
// return ExposedModuleErrNotAllowedToCreate()
|
||||
// }
|
||||
|
||||
// TODO - fetch Node
|
||||
aProps.setNode(nil)
|
||||
|
||||
// Check for node - compose.Module combo
|
||||
if err = svc.uniqueCheck(ctx, new); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spew.Dump("NEW", new)
|
||||
|
||||
// new.ID = nextID()
|
||||
// new.CreatedAt = *now()
|
||||
// new.UpdatedAt = nil
|
||||
// new.DeletedAt = nil
|
||||
|
||||
// if new.Fields != nil {
|
||||
// _ = new.Fields.Walk(func(f *types.ModuleField) error {
|
||||
// f.ID = nextID()
|
||||
// f.ModuleID = new.ID
|
||||
// f.CreatedAt = *now()
|
||||
// f.UpdatedAt = nil
|
||||
// f.DeletedAt = nil
|
||||
// return nil
|
||||
// })
|
||||
// }
|
||||
|
||||
aProps.setModule(new)
|
||||
|
||||
// if err = store.CreateComposeModule(ctx, s, new); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// if err = store.CreateComposeModuleField(ctx, s, new.Fields...); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// _ = svc.eventbus.WaitFor(ctx, event.ModuleAfterCreate(new, nil, ns))
|
||||
return nil
|
||||
})
|
||||
|
||||
return new, svc.recordAction(svc.ctx, aProps, ExposedModuleActionCreate, err)
|
||||
}
|
||||
|
||||
func (svc exposedModule) uniqueCheck(ctx context.Context, m *types.ExposedModule) (err error) {
|
||||
f := types.ExposedModuleFilter{
|
||||
NodeID: m.NodeID,
|
||||
ComposeModuleID: m.ComposeModuleID,
|
||||
}
|
||||
|
||||
if set, _, err := store.SearchFederationExposedModules(ctx, svc.store, f); len(set) > 0 && err != nil {
|
||||
return ExposedModuleErrNotUnique()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// trim1st removes 1st param and returns only error
|
||||
func trim1st(_ interface{}, err error) error {
|
||||
return err
|
||||
}
|
||||
@@ -20,13 +20,14 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
moduleActionProps struct {
|
||||
exposedModuleActionProps struct {
|
||||
module *types.ExposedModule
|
||||
changed *types.ExposedModule
|
||||
filter *types.ExposedModuleFilter
|
||||
node *types.Node
|
||||
}
|
||||
|
||||
moduleAction struct {
|
||||
exposedModuleAction struct {
|
||||
timestamp time.Time
|
||||
resource string
|
||||
action string
|
||||
@@ -36,10 +37,10 @@ type (
|
||||
// prefix for error when action fails
|
||||
errorMessage string
|
||||
|
||||
props *moduleActionProps
|
||||
props *exposedModuleActionProps
|
||||
}
|
||||
|
||||
moduleError struct {
|
||||
exposedModuleError struct {
|
||||
timestamp time.Time
|
||||
error string
|
||||
resource string
|
||||
@@ -50,7 +51,7 @@ type (
|
||||
|
||||
wrap error
|
||||
|
||||
props *moduleActionProps
|
||||
props *exposedModuleActionProps
|
||||
}
|
||||
)
|
||||
|
||||
@@ -62,44 +63,55 @@ var (
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Props methods
|
||||
// setModule updates moduleActionProps's module
|
||||
// setModule updates exposedModuleActionProps's module
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *moduleActionProps) setModule(module *types.ExposedModule) *moduleActionProps {
|
||||
func (p *exposedModuleActionProps) setModule(module *types.ExposedModule) *exposedModuleActionProps {
|
||||
p.module = module
|
||||
return p
|
||||
}
|
||||
|
||||
// setChanged updates moduleActionProps's changed
|
||||
// setChanged updates exposedModuleActionProps's changed
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *moduleActionProps) setChanged(changed *types.ExposedModule) *moduleActionProps {
|
||||
func (p *exposedModuleActionProps) setChanged(changed *types.ExposedModule) *exposedModuleActionProps {
|
||||
p.changed = changed
|
||||
return p
|
||||
}
|
||||
|
||||
// setFilter updates moduleActionProps's filter
|
||||
// setFilter updates exposedModuleActionProps's filter
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *moduleActionProps) setFilter(filter *types.ExposedModuleFilter) *moduleActionProps {
|
||||
func (p *exposedModuleActionProps) setFilter(filter *types.ExposedModuleFilter) *exposedModuleActionProps {
|
||||
p.filter = filter
|
||||
return p
|
||||
}
|
||||
|
||||
// serialize converts moduleActionProps to actionlog.Meta
|
||||
// setNode updates exposedModuleActionProps's node
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p moduleActionProps) serialize() actionlog.Meta {
|
||||
func (p *exposedModuleActionProps) setNode(node *types.Node) *exposedModuleActionProps {
|
||||
p.node = node
|
||||
return p
|
||||
}
|
||||
|
||||
// serialize converts exposedModuleActionProps to actionlog.Meta
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p exposedModuleActionProps) serialize() actionlog.Meta {
|
||||
var (
|
||||
m = make(actionlog.Meta)
|
||||
)
|
||||
@@ -117,6 +129,10 @@ func (p moduleActionProps) serialize() actionlog.Meta {
|
||||
m.Set("filter.sort", p.filter.Sort, true)
|
||||
m.Set("filter.limit", p.filter.Limit, true)
|
||||
}
|
||||
if p.node != nil {
|
||||
m.Set("node.ID", p.node.ID, true)
|
||||
m.Set("node.Name", p.node.Name, true)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
@@ -125,7 +141,7 @@ func (p moduleActionProps) serialize() actionlog.Meta {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p moduleActionProps) tr(in string, err error) string {
|
||||
func (p exposedModuleActionProps) tr(in string, err error) string {
|
||||
var (
|
||||
pairs = []string{"{err}"}
|
||||
// first non-empty string
|
||||
@@ -199,6 +215,20 @@ func (p moduleActionProps) tr(in string, err error) string {
|
||||
pairs = append(pairs, "{filter.sort}", fns(p.filter.Sort))
|
||||
pairs = append(pairs, "{filter.limit}", fns(p.filter.Limit))
|
||||
}
|
||||
|
||||
if p.node != nil {
|
||||
// replacement for "{node}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{node}",
|
||||
fns(
|
||||
p.node.ID,
|
||||
p.node.Name,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{node.ID}", fns(p.node.ID))
|
||||
pairs = append(pairs, "{node.Name}", fns(p.node.Name))
|
||||
}
|
||||
return strings.NewReplacer(pairs...).Replace(in)
|
||||
}
|
||||
|
||||
@@ -210,8 +240,8 @@ func (p moduleActionProps) tr(in string, err error) string {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (a *moduleAction) String() string {
|
||||
var props = &moduleActionProps{}
|
||||
func (a *exposedModuleAction) String() string {
|
||||
var props = &exposedModuleActionProps{}
|
||||
|
||||
if a.props != nil {
|
||||
props = a.props
|
||||
@@ -220,7 +250,7 @@ func (a *moduleAction) String() string {
|
||||
return props.tr(a.log, nil)
|
||||
}
|
||||
|
||||
func (e *moduleAction) LoggableAction() *actionlog.Action {
|
||||
func (e *exposedModuleAction) LoggableAction() *actionlog.Action {
|
||||
return &actionlog.Action{
|
||||
Timestamp: e.timestamp,
|
||||
Resource: e.resource,
|
||||
@@ -241,8 +271,8 @@ func (e *moduleAction) LoggableAction() *actionlog.Action {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *moduleError) String() string {
|
||||
var props = &moduleActionProps{}
|
||||
func (e *exposedModuleError) String() string {
|
||||
var props = &exposedModuleActionProps{}
|
||||
|
||||
if e.props != nil {
|
||||
props = e.props
|
||||
@@ -261,8 +291,8 @@ func (e *moduleError) String() string {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *moduleError) Error() string {
|
||||
var props = &moduleActionProps{}
|
||||
func (e *exposedModuleError) Error() string {
|
||||
var props = &exposedModuleActionProps{}
|
||||
|
||||
if e.props != nil {
|
||||
props = e.props
|
||||
@@ -275,8 +305,8 @@ func (e *moduleError) Error() string {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *moduleError) Is(err error) bool {
|
||||
t, ok := err.(*moduleError)
|
||||
func (e *exposedModuleError) Is(err error) bool {
|
||||
t, ok := err.(*exposedModuleError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
@@ -288,15 +318,15 @@ func (e *moduleError) Is(err error) bool {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *moduleError) IsGeneric() bool {
|
||||
func (e *exposedModuleError) IsGeneric() bool {
|
||||
return e.error == "generic"
|
||||
}
|
||||
|
||||
// Wrap wraps moduleError around another error
|
||||
// Wrap wraps exposedModuleError around another error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *moduleError) Wrap(err error) *moduleError {
|
||||
func (e *exposedModuleError) Wrap(err error) *exposedModuleError {
|
||||
e.wrap = err
|
||||
return e
|
||||
}
|
||||
@@ -305,11 +335,11 @@ func (e *moduleError) Wrap(err error) *moduleError {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *moduleError) Unwrap() error {
|
||||
func (e *exposedModuleError) Unwrap() error {
|
||||
return e.wrap
|
||||
}
|
||||
|
||||
func (e *moduleError) LoggableAction() *actionlog.Action {
|
||||
func (e *exposedModuleError) LoggableAction() *actionlog.Action {
|
||||
return &actionlog.Action{
|
||||
Timestamp: e.timestamp,
|
||||
Resource: e.resource,
|
||||
@@ -325,12 +355,12 @@ func (e *moduleError) LoggableAction() *actionlog.Action {
|
||||
// *********************************************************************************************************************
|
||||
// Action constructors
|
||||
|
||||
// ModuleActionSearch returns "federation:exposed_module.search" error
|
||||
// ExposedModuleActionSearch returns "federation:exposed_module.search" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleActionSearch(props ...*moduleActionProps) *moduleAction {
|
||||
a := &moduleAction{
|
||||
func ExposedModuleActionSearch(props ...*exposedModuleActionProps) *exposedModuleAction {
|
||||
a := &exposedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
action: "search",
|
||||
@@ -345,12 +375,12 @@ func ModuleActionSearch(props ...*moduleActionProps) *moduleAction {
|
||||
return a
|
||||
}
|
||||
|
||||
// ModuleActionLookup returns "federation:exposed_module.lookup" error
|
||||
// ExposedModuleActionLookup returns "federation:exposed_module.lookup" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleActionLookup(props ...*moduleActionProps) *moduleAction {
|
||||
a := &moduleAction{
|
||||
func ExposedModuleActionLookup(props ...*exposedModuleActionProps) *exposedModuleAction {
|
||||
a := &exposedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
action: "lookup",
|
||||
@@ -365,12 +395,12 @@ func ModuleActionLookup(props ...*moduleActionProps) *moduleAction {
|
||||
return a
|
||||
}
|
||||
|
||||
// ModuleActionCreate returns "federation:exposed_module.create" error
|
||||
// ExposedModuleActionCreate returns "federation:exposed_module.create" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleActionCreate(props ...*moduleActionProps) *moduleAction {
|
||||
a := &moduleAction{
|
||||
func ExposedModuleActionCreate(props ...*exposedModuleActionProps) *exposedModuleAction {
|
||||
a := &exposedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
action: "create",
|
||||
@@ -385,12 +415,12 @@ func ModuleActionCreate(props ...*moduleActionProps) *moduleAction {
|
||||
return a
|
||||
}
|
||||
|
||||
// ModuleActionUpdate returns "federation:exposed_module.update" error
|
||||
// ExposedModuleActionUpdate returns "federation:exposed_module.update" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleActionUpdate(props ...*moduleActionProps) *moduleAction {
|
||||
a := &moduleAction{
|
||||
func ExposedModuleActionUpdate(props ...*exposedModuleActionProps) *exposedModuleAction {
|
||||
a := &exposedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
action: "update",
|
||||
@@ -405,12 +435,12 @@ func ModuleActionUpdate(props ...*moduleActionProps) *moduleAction {
|
||||
return a
|
||||
}
|
||||
|
||||
// ModuleActionDelete returns "federation:exposed_module.delete" error
|
||||
// ExposedModuleActionDelete returns "federation:exposed_module.delete" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleActionDelete(props ...*moduleActionProps) *moduleAction {
|
||||
a := &moduleAction{
|
||||
func ExposedModuleActionDelete(props ...*exposedModuleActionProps) *exposedModuleAction {
|
||||
a := &exposedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
action: "delete",
|
||||
@@ -425,12 +455,12 @@ func ModuleActionDelete(props ...*moduleActionProps) *moduleAction {
|
||||
return a
|
||||
}
|
||||
|
||||
// ModuleActionUndelete returns "federation:exposed_module.undelete" error
|
||||
// ExposedModuleActionUndelete returns "federation:exposed_module.undelete" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleActionUndelete(props ...*moduleActionProps) *moduleAction {
|
||||
a := &moduleAction{
|
||||
func ExposedModuleActionUndelete(props ...*exposedModuleActionProps) *exposedModuleAction {
|
||||
a := &exposedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
action: "undelete",
|
||||
@@ -449,13 +479,13 @@ func ModuleActionUndelete(props ...*moduleActionProps) *moduleAction {
|
||||
// *********************************************************************************************************************
|
||||
// Error constructors
|
||||
|
||||
// ModuleErrGeneric returns "federation:exposed_module.generic" audit event as actionlog.Error
|
||||
// ExposedModuleErrGeneric returns "federation:exposed_module.generic" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrGeneric(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrGeneric(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "generic",
|
||||
@@ -463,7 +493,7 @@ func ModuleErrGeneric(props ...*moduleActionProps) *moduleError {
|
||||
message: "failed to complete request due to internal error",
|
||||
log: "{err}",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -479,13 +509,13 @@ func ModuleErrGeneric(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotFound returns "federation:exposed_module.notFound" audit event as actionlog.Warning
|
||||
// ExposedModuleErrNotFound returns "federation:exposed_module.notFound" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotFound(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotFound(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notFound",
|
||||
@@ -493,7 +523,7 @@ func ModuleErrNotFound(props ...*moduleActionProps) *moduleError {
|
||||
message: "module does not exist",
|
||||
log: "module does not exist",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -509,13 +539,13 @@ func ModuleErrNotFound(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrInvalidID returns "federation:exposed_module.invalidID" audit event as actionlog.Warning
|
||||
// ExposedModuleErrInvalidID returns "federation:exposed_module.invalidID" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrInvalidID(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrInvalidID(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "invalidID",
|
||||
@@ -523,7 +553,7 @@ func ModuleErrInvalidID(props ...*moduleActionProps) *moduleError {
|
||||
message: "invalid ID",
|
||||
log: "invalid ID",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -539,13 +569,13 @@ func ModuleErrInvalidID(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrStaleData returns "federation:exposed_module.staleData" audit event as actionlog.Warning
|
||||
// ExposedModuleErrStaleData returns "federation:exposed_module.staleData" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrStaleData(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrStaleData(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "staleData",
|
||||
@@ -553,7 +583,7 @@ func ModuleErrStaleData(props ...*moduleActionProps) *moduleError {
|
||||
message: "stale data",
|
||||
log: "stale data",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -569,13 +599,43 @@ func ModuleErrStaleData(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotAllowedToRead returns "federation:exposed_module.notAllowedToRead" audit event as actionlog.Error
|
||||
// ExposedModuleErrNotUnique returns "federation:exposed_module.notUnique" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotAllowedToRead(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotUnique(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notUnique",
|
||||
action: "error",
|
||||
message: "node not unique",
|
||||
log: "used duplicate node TODO - module.node_id for this compose module TODO - module.rel_compose_module",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// ExposedModuleErrNotAllowedToRead returns "federation:exposed_module.notAllowedToRead" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ExposedModuleErrNotAllowedToRead(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notAllowedToRead",
|
||||
@@ -583,7 +643,7 @@ func ModuleErrNotAllowedToRead(props ...*moduleActionProps) *moduleError {
|
||||
message: "not allowed to read this module",
|
||||
log: "could not read {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -599,13 +659,13 @@ func ModuleErrNotAllowedToRead(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotAllowedToListModules returns "federation:exposed_module.notAllowedToListModules" audit event as actionlog.Error
|
||||
// ExposedModuleErrNotAllowedToListModules returns "federation:exposed_module.notAllowedToListModules" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotAllowedToListModules(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotAllowedToListModules(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notAllowedToListModules",
|
||||
@@ -613,7 +673,7 @@ func ModuleErrNotAllowedToListModules(props ...*moduleActionProps) *moduleError
|
||||
message: "not allowed to list modules",
|
||||
log: "could not list modules; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -629,13 +689,13 @@ func ModuleErrNotAllowedToListModules(props ...*moduleActionProps) *moduleError
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotAllowedToCreate returns "federation:exposed_module.notAllowedToCreate" audit event as actionlog.Error
|
||||
// ExposedModuleErrNotAllowedToCreate returns "federation:exposed_module.notAllowedToCreate" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotAllowedToCreate(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotAllowedToCreate(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notAllowedToCreate",
|
||||
@@ -643,7 +703,7 @@ func ModuleErrNotAllowedToCreate(props ...*moduleActionProps) *moduleError {
|
||||
message: "not allowed to create modules",
|
||||
log: "could not create modules; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -659,13 +719,13 @@ func ModuleErrNotAllowedToCreate(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotAllowedToUpdate returns "federation:exposed_module.notAllowedToUpdate" audit event as actionlog.Error
|
||||
// ExposedModuleErrNotAllowedToUpdate returns "federation:exposed_module.notAllowedToUpdate" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotAllowedToUpdate(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotAllowedToUpdate(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notAllowedToUpdate",
|
||||
@@ -673,7 +733,7 @@ func ModuleErrNotAllowedToUpdate(props ...*moduleActionProps) *moduleError {
|
||||
message: "not allowed to update this module",
|
||||
log: "could not update {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -689,13 +749,13 @@ func ModuleErrNotAllowedToUpdate(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotAllowedToDelete returns "federation:exposed_module.notAllowedToDelete" audit event as actionlog.Error
|
||||
// ExposedModuleErrNotAllowedToDelete returns "federation:exposed_module.notAllowedToDelete" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotAllowedToDelete(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotAllowedToDelete(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notAllowedToDelete",
|
||||
@@ -703,7 +763,7 @@ func ModuleErrNotAllowedToDelete(props ...*moduleActionProps) *moduleError {
|
||||
message: "not allowed to delete this module",
|
||||
log: "could not delete {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -719,13 +779,13 @@ func ModuleErrNotAllowedToDelete(props ...*moduleActionProps) *moduleError {
|
||||
|
||||
}
|
||||
|
||||
// ModuleErrNotAllowedToUndelete returns "federation:exposed_module.notAllowedToUndelete" audit event as actionlog.Error
|
||||
// ExposedModuleErrNotAllowedToUndelete returns "federation:exposed_module.notAllowedToUndelete" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func ModuleErrNotAllowedToUndelete(props ...*moduleActionProps) *moduleError {
|
||||
var e = &moduleError{
|
||||
func ExposedModuleErrNotAllowedToUndelete(props ...*exposedModuleActionProps) *exposedModuleError {
|
||||
var e = &exposedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:exposed_module",
|
||||
error: "notAllowedToUndelete",
|
||||
@@ -733,7 +793,7 @@ func ModuleErrNotAllowedToUndelete(props ...*moduleActionProps) *moduleError {
|
||||
message: "not allowed to undelete this module",
|
||||
log: "could not undelete {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *moduleActionProps {
|
||||
props: func() *exposedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
@@ -756,7 +816,7 @@ func ModuleErrNotAllowedToUndelete(props ...*moduleActionProps) *moduleError {
|
||||
//
|
||||
// context is used to enrich audit log entry with current user info, request ID, IP address...
|
||||
// props are collected action/error properties
|
||||
// action (optional) fn will be used to construct moduleAction struct from given props (and error)
|
||||
// action (optional) fn will be used to construct exposedModuleAction struct from given props (and error)
|
||||
// err is any error that occurred while action was happening
|
||||
//
|
||||
// Action has success and fail (error) state:
|
||||
@@ -766,28 +826,28 @@ func ModuleErrNotAllowedToUndelete(props ...*moduleActionProps) *moduleError {
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (svc module) recordAction(ctx context.Context, props *moduleActionProps, action func(...*moduleActionProps) *moduleAction, err error) error {
|
||||
func (svc exposedModule) recordAction(ctx context.Context, props *exposedModuleActionProps, action func(...*exposedModuleActionProps) *exposedModuleAction, err error) error {
|
||||
var (
|
||||
ok bool
|
||||
|
||||
// Return error
|
||||
retError *moduleError
|
||||
retError *exposedModuleError
|
||||
|
||||
// Recorder error
|
||||
recError *moduleError
|
||||
recError *exposedModuleError
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if retError, ok = err.(*moduleError); !ok {
|
||||
// got non-module error, wrap it with ModuleErrGeneric
|
||||
retError = ModuleErrGeneric(props).Wrap(err)
|
||||
if retError, ok = err.(*exposedModuleError); !ok {
|
||||
// got non-exposedModule error, wrap it with ExposedModuleErrGeneric
|
||||
retError = ExposedModuleErrGeneric(props).Wrap(err)
|
||||
|
||||
if action != nil {
|
||||
// copy action to returning and recording error
|
||||
retError.action = action().action
|
||||
}
|
||||
|
||||
// we'll use ModuleErrGeneric for recording too
|
||||
// we'll use ExposedModuleErrGeneric for recording too
|
||||
// because it can hold more info
|
||||
recError = retError
|
||||
} else if retError != nil {
|
||||
@@ -809,8 +869,8 @@ func (svc module) recordAction(ctx context.Context, props *moduleActionProps, ac
|
||||
break
|
||||
}
|
||||
|
||||
// update recError ONLY of wrapped error is of type moduleError
|
||||
if unwrappedSinkError, ok := unwrappedError.(*moduleError); ok {
|
||||
// update recError ONLY of wrapped error is of type exposedModuleError
|
||||
if unwrappedSinkError, ok := unwrappedError.(*exposedModuleError); ok {
|
||||
recError = unwrappedSinkError
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# List of loggable service actions
|
||||
|
||||
resource: federation:exposed_module
|
||||
service: module
|
||||
service: exposedModule
|
||||
|
||||
# Default sensitivity for actions
|
||||
defaultActionSeverity: notice
|
||||
@@ -22,6 +22,9 @@ props:
|
||||
- name: filter
|
||||
type: "*types.ExposedModuleFilter"
|
||||
fields: [ query, sort, limit ]
|
||||
- name: node
|
||||
type: "*types.Node"
|
||||
fields: [ ID, Name ]
|
||||
|
||||
actions:
|
||||
- action: search
|
||||
@@ -57,6 +60,11 @@ errors:
|
||||
message: "stale data"
|
||||
severity: warning
|
||||
|
||||
- error: notUnique
|
||||
message: "node not unique"
|
||||
log: "used duplicate node TODO - module.node_id for this compose module TODO - module.rel_compose_module"
|
||||
severity: warning
|
||||
|
||||
- error: notAllowedToRead
|
||||
message: "not allowed to read this module"
|
||||
log: "could not read {module}; insufficient permissions"
|
||||
|
||||
137
federation/service/shared_module.go
Normal file
137
federation/service/shared_module.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
composeService "github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
)
|
||||
|
||||
type (
|
||||
sharedModule struct {
|
||||
ctx context.Context
|
||||
compose composeService.ModuleService
|
||||
store store.Storer
|
||||
actionlog actionlog.Recorder
|
||||
}
|
||||
|
||||
SharedModuleService interface {
|
||||
Find(ctx context.Context, filter types.SharedModuleFilter) (types.SharedModuleSet, types.SharedModuleFilter, error)
|
||||
FindByID(ctx context.Context, nodeID uint64, moduleID uint64) (*types.SharedModule, error)
|
||||
FindByAny(ctx context.Context, nodeID uint64, identifier interface{}) (*types.SharedModule, error)
|
||||
// DeleteByID(ctx context.Context, nodeID, moduleID uint64) error
|
||||
}
|
||||
|
||||
// moduleUpdateHandler func(ctx context.Context, ns *types.Node, c *types.SharedModule) (bool, bool, error)
|
||||
)
|
||||
|
||||
func SharedModule() SharedModuleService {
|
||||
return &sharedModule{
|
||||
ctx: context.Background(),
|
||||
compose: composeService.Module(),
|
||||
store: DefaultStore,
|
||||
actionlog: DefaultActionlog,
|
||||
}
|
||||
}
|
||||
|
||||
// FindByAny tries to find module in a particular namespace by id, handle or name
|
||||
func (svc sharedModule) FindByAny(ctx context.Context, nodeID uint64, identifier interface{}) (m *types.SharedModule, err error) {
|
||||
if ID, ok := identifier.(uint64); ok {
|
||||
m, err = svc.FindByID(ctx, nodeID, ID)
|
||||
} else if strIdentifier, ok := identifier.(string); ok {
|
||||
if ID, _ := strconv.ParseUint(strIdentifier, 10, 64); ID > 0 {
|
||||
m, err = svc.FindByID(ctx, nodeID, ID)
|
||||
}
|
||||
} else {
|
||||
// force invalid ID error
|
||||
// we do that to wrap error with lookup action context
|
||||
_, err = svc.FindByID(ctx, nodeID, 0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (svc sharedModule) FindByID(ctx context.Context, nodeID uint64, moduleID uint64) (module *types.SharedModule, err error) {
|
||||
err = func() error {
|
||||
if module, err = store.LookupFederationSharedModuleByID(svc.ctx, svc.store, moduleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return module, err
|
||||
}
|
||||
|
||||
// func (svc sharedModule) DeleteByID(ctx context.Context, nodeID, moduleID uint64) error {
|
||||
// return trim1st(svc.updater(ctx, nodeID, moduleID, ModuleActionDelete, svc.handleDelete))
|
||||
// }
|
||||
|
||||
// func (svc sharedModule) updater(ctx context.Context, nodeID, moduleID uint64, action func(...*moduleActionProps) *moduleAction, fn moduleUpdateHandler) (*types.SharedModule, error) {
|
||||
// var (
|
||||
// moduleChanged, fieldsChanged bool
|
||||
|
||||
// n *types.Node
|
||||
// m *types.SharedModule
|
||||
// // m, old *types.SharedModule
|
||||
// aProps = &moduleActionProps{module: &types.SharedModule{ID: moduleID, NodeID: nodeID}}
|
||||
// err error
|
||||
// )
|
||||
|
||||
// spew.Dump("before handle delete", fn, n, m)
|
||||
|
||||
// err = store.Tx(ctx, svc.store, func(ctx context.Context, s store.Storer) (err error) {
|
||||
// if m, err = svc.store.LookupFederationSharedModuleByID(ctx, moduleID); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // TODO - handle node id also
|
||||
// if moduleChanged, fieldsChanged, err = fn(ctx, n, m); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// return err
|
||||
// })
|
||||
|
||||
// return m, svc.recordAction(ctx, aProps, action, err)
|
||||
// }
|
||||
|
||||
// func (svc sharedModule) handleDelete(ctx context.Context, n *types.Node, m *types.SharedModule) (bool, bool, error) {
|
||||
// if err := store.DeleteFederationSharedModuleByID(ctx, svc.store, m.ID); err != nil {
|
||||
// return false, false, err
|
||||
// }
|
||||
|
||||
// return false, false, nil
|
||||
// }
|
||||
|
||||
func (svc sharedModule) Find(ctx context.Context, filter types.SharedModuleFilter) (set types.SharedModuleSet, f types.SharedModuleFilter, err error) {
|
||||
var (
|
||||
aProps = &sharedModuleActionProps{filter: &filter}
|
||||
)
|
||||
|
||||
err = func() error {
|
||||
// handle node for actionlog here?
|
||||
if f.NodeID > 0 {
|
||||
}
|
||||
|
||||
if set, f, err = store.SearchFederationSharedModules(ctx, svc.store, filter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return set, f, svc.recordAction(ctx, aProps, SharedModuleActionSearch, err)
|
||||
}
|
||||
|
||||
// // trim1st removes 1st param and returns only error
|
||||
// func trim1st(_ interface{}, err error) error {
|
||||
// return err
|
||||
// }
|
||||
871
federation/service/shared_module_actions.gen.go
Normal file
871
federation/service/shared_module_actions.gen.go
Normal file
@@ -0,0 +1,871 @@
|
||||
package service
|
||||
|
||||
// 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:
|
||||
// federation/service/shared_module_actions.yaml
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
)
|
||||
|
||||
type (
|
||||
sharedModuleActionProps struct {
|
||||
module *types.SharedModule
|
||||
changed *types.SharedModule
|
||||
filter *types.SharedModuleFilter
|
||||
node *types.Node
|
||||
}
|
||||
|
||||
sharedModuleAction struct {
|
||||
timestamp time.Time
|
||||
resource string
|
||||
action string
|
||||
log string
|
||||
severity actionlog.Severity
|
||||
|
||||
// prefix for error when action fails
|
||||
errorMessage string
|
||||
|
||||
props *sharedModuleActionProps
|
||||
}
|
||||
|
||||
sharedModuleError struct {
|
||||
timestamp time.Time
|
||||
error string
|
||||
resource string
|
||||
action string
|
||||
message string
|
||||
log string
|
||||
severity actionlog.Severity
|
||||
|
||||
wrap error
|
||||
|
||||
props *sharedModuleActionProps
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// just a placeholder to cover template cases w/o fmt package use
|
||||
_ = fmt.Println
|
||||
)
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Props methods
|
||||
// setModule updates sharedModuleActionProps's module
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *sharedModuleActionProps) setModule(module *types.SharedModule) *sharedModuleActionProps {
|
||||
p.module = module
|
||||
return p
|
||||
}
|
||||
|
||||
// setChanged updates sharedModuleActionProps's changed
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *sharedModuleActionProps) setChanged(changed *types.SharedModule) *sharedModuleActionProps {
|
||||
p.changed = changed
|
||||
return p
|
||||
}
|
||||
|
||||
// setFilter updates sharedModuleActionProps's filter
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *sharedModuleActionProps) setFilter(filter *types.SharedModuleFilter) *sharedModuleActionProps {
|
||||
p.filter = filter
|
||||
return p
|
||||
}
|
||||
|
||||
// setNode updates sharedModuleActionProps's node
|
||||
//
|
||||
// Allows method chaining
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p *sharedModuleActionProps) setNode(node *types.Node) *sharedModuleActionProps {
|
||||
p.node = node
|
||||
return p
|
||||
}
|
||||
|
||||
// serialize converts sharedModuleActionProps to actionlog.Meta
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p sharedModuleActionProps) serialize() actionlog.Meta {
|
||||
var (
|
||||
m = make(actionlog.Meta)
|
||||
)
|
||||
|
||||
if p.module != nil {
|
||||
m.Set("module.ID", p.module.ID, true)
|
||||
}
|
||||
if p.changed != nil {
|
||||
m.Set("changed.ID", p.changed.ID, true)
|
||||
}
|
||||
if p.filter != nil {
|
||||
m.Set("filter.query", p.filter.Query, true)
|
||||
m.Set("filter.sort", p.filter.Sort, true)
|
||||
m.Set("filter.limit", p.filter.Limit, true)
|
||||
}
|
||||
if p.node != nil {
|
||||
m.Set("node.ID", p.node.ID, true)
|
||||
m.Set("node.Name", p.node.Name, true)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// tr translates string and replaces meta value placeholder with values
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (p sharedModuleActionProps) tr(in string, err error) string {
|
||||
var (
|
||||
pairs = []string{"{err}"}
|
||||
// first non-empty string
|
||||
fns = func(ii ...interface{}) string {
|
||||
for _, i := range ii {
|
||||
if s := fmt.Sprintf("%v", i); len(s) > 0 {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
for {
|
||||
// Unwrap errors
|
||||
ue := errors.Unwrap(err)
|
||||
if ue == nil {
|
||||
break
|
||||
}
|
||||
|
||||
err = ue
|
||||
}
|
||||
|
||||
pairs = append(pairs, err.Error())
|
||||
} else {
|
||||
pairs = append(pairs, "nil")
|
||||
}
|
||||
|
||||
if p.module != nil {
|
||||
// replacement for "{module}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{module}",
|
||||
fns(
|
||||
p.module.ID,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{module.ID}", fns(p.module.ID))
|
||||
}
|
||||
|
||||
if p.changed != nil {
|
||||
// replacement for "{changed}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{changed}",
|
||||
fns(
|
||||
p.changed.ID,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{changed.ID}", fns(p.changed.ID))
|
||||
}
|
||||
|
||||
if p.filter != nil {
|
||||
// replacement for "{filter}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{filter}",
|
||||
fns(
|
||||
p.filter.Query,
|
||||
p.filter.Sort,
|
||||
p.filter.Limit,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{filter.query}", fns(p.filter.Query))
|
||||
pairs = append(pairs, "{filter.sort}", fns(p.filter.Sort))
|
||||
pairs = append(pairs, "{filter.limit}", fns(p.filter.Limit))
|
||||
}
|
||||
|
||||
if p.node != nil {
|
||||
// replacement for "{node}" (in order how fields are defined)
|
||||
pairs = append(
|
||||
pairs,
|
||||
"{node}",
|
||||
fns(
|
||||
p.node.ID,
|
||||
p.node.Name,
|
||||
),
|
||||
)
|
||||
pairs = append(pairs, "{node.ID}", fns(p.node.ID))
|
||||
pairs = append(pairs, "{node.Name}", fns(p.node.Name))
|
||||
}
|
||||
return strings.NewReplacer(pairs...).Replace(in)
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Action methods
|
||||
|
||||
// String returns loggable description as string
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (a *sharedModuleAction) String() string {
|
||||
var props = &sharedModuleActionProps{}
|
||||
|
||||
if a.props != nil {
|
||||
props = a.props
|
||||
}
|
||||
|
||||
return props.tr(a.log, nil)
|
||||
}
|
||||
|
||||
func (e *sharedModuleAction) LoggableAction() *actionlog.Action {
|
||||
return &actionlog.Action{
|
||||
Timestamp: e.timestamp,
|
||||
Resource: e.resource,
|
||||
Action: e.action,
|
||||
Severity: e.severity,
|
||||
Description: e.String(),
|
||||
Meta: e.props.serialize(),
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Error methods
|
||||
|
||||
// String returns loggable description as string
|
||||
//
|
||||
// It falls back to message if log is not set
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *sharedModuleError) String() string {
|
||||
var props = &sharedModuleActionProps{}
|
||||
|
||||
if e.props != nil {
|
||||
props = e.props
|
||||
}
|
||||
|
||||
if e.wrap != nil && !strings.Contains(e.log, "{err}") {
|
||||
// Suffix error log with {err} to ensure
|
||||
// we log the cause for this error
|
||||
e.log += ": {err}"
|
||||
}
|
||||
|
||||
return props.tr(e.log, e.wrap)
|
||||
}
|
||||
|
||||
// Error satisfies
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *sharedModuleError) Error() string {
|
||||
var props = &sharedModuleActionProps{}
|
||||
|
||||
if e.props != nil {
|
||||
props = e.props
|
||||
}
|
||||
|
||||
return props.tr(e.message, e.wrap)
|
||||
}
|
||||
|
||||
// Is fn for error equality check
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *sharedModuleError) Is(err error) bool {
|
||||
t, ok := err.(*sharedModuleError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return t.resource == e.resource && t.error == e.error
|
||||
}
|
||||
|
||||
// Is fn for error equality check
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *sharedModuleError) IsGeneric() bool {
|
||||
return e.error == "generic"
|
||||
}
|
||||
|
||||
// Wrap wraps sharedModuleError around another error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *sharedModuleError) Wrap(err error) *sharedModuleError {
|
||||
e.wrap = err
|
||||
return e
|
||||
}
|
||||
|
||||
// Unwrap returns wrapped error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (e *sharedModuleError) Unwrap() error {
|
||||
return e.wrap
|
||||
}
|
||||
|
||||
func (e *sharedModuleError) LoggableAction() *actionlog.Action {
|
||||
return &actionlog.Action{
|
||||
Timestamp: e.timestamp,
|
||||
Resource: e.resource,
|
||||
Action: e.action,
|
||||
Severity: e.severity,
|
||||
Description: e.String(),
|
||||
Error: e.Error(),
|
||||
Meta: e.props.serialize(),
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Action constructors
|
||||
|
||||
// SharedModuleActionSearch returns "federation:shared_module.search" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleActionSearch(props ...*sharedModuleActionProps) *sharedModuleAction {
|
||||
a := &sharedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
action: "search",
|
||||
log: "searched for modules",
|
||||
severity: actionlog.Info,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// SharedModuleActionLookup returns "federation:shared_module.lookup" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleActionLookup(props ...*sharedModuleActionProps) *sharedModuleAction {
|
||||
a := &sharedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
action: "lookup",
|
||||
log: "looked-up for a {module}",
|
||||
severity: actionlog.Info,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// SharedModuleActionCreate returns "federation:shared_module.create" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleActionCreate(props ...*sharedModuleActionProps) *sharedModuleAction {
|
||||
a := &sharedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
action: "create",
|
||||
log: "created {module}",
|
||||
severity: actionlog.Notice,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// SharedModuleActionUpdate returns "federation:shared_module.update" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleActionUpdate(props ...*sharedModuleActionProps) *sharedModuleAction {
|
||||
a := &sharedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
action: "update",
|
||||
log: "updated {module}",
|
||||
severity: actionlog.Notice,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// SharedModuleActionDelete returns "federation:shared_module.delete" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleActionDelete(props ...*sharedModuleActionProps) *sharedModuleAction {
|
||||
a := &sharedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
action: "delete",
|
||||
log: "deleted {module}",
|
||||
severity: actionlog.Notice,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// SharedModuleActionUndelete returns "federation:shared_module.undelete" error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleActionUndelete(props ...*sharedModuleActionProps) *sharedModuleAction {
|
||||
a := &sharedModuleAction{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
action: "undelete",
|
||||
log: "undeleted {module}",
|
||||
severity: actionlog.Notice,
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
a.props = props[0]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
// Error constructors
|
||||
|
||||
// SharedModuleErrGeneric returns "federation:shared_module.generic" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrGeneric(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "generic",
|
||||
action: "error",
|
||||
message: "failed to complete request due to internal error",
|
||||
log: "{err}",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotFound returns "federation:shared_module.notFound" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotFound(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notFound",
|
||||
action: "error",
|
||||
message: "module does not exist",
|
||||
log: "module does not exist",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrInvalidID returns "federation:shared_module.invalidID" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrInvalidID(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "invalidID",
|
||||
action: "error",
|
||||
message: "invalid ID",
|
||||
log: "invalid ID",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrStaleData returns "federation:shared_module.staleData" audit event as actionlog.Warning
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrStaleData(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "staleData",
|
||||
action: "error",
|
||||
message: "stale data",
|
||||
log: "stale data",
|
||||
severity: actionlog.Warning,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotAllowedToRead returns "federation:shared_module.notAllowedToRead" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotAllowedToRead(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notAllowedToRead",
|
||||
action: "error",
|
||||
message: "not allowed to read this module",
|
||||
log: "could not read {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotAllowedToListModules returns "federation:shared_module.notAllowedToListModules" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotAllowedToListModules(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notAllowedToListModules",
|
||||
action: "error",
|
||||
message: "not allowed to list modules",
|
||||
log: "could not list modules; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotAllowedToCreate returns "federation:shared_module.notAllowedToCreate" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotAllowedToCreate(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notAllowedToCreate",
|
||||
action: "error",
|
||||
message: "not allowed to create modules",
|
||||
log: "could not create modules; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotAllowedToUpdate returns "federation:shared_module.notAllowedToUpdate" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotAllowedToUpdate(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notAllowedToUpdate",
|
||||
action: "error",
|
||||
message: "not allowed to update this module",
|
||||
log: "could not update {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotAllowedToDelete returns "federation:shared_module.notAllowedToDelete" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotAllowedToDelete(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notAllowedToDelete",
|
||||
action: "error",
|
||||
message: "not allowed to delete this module",
|
||||
log: "could not delete {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// SharedModuleErrNotAllowedToUndelete returns "federation:shared_module.notAllowedToUndelete" audit event as actionlog.Error
|
||||
//
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func SharedModuleErrNotAllowedToUndelete(props ...*sharedModuleActionProps) *sharedModuleError {
|
||||
var e = &sharedModuleError{
|
||||
timestamp: time.Now(),
|
||||
resource: "federation:shared_module",
|
||||
error: "notAllowedToUndelete",
|
||||
action: "error",
|
||||
message: "not allowed to undelete this module",
|
||||
log: "could not undelete {module}; insufficient permissions",
|
||||
severity: actionlog.Error,
|
||||
props: func() *sharedModuleActionProps {
|
||||
if len(props) > 0 {
|
||||
return props[0]
|
||||
}
|
||||
return nil
|
||||
}(),
|
||||
}
|
||||
|
||||
if len(props) > 0 {
|
||||
e.props = props[0]
|
||||
}
|
||||
|
||||
return e
|
||||
|
||||
}
|
||||
|
||||
// *********************************************************************************************************************
|
||||
// *********************************************************************************************************************
|
||||
|
||||
// recordAction is a service helper function wraps function that can return error
|
||||
//
|
||||
// context is used to enrich audit log entry with current user info, request ID, IP address...
|
||||
// props are collected action/error properties
|
||||
// action (optional) fn will be used to construct sharedModuleAction struct from given props (and error)
|
||||
// err is any error that occurred while action was happening
|
||||
//
|
||||
// Action has success and fail (error) state:
|
||||
// - when recorded without an error (4th param), action is recorded as successful.
|
||||
// - when an additional error is given (4th param), action is used to wrap
|
||||
// the additional error
|
||||
//
|
||||
// This function is auto-generated.
|
||||
//
|
||||
func (svc sharedModule) recordAction(ctx context.Context, props *sharedModuleActionProps, action func(...*sharedModuleActionProps) *sharedModuleAction, err error) error {
|
||||
var (
|
||||
ok bool
|
||||
|
||||
// Return error
|
||||
retError *sharedModuleError
|
||||
|
||||
// Recorder error
|
||||
recError *sharedModuleError
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if retError, ok = err.(*sharedModuleError); !ok {
|
||||
// got non-sharedModule error, wrap it with SharedModuleErrGeneric
|
||||
retError = SharedModuleErrGeneric(props).Wrap(err)
|
||||
|
||||
if action != nil {
|
||||
// copy action to returning and recording error
|
||||
retError.action = action().action
|
||||
}
|
||||
|
||||
// we'll use SharedModuleErrGeneric for recording too
|
||||
// because it can hold more info
|
||||
recError = retError
|
||||
} else if retError != nil {
|
||||
if action != nil {
|
||||
// copy action to returning and recording error
|
||||
retError.action = action().action
|
||||
}
|
||||
// start with copy of return error for recording
|
||||
// this will be updated with tha root cause as we try and
|
||||
// unwrap the error
|
||||
recError = retError
|
||||
|
||||
// find the original recError for this error
|
||||
// for the purpose of logging
|
||||
var unwrappedError error = retError
|
||||
for {
|
||||
if unwrappedError = errors.Unwrap(unwrappedError); unwrappedError == nil {
|
||||
// nothing wrapped
|
||||
break
|
||||
}
|
||||
|
||||
// update recError ONLY of wrapped error is of type sharedModuleError
|
||||
if unwrappedSinkError, ok := unwrappedError.(*sharedModuleError); ok {
|
||||
recError = unwrappedSinkError
|
||||
}
|
||||
}
|
||||
|
||||
if retError.props == nil {
|
||||
// set props on returning error if empty
|
||||
retError.props = props
|
||||
}
|
||||
|
||||
if recError.props == nil {
|
||||
// set props on recording error if empty
|
||||
recError.props = props
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if svc.actionlog != nil {
|
||||
if retError != nil {
|
||||
// failed action, log error
|
||||
svc.actionlog.Record(ctx, recError)
|
||||
} else if action != nil {
|
||||
// successful
|
||||
svc.actionlog.Record(ctx, action(props))
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// retError not an interface and that WILL (!!) cause issues
|
||||
// with nil check (== nil) when it is not explicitly returned
|
||||
return nil
|
||||
}
|
||||
|
||||
return retError
|
||||
}
|
||||
85
federation/service/shared_module_actions.yaml
Normal file
85
federation/service/shared_module_actions.yaml
Normal file
@@ -0,0 +1,85 @@
|
||||
# List of loggable service actions
|
||||
|
||||
resource: federation:shared_module
|
||||
service: sharedModule
|
||||
|
||||
# Default sensitivity for actions
|
||||
defaultActionSeverity: notice
|
||||
|
||||
# default severity for errors
|
||||
defaultErrorSeverity: error
|
||||
|
||||
import:
|
||||
- github.com/cortezaproject/corteza-server/federation/types
|
||||
|
||||
props:
|
||||
- name: module
|
||||
type: "*types.SharedModule"
|
||||
fields: [ ID ]
|
||||
- name: changed
|
||||
type: "*types.SharedModule"
|
||||
fields: [ ID ]
|
||||
- name: filter
|
||||
type: "*types.SharedModuleFilter"
|
||||
fields: [ query, sort, limit ]
|
||||
- name: node
|
||||
type: "*types.Node"
|
||||
fields: [ ID, Name ]
|
||||
|
||||
actions:
|
||||
- action: search
|
||||
log: "searched for modules"
|
||||
severity: info
|
||||
|
||||
- action: lookup
|
||||
log: "looked-up for a {module}"
|
||||
severity: info
|
||||
|
||||
- action: create
|
||||
log: "created {module}"
|
||||
|
||||
- action: update
|
||||
log: "updated {module}"
|
||||
|
||||
- action: delete
|
||||
log: "deleted {module}"
|
||||
|
||||
- action: undelete
|
||||
log: "undeleted {module}"
|
||||
|
||||
errors:
|
||||
- error: notFound
|
||||
message: "module does not exist"
|
||||
severity: warning
|
||||
|
||||
- error: invalidID
|
||||
message: "invalid ID"
|
||||
severity: warning
|
||||
|
||||
- error: staleData
|
||||
message: "stale data"
|
||||
severity: warning
|
||||
|
||||
- error: notAllowedToRead
|
||||
message: "not allowed to read this module"
|
||||
log: "could not read {module}; insufficient permissions"
|
||||
|
||||
- error: notAllowedToListModules
|
||||
message: "not allowed to list modules"
|
||||
log: "could not list modules; insufficient permissions"
|
||||
|
||||
- error: notAllowedToCreate
|
||||
message: "not allowed to create modules"
|
||||
log: "could not create modules; insufficient permissions"
|
||||
|
||||
- error: notAllowedToUpdate
|
||||
message: "not allowed to update this module"
|
||||
log: "could not update {module}; insufficient permissions"
|
||||
|
||||
- error: notAllowedToDelete
|
||||
message: "not allowed to delete this module"
|
||||
log: "could not delete {module}; insufficient permissions"
|
||||
|
||||
- error: notAllowedToUndelete
|
||||
message: "not allowed to undelete this module"
|
||||
log: "could not undelete {module}; insufficient permissions"
|
||||
@@ -1,143 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
composeService "github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type (
|
||||
module struct {
|
||||
ctx context.Context
|
||||
compose composeService.ModuleService
|
||||
store store.Storer
|
||||
actionlog actionlog.Recorder
|
||||
}
|
||||
|
||||
ExposedModuleService interface {
|
||||
Find(ctx context.Context, filter types.ExposedModuleFilter) (types.ExposedModuleSet, error)
|
||||
FindByID(ctx context.Context, nodeID uint64, moduleID uint64) (*types.ExposedModule, error)
|
||||
FindByAny(ctx context.Context, nodeID uint64, identifier interface{}) (*types.ExposedModule, error)
|
||||
DeleteByID(ctx context.Context, nodeID, moduleID uint64) error
|
||||
// Remove(ctx context.Context, filter types.ExposedModuleFilter) (err error)
|
||||
}
|
||||
|
||||
moduleUpdateHandler func(ctx context.Context, ns *types.Node, c *types.ExposedModule) (bool, bool, error)
|
||||
)
|
||||
|
||||
func ExposedModule() ExposedModuleService {
|
||||
return &module{
|
||||
ctx: context.Background(),
|
||||
compose: composeService.Module(),
|
||||
store: DefaultStore,
|
||||
actionlog: DefaultActionlog,
|
||||
}
|
||||
}
|
||||
|
||||
// FindByAny tries to find module in a particular namespace by id, handle or name
|
||||
func (svc module) FindByAny(ctx context.Context, nodeID uint64, identifier interface{}) (m *types.ExposedModule, err error) {
|
||||
if ID, ok := identifier.(uint64); ok {
|
||||
m, err = svc.FindByID(ctx, nodeID, ID)
|
||||
} else if strIdentifier, ok := identifier.(string); ok {
|
||||
if ID, _ := strconv.ParseUint(strIdentifier, 10, 64); ID > 0 {
|
||||
m, err = svc.FindByID(ctx, nodeID, ID)
|
||||
}
|
||||
} else {
|
||||
// force invalid ID error
|
||||
// we do that to wrap error with lookup action context
|
||||
_, err = svc.FindByID(ctx, nodeID, 0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (svc module) FindByID(ctx context.Context, nodeID uint64, moduleID uint64) (module *types.ExposedModule, err error) {
|
||||
err = func() error {
|
||||
if module, err = store.LookupFederationExposedModuleByID(svc.ctx, svc.store, moduleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return module, err
|
||||
}
|
||||
|
||||
func (svc module) DeleteByID(ctx context.Context, nodeID, moduleID uint64) error {
|
||||
return trim1st(svc.updater(ctx, nodeID, moduleID, ModuleActionDelete, svc.handleDelete))
|
||||
}
|
||||
|
||||
func (svc module) updater(ctx context.Context, nodeID, moduleID uint64, action func(...*moduleActionProps) *moduleAction, fn moduleUpdateHandler) (*types.ExposedModule, error) {
|
||||
var (
|
||||
moduleChanged, fieldsChanged bool
|
||||
|
||||
n *types.Node
|
||||
m *types.ExposedModule
|
||||
// m, old *types.ExposedModule
|
||||
aProps = &moduleActionProps{module: &types.ExposedModule{ID: moduleID, NodeID: nodeID}}
|
||||
err error
|
||||
)
|
||||
|
||||
spew.Dump("before handle delete", fn, n, m)
|
||||
|
||||
err = store.Tx(ctx, svc.store, func(ctx context.Context, s store.Storer) (err error) {
|
||||
if m, err = svc.store.LookupFederationExposedModuleByID(ctx, moduleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO - handle node id also
|
||||
if moduleChanged, fieldsChanged, err = fn(ctx, n, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return m, svc.recordAction(ctx, aProps, action, err)
|
||||
}
|
||||
|
||||
func (svc module) handleDelete(ctx context.Context, n *types.Node, m *types.ExposedModule) (bool, bool, error) {
|
||||
if err := store.DeleteFederationExposedModuleByID(ctx, svc.store, m.ID); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
func (svc module) Find(ctx context.Context, filter types.ExposedModuleFilter) (set types.ExposedModuleSet, err error) {
|
||||
// get all modules per-node
|
||||
// feed the id's into the compose moduleservice
|
||||
// get the data
|
||||
// transform (but not here)
|
||||
|
||||
// go to store and fetch the id's, first as module id in filter
|
||||
// then without it
|
||||
|
||||
err = func() error {
|
||||
if set, _, err = store.SearchFederationExposedModules(svc.ctx, svc.store, filter); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
// return loadModuleFields(svc.ctx, svc.store, set...)
|
||||
}()
|
||||
|
||||
spew.Dump("ERR", err)
|
||||
|
||||
return set, err
|
||||
}
|
||||
|
||||
// trim1st removes 1st param and returns only error
|
||||
func trim1st(_ interface{}, err error) error {
|
||||
return err
|
||||
}
|
||||
@@ -10,7 +10,7 @@ type (
|
||||
ExposedModule struct {
|
||||
ID uint64 `json:"moduleID,string"`
|
||||
NodeID uint64 `json:"nodeID,string"`
|
||||
ComposeModuleID uint64 `json:"ComposeModuleID,string"`
|
||||
ComposeModuleID uint64 `json:"composeModuleID,string"`
|
||||
Fields ModuleFieldMappingList `json:"fields"`
|
||||
|
||||
CreatedAt time.Time `json:"createdAt,omitempty"`
|
||||
@@ -19,8 +19,9 @@ type (
|
||||
}
|
||||
|
||||
ExposedModuleFilter struct {
|
||||
NodeID uint64 `json:"node"`
|
||||
Query string `json:"query"`
|
||||
NodeID uint64 `json:"node"`
|
||||
ComposeModuleID uint64 `json:"composeModuleID"`
|
||||
Query string `json:"query"`
|
||||
|
||||
Check func(*ExposedModule) (bool, error) `json:"-"`
|
||||
|
||||
|
||||
35
federation/types/shared_module.go
Normal file
35
federation/types/shared_module.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
)
|
||||
|
||||
type (
|
||||
SharedModule struct {
|
||||
ID uint64 `json:"moduleID,string"`
|
||||
NodeID uint64 `json:"nodeID,string"`
|
||||
Handle string `json:"handle"`
|
||||
Name string `json:"name"`
|
||||
ExternalFederationModuleID uint64 `json:"externalFederationModuleID,string"`
|
||||
Fields ModuleFieldMappingList `json:"fields"`
|
||||
|
||||
CreatedAt time.Time `json:"createdAt,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty"`
|
||||
}
|
||||
|
||||
SharedModuleFilter struct {
|
||||
NodeID uint64 `json:"node"`
|
||||
Query string `json:"query"`
|
||||
|
||||
Handle string `json:"handle"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Check func(*SharedModule) (bool, error) `json:"-"`
|
||||
|
||||
filter.Sorting
|
||||
filter.Paging
|
||||
}
|
||||
)
|
||||
@@ -19,6 +19,11 @@ type (
|
||||
//
|
||||
// This type is auto-generated.
|
||||
NodeSet []*Node
|
||||
|
||||
// SharedModuleSet slice of SharedModule
|
||||
//
|
||||
// This type is auto-generated.
|
||||
SharedModuleSet []*SharedModule
|
||||
)
|
||||
|
||||
// Walk iterates through every slice item and calls w(ExposedModule) err
|
||||
@@ -132,3 +137,59 @@ func (set NodeSet) IDs() (IDs []uint64) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Walk iterates through every slice item and calls w(SharedModule) err
|
||||
//
|
||||
// This function is auto-generated.
|
||||
func (set SharedModuleSet) Walk(w func(*SharedModule) error) (err error) {
|
||||
for i := range set {
|
||||
if err = w(set[i]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Filter iterates through every slice item, calls f(SharedModule) (bool, err) and return filtered slice
|
||||
//
|
||||
// This function is auto-generated.
|
||||
func (set SharedModuleSet) Filter(f func(*SharedModule) (bool, error)) (out SharedModuleSet, err error) {
|
||||
var ok bool
|
||||
out = SharedModuleSet{}
|
||||
for i := range set {
|
||||
if ok, err = f(set[i]); err != nil {
|
||||
return
|
||||
} else if ok {
|
||||
out = append(out, set[i])
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FindByID finds items from slice by its ID property
|
||||
//
|
||||
// This function is auto-generated.
|
||||
func (set SharedModuleSet) FindByID(ID uint64) *SharedModule {
|
||||
for i := range set {
|
||||
if set[i].ID == ID {
|
||||
return set[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IDs returns a slice of uint64s from all items in the set
|
||||
//
|
||||
// This function is auto-generated.
|
||||
func (set SharedModuleSet) IDs() (IDs []uint64) {
|
||||
IDs = make([]uint64, len(set))
|
||||
|
||||
for i := range set {
|
||||
IDs[i] = set[i].ID
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -193,3 +193,93 @@ func TestNodeSetIDs(t *testing.T) {
|
||||
req.Equal(len(val), len(value))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedModuleSetWalk(t *testing.T) {
|
||||
var (
|
||||
value = make(SharedModuleSet, 3)
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
// check walk with no errors
|
||||
{
|
||||
err := value.Walk(func(*SharedModule) error {
|
||||
return nil
|
||||
})
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
// check walk with error
|
||||
req.Error(value.Walk(func(*SharedModule) error { return fmt.Errorf("walk error") }))
|
||||
}
|
||||
|
||||
func TestSharedModuleSetFilter(t *testing.T) {
|
||||
var (
|
||||
value = make(SharedModuleSet, 3)
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
// filter nothing
|
||||
{
|
||||
set, err := value.Filter(func(*SharedModule) (bool, error) {
|
||||
return true, nil
|
||||
})
|
||||
req.NoError(err)
|
||||
req.Equal(len(set), len(value))
|
||||
}
|
||||
|
||||
// filter one item
|
||||
{
|
||||
found := false
|
||||
set, err := value.Filter(func(*SharedModule) (bool, error) {
|
||||
if !found {
|
||||
found = true
|
||||
return found, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
req.NoError(err)
|
||||
req.Len(set, 1)
|
||||
}
|
||||
|
||||
// filter error
|
||||
{
|
||||
_, err := value.Filter(func(*SharedModule) (bool, error) {
|
||||
return false, fmt.Errorf("filter error")
|
||||
})
|
||||
req.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedModuleSetIDs(t *testing.T) {
|
||||
var (
|
||||
value = make(SharedModuleSet, 3)
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
// construct objects
|
||||
value[0] = new(SharedModule)
|
||||
value[1] = new(SharedModule)
|
||||
value[2] = new(SharedModule)
|
||||
// set ids
|
||||
value[0].ID = 1
|
||||
value[1].ID = 2
|
||||
value[2].ID = 3
|
||||
|
||||
// Find existing
|
||||
{
|
||||
val := value.FindByID(2)
|
||||
req.Equal(uint64(2), val.ID)
|
||||
}
|
||||
|
||||
// Find non-existing
|
||||
{
|
||||
val := value.FindByID(4)
|
||||
req.Nil(val)
|
||||
}
|
||||
|
||||
// List IDs from set
|
||||
{
|
||||
val := value.IDs()
|
||||
req.Equal(len(val), len(value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
types:
|
||||
Node:
|
||||
ExposedModule:
|
||||
SharedModule:
|
||||
|
||||
77
store/federation_shared_modules.gen.go
Normal file
77
store/federation_shared_modules.gen.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package store
|
||||
|
||||
// This file is auto-generated.
|
||||
//
|
||||
// Template: pkg/codegen/assets/store_base.gen.go.tpl
|
||||
// Definitions: store/federation_shared_modules.yaml
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
)
|
||||
|
||||
type (
|
||||
FederationSharedModules interface {
|
||||
SearchFederationSharedModules(ctx context.Context, f types.SharedModuleFilter) (types.SharedModuleSet, types.SharedModuleFilter, error)
|
||||
LookupFederationSharedModuleByID(ctx context.Context, id uint64) (*types.SharedModule, error)
|
||||
|
||||
CreateFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) error
|
||||
|
||||
UpdateFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) error
|
||||
|
||||
UpsertFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) error
|
||||
|
||||
DeleteFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) error
|
||||
DeleteFederationSharedModuleByID(ctx context.Context, ID uint64) error
|
||||
|
||||
TruncateFederationSharedModules(ctx context.Context) error
|
||||
}
|
||||
)
|
||||
|
||||
var _ *types.SharedModule
|
||||
var _ context.Context
|
||||
|
||||
// SearchFederationSharedModules returns all matching FederationSharedModules from store
|
||||
func SearchFederationSharedModules(ctx context.Context, s FederationSharedModules, f types.SharedModuleFilter) (types.SharedModuleSet, types.SharedModuleFilter, error) {
|
||||
return s.SearchFederationSharedModules(ctx, f)
|
||||
}
|
||||
|
||||
// LookupFederationSharedModuleByID searches for shared federation module by ID
|
||||
//
|
||||
// It returns shared federation module
|
||||
func LookupFederationSharedModuleByID(ctx context.Context, s FederationSharedModules, id uint64) (*types.SharedModule, error) {
|
||||
return s.LookupFederationSharedModuleByID(ctx, id)
|
||||
}
|
||||
|
||||
// CreateFederationSharedModule creates one or more FederationSharedModules in store
|
||||
func CreateFederationSharedModule(ctx context.Context, s FederationSharedModules, rr ...*types.SharedModule) error {
|
||||
return s.CreateFederationSharedModule(ctx, rr...)
|
||||
}
|
||||
|
||||
// UpdateFederationSharedModule updates one or more (existing) FederationSharedModules in store
|
||||
func UpdateFederationSharedModule(ctx context.Context, s FederationSharedModules, rr ...*types.SharedModule) error {
|
||||
return s.UpdateFederationSharedModule(ctx, rr...)
|
||||
}
|
||||
|
||||
// UpsertFederationSharedModule creates new or updates existing one or more FederationSharedModules in store
|
||||
func UpsertFederationSharedModule(ctx context.Context, s FederationSharedModules, rr ...*types.SharedModule) error {
|
||||
return s.UpsertFederationSharedModule(ctx, rr...)
|
||||
}
|
||||
|
||||
// DeleteFederationSharedModule Deletes one or more FederationSharedModules from store
|
||||
func DeleteFederationSharedModule(ctx context.Context, s FederationSharedModules, rr ...*types.SharedModule) error {
|
||||
return s.DeleteFederationSharedModule(ctx, rr...)
|
||||
}
|
||||
|
||||
// DeleteFederationSharedModuleByID Deletes FederationSharedModule from store
|
||||
func DeleteFederationSharedModuleByID(ctx context.Context, s FederationSharedModules, ID uint64) error {
|
||||
return s.DeleteFederationSharedModuleByID(ctx, ID)
|
||||
}
|
||||
|
||||
// TruncateFederationSharedModules Deletes all FederationSharedModules from store
|
||||
func TruncateFederationSharedModules(ctx context.Context, s FederationSharedModules) error {
|
||||
return s.TruncateFederationSharedModules(ctx)
|
||||
}
|
||||
29
store/federation_shared_modules.yaml
Normal file
29
store/federation_shared_modules.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
import:
|
||||
- github.com/cortezaproject/corteza-server/federation/types
|
||||
|
||||
types:
|
||||
type: types.SharedModule
|
||||
|
||||
fields:
|
||||
- { field: ID }
|
||||
- { field: NodeID }
|
||||
- { field: Handle }
|
||||
- { field: Name }
|
||||
- { field: ExternalFederationModuleID }
|
||||
- { field: Fields, type: "json.Text" }
|
||||
|
||||
|
||||
lookups:
|
||||
- fields: [ID]
|
||||
description: |-
|
||||
searches for shared federation module by ID
|
||||
|
||||
It returns shared federation module
|
||||
|
||||
rdbms:
|
||||
alias: cmd
|
||||
table: federation_module_shared
|
||||
customFilterConverter: true
|
||||
mapFields:
|
||||
NodeID: { column: rel_node }
|
||||
ExternalFederationModuleID: { column: xref_module }
|
||||
@@ -17,6 +17,7 @@ package store
|
||||
// - store/compose_records.yaml
|
||||
// - store/credentials.yaml
|
||||
// - store/federation_exposed_modules.yaml
|
||||
// - store/federation_shared_modules.yaml
|
||||
// - store/labels.yaml
|
||||
// - store/messaging_attachments.yaml
|
||||
// - store/messaging_channel_members.yaml
|
||||
@@ -53,6 +54,7 @@ type (
|
||||
ComposeRecords
|
||||
Credentials
|
||||
FederationExposedModules
|
||||
FederationSharedModules
|
||||
Labels
|
||||
MessagingAttachments
|
||||
MessagingChannelMembers
|
||||
|
||||
515
store/rdbms/federation_shared_modules.gen.go
Normal file
515
store/rdbms/federation_shared_modules.gen.go
Normal file
@@ -0,0 +1,515 @@
|
||||
package rdbms
|
||||
|
||||
// This file is an auto-generated file
|
||||
//
|
||||
// Template: pkg/codegen/assets/store_rdbms.gen.go.tpl
|
||||
// Definitions: store/federation_shared_modules.yaml
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior
|
||||
// and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
)
|
||||
|
||||
var _ = errors.Is
|
||||
|
||||
// SearchFederationSharedModules returns all matching rows
|
||||
//
|
||||
// This function calls convertFederationSharedModuleFilter with the given
|
||||
// types.SharedModuleFilter and expects to receive a working squirrel.SelectBuilder
|
||||
func (s Store) SearchFederationSharedModules(ctx context.Context, f types.SharedModuleFilter) (types.SharedModuleSet, types.SharedModuleFilter, error) {
|
||||
var (
|
||||
err error
|
||||
set []*types.SharedModule
|
||||
q squirrel.SelectBuilder
|
||||
)
|
||||
q, err = s.convertFederationSharedModuleFilter(f)
|
||||
if err != nil {
|
||||
return nil, f, err
|
||||
}
|
||||
|
||||
// Cleanup anything we've accidentally received...
|
||||
f.PrevPage, f.NextPage = nil, nil
|
||||
|
||||
// When cursor for a previous page is used it's marked as reversed
|
||||
// This tells us to flip the descending flag on all used sort keys
|
||||
reversedCursor := f.PageCursor != nil && f.PageCursor.Reverse
|
||||
|
||||
// If paging with reverse cursor, change the sorting
|
||||
// direction for all columns we're sorting by
|
||||
curSort := f.Sort.Clone()
|
||||
if reversedCursor {
|
||||
curSort.Reverse()
|
||||
}
|
||||
|
||||
return set, f, s.config.ErrorHandler(func() error {
|
||||
set, err = s.fetchFullPageOfFederationSharedModules(ctx, q, curSort, f.PageCursor, f.Limit, f.Check)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.Limit > 0 && len(set) > 0 {
|
||||
if f.PageCursor != nil && (!f.PageCursor.Reverse || uint(len(set)) == f.Limit) {
|
||||
f.PrevPage = s.collectFederationSharedModuleCursorValues(set[0], curSort.Columns()...)
|
||||
f.PrevPage.Reverse = true
|
||||
}
|
||||
|
||||
// Less items fetched then requested by page-limit
|
||||
// not very likely there's another page
|
||||
f.NextPage = s.collectFederationSharedModuleCursorValues(set[len(set)-1], curSort.Columns()...)
|
||||
}
|
||||
|
||||
f.PageCursor = nil
|
||||
return nil
|
||||
}())
|
||||
}
|
||||
|
||||
// fetchFullPageOfFederationSharedModules collects all requested results.
|
||||
//
|
||||
// Function applies:
|
||||
// - cursor conditions (where ...)
|
||||
// - sorting rules (order by ...)
|
||||
// - limit
|
||||
//
|
||||
// Main responsibility of this function is to perform additional sequential queries in case when not enough results
|
||||
// are collected due to failed check on a specific row (by check fn). Function then moves cursor to the last item fetched
|
||||
func (s Store) fetchFullPageOfFederationSharedModules(
|
||||
ctx context.Context,
|
||||
q squirrel.SelectBuilder,
|
||||
sort filter.SortExprSet,
|
||||
cursor *filter.PagingCursor,
|
||||
limit uint,
|
||||
check func(*types.SharedModule) (bool, error),
|
||||
) ([]*types.SharedModule, error) {
|
||||
var (
|
||||
set = make([]*types.SharedModule, 0, DefaultSliceCapacity)
|
||||
aux []*types.SharedModule
|
||||
last *types.SharedModule
|
||||
|
||||
// When cursor for a previous page is used it's marked as reversed
|
||||
// This tells us to flip the descending flag on all used sort keys
|
||||
reversedCursor = cursor != nil && cursor.Reverse
|
||||
|
||||
// copy of the select builder
|
||||
tryQuery squirrel.SelectBuilder
|
||||
|
||||
fetched uint
|
||||
err error
|
||||
)
|
||||
|
||||
// Make sure we always end our sort by primary keys
|
||||
if sort.Get("id") == nil {
|
||||
sort = append(sort, &filter.SortExpr{Column: "id"})
|
||||
}
|
||||
|
||||
// Apply sorting expr from filter to query
|
||||
if q, err = setOrderBy(q, sort, s.sortableFederationSharedModuleColumns()...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for try := 0; try < MaxRefetches; try++ {
|
||||
tryQuery = setCursorCond(q, cursor)
|
||||
if limit > 0 {
|
||||
tryQuery = tryQuery.Limit(uint64(limit))
|
||||
}
|
||||
|
||||
if aux, fetched, last, err = s.QueryFederationSharedModules(ctx, tryQuery, check); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if limit > 0 && uint(len(aux)) >= limit {
|
||||
// we should use only as much as requested
|
||||
set = append(set, aux[0:limit]...)
|
||||
break
|
||||
} else {
|
||||
set = append(set, aux...)
|
||||
}
|
||||
|
||||
// if limit is not set or we've already collected enough items
|
||||
// we can break the loop right away
|
||||
if limit == 0 || fetched == 0 || fetched < limit {
|
||||
break
|
||||
}
|
||||
|
||||
// In case limit is set very low and we've missed records in the first fetch,
|
||||
// make sure next fetch limit is a bit higher
|
||||
if limit < MinEnsureFetchLimit {
|
||||
limit = MinEnsureFetchLimit
|
||||
}
|
||||
|
||||
// @todo improve strategy for collecting next page with lower limit
|
||||
|
||||
// Point cursor to the last fetched element
|
||||
if cursor = s.collectFederationSharedModuleCursorValues(last, sort.Columns()...); cursor == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if reversedCursor {
|
||||
// Cursor for previous page was used
|
||||
// Fetched set needs to be reverseCursor because we've forced a descending order to
|
||||
// get the previous page
|
||||
for i, j := 0, len(set)-1; i < j; i, j = i+1, j-1 {
|
||||
set[i], set[j] = set[j], set[i]
|
||||
}
|
||||
}
|
||||
|
||||
return set, nil
|
||||
}
|
||||
|
||||
// QueryFederationSharedModules queries the database, converts and checks each row and
|
||||
// returns collected set
|
||||
//
|
||||
// Fn also returns total number of fetched items and last fetched item so that the caller can construct cursor
|
||||
// for next page of results
|
||||
func (s Store) QueryFederationSharedModules(
|
||||
ctx context.Context,
|
||||
q squirrel.Sqlizer,
|
||||
check func(*types.SharedModule) (bool, error),
|
||||
) ([]*types.SharedModule, uint, *types.SharedModule, error) {
|
||||
var (
|
||||
set = make([]*types.SharedModule, 0, DefaultSliceCapacity)
|
||||
res *types.SharedModule
|
||||
|
||||
// Query rows with
|
||||
rows, err = s.Query(ctx, q)
|
||||
|
||||
fetched uint
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
fetched++
|
||||
if err = rows.Err(); err == nil {
|
||||
res, err = s.internalFederationSharedModuleRowScanner(rows)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
|
||||
// If check function is set, call it and act accordingly
|
||||
if check != nil {
|
||||
if chk, err := check(res); err != nil {
|
||||
return nil, 0, nil, err
|
||||
} else if !chk {
|
||||
// did not pass the check
|
||||
// go with the next row
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
set = append(set, res)
|
||||
}
|
||||
|
||||
return set, fetched, res, rows.Err()
|
||||
}
|
||||
|
||||
// LookupFederationSharedModuleByID searches for shared federation module by ID
|
||||
//
|
||||
// It returns shared federation module
|
||||
func (s Store) LookupFederationSharedModuleByID(ctx context.Context, id uint64) (*types.SharedModule, error) {
|
||||
return s.execLookupFederationSharedModule(ctx, squirrel.Eq{
|
||||
s.preprocessColumn("cmd.id", ""): s.preprocessValue(id, ""),
|
||||
})
|
||||
}
|
||||
|
||||
// CreateFederationSharedModule creates one or more rows in federation_module_shared table
|
||||
func (s Store) CreateFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) (err error) {
|
||||
for _, res := range rr {
|
||||
err = s.checkFederationSharedModuleConstraints(ctx, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.execCreateFederationSharedModules(ctx, s.internalFederationSharedModuleEncoder(res))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateFederationSharedModule updates one or more existing rows in federation_module_shared
|
||||
func (s Store) UpdateFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) error {
|
||||
return s.config.ErrorHandler(s.partialFederationSharedModuleUpdate(ctx, nil, rr...))
|
||||
}
|
||||
|
||||
// partialFederationSharedModuleUpdate updates one or more existing rows in federation_module_shared
|
||||
func (s Store) partialFederationSharedModuleUpdate(ctx context.Context, onlyColumns []string, rr ...*types.SharedModule) (err error) {
|
||||
for _, res := range rr {
|
||||
err = s.checkFederationSharedModuleConstraints(ctx, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.execUpdateFederationSharedModules(
|
||||
ctx,
|
||||
squirrel.Eq{
|
||||
s.preprocessColumn("cmd.id", ""): s.preprocessValue(res.ID, ""),
|
||||
},
|
||||
s.internalFederationSharedModuleEncoder(res).Skip("id").Only(onlyColumns...))
|
||||
if err != nil {
|
||||
return s.config.ErrorHandler(err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpsertFederationSharedModule updates one or more existing rows in federation_module_shared
|
||||
func (s Store) UpsertFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) (err error) {
|
||||
for _, res := range rr {
|
||||
err = s.checkFederationSharedModuleConstraints(ctx, res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.config.ErrorHandler(s.execUpsertFederationSharedModules(ctx, s.internalFederationSharedModuleEncoder(res)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFederationSharedModule Deletes one or more rows from federation_module_shared table
|
||||
func (s Store) DeleteFederationSharedModule(ctx context.Context, rr ...*types.SharedModule) (err error) {
|
||||
for _, res := range rr {
|
||||
|
||||
err = s.execDeleteFederationSharedModules(ctx, squirrel.Eq{
|
||||
s.preprocessColumn("cmd.id", ""): s.preprocessValue(res.ID, ""),
|
||||
})
|
||||
if err != nil {
|
||||
return s.config.ErrorHandler(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteFederationSharedModuleByID Deletes row from the federation_module_shared table
|
||||
func (s Store) DeleteFederationSharedModuleByID(ctx context.Context, ID uint64) error {
|
||||
return s.execDeleteFederationSharedModules(ctx, squirrel.Eq{
|
||||
s.preprocessColumn("cmd.id", ""): s.preprocessValue(ID, ""),
|
||||
})
|
||||
}
|
||||
|
||||
// TruncateFederationSharedModules Deletes all rows from the federation_module_shared table
|
||||
func (s Store) TruncateFederationSharedModules(ctx context.Context) error {
|
||||
return s.config.ErrorHandler(s.Truncate(ctx, s.federationSharedModuleTable()))
|
||||
}
|
||||
|
||||
// execLookupFederationSharedModule prepares FederationSharedModule query and executes it,
|
||||
// returning types.SharedModule (or error)
|
||||
func (s Store) execLookupFederationSharedModule(ctx context.Context, cnd squirrel.Sqlizer) (res *types.SharedModule, err error) {
|
||||
var (
|
||||
row rowScanner
|
||||
)
|
||||
|
||||
row, err = s.QueryRow(ctx, s.federationSharedModulesSelectBuilder().Where(cnd))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res, err = s.internalFederationSharedModuleRowScanner(row)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// execCreateFederationSharedModules updates all matched (by cnd) rows in federation_module_shared with given data
|
||||
func (s Store) execCreateFederationSharedModules(ctx context.Context, payload store.Payload) error {
|
||||
return s.config.ErrorHandler(s.Exec(ctx, s.InsertBuilder(s.federationSharedModuleTable()).SetMap(payload)))
|
||||
}
|
||||
|
||||
// execUpdateFederationSharedModules updates all matched (by cnd) rows in federation_module_shared with given data
|
||||
func (s Store) execUpdateFederationSharedModules(ctx context.Context, cnd squirrel.Sqlizer, set store.Payload) error {
|
||||
return s.config.ErrorHandler(s.Exec(ctx, s.UpdateBuilder(s.federationSharedModuleTable("cmd")).Where(cnd).SetMap(set)))
|
||||
}
|
||||
|
||||
// execUpsertFederationSharedModules inserts new or updates matching (by-primary-key) rows in federation_module_shared with given data
|
||||
func (s Store) execUpsertFederationSharedModules(ctx context.Context, set store.Payload) error {
|
||||
upsert, err := s.config.UpsertBuilder(
|
||||
s.config,
|
||||
s.federationSharedModuleTable(),
|
||||
set,
|
||||
"id",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.config.ErrorHandler(s.Exec(ctx, upsert))
|
||||
}
|
||||
|
||||
// execDeleteFederationSharedModules Deletes all matched (by cnd) rows in federation_module_shared with given data
|
||||
func (s Store) execDeleteFederationSharedModules(ctx context.Context, cnd squirrel.Sqlizer) error {
|
||||
return s.config.ErrorHandler(s.Exec(ctx, s.DeleteBuilder(s.federationSharedModuleTable("cmd")).Where(cnd)))
|
||||
}
|
||||
|
||||
func (s Store) internalFederationSharedModuleRowScanner(row rowScanner) (res *types.SharedModule, err error) {
|
||||
res = &types.SharedModule{}
|
||||
|
||||
if _, has := s.config.RowScanners["federationSharedModule"]; has {
|
||||
scanner := s.config.RowScanners["federationSharedModule"].(func(_ rowScanner, _ *types.SharedModule) error)
|
||||
err = scanner(row, res)
|
||||
} else {
|
||||
err = row.Scan(
|
||||
&res.ID,
|
||||
&res.NodeID,
|
||||
&res.Handle,
|
||||
&res.Name,
|
||||
&res.ExternalFederationModuleID,
|
||||
&res.Fields,
|
||||
)
|
||||
}
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not scan db row for FederationSharedModule: %w", err)
|
||||
} else {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
// QueryFederationSharedModules returns squirrel.SelectBuilder with set table and all columns
|
||||
func (s Store) federationSharedModulesSelectBuilder() squirrel.SelectBuilder {
|
||||
return s.SelectBuilder(s.federationSharedModuleTable("cmd"), s.federationSharedModuleColumns("cmd")...)
|
||||
}
|
||||
|
||||
// federationSharedModuleTable name of the db table
|
||||
func (Store) federationSharedModuleTable(aa ...string) string {
|
||||
var alias string
|
||||
if len(aa) > 0 {
|
||||
alias = " AS " + aa[0]
|
||||
}
|
||||
|
||||
return "federation_module_shared" + alias
|
||||
}
|
||||
|
||||
// FederationSharedModuleColumns returns all defined table columns
|
||||
//
|
||||
// With optional string arg, all columns are returned aliased
|
||||
func (Store) federationSharedModuleColumns(aa ...string) []string {
|
||||
var alias string
|
||||
if len(aa) > 0 {
|
||||
alias = aa[0] + "."
|
||||
}
|
||||
|
||||
return []string{
|
||||
alias + "id",
|
||||
alias + "rel_node",
|
||||
alias + "handle",
|
||||
alias + "name",
|
||||
alias + "xref_module",
|
||||
alias + "fields",
|
||||
}
|
||||
}
|
||||
|
||||
// {true true true true true}
|
||||
|
||||
// sortableFederationSharedModuleColumns returns all FederationSharedModule columns flagged as sortable
|
||||
//
|
||||
// With optional string arg, all columns are returned aliased
|
||||
func (Store) sortableFederationSharedModuleColumns() []string {
|
||||
return []string{
|
||||
"id",
|
||||
}
|
||||
}
|
||||
|
||||
// internalFederationSharedModuleEncoder encodes fields from types.SharedModule to store.Payload (map)
|
||||
//
|
||||
// Encoding is done by using generic approach or by calling encodeFederationSharedModule
|
||||
// func when rdbms.customEncoder=true
|
||||
func (s Store) internalFederationSharedModuleEncoder(res *types.SharedModule) store.Payload {
|
||||
return store.Payload{
|
||||
"id": res.ID,
|
||||
"rel_node": res.NodeID,
|
||||
"handle": res.Handle,
|
||||
"name": res.Name,
|
||||
"xref_module": res.ExternalFederationModuleID,
|
||||
"fields": res.Fields,
|
||||
}
|
||||
}
|
||||
|
||||
// collectFederationSharedModuleCursorValues collects values from the given resource that and sets them to the cursor
|
||||
// to be used for pagination
|
||||
//
|
||||
// Values that are collected must come from sortable, unique or primary columns/fields
|
||||
// At least one of the collected columns must be flagged as unique, otherwise fn appends primary keys at the end
|
||||
//
|
||||
// Known issue:
|
||||
// when collecting cursor values for query that sorts by unique column with partial index (ie: unique handle on
|
||||
// undeleted items)
|
||||
func (s Store) collectFederationSharedModuleCursorValues(res *types.SharedModule, cc ...string) *filter.PagingCursor {
|
||||
var (
|
||||
cursor = &filter.PagingCursor{}
|
||||
|
||||
hasUnique bool
|
||||
|
||||
// All known primary key columns
|
||||
|
||||
pkId bool
|
||||
|
||||
collect = func(cc ...string) {
|
||||
for _, c := range cc {
|
||||
switch c {
|
||||
case "id":
|
||||
cursor.Set(c, res.ID, false)
|
||||
|
||||
pkId = true
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
collect(cc...)
|
||||
if !hasUnique || !(pkId && true) {
|
||||
collect("id")
|
||||
}
|
||||
|
||||
return cursor
|
||||
}
|
||||
|
||||
// checkFederationSharedModuleConstraints performs lookups (on valid) resource to check if any of the values on unique fields
|
||||
// already exists in the store
|
||||
//
|
||||
// Using built-in constraint checking would be more performant but unfortunately we can not rely
|
||||
// on the full support (MySQL does not support conditional indexes)
|
||||
func (s *Store) checkFederationSharedModuleConstraints(ctx context.Context, res *types.SharedModule) error {
|
||||
// Consider resource valid when all fields in unique constraint check lookups
|
||||
// have valid (non-empty) value
|
||||
//
|
||||
// Only string and uint64 are supported for now
|
||||
// feel free to add additional types if needed
|
||||
var valid = true
|
||||
|
||||
if !valid {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
28
store/rdbms/federation_shared_modules.go
Normal file
28
store/rdbms/federation_shared_modules.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package rdbms
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/cortezaproject/corteza-server/federation/types"
|
||||
)
|
||||
|
||||
func (s Store) convertFederationSharedModuleFilter(f types.SharedModuleFilter) (query squirrel.SelectBuilder, err error) {
|
||||
query = s.federationSharedModulesSelectBuilder()
|
||||
|
||||
// query = filter.StateCondition(query, "cmd.deleted_at", f.Deleted)
|
||||
|
||||
if f.NodeID > 0 {
|
||||
query = query.Where("cmd.rel_node = ?", f.NodeID)
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
q := "%" + strings.ToLower(f.Query) + "%"
|
||||
query = query.Where(squirrel.Or{
|
||||
squirrel.Like{"LOWER(cmd.name)": q},
|
||||
squirrel.Like{"LOWER(cmd.handle)": q},
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -15,6 +15,7 @@ package tests
|
||||
// - store/compose_pages.yaml
|
||||
// - store/credentials.yaml
|
||||
// - store/federation_exposed_modules.yaml
|
||||
// - store/federation_shared_modules.yaml
|
||||
// - store/labels.yaml
|
||||
// - store/messaging_attachments.yaml
|
||||
// - store/messaging_channel_members.yaml
|
||||
@@ -107,6 +108,11 @@ func testAllGenerated(t *testing.T, s store.Storer) {
|
||||
testFederationExposedModules(t, s)
|
||||
})
|
||||
|
||||
// Run generated tests for FederationSharedModules
|
||||
t.Run("FederationSharedModules", func(t *testing.T) {
|
||||
testFederationSharedModules(t, s)
|
||||
})
|
||||
|
||||
// Run generated tests for Labels
|
||||
t.Run("Labels", func(t *testing.T) {
|
||||
testLabels(t, s)
|
||||
|
||||
Reference in New Issue
Block a user