@@ -44,15 +44,6 @@ type (
|
||||
}
|
||||
|
||||
Mitigations []*Mitigation
|
||||
|
||||
UpdateMitigationParams struct {
|
||||
ExpectedVersion int
|
||||
Name *string
|
||||
Description *string
|
||||
Category *string
|
||||
State *MitigationState
|
||||
Importance *MitigationImportance
|
||||
}
|
||||
)
|
||||
|
||||
func (c Mitigation) CursorKey(orderBy MitigationOrderField) page.CursorKey {
|
||||
@@ -223,60 +214,33 @@ func (c *Mitigation) Update(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
params UpdateMitigationParams,
|
||||
) error {
|
||||
q := `
|
||||
UPDATE mitigations SET
|
||||
name = COALESCE(@name, name),
|
||||
description = COALESCE(@description, description),
|
||||
category = COALESCE(@category, category),
|
||||
state = COALESCE(@state, state),
|
||||
importance = COALESCE(@importance, importance),
|
||||
updated_at = @updated_at,
|
||||
version = version + 1
|
||||
UPDATE mitigations
|
||||
SET
|
||||
name = @name,
|
||||
description = @description,
|
||||
category = @category,
|
||||
state = @state,
|
||||
importance = @importance,
|
||||
updated_at = @updated_at
|
||||
WHERE %s
|
||||
AND id = @mitigation_id
|
||||
AND version = @expected_version
|
||||
RETURNING
|
||||
id,
|
||||
organization_id,
|
||||
category,
|
||||
name,
|
||||
description,
|
||||
importance,
|
||||
state,
|
||||
content_ref,
|
||||
created_at,
|
||||
updated_at,
|
||||
standards,
|
||||
version
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.NamedArgs{
|
||||
"mitigation_id": c.ID,
|
||||
"expected_version": params.ExpectedVersion,
|
||||
"name": params.Name,
|
||||
"description": params.Description,
|
||||
"category": params.Category,
|
||||
"state": params.State,
|
||||
"importance": params.Importance,
|
||||
"updated_at": time.Now(),
|
||||
"mitigation_id": c.ID,
|
||||
"name": c.Name,
|
||||
"description": c.Description,
|
||||
"category": c.Category,
|
||||
"state": c.State,
|
||||
"importance": c.Importance,
|
||||
"updated_at": c.UpdatedAt,
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query mitigations: %w", err)
|
||||
}
|
||||
|
||||
mitigation, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Mitigation])
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot collect mitigations: %w", err)
|
||||
}
|
||||
|
||||
*c = mitigation
|
||||
|
||||
return nil
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -42,14 +42,6 @@ type (
|
||||
}
|
||||
|
||||
Tasks []*Task
|
||||
|
||||
UpdateTaskParams struct {
|
||||
ExpectedVersion int
|
||||
Name *string
|
||||
Description *string
|
||||
State *TaskState
|
||||
TimeEstimate *time.Duration
|
||||
}
|
||||
)
|
||||
|
||||
func (c Task) CursorKey(orderBy TaskOrderField) page.CursorKey {
|
||||
@@ -210,58 +202,33 @@ func (c *Task) Update(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
params UpdateTaskParams,
|
||||
) error {
|
||||
q := `
|
||||
UPDATE tasks SET
|
||||
name = COALESCE(@name, name),
|
||||
description = COALESCE(@description, description),
|
||||
state = COALESCE(@state, state),
|
||||
time_estimate = COALESCE(@time_estimate, time_estimate),
|
||||
updated_at = @updated_at,
|
||||
version = version + 1
|
||||
UPDATE tasks
|
||||
SET
|
||||
name = @name,
|
||||
description = @description,
|
||||
state = @state,
|
||||
time_estimate = @time_estimate,
|
||||
updated_at = @updated_at
|
||||
WHERE %s
|
||||
AND id = @task_id
|
||||
AND version = @expected_version
|
||||
RETURNING
|
||||
id,
|
||||
mitigation_id,
|
||||
name,
|
||||
description,
|
||||
state,
|
||||
time_estimate,
|
||||
assigned_to,
|
||||
created_at,
|
||||
updated_at,
|
||||
version
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.NamedArgs{
|
||||
"task_id": c.ID,
|
||||
"expected_version": params.ExpectedVersion,
|
||||
"name": params.Name,
|
||||
"description": params.Description,
|
||||
"state": params.State,
|
||||
"time_estimate": params.TimeEstimate,
|
||||
"updated_at": time.Now(),
|
||||
"task_id": c.ID,
|
||||
"name": c.Name,
|
||||
"description": c.Description,
|
||||
"state": c.State,
|
||||
"time_estimate": c.TimeEstimate,
|
||||
"updated_at": c.UpdatedAt,
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query tasks: %w", err)
|
||||
}
|
||||
|
||||
task, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Task])
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot collect tasks: %w", err)
|
||||
}
|
||||
|
||||
*c = task
|
||||
|
||||
return nil
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Task) AssignTo(
|
||||
@@ -387,94 +354,3 @@ WHERE %s
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper functions for task management
|
||||
|
||||
var (
|
||||
ErrAssignTaskFailed = fmt.Errorf("failed to assign task")
|
||||
ErrUnassignTaskFailed = fmt.Errorf("failed to unassign task")
|
||||
ErrUpdateTaskFailed = fmt.Errorf("failed to update task")
|
||||
ErrDeleteTaskFailed = fmt.Errorf("failed to delete task")
|
||||
)
|
||||
|
||||
type TaskUpdate struct {
|
||||
Name *string
|
||||
Description *string
|
||||
State *TaskState
|
||||
TimeEstimate *time.Duration
|
||||
}
|
||||
|
||||
func AssignTask(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
taskID gid.GID,
|
||||
assignedToID gid.GID,
|
||||
) (*Task, error) {
|
||||
task := &Task{ID: taskID}
|
||||
if err := task.LoadByID(ctx, conn, scope, taskID); err != nil {
|
||||
return nil, ErrAssignTaskFailed
|
||||
}
|
||||
|
||||
if err := task.AssignTo(ctx, conn, scope, assignedToID); err != nil {
|
||||
return nil, ErrAssignTaskFailed
|
||||
}
|
||||
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func UnassignTask(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
taskID gid.GID,
|
||||
) (*Task, error) {
|
||||
task := &Task{ID: taskID}
|
||||
if err := task.LoadByID(ctx, conn, scope, taskID); err != nil {
|
||||
return nil, ErrUnassignTaskFailed
|
||||
}
|
||||
|
||||
if err := task.Unassign(ctx, conn, scope); err != nil {
|
||||
return nil, ErrUnassignTaskFailed
|
||||
}
|
||||
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func UpdateTask(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
taskID gid.GID,
|
||||
expectedVersion int,
|
||||
updates *TaskUpdate,
|
||||
) (*Task, error) {
|
||||
task := &Task{ID: taskID}
|
||||
|
||||
if err := task.Update(ctx, conn, scope, UpdateTaskParams{
|
||||
ExpectedVersion: expectedVersion,
|
||||
Name: updates.Name,
|
||||
Description: updates.Description,
|
||||
State: updates.State,
|
||||
TimeEstimate: updates.TimeEstimate,
|
||||
}); err != nil {
|
||||
return nil, ErrUpdateTaskFailed
|
||||
}
|
||||
|
||||
return task, nil
|
||||
}
|
||||
|
||||
func DeleteTask(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
taskID gid.GID,
|
||||
) error {
|
||||
task := &Task{ID: taskID}
|
||||
|
||||
if err := task.Delete(ctx, conn, scope); err != nil {
|
||||
return ErrDeleteTaskFailed
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -39,13 +39,12 @@ type (
|
||||
}
|
||||
|
||||
UpdateMitigationRequest struct {
|
||||
ID gid.GID
|
||||
ExpectedVersion int
|
||||
Name *string
|
||||
Description *string
|
||||
Category *string
|
||||
State *coredata.MitigationState
|
||||
Importance *coredata.MitigationImportance
|
||||
ID gid.GID
|
||||
Name *string
|
||||
Description *string
|
||||
Category *string
|
||||
State *coredata.MitigationState
|
||||
Importance *coredata.MitigationImportance
|
||||
}
|
||||
)
|
||||
|
||||
@@ -73,22 +72,44 @@ func (s MitigationService) Update(
|
||||
ctx context.Context,
|
||||
req UpdateMitigationRequest,
|
||||
) (*coredata.Mitigation, error) {
|
||||
params := coredata.UpdateMitigationParams{
|
||||
ExpectedVersion: req.ExpectedVersion,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
Category: req.Category,
|
||||
State: req.State,
|
||||
Importance: req.Importance,
|
||||
}
|
||||
|
||||
mitigation := &coredata.Mitigation{ID: req.ID}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return mitigation.Update(ctx, conn, s.svc.scope, params)
|
||||
})
|
||||
if err := mitigation.LoadByID(ctx, conn, s.svc.scope, req.ID); err != nil {
|
||||
return fmt.Errorf("cannot load mitigation: %w", err)
|
||||
}
|
||||
|
||||
if req.Name != nil {
|
||||
mitigation.Name = *req.Name
|
||||
}
|
||||
|
||||
if req.Description != nil {
|
||||
mitigation.Description = *req.Description
|
||||
}
|
||||
|
||||
if req.Category != nil {
|
||||
mitigation.Category = *req.Category
|
||||
}
|
||||
|
||||
if req.State != nil {
|
||||
mitigation.State = *req.State
|
||||
}
|
||||
|
||||
if req.Importance != nil {
|
||||
mitigation.Importance = *req.Importance
|
||||
}
|
||||
|
||||
mitigation.UpdatedAt = time.Now()
|
||||
|
||||
if err := mitigation.Update(ctx, conn, s.svc.scope); err != nil {
|
||||
return fmt.Errorf("cannot update mitigation: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package probo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -40,12 +39,11 @@ type (
|
||||
}
|
||||
|
||||
UpdateTaskRequest struct {
|
||||
TaskID gid.GID
|
||||
ExpectedVersion int
|
||||
Name *string
|
||||
Description *string
|
||||
State *coredata.TaskState
|
||||
TimeEstimate *time.Duration
|
||||
TaskID gid.GID
|
||||
Name *string
|
||||
Description *string
|
||||
State *coredata.TaskState
|
||||
TimeEstimate *time.Duration
|
||||
}
|
||||
)
|
||||
|
||||
@@ -114,20 +112,15 @@ func (s TaskService) Assign(
|
||||
taskID gid.GID,
|
||||
assignedToID gid.GID,
|
||||
) (*coredata.Task, error) {
|
||||
task := &coredata.Task{}
|
||||
task := &coredata.Task{ID: taskID}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
var assignErr error
|
||||
task, assignErr = coredata.AssignTask(ctx, conn, s.svc.scope, taskID, assignedToID)
|
||||
return assignErr
|
||||
return task.AssignTo(ctx, conn, s.svc.scope, assignedToID)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrAssignTaskFailed) {
|
||||
return nil, errors.New("failed to assign task, please try again")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -138,20 +131,15 @@ func (s TaskService) Unassign(
|
||||
ctx context.Context,
|
||||
taskID gid.GID,
|
||||
) (*coredata.Task, error) {
|
||||
task := &coredata.Task{}
|
||||
task := &coredata.Task{ID: taskID}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
var unassignErr error
|
||||
task, unassignErr = coredata.UnassignTask(ctx, conn, s.svc.scope, taskID)
|
||||
return unassignErr
|
||||
return task.Unassign(ctx, conn, s.svc.scope)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrUnassignTaskFailed) {
|
||||
return nil, errors.New("failed to unassign task, please try again")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -162,32 +150,41 @@ func (s TaskService) Update(
|
||||
ctx context.Context,
|
||||
req UpdateTaskRequest,
|
||||
) (*coredata.Task, error) {
|
||||
task := &coredata.Task{}
|
||||
task := &coredata.Task{ID: req.TaskID}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
var updateErr error
|
||||
task, updateErr = coredata.UpdateTask(
|
||||
ctx,
|
||||
conn,
|
||||
s.svc.scope,
|
||||
req.TaskID,
|
||||
req.ExpectedVersion,
|
||||
&coredata.TaskUpdate{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
State: req.State,
|
||||
TimeEstimate: req.TimeEstimate,
|
||||
},
|
||||
)
|
||||
return updateErr
|
||||
if err := task.LoadByID(ctx, conn, s.svc.scope, req.TaskID); err != nil {
|
||||
return fmt.Errorf("cannot load task %q: %w", req.TaskID, err)
|
||||
}
|
||||
|
||||
if req.Name != nil {
|
||||
task.Name = *req.Name
|
||||
}
|
||||
|
||||
if req.Description != nil {
|
||||
task.Description = *req.Description
|
||||
}
|
||||
|
||||
if req.State != nil {
|
||||
task.State = *req.State
|
||||
}
|
||||
|
||||
if req.TimeEstimate != nil {
|
||||
task.TimeEstimate = req.TimeEstimate
|
||||
}
|
||||
|
||||
task.UpdatedAt = time.Now()
|
||||
|
||||
if err := task.Update(ctx, conn, s.svc.scope); err != nil {
|
||||
return fmt.Errorf("cannot update task: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrUpdateTaskFailed) {
|
||||
return nil, errors.New("failed to update task, please try again")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -198,16 +195,15 @@ func (s TaskService) Delete(
|
||||
ctx context.Context,
|
||||
taskID gid.GID,
|
||||
) error {
|
||||
task := &coredata.Task{ID: taskID}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return coredata.DeleteTask(ctx, conn, s.svc.scope, taskID)
|
||||
return task.Delete(ctx, conn, s.svc.scope)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, coredata.ErrDeleteTaskFailed) {
|
||||
return errors.New("failed to delete task, please try again")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,10 @@ enum MitigationOrderField
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/coredata.MitigationOrderField"
|
||||
) {
|
||||
NAME
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/coredata.MitigationOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum TaskOrderField
|
||||
|
||||
@@ -2409,7 +2409,10 @@ enum MitigationOrderField
|
||||
@goModel(
|
||||
model: "github.com/getprobo/probo/pkg/coredata.MitigationOrderField"
|
||||
) {
|
||||
NAME
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "github.com/getprobo/probo/pkg/coredata.MitigationOrderFieldCreatedAt"
|
||||
)
|
||||
}
|
||||
|
||||
enum TaskOrderField
|
||||
@@ -23057,12 +23060,12 @@ var (
|
||||
|
||||
func (ec *executionContext) unmarshalNMitigationOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationOrderField(ctx context.Context, v any) (coredata.MitigationOrderField, error) {
|
||||
tmp, err := graphql.UnmarshalString(v)
|
||||
res := coredata.MitigationOrderField(tmp)
|
||||
res := unmarshalNMitigationOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationOrderField[tmp]
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNMitigationOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationOrderField(ctx context.Context, sel ast.SelectionSet, v coredata.MitigationOrderField) graphql.Marshaler {
|
||||
res := graphql.MarshalString(string(v))
|
||||
res := graphql.MarshalString(marshalNMitigationOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationOrderField[v])
|
||||
if res == graphql.Null {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||
@@ -23071,6 +23074,15 @@ func (ec *executionContext) marshalNMitigationOrderField2githubᚗcomᚋgetprobo
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalNMitigationOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationOrderField = map[string]coredata.MitigationOrderField{
|
||||
"CREATED_AT": coredata.MitigationOrderFieldCreatedAt,
|
||||
}
|
||||
marshalNMitigationOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationOrderField = map[coredata.MitigationOrderField]string{
|
||||
coredata.MitigationOrderFieldCreatedAt: "CREATED_AT",
|
||||
}
|
||||
)
|
||||
|
||||
func (ec *executionContext) unmarshalNMitigationState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationState(ctx context.Context, v any) (coredata.MitigationState, error) {
|
||||
tmp, err := graphql.UnmarshalString(v)
|
||||
res := unmarshalNMitigationState2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐMitigationState[tmp]
|
||||
|
||||
@@ -372,20 +372,6 @@ func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.Upda
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteFramework is the resolver for the deleteFramework field.
|
||||
func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) {
|
||||
svc := r.GetTenantServiceIfAuthorized(ctx, input.FrameworkID.TenantID())
|
||||
|
||||
err := svc.Frameworks.Delete(ctx, input.FrameworkID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete framework: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteFrameworkPayload{
|
||||
DeletedFrameworkID: input.FrameworkID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ImportFramework is the resolver for the importFramework field.
|
||||
func (r *mutationResolver) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) {
|
||||
svc := r.GetTenantServiceIfAuthorized(ctx, input.OrganizationID.TenantID())
|
||||
@@ -405,6 +391,20 @@ func (r *mutationResolver) ImportFramework(ctx context.Context, input types.Impo
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteFramework is the resolver for the deleteFramework field.
|
||||
func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) {
|
||||
svc := r.GetTenantServiceIfAuthorized(ctx, input.FrameworkID.TenantID())
|
||||
|
||||
err := svc.Frameworks.Delete(ctx, input.FrameworkID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot delete framework: %w", err)
|
||||
}
|
||||
|
||||
return &types.DeleteFrameworkPayload{
|
||||
DeletedFrameworkID: input.FrameworkID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// // CreateMitigation is the resolver for the createMitigation field.
|
||||
func (r *mutationResolver) CreateMitigation(ctx context.Context, input types.CreateMitigationInput) (*types.CreateMitigationPayload, error) {
|
||||
svc := r.GetTenantServiceIfAuthorized(ctx, input.OrganizationID.TenantID())
|
||||
|
||||
Reference in New Issue
Block a user