Added schedule overview to admin

This commit is contained in:
frikky
2020-06-11 18:03:01 +02:00
parent 8b606620d0
commit c592ca649a
4 changed files with 173 additions and 18 deletions
+61 -2
View File
@@ -238,7 +238,7 @@ type AppInfo struct {
type ScheduleOld struct { type ScheduleOld struct {
Id string `json:"id" datastore:"id"` Id string `json:"id" datastore:"id"`
Seconds int `json:"seconds" datastore:"seconds"` Seconds int `json:"seconds" datastore:"seconds"`
WorkflowId string `json:"workflow_id datastore:"workflow_id", ` WorkflowId string `json:"workflow_id" datastore:"workflow_id", `
Argument string `json:"argument" datastore:"argument"` Argument string `json:"argument" datastore:"argument"`
AppInfo AppInfo `json:"appinfo" datastore:"appinfo,noindex"` AppInfo AppInfo `json:"appinfo" datastore:"appinfo,noindex"`
Finished bool `json:"finished" finished:"id"` Finished bool `json:"finished" finished:"id"`
@@ -1803,6 +1803,49 @@ func getUserCount() (int, error) {
return count, nil return count, nil
} }
func handleGetSchedules(resp http.ResponseWriter, request *http.Request) {
cors := handleCors(resp, request)
if cors {
return
}
user, err := handleApiAuthentication(resp, request)
if err != nil {
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
}
if user.Role != "admin" {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Admin required"}`))
return
}
ctx := context.Background()
schedules, err := getAllSchedules(ctx)
if err != nil {
log.Printf("Failed getting schedules: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Couldn't get schedules"}`))
return
}
newjson, err := json.Marshal(schedules)
if err != nil {
log.Printf("Failed unmarshal: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed unpacking environments"}`)))
return
}
//log.Printf("Existing environments: %s", string(newjson))
resp.WriteHeader(200)
resp.Write(newjson)
}
func handleGetEnvironments(resp http.ResponseWriter, request *http.Request) { func handleGetEnvironments(resp http.ResponseWriter, request *http.Request) {
cors := handleCors(resp, request) cors := handleCors(resp, request)
if cors { if cors {
@@ -2635,6 +2678,21 @@ func handleDeleteSchedule(resp http.ResponseWriter, request *http.Request) {
return return
} }
user, err := handleApiAuthentication(resp, request)
if err != nil {
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
}
// FIXME: IAM - Get workflow and check owner
if user.Role != "admin" {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Admin required"}`))
return
}
location := strings.Split(request.URL.String(), "/") location := strings.Split(request.URL.String(), "/")
var workflowId string var workflowId string
@@ -2655,7 +2713,7 @@ func handleDeleteSchedule(resp http.ResponseWriter, request *http.Request) {
} }
ctx := context.Background() ctx := context.Background()
err := DeleteKey(ctx, "schedules", workflowId) err = DeleteKey(ctx, "schedules", workflowId)
if err != nil { if err != nil {
resp.WriteHeader(401) resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "message": "Can't delete"}`)) resp.Write([]byte(`{"success": false, "message": "Can't delete"}`))
@@ -5914,6 +5972,7 @@ func init() {
/* Everything below here increases the counters*/ /* Everything below here increases the counters*/
r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/workflows/schedules", handleGetSchedules).Methods("GET", "OPTIONS")
//r.HandleFunc("/api/v1/workflows/{key}/execute_fs", executeWorkflowFS) //r.HandleFunc("/api/v1/workflows/{key}/execute_fs", executeWorkflowFS)
r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS") r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS")
r.HandleFunc("/api/v1/workflows/{key}/schedule", scheduleWorkflow).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/workflows/{key}/schedule", scheduleWorkflow).Methods("POST", "OPTIONS")
+1 -13
View File
@@ -2021,6 +2021,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) {
} }
func stopSchedule(resp http.ResponseWriter, request *http.Request) { func stopSchedule(resp http.ResponseWriter, request *http.Request) {
log.Printf("Delete?")
cors := handleCors(resp, request) cors := handleCors(resp, request)
if cors { if cors {
return return
@@ -2079,19 +2080,6 @@ func stopSchedule(resp http.ResponseWriter, request *http.Request) {
return return
} }
if len(workflow.Actions) == 0 {
workflow.Actions = []Action{}
}
if len(workflow.Branches) == 0 {
workflow.Branches = []Branch{}
}
if len(workflow.Triggers) == 0 {
workflow.Triggers = []Trigger{}
}
if len(workflow.Errors) == 0 {
workflow.Errors = []string{}
}
err = deleteSchedule(ctx, scheduleId) err = deleteSchedule(ctx, scheduleId)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "Job not found") { if strings.Contains(err.Error(), "Job not found") {
+109 -1
View File
@@ -8,7 +8,8 @@ import ListItem from '@material-ui/core/ListItem';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Tabs from '@material-ui/core/Tabs'; import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab'; import Tab from '@material-ui/core/Tab';
import ListItemText from '@material-ui/core/ListItemText';
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import { useAlert } from "react-alert"; import { useAlert } from "react-alert";
@@ -29,9 +30,39 @@ const Admin = (props) => {
const [curTab, setCurTab] = React.useState(0); const [curTab, setCurTab] = React.useState(0);
const [users, setUsers] = React.useState([]); const [users, setUsers] = React.useState([]);
const [environments, setEnvironments] = React.useState([]); const [environments, setEnvironments] = React.useState([]);
const [schedules, setSchedules] = React.useState([])
const alert = useAlert() const alert = useAlert()
const deleteSchedule = (data) => {
// FIXME - add some check here ROFL
console.log("INPUT: ", data)
// Just use this one?
const url = globalUrl+'/api/v1/workflows/'+data["workflow_id datastore:"]+"/schedule/"+data.id
console.log("URL: ", url)
fetch(url, {
method: 'DELETE',
credentials: "include",
headers: {
'Content-Type': 'application/json',
},
})
.then(response =>
response.json().then(responseJson => {
if (responseJson["success"] === false) {
alert.error("Failed stopping schedule")
} else {
getSchedules()
alert.success("Successfully stopped schedule!")
}
}),
)
.catch(error => {
console.log("Error in userdata: ", error)
});
}
const submitUser = (data) => { const submitUser = (data) => {
// FIXME - add some check here ROFL // FIXME - add some check here ROFL
console.log("INPUT: ", data) console.log("INPUT: ", data)
@@ -132,6 +163,31 @@ const Admin = (props) => {
}); });
} }
const getSchedules = () => {
fetch(globalUrl+"/api/v1/workflows/schedules", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for apps :O!")
return
}
return response.json()
})
.then((responseJson) => {
setSchedules(responseJson)
})
.catch(error => {
alert.error(error.toString())
});
}
const getEnvironments = () => { const getEnvironments = () => {
fetch(globalUrl+"/api/v1/getenvironments", { fetch(globalUrl+"/api/v1/getenvironments", {
method: 'GET', method: 'GET',
@@ -329,6 +385,54 @@ const Admin = (props) => {
</div> </div>
: null : null
const schedulesView = curTab === 2 ?
<div>
<h2>
Schedules
</h2>
<Divider style={{marginTop: 20, marginBottom: 20, backgroundColor: inputColor}}/>
<List>
<ListItem>
<ListItemText
primary="Interval (seconds)"
style={{maxWidth: 200}}
/>
<ListItemText
primary="Argument"
style={{maxWidth: 400, overflow: "hidden"}}
/>
<ListItemText
primary="Actions"
/>
</ListItem>
{schedules === undefined || schedules === null ? null : schedules.map(schedule => {
return (
<ListItem>
<ListItemText
style={{maxWidth: 200}}
primary={schedule.seconds}
/>
<ListItemText
primary={schedule.argument}
style={{maxWidth: 400, overflow: "hidden"}}
/>
<ListItemText>
<Button
style={{}}
variant="contained"
color="primary"
onClick={() => deleteSchedule(schedule)}
>
Delete
</Button>
</ListItemText>
</ListItem>
)
})}
</List>
</div>
: null
const environmentView = curTab === 1 ? const environmentView = curTab === 1 ?
<div> <div>
<h2> <h2>
@@ -359,6 +463,8 @@ const Admin = (props) => {
const setConfig = (event, newValue) => { const setConfig = (event, newValue) => {
if (newValue === 1) { if (newValue === 1) {
getEnvironments() getEnvironments()
} else if (newValue === 2) {
getSchedules()
} }
setModalUser({}) setModalUser({})
@@ -377,10 +483,12 @@ const Admin = (props) => {
> >
<Tab label="Users" /> <Tab label="Users" />
<Tab label="Environments"/> <Tab label="Environments"/>
<Tab label="Schedules"/>
</Tabs> </Tabs>
<div style={{marginBottom: 10}}/> <div style={{marginBottom: 10}}/>
{usersView} {usersView}
{environmentView} {environmentView}
{schedulesView}
</Paper> </Paper>
</div> </div>
+2 -2
View File
@@ -1588,14 +1588,14 @@ const AppCreator = (props) => {
{bearerAuth} {bearerAuth}
{apiKey} {apiKey}
{authenticationOption === "No authentication" ? null : {/*authenticationOption === "No authentication" ? null :
<FormControlLabel <FormControlLabel
style={{color: "white", marginBottom: 0, marginTop: 20}} style={{color: "white", marginBottom: 0, marginTop: 20}}
label=<div style={{color: "white"}}>Authentication required (default true)</div> label=<div style={{color: "white"}}>Authentication required (default true)</div>
control={<Switch checked={authenticationRequired} onChange={() => { control={<Switch checked={authenticationRequired} onChange={() => {
setAuthenticationRequired(!authenticationRequired) setAuthenticationRequired(!authenticationRequired)
}} />} }} />}
/>} />*/}
<Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/> <Divider style={{marginBottom: "10px", marginTop: "30px", height: "1px", width: "100%", backgroundColor: "grey"}}/>
<div style={{marginTop: "25px"}}> <div style={{marginTop: "25px"}}>
{actionView} {actionView}