From 18a3d696230de521aec2447747078a35be5c3a31 Mon Sep 17 00:00:00 2001 From: frikky Date: Sat, 3 Apr 2021 20:06:56 +0200 Subject: [PATCH] Started migration according to #324 --- backend/go-app/main.go | 103 ++++++++++++++++++++----- backend/go-app/walkoff.go | 16 ++-- frontend/src/views/Admin.jsx | 6 +- frontend/src/views/AngularWorkflow.jsx | 76 +++++++++++++++++- functions/onprem/worker/worker.go | 17 +++- 5 files changed, 180 insertions(+), 38 deletions(-) diff --git a/backend/go-app/main.go b/backend/go-app/main.go index d2110f56..0b2b47cd 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -842,7 +842,7 @@ func handleSetEnvironments(resp http.ResponseWriter, request *http.Request) { resp.Write([]byte(`{"success": true}`)) } -func createNewUser(username, password, role, apikey string, org shuffle.Org) error { +func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) error { // Returns false if there is an issue // Use this for register err := shuffle.CheckPasswordStrength(password) @@ -893,7 +893,10 @@ func createNewUser(username, password, role, apikey string, org shuffle.Org) err newUser.Roles = []string{"user"} } - newUser.ActiveOrg = org + newUser.ActiveOrg = shuffle.OrgMini{ + Id: org.Id, + Name: org.Name, + } if len(apikey) > 0 { newUser.ApiKey = apikey @@ -1000,7 +1003,10 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) { _, err = dbclient.GetAll(ctx, q, &orgs) if err == nil && len(orgs) == 1 { log.Printf("No org exists in auth. Setting to default (first one)") - currentOrg = orgs[0] + currentOrg = shuffle.OrgMini{ + Id: orgs[0].Id, + Name: orgs[0].Name, + } } } @@ -1274,7 +1280,11 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { } if len(newOrgs) > 0 { - userInfo.ActiveOrg = newOrgs[0] + userInfo.ActiveOrg = shuffle.OrgMini{ + Id: newOrgs[0].Id, + Name: newOrgs[0].Name, + } + userInfo.Orgs = newStringOrgs err = shuffle.SetUser(ctx, &userInfo) @@ -1291,7 +1301,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { } else { // 1. Check if the org exists by ID // 2. if it does, overwrite user - userInfo.ActiveOrg = shuffle.Org{ + userInfo.ActiveOrg = shuffle.OrgMini{ Id: userInfo.Orgs[0], } err = shuffle.SetUser(ctx, &userInfo) @@ -1304,12 +1314,15 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { // FIXME: Remove this dependency by updating users' orgs when org itself is updated org, err := shuffle.GetOrg(ctx, userInfo.ActiveOrg.Id) if err == nil { - userInfo.ActiveOrg = *org - userInfo.ActiveOrg.Users = []shuffle.User{} + userInfo.ActiveOrg = shuffle.OrgMini{ + Id: org.Id, + Name: org.Name, + } + + userInfo.ActiveOrg.Users = []shuffle.UserMini{} } - userInfo.ActiveOrg.Users = []shuffle.User{} - userInfo.ActiveOrg.SyncConfig = shuffle.SyncConfig{} + userInfo.ActiveOrg.Users = []shuffle.UserMini{} currentOrg, err := json.Marshal(userInfo.ActiveOrg) if err != nil { currentOrg = []byte("{}") @@ -4988,6 +5001,39 @@ func runInit(ctx context.Context) { } } else { log.Printf("There are %d org(s).", len(activeOrgs)) + + if len(activeOrgs) == 1 { + if len(activeOrgs[0].Users) == 0 { + log.Printf("ORG doesn't have any users??") + + q := datastore.NewQuery("Users") + var users []shuffle.User + _, err = dbclient.GetAll(ctx, q, &users) + if err != nil && len(users) == 0 { + log.Printf("Failed getting users in org fix") + } else { + // Remapping everyone to admin. This should never happen. + + for _, user := range users { + user.ActiveOrg = shuffle.OrgMini{ + Id: activeOrgs[0].Id, + Name: activeOrgs[0].Name, + Role: "admin", + } + + activeOrgs[0].Users = append(activeOrgs[0].Users, user) + } + + err = shuffle.SetOrg(ctx, activeOrgs[0], activeOrgs[0].Id) + if err != nil { + log.Printf("Failed setting org: %s", err) + } else { + log.Printf("Successfully updated org to have users!") + } + } + + } + } } } @@ -5004,7 +5050,7 @@ func runInit(ctx context.Context) { newUser := shuffle.User{ Username: user.Username, Id: user.Id, - ActiveOrg: shuffle.Org{ + ActiveOrg: shuffle.OrgMini{ Id: activeOrg.Id, }, Orgs: []string{activeOrg.Id}, @@ -5050,7 +5096,7 @@ func runInit(ctx context.Context) { q := datastore.NewQuery("Users").Filter("active =", true) var activeusers []shuffle.User _, err = dbclient.GetAll(ctx, q, &activeusers) - if err != nil { + if err != nil && len(activeusers) == 0 { log.Printf("Error getting users during init: %s", err) } else { q := datastore.NewQuery("Users") @@ -5074,9 +5120,9 @@ func runInit(ctx context.Context) { if len(user.Orgs) == 0 { defaultName := "default" user.Orgs = []string{defaultName} - user.ActiveOrg = shuffle.Org{ + user.ActiveOrg = shuffle.OrgMini{ Name: defaultName, - Role: "user", + Role: "admin", } } @@ -5101,9 +5147,10 @@ func runInit(ctx context.Context) { } else { apikey := os.Getenv("SHUFFLE_DEFAULT_APIKEY") - tmpOrg := shuffle.Org{ + tmpOrg := shuffle.OrgMini{ Name: "default", } + err = createNewUser(username, password, "admin", apikey, tmpOrg) if err != nil { log.Printf("Failed to create default user %s: %s", username, err) @@ -5123,7 +5170,11 @@ func runInit(ctx context.Context) { if len(activeOrgs) == 1 && len(users) > 0 { for _, user := range users { if user.ActiveOrg.Id == "" && len(user.Username) > 0 { - user.ActiveOrg = activeOrgs[0] + user.ActiveOrg = shuffle.OrgMini{ + Id: activeOrgs[0].Id, + Name: activeOrgs[0].Name, + } + err = shuffle.SetUser(ctx, &user) if err != nil { log.Printf("Failed updating user %s with org", user.Username) @@ -5178,7 +5229,7 @@ func runInit(ctx context.Context) { q := datastore.NewQuery("workflow").Limit(35) var workflows []shuffle.Workflow _, err = dbclient.GetAll(ctx, q, &workflows) - if err != nil { + if err != nil && len(workflows) == 0 { log.Printf("Error getting workflows in runinit: %s", err) } else { updated := 0 @@ -5187,7 +5238,11 @@ func runInit(ctx context.Context) { setLocal := false if workflow.ExecutingOrg.Id == "" || len(workflow.OrgId) == 0 { workflow.OrgId = activeOrgs[0].Id - workflow.ExecutingOrg = activeOrgs[0] + workflow.ExecutingOrg = shuffle.OrgMini{ + Id: activeOrgs[0].Id, + Name: activeOrgs[0].Name, + } + setLocal = true } else if workflow.Edited == 0 { workflow.Edited = timeNow @@ -5475,7 +5530,7 @@ func runInit(ctx context.Context) { q := datastore.NewQuery("workflow").Limit(35) var workflows []shuffle.Workflow _, err = dbclient.GetAll(ctx, q, &workflows) - if err != nil { + if err != nil && len(workflows) == 0 { log.Printf("Error getting workflows: %s", err) } else { if len(workflows) == 0 { @@ -6041,7 +6096,15 @@ func makeWorkflowPublic(resp http.ResponseWriter, request *http.Request) { FifthItem: user.Id, } - err = executeCloudAction(action, user.ActiveOrg.SyncConfig.Apikey) + org, err := shuffle.GetOrg(ctx, user.ActiveOrg.Id) + if err != nil { + log.Printf("[WARNING] Failed setting getting org during cloud job setting: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err))) + return + } + + err = executeCloudAction(action, org.SyncConfig.Apikey) if err != nil { log.Printf("[WARNING] Failed cloud PUBLISH: %s", err) resp.WriteHeader(401) @@ -6160,7 +6223,7 @@ func initHandlers() { r.HandleFunc("/api/v1/workflows/{key}/schedule/{schedule}", stopSchedule).Methods("DELETE", "OPTIONS") r.HandleFunc("/api/v1/workflows/{key}/outlook", createOutlookSub).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/workflows/{key}/outlook/{triggerId}", handleDeleteOutlookSub).Methods("DELETE", "OPTIONS") - r.HandleFunc("/api/v1/workflows/{key}/executions", getWorkflowExecutions).Methods("GET", "OPTIONS") + r.HandleFunc("/api/v1/workflows/{key}/executions", shuffle.GetWorkflowExecutions).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/workflows/{key}/executions/{key}/abort", shuffle.AbortExecution).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/workflows/{key}", deleteWorkflow).Methods("DELETE", "OPTIONS") diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index c694fd82..935e989e 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -642,7 +642,7 @@ func createSchedule(ctx context.Context, scheduleId, workflowId, name, startNode Body: ioutil.NopCloser(strings.NewReader(bodyWrapper)), } - _, _, err := handleExecution(workflowId, shuffle.Workflow{ExecutingOrg: shuffle.Org{Id: orgId}}, request) + _, _, err := handleExecution(workflowId, shuffle.Workflow{ExecutingOrg: shuffle.OrgMini{Id: orgId}}, request) if err != nil { log.Printf("Failed to execute %s: %s", workflowId, err) } @@ -2513,10 +2513,10 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request // //workflowExecution.ExecutionOrg.SyncFeatures = Org{} //} - workflowExecution.Workflow.ExecutingOrg = shuffle.Org{ + workflowExecution.Workflow.ExecutingOrg = shuffle.OrgMini{ Id: workflowExecution.Workflow.ExecutingOrg.Id, } - workflowExecution.Workflow.Org = []shuffle.Org{ + workflowExecution.Workflow.Org = []shuffle.OrgMini{ workflowExecution.Workflow.ExecutingOrg, } @@ -2698,8 +2698,8 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) { //memcacheName := fmt.Sprintf("%s_%s", user.Username, fileId) ctx := context.Background() workflow, err := shuffle.GetWorkflow(ctx, fileId) - if err != nil { - log.Printf("Failed getting the workflow locally (execute workflow): %s", err) + if err != nil && workflow.ID == "" { + log.Printf("[WARNING] Failed getting the workflow locally (execute workflow): %s", err) resp.WriteHeader(401) resp.Write([]byte(`{"success": false}`)) return @@ -2716,7 +2716,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) { log.Printf("[INFO] Starting execution of %s!", fileId) - user.ActiveOrg.Users = []shuffle.User{} + user.ActiveOrg.Users = []shuffle.UserMini{} workflow.ExecutingOrg = user.ActiveOrg workflowExecution, executionResp, err := handleExecution(fileId, *workflow, request) @@ -4502,11 +4502,11 @@ func iterateWorkflowGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra workflow.ID = uuid.NewV4().String() workflow.OrgId = orgId - workflow.ExecutingOrg = shuffle.Org{ + workflow.ExecutingOrg = shuffle.OrgMini{ Id: orgId, } - workflow.Org = append(workflow.Org, shuffle.Org{ + workflow.Org = append(workflow.Org, shuffle.OrgMini{ Id: orgId, }) workflow.IsValid = false diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index 6201fdf8..b73af2fb 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -2043,7 +2043,7 @@ const Admin = (props) => { /> { return ( { if (nodedata.app_name == "Shuffle Tools" || nodedata.app_name == "Testing") { //console.log("NODE: ", //selector: `node[app_name="Shuffle Tools"]`, - console.log(event.target) + //console.log(event.target) // 1. Find location of node // 2. Check if it's within view of another node (inside) @@ -1387,6 +1387,42 @@ const AngularWorkflow = (props) => { const onEdgeAdded = (event) => { setLastSaved(false) const edge = event.target.data() + var targetnode = workflow.triggers.findIndex(data => data.id === edge.target) + if (targetnode !== -1) { + console.log("TARGETNODE: ", targetnode) + if (workflow.triggers[targetnode].app_name === "User Input" || workflow.triggers[targetnode].app_name === "Shuffle Workflow") { + } else { + alert.error("Can't have triggers as target of branch") + event.target.remove() + } + } + + targetnode = -1 + var sourcenode = workflow.triggers.findIndex(data => data.id === edge.source) + //console.log("SOURCENODE: ", sourcenode) + if (sourcenode !== -1) { + if (workflow.triggers[sourcenode].app_name === "User Input" || workflow.triggers[sourcenode].app_name === "Shuffle Workflow") { + //console.log("NORMAL TRIGGER") + } else { + var currentnode = cy.getElementById(workflow.triggers[sourcenode].id) + if (currentnode !== null && currentnode !== undefined) { + console.log("SHOULD CHECK IF TRIGGER HAS MULTIPLE EDGES: ", currentnode) + // https://js.cytoscape.org/#edges.connectedNodes + //console.log("CURRENTNODE: ", currentnode) + //console.log("EDGES: ", currentnode.connectedEdges(`node[id=${workflow.triggers[sourcenode].id}]`)) + //console.log("EDGES2: ", currentnode.connectedEdges()) + //currentnode.connectedEdges().animate({style: {lineColor: "red"}}) + //console.log("OUTGOERS: ", currentnode.outgoers()) + + //console.log("LEN2: ", currentnode.edges().length) + //if (currentnode.connectedNodes().length > 0) { + // alert.error("Can't have multiple branches from this trigger") + // event.target.remove() + //} + } + } + } + //console.log(workflow.branches) // Check if: @@ -1407,7 +1443,7 @@ const AngularWorkflow = (props) => { found = true break } else if (edge.target === workflow.start) { - var targetnode = workflow.triggers.findIndex(data => data.id === edge.source) + targetnode = workflow.triggers.findIndex(data => data.id === edge.source) if (targetnode === -1) { alert.error("Can't make arrow to starting node") event.target.remove() @@ -1428,10 +1464,14 @@ const AngularWorkflow = (props) => { // break // } } else { + console.log("INSIDE LAST CHECK: ", edge) + // Find the targetnode and check if its a trigger // FIXME - do this for both actions and other types? + /* targetnode = workflow.triggers.findIndex(data => data.id === edge.target) if (targetnode !== -1) { + console.log("TARGETNODE: ", targetnode) if (workflow.triggers[targetnode].app_name === "User Input" || workflow.triggers[targetnode].app_name === "Shuffle Workflow") { } else { alert.error("Can't have triggers as target of branch") @@ -1440,6 +1480,9 @@ const AngularWorkflow = (props) => { break } } + */ + + } } @@ -1491,6 +1534,7 @@ const AngularWorkflow = (props) => { workflow.branches = workflow.branches.filter(a => a.id !== edge.data().id) setWorkflow(workflow) + event.target.remove() // trigger as source check const indexcheck = workflow.triggers.findIndex(data => edge.data()["source"] === data.id) @@ -6811,6 +6855,9 @@ const AngularWorkflow = (props) => { theme="solarized" collapsed={true} displayDataTypes={false} + enableClipboard={(copy) => { + handleReactJsonClipboard(copy) + }} onSelect={(select) => { HandleJsonCopy(showResult, select, "exec") console.log("SELECTED!: ", select) @@ -6858,6 +6905,22 @@ const AngularWorkflow = (props) => { ) } + const handleReactJsonClipboard = (copy) => { + console.log("COPY: ", copy) + + const elementName = "copy_element_shuffle" + var copyText = document.getElementById(elementName); + if (copyText !== null && copyText !== undefined) { + navigator.clipboard.writeText(JSON.stringify(copy)) + copyText.select(); + copyText.setSelectionRange(0, 99999); /* For mobile devices */ + + /* Copy the text inside the text field */ + document.execCommand("copy"); + alert.success("Copied data") + } + } + const HandleJsonCopy = (base, copy, base_node_name) => { console.log("COPY: ", copy) var newitem = JSON.parse(base) @@ -7204,10 +7267,14 @@ const AngularWorkflow = (props) => { {data.status} - {validate.valid ? + { + handleReactJsonClipboard(copy) + }} displayDataTypes={false} onSelect={(select) => { HandleJsonCopy(showResult, select, data.action.label) @@ -7394,6 +7461,9 @@ const AngularWorkflow = (props) => { theme="solarized" collapsed={false} displayDataTypes={false} + enableClipboard={(copy) => { + handleReactJsonClipboard(copy) + }} onSelect={(select) => { HandleJsonCopy(JSON.stringify(validate.result), select, selectedResult.action.label) }} diff --git a/functions/onprem/worker/worker.go b/functions/onprem/worker/worker.go index cc981636..642af1bc 100644 --- a/functions/onprem/worker/worker.go +++ b/functions/onprem/worker/worker.go @@ -24,7 +24,7 @@ import ( //"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" dockerclient "github.com/docker/docker/client" - "github.com/satori/go.uuid" + //"github.com/satori/go.uuid" "github.com/gorilla/mux" "github.com/patrickmn/go-cache" @@ -857,17 +857,25 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { } // Added UUID to identifier just in case - identifier := fmt.Sprintf("%s_%s_%s_%s_%s", appname, appversion, action.ID, workflowExecution.ExecutionId, uuid.NewV4()) + //identifier := fmt.Sprintf("%s_%s_%s_%s_%s", appname, appversion, action.ID, workflowExecution.ExecutionId, uuid.NewV4()) + identifier := fmt.Sprintf("%s_%s_%s_%s", appname, appversion, action.ID, workflowExecution.ExecutionId) if strings.Contains(identifier, " ") { identifier = strings.ReplaceAll(identifier, " ", "-") } + //if arrayContains(executed, action.ID) || arrayContains(visited, action.ID) { + // log.Printf("[WARNING] Action %s is already executed") + // continue + //} + //visited = append(visited, action.ID) + //executed = append(executed, action.ID) + // FIXME - check whether it's running locally yet too dockercli, err := dockerclient.NewEnvClient() if err != nil { log.Printf("[ERROR] Unable to create docker client (2): %s", err) //return err - return + continue } stats, err := dockercli.ContainerInspect(context.Background(), identifier) @@ -1309,6 +1317,7 @@ func arrayContains(visited []string, id string) bool { for _, item := range visited { if item == id { found = true + break } } @@ -2094,7 +2103,7 @@ func sendResult(workflowExecution shuffle.WorkflowExecution, data []byte) { } body, err := ioutil.ReadAll(newresp.Body) - log.Printf("[INFO] BACKEND STATUS: %d", newresp.StatusCode) + //log.Printf("[INFO] BACKEND STATUS: %d", newresp.StatusCode) if err != nil { log.Printf("[ERROR] Failed reading body: %s", err) } else {