diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py
index 1a311ee7..ae57b0d2 100644
--- a/backend/app_sdk/app_base.py
+++ b/backend/app_sdk/app_base.py
@@ -101,7 +101,7 @@ class AppBase:
except requests.exceptions.ConnectionError as e:
print("Connectionerror: %s" % e)
- action_result["result"] = "Bad setup during startup: %d" % e
+ action_result["result"] = "Bad setup during startup: %s" % e
self.send_result(action_result, headers, stream_path)
return
@@ -288,7 +288,7 @@ class AppBase:
# Do stuff here.
innervalue = parse_nested_param(data, maxDepth(data)-0)
outervalue = parse_nested_param(data, maxDepth(data)-1)
- print("INNER: ", outervalue)
+ print("INNER: ", innervalue)
print("OUTER: ", outervalue)
if outervalue != innervalue:
@@ -710,7 +710,17 @@ class AppBase:
continue
#print(destinationvalue)
- if not run_validation(sourcevalue, condition["condition"]["value"], destinationvalue):
+ # NEGATE
+ validation = run_validation(sourcevalue, condition["condition"]["value"], destinationvalue)
+
+ # Configuration = negated because of WorkflowAppActionParam..
+ try:
+ if condition["condition"]["configuration"]:
+ validation = not validation
+ except KeyError:
+ pass
+
+ if not validation:
self.logger.info("Failed condition check for %s %s %s." % (sourcevalue, condition["condition"]["value"], destinationvalue))
return False, "Failed condition: %s %s %s" % (sourcevalue, condition["condition"]["value"], destinationvalue)
diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go
index 0aa12fe4..f620cc7f 100644
--- a/backend/go-app/codegen.go
+++ b/backend/go-app/codegen.go
@@ -398,7 +398,7 @@ func makePythoncode(swagger *openapi3.Swagger, name, url, method string, paramet
verifyAddin,
)
- log.Printf("%s", data)
+ //log.Printf("%s", data)
return functionname, data
}
diff --git a/backend/go-app/main.go b/backend/go-app/main.go
index 0b58ae5d..7004a6b5 100644
--- a/backend/go-app/main.go
+++ b/backend/go-app/main.go
@@ -662,7 +662,7 @@ func handleApiAuthentication(resp http.ResponseWriter, request *http.Request) (U
if len(Userdata.Username) > 0 {
return Userdata, nil
} else {
- return Userdata, errors.New("User is invalid")
+ return Userdata, errors.New(fmt.Sprintf("User is invalid - no username found: %#v", Userdata))
}
}
@@ -1605,8 +1605,11 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
}
// This is a long check to see if an inactive admin can access the site
+ parsedAdmin := "false"
if !userInfo.Active {
if userInfo.Role == "admin" {
+ parsedAdmin = "true"
+
ctx := context.Background()
q := datastore.NewQuery("Users")
var users []User
@@ -1672,7 +1675,14 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
Expires: expiration,
})
- returnData := fmt.Sprintf(`{"success": true, "cookies": [{"key": "session_token", "value": "%s", "expiration": %d}]}`, userInfo.Session, expiration.Unix())
+ returnData := fmt.Sprintf(`
+ {
+ "success": true,
+ "admin": %s,
+ "orgs": [{"name": "Shuffle", "id": "123", "role": "admin"}],
+ "selected_org": {"name": "Shuffle", "id": "123", "role": "admin"},
+ "cookies": [{"key": "session_token", "value": "%s", "expiration": %d}]
+ }`, parsedAdmin, userInfo.Session, expiration.Unix())
resp.WriteHeader(200)
resp.Write([]byte(returnData))
@@ -6134,7 +6144,7 @@ func handleAppHotload(location string) error {
}
//log.Printf("Reading app folder: %#v", dir)
- err = iterateAppGithubFolders(fs, dir, "", "")
+ err = iterateAppGithubFolders(fs, dir, "", "", false)
if err != nil {
log.Printf("Err: %s", err)
return err
@@ -6345,7 +6355,7 @@ func runInit(ctx context.Context) {
//iterateAppGithubFolders(fs, dir, "", "testing")
// FIXME: Get all the apps?
- iterateAppGithubFolders(fs, dir, "", "")
+ iterateAppGithubFolders(fs, dir, "", "", false)
// Hotloads locally
location := os.Getenv("APP_HOTLOAD_FOLDER")
diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go
index 037c8500..da75a0be 100644
--- a/backend/go-app/walkoff.go
+++ b/backend/go-app/walkoff.go
@@ -94,6 +94,7 @@ type AuthenticationUsage struct {
}
// An app inside Shuffle
+// Source string `json:"source" datastore:"soure" yaml:"source"` - downloadlocation
type WorkflowApp struct {
Name string `json:"name" yaml:"name" required:true datastore:"name"`
IsValid bool `json:"is_valid" yaml:"is_valid" required:true datastore:"is_valid"`
@@ -4221,9 +4222,10 @@ func loadSpecificApps(resp http.ResponseWriter, request *http.Request) {
// Field1 & 2 can be a lot of things..
type tmpStruct struct {
- URL string `json:"url"`
- Field1 string `json:"field_1"`
- Field2 string `json:"field_2"`
+ URL string `json:"url"`
+ Field1 string `json:"field_1"`
+ Field2 string `json:"field_2"`
+ ForceUpdate bool `json:"force_update"`
}
//log.Printf("Body: %s", string(body))
@@ -4265,7 +4267,13 @@ func loadSpecificApps(resp http.ResponseWriter, request *http.Request) {
log.Printf("FAiled reading folder: %s", err)
}
_ = r
- iterateAppGithubFolders(fs, dir, "", "")
+
+ if tmpBody.ForceUpdate {
+ log.Printf("Running with force update!")
+ } else {
+ log.Printf("Updating apps with updates")
+ }
+ iterateAppGithubFolders(fs, dir, "", "", tmpBody.ForceUpdate)
} else if strings.Contains(tmpBody.URL, "s3") {
//https://docs.aws.amazon.com/sdk-for-go/api/service/s3/
@@ -4490,8 +4498,13 @@ func iterateWorkflowGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra
}
// Onlyname is used to
-func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra string, onlyname string) error {
+func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra string, onlyname string, forceUpdate bool) error {
var err error
+
+ allapps := []WorkflowApp{}
+
+ // It's here to prevent getting them in every iteration
+ ctx := context.Background()
for _, file := range dir {
if len(onlyname) > 0 && file.Name() != onlyname {
continue
@@ -4508,7 +4521,7 @@ func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra strin
}
// Go routine? Hmm, this can be super quick I guess
- err = iterateAppGithubFolders(fs, dir, tmpExtra, "")
+ err = iterateAppGithubFolders(fs, dir, tmpExtra, "", forceUpdate)
if err != nil {
log.Printf("Error reading folder: %s", err)
continue
@@ -4591,12 +4604,12 @@ func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra strin
fmt.Sprintf("%s:%s_%s", baseDockerName, newName, workflowapp.AppVersion),
}
- ctx := context.Background()
- allapps, err := getAllWorkflowApps(ctx)
- if err != nil {
- log.Printf("Failed getting apps to verify: %s", err)
- continue
- //return err
+ if len(allapps) == 0 {
+ allapps, err = getAllWorkflowApps(ctx)
+ if err != nil {
+ log.Printf("Failed getting apps to verify: %s", err)
+ continue
+ }
}
// Make an option to override existing apps?
@@ -4607,7 +4620,7 @@ func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra strin
if app.Name == workflowapp.Name && app.AppVersion == workflowapp.AppVersion {
// FIXME: Check if there's a new APP_SDK as well.
// Skip this check if app_sdk is new.
- if app.Hash == md5 && app.Hash != "" {
+ if app.Hash == md5 && app.Hash != "" && !forceUpdate {
skip = true
break
}
@@ -4617,7 +4630,7 @@ func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra strin
}
}
- if skip {
+ if skip && !forceUpdate {
continue
}
@@ -4677,6 +4690,7 @@ func iterateAppGithubFolders(fs billy.Filesystem, dir []os.FileInfo, extra strin
if len(removeApps) > 0 {
for _, item := range removeApps {
+ log.Printf("Removing duplicate: %s", item)
err = DeleteKey(ctx, "workflowapp", item)
if err != nil {
log.Printf("Failed deleting %s", item)
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 2c23c389..8b7966f2 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -11,22 +11,18 @@ import Webhooks from "./views/Webhooks";
import Workflows from "./views/Workflows";
import EditWebhook from "./views/EditWebhook";
import AngularWorkflow from "./views/AngularWorkflow";
-// import ForgotPassword from "./views/ForgotPassword";
-// import ForgotPasswordLink from "./components/ForgotPasswordLink";
import Header from './components/Header';
import Apps from './views/Apps';
import AppCreator from './views/AppCreator';
import Contact from './views/Contact';
import Oauth2 from './views/Oauth2';
-// import About from "./views/About";
-// import Post from "./views/Post";
+
import Dashboard from "./views/Dashboard";
import AdminSetup from "./views/AdminSetup";
import Admin from "./views/Admin";
import Docs from "./views/Docs";
-// import RegisterLink from "./views/RegisterLink";
-// import LandingPage from "./views/Landingpage";
+
import LandingPageNew from "./views/LandingpageNew";
import LoginPage from "./views/LoginPage";
import SettingsPage from "./views/SettingsPage";
@@ -165,4 +161,3 @@ const App = (message, props) => {
};
export default App;
-
diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js
index 7a01cb53..cf3c4dfd 100644
--- a/frontend/src/components/Header.js
+++ b/frontend/src/components/Header.js
@@ -6,6 +6,9 @@ import {Link} from 'react-router-dom';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
+
+import MenuItem from '@material-ui/core/MenuItem';
+import Select from '@material-ui/core/Select';
import Button from '@material-ui/core/Button';
import HomeIcon from '@material-ui/icons/Home';
import PolymerIcon from '@material-ui/icons/Polymer';
@@ -17,7 +20,8 @@ const hoverColor = "#f85a3e"
const hoverOutColor = "#e8eaf6"
const Header = props => {
- const { globalUrl, isLoggedIn, removeCookie, homePage, isLoaded } = props;
+
+ const { globalUrl, isLoggedIn, removeCookie, homePage, isLoaded } = props;
const [HomeHoverColor, setHomeHoverColor] = useState(hoverOutColor);
const [SoarHoverColor, setSoarHoverColor] = useState(hoverOutColor);
@@ -100,7 +104,7 @@ const Header = props => {
// Handle top bar or something
- const loginTextBrowser = !isLoggedIn ?
+ const loginTextBrowser = !isLoggedIn ?
@@ -192,6 +196,32 @@ const Header = props => {
+ {userdata === undefined || userdata.orgs.length <= 1 ? null :
+
+
+
+ }
+
@@ -287,7 +317,7 @@ const Header = props => {
{loadedCheck}
- );
-};
+ )
+}
export default Header;
diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx
index 112c29f8..09db2c87 100644
--- a/frontend/src/views/Admin.jsx
+++ b/frontend/src/views/Admin.jsx
@@ -1,7 +1,9 @@
-import React, { useEffect } from 'react';
+import React, { useEffect} from 'react';
-import { Link } from 'react-router-dom';
+import {Link} from 'react-router-dom';
import Paper from '@material-ui/core/Paper';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Switch from '@material-ui/core/Switch';
import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import List from '@material-ui/core/List';
@@ -26,7 +28,6 @@ const Admin = (props) => {
const { globalUrl } = props;
const theme = useTheme();
-
const [firstRequest, setFirstRequest] = React.useState(true);
const [modalUser, setModalUser] = React.useState({});
const [modalOpen, setModalOpen] = React.useState(false);
@@ -57,20 +58,20 @@ const Admin = (props) => {
'Content-Type': 'application/json',
},
})
- .then(response =>
- response.json().then(responseJson => {
- console.log("RESP: ", responseJson)
- if (responseJson["success"] === false) {
- alert.error("Failed stopping schedule")
- } else {
- getAppAuthentication()
- alert.success("Successfully stopped schedule!")
- }
- }),
- )
- .catch(error => {
- console.log("Error in userdata: ", error)
- });
+ .then(response =>
+ response.json().then(responseJson => {
+ console.log("RESP: ", responseJson)
+ if (responseJson["success"] === false) {
+ alert.error("Failed stopping schedule")
+ } else {
+ getAppAuthentication()
+ alert.success("Successfully stopped schedule!")
+ }
+ }),
+ )
+ .catch(error => {
+ console.log("Error in userdata: ", error)
+ });
}
const deleteSchedule = (data) => {
@@ -106,6 +107,7 @@ const Admin = (props) => {
const onPasswordChange = () => {
const data = { "username": selectedUser.username, "newpassword": newPassword }
const url = globalUrl + '/api/v1/users/passwordchange';
+
fetch(url, {
mode: 'cors',
method: 'POST',
@@ -141,24 +143,24 @@ const Admin = (props) => {
'Content-Type': 'application/json',
},
})
- .then(response => {
- if (response.status === 200) {
- getUsers()
- }
+ .then(response => {
+ if (response.status === 200) {
+ getUsers()
+ }
- return response.json()
- })
- .then((responseJson) => {
- if (!responseJson.success && responseJson.reason !== undefined) {
- alert.error("Failed to deactivate user: " + responseJson.reason)
- } else {
- alert.success("Deactivated user " + data.id)
- }
- })
+ return response.json()
+ })
+ .then((responseJson) => {
+ if (!responseJson.success && responseJson.reason !== undefined) {
+ alert.error("Failed to deactivate user: "+responseJson.reason)
+ } else {
+ alert.success("Deactivated user "+data.id)
+ }
+ })
- .catch(error => {
- console.log("Error in userdata: ", error)
- });
+ .catch(error => {
+ console.log("Error in userdata: ", error)
+ });
}
const submitUser = (data) => {
@@ -790,250 +792,342 @@ const Admin = (props) => {
)
})}
-
+
: null
-const schedulesView = curTab === 3 ?
-
-
-
Schedules
- Schedules used in Workflows. Makes locating and control easier.
-
-
-
-
-
-
-
-
- {schedules === undefined || schedules === null ? null : schedules.map(schedule => {
- return (
-
-
-
-
-
-
-
- )
- })}
-
-
- : null
-
-const authenticationView = curTab === 1 ?
-
-
-
App Authentication
- Control the authentication options for individual apps. Actions can be destructive!
-
-
-
-
-
-
-
-
-
-
-
-
- {authentication === undefined ? null : authentication.map(data => {
- return (
-
- }
- style={{ minWidth: 150, maxWidth: 150 }}
+ const schedulesView = curTab === 3 ?
+
+
+
Schedules
+ Schedules used in Workflows. Makes locating and control easier.
+
+
+
+
+
+
+
+
+ {schedules === undefined || schedules === null ? null : schedules.map(schedule => {
+ return (
+
+
-
-
-
-
- {
- return data.key
- }).join(", ")}
- style={{ minWidth: 200, maxWidth: 200, overflow: "hidden" }}
- />
-
-
- )
- })}
-
-
- : null
-
-const environmentView = curTab === 2 ?
-
-
-
Environments
- Decides what Orborus environment to execute an action in a workflow in.
+
+
+ )
+ })}
+
-
setModalOpen(true)}
- >
- Add environment
+ : null
+
+ const authenticationView = curTab === 1 ?
+
+
+
App Authentication
+ Control the authentication options for individual apps. Actions can be destructive!
+
+
+
+
+
+
+
+
+
+
+
+
+ {authentication === undefined ? null : authentication.map(data => {
+ return (
+
+
+ style={{minWidth: 150, maxWidth: 150}}
+ />
+
+
+
+
+ {
+ return data.key
+ }).join(", ")}
+ style={{minWidth: 200, maxWidth: 200, overflow: "hidden"}}
+ />
+
+ {
+ deleteAuthentication(data)
+ }}
+ >
+ Delete
+
+
+
+ )
+ })}
+
+
+ : null
+
+ const environmentView = curTab === 2 ?
+
+
+
Environments
+ Decides what Orborus environment to execute an action in a workflow in.
+
+
setModalOpen(true)}
+ >
+ Add environment
-
getEnvironments()}
- >
-
-
-
-
-
-
-
-
-
- {environments === undefined ? null : environments.map(environment => {
- return (
-
-
-
-
- deleteEnvironment(environment.Name)} color="primary">Delete
-
-
- )
- })}
-
-
- : null
+ getEnvironments()}
+ >
+
+
+
+
+
+
+
+
+
+ {environments === undefined ? null : environments.map(environment => {
+ return (
+
+
+
+
+ deleteEnvironment(environment.Name)} color="primary">Delete
+
+
+ )
+ })}
+
+
+ : null
-// primary={environment.Registered ? "true" : "false"}
+ const organizationsTab = curTab === 5 ?
+
+
+
Organizations
+ Global admin: control organizations
+
+
setModalOpen(true)}
+ >
+ Add organization
+
+
+
+
+
+
+
+
+
+
+
+ {console.log("INVERT")}} />
+ style={{minWidth: 150, maxWidth: 150}}
+ />
+
+
+
+ : null
-const setConfig = (event, newValue) => {
- if (newValue === 1) {
- getAppAuthentication()
- } else if (newValue === 2) {
- getEnvironments()
- } else if (newValue === 3) {
- getSchedules()
+ const hybridTab = curTab === 4 ?
+
+
+
Hybrid
+
+
+
+
+
+
+
+
+
+
+
+
+ {console.log("INVERT")}} />
+ style={{minWidth: 150, maxWidth: 150}}
+ />
+
+
+
+ : null
+
+ // primary={environment.Registered ? "true" : "false"}
+
+ const setConfig = (event, newValue) => {
+ if (newValue === 1) {
+ getAppAuthentication()
+ } else if (newValue === 2) {
+ getEnvironments()
+ } else if (newValue === 3) {
+ getSchedules()
+ }
+
+ setModalUser({})
+ setCurTab(newValue)
}
- setModalUser({})
- setCurTab(newValue)
+ const iconStyle = {marginRight: 10}
+ const data =
+
+
+
+ Users />
+ App Authentication/>
+ Environments/>
+ Schedules />
+ {window.location.protocol == "http:" && window.location.port === "3000" ? Hybrid/> : null}
+ {window.location.protocol == "http:" && window.location.port === "3000" ? Organizations/> : null}
+
+
+
+ {authenticationView}
+ {usersView}
+ {environmentView}
+ {schedulesView}
+ {hybridTab}
+ {organizationsTab}
+
+
+
+
+ return (
+
+ {modalView}
+ {editUserModal}
+ {editAuthenticationModal}
+ {data}
+
+ )
}
-const data =
-
-
-
-
-
-
-
-
-
-
- {authenticationView}
- {usersView}
- {environmentView}
- {schedulesView}
-
-
-
-
-return (
-
- {modalView}
- {editUserModal}
- {editAuthenticationModal}
- {data}
-
-)
-}
-
-export default Admin;
+export default Admin
\ No newline at end of file
diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx
index db31586e..294b4d2a 100644
--- a/frontend/src/views/AngularWorkflow.jsx
+++ b/frontend/src/views/AngularWorkflow.jsx
@@ -949,6 +949,10 @@ const AngularWorkflow = (props) => {
if (curaction.selectedAuthentication === null || curaction.selectedAuthentication === undefined || curaction.selectedAuthentication.length === "") {
curaction.selectedAuthentication = {}
}
+ } else {
+ curaction.authentication = []
+ curaction.authentication_id = ""
+ curaction.selectedAuthentication = {}
}
setSelectedApp(curapp)
@@ -2997,7 +3001,7 @@ const AngularWorkflow = (props) => {
paddingLeft: 10,
minHeight: "100%",
zIndex: 1000,
- resize: "horizontal",
+ resize: "vertical",
overflow: "auto",
}
@@ -3512,14 +3516,6 @@ const AngularWorkflow = (props) => {
{data.name}
-
- {
- e.preventDefault()
- changeActionParameterVariant("STATIC_VALUE")
- }}>
-
-
-
{datafield}
@@ -3552,11 +3548,21 @@ const AngularWorkflow = (props) => {
Condition
+
+ {
+ console.log("VALUE: ", conditionValue.configuration)
+ conditionValue.configuration = !conditionValue.configuration
+ setConditionValue(conditionValue)
+ setUpdate("condition "+conditionValue.configuration)
+ }}>
+ {conditionValue.configuration ? "!" : "="}
+
+
-
-
{setVariableAnchorEl(e.currentTarget)}}>
+
+ {setVariableAnchorEl(e.currentTarget)}}>
{conditionValue.value}
-
-
+
diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx
index 0f7daa29..35bef2d4 100644
--- a/frontend/src/views/Apps.jsx
+++ b/frontend/src/views/Apps.jsx
@@ -286,7 +286,7 @@ const Apps = (props) => {
}
return (
- {
+ {
if (selectedApp.id !== data.id) {
setSelectedApp(data)
console.log(data)
@@ -515,7 +515,7 @@ const Apps = (props) => {
newActionname = newActionname.replace("_", " ")
newActionname = newActionname.charAt(0).toUpperCase()+newActionname.substring(1)
return (
-