Files
upstream-corteza/server/system/rest/dal_connection.go
upstream-mirror 7e385fc126
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:22:23 +05:00

296 lines
7.9 KiB
Go

package rest
import (
"context"
"io"
"net/http"
"time"
federationService "github.com/cortezaproject/corteza/server/federation/service"
federationTypes "github.com/cortezaproject/corteza/server/federation/types"
"github.com/cortezaproject/corteza/server/pkg/api"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/handle"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/system/rest/request"
"github.com/cortezaproject/corteza/server/system/service"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/modern-go/reflect2"
)
type (
DalConnection struct {
svc connectionService
federationSvc federationNodeService
connectionAc connectionAccessController
}
connectionPayload struct {
*types.DalConnection
CanGrant bool `json:"canGrant"`
CanUpdateConnection bool `json:"canUpdateConnection"`
CanDeleteConnection bool `json:"canDeleteConnection"`
CanManageDalConfig bool `json:"canManageDalConfig"`
}
connectionSetPayload struct {
Filter types.DalConnectionFilter `json:"filter"`
Set []*connectionPayload `json:"set"`
}
connectionAccessController interface {
CanGrant(context.Context) bool
CanCreateDalConnection(context.Context) bool
CanUpdateDalConnection(context.Context, *types.DalConnection) bool
CanDeleteDalConnection(context.Context, *types.DalConnection) bool
CanManageDalConfigOnDalConnection(context.Context, *types.DalConnection) bool
}
connectionService interface {
FindByID(ctx context.Context, ID uint64) (*types.DalConnection, error)
Create(ctx context.Context, new *types.DalConnection) (*types.DalConnection, error)
Update(ctx context.Context, upd *types.DalConnection) (*types.DalConnection, error)
DeleteByID(ctx context.Context, ID uint64) error
UndeleteByID(ctx context.Context, ID uint64) error
Search(ctx context.Context, filter types.DalConnectionFilter) (types.DalConnectionSet, types.DalConnectionFilter, error)
}
federationNodeService interface {
Search(ctx context.Context, filter federationTypes.NodeFilter) (set federationTypes.NodeSet, f federationTypes.NodeFilter, err error)
}
)
func (DalConnection) New() *DalConnection {
return &DalConnection{
svc: service.DefaultDalConnection,
federationSvc: federationService.DefaultNode,
connectionAc: service.DefaultAccessControl,
}
}
func (ctrl DalConnection) List(ctx context.Context, r *request.DalConnectionList) (interface{}, error) {
var (
err error
dalConnections types.DalConnectionSet
f = types.DalConnectionFilter{
DalConnectionID: r.ConnectionID,
Handle: r.Handle,
Type: r.Type,
Deleted: filter.State(r.Deleted),
}
)
if f.Deleted == 0 {
f.Deleted = filter.StateExcluded
}
f.IncTotal = r.IncTotal
dalConnections, f, err = ctrl.collectConnections(ctx, f)
if err != nil {
return nil, err
}
return ctrl.makeFilterPayload(ctx, dalConnections, f)
}
func (ctrl DalConnection) Create(ctx context.Context, r *request.DalConnectionCreate) (interface{}, error) {
connection := &types.DalConnection{
Handle: r.Handle,
Type: r.Type,
Meta: r.Meta,
Config: r.Config,
}
res, err := ctrl.svc.Create(ctx, connection)
if err != nil {
return nil, err
}
return ctrl.makePayload(ctx, res), nil
}
func (ctrl DalConnection) Update(ctx context.Context, r *request.DalConnectionUpdate) (interface{}, error) {
connection := &types.DalConnection{
ID: r.ConnectionID,
Handle: r.Handle,
Type: r.Type,
Meta: r.Meta,
Config: r.Config,
UpdatedAt: r.UpdatedAt,
}
res, err := ctrl.svc.Update(ctx, connection)
if err != nil {
return nil, err
}
return ctrl.makePayload(ctx, res), nil
}
func (ctrl DalConnection) Read(ctx context.Context, r *request.DalConnectionRead) (interface{}, error) {
res, err := ctrl.svc.FindByID(ctx, r.ConnectionID)
if err != nil {
return nil, err
}
return ctrl.makePayload(ctx, res), nil
}
func (ctrl DalConnection) Delete(ctx context.Context, r *request.DalConnectionDelete) (interface{}, error) {
return api.OK(), ctrl.svc.DeleteByID(ctx, r.ConnectionID)
}
func (ctrl DalConnection) Undelete(ctx context.Context, r *request.DalConnectionUndelete) (interface{}, error) {
return api.OK(), ctrl.svc.UndeleteByID(ctx, r.ConnectionID)
}
func (ctrl DalConnection) makeFilterPayload(ctx context.Context, connections types.DalConnectionSet, f types.DalConnectionFilter) (out *connectionSetPayload, err error) {
out = &connectionSetPayload{
Filter: f,
Set: make([]*connectionPayload, 0, len(connections)),
}
for _, c := range connections {
out.Set = append(out.Set, ctrl.makePayload(ctx, c))
}
return
}
// Make payload for dal-connection
//
// # Payload is without connection params on the config prop
//
// An explicit call to /params
func (ctrl DalConnection) makePayload(ctx context.Context, c *types.DalConnection) *connectionPayload {
return &connectionPayload{
DalConnection: c,
CanGrant: ctrl.connectionAc.CanGrant(ctx),
CanUpdateConnection: ctrl.connectionAc.CanUpdateDalConnection(ctx, c),
CanDeleteConnection: ctrl.connectionAc.CanDeleteDalConnection(ctx, c),
CanManageDalConfig: ctrl.connectionAc.CanManageDalConfigOnDalConnection(ctx, c),
}
}
func (ctrl DalConnection) federatedNodeToConnection(f *federationTypes.Node) *types.DalConnection {
h, _ := handle.Cast(nil, f.Name)
return &types.DalConnection{
ID: f.ID,
Meta: types.ConnectionMeta{
Name: f.Name,
Ownership: f.Contact,
},
Handle: h,
Type: federationTypes.NodeResourceType,
//Config: types.ConnectionConfig{
// Connection: dal.NewFederatedNodeConnection(f.BaseURL, f.PairToken, f.AuthToken),
//},
CreatedAt: f.CreatedAt,
CreatedBy: f.CreatedBy,
UpdatedAt: f.UpdatedAt,
UpdatedBy: f.UpdatedBy,
DeletedAt: f.DeletedAt,
DeletedBy: f.DeletedBy,
}
}
func (ctrl DalConnection) collectConnections(ctx context.Context, filter types.DalConnectionFilter) (out types.DalConnectionSet, f types.DalConnectionFilter, err error) {
var (
dalConnections types.DalConnectionSet
federatedNodes federationTypes.NodeSet
)
if dalConnections, f, err = ctrl.svc.Search(ctx, filter); err != nil {
return nil, f, err
}
if !reflect2.IsNil(ctrl.federationSvc) {
if federatedNodes, _, err = ctrl.federationSvc.Search(ctx, federationTypes.NodeFilter{
// @todo IDs?
Deleted: f.Deleted,
}); err != nil {
return nil, f, err
}
}
out = append(out, dalConnections...)
// We're converting federation nodes to DAL connection structs so that we have
// a unified output.
//
// Eventually federation nodes will become connections, so this is ok
for _, nn := range federatedNodes {
out = append(out, ctrl.federatedNodeToConnection(nn))
}
out = ctrl.filterConnections(out, f)
return
}
func (ctrl DalConnection) filterConnections(baseConnections types.DalConnectionSet, f types.DalConnectionFilter) (out types.DalConnectionSet) {
for _, conn := range baseConnections {
include := true
if len(f.DalConnectionID) > 0 {
include = include && ctrl.inIDSet(id.Uints(f.DalConnectionID...), conn.ID)
}
if f.Handle != "" {
include = include && f.Handle == conn.Handle
}
if f.Type != "" {
include = include && f.Type == conn.Type
}
{
if f.Deleted == filter.StateExcluded {
include = include && conn.DeletedAt == nil
}
if f.Deleted == filter.StateExclusive {
include = include && conn.DeletedAt != nil
}
}
if include {
out = append(out, conn)
}
}
return
}
func (ctrl DalConnection) inIDSet(set []uint64, target uint64) (out bool) {
for _, id := range set {
out = out || id == target
}
return
}
func (ctrl DalConnection) serve(ctx context.Context, fn string, archive io.ReadSeeker, err error) (interface{}, error) {
if err != nil {
return nil, err
}
return func(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Content-Disposition", "attachment; filename="+fn)
http.ServeContent(w, req, fn, time.Now(), archive)
}, nil
}