Started adding web3 functionality + some bug fixes
This commit is contained in:
@@ -21,7 +21,7 @@ require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/h2non/filetype v1.1.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shuffle/shuffle-shared v0.1.28
|
||||
github.com/shuffle/shuffle-shared v0.1.30
|
||||
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
google.golang.org/api v0.58.0
|
||||
|
||||
@@ -1003,6 +1003,24 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This is bad, but we've had a lot of bugs with edit users, and this is the quick fix.
|
||||
if userInfo.Role == "" && userInfo.ActiveOrg.Role == "" && parsedAdmin == "false" {
|
||||
userInfo.Role = "admin"
|
||||
userInfo.ActiveOrg.Role = "admin"
|
||||
parsedAdmin = "true"
|
||||
|
||||
err = shuffle.SetUser(ctx, &userInfo, true)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] Automatically asigning user as admin to their org because they don't have a role at all failed: %s", err)
|
||||
resp.WriteHeader(500)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
} else {
|
||||
log.Printf("[DEBUG] Made user %s org-admin as they didn't have any role specified", err)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
returnValue := shuffle.HandleInfo{
|
||||
Success: true,
|
||||
Username: userInfo.Username,
|
||||
@@ -1017,6 +1035,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
||||
Expiration: expiration.Unix(),
|
||||
},
|
||||
},
|
||||
EthInfo: userInfo.EthInfo,
|
||||
}
|
||||
|
||||
returnData, err := json.Marshal(returnValue)
|
||||
@@ -5785,6 +5804,7 @@ func initHandlers() {
|
||||
|
||||
// This is a new API that validates if a key has been seen before.
|
||||
// Not sure what the best course of action is for it.
|
||||
r.HandleFunc("/api/v1/environments/{key}/stop", shuffle.HandleStopExecutions).Methods("GET", "POST", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/orgs/{orgId}/validate_app_values", shuffle.HandleKeyValueCheck).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/orgs/{orgId}/get_cache", shuffle.HandleGetCacheKey).Methods("POST", "OPTIONS")
|
||||
r.HandleFunc("/api/v1/orgs/{orgId}/set_cache", shuffle.HandleSetCacheKey).Methods("POST", "OPTIONS")
|
||||
|
||||
@@ -577,7 +577,7 @@ func handleGetWorkflowqueueConfirm(resp http.ResponseWriter, request *http.Reque
|
||||
|
||||
//setWorkflowqueuetest(id)
|
||||
ctx := context.Background()
|
||||
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id)
|
||||
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id, 100)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] (1) Failed reading body for workflowqueue: %s", err)
|
||||
resp.WriteHeader(401)
|
||||
@@ -689,7 +689,7 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id)
|
||||
executionRequests, err := shuffle.GetWorkflowQueue(ctx, id, 100)
|
||||
if err != nil {
|
||||
// Skipping as this comes up over and over
|
||||
//log.Printf("(2) Failed reading body for workflowqueue: %s", err)
|
||||
@@ -838,7 +838,7 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "reason": "success"}`)))
|
||||
return
|
||||
} else {
|
||||
//log.Printf("[WARNING] Handling other execution variant: %s", err)
|
||||
log.Printf("[DEBUG] Handling other execution variant: %s", err)
|
||||
}
|
||||
|
||||
var actionResult shuffle.ActionResult
|
||||
@@ -962,9 +962,15 @@ func runWorkflowExecutionTransaction(ctx context.Context, attempts int64, workfl
|
||||
//log.Printf("BASE LENGTH: %d", len(workflowExecution.Results))
|
||||
workflowExecution, dbSave, err := shuffle.ParsedExecutionResult(ctx, *workflowExecution, actionResult, false)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Failed running of parsedexecution: %s", err)
|
||||
b, suberr := json.Marshal(actionResult)
|
||||
if suberr != nil {
|
||||
log.Printf("[ERROR] Failed running of parsedexecution: %s", err)
|
||||
} else {
|
||||
log.Printf("[ERROR] Failed running of parsedexecution: %s. Data: %s", err, string(b))
|
||||
}
|
||||
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed getting execution"}`)))
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed updating execution"}`)))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1284,7 +1290,7 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
|
||||
workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] Failed in prepareExecution: %s", err)
|
||||
return shuffle.WorkflowExecution{}, "", err
|
||||
return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed preparration: %s", err), err
|
||||
}
|
||||
|
||||
err = imageCheckBuilder(execInfo.ImageNames)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#
|
||||
+2
-2
@@ -16,7 +16,7 @@ services:
|
||||
depends_on:
|
||||
- backend
|
||||
backend:
|
||||
#build: ./backend
|
||||
build: ./backend
|
||||
image: ghcr.io/frikky/shuffle-backend:nightly
|
||||
container_name: shuffle-backend
|
||||
hostname: ${BACKEND_HOSTNAME}
|
||||
@@ -48,7 +48,7 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- SHUFFLE_APP_SDK_VERSION=0.8.97
|
||||
- SHUFFLE_WORKER_VERSION=0.9.30
|
||||
- SHUFFLE_WORKER_VERSION=0.9.25
|
||||
- ORG_ID=${ORG_ID}
|
||||
- ENVIRONMENT_NAME=${ENVIRONMENT_NAME}
|
||||
- BASE_URL=http://${OUTER_HOSTNAME}:${BACKEND_PORT}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"@material-ui/lab": "^4.0.0-alpha.58",
|
||||
"@material-ui/styles": "^4.5.2",
|
||||
"@material-ui/utils": "^4.11.2",
|
||||
"@metamask/detect-provider": "^1.2.0",
|
||||
"@uiw/react-codemirror": "^3.2.1",
|
||||
"@use-it/interval": "^1.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
@@ -79,9 +80,9 @@
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app",
|
||||
"rules":{
|
||||
"jsx-a11y/img-redundant-alt" : "off",
|
||||
"no-redeclare" : "off",
|
||||
"rules": {
|
||||
"jsx-a11y/img-redundant-alt": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-loop-func": "off"
|
||||
}
|
||||
},
|
||||
|
||||
+102
-3
@@ -38,6 +38,8 @@ import AlertTemplate from "./components/AlertTemplate";
|
||||
import { positions, Provider } from "react-alert";
|
||||
import {isMobile} from "react-device-detect";
|
||||
|
||||
import detectEthereumProvider from '@metamask/detect-provider';
|
||||
|
||||
// Production - backend proxy forwarding in nginx
|
||||
var globalUrl = window.location.origin
|
||||
|
||||
@@ -97,18 +99,113 @@ const App = (message, props) => {
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(responseJson => {
|
||||
var userInfo = {}
|
||||
if (responseJson.success === true) {
|
||||
console.log(responseJson)
|
||||
setUserData(responseJson)
|
||||
|
||||
userInfo = responseJson
|
||||
setIsLoggedIn(true)
|
||||
//console.log("Cookies: ", cookies)
|
||||
|
||||
// Updating cookie every request
|
||||
for (var key in responseJson["cookies"]) {
|
||||
setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" })
|
||||
}
|
||||
}
|
||||
|
||||
// Handling Ethereum update
|
||||
detectEthereumProvider()
|
||||
.then((provider) => {
|
||||
if (provider) {
|
||||
if (userInfo.eth_info.account !== undefined && userInfo.eth_info.account !== null && userInfo.eth_info.account.length === 0) {
|
||||
userInfo.eth_info = {}
|
||||
var method = "eth_requestAccounts"
|
||||
var params = []
|
||||
provider.request({
|
||||
method: method,
|
||||
params,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result !== undefined && result !== null && result.length > 0) {
|
||||
userInfo.eth_info.account = result[0]
|
||||
|
||||
// Getting and setting balance for the current user
|
||||
method = "eth_getBalance"
|
||||
params = [
|
||||
userInfo.eth_info.account,
|
||||
"latest"
|
||||
]
|
||||
provider.request({
|
||||
method: method,
|
||||
params,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result !== undefined && result !== null && result.length > 0) {
|
||||
userInfo.parsed_balance = result/1000000000000000000
|
||||
} else {
|
||||
alert.error("Couldn't find balance: ", result)
|
||||
}
|
||||
// The result varies by RPC method.
|
||||
// For example, this method will return a transaction hash hexadecimal string on success.
|
||||
})
|
||||
.catch((error) => {
|
||||
// If the request fails, the Promise will reject with an error.
|
||||
alert.error("Failed getting info from ethereum API: "+error)
|
||||
})
|
||||
} else {
|
||||
alert.error("Couldn't find any user: ", result)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// If the request fails, the Promise will reject with an error.
|
||||
alert.error("Failed getting info from ethereum API: "+error)
|
||||
})
|
||||
}
|
||||
|
||||
// Register hooks here
|
||||
provider.on('message', (event) => {
|
||||
alert.info("Message from MetaMask: ", event)
|
||||
})
|
||||
|
||||
provider.on('chainChanged', (chainId) => {
|
||||
console.log("Changed chain to: ", chainId)
|
||||
|
||||
method = "eth_getBalance"
|
||||
params = [
|
||||
userInfo.eth_info.account,
|
||||
"latest"
|
||||
]
|
||||
provider.request({
|
||||
method: method,
|
||||
params,
|
||||
})
|
||||
.then((result) => {
|
||||
console.log("Got result: ", result)
|
||||
if (result !== undefined && result !== null) {
|
||||
userInfo.eth_info.balance = result
|
||||
userInfo.eth_info.parsed_balance = result/1000000000000000000
|
||||
console.log("INFO: ", userInfo)
|
||||
setUserData(userInfo)
|
||||
} else {
|
||||
alert.error("Couldn't find balance: ", result)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// If the request fails, the Promise will reject with an error.
|
||||
alert.error("Failed getting info from ethereum API: "+error)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (userInfo.eth_info !== undefined && userInfo.eth_info.balance !== undefined) {
|
||||
console.log(userInfo.eth_info.balance)
|
||||
userInfo.eth_info.parsed_balance = userInfo.eth_info.balance/1000000000000000000
|
||||
}
|
||||
|
||||
console.log("USER: ", userInfo)
|
||||
setUserData(userInfo)
|
||||
setIsLoaded(true)
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
setIsLoaded(true)
|
||||
@@ -133,7 +230,9 @@ const App = (message, props) => {
|
||||
<Route exact path="/login" render={props => <LoginPage isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} checkLogin={checkLogin} {...props} />} />
|
||||
<Route exact path="/admin" render={props => <Admin userdata={userdata} isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
||||
<Route exact path="/admin/:key" render={props => <Admin isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn} register={true} isLoaded={isLoaded} globalUrl={globalUrl} setCookie={setCookie} cookies={cookies} {...props} />} />
|
||||
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
||||
{userdata.id !== undefined ?
|
||||
<Route exact path="/settings" render={props => <SettingsPage isLoaded={isLoaded} setUserData={setUserData} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
||||
: null}
|
||||
<Route exact path="/AdminSetup" render={props => <AdminSetup isLoaded={isLoaded} userdata={userdata} globalUrl={globalUrl} {...props} />} />
|
||||
<Route exact path="/webhooks" render={props => <Webhooks isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
||||
<Route exact path="/webhooks/:key" render={props => <EditWebhook isLoaded={isLoaded} globalUrl={globalUrl} {...props} />} />
|
||||
|
||||
@@ -685,6 +685,31 @@ const Admin = (props) => {
|
||||
})
|
||||
}
|
||||
|
||||
const abortEnvironmentWorkflows = (environment) => {
|
||||
console.log("Aborting all workflows started >10 minutes ago, not finished")
|
||||
|
||||
fetch(`${globalUrl}/api/v1/environments/${environment}/stop`, {
|
||||
method: 'GET',
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for apps :O!")
|
||||
return
|
||||
}
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((responseJson) => {
|
||||
console.log("Got response for execution: ", responseJson)
|
||||
//console.log("RESPONSE: ", responseJson)
|
||||
//setFiles(responseJson)
|
||||
})
|
||||
.catch(error => {
|
||||
//alert.error(error.toString())
|
||||
})
|
||||
}
|
||||
|
||||
const deleteEnvironment = (environment) => {
|
||||
// FIXME - add some check here ROFL
|
||||
//const name = environment.name
|
||||
@@ -1375,6 +1400,7 @@ const Admin = (props) => {
|
||||
style={{ maxHeight: 50, flex: 1 }}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
disabled={selectedUser.role === "admin"}
|
||||
onClick={() => {
|
||||
setUser(selectedUser.id, "username", newUsername)
|
||||
}}
|
||||
@@ -1410,6 +1436,7 @@ const Admin = (props) => {
|
||||
style={{ maxHeight: 50, flex: 1 }}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
disabled={selectedUser.role === "admin"}
|
||||
onClick={() => onPasswordChange()}
|
||||
>
|
||||
Submit
|
||||
@@ -1421,6 +1448,7 @@ const Admin = (props) => {
|
||||
style={{}}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
disabled={selectedUser.role === "admin"}
|
||||
onClick={() => deleteUser(selectedUser)}
|
||||
>
|
||||
{selectedUser.active ? "Deactivate" : "Activate"}
|
||||
@@ -1429,6 +1457,7 @@ const Admin = (props) => {
|
||||
style={{}}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
disabled={selectedUser.role === "admin" && selectedUser.username !== userdata.username}
|
||||
onClick={() => generateApikey(selectedUser)}
|
||||
>
|
||||
Get new API key
|
||||
@@ -2148,6 +2177,7 @@ const Admin = (props) => {
|
||||
onClick={() => {
|
||||
generateApikey(data)
|
||||
}}
|
||||
disabled={data.role === "admin" && data.username !== userdata.username}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
>
|
||||
@@ -2777,14 +2807,20 @@ const Admin = (props) => {
|
||||
{environment.default ?
|
||||
null
|
||||
:
|
||||
<Button variant="outlined" style={{borderRadius: "0px"}} onClick={() => setDefaultEnvironment(environment)} color="primary">Set default</Button>
|
||||
<Button variant="outlined" style={{borderRadius: "0px"}} onClick={() => setDefaultEnvironment(environment)} color="primary">Make default</Button>
|
||||
}
|
||||
</ListItemText>
|
||||
<ListItemText
|
||||
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
|
||||
>
|
||||
<Button variant={environment.archived ? "contained" : "outlined"} style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment)} color="primary">{environment.archived ? "Activate" : "Disable"}</Button>
|
||||
{/*<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => flushQueue(environment.Name)} color="primary">Flush Queue</Button>*/}
|
||||
<div style={{display: "flex"}}>
|
||||
<Button variant={environment.archived ? "contained" : "outlined"} style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment)} color="primary">{environment.archived ? "Activate" : "Disable"}</Button>
|
||||
{/*<Button variant={environment.archived ? "contained" : "outlined"} style={{borderRadius: "0px"}} onClick={() => {
|
||||
console.log("Should clear executions")
|
||||
abortEnvironmentWorkflows(environment)
|
||||
}} color="primary">Clear executions</Button>*/}
|
||||
{/*<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => flushQueue(environment.Name)} color="primary">Flush Queue</Button>*/}
|
||||
</div>
|
||||
</ListItemText>
|
||||
<ListItemText
|
||||
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
|
||||
|
||||
@@ -417,10 +417,10 @@ const Apps = (props) => {
|
||||
}
|
||||
}}>
|
||||
<Grid container style={{margin: 10, flex: "10", maxHeight: 110, overflow: "hidden",}}>
|
||||
<ButtonBase style={{backgroundColor: theme.palette.inputColor, border: 3}}>
|
||||
<ButtonBase style={{backgroundColor: theme.palette.surfaceColor, maxHeight:100, marginTop: 5,}}>
|
||||
{imageline}
|
||||
</ButtonBase>
|
||||
<div style={{marginLeft: "10px", marginTop: "5px", marginBottom: "5px", width: boxWidth, backgroundColor: boxColor}}/>
|
||||
<div style={{marginLeft: "10px", marginTop: 5, marginBottom: 5, width: boxWidth, backgroundColor: boxColor}}/>
|
||||
<Grid container style={{margin: "0px 0px 10px 10px", flex: "1"}}>
|
||||
<Grid style={{display: "flex", flexDirection: "column", }}>
|
||||
<Grid item style={{flex: "1"}}>
|
||||
@@ -648,7 +648,7 @@ const Apps = (props) => {
|
||||
var baseInfo = newAppname.length > 0 ?
|
||||
<div style={{position: "relative"}}>
|
||||
<div style={{display: "flex"}}>
|
||||
<div style={{marginRight: 15, marginTop: 10}}>
|
||||
<div style={{marginRight: 15, marginTop: 10, backgroundColor: theme.palette.surfaceColor,}}>
|
||||
{imageline}
|
||||
</div>
|
||||
<div style={{maxWidth: "85%", overflow: "hidden"}}>
|
||||
@@ -846,7 +846,7 @@ const Apps = (props) => {
|
||||
return(
|
||||
<div style={{}}>
|
||||
<Paper square style={uploadViewPaperStyle}>
|
||||
<div style={{width: "100%", margin: 25}}>
|
||||
<div style={{margin: 25}}>
|
||||
<h2>App Creator</h2>
|
||||
<a rel="noopener noreferrer" href="https://shuffler.io/docs/apps" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">How it works</a>
|
||||
- <a rel="noopener noreferrer" href="https://github.com/frikky/security-openapis" style={{textDecoration: "none", color: "#f85a3e"}} target="_blank">Security API's</a>
|
||||
@@ -885,7 +885,7 @@ const Apps = (props) => {
|
||||
</div>
|
||||
</Paper>
|
||||
<Paper square style={uploadViewPaperStyle}>
|
||||
<div style={{width: "100%", margin: 25}}>
|
||||
<div style={{margin: 25}}>
|
||||
{baseInfo}
|
||||
</div>
|
||||
</Paper>
|
||||
@@ -1684,7 +1684,6 @@ const Apps = (props) => {
|
||||
</Dialog>
|
||||
: null
|
||||
|
||||
|
||||
const loadedCheck = isLoaded && !firstrequest ?
|
||||
<div>
|
||||
{appView}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
|
||||
import {Paper, Button, Divider, TextField} from '@material-ui/core';
|
||||
import {Typography, Paper, Button, Divider, TextField} from '@material-ui/core';
|
||||
import {Link} from 'react-router-dom';
|
||||
import { useAlert } from "react-alert";
|
||||
import { useTheme } from '@material-ui/core/styles';
|
||||
|
||||
import detectEthereumProvider from '@metamask/detect-provider';
|
||||
|
||||
const Settings = (props) => {
|
||||
const { globalUrl, isLoaded, userdata, } = props;
|
||||
const { globalUrl, isLoaded, userdata, setUserData } = props;
|
||||
const theme = useTheme();
|
||||
const alert = useAlert()
|
||||
|
||||
@@ -29,8 +31,36 @@ const Settings = (props) => {
|
||||
|
||||
const [firstrequest, setFirstRequest] = useState(true)
|
||||
|
||||
const [userInfo, ] = useState(userdata)
|
||||
const [userSettings, setUserSettings] = useState({})
|
||||
console.log(userdata)
|
||||
|
||||
|
||||
/*
|
||||
const [userdata.eth_info, setEthInfo] = useState(userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0 ? userdata.eth_info : {
|
||||
"account": "",
|
||||
"balance": "",
|
||||
})
|
||||
*/
|
||||
|
||||
/*
|
||||
console.log(userdata.eth_info)
|
||||
if (userdata.eth_info.account.length === 0 && userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0) {
|
||||
setEthInfo(userdata.eth_info)
|
||||
} else if (userdata.eth_info.balance.length > 0 && userdata.eth_info.parsed_balance === undefined) {
|
||||
//console.log(window.ethereum)
|
||||
//console.log(window.ethereum.utils.formatEther(userdata.eth_info.balance))
|
||||
const parsed_balance = parseInt(userdata.eth_info.balance, 16)/1000000000000000000
|
||||
console.log("Parsed balance: ", parsed_balance)
|
||||
userdata.eth_info.parsed_balance = parsed_balance
|
||||
userdata.eth_info.parsed_balance = parsed_balance
|
||||
setEthInfo(userdata.eth_info)
|
||||
} else if (userdata.eth_info !== undefined && userdata.eth_info.balance !== userdata.eth_info.balance) {
|
||||
console.log("Updating balance: ", userdata.eth_info)
|
||||
setEthInfo(userdata.eth_info)
|
||||
}
|
||||
*/
|
||||
|
||||
//Returns the value from a storage position at a given address.
|
||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
|
||||
|
||||
const bodyDivStyle = {
|
||||
@@ -133,39 +163,97 @@ const Settings = (props) => {
|
||||
|
||||
// Gotta be a better way of doing this rofl
|
||||
const setFields = () => {
|
||||
if (userInfo.username !== undefined) {
|
||||
if (userInfo.username.length > 0) {
|
||||
setUsername(userInfo.username)
|
||||
if (userdata.username !== undefined) {
|
||||
if (userdata.username.length > 0) {
|
||||
setUsername(userdata.username)
|
||||
}
|
||||
//if (userInfo.firstname.length > 0) {
|
||||
// setFirstname(userInfo.firstname)
|
||||
//if (userdata.firstname.length > 0) {
|
||||
// setFirstname(userdata.firstname)
|
||||
//}
|
||||
//if (userInfo.lastname.length > 0) {
|
||||
// setLastname(userInfo.lastname)
|
||||
//if (userdata.lastname.length > 0) {
|
||||
// setLastname(userdata.lastname)
|
||||
//}
|
||||
//if (userInfo.title.length > 0) {
|
||||
// setTitle(userInfo.title)
|
||||
//if (userdata.title.length > 0) {
|
||||
// setTitle(userdata.title)
|
||||
//}
|
||||
//if (userInfo.companyname.length > 0) {
|
||||
// setCompanyname(userInfo.companyname)
|
||||
//if (userdata.companyname.length > 0) {
|
||||
// setCompanyname(userdata.companyname)
|
||||
//}
|
||||
//if (userInfo.phone.length > 0) {
|
||||
// setPhone(userInfo.phone)
|
||||
//if (userdata.phone.length > 0) {
|
||||
// setPhone(userdata.phone)
|
||||
//}
|
||||
//if (userInfo.email.length > 0) {
|
||||
// setEmail(userInfo.email)
|
||||
//if (userdata.email.length > 0) {
|
||||
// setEmail(userdata.email)
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
const registerProviders = (userdata) => {
|
||||
// Register hooks here
|
||||
detectEthereumProvider()
|
||||
.then((provider) => {
|
||||
if (provider) {
|
||||
|
||||
if (!provider.isMetaMask) {
|
||||
alert.error("Only MetaMask is supported as of now.")
|
||||
return
|
||||
}
|
||||
|
||||
// Find the ethereum network
|
||||
// Get the users' account(s)
|
||||
//alert.info("Connecting to MetaMask")
|
||||
//console.log("Connected: ", provider.isConnected())
|
||||
|
||||
if (!provider.isConnected()) {
|
||||
alert.error("Metamask is not connected.")
|
||||
return
|
||||
}
|
||||
|
||||
provider.on('message', (event) => {
|
||||
alert.info("Ethereum message: ", event)
|
||||
})
|
||||
|
||||
provider.on('chainChanged', (chainId) => {
|
||||
console.log("Changed chain to: ", chainId)
|
||||
|
||||
const method = "eth_getBalance"
|
||||
const params = [
|
||||
userdata.eth_info.account,
|
||||
"latest"
|
||||
]
|
||||
provider.request({
|
||||
method: method,
|
||||
params,
|
||||
})
|
||||
.then((result) => {
|
||||
console.log("Got result: ", result)
|
||||
if (result !== undefined && result !== null) {
|
||||
userdata.eth_info.balance = result
|
||||
userdata.eth_info.parsed_balance = result/1000000000000000000
|
||||
console.log("INFO: ", userdata)
|
||||
setUserData(userdata)
|
||||
} else {
|
||||
alert.error("Couldn't find balance: ", result)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// If the request fails, the Promise will reject with an error.
|
||||
alert.error("Failed getting info from ethereum API: "+error)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// This should "always" have data
|
||||
useEffect(() => {
|
||||
if (firstrequest) {
|
||||
setFirstRequest(false)
|
||||
getSettings()
|
||||
//registerProviders(userdata)
|
||||
}
|
||||
|
||||
if (Object.getOwnPropertyNames(userInfo).length > 0 && (username === "" && email === "")) {
|
||||
if (Object.getOwnPropertyNames(userdata).length > 0 && (username === "" && email === "")) {
|
||||
setFields()
|
||||
}
|
||||
})
|
||||
@@ -440,9 +528,213 @@ const Settings = (props) => {
|
||||
Submit password change
|
||||
</Button>
|
||||
<h3>{passwordFormMessage}</h3>
|
||||
<Divider style={{marginTop: "40px"}}/>
|
||||
{userdata !== undefined && userdata.eth_info !== undefined && userdata.eth_info.account.length > 0 ?
|
||||
<Button
|
||||
style={{height: 40, marginTop: 10}}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth={true}
|
||||
onClick={() => {
|
||||
handleEthereumTokenCreation()
|
||||
}}
|
||||
>
|
||||
Create token
|
||||
</Button>
|
||||
:
|
||||
<Button
|
||||
style={{height: 40, marginTop: 10}}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
fullWidth={true}
|
||||
onClick={() => {
|
||||
handleEthereumConnection()
|
||||
}}
|
||||
>
|
||||
Authenticate
|
||||
</Button>
|
||||
}
|
||||
|
||||
{userdata.eth_info !== undefined && userdata.eth_info.account !== undefined && userdata.eth_info.account.length > 0 && userdata.eth_info.parsed_balance !== undefined ?
|
||||
<div style={{marginTop: 10, display: "flex",}}>
|
||||
<Paper square style={{borderRadius: theme.palette.borderRadius, padding: 50, backgroundColor: theme.palette.inputColor}}>
|
||||
<Typography>
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Ethereum-icon-purple.svg/480px-Ethereum-icon-purple.svg.png" style={{height: 30 }}/>
|
||||
</Typography>
|
||||
<Typography>
|
||||
{/*window.ethereum.fromWei(userdata.eth_info.balance, "ether")*/}
|
||||
{userdata.eth_info.parsed_balance.toFixed(4)} ETH
|
||||
</Typography>
|
||||
</Paper>
|
||||
</div>
|
||||
: null}
|
||||
</Paper>
|
||||
</div>
|
||||
|
||||
|
||||
/*
|
||||
0x1 1 Ethereum Main Network (Mainnet)
|
||||
0x3 3 Ropsten Test Network
|
||||
0x4 4 Rinkeby Test Network
|
||||
0x5 5 Goerli Test Network
|
||||
0x2a 42 Kovan Test Network
|
||||
*/
|
||||
const setUser = (userId, field, value) => {
|
||||
const data = { "user_id": userId }
|
||||
data[field] = value
|
||||
|
||||
fetch(globalUrl + "/api/v1/users/updateuser", {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
||||
}
|
||||
|
||||
return response.json()
|
||||
})
|
||||
.then((responseJson) => {
|
||||
if (!responseJson.success && responseJson.reason !== undefined) {
|
||||
alert.error("Failed updating user: " + responseJson.reason)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
});
|
||||
}
|
||||
|
||||
const handleEthereumTokenCreation = async () => {
|
||||
const provider = await detectEthereumProvider();
|
||||
if (!provider) {
|
||||
console.log('Please install MetaMask!');
|
||||
alert.error("Please download the MetaMask browser extension to authenticate fully!")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (!provider.isMetaMask) {
|
||||
alert.error("Only MetaMask is supported as of now.")
|
||||
return
|
||||
}
|
||||
|
||||
if (!provider.isConnected()) {
|
||||
alert.error("Metamask is not connected.")
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Should make a token")
|
||||
}
|
||||
|
||||
const handleEthereumConnection = async () => {
|
||||
const provider = await detectEthereumProvider();
|
||||
if (!provider) {
|
||||
console.log('Please install MetaMask!');
|
||||
alert.error("Please download the MetaMask browser extension to authenticate fully!")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (!provider.isMetaMask) {
|
||||
alert.error("Only MetaMask is supported as of now.")
|
||||
return
|
||||
}
|
||||
|
||||
// Find the ethereum network
|
||||
// Get the users' account(s)
|
||||
//alert.info("Connecting to MetaMask")
|
||||
//console.log("Connected: ", provider.isConnected())
|
||||
|
||||
if (!provider.isConnected()) {
|
||||
alert.error("Metamask is not connected.")
|
||||
return
|
||||
}
|
||||
|
||||
provider.on('message', (event) => {
|
||||
alert.info("Ethereum message: ", event)
|
||||
})
|
||||
|
||||
/*
|
||||
params: [
|
||||
{
|
||||
from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155',
|
||||
to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
|
||||
gas: '0x76c0', // 30400
|
||||
gasPrice: '0x9184e72a000', // 10000000000000
|
||||
value: '0x9184e72a', // 2441406250
|
||||
data:
|
||||
'0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675',
|
||||
},
|
||||
]
|
||||
*/
|
||||
|
||||
// https://docs.metamask.io/guide/rpc-api.html
|
||||
// Gets accounts - requires previous permissions
|
||||
//const method = "eth_accounts"
|
||||
//const params = []
|
||||
//
|
||||
// Asks for permission, and gets the accounts
|
||||
var method = "eth_requestAccounts"
|
||||
var params = []
|
||||
provider.request({
|
||||
method: method,
|
||||
params,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result !== undefined && result !== null && result.length > 0) {
|
||||
userdata.eth_info.account = result[0]
|
||||
|
||||
// Getting and setting balance for the current user
|
||||
method = "eth_getBalance"
|
||||
params = [
|
||||
userdata.eth_info.account,
|
||||
"latest"
|
||||
]
|
||||
provider.request({
|
||||
method: method,
|
||||
params,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result !== undefined && result !== null && result.length > 0) {
|
||||
userdata.eth_info.balance = result
|
||||
userdata.eth_info.parsed_balance = result/1000000000000000000
|
||||
console.log(userdata.eth_info)
|
||||
setUserData(userdata.eth_info)
|
||||
|
||||
// Updating
|
||||
//if (userdata.eth_info !== userdata.userdata.eth_info) {
|
||||
//}
|
||||
|
||||
setUser(userdata.id, "eth_info", userdata.eth_info)
|
||||
userdata.userdata.eth_info = userdata.eth_info
|
||||
} else {
|
||||
alert.error("Couldn't find balance: ", result)
|
||||
}
|
||||
// The result varies by RPC method.
|
||||
// For example, this method will return a transaction hash hexadecimal string on success.
|
||||
})
|
||||
.catch((error) => {
|
||||
// If the request fails, the Promise will reject with an error.
|
||||
//setEthInfo(userdata.eth_info)
|
||||
alert.error("Failed getting info from ethereum API: "+error)
|
||||
})
|
||||
} else {
|
||||
alert.error("Couldn't find any user: ", result)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// If the request fails, the Promise will reject with an error.
|
||||
alert.error("Failed getting info from ethereum API: "+error)
|
||||
})
|
||||
|
||||
// Gets the users' balance in WEI (one quintilionth ETH)
|
||||
}
|
||||
|
||||
const loadedCheck = isLoaded && !firstrequest ?
|
||||
<div style={bodyDivStyle}>
|
||||
{landingpageData}
|
||||
|
||||
@@ -646,7 +646,7 @@ const Workflows = (props) => {
|
||||
for (var key in responseJson) {
|
||||
for (var actionkey in responseJson[key].actions) {
|
||||
const action = responseJson[key].actions[actionkey]
|
||||
console.log("Action: ", action)
|
||||
//console.log("Action: ", action)
|
||||
if (actionnamelist.includes(action.app_name)) {
|
||||
continue
|
||||
}
|
||||
@@ -656,7 +656,7 @@ const Workflows = (props) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(parsedactionlist)
|
||||
//console.log(parsedactionlist)
|
||||
setActionImageList(parsedactionlist)
|
||||
}
|
||||
|
||||
|
||||
@@ -217,6 +217,7 @@ func deployServiceWorkers(image string) {
|
||||
Image: image,
|
||||
Env: []string{
|
||||
fmt.Sprintf("SHUFFLE_SWARM_CONFIG=%s", os.Getenv("SHUFFLE_SWARM_CONFIG")),
|
||||
fmt.Sprintf("SHUFFLE_SWARM_NETWORK_NAME=%s", networkName),
|
||||
},
|
||||
Mounts: []mount.Mount{
|
||||
mount.Mount{
|
||||
|
||||
@@ -117,11 +117,11 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
log.Printf("[INFO] NOT cleaning up containers. IDS: %d, CLEANUP env: %s", len(containerIds), cleanupEnv)
|
||||
log.Printf("[DEBUG] NOT cleaning up containers. IDS: %d, CLEANUP env: %s", len(containerIds), cleanupEnv)
|
||||
}
|
||||
|
||||
if len(reason) > 0 && len(nodeId) > 0 {
|
||||
log.Printf("[INFO] Running abort of workflow because it should be finished")
|
||||
//log.Printf("[INFO] Running abort of workflow because it should be finished")
|
||||
|
||||
abortUrl := fmt.Sprintf("%s/api/v1/workflows/%s/executions/%s/abort", baseUrl, workflowExecution.Workflow.ID, workflowExecution.ExecutionId)
|
||||
path := fmt.Sprintf("?reason=%s", url.QueryEscape(reason))
|
||||
@@ -134,7 +134,7 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
|
||||
|
||||
//fmt.Println(url.QueryEscape(query))
|
||||
abortUrl += path
|
||||
log.Printf("[INFO] Abort URL: %s", abortUrl)
|
||||
log.Printf("[DEBUG] Abort URL: %s", abortUrl)
|
||||
|
||||
req, err := http.NewRequest(
|
||||
"GET",
|
||||
@@ -178,7 +178,7 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("[INFO] All App Logs: %#v", allLogs)
|
||||
log.Printf("[DEBUG] All App Logs: %#v", allLogs)
|
||||
_, err = client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("[WARNING] Failed abort request: %s", err)
|
||||
@@ -301,7 +301,7 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
|
||||
})
|
||||
}
|
||||
} else {
|
||||
log.Printf("[WARNING] Not mounting folders")
|
||||
//log.Printf("[WARNING] Not mounting folders")
|
||||
}
|
||||
|
||||
config := &container.Config{
|
||||
@@ -397,7 +397,7 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env []
|
||||
//log.Printf("[INFO] Info for container: %#v", stats)
|
||||
//log.Printf("%#v", stats.Config)
|
||||
//log.Printf("%#v", stats.ContainerJSONBase.State)
|
||||
log.Printf("[INFO] EXECUTION STATUS: %s", stats.ContainerJSONBase.State.Status)
|
||||
log.Printf("[DEBUG] EXECUTION STATUS: %s", stats.ContainerJSONBase.State.Status)
|
||||
logOptions := types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
}
|
||||
@@ -1352,7 +1352,7 @@ func executionInit(workflowExecution shuffle.WorkflowExecution) error {
|
||||
|
||||
// Setting up extra counter
|
||||
for _, trigger := range workflowExecution.Workflow.Triggers {
|
||||
//log.Printf("Appname trigger (0): %s", trigger.AppName)
|
||||
log.Printf("[DEBUG] Appname trigger (0): %s", trigger.AppName)
|
||||
if trigger.AppName == "User Input" || trigger.AppName == "Shuffle Workflow" {
|
||||
extra += 1
|
||||
}
|
||||
@@ -2717,28 +2717,13 @@ func main() {
|
||||
//wg.Wait()
|
||||
} else {
|
||||
log.Printf("\n\n[INFO] Running NON-OPTIMIZED execution for type %s with %d environment(s). This only happens when ran manually OR when running with subflows. Status: %s\n\n", workflowExecution.ExecutionSource, len(environments), workflowExecution.Status)
|
||||
//err := executionInit(workflowExecution)
|
||||
//if err != nil {
|
||||
// log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
|
||||
// shutdown(workflowExecution, "", "", true)
|
||||
//}
|
||||
err := executionInit(workflowExecution)
|
||||
if err != nil {
|
||||
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
|
||||
shutdown(workflowExecution, "", "", true)
|
||||
}
|
||||
|
||||
// Trying to make worker into microservice~ :)
|
||||
if os.Getenv("SHUFFLE_SWARM_CONFIG") == "run" {
|
||||
listener := webserverSetup(workflowExecution)
|
||||
err := executionInit(workflowExecution)
|
||||
if err != nil {
|
||||
log.Printf("[INFO] Workflow setup failed: %s", workflowExecution.ExecutionId, err)
|
||||
log.Printf("[DEBUG] Shutting down (30)")
|
||||
shutdown(workflowExecution, "", "", true)
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(time.Duration(1))
|
||||
handleExecutionResult(workflowExecution)
|
||||
}()
|
||||
|
||||
runWebserver(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user