diff --git a/pkg/api/console/v1/v1_resolver.go b/pkg/api/console/v1/v1_resolver.go index ad7e12811..00d801c65 100644 --- a/pkg/api/console/v1/v1_resolver.go +++ b/pkg/api/console/v1/v1_resolver.go @@ -131,6 +131,13 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error } return types.NewFramework(framework), nil + case coredata.ControlEntityType: + control, err := r.svc.GetControl(ctx, id) + if err != nil { + return nil, err + } + + return types.NewControl(control), nil default: } diff --git a/pkg/probo/coredata/control.go b/pkg/probo/coredata/control.go index 6c5939cb8..03ee70e25 100644 --- a/pkg/probo/coredata/control.go +++ b/pkg/probo/coredata/control.go @@ -60,6 +60,63 @@ func (c *Control) scan(r pgx.Row) error { ) } +func (v *Control) LoadByID( + ctx context.Context, + conn pg.Conn, + scope *Scope, + controlID gid.GID, +) error { + q := ` +WITH control_states AS ( + SELECT + control_id, + to_state, + reason, + RANK() OVER w + FROM + control_state_transitions + WHERE + control_id = @control_id + WINDOW + w AS (PARTITION BY control_id ORDER BY created_at DESC) +) +SELECT + id, + framework_id, + name, + description, + cs.to_state AS state, + content_ref, + created_at, + updated_at +FROM + controls +INNER JOIN + control_states cs ON cs.control_id = controls.id +WHERE + %s + AND id = @control_id + AND cs.rank = 1 +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.NamedArgs{"control_id": controlID} + maps.Copy(args, scope.SQLArguments()) + + r := conn.QueryRow(ctx, q, args) + + c2 := Control{} + if err := c2.scan(r); err != nil { + return err + } + + *v = c2 + + return nil +} + func (c *Controls) LoadByFrameworkID( ctx context.Context, conn pg.Conn, diff --git a/pkg/probo/probo.go b/pkg/probo/probo.go index 780c37c2c..175c7ecd2 100644 --- a/pkg/probo/probo.go +++ b/pkg/probo/probo.go @@ -129,6 +129,26 @@ func (s Service) GetFramework( return framework, nil } +func (s Service) GetControl( + ctx context.Context, + controlID gid.GID, +) (*coredata.Control, error) { + control := &coredata.Control{} + + err := s.pg.WithConn( + ctx, + func(conn pg.Conn) error { + return control.LoadByID(ctx, conn, s.scope, controlID) + }, + ) + + if err != nil { + return nil, err + } + + return control, nil +} + func (s Service) ListOrganizationFrameworks( ctx context.Context, organizationID gid.GID,