Add route to list dal connections for privacy console
It will only list dal connections with minimal data.
This commit is contained in:
@@ -2268,3 +2268,31 @@ endpoints:
|
||||
post:
|
||||
- { name: comment, type: "string", title: "Comment description", required: true }
|
||||
|
||||
- title: Data Privacy
|
||||
entrypoint: dataPrivacy
|
||||
imports:
|
||||
- github.com/cortezaproject/corteza-server/pkg/filter
|
||||
path: "/data-privacy"
|
||||
apis:
|
||||
- name: connection list
|
||||
method: GET
|
||||
title: List connections for data privacy
|
||||
path: "/connection/"
|
||||
parameters:
|
||||
get:
|
||||
- name: connectionID
|
||||
type: "[]string"
|
||||
required: false
|
||||
title: Filter by connection ID
|
||||
- type: string
|
||||
name: handle
|
||||
required: false
|
||||
title: Search handle to match against connections
|
||||
- type: string
|
||||
name: type
|
||||
required: false
|
||||
title: Search type to match against connections
|
||||
- name: deleted
|
||||
required: false
|
||||
title: Exclude (0, default), include (1) or return only (2) deleted connections
|
||||
type: filter.State
|
||||
|
||||
63
system/rest/data_privacy.go
Normal file
63
system/rest/data_privacy.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/system/service"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
DataPrivacy struct {
|
||||
privacy service.DataPrivacyService
|
||||
ac privacyAccessController
|
||||
}
|
||||
|
||||
privacyAccessController interface {
|
||||
CanGrant(context.Context) bool
|
||||
}
|
||||
|
||||
privacyConnectionSetPayload struct {
|
||||
Filter types.DalConnectionFilter `json:"filter"`
|
||||
Set types.PrivacyDalConnectionSet `json:"set"`
|
||||
}
|
||||
)
|
||||
|
||||
func (DataPrivacy) New() *DataPrivacy {
|
||||
return &DataPrivacy{
|
||||
privacy: service.DefaultDataPrivacy,
|
||||
ac: service.DefaultAccessControl,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl DataPrivacy) ConnectionList(ctx context.Context, r *request.DataPrivacyConnectionList) (interface{}, error) {
|
||||
var (
|
||||
err error
|
||||
set types.PrivacyDalConnectionSet
|
||||
|
||||
f = types.DalConnectionFilter{
|
||||
ConnectionID: payload.ParseUint64s(r.ConnectionID),
|
||||
Handle: r.Handle,
|
||||
Type: r.Type,
|
||||
|
||||
Deleted: r.Deleted,
|
||||
}
|
||||
)
|
||||
|
||||
set, f, err = ctrl.privacy.FindConnections(ctx, f)
|
||||
return ctrl.makeFilterConnectionPayload(ctx, set, f, err)
|
||||
}
|
||||
|
||||
func (ctrl DataPrivacy) makeFilterConnectionPayload(_ context.Context, rr types.PrivacyDalConnectionSet, f types.DalConnectionFilter, err error) (*privacyConnectionSetPayload, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rr) == 0 {
|
||||
rr = make([]*types.PrivacyDalConnection, 0)
|
||||
}
|
||||
|
||||
return &privacyConnectionSetPayload{Filter: f, Set: rr}, nil
|
||||
}
|
||||
57
system/rest/handlers/dataPrivacy.go
Normal file
57
system/rest/handlers/dataPrivacy.go
Normal file
@@ -0,0 +1,57 @@
|
||||
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/cortezaproject/corteza-server/pkg/api"
|
||||
"github.com/cortezaproject/corteza-server/system/rest/request"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
DataPrivacyAPI interface {
|
||||
ConnectionList(context.Context, *request.DataPrivacyConnectionList) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
DataPrivacy struct {
|
||||
ConnectionList func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
)
|
||||
|
||||
func NewDataPrivacy(h DataPrivacyAPI) *DataPrivacy {
|
||||
return &DataPrivacy{
|
||||
ConnectionList: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewDataPrivacyConnectionList()
|
||||
if err := params.Fill(r); err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.ConnectionList(r.Context(), params)
|
||||
if err != nil {
|
||||
api.Send(w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
api.Send(w, r, value)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h DataPrivacy) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Get("/data-privacy/connection/", h.ConnectionList)
|
||||
})
|
||||
}
|
||||
134
system/rest/request/dataPrivacy.go
Normal file
134
system/rest/request/dataPrivacy.go
Normal file
@@ -0,0 +1,134 @@
|
||||
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/filter"
|
||||
"github.com/cortezaproject/corteza-server/pkg/payload"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dummy vars to prevent
|
||||
// unused imports complain
|
||||
var (
|
||||
_ = chi.URLParam
|
||||
_ = multipart.ErrMessageTooLarge
|
||||
_ = payload.ParseUint64s
|
||||
_ = strings.ToLower
|
||||
_ = io.EOF
|
||||
_ = fmt.Errorf
|
||||
_ = json.NewEncoder
|
||||
)
|
||||
|
||||
type (
|
||||
// Internal API interface
|
||||
DataPrivacyConnectionList struct {
|
||||
// ConnectionID GET parameter
|
||||
//
|
||||
// Filter by connection ID
|
||||
ConnectionID []string
|
||||
|
||||
// Handle GET parameter
|
||||
//
|
||||
// Search handle to match against connections
|
||||
Handle string
|
||||
|
||||
// Type GET parameter
|
||||
//
|
||||
// Search type to match against connections
|
||||
Type string
|
||||
|
||||
// Deleted GET parameter
|
||||
//
|
||||
// Exclude (0, default), include (1) or return only (2) deleted connections
|
||||
Deleted filter.State
|
||||
}
|
||||
)
|
||||
|
||||
// NewDataPrivacyConnectionList request
|
||||
func NewDataPrivacyConnectionList() *DataPrivacyConnectionList {
|
||||
return &DataPrivacyConnectionList{}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r DataPrivacyConnectionList) Auditable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"connectionID": r.ConnectionID,
|
||||
"handle": r.Handle,
|
||||
"type": r.Type,
|
||||
"deleted": r.Deleted,
|
||||
}
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r DataPrivacyConnectionList) GetConnectionID() []string {
|
||||
return r.ConnectionID
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r DataPrivacyConnectionList) GetHandle() string {
|
||||
return r.Handle
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r DataPrivacyConnectionList) GetType() string {
|
||||
return r.Type
|
||||
}
|
||||
|
||||
// Auditable returns all auditable/loggable parameters
|
||||
func (r DataPrivacyConnectionList) GetDeleted() filter.State {
|
||||
return r.Deleted
|
||||
}
|
||||
|
||||
// Fill processes request and fills internal variables
|
||||
func (r *DataPrivacyConnectionList) Fill(req *http.Request) (err error) {
|
||||
|
||||
{
|
||||
// GET params
|
||||
tmp := req.URL.Query()
|
||||
|
||||
if val, ok := tmp["connectionID[]"]; ok {
|
||||
r.ConnectionID, err = val, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if val, ok := tmp["connectionID"]; ok {
|
||||
r.ConnectionID, err = val, nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := tmp["handle"]; ok && len(val) > 0 {
|
||||
r.Handle, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := tmp["type"]; ok && len(val) > 0 {
|
||||
r.Type, err = val[0], nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := tmp["deleted"]; ok && len(val) > 0 {
|
||||
r.Deleted, err = payload.ParseFilterState(val[0]), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -47,6 +47,8 @@ func MountRoutes() func(r chi.Router) {
|
||||
handlers.NewApigwRoute(ApigwRoute{}.New()).MountRoutes(r)
|
||||
handlers.NewApigwFilter(ApigwFilter{}.New()).MountRoutes(r)
|
||||
handlers.NewApigwProfiler(ApigwProfiler{}.New()).MountRoutes(r)
|
||||
handlers.NewDataPrivacy(DataPrivacy{}.New()).MountRoutes(r)
|
||||
// @todo move these two to dataPrivacy routes
|
||||
handlers.NewDataPrivacyRequest(DataPrivacyRequest{}.New()).MountRoutes(r)
|
||||
handlers.NewDataPrivacyRequestComment(DataPrivacyRequestComment{}.New()).MountRoutes(r)
|
||||
})
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
type (
|
||||
dataPrivacy struct {
|
||||
actionlog actionlog.Recorder
|
||||
store store.Storer
|
||||
|
||||
ac dataPrivacyAccessController
|
||||
eventbus eventDispatcher
|
||||
|
||||
store store.Storer
|
||||
dalConn dalConnectionService
|
||||
}
|
||||
|
||||
dataPrivacyAccessController interface {
|
||||
@@ -25,9 +25,17 @@ type (
|
||||
CanCreateDataPrivacyRequest(context.Context) bool
|
||||
CanReadDataPrivacyRequest(context.Context, *types.DataPrivacyRequest) bool
|
||||
CanApproveDataPrivacyRequest(context.Context, *types.DataPrivacyRequest) bool
|
||||
|
||||
CanSearchDalConnections(context.Context) bool
|
||||
}
|
||||
|
||||
dalConnectionService interface {
|
||||
Search(ctx context.Context, filter types.DalConnectionFilter) (r types.DalConnectionSet, f types.DalConnectionFilter, err error)
|
||||
}
|
||||
|
||||
DataPrivacyService interface {
|
||||
FindConnections(ctx context.Context, filter types.DalConnectionFilter) (out types.PrivacyDalConnectionSet, f types.DalConnectionFilter, err error)
|
||||
|
||||
FindRequestByID(ctx context.Context, requestID uint64) (*types.DataPrivacyRequest, error)
|
||||
FindRequests(context.Context, types.DataPrivacyRequestFilter) (types.DataPrivacyRequestSet, types.DataPrivacyRequestFilter, error)
|
||||
CreateRequest(ctx context.Context, request *types.DataPrivacyRequest) (*types.DataPrivacyRequest, error)
|
||||
@@ -41,12 +49,55 @@ type (
|
||||
func DataPrivacy(s store.Storer, ac dataPrivacyAccessController, al actionlog.Recorder, eb eventDispatcher) *dataPrivacy {
|
||||
return &dataPrivacy{
|
||||
actionlog: al,
|
||||
store: s,
|
||||
ac: ac,
|
||||
eventbus: eb,
|
||||
store: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (svc dataPrivacy) FindConnections(ctx context.Context, filter types.DalConnectionFilter) (out types.PrivacyDalConnectionSet, f types.DalConnectionFilter, err error) {
|
||||
var (
|
||||
cc types.DalConnectionSet
|
||||
)
|
||||
err = func() error {
|
||||
if !svc.ac.CanSearchDalConnections(ctx) {
|
||||
return DalConnectionErrNotAllowedToSearch()
|
||||
}
|
||||
|
||||
cc, f, err = svc.dalConn.Search(ctx, filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cc.Walk(func(c *types.DalConnection) error {
|
||||
pc := types.PrivacyDalConnection{
|
||||
ID: c.ID,
|
||||
Name: c.Meta.Name,
|
||||
Handle: c.Handle,
|
||||
Type: c.Type,
|
||||
Location: c.Meta.Location,
|
||||
Ownership: c.Meta.Ownership,
|
||||
SensitivityLevel: c.Config.Privacy.SensitivityLevelID,
|
||||
CreatedAt: c.CreatedAt,
|
||||
CreatedBy: c.CreatedBy,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
UpdatedBy: c.UpdatedBy,
|
||||
DeletedAt: c.DeletedAt,
|
||||
DeletedBy: c.DeletedBy,
|
||||
}
|
||||
out = append(out, &pc)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (svc dataPrivacy) FindRequestByID(ctx context.Context, requestID uint64) (r *types.DataPrivacyRequest, err error) {
|
||||
var (
|
||||
raProps = &dataPrivacyActionProps{dataPrivacyRequest: &types.DataPrivacyRequest{ID: requestID}}
|
||||
|
||||
@@ -28,9 +28,9 @@ type (
|
||||
CreatedAt time.Time `json:"createdAt,omitempty"`
|
||||
CreatedBy uint64 `json:"createdBy,string" `
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
|
||||
UpdatedBy uint64 `json:"updatedBy,string,omitempty" `
|
||||
UpdatedBy uint64 `json:"updatedBy,string,omitempty"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty"`
|
||||
DeletedBy uint64 `json:"deletedBy,string,omitempty" `
|
||||
DeletedBy uint64 `json:"deletedBy,string,omitempty"`
|
||||
}
|
||||
|
||||
ConnectionConfig struct {
|
||||
|
||||
@@ -3,6 +3,7 @@ package types
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"github.com/cortezaproject/corteza-server/pkg/geolocation"
|
||||
"github.com/cortezaproject/corteza-server/pkg/sql"
|
||||
"time"
|
||||
|
||||
@@ -99,6 +100,25 @@ type (
|
||||
filter.Paging
|
||||
}
|
||||
|
||||
PrivacyDalConnection struct {
|
||||
ID uint64 `json:"connectionID,string"`
|
||||
Name string `json:"name"`
|
||||
Handle string `json:"handle"`
|
||||
|
||||
Type string `json:"type"`
|
||||
|
||||
Location geolocation.Full `json:"location"`
|
||||
Ownership string `json:"ownership"`
|
||||
SensitivityLevel uint64 `json:"sensitivityLevel,string,omitempty"`
|
||||
|
||||
CreatedAt time.Time `json:"createdAt,omitempty"`
|
||||
CreatedBy uint64 `json:"createdBy,string" `
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
|
||||
UpdatedBy uint64 `json:"updatedBy,string,omitempty" `
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty"`
|
||||
DeletedBy uint64 `json:"deletedBy,string,omitempty" `
|
||||
}
|
||||
|
||||
RequestStatus string
|
||||
RequestKind string
|
||||
)
|
||||
|
||||
61
system/types/type_set.gen.go
generated
61
system/types/type_set.gen.go
generated
@@ -85,6 +85,11 @@ type (
|
||||
// This type is auto-generated.
|
||||
DataPrivacyRequestCommentSet []*DataPrivacyRequestComment
|
||||
|
||||
// PrivacyDalConnectionSet slice of PrivacyDalConnection
|
||||
//
|
||||
// This type is auto-generated.
|
||||
PrivacyDalConnectionSet []*PrivacyDalConnection
|
||||
|
||||
// QueueSet slice of Queue
|
||||
//
|
||||
// This type is auto-generated.
|
||||
@@ -872,6 +877,62 @@ func (set DataPrivacyRequestCommentSet) IDs() (IDs []uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
// Walk iterates through every slice item and calls w(PrivacyDalConnection) err
|
||||
//
|
||||
// This function is auto-generated.
|
||||
func (set PrivacyDalConnectionSet) Walk(w func(*PrivacyDalConnection) error) (err error) {
|
||||
for i := range set {
|
||||
if err = w(set[i]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Filter iterates through every slice item, calls f(PrivacyDalConnection) (bool, err) and return filtered slice
|
||||
//
|
||||
// This function is auto-generated.
|
||||
func (set PrivacyDalConnectionSet) Filter(f func(*PrivacyDalConnection) (bool, error)) (out PrivacyDalConnectionSet, err error) {
|
||||
var ok bool
|
||||
out = PrivacyDalConnectionSet{}
|
||||
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 PrivacyDalConnectionSet) FindByID(ID uint64) *PrivacyDalConnection {
|
||||
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 PrivacyDalConnectionSet) IDs() (IDs []uint64) {
|
||||
IDs = make([]uint64, len(set))
|
||||
|
||||
for i := range set {
|
||||
IDs[i] = set[i].ID
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Walk iterates through every slice item and calls w(Queue) err
|
||||
//
|
||||
// This function is auto-generated.
|
||||
|
||||
90
system/types/type_set.gen_test.go
generated
90
system/types/type_set.gen_test.go
generated
@@ -1228,6 +1228,96 @@ func TestDataPrivacyRequestCommentSetIDs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivacyDalConnectionSetWalk(t *testing.T) {
|
||||
var (
|
||||
value = make(PrivacyDalConnectionSet, 3)
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
// check walk with no errors
|
||||
{
|
||||
err := value.Walk(func(*PrivacyDalConnection) error {
|
||||
return nil
|
||||
})
|
||||
req.NoError(err)
|
||||
}
|
||||
|
||||
// check walk with error
|
||||
req.Error(value.Walk(func(*PrivacyDalConnection) error { return fmt.Errorf("walk error") }))
|
||||
}
|
||||
|
||||
func TestPrivacyDalConnectionSetFilter(t *testing.T) {
|
||||
var (
|
||||
value = make(PrivacyDalConnectionSet, 3)
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
// filter nothing
|
||||
{
|
||||
set, err := value.Filter(func(*PrivacyDalConnection) (bool, error) {
|
||||
return true, nil
|
||||
})
|
||||
req.NoError(err)
|
||||
req.Equal(len(set), len(value))
|
||||
}
|
||||
|
||||
// filter one item
|
||||
{
|
||||
found := false
|
||||
set, err := value.Filter(func(*PrivacyDalConnection) (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(*PrivacyDalConnection) (bool, error) {
|
||||
return false, fmt.Errorf("filter error")
|
||||
})
|
||||
req.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivacyDalConnectionSetIDs(t *testing.T) {
|
||||
var (
|
||||
value = make(PrivacyDalConnectionSet, 3)
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
// construct objects
|
||||
value[0] = new(PrivacyDalConnection)
|
||||
value[1] = new(PrivacyDalConnection)
|
||||
value[2] = new(PrivacyDalConnection)
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueSetWalk(t *testing.T) {
|
||||
var (
|
||||
value = make(QueueSet, 3)
|
||||
|
||||
@@ -37,3 +37,4 @@ types:
|
||||
noIdField: true
|
||||
DataPrivacyRequest: {}
|
||||
DataPrivacyRequestComment: {}
|
||||
PrivacyDalConnection:
|
||||
|
||||
Reference in New Issue
Block a user