#141: File download through app sdk possible
This commit is contained in:
@@ -824,6 +824,26 @@ class AppBase:
|
||||
|
||||
return True, ""
|
||||
|
||||
# Things to consider for files:
|
||||
# - How can you download / stream a file?
|
||||
# - Can you decide if you want a stream or the files directly?
|
||||
def get_files(full_execution, value):
|
||||
print("FULL EXEC: %s" % full_execution)
|
||||
org_id = full_execution["workflow"]["execution_org"]["id"]
|
||||
print("SHOULD GET FILES BASED ON ORG %s, workflow %s and value(s) %s" % (org_id, full_execution["workflow"]["id"], value))
|
||||
get_path = "/api/v1/files/%s/content?execution_id=%s" % (value, full_execution["execution_id"])
|
||||
|
||||
print("PATH: %s" % get_path)
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer %s" % self.authorization
|
||||
}
|
||||
ret = requests.get("%s%s" % (self.url, get_path), headers=headers)
|
||||
print("RET CONTENT: %s" % ret.text)
|
||||
print("RET CODE FILE: %d" % ret.status_code)
|
||||
|
||||
# r.HandleFunc("/api/v1/files/{fileId}/content", handleGetFileContent).Methods("GET", "OPTIONS")
|
||||
|
||||
# Checks whether conditions are met, otherwise set
|
||||
branchcheck, tmpresult = check_branch_conditions(action, fullexecution)
|
||||
if not branchcheck:
|
||||
@@ -848,7 +868,7 @@ class AppBase:
|
||||
actionname.replace(" ", "_", -1)
|
||||
#if action.generated:
|
||||
# actionname = actionname.lower()
|
||||
|
||||
|
||||
# Runs the actual functions
|
||||
try:
|
||||
func = getattr(self, actionname, None)
|
||||
@@ -891,8 +911,16 @@ class AppBase:
|
||||
multiexecution = False
|
||||
multi_execution_lists = []
|
||||
for parameter in action["parameters"]:
|
||||
check, value, is_loop = parse_params(action, fullexecution, parameter)
|
||||
is_file = False
|
||||
try:
|
||||
if parameter["schema"]["type"] == "file":
|
||||
print("SHOULD HANDLE FILE. Get based on value %s" % parameter["value"])
|
||||
get_files(fullexecution, parameter["value"])
|
||||
is_file = True
|
||||
except KeyError as e:
|
||||
print("SCHEMA ERROR: %s" % e)
|
||||
|
||||
check, value, is_loop = parse_params(action, fullexecution, parameter)
|
||||
if check:
|
||||
raise "Value check error: %s" % Exception(check)
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ NAME=shuffle-app_sdk
|
||||
VERSION=0.8.0
|
||||
|
||||
docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force
|
||||
docker build . -t frikky/shuffle:$NAME -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION
|
||||
docker build . -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION
|
||||
|
||||
#docker push frikky/$NAME:$VERSION
|
||||
#docker push docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION
|
||||
#docker push ghcr.io/frikky/$NAME:$VERSION
|
||||
|
||||
docker push frikky/shuffle:$NAME
|
||||
docker push frikky/shuffle:app_sdk
|
||||
docker push ghcr.io/frikky/$NAME:$VERSION
|
||||
|
||||
+87
-83
@@ -620,9 +620,6 @@ func handleApiAuthentication(resp http.ResponseWriter, request *http.Request) (U
|
||||
return User{}, errors.New("Invalid format for apikey")
|
||||
}
|
||||
|
||||
// fml
|
||||
//log.Println(apikeyCheck)
|
||||
|
||||
// This is annoying af and is done because of maxlength lol
|
||||
newApikey := apikeyCheck[1]
|
||||
if len(newApikey) > 249 {
|
||||
@@ -630,57 +627,15 @@ func handleApiAuthentication(resp http.ResponseWriter, request *http.Request) (U
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
//if item, err := memcache.Get(ctx, newApikey); err == memcache.ErrCacheMiss {
|
||||
// // Not in cache
|
||||
//} else if err != nil {
|
||||
// // Error with cache
|
||||
// log.Printf("Error getting item: %v", err)
|
||||
//} else {
|
||||
// var Userdata User
|
||||
// err = json.Unmarshal(item.Value, &Userdata)
|
||||
|
||||
// if err == nil {
|
||||
// if len(Userdata.Username) > 0 {
|
||||
// return Userdata, nil
|
||||
// } else {
|
||||
// return Userdata, errors.New("User is invalid")
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// Make specific check for just service user?
|
||||
// Get the user based on APIkey here
|
||||
//log.Println(apikeyCheck[1])
|
||||
Userdata, err := getApikey(ctx, apikeyCheck[1])
|
||||
if err != nil {
|
||||
log.Printf("Apikey %s doesn't exist: %s", apikey, err)
|
||||
return User{}, err
|
||||
}
|
||||
|
||||
// Caching both bad and good apikeys :)
|
||||
//b, err := json.Marshal(Userdata)
|
||||
//if err != nil {
|
||||
// log.Printf("Failed marshalling: %s", err)
|
||||
// return User{}, err
|
||||
//}
|
||||
|
||||
// Add to cache if it doesn't exist
|
||||
//item := &memcache.Item{
|
||||
// Key: newApikey,
|
||||
// Value: b,
|
||||
// Expiration: time.Minute * 60,
|
||||
//}
|
||||
|
||||
//if err := memcache.Add(ctx, item); err == memcache.ErrNotStored {
|
||||
// if err := memcache.Set(ctx, item); err != nil {
|
||||
// log.Printf("Error setting item: %v", err)
|
||||
// }
|
||||
//} else if err != nil {
|
||||
// log.Printf("error adding item: %v", err)
|
||||
//} else {
|
||||
// log.Printf("Set cache for %s", item.Key)
|
||||
//}
|
||||
|
||||
if len(Userdata.Username) > 0 {
|
||||
return Userdata, nil
|
||||
} else {
|
||||
@@ -3957,7 +3912,7 @@ func executeSchedule(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
log.Printf("EXECUTING %s!", workflowId)
|
||||
log.Printf("[INFO] EXECUTING %s!", workflowId)
|
||||
idConfig, err := getSchedule(ctx, workflowId)
|
||||
if err != nil {
|
||||
log.Printf("Error getting schedule: %s", err)
|
||||
@@ -7186,39 +7141,37 @@ func runInit(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fileq := datastore.NewQuery("Files").Limit(1)
|
||||
count, err := dbclient.Count(ctx, fileq)
|
||||
fileq := datastore.NewQuery("Files").Limit(1)
|
||||
count, err := dbclient.Count(ctx, fileq)
|
||||
log.Printf("FILECOUNT: %d", count)
|
||||
if err == nil && count < 10 {
|
||||
basepath := "."
|
||||
filename := "testfile.txt"
|
||||
fileId := uuid.NewV4().String()
|
||||
log.Printf("Creating new file reference %s because none exist!", fileId)
|
||||
workflowId := "2cf1169d-b460-41de-8c36-28b2092866f8"
|
||||
downloadPath := fmt.Sprintf("%s/%s/%s/%s", basepath, activeOrgs[0].Id, workflowId, fileId)
|
||||
|
||||
if err == nil && count == 0 {
|
||||
basepath := "."
|
||||
filename := "testfile.txt"
|
||||
fileId := uuid.NewV4().String()
|
||||
log.Printf("Creating new file reference %s because none exist!", fileId)
|
||||
workflowId := "2e9d6474-402c-4dcc-bb53-45f638ca18d3"
|
||||
downloadPath := fmt.Sprintf("%s/%s/%s/%s", basepath, activeOrgs[0].Id, workflowId, fileId)
|
||||
|
||||
timeNow := time.Now().Unix()
|
||||
newFile := File{
|
||||
Id: fileId,
|
||||
CreatedAt: timeNow,
|
||||
UpdatedAt: timeNow,
|
||||
Description: "Created by system for testing",
|
||||
Status: "active",
|
||||
Filename: filename,
|
||||
OrgId: activeOrgs[0].Id,
|
||||
WorkflowId: workflowId,
|
||||
DownloadPath: downloadPath,
|
||||
}
|
||||
|
||||
err = setFile(ctx, newFile)
|
||||
if err != nil {
|
||||
log.Printf("Failed setting file: %s", err)
|
||||
} else {
|
||||
log.Printf("Created file %s in init", newFile.DownloadPath)
|
||||
}
|
||||
timeNow := time.Now().Unix()
|
||||
newFile := File{
|
||||
Id: fileId,
|
||||
CreatedAt: timeNow,
|
||||
UpdatedAt: timeNow,
|
||||
Description: "Created by system for testing",
|
||||
Status: "active",
|
||||
Filename: filename,
|
||||
OrgId: activeOrgs[0].Id,
|
||||
WorkflowId: workflowId,
|
||||
DownloadPath: downloadPath,
|
||||
}
|
||||
*/
|
||||
|
||||
err = setFile(ctx, newFile)
|
||||
if err != nil {
|
||||
log.Printf("Failed setting file: %s", err)
|
||||
} else {
|
||||
log.Printf("Created file %s in init", newFile.DownloadPath)
|
||||
}
|
||||
}
|
||||
|
||||
var allworkflowapps []AppAuthenticationStorage
|
||||
q = datastore.NewQuery("workflowappauth")
|
||||
@@ -7241,7 +7194,7 @@ func runInit(ctx context.Context) {
|
||||
|
||||
var schedules []ScheduleOld
|
||||
q = datastore.NewQuery("schedules")
|
||||
_, err := dbclient.GetAll(ctx, q, &schedules)
|
||||
_, err = dbclient.GetAll(ctx, q, &schedules)
|
||||
if err == nil {
|
||||
log.Printf("Setting up all schedules with org %s", activeOrgs[0].Id)
|
||||
for _, item := range schedules {
|
||||
@@ -8016,13 +7969,59 @@ func handleGetFileContent(resp http.ResponseWriter, request *http.Request) {
|
||||
fileId = location[4]
|
||||
}
|
||||
|
||||
//log.Printf("In file download")
|
||||
log.Printf("\n\nUser is trying to get file %s\n\n", fileId)
|
||||
|
||||
// 1. Check user directly
|
||||
// 2. Check workflow execution authorization
|
||||
setOrgId := false
|
||||
user, err := handleApiAuthentication(resp, request)
|
||||
if err != nil {
|
||||
log.Printf("Api authentication failed in file download: %s", err)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
// r.HandleFunc("/api/v1/files/{fileId}/content", handleGetFileContent).Methods("GET", "OPTIONS")
|
||||
log.Printf("INITIAL Api authentication failed in file download: %s", err)
|
||||
executionId, ok := request.URL.Query()["execution_id"]
|
||||
if ok && len(executionId) > 0 {
|
||||
ctx := context.Background()
|
||||
workflowExecution, err := getWorkflowExecution(ctx, executionId[0])
|
||||
if err != nil {
|
||||
log.Printf("Couldn't find execution ID %s", executionId[0])
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
}
|
||||
|
||||
apikey := request.Header.Get("Authorization")
|
||||
if !strings.HasPrefix(apikey, "Bearer ") {
|
||||
log.Printf("Apikey doesn't start with bearer (2)")
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
}
|
||||
|
||||
apikeyCheck := strings.Split(apikey, " ")
|
||||
if len(apikeyCheck) != 2 {
|
||||
log.Printf("Invalid format for apikey (2)")
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
}
|
||||
|
||||
// This is annoying af and is done because of maxlength lol
|
||||
newApikey := apikeyCheck[1]
|
||||
if newApikey != workflowExecution.Authorization {
|
||||
log.Printf("Bad apikey for execution %s. %s vs %s", executionId[0], apikey, workflowExecution.Authorization)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Authorization is correct for execution %s! %s vs %s", executionId, apikey, workflowExecution.Authorization)
|
||||
setOrgId = true
|
||||
} else {
|
||||
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Verify if the user has access to the file: org_id and workflow
|
||||
@@ -8037,6 +8036,11 @@ func handleGetFileContent(resp http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// This is a workaround for file grabs from an app
|
||||
if setOrgId == true {
|
||||
user.ActiveOrg.Id = file.OrgId
|
||||
}
|
||||
|
||||
found := false
|
||||
if file.OrgId == user.ActiveOrg.Id {
|
||||
found = true
|
||||
|
||||
+17
-13
@@ -1089,14 +1089,14 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Updating %s in %s from %s to %s", actionResult.Action.ID, workflowExecution.ExecutionId, workflowExecution.Results[outerindex].Status, actionResult.Status)
|
||||
log.Printf("[INFO] Updating %s in %s from %s to %s", actionResult.Action.ID, workflowExecution.ExecutionId, workflowExecution.Results[outerindex].Status, actionResult.Status)
|
||||
workflowExecution.Results[outerindex] = actionResult
|
||||
} else {
|
||||
log.Printf("Setting value of %s in %s to %s", actionResult.Action.ID, workflowExecution.ExecutionId, actionResult.Status)
|
||||
log.Printf("[INFO] Setting value of %s in %s to %s", actionResult.Action.ID, workflowExecution.ExecutionId, actionResult.Status)
|
||||
workflowExecution.Results = append(workflowExecution.Results, actionResult)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Setting value of %s in %s to %s", actionResult.Action.ID, workflowExecution.ExecutionId, actionResult.Status)
|
||||
log.Printf("[INFO] Setting value of %s in %s to %s", actionResult.Action.ID, workflowExecution.ExecutionId, actionResult.Status)
|
||||
workflowExecution.Results = append(workflowExecution.Results, actionResult)
|
||||
}
|
||||
|
||||
@@ -1179,7 +1179,7 @@ func handleWorkflowQueue(resp http.ResponseWriter, request *http.Request) {
|
||||
_ = skippedNodes
|
||||
|
||||
if finished {
|
||||
log.Printf("Execution of %s finished.", workflowExecution.ExecutionId)
|
||||
log.Printf("[INFO] Execution of %s finished.", workflowExecution.ExecutionId)
|
||||
//log.Println("Might be finished based on length of results and everything being SUCCESS or FINISHED - VERIFY THIS. Setting status to finished.")
|
||||
|
||||
workflowExecution.Result = lastResult
|
||||
@@ -1316,15 +1316,15 @@ func handleExecutionStatistics(execution WorkflowExecution) {
|
||||
for _, exampleresult := range appResults {
|
||||
err := setExampleresult(ctx, exampleresult)
|
||||
if err != nil {
|
||||
log.Printf("Failed setting examplresult %s: %s", exampleresult.ExampleId, err)
|
||||
log.Printf("[ERROR] Failed setting examplresult %s: %s", exampleresult.ExampleId, err)
|
||||
} else {
|
||||
successful += 1
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Added %d exampleresults to backend", successful)
|
||||
log.Printf("[INFO] Added %d exampleresults to backend", successful)
|
||||
} else {
|
||||
log.Printf("No example results necessary to be added for execution %s", execution.ExecutionId)
|
||||
log.Printf("[INFO] No example results necessary to be added for execution %s", execution.ExecutionId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1438,6 +1438,7 @@ func setNewWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
workflow.ID = uuid.NewV4().String()
|
||||
workflow.Owner = user.Id
|
||||
workflow.Sharing = "private"
|
||||
user.ActiveOrg.Users = []User{}
|
||||
workflow.ExecutingOrg = user.ActiveOrg
|
||||
workflow.OrgId = user.ActiveOrg.Id
|
||||
|
||||
@@ -1816,7 +1817,8 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
if len(workflow.ExecutingOrg.Id) == 0 {
|
||||
log.Printf("setting executing org")
|
||||
log.Printf("Setting executing org for workflow")
|
||||
user.ActiveOrg.Users = []User{}
|
||||
workflow.ExecutingOrg = user.ActiveOrg
|
||||
}
|
||||
|
||||
@@ -2339,17 +2341,17 @@ func abortExecution(resp http.ResponseWriter, request *http.Request) {
|
||||
|
||||
// FIXME - have a check for org etc too..
|
||||
if user.Id != workflowExecution.Workflow.Owner && user.Role != "admin" {
|
||||
log.Printf("Wrong user (%s) for workflowexecution workflow %s", user.Username, workflowExecution.Workflow.ID)
|
||||
log.Printf("[INFO] Wrong user (%s) for workflowexecution workflow %s", user.Username, workflowExecution.Workflow.ID)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(`{"success": false}`))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.Printf("API key to abort/finish execution %s is correct.", executionId)
|
||||
log.Printf("[INFO] API key to abort/finish execution %s is correct.", executionId)
|
||||
}
|
||||
|
||||
if workflowExecution.Status == "ABORTED" || workflowExecution.Status == "FAILURE" || workflowExecution.Status == "FINISHED" {
|
||||
log.Printf("Stopped execution of %s with status %s", executionId, workflowExecution.Status)
|
||||
log.Printf("[INFO] Stopped execution of %s with status %s", executionId, workflowExecution.Status)
|
||||
resp.WriteHeader(401)
|
||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Status for %s is %s, which can't be aborted."}`, executionId, workflowExecution.Status)))
|
||||
return
|
||||
@@ -2461,7 +2463,7 @@ func handleExecution(id string, workflow Workflow, request *http.Request) (Workf
|
||||
}
|
||||
|
||||
if len(workflow.ExecutingOrg.Id) == 0 {
|
||||
log.Printf("Stopped execution because there is no executing org for workflow %s", workflow.ID)
|
||||
log.Printf("[INFO] Stopped execution because there is no executing org for workflow %s", workflow.ID)
|
||||
return WorkflowExecution{}, fmt.Sprintf("Workflow has no executing org defined"), errors.New("Workflow has no executing org defined")
|
||||
}
|
||||
|
||||
@@ -2479,7 +2481,7 @@ func handleExecution(id string, workflow Workflow, request *http.Request) (Workf
|
||||
}
|
||||
|
||||
if !workflow.IsValid {
|
||||
log.Printf("Stopped execution as workflow %s is not valid.", workflow.ID)
|
||||
log.Printf("[ERROR] Stopped execution as workflow %s is not valid.", workflow.ID)
|
||||
return WorkflowExecution{}, fmt.Sprintf(`workflow %s is invalid`, workflow.ID), errors.New("Failed getting workflow")
|
||||
}
|
||||
|
||||
@@ -3104,6 +3106,8 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Starting execution of %s!", fileId)
|
||||
|
||||
user.ActiveOrg.Users = []User{}
|
||||
workflow.ExecutingOrg = user.ActiveOrg
|
||||
workflowExecution, executionResp, err := handleExecution(fileId, *workflow, request)
|
||||
|
||||
|
||||
@@ -2836,7 +2836,16 @@ const AngularWorkflow = (props) => {
|
||||
}}
|
||||
/>
|
||||
|
||||
if (selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0) {
|
||||
console.log(selectedActionParameters[count])
|
||||
if (selectedActionParameters[count].schema !== undefined && selectedActionParameters[count].schema !== null && selectedActionParameters[count].schema.type === "file") {
|
||||
const fileId = "6daabec1-892b-469c-b603-c902e47223a9"
|
||||
datafield = `SHOW FILES FROM OTHER NODES? Filename: ${selectedActionParameters[count].value}`
|
||||
if (selectedActionParameters[count].value != fileId) {
|
||||
changeActionParameter(fileId, count)
|
||||
setUpdate(Math.random())
|
||||
|
||||
}
|
||||
} else if (selectedActionParameters[count].options !== undefined && selectedActionParameters[count].options !== null && selectedActionParameters[count].options.length > 0) {
|
||||
if (selectedActionParameters[count].value === "" && selectedActionParameters[count].required) {
|
||||
// Rofl, dirty workaround :)
|
||||
const e = {
|
||||
|
||||
Reference in New Issue
Block a user