3
0

Added base federation module

This commit is contained in:
Peter Grlica
2020-09-02 16:38:24 +02:00
parent 30b49e4f2d
commit d47acaf0db
14 changed files with 447 additions and 0 deletions
+2
View File
@@ -22,6 +22,7 @@ type (
HTTPServer options.HTTPServerOpt
Websocket options.WebsocketOpt
Eventbus options.EventbusOpt
Federation options.FederationOpt
}
)
@@ -44,5 +45,6 @@ func NewOptions() *Options {
HTTPServer: *options.HTTPServer(),
Websocket: *options.Websocket(),
Eventbus: *options.Eventbus(),
Federation: *options.Federation(),
}
}
+5
View File
@@ -3,6 +3,7 @@ package app
import (
"context"
composeRest "github.com/cortezaproject/corteza-server/compose/rest"
federationRest "github.com/cortezaproject/corteza-server/federation/rest"
messagingRest "github.com/cortezaproject/corteza-server/messaging/rest"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/api/server"
@@ -70,4 +71,8 @@ func (app *CortezaApp) mountHttpRoutes(r chi.Router) {
)
r.Route("/"+webappBaseUrl, webapp.MakeWebappServer(app.Opt.HTTPServer))
}
if app.Opt.Federation.Enabled {
r.Route("/federation", federationRest.MountRoutes)
}
}
+17
View File
@@ -0,0 +1,17 @@
---
# This is direct conversion from old api/*/spec.json files
# using https://www.json2yaml.com/
#
# Next step: swagger.
endpoints:
- title: Foobar
entrypoint: foobar
path: "/foobar"
authentication: []
imports:
apis:
- name: foobar
method: GET
title: Foo bar
path: "/"
+37
View File
@@ -0,0 +1,37 @@
package rest
import (
"context"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/federation/rest/request"
)
type (
namespacePayload struct {
*types.Namespace
CanGrant bool `json:"canGrant"`
CanUpdateNamespace bool `json:"canUpdateNamespace"`
CanDeleteNamespace bool `json:"canDeleteNamespace"`
CanManageNamespace bool `json:"canManageNamespace"`
CanCreateModule bool `json:"canCreateModule"`
CanCreateChart bool `json:"canCreateChart"`
CanCreatePage bool `json:"canCreatePage"`
}
payload struct{}
Foobar struct{}
accessController interface {
CanGrant(context.Context) bool
}
)
func (Foobar) New() *Foobar {
return &Foobar{}
}
func (ctrl Foobar) Foobar(ctx context.Context, r *request.FoobarFoobar) (interface{}, error) {
return &struct{}{}, nil
}
+63
View File
@@ -0,0 +1,63 @@
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
FoobarAPI interface {
Foobar(context.Context, *request.FoobarFoobar) (interface{}, error)
}
// HTTP API interface
Foobar struct {
Foobar func(http.ResponseWriter, *http.Request)
}
)
func NewFoobar(h FoobarAPI) *Foobar {
return &Foobar{
Foobar: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewFoobarFoobar()
if err := params.Fill(r); err != nil {
logger.LogParamError("Foobar.Foobar", r, err)
resputil.JSON(w, err)
return
}
value, err := h.Foobar(r.Context(), params)
if err != nil {
logger.LogControllerError("Foobar.Foobar", r, err, params.Auditable())
resputil.JSON(w, err)
return
}
logger.LogControllerCall("Foobar.Foobar", r, params.Auditable())
if !serveHTTP(value, w, r) {
resputil.JSON(w, value)
}
},
}
}
func (h Foobar) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Get("/foobar/", h.Foobar)
})
}
+17
View File
@@ -0,0 +1,17 @@
package handlers
import (
"net/http"
)
// Edit this file in `codegen/common/rest/handlers/util.go`;
// any changes under [service] will be overwritten by codegen.
func serveHTTP(value interface{}, w http.ResponseWriter, r *http.Request) bool {
switch fn := value.(type) {
case func(http.ResponseWriter, *http.Request):
fn(w, r)
return true
}
return false
}
+18
View File
@@ -0,0 +1,18 @@
package rest
import (
"net/http"
"github.com/cortezaproject/corteza-server/compose/service"
)
func middlewareAllowedAccess(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !service.DefaultAccessControl.CanAccess(r.Context()) {
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
+60
View File
@@ -0,0 +1,60 @@
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
FoobarFoobar struct {
}
)
// NewFoobarFoobar request
func NewFoobarFoobar() *FoobarFoobar {
return &FoobarFoobar{}
}
// Auditable returns all auditable/loggable parameters
func (r FoobarFoobar) Auditable() map[string]interface{} {
return map[string]interface{}{}
}
// Fill processes request and fills internal variables
func (r *FoobarFoobar) 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)
}
}
return err
}
+22
View File
@@ -0,0 +1,22 @@
package rest
import (
"github.com/go-chi/chi"
"github.com/cortezaproject/corteza-server/federation/rest/handlers"
"github.com/cortezaproject/corteza-server/pkg/auth"
)
func MountRoutes(r chi.Router) {
var (
foobar = Foobar{}.New()
)
// Protect all _private_ routes
r.Group(func(r chi.Router) {
r.Use(auth.MiddlewareValidOnly)
r.Use(middlewareAllowedAccess)
handlers.NewFoobar(foobar).MountRoutes(r)
})
}
+8
View File
@@ -0,0 +1,8 @@
package types
type (
Node struct {
ID uint64 `json:"recordID,string"`
Name string `json:"name,string"`
}
)
+73
View File
@@ -0,0 +1,73 @@
package types
// 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/types/types.yaml
type (
// NodeSet slice of Node
//
// This type is auto-generated.
NodeSet []*Node
)
// Walk iterates through every slice item and calls w(Node) err
//
// This function is auto-generated.
func (set NodeSet) Walk(w func(*Node) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(Node) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set NodeSet) Filter(f func(*Node) (bool, error)) (out NodeSet, err error) {
var ok bool
out = NodeSet{}
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 NodeSet) FindByID(ID uint64) *Node {
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 NodeSet) IDs() (IDs []uint64) {
IDs = make([]uint64, len(set))
for i := range set {
IDs[i] = set[i].ID
}
return
}
+105
View File
@@ -0,0 +1,105 @@
package types
// 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/types/types.yaml
import (
"fmt"
"github.com/stretchr/testify/require"
"testing"
)
func TestNodeSetWalk(t *testing.T) {
var (
value = make(NodeSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*Node) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*Node) error { return fmt.Errorf("walk error") }))
}
func TestNodeSetFilter(t *testing.T) {
var (
value = make(NodeSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*Node) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*Node) (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(*Node) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestNodeSetIDs(t *testing.T) {
var (
value = make(NodeSet, 3)
req = require.New(t)
)
// construct objects
value[0] = new(Node)
value[1] = new(Node)
value[2] = new(Node)
// 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))
}
}
+2
View File
@@ -0,0 +1,2 @@
types:
Node:
+18
View File
@@ -0,0 +1,18 @@
package options
type (
FederationOpt struct {
Enabled bool `env:"FEDERATION_ENABLED"`
}
)
func Federation() (o *FederationOpt) {
o = &FederationOpt{
Enabled: false,
}
fill(o)
return
}