Refactor probo service

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-11 17:02:28 +01:00
parent b41f417af6
commit 9640e4266a
40 changed files with 1101 additions and 1591 deletions

View File

@@ -30,12 +30,13 @@ import (
type (
User struct {
ID gid.GID `db:"id"`
EmailAddress string `db:"email_address"`
HashedPassword []byte `db:"hashed_password"`
FullName string `db:"fullname"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
ID gid.GID `db:"id"`
EmailAddress string `db:"email_address"`
HashedPassword []byte `db:"hashed_password"`
FullName string `db:"fullname"`
EmailAddressVerified bool `db:"email_address_verified"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
ErrUserNotFound struct {

View File

@@ -0,0 +1,167 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
type (
ControlService struct {
svc *TenantService
}
CreateControlRequest struct {
FrameworkID gid.GID
Name string
Description string
ContentRef string
Category string
}
UpdateControlRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
Category *string
State *coredata.ControlState
}
)
func (s ControlService) Get(
ctx context.Context,
controlID gid.GID,
) (*coredata.Control, error) {
control := &coredata.Control{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return control.LoadByID(ctx, conn, s.svc.scope, controlID)
},
)
if err != nil {
return nil, err
}
return control, nil
}
func (s ControlService) Update(
ctx context.Context,
req UpdateControlRequest,
) (*coredata.Control, error) {
params := coredata.UpdateControlParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
Category: req.Category,
State: req.State,
}
control := &coredata.Control{ID: req.ID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return control.Update(ctx, conn, s.svc.scope, params)
})
if err != nil {
return nil, err
}
return control, nil
}
func (s ControlService) ListForFrameworkID(
ctx context.Context,
frameworkID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Control], error) {
var controls coredata.Controls
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return controls.LoadByFrameworkID(
ctx,
conn,
s.svc.scope,
frameworkID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(controls, cursor), nil
}
func (s ControlService) Create(
ctx context.Context,
req CreateControlRequest,
) (*coredata.Control, error) {
now := time.Now()
controlID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.ControlEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create control global id: %w", err)
}
framework := &coredata.Framework{}
control := &coredata.Control{
ID: controlID,
FrameworkID: req.FrameworkID,
Name: req.Name,
Description: req.Description,
Category: req.Category,
State: coredata.ControlStateNotStarted,
ContentRef: req.ContentRef,
CreatedAt: now,
UpdatedAt: now,
}
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := framework.LoadByID(ctx, conn, s.svc.scope, req.FrameworkID); err != nil {
return fmt.Errorf("cannot load framework %q: %w", req.FrameworkID, err)
}
if err := control.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert control: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return control, nil
}

View File

@@ -1,80 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type (
CreateControlRequest struct {
FrameworkID gid.GID
Name string
Description string
ContentRef string
Category string
}
)
func (s Service) CreateControl(
ctx context.Context,
req CreateControlRequest,
) (*coredata.Control, error) {
now := time.Now()
controlID, err := gid.NewGID(s.scope.GetTenantID(), coredata.ControlEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create control global id: %w", err)
}
framework := &coredata.Framework{}
control := &coredata.Control{
ID: controlID,
FrameworkID: req.FrameworkID,
Name: req.Name,
Description: req.Description,
Category: req.Category,
State: coredata.ControlStateNotStarted,
ContentRef: req.ContentRef,
CreatedAt: now,
UpdatedAt: now,
}
err = s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := framework.LoadByID(ctx, conn, s.scope, req.FrameworkID); err != nil {
return fmt.Errorf("cannot load framework %q: %w", req.FrameworkID, err)
}
if err := control.Insert(ctx, conn, s.scope); err != nil {
return fmt.Errorf("cannot insert control: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return control, nil
}

View File

@@ -1,68 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type (
CreateFrameworkRequest struct {
OrganizationID gid.GID
Name string
Description string
ContentRef string
}
)
func (s Service) CreateFramework(
ctx context.Context,
req CreateFrameworkRequest,
) (*coredata.Framework, error) {
now := time.Now()
frameworkID, err := gid.NewGID(s.scope.GetTenantID(), coredata.FrameworkEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create global id: %w", err)
}
framework := &coredata.Framework{
ID: frameworkID,
OrganizationID: req.OrganizationID,
Name: req.Name,
Description: req.Description,
ContentRef: req.ContentRef,
CreatedAt: now,
UpdatedAt: now,
}
err = s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return framework.Insert(ctx, conn, s.scope)
},
)
if err != nil {
return nil, err
}
return framework, nil
}

View File

@@ -1,79 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type (
CreatePeopleRequest struct {
OrganizationID gid.GID
FullName string
PrimaryEmailAddress string
AdditionalEmailAddresses []string
Kind coredata.PeopleKind
}
)
func (s Service) CreatePeople(
ctx context.Context,
req CreatePeopleRequest,
) (*coredata.People, error) {
now := time.Now()
peopleID, err := gid.NewGID(s.scope.GetTenantID(), coredata.PeopleEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create people global id: %w", err)
}
organization := &coredata.Organization{}
people := &coredata.People{
ID: peopleID,
OrganizationID: req.OrganizationID,
Kind: req.Kind,
FullName: req.FullName,
PrimaryEmailAddress: req.PrimaryEmailAddress,
AdditionalEmailAddresses: req.AdditionalEmailAddresses,
CreatedAt: now,
UpdatedAt: now,
}
err = s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := organization.LoadByID(ctx, conn, s.scope, req.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization %q: %w", req.OrganizationID, err)
}
if err := people.Insert(ctx, conn, s.scope); err != nil {
return fmt.Errorf("cannot insert people: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return people, nil
}

View File

@@ -1,78 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type (
CreateTaskRequest struct {
ControlID gid.GID
Name string
ContentRef string
Description string
}
)
func (s Service) CreateTask(
ctx context.Context,
req CreateTaskRequest,
) (*coredata.Task, error) {
now := time.Now()
taskID, err := gid.NewGID(s.scope.GetTenantID(), coredata.TaskEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create task global id: %w", err)
}
control := &coredata.Control{}
task := &coredata.Task{
ID: taskID,
ControlID: req.ControlID,
Name: req.Name,
ContentRef: req.ContentRef,
State: coredata.TaskStateTodo,
Description: req.Description,
CreatedAt: now,
UpdatedAt: now,
}
err = s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := control.LoadByID(ctx, conn, s.scope, req.ControlID); err != nil {
return fmt.Errorf("cannot laod control %q: %w", req.ControlID, err)
}
if err := task.Insert(ctx, conn, s.scope); err != nil {
return fmt.Errorf("cannot insert task: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return task, nil
}

View File

@@ -14,76 +14,4 @@
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type (
CreateVendorRequest struct {
OrganizationID gid.GID
Name string
Description string
ServiceStartAt time.Time
ServiceTerminationAt *time.Time
ServiceCriticality coredata.ServiceCriticality
RiskTier coredata.RiskTier
StatusPageURL *string
TermsOfServiceURL *string
PrivacyPolicyURL *string
}
)
func (s Service) CreateVendor(
ctx context.Context,
req CreateVendorRequest,
) (*coredata.Vendor, error) {
now := time.Now()
vendorID, err := gid.NewGID(s.scope.GetTenantID(), coredata.VendorEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create vendor global id: %w", err)
}
organization := &coredata.Organization{}
vendor := &coredata.Vendor{
ID: vendorID,
OrganizationID: req.OrganizationID,
Name: req.Name,
CreatedAt: now,
UpdatedAt: now,
Description: req.Description,
ServiceStartAt: req.ServiceStartAt,
ServiceTerminationAt: req.ServiceTerminationAt,
ServiceCriticality: req.ServiceCriticality,
RiskTier: req.RiskTier,
StatusPageURL: req.StatusPageURL,
TermsOfServiceURL: req.TermsOfServiceURL,
PrivacyPolicyURL: req.PrivacyPolicyURL,
}
err = s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := organization.LoadByID(ctx, conn, s.scope, req.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization %q: %w", req.OrganizationID, err)
}
if err := vendor.Insert(ctx, conn, s.scope); err != nil {
return fmt.Errorf("cannot insert vendor: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return vendor, nil
}
type ()

View File

@@ -1,42 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s *Service) DeleteEvidence(
ctx context.Context,
evidenceID gid.GID,
) error {
evidence := &coredata.Evidence{ID: evidenceID}
return s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := evidence.Delete(ctx, conn, s.scope); err != nil {
return fmt.Errorf("cannot delete evidence: %w", err)
}
return nil
},
)
}

View File

@@ -1,37 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) DeleteFramework(
ctx context.Context,
frameworkID gid.GID,
) error {
framework := &coredata.Framework{ID: frameworkID}
return s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return framework.Delete(ctx, conn, s.scope)
},
)
}

View File

@@ -1,37 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) DeletePeople(
ctx context.Context,
peopleID gid.GID,
) error {
people := coredata.People{ID: peopleID}
return s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return people.Delete(ctx, conn, s.scope)
},
)
}

View File

@@ -1,36 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) DeleteTask(
ctx context.Context,
taskID gid.GID,
) error {
task := coredata.Task{ID: taskID}
return s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return task.Delete(ctx, conn, s.scope)
},
)
}

View File

@@ -1,36 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) DeleteVendor(
ctx context.Context,
vendorID gid.GID,
) error {
vendor := coredata.Vendor{ID: vendorID}
return s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendor.Delete(ctx, conn, s.scope)
},
)
}

View File

@@ -26,11 +26,16 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/crypto/uuid"
"go.gearno.de/kit/pg"
)
type (
EvidenceService struct {
svc *TenantService
}
CreateEvidenceRequest struct {
TaskID gid.GID
Name string
@@ -38,12 +43,32 @@ type (
}
)
func (s Service) CreateEvidence(
func (s EvidenceService) Get(
ctx context.Context,
evidenceID gid.GID,
) (*coredata.Evidence, error) {
evidence := &coredata.Evidence{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return evidence.LoadByID(ctx, conn, s.svc.scope, evidenceID)
},
)
if err != nil {
return nil, err
}
return evidence, nil
}
func (s EvidenceService) Create(
ctx context.Context,
req CreateEvidenceRequest,
) (*coredata.Evidence, error) {
now := time.Now()
evidenceID, err := gid.NewGID(s.scope.GetTenantID(), coredata.EvidenceEntityType)
evidenceID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.EvidenceEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create evidence global id: %w", err)
}
@@ -60,8 +85,8 @@ func (s Service) CreateEvidence(
return nil, fmt.Errorf("cannot generate object key: %w", err)
}
putObjectOutput, err := s.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(s.bucket),
putObjectOutput, err := s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: aws.String(contentType),
@@ -70,8 +95,8 @@ func (s Service) CreateEvidence(
return nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.bucket),
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
@@ -93,14 +118,14 @@ func (s Service) CreateEvidence(
UpdatedAt: now,
}
err = s.pg.WithTx(
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := task.LoadByID(ctx, conn, s.scope, req.TaskID); err != nil {
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 err := evidence.Insert(ctx, conn, s.scope); err != nil {
if err := evidence.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert evidence: %w", err)
}
@@ -115,3 +140,75 @@ func (s Service) CreateEvidence(
return evidence, nil
}
func (s EvidenceService) GenerateFileURL(
ctx context.Context,
evidenceID gid.GID,
expiresIn time.Duration,
) (*string, error) {
evidence, err := s.Get(ctx, evidenceID)
if err != nil {
return nil, fmt.Errorf("cannot get evidence: %w", err)
}
presignClient := s3.NewPresignClient(s.svc.s3)
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(evidence.ObjectKey),
ResponseContentType: aws.String(evidence.MimeType),
ResponseContentDisposition: aws.String(fmt.Sprintf("attachment; filename=\"%s\"", evidence.Filename)),
}, func(opts *s3.PresignOptions) {
opts.Expires = expiresIn
})
if err != nil {
return nil, fmt.Errorf("cannot presign GetObject request: %w", err)
}
return &presignedReq.URL, nil
}
func (s EvidenceService) ListForTaskID(
ctx context.Context,
taskID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Evidence], error) {
var evidences coredata.Evidences
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return evidences.LoadByTaskID(
ctx,
conn,
s.svc.scope,
taskID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(evidences, cursor), nil
}
func (s *EvidenceService) Delete(
ctx context.Context,
evidenceID gid.GID,
) error {
evidence := &coredata.Evidence{ID: evidenceID}
return s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := evidence.Delete(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot delete evidence: %w", err)
}
return nil
},
)
}

View File

@@ -0,0 +1,165 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
type (
FrameworkService struct {
svc *TenantService
}
CreateFrameworkRequest struct {
OrganizationID gid.GID
Name string
Description string
ContentRef string
}
UpdateFrameworkRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
}
)
func (s FrameworkService) Create(
ctx context.Context,
req CreateFrameworkRequest,
) (*coredata.Framework, error) {
now := time.Now()
frameworkID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.FrameworkEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create global id: %w", err)
}
framework := &coredata.Framework{
ID: frameworkID,
OrganizationID: req.OrganizationID,
Name: req.Name,
Description: req.Description,
ContentRef: req.ContentRef,
CreatedAt: now,
UpdatedAt: now,
}
err = s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return framework.Insert(ctx, conn, s.svc.scope)
},
)
if err != nil {
return nil, err
}
return framework, nil
}
func (s FrameworkService) ListForOrganizationID(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Framework], error) {
var frameworks coredata.Frameworks
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return frameworks.LoadByOrganizationID(
ctx,
conn,
s.svc.scope,
organizationID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(frameworks, cursor), nil
}
func (s FrameworkService) Get(
ctx context.Context,
frameworkID gid.GID,
) (*coredata.Framework, error) {
framework := &coredata.Framework{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return framework.LoadByID(ctx, conn, s.svc.scope, frameworkID)
},
)
if err != nil {
return nil, err
}
return framework, nil
}
func (s FrameworkService) Update(
ctx context.Context,
req UpdateFrameworkRequest,
) (*coredata.Framework, error) {
params := coredata.UpdateFrameworkParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
}
framework := &coredata.Framework{ID: req.ID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return framework.Update(ctx, conn, s.svc.scope, params)
})
if err != nil {
return nil, err
}
return framework, nil
}
func (s FrameworkService) Delete(
ctx context.Context,
frameworkID gid.GID,
) error {
framework := &coredata.Framework{ID: frameworkID}
return s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return framework.Delete(ctx, conn, s.svc.scope)
},
)
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
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
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) GetEvidence(
ctx context.Context,
evidenceID gid.GID,
) (*coredata.Evidence, error) {
evidence := &coredata.Evidence{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return evidence.LoadByID(ctx, conn, s.scope, evidenceID)
},
)
if err != nil {
return nil, err
}
return evidence, nil
}

View File

@@ -1,52 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/getprobo/probo/pkg/gid"
)
func (s Service) GetEvidenceFileURL(
ctx context.Context,
evidenceID gid.GID,
expiresIn time.Duration,
) (*string, error) {
evidence, err := s.GetEvidence(ctx, evidenceID)
if err != nil {
return nil, fmt.Errorf("cannot get evidence: %w", err)
}
presignClient := s3.NewPresignClient(s.s3)
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(s.bucket),
Key: aws.String(evidence.ObjectKey),
ResponseContentType: aws.String(evidence.MimeType),
ResponseContentDisposition: aws.String(fmt.Sprintf("attachment; filename=\"%s\"", evidence.Filename)),
}, func(opts *s3.PresignOptions) {
opts.Expires = expiresIn
})
if err != nil {
return nil, fmt.Errorf("cannot presign GetObject request: %w", err)
}
return &presignedReq.URL, nil
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) GetFramework(
ctx context.Context,
frameworkID gid.GID,
) (*coredata.Framework, error) {
framework := &coredata.Framework{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return framework.LoadByID(ctx, conn, s.scope, frameworkID)
},
)
if err != nil {
return nil, err
}
return framework, nil
}

View File

@@ -1,48 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) GetOrganization(
ctx context.Context,
organizationID gid.GID,
) (*coredata.Organization, error) {
organization := &coredata.Organization{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return organization.LoadByID(
ctx,
conn,
s.scope,
organizationID,
)
},
)
if err != nil {
return nil, err
}
return organization, nil
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) GetPeople(
ctx context.Context,
peopleID gid.GID,
) (*coredata.People, error) {
people := &coredata.People{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return people.LoadByID(ctx, conn, s.scope, peopleID)
},
)
if err != nil {
return nil, err
}
return people, nil
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) GetTask(
ctx context.Context,
taskID gid.GID,
) (*coredata.Task, error) {
task := &coredata.Task{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return task.LoadByID(ctx, conn, s.scope, taskID)
},
)
if err != nil {
return nil, err
}
return task, nil
}

View File

@@ -1,43 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
func (s Service) GetVendor(
ctx context.Context,
vendorID gid.GID,
) (*coredata.Vendor, error) {
vendor := &coredata.Vendor{}
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendor.LoadByID(ctx, conn, s.scope, vendorID)
},
)
if err != nil {
return nil, err
}
return vendor, nil
}

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
func (s Service) ListControlTasks(
ctx context.Context,
controlID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Task], error) {
var tasks coredata.Tasks
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return tasks.LoadByControlID(
ctx,
conn,
s.scope,
controlID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(tasks, cursor), nil
}

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
func (s Service) ListFrameworkControls(
ctx context.Context,
frameworkID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Control], error) {
var controls coredata.Controls
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return controls.LoadByFrameworkID(
ctx,
conn,
s.scope,
frameworkID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(controls, cursor), nil
}

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
func (s Service) ListOrganizationFrameworks(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Framework], error) {
var frameworks coredata.Frameworks
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return frameworks.LoadByOrganizationID(
ctx,
conn,
s.scope,
organizationID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(frameworks, cursor), nil
}

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
func (s Service) ListOrganizationPeoples(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.People], error) {
var peoples coredata.Peoples
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return peoples.LoadByOrganizationID(
ctx,
conn,
s.scope,
organizationID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(peoples, cursor), nil
}

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
func (s Service) ListOrganizationVendors(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Vendor], error) {
var vendors coredata.Vendors
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendors.LoadByOrganizationID(
ctx,
conn,
s.scope,
organizationID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(vendors, cursor), nil
}

View File

@@ -1,51 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
func (s Service) ListTaskEvidences(
ctx context.Context,
taskID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Evidence], error) {
var evidences coredata.Evidences
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return evidences.LoadByTaskID(
ctx,
conn,
s.scope,
taskID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(evidences, cursor), nil
}

View File

@@ -25,32 +25,34 @@ import (
)
type (
OrganizationService struct {
svc *TenantService
}
CreateOrganizationRequest struct {
Name string
}
)
func (s Service) CreateOrganization(
func (s OrganizationService) Create(
ctx context.Context,
req CreateOrganizationRequest,
) (*coredata.Organization, error) {
tenantID := gid.NewTenantID()
now := time.Now()
organizationID, err := gid.NewGID(tenantID, coredata.OrganizationEntityType)
organizationID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.OrganizationEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create organization global id: %w", err)
}
organization := &coredata.Organization{
ID: organizationID,
TenantID: tenantID,
TenantID: s.svc.scope.GetTenantID(),
Name: req.Name,
CreatedAt: now,
UpdatedAt: now,
}
err = s.pg.WithConn(
err = s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
if err := organization.Insert(ctx, conn); err != nil {
@@ -67,3 +69,28 @@ func (s Service) CreateOrganization(
return organization, nil
}
func (s OrganizationService) Get(
ctx context.Context,
organizationID gid.GID,
) (*coredata.Organization, error) {
organization := &coredata.Organization{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return organization.LoadByID(
ctx,
conn,
s.svc.scope,
organizationID,
)
},
)
if err != nil {
return nil, err
}
return organization, nil
}

180
pkg/probo/people_service.go Normal file
View File

@@ -0,0 +1,180 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
type (
PeopleService struct {
svc *TenantService
}
UpdatePeopleRequest struct {
ID gid.GID
ExpectedVersion int
Kind *coredata.PeopleKind
FullName *string
PrimaryEmailAddress *string
AdditionalEmailAddresses *[]string
}
CreatePeopleRequest struct {
OrganizationID gid.GID
FullName string
PrimaryEmailAddress string
AdditionalEmailAddresses []string
Kind coredata.PeopleKind
}
)
func (s PeopleService) Get(
ctx context.Context,
peopleID gid.GID,
) (*coredata.People, error) {
people := &coredata.People{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return people.LoadByID(ctx, conn, s.svc.scope, peopleID)
},
)
if err != nil {
return nil, err
}
return people, nil
}
func (s PeopleService) ListForOrganizationID(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.People], error) {
var peoples coredata.Peoples
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return peoples.LoadByOrganizationID(
ctx,
conn,
s.svc.scope,
organizationID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(peoples, cursor), nil
}
func (s PeopleService) Update(
ctx context.Context,
req UpdatePeopleRequest,
) (*coredata.People, error) {
params := coredata.UpdatePeopleParams{
ExpectedVersion: req.ExpectedVersion,
Kind: req.Kind,
FullName: req.FullName,
PrimaryEmailAddress: req.PrimaryEmailAddress,
AdditionalEmailAddresses: req.AdditionalEmailAddresses,
}
people := &coredata.People{ID: req.ID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return people.Update(ctx, conn, s.svc.scope, params)
})
if err != nil {
return nil, err
}
return people, nil
}
func (s PeopleService) Create(
ctx context.Context,
req CreatePeopleRequest,
) (*coredata.People, error) {
now := time.Now()
peopleID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.PeopleEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create people global id: %w", err)
}
organization := &coredata.Organization{}
people := &coredata.People{
ID: peopleID,
OrganizationID: req.OrganizationID,
Kind: req.Kind,
FullName: req.FullName,
PrimaryEmailAddress: req.PrimaryEmailAddress,
AdditionalEmailAddresses: req.AdditionalEmailAddresses,
CreatedAt: now,
UpdatedAt: now,
}
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := organization.LoadByID(ctx, conn, s.svc.scope, req.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization %q: %w", req.OrganizationID, err)
}
if err := people.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert people: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return people, nil
}
func (s PeopleService) Delete(
ctx context.Context,
peopleID gid.GID,
) error {
people := coredata.People{ID: peopleID}
return s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return people.Delete(ctx, conn, s.svc.scope)
},
)
}

View File

@@ -12,7 +12,7 @@ import (
)
type PolicyService struct {
svc *Service
svc *TenantService
}
type (
@@ -142,7 +142,7 @@ func (s *PolicyService) Delete(
)
}
func (s *PolicyService) ListByOrganization(
func (s *PolicyService) ListByOrganizationID(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,

View File

@@ -29,9 +29,23 @@ type (
pg *pg.Client
s3 *s3.Client
bucket string
scope coredata.Scoper
}
Policies *PolicyService
TenantService struct {
pg *pg.Client
s3 *s3.Client
bucket string
scope coredata.Scoper
Policies *PolicyService
Controls *ControlService
Evidences *EvidenceService
Frameworks *FrameworkService
Tasks *TaskService
Peoples *PeopleService
Organizations *OrganizationService
Vendors *VendorService
}
)
@@ -49,23 +63,27 @@ func NewService(
pg: pgClient,
s3: s3Client,
bucket: bucket,
scope: coredata.NewNoScope(),
}
svc.Policies = &PolicyService{svc: svc}
return svc, nil
}
func (s *Service) WithTenant(tenantID gid.TenantID) *Service {
newSvc := &Service{
func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
tenantService := &TenantService{
pg: s.pg,
s3: s.s3,
bucket: s.bucket,
scope: coredata.NewScope(tenantID),
}
newSvc.Policies = &PolicyService{svc: newSvc}
tenantService.Policies = &PolicyService{svc: tenantService}
tenantService.Controls = &ControlService{svc: tenantService}
tenantService.Evidences = &EvidenceService{svc: tenantService}
tenantService.Frameworks = &FrameworkService{svc: tenantService}
tenantService.Tasks = &TaskService{svc: tenantService}
tenantService.Peoples = &PeopleService{svc: tenantService}
tenantService.Organizations = &OrganizationService{svc: tenantService}
tenantService.Vendors = &VendorService{svc: tenantService}
return newSvc
return tenantService
}

176
pkg/probo/task_service.go Normal file
View File

@@ -0,0 +1,176 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
type (
TaskService struct {
svc *TenantService
}
CreateTaskRequest struct {
ControlID gid.GID
Name string
ContentRef string
Description string
}
UpdateTaskRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
State *coredata.TaskState
}
)
func (s TaskService) Create(
ctx context.Context,
req CreateTaskRequest,
) (*coredata.Task, error) {
now := time.Now()
taskID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.TaskEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create task global id: %w", err)
}
control := &coredata.Control{}
task := &coredata.Task{
ID: taskID,
ControlID: req.ControlID,
Name: req.Name,
ContentRef: req.ContentRef,
State: coredata.TaskStateTodo,
Description: req.Description,
CreatedAt: now,
UpdatedAt: now,
}
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := control.LoadByID(ctx, conn, s.svc.scope, req.ControlID); err != nil {
return fmt.Errorf("cannot laod control %q: %w", req.ControlID, err)
}
if err := task.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert task: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return task, nil
}
func (s TaskService) Update(
ctx context.Context,
req UpdateTaskRequest,
) (*coredata.Task, error) {
params := coredata.UpdateTaskParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
State: req.State,
}
task := &coredata.Task{ID: req.ID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return task.Update(ctx, conn, s.svc.scope, params)
})
if err != nil {
return nil, err
}
return task, nil
}
func (s TaskService) ListForControlID(
ctx context.Context,
controlID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Task], error) {
var tasks coredata.Tasks
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return tasks.LoadByControlID(
ctx,
conn,
s.svc.scope,
controlID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(tasks, cursor), nil
}
func (s TaskService) Delete(
ctx context.Context,
taskID gid.GID,
) error {
task := coredata.Task{ID: taskID}
return s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return task.Delete(ctx, conn, s.svc.scope)
},
)
}
func (s TaskService) Get(
ctx context.Context,
taskID gid.GID,
) (*coredata.Task, error) {
task := &coredata.Task{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return task.LoadByID(ctx, conn, s.svc.scope, taskID)
},
)
if err != nil {
return nil, err
}
return task, nil
}

View File

@@ -1,58 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type UpdateControlRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
Category *string
State *coredata.ControlState
}
func (s Service) UpdateControl(
ctx context.Context,
req UpdateControlRequest,
) (*coredata.Control, error) {
params := coredata.UpdateControlParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
Category: req.Category,
State: req.State,
}
control := &coredata.Control{ID: req.ID}
err := s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return control.Update(ctx, conn, s.scope, params)
})
if err != nil {
return nil, err
}
return control, nil
}

View File

@@ -1,54 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type UpdateFrameworkRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
}
func (s Service) UpdateFramework(
ctx context.Context,
req UpdateFrameworkRequest,
) (*coredata.Framework, error) {
params := coredata.UpdateFrameworkParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
}
framework := &coredata.Framework{ID: req.ID}
err := s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return framework.Update(ctx, conn, s.scope, params)
})
if err != nil {
return nil, err
}
return framework, nil
}

View File

@@ -1,58 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type UpdatePeopleRequest struct {
ID gid.GID
ExpectedVersion int
Kind *coredata.PeopleKind
FullName *string
PrimaryEmailAddress *string
AdditionalEmailAddresses *[]string
}
func (s Service) UpdatePeople(
ctx context.Context,
req UpdatePeopleRequest,
) (*coredata.People, error) {
params := coredata.UpdatePeopleParams{
ExpectedVersion: req.ExpectedVersion,
Kind: req.Kind,
FullName: req.FullName,
PrimaryEmailAddress: req.PrimaryEmailAddress,
AdditionalEmailAddresses: req.AdditionalEmailAddresses,
}
people := &coredata.People{ID: req.ID}
err := s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return people.Update(ctx, conn, s.scope, params)
})
if err != nil {
return nil, err
}
return people, nil
}

View File

@@ -1,56 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type UpdateTaskRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
State *coredata.TaskState
}
func (s Service) UpdateTask(
ctx context.Context,
req UpdateTaskRequest,
) (*coredata.Task, error) {
params := coredata.UpdateTaskParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
State: req.State,
}
task := &coredata.Task{ID: req.ID}
err := s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return task.Update(ctx, conn, s.scope, params)
})
if err != nil {
return nil, err
}
return task, nil
}

View File

@@ -1,69 +0,0 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/kit/pg"
)
type UpdateVendorRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
ServiceStartAt *time.Time
ServiceTerminationAt *time.Time
ServiceCriticality *coredata.ServiceCriticality
RiskTier *coredata.RiskTier
StatusPageURL *string
TermsOfServiceURL *string
PrivacyPolicyURL *string
}
func (s Service) UpdateVendor(
ctx context.Context,
req UpdateVendorRequest,
) (*coredata.Vendor, error) {
params := coredata.UpdateVendorParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
ServiceStartAt: req.ServiceStartAt,
ServiceTerminationAt: req.ServiceTerminationAt,
ServiceCriticality: req.ServiceCriticality,
RiskTier: req.RiskTier,
StatusPageURL: req.StatusPageURL,
TermsOfServiceURL: req.TermsOfServiceURL,
PrivacyPolicyURL: req.PrivacyPolicyURL,
}
vendor := &coredata.Vendor{ID: req.ID}
err := s.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return vendor.Update(ctx, conn, s.scope, params)
})
if err != nil {
return nil, err
}
return vendor, nil
}

199
pkg/probo/vendor_service.go Normal file
View File

@@ -0,0 +1,199 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package probo
import (
"context"
"fmt"
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/kit/pg"
)
type (
VendorService struct {
svc *TenantService
}
CreateVendorRequest struct {
OrganizationID gid.GID
Name string
Description string
ServiceStartAt time.Time
ServiceTerminationAt *time.Time
ServiceCriticality coredata.ServiceCriticality
RiskTier coredata.RiskTier
StatusPageURL *string
TermsOfServiceURL *string
PrivacyPolicyURL *string
}
UpdateVendorRequest struct {
ID gid.GID
ExpectedVersion int
Name *string
Description *string
ServiceStartAt *time.Time
ServiceTerminationAt *time.Time
ServiceCriticality *coredata.ServiceCriticality
RiskTier *coredata.RiskTier
StatusPageURL *string
TermsOfServiceURL *string
PrivacyPolicyURL *string
}
)
func (s VendorService) ListForOrganizationID(
ctx context.Context,
organizationID gid.GID,
cursor *page.Cursor,
) (*page.Page[*coredata.Vendor], error) {
var vendors coredata.Vendors
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendors.LoadByOrganizationID(
ctx,
conn,
s.svc.scope,
organizationID,
cursor,
)
},
)
if err != nil {
return nil, err
}
return page.NewPage(vendors, cursor), nil
}
func (s VendorService) Update(
ctx context.Context,
req UpdateVendorRequest,
) (*coredata.Vendor, error) {
params := coredata.UpdateVendorParams{
ExpectedVersion: req.ExpectedVersion,
Name: req.Name,
Description: req.Description,
ServiceStartAt: req.ServiceStartAt,
ServiceTerminationAt: req.ServiceTerminationAt,
ServiceCriticality: req.ServiceCriticality,
RiskTier: req.RiskTier,
StatusPageURL: req.StatusPageURL,
TermsOfServiceURL: req.TermsOfServiceURL,
PrivacyPolicyURL: req.PrivacyPolicyURL,
}
vendor := &coredata.Vendor{ID: req.ID}
err := s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
return vendor.Update(ctx, conn, s.svc.scope, params)
})
if err != nil {
return nil, err
}
return vendor, nil
}
func (s VendorService) Get(
ctx context.Context,
vendorID gid.GID,
) (*coredata.Vendor, error) {
vendor := &coredata.Vendor{}
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendor.LoadByID(ctx, conn, s.svc.scope, vendorID)
},
)
if err != nil {
return nil, err
}
return vendor, nil
}
func (s VendorService) Delete(
ctx context.Context,
vendorID gid.GID,
) error {
vendor := coredata.Vendor{ID: vendorID}
return s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return vendor.Delete(ctx, conn, s.svc.scope)
},
)
}
func (s VendorService) Create(
ctx context.Context,
req CreateVendorRequest,
) (*coredata.Vendor, error) {
now := time.Now()
vendorID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.VendorEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create vendor global id: %w", err)
}
organization := &coredata.Organization{}
vendor := &coredata.Vendor{
ID: vendorID,
OrganizationID: req.OrganizationID,
Name: req.Name,
CreatedAt: now,
UpdatedAt: now,
Description: req.Description,
ServiceStartAt: req.ServiceStartAt,
ServiceTerminationAt: req.ServiceTerminationAt,
ServiceCriticality: req.ServiceCriticality,
RiskTier: req.RiskTier,
StatusPageURL: req.StatusPageURL,
TermsOfServiceURL: req.TermsOfServiceURL,
PrivacyPolicyURL: req.PrivacyPolicyURL,
}
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
if err := organization.LoadByID(ctx, conn, s.svc.scope, req.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization %q: %w", req.OrganizationID, err)
}
if err := vendor.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert vendor: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return vendor, nil
}

View File

@@ -23,7 +23,7 @@ func (r *controlResolver) Tasks(ctx context.Context, obj *types.Control, first *
svc := r.proboSvc.WithTenant(obj.ID.TenantID())
cursor := types.NewCursor(first, after, last, before)
page, err := svc.ListControlTasks(ctx, obj.ID, cursor)
page, err := svc.Tasks.ListForControlID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list control tasks: %w", err)
}
@@ -35,7 +35,7 @@ func (r *controlResolver) Tasks(ctx context.Context, obj *types.Control, first *
func (r *evidenceResolver) FileURL(ctx context.Context, obj *types.Evidence) (string, error) {
svc := r.proboSvc.WithTenant(obj.ID.TenantID())
fileURL, err := svc.GetEvidenceFileURL(ctx, obj.ID, 15*time.Minute)
fileURL, err := svc.Evidences.GenerateFileURL(ctx, obj.ID, 15*time.Minute)
if err != nil {
return "", fmt.Errorf("cannot generate file URL: %w", err)
}
@@ -48,7 +48,7 @@ func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework,
svc := r.proboSvc.WithTenant(obj.ID.TenantID())
cursor := types.NewCursor(first, after, last, before)
page, err := svc.ListFrameworkControls(ctx, obj.ID, cursor)
page, err := svc.Controls.ListForFrameworkID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list framework controls: %w", err)
}
@@ -60,7 +60,7 @@ func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework,
func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) {
svc := r.proboSvc.WithTenant(input.OrganizationID.TenantID())
vendor, err := svc.CreateVendor(ctx, probo.CreateVendorRequest{
vendor, err := svc.Vendors.Create(ctx, probo.CreateVendorRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Description: input.Description,
@@ -84,7 +84,7 @@ func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateV
func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.UpdateVendorPayload, error) {
svc := r.proboSvc.WithTenant(input.ID.TenantID())
vendor, err := svc.UpdateVendor(ctx, probo.UpdateVendorRequest{
vendor, err := svc.Vendors.Update(ctx, probo.UpdateVendorRequest{
ID: input.ID,
ExpectedVersion: input.ExpectedVersion,
Name: input.Name,
@@ -110,7 +110,7 @@ func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateV
func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (*types.DeleteVendorPayload, error) {
svc := r.proboSvc.WithTenant(input.VendorID.TenantID())
err := svc.DeleteVendor(ctx, input.VendorID)
err := svc.Vendors.Delete(ctx, input.VendorID)
if err != nil {
return nil, fmt.Errorf("cannot delete vendor: %w", err)
}
@@ -124,7 +124,7 @@ func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteV
func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) {
svc := r.proboSvc.WithTenant(input.OrganizationID.TenantID())
people, err := svc.CreatePeople(ctx, probo.CreatePeopleRequest{
people, err := svc.Peoples.Create(ctx, probo.CreatePeopleRequest{
OrganizationID: input.OrganizationID,
FullName: input.FullName,
PrimaryEmailAddress: input.PrimaryEmailAddress,
@@ -145,7 +145,7 @@ func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreateP
func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdatePeopleInput) (*types.UpdatePeoplePayload, error) {
svc := r.proboSvc.WithTenant(input.ID.TenantID())
people, err := svc.UpdatePeople(ctx, probo.UpdatePeopleRequest{
people, err := svc.Peoples.Update(ctx, probo.UpdatePeopleRequest{
ID: input.ID,
ExpectedVersion: input.ExpectedVersion,
FullName: input.FullName,
@@ -166,7 +166,7 @@ func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdateP
func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeletePeopleInput) (*types.DeletePeoplePayload, error) {
svc := r.proboSvc.WithTenant(input.PeopleID.TenantID())
err := svc.DeletePeople(ctx, input.PeopleID)
err := svc.Peoples.Delete(ctx, input.PeopleID)
if err != nil {
return nil, fmt.Errorf("cannot delete people: %w", err)
}
@@ -178,7 +178,9 @@ func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeleteP
// CreateOrganization is the resolver for the createOrganization field.
func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error) {
organization, err := r.proboSvc.CreateOrganization(ctx, probo.CreateOrganizationRequest{
svc := r.proboSvc.WithTenant(gid.NewTenantID())
organization, err := svc.Organizations.Create(ctx, probo.CreateOrganizationRequest{
Name: input.Name,
})
if err != nil {
@@ -204,7 +206,7 @@ func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.D
func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) {
svc := r.proboSvc.WithTenant(input.ControlID.TenantID())
task, err := svc.CreateTask(ctx, probo.CreateTaskRequest{
task, err := svc.Tasks.Create(ctx, probo.CreateTaskRequest{
ControlID: input.ControlID,
Name: input.Name,
Description: input.Description,
@@ -222,7 +224,7 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTas
func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error) {
svc := r.proboSvc.WithTenant(input.TaskID.TenantID())
task, err := svc.UpdateTask(ctx, probo.UpdateTaskRequest{
task, err := svc.Tasks.Update(ctx, probo.UpdateTaskRequest{
ID: input.TaskID,
ExpectedVersion: input.ExpectedVersion,
Name: input.Name,
@@ -242,7 +244,7 @@ func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTas
func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) {
svc := r.proboSvc.WithTenant(input.TaskID.TenantID())
err := svc.DeleteTask(ctx, input.TaskID)
err := svc.Tasks.Delete(ctx, input.TaskID)
if err != nil {
return nil, fmt.Errorf("cannot delete task: %w", err)
}
@@ -256,7 +258,7 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTas
func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) {
svc := r.proboSvc.WithTenant(input.OrganizationID.TenantID())
framework, err := svc.CreateFramework(ctx, probo.CreateFrameworkRequest{
framework, err := svc.Frameworks.Create(ctx, probo.CreateFrameworkRequest{
OrganizationID: input.OrganizationID,
Name: input.Name,
Description: input.Description,
@@ -274,7 +276,7 @@ func (r *mutationResolver) CreateFramework(ctx context.Context, input types.Crea
func (r *mutationResolver) CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error) {
svc := r.proboSvc.WithTenant(input.FrameworkID.TenantID())
control, err := svc.CreateControl(ctx, probo.CreateControlRequest{
control, err := svc.Controls.Create(ctx, probo.CreateControlRequest{
FrameworkID: input.FrameworkID,
Name: input.Name,
Description: input.Description,
@@ -293,7 +295,7 @@ func (r *mutationResolver) CreateControl(ctx context.Context, input types.Create
func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) {
svc := r.proboSvc.WithTenant(input.ID.TenantID())
framework, err := svc.UpdateFramework(ctx, probo.UpdateFrameworkRequest{
framework, err := svc.Frameworks.Update(ctx, probo.UpdateFrameworkRequest{
ID: input.ID,
ExpectedVersion: input.ExpectedVersion,
Name: input.Name,
@@ -312,7 +314,7 @@ func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.Upda
func (r *mutationResolver) UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error) {
svc := r.proboSvc.WithTenant(input.ID.TenantID())
control, err := svc.UpdateControl(ctx, probo.UpdateControlRequest{
control, err := svc.Controls.Update(ctx, probo.UpdateControlRequest{
ID: input.ID,
ExpectedVersion: input.ExpectedVersion,
Name: input.Name,
@@ -339,7 +341,7 @@ func (r *mutationResolver) UploadEvidence(ctx context.Context, input types.Uploa
File: input.File.File,
}
evidence, err := svc.CreateEvidence(ctx, req)
evidence, err := svc.Evidences.Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to create evidence: %w", err)
}
@@ -353,7 +355,7 @@ func (r *mutationResolver) UploadEvidence(ctx context.Context, input types.Uploa
func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.DeleteEvidenceInput) (*types.DeleteEvidencePayload, error) {
svc := r.proboSvc.WithTenant(input.EvidenceID.TenantID())
err := svc.DeleteEvidence(ctx, input.EvidenceID)
err := svc.Evidences.Delete(ctx, input.EvidenceID)
if err != nil {
return nil, fmt.Errorf("failed to delete evidence: %w", err)
}
@@ -426,7 +428,7 @@ func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organi
cursor := types.NewCursor(first, after, last, before)
page, err := svc.ListOrganizationFrameworks(ctx, obj.ID, cursor)
page, err := svc.Frameworks.ListForOrganizationID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list organization frameworks: %w", err)
}
@@ -440,7 +442,7 @@ func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organizat
cursor := types.NewCursor(first, after, last, before)
page, err := svc.ListOrganizationVendors(ctx, obj.ID, cursor)
page, err := svc.Vendors.ListForOrganizationID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list organization vendors: %w", err)
}
@@ -454,7 +456,7 @@ func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organizat
cursor := types.NewCursor(first, after, last, before)
page, err := svc.ListOrganizationPeoples(ctx, obj.ID, cursor)
page, err := svc.Peoples.ListForOrganizationID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list organization peoples: %w", err)
}
@@ -467,7 +469,7 @@ func (r *organizationResolver) Policies(ctx context.Context, obj *types.Organiza
svc := r.proboSvc.WithTenant(obj.ID.TenantID())
cursor := types.NewCursor(first, after, last, before)
page, err := svc.Policies.ListByOrganization(ctx, obj.ID, cursor)
page, err := svc.Policies.ListByOrganizationID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list organization policies: %w", err)
}
@@ -485,7 +487,7 @@ func (r *policyResolver) Owner(ctx context.Context, obj *types.Policy) (*types.P
}
// Get the owner
owner, err := svc.GetPeople(ctx, policy.OwnerID)
owner, err := svc.Peoples.Get(ctx, policy.OwnerID)
if err != nil {
return nil, fmt.Errorf("cannot get owner: %w", err)
}
@@ -499,49 +501,49 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
switch id.EntityType() {
case coredata.OrganizationEntityType:
organization, err := svc.GetOrganization(ctx, id)
organization, err := svc.Organizations.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewOrganization(organization), nil
case coredata.PeopleEntityType:
people, err := svc.GetPeople(ctx, id)
people, err := svc.Peoples.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewPeople(people), nil
case coredata.VendorEntityType:
vendor, err := svc.GetVendor(ctx, id)
vendor, err := svc.Vendors.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewVendor(vendor), nil
case coredata.FrameworkEntityType:
framework, err := svc.GetFramework(ctx, id)
framework, err := svc.Frameworks.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewFramework(framework), nil
case coredata.ControlEntityType:
control, err := svc.GetControl(ctx, id)
control, err := svc.Controls.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewControl(control), nil
case coredata.TaskEntityType:
task, err := svc.GetTask(ctx, id)
task, err := svc.Tasks.Get(ctx, id)
if err != nil {
return nil, err
}
return types.NewTask(task), nil
case coredata.EvidenceEntityType:
evidence, err := svc.GetEvidence(ctx, id)
evidence, err := svc.Evidences.Get(ctx, id)
if err != nil {
return nil, err
}
@@ -570,9 +572,9 @@ func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *in
svc := r.proboSvc.WithTenant(obj.ID.TenantID())
cursor := types.NewCursor(first, after, last, before)
page, err := svc.ListTaskEvidences(ctx, obj.ID, cursor)
page, err := svc.Evidences.ListForTaskID(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list organization frameworks: %w", err)
return nil, fmt.Errorf("cannot list task evidences: %w", err)
}
return types.NewEvidenceConnection(page), nil
@@ -597,7 +599,9 @@ func (r *userResolver) Organizations(ctx context.Context, obj *types.User, first
// Get the organization details for each organization ID
var edges []*types.OrganizationEdge
for _, organizationID := range organizationIDs {
organization, err := r.proboSvc.GetOrganization(ctx, organizationID)
svc := r.proboSvc.WithTenant(organizationID.TenantID())
organization, err := svc.Organizations.Get(ctx, organizationID)
if err != nil {
return nil, fmt.Errorf("failed to get organization details: %w", err)
}