From 7201cabb438abce7855ac51782fd625869252024 Mon Sep 17 00:00:00 2001 From: mr Date: Wed, 5 Feb 2025 16:41:16 +0100 Subject: [PATCH] workflow partial allows --- models/utils/common.go | 11 +++++ models/workflow/graph/graph.go | 26 +++++++++-- models/workflow/graph/item.go | 8 ++++ models/workflow/workflow_mongo_accessor.go | 50 +++++++++++++++++++--- 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/models/utils/common.go b/models/utils/common.go index 1637078..d3a1703 100644 --- a/models/utils/common.go +++ b/models/utils/common.go @@ -13,6 +13,17 @@ type Owner struct { Logo string `json:"logo,omitempty" bson:"logo,omitempty"` } +func VerifyAccess(a Accessor, id string) error { + data, _, err := a.LoadOne(id) + if err != nil { + return err + } + if a.ShouldVerifyAuth() && !data.VerifyAuth(a.GetRequest()) { + return errors.New("you are not allowed to access :" + a.GetType().String()) + } + return nil +} + // GenericLoadOne loads one object from the database (generic) func GenericStoreOne(data DBObject, a Accessor) (DBObject, int, error) { data.GenerateID() diff --git a/models/workflow/graph/graph.go b/models/workflow/graph/graph.go index 9fad899..991d321 100644 --- a/models/workflow/graph/graph.go +++ b/models/workflow/graph/graph.go @@ -9,9 +9,29 @@ import ( // Graph is a struct that represents a graph type Graph struct { - Zoom float64 `bson:"zoom" json:"zoom" default:"1"` // Zoom is the graphical zoom of the graph - Items map[string]GraphItem `bson:"items" json:"items" default:"{}" validate:"required"` // Items is the list of elements in the graph - Links []GraphLink `bson:"links" json:"links" default:"{}" validate:"required"` // Links is the list of links between elements in the graph + Partial bool `json:"partial" default:"false"` // Partial is a flag that indicates if the graph is partial + Zoom float64 `bson:"zoom" json:"zoom" default:"1"` // Zoom is the graphical zoom of the graph + Items map[string]GraphItem `bson:"items" json:"items" default:"{}" validate:"required"` // Items is the list of elements in the graph + Links []GraphLink `bson:"links" json:"links" default:"{}" validate:"required"` // Links is the list of links between elements in the graph +} + +func (g *Graph) Clear(id string) { + realItems := map[string]GraphItem{} + for k, it := range g.Items { + if k == id { + realinks := []GraphLink{} + for _, link := range g.Links { + if link.Source.ID != id && link.Destination.ID != id { + realinks = append(realinks, link) + } + } + g.Links = realinks + g.Partial = true + } else { + realItems[k] = it + } + } + g.Items = realItems } func (wf *Graph) IsProcessing(item GraphItem) bool { diff --git a/models/workflow/graph/item.go b/models/workflow/graph/item.go index 7519f23..5e92ef6 100644 --- a/models/workflow/graph/item.go +++ b/models/workflow/graph/item.go @@ -28,3 +28,11 @@ func (g *GraphItem) GetResource() (tools.DataType, resources.ResourceInterface) } return tools.INVALID, nil } + +func (g *GraphItem) Clear() { + g.Data = nil + g.Compute = nil + g.Workflow = nil + g.Processing = nil + g.Storage = nil +} diff --git a/models/workflow/workflow_mongo_accessor.go b/models/workflow/workflow_mongo_accessor.go index 428808f..451d5df 100644 --- a/models/workflow/workflow_mongo_accessor.go +++ b/models/workflow/workflow_mongo_accessor.go @@ -1,6 +1,8 @@ package workflow import ( + "errors" + "cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/logs" "cloud.o-forge.io/core/oc-lib/models/collaborative_area/shallow_collaborative_area" @@ -47,7 +49,7 @@ func (a *workflowMongoAccessor) DeleteOne(id string) (utils.DBObject, int, error a.execute(res.(*Workflow), true, false) // up to date the workspace for the workflow a.share(res.(*Workflow), true, a.GetCaller()) } - return res, code, err + return a.verifyResource(res), code, err } /* @@ -89,7 +91,11 @@ func (a *workflowMongoAccessor) share(realData *Workflow, delete bool, caller *t // UpdateOne updates a workflow in the database func (a *workflowMongoAccessor) UpdateOne(set utils.DBObject, id string) (utils.DBObject, int, error) { // avoid the update if the schedule is the same - res, code, err := utils.GenericUpdateOne(set, id, a, &Workflow{}) + set = a.verifyResource(set) + if set.(*Workflow).Graph.Partial { + return nil, 403, errors.New("you are not allowed to update a partial workflow") + } + res, code, err := utils.GenericUpdateOne(a.verifyResource(set), id, a, &Workflow{}) if code != 200 { return nil, code, err } @@ -101,7 +107,11 @@ func (a *workflowMongoAccessor) UpdateOne(set utils.DBObject, id string) (utils. // StoreOne stores a workflow in the database func (a *workflowMongoAccessor) StoreOne(data utils.DBObject) (utils.DBObject, int, error) { + data = a.verifyResource(data) d := data.(*Workflow) + if d.Graph.Partial { + return nil, 403, errors.New("you are not allowed to update a partial workflow") + } res, code, err := utils.GenericStoreOne(d, a) if err != nil || code != 200 { return nil, code, err @@ -121,7 +131,6 @@ func (a *workflowMongoAccessor) CopyOne(data utils.DBObject) (utils.DBObject, in // execute is a function that executes a workflow // it stores the workflow resources in a specific workspace to never have a conflict in UI and logic func (a *workflowMongoAccessor) execute(workflow *Workflow, delete bool, active bool) { - filters := &dbs.Filters{ Or: map[string][]dbs.Filter{ // filter by standard workspace name attached to a workflow "abstractobject.name": {{Operator: dbs.LIKE.String(), Value: workflow.Name + "_workspace"}}, @@ -164,7 +173,7 @@ func (a *workflowMongoAccessor) LoadOne(id string) (utils.DBObject, int, error) return utils.GenericLoadOne[*Workflow](id, func(d utils.DBObject) (utils.DBObject, int, error) { w := d.(*Workflow) a.execute(w, false, true) // if no workspace is attached to the workflow, create it - return d, 200, nil + return a.verifyResource(d), 200, nil }, a) } @@ -173,5 +182,36 @@ func (a *workflowMongoAccessor) LoadAll(isDraft bool) ([]utils.ShallowDBObject, } func (a *workflowMongoAccessor) Search(filters *dbs.Filters, search string, isDraft bool) ([]utils.ShallowDBObject, int, error) { - return utils.GenericSearch[*Workflow](filters, search, (&Workflow{}).GetObjectFilters(search), func(d utils.DBObject) utils.ShallowDBObject { return d }, isDraft, a) + return utils.GenericSearch[*Workflow](filters, search, (&Workflow{}).GetObjectFilters(search), func(d utils.DBObject) utils.ShallowDBObject { return a.verifyResource(d) }, isDraft, a) +} + +func (a *workflowMongoAccessor) verifyResource(obj utils.DBObject) utils.DBObject { + wf := obj.(*Workflow) + if wf.Graph == nil { + return nil + } + for _, item := range wf.Graph.Items { + t, resource := item.GetResource() + if resource == nil { + continue + } + var access utils.Accessor + if t == tools.COMPUTE_RESOURCE { + access = resources.NewAccessor[*resources.ComputeResource](t, a.GetRequest(), func() utils.DBObject { return &resources.ComputeResource{} }) + } else if t == tools.PROCESSING_RESOURCE { + access = resources.NewAccessor[*resources.ProcessingResource](t, a.GetRequest(), func() utils.DBObject { return &resources.ProcessingResource{} }) + } else if t == tools.STORAGE_RESOURCE { + access = resources.NewAccessor[*resources.StorageResource](t, a.GetRequest(), func() utils.DBObject { return &resources.StorageResource{} }) + } else if t == tools.WORKFLOW_RESOURCE { + access = resources.NewAccessor[*resources.WorkflowResource](t, a.GetRequest(), func() utils.DBObject { return &resources.WorkflowResource{} }) + } else if t == tools.DATA_RESOURCE { + access = resources.NewAccessor[*resources.DataResource](t, a.GetRequest(), func() utils.DBObject { return &resources.DataResource{} }) + } else { + wf.Graph.Clear(item.Data.GetID()) + } + if error := utils.VerifyAccess(access, resource.GetID()); error != nil { + wf.Graph.Clear(item.Data.GetID()) + } + } + return wf }