Files
upstream-corteza/server/system/service/apigw_route.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

275 lines
6.4 KiB
Go

package service
import (
"context"
"github.com/cortezaproject/corteza/server/pkg/actionlog"
"github.com/cortezaproject/corteza/server/pkg/apigw"
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/types"
)
type (
apigwRoute struct {
actionlog actionlog.Recorder
store store.Storer
ac routeAccessController
}
routeAccessController interface {
CanGrant(context.Context) bool
CanSearchApigwRoutes(ctx context.Context) bool
CanCreateApigwRoute(context.Context) bool
CanReadApigwRoute(context.Context, *types.ApigwRoute) bool
CanUpdateApigwRoute(context.Context, *types.ApigwRoute) bool
CanDeleteApigwRoute(context.Context, *types.ApigwRoute) bool
}
)
func Route() *apigwRoute {
return &apigwRoute{
ac: DefaultAccessControl,
actionlog: DefaultActionlog,
store: DefaultStore,
}
}
func (svc *apigwRoute) FindByID(ctx context.Context, ID uint64) (q *types.ApigwRoute, err error) {
var (
rProps = &apigwRouteActionProps{}
)
err = func() error {
if q, err = loadApigwRoute(ctx, svc.store, ID); err != nil {
return ApigwRouteErrInvalidID().Wrap(err)
}
rProps.setRoute(q)
if !svc.ac.CanReadApigwRoute(ctx, q) {
return ApigwRouteErrNotAllowedToRead(rProps)
}
return nil
}()
return q, svc.recordAction(ctx, rProps, ApigwRouteActionLookup, err)
}
func (svc *apigwRoute) Create(ctx context.Context, new *types.ApigwRoute) (q *types.ApigwRoute, err error) {
var (
qProps = &apigwRouteActionProps{route: new}
)
err = func() (err error) {
if !svc.ac.CanCreateApigwRoute(ctx) {
return ApigwRouteErrNotAllowedToCreate(qProps)
}
new.ID = nextID()
new.CreatedAt = *now()
new.CreatedBy = a.GetIdentityFromContext(ctx).Identity()
// todo
new.Group = 0
qProps.setNew(new)
if err = store.CreateApigwRoute(ctx, svc.store, new); err != nil {
return err
}
q = new
// send the signal to reload new route
if new.Enabled {
if err = apigw.Service().ReloadEndpoint(ctx, new.Method, new.Endpoint); err != nil {
return err
}
}
return nil
}()
return q, svc.recordAction(ctx, qProps, ApigwRouteActionCreate, err)
}
func (svc *apigwRoute) Update(ctx context.Context, upd *types.ApigwRoute) (res *types.ApigwRoute, err error) {
var (
qProps = &apigwRouteActionProps{update: upd}
e error
)
err = func() (err error) {
if res, e = loadApigwRoute(ctx, svc.store, upd.ID); e != nil {
return ApigwRouteErrNotFound(qProps)
}
var (
// check if old endpoint moved and attach the 404 handler
endpointMoved = res.Enabled != upd.Enabled || res.Method != upd.Method || res.Endpoint != upd.Endpoint
)
if !svc.ac.CanUpdateApigwRoute(ctx, res) {
return ApigwRouteErrNotAllowedToUpdate(qProps)
}
// Test if stale (update has an older version of data)
if isStale(upd.UpdatedAt, res.UpdatedAt, res.CreatedAt) {
return ApigwRouteErrStaleData()
}
// copy (potentially) updated files from the payload
res.Meta = upd.Meta
res.Method = upd.Method
res.Endpoint = upd.Endpoint
res.Enabled = upd.Enabled
res.Group = upd.Group
// ensure we have a valid endpoint
res.UpdatedAt = now()
res.UpdatedBy = a.GetIdentityFromContext(ctx).Identity()
if err = store.UpdateApigwRoute(ctx, svc.store, res); err != nil {
return
}
// @todo move this into struct of the service (svc),
// same as we do for services for other structs
ags := apigw.Service()
// old endpoint moved: attach 404 handler
if endpointMoved {
ags.NotFound(ctx, res.Method, res.Endpoint)
}
// send the signal to reload updated route
if upd.Enabled {
if err = ags.ReloadEndpoint(ctx, upd.Method, upd.Endpoint); err != nil {
return err
}
}
return nil
}()
return res, svc.recordAction(ctx, qProps, ApigwRouteActionUpdate, err)
}
func (svc *apigwRoute) DeleteByID(ctx context.Context, ID uint64) (err error) {
var (
qProps = &apigwRouteActionProps{}
q *types.ApigwRoute
)
err = func() (err error) {
if q, err = loadApigwRoute(ctx, svc.store, ID); err != nil {
return
}
if !svc.ac.CanDeleteApigwRoute(ctx, q) {
return ApigwRouteErrNotAllowedToDelete(qProps)
}
qProps.setRoute(q)
q.DeletedAt = now()
q.DeletedBy = a.GetIdentityFromContext(ctx).Identity()
if err = store.UpdateApigwRoute(ctx, svc.store, q); err != nil {
return
}
// send the signal to reload deleted route
if q.Enabled {
apigw.Service().NotFound(ctx, q.Method, q.Endpoint)
}
return nil
}()
return svc.recordAction(ctx, qProps, ApigwRouteActionDelete, err)
}
func (svc *apigwRoute) UndeleteByID(ctx context.Context, ID uint64) (err error) {
var (
qProps = &apigwRouteActionProps{}
q *types.ApigwRoute
)
err = func() (err error) {
if q, err = loadApigwRoute(ctx, svc.store, ID); err != nil {
return
}
if !svc.ac.CanDeleteApigwRoute(ctx, q) {
return ApigwRouteErrNotAllowedToUndelete(qProps)
}
qProps.setRoute(q)
q.DeletedAt = nil
q.UpdatedBy = a.GetIdentityFromContext(ctx).Identity()
if err = store.UpdateApigwRoute(ctx, svc.store, q); err != nil {
return
}
// send the signal to reload all queues
if q.Enabled {
if err = apigw.Service().ReloadEndpoint(ctx, q.Method, q.Endpoint); err != nil {
return err
}
}
return nil
}()
return svc.recordAction(ctx, qProps, ApigwRouteActionDelete, err)
}
func (svc *apigwRoute) Search(ctx context.Context, filter types.ApigwRouteFilter) (r types.ApigwRouteSet, f types.ApigwRouteFilter, err error) {
var (
aProps = &apigwRouteActionProps{search: &filter}
)
// For each fetched item, store backend will check if it is valid or not
filter.Check = func(res *types.ApigwRoute) (bool, error) {
if !svc.ac.CanReadApigwRoute(ctx, res) {
return false, nil
}
return true, nil
}
err = func() error {
if !svc.ac.CanSearchApigwRoutes(ctx) {
return ApigwRouteErrNotAllowedToSearch()
}
if r, f, err = store.SearchApigwRoutes(ctx, svc.store, filter); err != nil {
return err
}
return nil
}()
return r, f, svc.recordAction(ctx, aProps, ApigwRouteActionSearch, err)
}
func loadApigwRoute(ctx context.Context, s store.ApigwRoutes, ID uint64) (res *types.ApigwRoute, err error) {
if ID == 0 {
return nil, ApigwRouteErrInvalidID()
}
if res, err = store.LookupApigwRouteByID(ctx, s, ID); errors.IsNotFound(err) {
return nil, ApigwRouteErrNotFound()
}
return
}