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
297 lines
8.2 KiB
Go
297 lines
8.2 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"github.com/cortezaproject/corteza/server/pkg/actionlog"
|
|
a "github.com/cortezaproject/corteza/server/pkg/auth"
|
|
"github.com/cortezaproject/corteza/server/pkg/errors"
|
|
"github.com/cortezaproject/corteza/server/store"
|
|
"github.com/cortezaproject/corteza/server/system/service/event"
|
|
"github.com/cortezaproject/corteza/server/system/types"
|
|
)
|
|
|
|
type (
|
|
dataPrivacy struct {
|
|
actionlog actionlog.Recorder
|
|
store store.Storer
|
|
|
|
ac dataPrivacyAccessController
|
|
eventbus eventDispatcher
|
|
dalConn dalConnectionService
|
|
}
|
|
|
|
dataPrivacyAccessController interface {
|
|
CanSearchDataPrivacyRequests(context.Context) bool
|
|
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)
|
|
UpdateRequestStatus(ctx context.Context, request *types.DataPrivacyRequest) (*types.DataPrivacyRequest, error)
|
|
|
|
FindRequestComments(ctx context.Context, filter types.DataPrivacyRequestCommentFilter) (rr types.DataPrivacyRequestCommentSet, f types.DataPrivacyRequestCommentFilter, err error)
|
|
CreateRequestComment(ctx context.Context, new *types.DataPrivacyRequestComment) (r *types.DataPrivacyRequestComment, err error)
|
|
}
|
|
)
|
|
|
|
func DataPrivacy(s store.Storer, ac dataPrivacyAccessController, al actionlog.Recorder, eb eventDispatcher) *dataPrivacy {
|
|
return &dataPrivacy{
|
|
actionlog: al,
|
|
store: s,
|
|
ac: ac,
|
|
eventbus: eb,
|
|
dalConn: DefaultDalConnection,
|
|
}
|
|
}
|
|
|
|
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 cc, f, err = store.SearchDalConnections(ctx, svc.store, filter); err != nil {
|
|
return err
|
|
}
|
|
|
|
err = cc.Walk(func(c *types.DalConnection) error {
|
|
pc := types.PrivacyDalConnection{
|
|
ID: c.ID,
|
|
Handle: c.Handle,
|
|
Type: c.Type,
|
|
Meta: types.PrivacyDalConnectionMeta{
|
|
Name: c.Meta.Name,
|
|
Ownership: c.Meta.Ownership,
|
|
Location: c.Meta.Location,
|
|
},
|
|
Config: types.PrivacyDalConnectionConfig{
|
|
Privacy: c.Config.Privacy,
|
|
},
|
|
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}}
|
|
)
|
|
|
|
err = func() error {
|
|
r, err = loadDataPrivacyRequest(ctx, svc.store, requestID)
|
|
if r, err = svc.procRequest(ctx, r, err); err != nil {
|
|
return err
|
|
}
|
|
|
|
raProps.setDataPrivacyRequest(r)
|
|
|
|
if !svc.ac.CanReadDataPrivacyRequest(ctx, r) {
|
|
return DataPrivacyErrNotAllowedToRead()
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
return r, svc.recordAction(ctx, raProps, DataPrivacyActionLookup, err)
|
|
}
|
|
|
|
func (svc dataPrivacy) procRequest(_ context.Context, r *types.DataPrivacyRequest, err error) (*types.DataPrivacyRequest, error) {
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
return nil, DataPrivacyErrNotFound()
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return r, nil
|
|
}
|
|
|
|
func (svc dataPrivacy) FindRequests(ctx context.Context, filter types.DataPrivacyRequestFilter) (rr types.DataPrivacyRequestSet, f types.DataPrivacyRequestFilter, err error) {
|
|
var (
|
|
raProps = &dataPrivacyActionProps{filter: &filter}
|
|
)
|
|
|
|
// For each fetched item, store backend will check if it is valid or not
|
|
filter.Check = func(req *types.DataPrivacyRequest) (bool, error) {
|
|
if !svc.ac.CanReadDataPrivacyRequest(ctx, req) {
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
err = func() error {
|
|
if !svc.ac.CanSearchDataPrivacyRequests(ctx) {
|
|
return DataPrivacyErrNotAllowedToSearch()
|
|
}
|
|
|
|
if rr, f, err = store.SearchDataPrivacyRequests(ctx, svc.store, filter); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
return rr, f, svc.recordAction(ctx, raProps, DataPrivacyActionSearch, err)
|
|
}
|
|
|
|
func (svc dataPrivacy) CreateRequest(ctx context.Context, new *types.DataPrivacyRequest) (r *types.DataPrivacyRequest, err error) {
|
|
var (
|
|
raProps = &dataPrivacyActionProps{new: new}
|
|
)
|
|
|
|
err = func() (err error) {
|
|
if len(new.Kind.String()) == 0 {
|
|
return DataPrivacyErrInvalidKind()
|
|
}
|
|
|
|
if !svc.ac.CanCreateDataPrivacyRequest(ctx) {
|
|
return DataPrivacyErrNotAllowedToCreate()
|
|
}
|
|
|
|
if err = svc.eventbus.WaitFor(ctx, event.DataPrivacyRequestBeforeCreate(new, r)); err != nil {
|
|
return
|
|
}
|
|
|
|
new.ID = nextID()
|
|
new.Status = types.RequestStatusPending
|
|
new.RequestedAt = *now()
|
|
new.RequestedBy = a.GetIdentityFromContext(ctx).Identity()
|
|
new.CreatedAt = *now()
|
|
|
|
if err = store.CreateDataPrivacyRequest(ctx, svc.store, new); err != nil {
|
|
return
|
|
}
|
|
|
|
r = new
|
|
|
|
svc.eventbus.Dispatch(ctx, event.DataPrivacyRequestAfterCreate(new, r))
|
|
return
|
|
}()
|
|
|
|
return r, svc.recordAction(ctx, raProps, DataPrivacyActionCreate, err)
|
|
}
|
|
|
|
func (svc dataPrivacy) UpdateRequestStatus(ctx context.Context, upd *types.DataPrivacyRequest) (r *types.DataPrivacyRequest, err error) {
|
|
var (
|
|
raProps = &dataPrivacyActionProps{update: upd}
|
|
)
|
|
|
|
err = func() (err error) {
|
|
if len(upd.Status.String()) == 0 {
|
|
return DataPrivacyErrInvalidStatus()
|
|
}
|
|
|
|
if upd.Status == types.RequestStatusPending {
|
|
return DataPrivacyErrInvalidStatus()
|
|
}
|
|
|
|
if upd.Status == types.RequestStatusApproved || upd.Status == types.RequestStatusRejected {
|
|
if !svc.ac.CanApproveDataPrivacyRequest(ctx, upd) {
|
|
return DataPrivacyErrNotAllowedToApprove()
|
|
}
|
|
}
|
|
|
|
if r, err = loadDataPrivacyRequest(ctx, svc.store, upd.ID); err != nil {
|
|
return
|
|
}
|
|
|
|
raProps.setDataPrivacyRequest(r)
|
|
|
|
if err = svc.eventbus.WaitFor(ctx, event.DataPrivacyRequestBeforeUpdate(upd, r)); err != nil {
|
|
return
|
|
}
|
|
|
|
r.Status = upd.Status
|
|
r.CompletedAt = now()
|
|
r.CompletedBy = a.GetIdentityFromContext(ctx).Identity()
|
|
r.UpdatedAt = now()
|
|
|
|
// Assign changed values
|
|
if err = store.UpdateDataPrivacyRequest(ctx, svc.store, r); err != nil {
|
|
return err
|
|
}
|
|
|
|
svc.eventbus.Dispatch(ctx, event.DataPrivacyRequestAfterUpdate(upd, r))
|
|
|
|
return nil
|
|
}()
|
|
|
|
return r, svc.recordAction(ctx, raProps, DataPrivacyActionApprove, err)
|
|
}
|
|
|
|
func (svc dataPrivacy) FindRequestComments(ctx context.Context, filter types.DataPrivacyRequestCommentFilter) (rr types.DataPrivacyRequestCommentSet, f types.DataPrivacyRequestCommentFilter, err error) {
|
|
err = func() error {
|
|
if rr, f, err = store.SearchDataPrivacyRequestComments(ctx, svc.store, filter); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
return rr, f, err
|
|
}
|
|
|
|
func (svc dataPrivacy) CreateRequestComment(ctx context.Context, new *types.DataPrivacyRequestComment) (r *types.DataPrivacyRequestComment, err error) {
|
|
err = func() (err error) {
|
|
|
|
_, err = svc.FindRequestByID(ctx, new.RequestID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
new.ID = nextID()
|
|
new.CreatedBy = a.GetIdentityFromContext(ctx).Identity()
|
|
new.CreatedAt = *now()
|
|
|
|
if err = store.CreateDataPrivacyRequestComment(ctx, svc.store, new); err != nil {
|
|
return
|
|
}
|
|
|
|
r = new
|
|
|
|
return
|
|
}()
|
|
|
|
return r, err
|
|
}
|
|
|
|
func loadDataPrivacyRequest(ctx context.Context, s store.DataPrivacyRequests, ID uint64) (res *types.DataPrivacyRequest, err error) {
|
|
if ID == 0 {
|
|
return nil, DataPrivacyErrInvalidID()
|
|
}
|
|
|
|
if res, err = store.LookupDataPrivacyRequestByID(ctx, s, ID); errors.IsNotFound(err) {
|
|
return nil, DataPrivacyErrNotFound()
|
|
}
|
|
|
|
return
|
|
}
|