From 7318f1b795218f781764e4b61bd6194fbc1d132d Mon Sep 17 00:00:00 2001 From: Onat <53895969+onattech@users.noreply.github.com> Date: Sun, 27 Mar 2022 12:48:20 +0300 Subject: [PATCH 1/4] Added rename file/folder endpoints in the backend --- app/mainapp/graphql/private/generated.go | 143 +++++++++++++++++- .../private/resolvers/code_editor.graphqls | 9 +- .../resolvers/code_editor.resolvers.go | 99 +++++++++++- 3 files changed, 241 insertions(+), 10 deletions(-) diff --git a/app/mainapp/graphql/private/generated.go b/app/mainapp/graphql/private/generated.go index f69414fe6..6e4f3b83f 100644 --- a/app/mainapp/graphql/private/generated.go +++ b/app/mainapp/graphql/private/generated.go @@ -125,7 +125,8 @@ type ComplexityRoot struct { PipelinePermissionsToUser func(childComplexity int, environmentID string, resourceID string, access []string, userID string) int RemoveUserFromAccessGroup func(childComplexity int, userID string, accessGroupID string, environmentID string) int RemoveUserFromEnvironment func(childComplexity int, userID string, environmentID string) int - RenameFolder func(childComplexity int, environmentID string, folderID string, nodeID string, pipelineID string) int + RenameFile func(childComplexity int, environmentID string, fileID string, nodeID string, pipelineID string, newName string) int + RenameFolder func(childComplexity int, environmentID string, folderID string, nodeID string, pipelineID string, newName string) int RunPipelines func(childComplexity int, pipelineID string, environmentID string) int StopPipelines func(childComplexity int, pipelineID string, runID string, environmentID string) int TurnOnOffPipeline func(childComplexity int, environmentID string, pipelineID string, online bool) int @@ -396,9 +397,10 @@ type MutationResolver interface { CreateFolderNode(ctx context.Context, input *FolderNodeInput) (*models.CodeFolders, error) MoveFolderNode(ctx context.Context, folderID string, toFolderID string, environmentID string, pipelineID string) (string, error) DeleteFolderNode(ctx context.Context, environmentID string, folderID string, nodeID string, pipelineID string) (string, error) - RenameFolder(ctx context.Context, environmentID string, folderID string, nodeID string, pipelineID string) (string, error) + RenameFolder(ctx context.Context, environmentID string, folderID string, nodeID string, pipelineID string, newName string) (string, error) UploadFileNode(ctx context.Context, environmentID string, nodeID string, pipelineID string, folderID string, file graphql.Upload) (string, error) DeleteFileNode(ctx context.Context, environmentID string, fileID string, nodeID string, pipelineID string) (string, error) + RenameFile(ctx context.Context, environmentID string, fileID string, nodeID string, pipelineID string, newName string) (string, error) MoveFileNode(ctx context.Context, fileID string, toFolderID string, environmentID string, pipelineID string) (string, error) CodeEditorRun(ctx context.Context, environmentID string, nodeID string, pipelineID string, path string) (string, error) UpdateMe(ctx context.Context, input *AddUpdateMeInput) (*models.Users, error) @@ -1002,6 +1004,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.RemoveUserFromEnvironment(childComplexity, args["user_id"].(string), args["environment_id"].(string)), true + case "Mutation.renameFile": + if e.complexity.Mutation.RenameFile == nil { + break + } + + args, err := ec.field_Mutation_renameFile_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RenameFile(childComplexity, args["environmentID"].(string), args["fileID"].(string), args["nodeID"].(string), args["pipelineID"].(string), args["newName"].(string)), true + case "Mutation.renameFolder": if e.complexity.Mutation.RenameFolder == nil { break @@ -1012,7 +1026,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.RenameFolder(childComplexity, args["environmentID"].(string), args["folderID"].(string), args["nodeID"].(string), args["pipelineID"].(string)), true + return e.complexity.Mutation.RenameFolder(childComplexity, args["environmentID"].(string), args["folderID"].(string), args["nodeID"].(string), args["pipelineID"].(string), args["newName"].(string)), true case "Mutation.runPipelines": if e.complexity.Mutation.RunPipelines == nil { @@ -2977,7 +2991,7 @@ extend type Mutation { + **Route**: Private + **Permissions**: admin_platform, platform_environment, specific_pipeline[write] """ - renameFolder(environmentID: String!, folderID: String!, nodeID: String!, pipelineID: String!): String! + renameFolder(environmentID: String!, folderID: String!, nodeID: String!, pipelineID: String!, newName: String!): String! """ Upload a node file. @@ -2993,7 +3007,14 @@ extend type Mutation { """ deleteFileNode(environmentID: String!, fileID: String!, nodeID: String!, pipelineID: String!): String! + """ + Rename a file. + + **Route**: Private + + **Permissions**: admin_platform, platform_environment, specific_pipeline[write] """ + renameFile(environmentID: String!, fileID: String!, nodeID: String!, pipelineID: String!, newName: String!): String! + + """ Move a file. + **Route**: Private + **Permissions**: admin_platform, platform_environment, specific_pipeline[write] @@ -4449,6 +4470,57 @@ func (ec *executionContext) field_Mutation_removeUserFromEnvironment_args(ctx co return args, nil } +func (ec *executionContext) field_Mutation_renameFile_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["environmentID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("environmentID")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["environmentID"] = arg0 + var arg1 string + if tmp, ok := rawArgs["fileID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fileID")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["fileID"] = arg1 + var arg2 string + if tmp, ok := rawArgs["nodeID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nodeID")) + arg2, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["nodeID"] = arg2 + var arg3 string + if tmp, ok := rawArgs["pipelineID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pipelineID")) + arg3, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["pipelineID"] = arg3 + var arg4 string + if tmp, ok := rawArgs["newName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("newName")) + arg4, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["newName"] = arg4 + return args, nil +} + func (ec *executionContext) field_Mutation_renameFolder_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4488,6 +4560,15 @@ func (ec *executionContext) field_Mutation_renameFolder_args(ctx context.Context } } args["pipelineID"] = arg3 + var arg4 string + if tmp, ok := rawArgs["newName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("newName")) + arg4, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["newName"] = arg4 return args, nil } @@ -7678,7 +7759,7 @@ func (ec *executionContext) _Mutation_renameFolder(ctx context.Context, field gr fc.Args = args resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().RenameFolder(rctx, args["environmentID"].(string), args["folderID"].(string), args["nodeID"].(string), args["pipelineID"].(string)) + return ec.resolvers.Mutation().RenameFolder(rctx, args["environmentID"].(string), args["folderID"].(string), args["nodeID"].(string), args["pipelineID"].(string), args["newName"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -7779,6 +7860,48 @@ func (ec *executionContext) _Mutation_deleteFileNode(ctx context.Context, field return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_renameFile(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_renameFile_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RenameFile(rctx, args["environmentID"].(string), args["fileID"].(string), args["nodeID"].(string), args["pipelineID"].(string), args["newName"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) _Mutation_moveFileNode(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -17718,6 +17841,16 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { + invalids++ + } + case "renameFile": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_renameFile(ctx, field) + } + + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc) + if out.Values[i] == graphql.Null { invalids++ } diff --git a/app/mainapp/graphql/private/resolvers/code_editor.graphqls b/app/mainapp/graphql/private/resolvers/code_editor.graphqls index 25e234412..3e777b549 100644 --- a/app/mainapp/graphql/private/resolvers/code_editor.graphqls +++ b/app/mainapp/graphql/private/resolvers/code_editor.graphqls @@ -71,7 +71,7 @@ extend type Mutation { + **Route**: Private + **Permissions**: admin_platform, platform_environment, specific_pipeline[write] """ - renameFolder(environmentID: String!, folderID: String!, nodeID: String!, pipelineID: String!): String! + renameFolder(environmentID: String!, folderID: String!, nodeID: String!, pipelineID: String!, newName: String!): String! """ Upload a node file. @@ -87,7 +87,14 @@ extend type Mutation { """ deleteFileNode(environmentID: String!, fileID: String!, nodeID: String!, pipelineID: String!): String! + """ + Rename a file. + + **Route**: Private + + **Permissions**: admin_platform, platform_environment, specific_pipeline[write] """ + renameFile(environmentID: String!, fileID: String!, nodeID: String!, pipelineID: String!, newName: String!): String! + + """ Move a file. + **Route**: Private + **Permissions**: admin_platform, platform_environment, specific_pipeline[write] diff --git a/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go b/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go index 43462be49..414bb7a09 100644 --- a/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go +++ b/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go @@ -5,7 +5,7 @@ package privateresolvers import ( "context" - permissions "dataplane/mainapp/auth_permissions" + "dataplane/mainapp/auth_permissions" "dataplane/mainapp/config" "dataplane/mainapp/database" "dataplane/mainapp/database/models" @@ -13,7 +13,6 @@ import ( privategraphql "dataplane/mainapp/graphql/private" "dataplane/mainapp/logging" "errors" - "fmt" "log" "os" "os/exec" @@ -225,8 +224,52 @@ func (r *mutationResolver) DeleteFolderNode(ctx context.Context, environmentID s return "Success", nil } -func (r *mutationResolver) RenameFolder(ctx context.Context, environmentID string, folderID string, nodeID string, pipelineID string) (string, error) { - panic(fmt.Errorf("not implemented")) +func (r *mutationResolver) RenameFolder(ctx context.Context, environmentID string, folderID string, nodeID string, pipelineID string, newName string) (string, error) { + currentUser := ctx.Value("currentUser").(string) + platformID := ctx.Value("platformID").(string) + + // ----- Permissions + perms := []models.Permissions{ + {Subject: "user", SubjectID: currentUser, Resource: "admin_platform", ResourceID: platformID, Access: "write", EnvironmentID: "d_platform"}, + {Subject: "user", SubjectID: currentUser, Resource: "platform_environment", ResourceID: platformID, Access: "write", EnvironmentID: environmentID}, + {Subject: "user", SubjectID: currentUser, Resource: "environment_edit_all_pipelines", ResourceID: platformID, Access: "write", EnvironmentID: environmentID}, + {Subject: "user", SubjectID: currentUser, Resource: "specific_pipeline", ResourceID: pipelineID, Access: "write", EnvironmentID: environmentID}, + } + + permOutcome, _, _, _ := permissions.MultiplePermissionChecks(perms) + + if permOutcome == "denied" { + return "", errors.New("Requires permissions.") + } + + // Get parent's folder id + f := models.CodeFolders{} + err := database.DBConn.Where("folder_id = ?", folderID).Find(&f).Error + if err != nil { + return "", errors.New(err.Error()) + } + + parentFolderpath, _ := filesystem.FolderConstructByID(database.DBConn, f.ParentID, environmentID) + folderpath, _ := filesystem.FolderConstructByID(database.DBConn, folderID, environmentID) + + // Make sure there is a path + if strings.TrimSpace(folderpath) == "" || strings.TrimSpace(parentFolderpath) == "" { + return "", errors.New("Missing folder path.") + } + + // 1. ----- Rename folder in the directory + err = os.Rename(config.CodeDirectory+folderpath, config.CodeDirectory+parentFolderpath+folderID+"_"+newName) + if err != nil { + return "", errors.New(err.Error()) + } + + // 2. ----- Rename folder in the database + err = database.DBConn.Model(&models.CodeFolders{}).Where("folder_id = ? and environment_id = ?", folderID, environmentID).Update("folder_name", newName).Error + if err != nil { + return "", errors.New(err.Error()) + } + + return "Success", nil } func (r *mutationResolver) UploadFileNode(ctx context.Context, environmentID string, nodeID string, pipelineID string, folderID string, file graphql.Upload) (string, error) { @@ -363,6 +406,54 @@ func (r *mutationResolver) DeleteFileNode(ctx context.Context, environmentID str return "Success", nil } +func (r *mutationResolver) RenameFile(ctx context.Context, environmentID string, fileID string, nodeID string, pipelineID string, newName string) (string, error) { + currentUser := ctx.Value("currentUser").(string) + platformID := ctx.Value("platformID").(string) + + // ----- Permissions + perms := []models.Permissions{ + {Subject: "user", SubjectID: currentUser, Resource: "admin_platform", ResourceID: platformID, Access: "write", EnvironmentID: "d_platform"}, + {Subject: "user", SubjectID: currentUser, Resource: "platform_environment", ResourceID: platformID, Access: "write", EnvironmentID: environmentID}, + {Subject: "user", SubjectID: currentUser, Resource: "environment_edit_all_pipelines", ResourceID: platformID, Access: "write", EnvironmentID: environmentID}, + {Subject: "user", SubjectID: currentUser, Resource: "specific_pipeline", ResourceID: pipelineID, Access: "write", EnvironmentID: environmentID}, + } + + permOutcome, _, _, _ := permissions.MultiplePermissionChecks(perms) + + if permOutcome == "denied" { + return "", errors.New("Requires permissions.") + } + + // Get parent's folder id + f := models.CodeFiles{} + err := database.DBConn.Where("file_id = ?", fileID).Find(&f).Error + if err != nil { + return "", errors.New(err.Error()) + } + + folderpath, _ := filesystem.FolderConstructByID(database.DBConn, f.FolderID, environmentID) + filepath, _ := filesystem.FileConstructByID(database.DBConn, fileID, environmentID) + + // Make sure there is a path + if strings.TrimSpace(filepath) == "" || strings.TrimSpace(folderpath) == "" { + return "", errors.New("Missing folder path.") + } + + // // 1. ----- Rename file in the directory + err = os.Rename(config.CodeDirectory+filepath, config.CodeDirectory+folderpath+newName) + if err != nil { + return "", errors.New(err.Error()) + } + + // // 2. ----- Rename file in the database + err = database.DBConn.Model(&models.CodeFiles{}).Where("file_id = ? and environment_id = ?", fileID, environmentID).Update("file_name", newName).Error + if err != nil { + return "", errors.New(err.Error()) + } + + return "Success", nil +} + func (r *mutationResolver) MoveFileNode(ctx context.Context, fileID string, toFolderID string, environmentID string, pipelineID string) (string, error) { currentUser := ctx.Value("currentUser").(string) platformID := ctx.Value("platformID").(string) From 43c6808447910c6d6937c0f81fbd300b3efffd50 Mon Sep 17 00:00:00 2001 From: Onat <53895969+onattech@users.noreply.github.com> Date: Sun, 27 Mar 2022 13:15:51 +0300 Subject: [PATCH 2/4] Fixed pipeline id not showing in the db on file creation --- app/mainapp/graphql/private/resolvers/code_editor.resolvers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go b/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go index 414bb7a09..f2621adf9 100644 --- a/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go +++ b/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go @@ -5,7 +5,7 @@ package privateresolvers import ( "context" - "dataplane/mainapp/auth_permissions" + permissions "dataplane/mainapp/auth_permissions" "dataplane/mainapp/config" "dataplane/mainapp/database" "dataplane/mainapp/database/models" @@ -296,6 +296,7 @@ func (r *mutationResolver) UploadFileNode(ctx context.Context, environmentID str file.File.Read(p) input := models.CodeFiles{ + PipelineID: pipelineID, EnvironmentID: environmentID, NodeID: nodeID, FileName: file.Filename, From 45e561126df298097bd41cf93f652a38f5c55feb Mon Sep 17 00:00:00 2001 From: Onat <53895969+onattech@users.noreply.github.com> Date: Sun, 27 Mar 2022 13:32:04 +0300 Subject: [PATCH 3/4] Added environment_id to db queries --- .../graphql/private/resolvers/code_editor.resolvers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go b/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go index f2621adf9..169fce4b1 100644 --- a/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go +++ b/app/mainapp/graphql/private/resolvers/code_editor.resolvers.go @@ -108,7 +108,7 @@ func (r *mutationResolver) MoveFolderNode(ctx context.Context, folderID string, // Update folder's parent in the database err = database.DBConn.Model(&models.CodeFolders{}). - Where("folder_id = ?", folderID).Update("parent_id", toFolderID).Error + Where("folder_id = ? and environment_id = ?", folderID, environmentID).Update("parent_id", toFolderID).Error if err != nil { return "", errors.New(err.Error()) } @@ -244,7 +244,7 @@ func (r *mutationResolver) RenameFolder(ctx context.Context, environmentID strin // Get parent's folder id f := models.CodeFolders{} - err := database.DBConn.Where("folder_id = ?", folderID).Find(&f).Error + err := database.DBConn.Where("folder_id = ? and environment_id = ?", folderID, environmentID).Find(&f).Error if err != nil { return "", errors.New(err.Error()) } @@ -427,7 +427,7 @@ func (r *mutationResolver) RenameFile(ctx context.Context, environmentID string, // Get parent's folder id f := models.CodeFiles{} - err := database.DBConn.Where("file_id = ?", fileID).Find(&f).Error + err := database.DBConn.Where("file_id = ? and environment_id = ?", fileID, environmentID).Find(&f).Error if err != nil { return "", errors.New(err.Error()) } From d1ddd6a7ddbef9e001a90b59fd3f4ef6cd6ba6ed Mon Sep 17 00:00:00 2001 From: Onat <53895969+onattech@users.noreply.github.com> Date: Sun, 27 Mar 2022 13:42:03 +0300 Subject: [PATCH 4/4] Added missing select field on file_construct_id.go --- app/mainapp/filesystem/file_construct_id.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mainapp/filesystem/file_construct_id.go b/app/mainapp/filesystem/file_construct_id.go index 43efd30f5..5d32ce7d4 100644 --- a/app/mainapp/filesystem/file_construct_id.go +++ b/app/mainapp/filesystem/file_construct_id.go @@ -10,7 +10,7 @@ import ( func FileConstructByID(db *gorm.DB, id string, environmentID string) (string, error) { var currentFile models.CodeFiles - db.Select("file_name").Where("file_id=? and environment_id = ?", id, environmentID).First(¤tFile) + db.Select("file_name", "folder_id").Where("file_id=? and environment_id = ?", id, environmentID).First(¤tFile) fileName := currentFile.FileName folderID := currentFile.FolderID